Systemd: "Environment" Directive to Set Path

systemd: Environment directive to set PATH

You can't use EnvVars in Environment directives. The whole Environment= will be ignored. If you use EnvironmentFile=, then the specified file will be loaded without substitution. So PATH=/local/bin:$PATH would be exactly that, and this is probably not what you want.

Under CentOS7 the following works.

# /etc/systemd/system/nagios.service.d/env.conf
[Service]
Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"

> sudo systemctl daemon-reload
> sudo systemctl restart nagios
> sudo cat /proc/28647/environ
...
PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
...

systemd prepending /bin to Environment PATH

I created a test service that just printed out the path after setting Environment= with a new path, and found it worked as expected on Ubuntu 16.04 with systemd 229.

I conclude that something in your script is pre-pending /bin to your environment.

Nothing in the systemd.exec man page suggests that systemd is designed to behave the way you observe.

How to load environment variables for the process of a systemd service?

Environment can be set in systemd service file as below under Exec options

Environment=LD_LIBRARY_PATH=/usr/lib

Below is the official documentation of systemd Environment/EnvironmentFile usage

Environment=

Sets environment variables for executed processes. Takes a space-separated list of variable assignments. This option may be specified more than once, in which case all listed variables will be set. If the same variable is set twice, the later setting will override the earlier setting. If the empty string is assigned to this option, the list of environment variables is reset, all prior assignments have no effect. Variable expansion is not performed inside the strings, however, specifier expansion is possible. The $ character has no special meaning. If you need to assign a value containing spaces or the equals sign to a variable, use double quotes (") for the assignment.

Example:

Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
gives three variables "VAR1", "VAR2", "VAR3" with the values "word1 word2", "word3", "$word 5 6".

See environ(7) for details about environment variables.

EnvironmentFile=

Similar to Environment= but reads the environment variables from a text file. The text file should contain new-line-separated variable assignments. Empty lines, lines without an "=" separator, or lines starting with ; or # will be ignored, which may be used for commenting. A line ending with a backslash will be concatenated with the following one, allowing multiline variable definitions. The parser strips leading and trailing whitespace from the values of assignments, unless you use double quotes (").

The argument passed should be an absolute filename or wildcard expression, optionally prefixed with "-", which indicates that if the file does not exist, it will not be read and no error or warning message is logged. This option may be specified more than once in which case all specified files are read. If the empty string is assigned to this option, the list of file to read is reset, all prior assignments have no effect.

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).

Settings from these files override settings made with Environment=. If the same variable is set twice from these files, the files will be read in the order they are specified and the later setting will override the earlier setting.

Read more here

Using variable in command path for ExecStart in systemd service

You can't use variables in the actual command. systemd.service:

The command to execute must be an absolute path name. It may contain
spaces, but control characters are not allowed.

You might wan't to wrap it in a shell command (which does parameter expansion):

ExecStart=/bin/bash -c '/${TESTEXTSERVICESFILES}/syslog/bin/nxlog -c ${TESTCONFDATA}/syslog/nxlog.conf'

systemd script - environment file updated by ExecStartPre

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.

How to use environment variables in a .service script

You are looking for EnvironmentFile= directive in [Service] section.

EnvironmentFile=/path/to/some/textFile

Read here for more info.

systemd env vars from an executable script

In order to have the variables from custom_script.sh accessible from your Java process, you'll have to insert them into the environment somehow, in a way that systemd will be pleased with. The docs for the EnvironmentFile= directive say that any line that is not a parameter assignment statement with an = sign will be ignored. So we need to take your script and cook it down so that all we have left are the variables after running it.

What you can do is create an auxiliary "distillery" service that sources your custom_script.sh file and prints every value in the environment to another file called custom_script.env. Then you can provide the "distilled" environment file to the Java process in the EnvironmentFile directive.

So if your original service adds After= and Requires= like this,

[Unit]  
Description=My description
After=custom-script-distillery
Requires=custom-script-distillery

[Service]
Type=simple
User=myuser
EnvironmentFile=/path/to/my/custom_script.env
ExecStart=/path/to/my/start_script.sh
ExecStop=/path/to/my/stop_script.sh
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=30s

[Install]
WantedBy=multi-user.target

Then the distillery could look like this:

[Unit]
Description=My service to distill custom_script.sh to an EnvironmentFile

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c 'set -o allexport; source /path/to/my/custom_script.sh; set +o allexport; unset IFS; set | grep -v "^BASH" > /path/to/my/custom_script.env'


Related Topics



Leave a reply



Submit