LostGoneAndNotFound
LostGoneAndNotFound

Reputation: 103

systemd: use variables in a unit file

I have unit files for bunch of services. In ExecStart I want to refer to directory part of a path name using a variable so that I can easily update many unit files in case a location of executables changes.

I am using EnvironmentFile to define the variables and source the file inside a unit file. However it appears that variables are not visible inside a unit file itself but only in the environment (I haven't tested it to see if they are indeed visible in the environment). Is there any other, idomatic way to use variable for dynamic configuration?

EnvironmentFile

[Service]
Environment=MYS_PATH=/opt/myservice
Environment=MYS_USER=user

Unit file

[Unit]
Description=My service
After=network.target

[Service]
EnvironmentFile=/etc/systemd/system/myservice.service.d/myservice_defs.conf
Type=simple
User=${MYS_USER}
WorkingDirectory=${MYS_PATH}
ExecStart=${MYS_PATH}/usr/bin/myservice -C ${MYS_PATH}/etc/myservice.conf

Upvotes: 7

Views: 13305

Answers (1)

aleivag
aleivag

Reputation: 2406

The short answer is "That is not how you use a EnvironmentFile", a EnvironmentFile should be in the form of just key value (without the Enviroment) prefix.

MYS_PATH=/opt/myservice
MYS_USER=user

what you where describing was a service overwrite and that is another thing all together, sadly your environmental variables only works on the context of the service you are launching and not the systemd unit itself. you still can use them for the Excec start except for defining the path to the binary).

But there some ways to achive what you want.

pystemd.run or systemd-run

You can create transient units, that do not survive restarts on your system, but can be programatically defined or on the fly, my favorite (for obvious reasons) is pystemd.run but you can use systemd-run also, the first one is a python library and the second one is a cli-tool

pystemd.run

# install pystemd
[root@~] pip install pystemd
[root@~] python
>>> import pystemd.run
>>> MYS_PATH='/opt/myservice'
>>> MYS_USER='user'
>>> pystemd.run([f'{MYS_PATH}/usr/bin/myservice', '-C' f'{MYS_PATH}/etc/myservice.conf'], cwd=MYS_PATH, user=MYS_USER) 

and you can do all sort of stuff because you are in python world.

systemd-run

[root@~] MYS_PATH='/opt/myservice'
[root@~] MYS_USER='user'
[root@~] systemd-run --uid ${MYS_USER} -p WorkingDirectory=${MYS_PATH} ${MYS_PATH}/usr/bin/myservice -C ${MYS_PATH}/etc/myservice.conf 

Using templates

also if you can avoid having multiple configurations you can always set template units, you just rename your unit from myservice.service to [email protected]. Then every time you start a unit you do it like systemctl start [email protected]

then on your unit you can use configsetting as %i anywhere you want, like this

[Unit]
Description=My service
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/myservice -C /etc/myservice/%i.conf

if you ask me... go with pystemd.run or systemd-run

Upvotes: 6

Related Questions