10

I am trying out systemd script along in Docker environment.

Consider this:

command mentioned in ExecStartPre updating environment file and ExecStart actually making use of environment variable mentioned in env. file.? (all in the same systemd file).

like this:

[Unit]
Description=test service
Before=memcached.service

[Service]
Type=oneshot
EnvironmentFile=-/etc/sysconfig/testfile
ExecStartPre=/usr/local/bin/update_sysconfig_testfile.sh
ExecStart=/usr/bin/testmebinary $VOLUMES

[Install]
WantedBy=multi-user.target

Here, $VOLUMES is defined inside testfile and it is updated by update_sysconfig_testfile.sh script.

Will systemd aware about the change made by ExecStartPre (or) it just loads whatever value in testfile?

If there is any better approach, please share.

kumar
  • 2,530
  • 6
  • 33
  • 57
  • 1
    You have got this far...just test it out and see what happens. – Munir Mar 16 '17 at 13:55
  • Your question would have been faster to test then to type out. – Mark Stosberg Mar 16 '17 at 14:29
  • Yes I tried it first. It worked in my local environment, but failed in docker environment :( – kumar Mar 16 '17 at 14:32
  • 4
    Questions like this are still useful, because folks like me search Google before building something like this, and then these appear in the search results. – Reid Nov 02 '18 at 19:00
  • @Reid true, but considering how easy the question is to answer by trying, the OP could just tried himself and posted both the question and answer if they thought it was useful to share. – Mark Stosberg Sep 30 '21 at 22:05

2 Answers2

5

Since at least systemd 237, you can write an file in ExecStartPre= that's read by EnvironmentFile= before ExecStart= runs as long as you prefix the file path with a dash (EnvironmentFile=-/some/path/.env).

This appears to due to the timing of when the environment is evaluated. poettering says:

the env vars are determined only at execution time

So it's an error if EnvironmentFile= is not defined when ExecStartPre= is executed which is why it needs to be optional, but when the "execution time" of ExecStart= comes, the EnvironmentFile is apparently re-checked and the environment variables set.

This could be better documented in man systemd.exec.

You can also use an alternative approach which is suggested in man systemd.exec where Environmentfile= is documented:

Use one systemd service to write the environment file and a second one to consume it. Using either a Before= or After= relationship in the [Unit] section, you can ensure that the service that writes the environment file is started first in the boot sequence.

Mark Stosberg
  • 12,961
  • 6
  • 44
  • 49
  • 1
    It seems that the man page now suggests it should work: `The files listed with this directive will be read shortly before the process is executed (more specifically, after all processes from a previous unit state terminated. This means you can generate these files in one unit state, and read it with this option in the next).` – Jan Katins Dec 04 '18 at 21:49
5

As an alternate approach, consider a script like with_testfile_vars doing the following:

#!/bin/sh
export foo=bar   # export the same calculated values you would otherwise write to the file
export baz=qux
exec "$@"        # then invoke your "real" program

...with a service file using that wrapper:

[Unit]
Description=test service
Before=memcached.service

[Service]
Type=oneshot
ExecStart=/usr/local/with_testfile_vars /usr/bin/testmebinary $VOLUMES

[Install]
WantedBy=multi-user.target

No EnvironmentFile needed at all, no ordering dependencies around how exactly it's interpreted, no concerns about how systemd's parsing differs from a shell's, etc.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Thanks! Unfortunately this no more works as `systemd` (nowadays) seems to not honour shebang lines. So you'll have to write `ExecStart=/bin/sh /usr/local/with_testfile_vars /usr/bin/testmebinary $VOLUMES`. – Axel Beckert Jan 13 '21 at 03:11
  • 1
    @AxelBeckert, shebangs are honored by the kernel after the `execve()` syscall has been invoked, not by any individual application (whose responsibility in starting another application ends at invoking that call). I run scripts using various interpreters (which require a shebang to be honored) from systemd all the time. – Charles Duffy Jan 13 '21 at 03:12
  • @AxelBeckert, ...I'm not sure Stack Overflow is the right place for it, but if you post a reproducer for the problem you're encountering (maybe at [unix.se]?) and @-notice me, I'd be happy to take a look. Be sure the question includes how file permissions are set; any filesystem flags (like `noexec`) that might influence success of the `execve` syscall; the exact byte-for-byte contents of that shebang line represented in a manner that reflects hidden or nonprintable characters (such as a BOM, or a character encoding like UTF-16), etc. – Charles Duffy Jan 13 '21 at 03:15
  • 1
    Sorry, false alarm. There was a typo in the shebang line. – Axel Beckert Jan 13 '21 at 03:28