The idea is to create a keep-down.service that never starts:
[Unit]
Description=Keeps daemon down
Before=mydaemon.service
ConditionPathIsDirectory=/var/lib/dummy-never-existing-path
[Service]
ExecStart=/bin/true
[Install]
WantedBy=multi-user.target
So it's needed by the mydaemon.service. While keep-down.service is installed, the mydaemon.service can't start (theoretically).
Motivation:
no systemctl commands can start the mydaemon.service
no modifications to the mydaemon.service unit file
no messing with the config of the mydaemon.service
it's atomic: installing/removing the keep-down.service custom package
The problem is that mydaemon.service starts anyways. Why is that?
You have specified that your keep-down service must start before mydaemon.service:
Before=mydaemon.service
But you haven't actually configured any dependency between the two, such as:
RequiredBy=mydaemon.service
Details are in the systemd.unit man page, which for example says this about Before= and After=:
Note that this setting is independent of and orthogonal to the
requirement dependencies as configured by Requires=. It is a common
pattern to include a unit name in both the After= and Requires=
option, in which case the unit listed will be started before the
unit that is configured with these options.
However, all of this is really unnecessary. You can accomplish with you want using the systemctl mask command:
mask NAME...
Mask one or more unit files, as specified on the command line. This
will link these units to /dev/null, making it impossible to start
them. This is a stronger version of disable, since it prohibits all
kinds of activation of the unit, including enablement and manual
activation. Use this option with care. This honors the --runtime
option to only mask temporarily until the next reboot of the
system. The --now option can be used to ensure that the units are
also stopped.
So:
# systemctl mask mydaemon
Related
I'm trying to start a task when bluetooth is ready on a raspi (running raspbian 10 - buster) with systemd.
I've added the file /lib/systemd/system/my.service with this content
[Unit]
After=bluetooth.target
[Service]
Type=idle
ExecStart=/root/my.sh
[Install]
Wants=bluetooth.target
When I look at what happens on startup with the graph created by systemd-analyse plot, I see that my service is started way before the bluetooth.target unit is activated.
But when I check with systemctl show my.service, it says
...
After=basic.target bluetooth.target system.slice systemd-journald.socket sysinit.target
...
So can someone explains me why my service doesn't start after bluetooth.target?
Thanx
[edit]
I've followed advice from #ukBaz and moved my service file to /etc/systemd/system and moved the Wants stanza to the Unit section (actually I changed it to 'Requires').
So my file now contains
[Unit]
After=bluetooth.target
Requires=bluetooth.target
[Service]
Type=idle
ExecStart=/root/my.sh
[Install]
WantedBy=multi-user.target
Now my service starts after bluetooth.target... but bluetooth.target gets started very early!
And systemctl show bluetooth.target tells me 'After=bluetooth.service' so how come it is started/reached way before bluetooth.service?
The system’s copy of unit files are generally kept in the /lib/systemd/system directory. When software installs unit files on the system, this is the location where they are placed by default.
If you wish to modify the way that a unit functions or create your own, the best location to do so is within the /etc/systemd/system directory. Unit files found in this directory location take precedence over any of the other locations on the filesystem.
Wants should be in the [Unit] section not in the [Install] section.
[Install] section is optional and is used to define the behaviour of a unit if it is enabled or disabled. I have only every put WantedBy=multi-user.target in this section. The multi-user.target tells systemd (as I understand it) that it is needed for “normal operation”.
I am trying to setup a custom systemd service on my linux system and was experimenting with it
Following is my custom service, where it will trigger a bash file
[Unit]
Description=Example systemd service.
After=nginx.service
[Service]
Type=simple
ExecStart=/bin/bash /usr/bin/test_service.sh
[Install]
WantedBy=multi-user.target
Since I have mentioned After=nginx.service i was expecting nginx serivce to start automatically
So after starting the above service, i check the status of nginx, which has not started
However if i replace After with Wants it works
Can someone differenciate between After and Wants and when to use what?
Specifying After=foo tells systemd how to order the units if they are both started at the same time. It will not cause the foo unit to autostart.
Use After=foo in combination with Wants=foo or Requires=foo to start foo if it's not already started and also to keep desired order of the units.
So your [Unit] should include:
[Unit]
Description=Example systemd service.
After=nginx.service
Wants=nginx.service
Difference between Wants and Requires:
Wants= : This directive is similar to Requires= , but less strict. Systemd will attempt to start any units listed here when this unit is activated. If these units are not found or fail to start, the current unit will continue to function. This is the recommended way to configure most dependency relationships.
I have 2 services a.service and b.service.
a.service is shown
[Unit]
Description=My service
[Service]
Type=forking
ExecStart=/bin/sh /home/admin/run.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target,
b.service
[Unit]
Description=My service
[Service]
Type=forking
ExecStart=/bin/sh $HOME/theFolder/run.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target
Now, when i start b.service, i'm sure a.service will be started.
During runtime, suddenly someone messes with /home/admin/run.sh and systemd is unable to start a.service (also systemctl status a.service shows failed as status). Now is there a option so that b.service can know that a.service is failed and it should stop/exit?
You want to add either BindsTo= or Requires= to your [Unit] section, as documented in man systemd.unit:
Requires=
Configures requirement dependencies on other units. If this unit gets activated, the units listed here
will be activated as well. If one of the other units gets deactivated or its activation fails, this unit
will be deactivated. This option may be specified more than once or multiple space-separated units may
be specified in one option in which case requirement dependencies for all listed names will be created.
Note that requirement dependencies do not influence the order in which services are started or stopped.
This has to be configured independently with the After= or Before= options. If a unit foo.service
requires a unit bar.service as configured with Requires= and no ordering is configured with After= or
Before=, then both units will be started simultaneously and without any delay between them if
foo.service is activated. Often, it is a better choice to use Wants= instead of Requires= in order to
achieve a system that is more robust when dealing with failing services.
BindsTo=
Configures requirement dependencies, very similar in style to Requires=, however in addition to this
behavior, it also declares that this unit is stopped when any of the units listed suddenly disappears.
Units can suddenly, unexpectedly disappear if a service terminates on its own choice, a device is
unplugged or a mount point unmounted without involvement of systemd.
We have an embedded target environment (separate from out host build environment) in which systemd is running but not cron.
We also have a script which, under most systems, I would simply create a cron entry to run it every five minutes.
Now I know how to create a service under systemd but this script is a one-shot that exits after it's done its work. What I'd like to do is have it run immediately on boot (after the syslog.target, of course) then every five minutes thereafter.
After reading up on systemd timers, I created the following service file is /lib/systemd/system/xyzzy.service:
[Unit]
Description=XYZZY
After=syslog.target
[Service]
Type=simple
ExecStart=/usr/bin/xyzzy.dash
and equivalent /lib/systemd/system/xyzzy.timer:
[Unit]
Description=XYZZY scheduler
[Timer]
OnBootSec=0min
OnUnitActiveSec=5min
[Install]
WantedBy=multi-user.target
Unfortunately, when booting the target, the timer does not appear to start since the output of systemctl list-timers --all does not include it. Starting the timer unit manually seems to work okay but this is something that should be run automatically with user intervention.
I would have thought the WantedBy would ensure the timer unit was installed and running and would therefore start the service periodically. However, I've noticed that the multi-user.target.wants directory does not actually have a symbolic link for the timer.
How is this done in systemd?
The timer is not active until you actually enable it:
systemctl enable xyzzy.timer
If you want to see how it works before rebooting, you can also start it:
systemctl start xyzzy.timer
In terms of doing that for a separate target environment where you aren't necessarily able to easily run arbitrary commands at boot time (but do presumably control the file system content), you can simply create the same symbolic links (in your development area) that the enable command would do.
For example (assuming SYSROOT identifies the root directory of the target file system):
ln -s ${SYSROOT}/lib/systemd/system/xyzzy.timer
${SYSROOT}/lib/systemd/system/multi-user.target.wants/xyzzy.timer
This will effectively put the timer unit into an enabled state for the multi-user.target, so systemd will start it with that target.
Also, normally your custom files would be stored in /etc/systemd/system/. The equivalent lib directory is intended to host systemd files installed by packages or the OS.
If it's important that your cron job run precisely every 5 minutes, you should check the accuracy because systemd's monotonic timers can slip over time
I'm trying to get a nodejs server to run on startup, so I created the following systemd unit file:
[Unit]
Description=TI SensorTag Communicator
After=network.target
[Service]
ExecStart=/usr/bin/node /home/pi/sensortag-comm/sensortag.js
User=root
[Install]
WantedBy=multi-user.target
I'm not sure what I'm doing wrong here. It seems to fail before the nodejs script even starts, as no logging occurs. My script is dependent on mysql 5.5 (I think this is where I'm running into an issue). Any insight, or even a different solution would be appreciated.
Also, it runs fine once I'm logged into the system.
Update
The service is enabled, and is logging through journalctl. I'll update with the results on 7/11/16.
Not sure why it didn't work the first time, but upon checking journalctl the issue was 100% that MySQL hadn't started. I once again changed it to After=MySQL.service and it worked perfectly!
If there is no mention of the service at all in the output of journalctl that could indicate that the service was not enabled to start at boot.
Make you run systemctl enable my-unit-name before your next boot test.
Also, since you depend on MySQL being up and running, you should declare that with something like: After=mysql.service. The exact service name may depend on your Linux distribution, which you didn't state.
Adding User=root adds nothing, as system units would be run by root by default anyway.
When you said "it fails", you didn't specify whether it was failing at boot time, or with a test run by systemctl start my-unit-name.
After attempting to start a service, there should be logging if you run journalctl -u my-unit.name.service.
You might also consider adding StandardOutput=journal to your unit file to make sure you capture output from the service you are running as well.