10

I have multiple systemd services that require a generated EnvironmentFile. I have a shell script which generates this Environment file, but since I need that environment file before any Exec... commands execute, I cannot use ExecStartPre=generate_env_file.sh . Therefore, I have another service (generate_env_file.service) set to run that script as a oneshot:

[Service]
Type=oneshot
ExecStartPre=/usr/bin/touch /path/to/config.ini
ExecStart=/path/to/generate_env_file.sh

and I have multiple other service files which have:

[Unit]
Requires=generate_env_file.service
After=generate_env_file.service

How can I guarantee that two or more dependent services (which require generate_env_file.service) will not run in parallel and spawn two parallel executions of generate_env_file.service?

I've looked at using RemainAfterExit=true or possibly StartLimitIntervalSec= and StartLimitBurst= to ensure that only one copy will execute at a time during some period but I'm not sure the best way to go about doing this.

0

3 Answers 3

11

RemainAfterExit=true is the way to go. In this case Systemd starts the service and Systemd considers it as started and live. However this doesn't cover the use case of executing systemctl restart generate_env_file.service. In this case systemd will re-execute your service. To solve this, you could create a marker file in the run file system in ExecStartPost= and add ConditionPathExists= directive to check the existence of file.

0
2

ConditionFirstBoot may also be interesting:

Takes a boolean argument. This condition may be used to conditionalize units on whether the system is booting up for the first time. This roughly means that /etc/ was unpopulated when the system started booting (for details, see "First Boot Semantics" in machine-id(5)). First boot is considered finished (this condition will evaluate as false) after the manager has finished the startup phase.

This condition may be used to populate /etc/ on the first boot after factory reset, or when a new system instance boots up for the first time.

For robustness, units with ConditionFirstBoot=yes should order themselves before first-boot-complete.target and pull in this passive target with Wants=. This ensures that in a case of an aborted first boot, these units will be re-run during the next system startup.

If the systemd.condition-first-boot= option is specified on the kernel command line (taking a boolean), it will override the result of this condition check, taking precedence over /etc/machine-id existence checks.

0

Update generate_env_file.sh to check to see if a lock file exists as soon as is starts. If the lock file exists, exit immediately.

If no lock file exists, touch the lock file immediately, then go about the business of generating the config file, then remove the lock file.

Put another way, I don't think systemd has a native way to handle the situation you are describing through configuration, so use a lock file.

And as @shellter points out, the Unix site is a more appropriate site for systemd questions in the future.

You must log in to answer this question.