4

I am trying to pass an environment variable defined in the current shell to one of the systemd unit I am writing.

DB_URL=databus.dev.mysite.io:8080

I am using this in a python script which is running as a service. My systemd unit will run this script as a unit making use of the variable for its working.

[Unit]
Description=device-CompStatus: Computes device availability status

[Service]
Type=simple    
ExecStart=/usr/bin/bash -c "/usr/bin/python /opt/deviceCompStatus/deviceCompStatusHandler.py"
Restart=always

[Install]
WantedBy=default.target

The way am using the variable in Python script would be

if os.environ.get('DB_URL') is not None:
    dbEndPoint = "http://" + os.environ['DB_URL']

The problem is am not able to use the variable when running the script in systemd. I looked up couple of resources Using environment variables in systemd units, it says to use assignment under [Service] directly as

[Service]
Environment=DB_URL=databus.dev.mysite.io:8080

As you can see, my DB_URL could change depending upon the environment I am deploying my machine, it could be a developer, or a production setup, in which the URLs would vary.

How do I do this dynamically? i.e. pass whatever value available to DB_URL to systemd environment?

I also tried using the EnvironmentFile= option to define a file and pass it to service. But the same problem again, my variable could be dynamic and cannot be hardcoded.

Update

After using the option

systemctl import-environment DB_URL

I am able to see the variable available in the environment of systemd which I confirmed by

systemctl show-environment
DB_URL=databus.dev.mysite.io:8080
LANG=en_US.UTF-8
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

but still the value is not reflected in the python application which I run. Is os.environ('DB_URL') a wrong way to access the variable?

10

You can affect the global systemd environment for all future commands by using

 sudo systemctl set-environment var=value

or if you already have var exported in your environment, you can use

 sudo systemctl import-environment var

After starting your unit you can remove the variable with unset-environment similarly.

As this is global in effect you would be better off simply writing the line DB_URL=databus.dev.mysite.io:8080 into some file /some/file and setting EnvironmentFile=/some/file in your unit.

An alternative method is to use a template unit myunit@.service which is started with systemctl start myunit@'databus.dev.mysite.io:8080'. You can then recover this parameter as %i inside the unit, for example in the [Service] section with a line like:

Environment=DB_URL=%i
  • Great suggestions! Thanks! How do you suggest this for a file for the third option under /some/file? Assuming I define it as IDB_URL=${IDB_URL} in the file? Is that right where the RHS side is the environment variable and LHS would be the the variable I want to pass to systemd. How would this be passed to the unit? – Inian Aug 2 '17 at 12:53
  • The contents of the file are not evaluated. You cannot use bash-style variables in the RHS. You need to write the file with the real RHS value databus.dev.mysite.io:8080 before starting the unit. – meuh Aug 2 '17 at 12:58
  • Fair point! But as I said before, my contents are dynamic, I cannot know the variable contents beforehand? So you suggest options 1) or 2) for this then? – Inian Aug 2 '17 at 12:58
  • Also an assignment like sudo systemctl set-environment DB_URL=${DB_URL} would be allowed to pass the environment to systemd? – Inian Aug 2 '17 at 13:00
  • 2
    The way that the systemd people themselves would have us do this is to have a .conf file snippet, individual to each target platform and generated with echo into /etc/systemd/system/deviceCompStatus.service.d, that adds Environment=DB_URL=development.example:8080 to the service unit. – JdeBP Aug 2 '17 at 18:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.