简体   繁体   中英

Cant access environment variable in Python for systemd service

I was writing a systemd service named 'spliti3.service' which executes a Python script in /usr/bin/ to help automatically adjust windows within 2 columns vertically for my i3wm.

In my /etc/systemd/system/spliti3.service :

[Unit]
Description=Launches screen with my config
After=network.target

[Service]
Type=simple
User=raz0229
ExecStart=/usr/bin/spliti3
RemainAfterExit=true
StandardOutput=append:$HOME/log0.log
StandardError=append:$HOME/log1.log

[Install]
WantedBy=multi-user.target

Here's part of my Python code that is causing problems. In /usr/bin/spliti3 :

#!/usr/bin/python3

from i3ipc import Connection, Event
import os
.
.
.
sock_path = os.environ.get('I3SOCK') # Returns NoneType
c = Connection(sock_path)

Seems like the only way to get sock_path is either through the $I3SOCK or i3 --get-socket-path command and can't be hard coded in the script.

Also, the script works just fine when executed on my machine but gives error on os.environ.get('I3SOCK') when registered as a service through systemctl . In the log file, it suggests that sock_path is None which is odd.

I know there is something wrong with my spliti3.service but not sure what's causing it.

Cant access environment variable [...] for systemd service

[...]

the script works just fine when executed on my machine but gives error on os.environ.get('I3SOCK') when registered as a service through systemctl . In the log file, it suggests that sock_path is None which is odd.

It's not the least bit odd. You seem to be assuming that systemd will run the service in a login shell of the execution user, or at least one with an environment configured like a login shell's. This is not the case.

It is standard for service management frameworks such as systemd to run services in minimal environments. This serves security and stability objectives. Systemd provides more of an environment than some other frameworks do, but even so, it does not process the execution user's shell configuration files. I don't expect that it even launches the script via a shell in the first place. The environment variables you can rely upon by default are documented in the systemd manual .

Systemd does provide means by which your service file could specify additional environment variables to define for the processes it manages (see docs ). However, the only reason I can imagine that you could not hardcode the wanted value into your script is that it has to be determined dynamically at runtime. That would make it challenging to get systemd to set the appropriate value.

Seems like the only way to get sock_path is either through the $I3SOCK or i3 --get-socket-path command.

If the script can get it from an environment variable then in principle, the script could also get it via a command-line argument, read it from a file, obtain it from a web service, or get it many other ways.

In particular, if the command i3 --get-socket-path indeed provides the wanted information, then I don't see why you wouldn't have the script run that command and capture the output (at least, I assume that it's the program output that conveys the information). If you like, you could make it do that only as a fallback, in the event that the $I3SOCK environment variable is not set.


As a separate matter, it is unclear why you configure the service to execute as (it appears) your login user. That's not inherently wrong, and it may even be exactly what you want, but if so then you would probably be better off setting it up as a user unit instead of a system-wide unit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM