2021-05-31 15:37:32 +00:00
|
|
|
#+title: Exploring systemd features
|
|
|
|
#+date: "2021-05-20 22:37:22 +08:00"
|
2021-06-13 04:20:18 +00:00
|
|
|
#+date_modified: "2021-06-09 10:29:31 +08:00"
|
2021-05-31 15:37:32 +00:00
|
|
|
#+language: en
|
2021-06-13 04:20:18 +00:00
|
|
|
#+property: header-args :eval no
|
2021-05-31 15:37:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
systemd is a big tool for a big system.
|
|
|
|
Let's explore some of them from a perspective of a wannabe power user.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* systemd at user-level
|
|
|
|
|
|
|
|
systemd has the ability to run at user-level empowering the user to manage their own system with their own settings.
|
|
|
|
It immensely helps separating user-specific settings from the system-wide settings.
|
|
|
|
|
|
|
|
systemd looks for the units from certain paths.
|
|
|
|
You can look for them from the =systemd.unit.5= manual page.
|
|
|
|
|
|
|
|
To run systemd as a user instance, simply add a =--user= flag beforehand for =systemctl= and other systemd binaries, if applicable.
|
|
|
|
|
|
|
|
#+begin_src shell :results none
|
|
|
|
systemctl --user show-units
|
|
|
|
systemctl --user show-environment
|
|
|
|
systemctl --user start $SERVICE
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Timers as cron replacement
|
|
|
|
|
|
|
|
You can schedule tasks with timers.
|
|
|
|
If systemd is compiled with the feature, it makes cron unnecessary.
|
|
|
|
|
|
|
|
systemd has different ways to denote time.
|
|
|
|
|
|
|
|
- Timespans denote the duration — e.g., =100 seconds=, =5M 3w=.
|
|
|
|
- Timestamps refer to a specific point in time — e.g., =2021-04-02=, =today=, =now=.
|
|
|
|
- Calendar events can refer to more than one point of time — e.g., =*-*-4/2=, =Sun,Wed,Fri *-1/2-1/8=.
|
|
|
|
|
|
|
|
Here's an example of setting a timer for an example backup service.
|
|
|
|
The following timer unit sets it to execute every day at 18:00.
|
|
|
|
|
2021-06-13 04:20:18 +00:00
|
|
|
#+begin_src ini
|
2021-05-31 15:37:32 +00:00
|
|
|
[Unit]
|
|
|
|
Description=A deduplicated backup from my computer
|
|
|
|
Documentation=man:borg(1) https://borgbackup.readthedocs.io/
|
|
|
|
|
|
|
|
[Timer]
|
|
|
|
Unit=borg-backup.service
|
|
|
|
OnCalendar=*-*-* 18:00:00
|
|
|
|
Persistent=true
|
|
|
|
|
|
|
|
[Install]
|
|
|
|
WantedBy=graphical.target
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
This will trigger =borg-backup.service= from the load path.
|
|
|
|
But you can omit it if you named the timer unit file similarly (e.g., =borg-backup.timer= with =borg-backup.service=).
|
|
|
|
|
|
|
|
You can find more information about it from the =systemd.time.5= manual page.
|
|
|
|
Furthermore, systemd has a testing tool for time with ~systemd-analyze {timespan,timestamp,calendar}~.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Unit templates
|
|
|
|
|
|
|
|
You can create unit templates which is useful for simple services that only requires an argument.
|
|
|
|
Rather than creating individual simple service files, let systemd handle it.
|
|
|
|
|
|
|
|
For example, you may want to spawn a service for Borgmatic with multiple repos.
|
|
|
|
If you don't know templates, the dumb way to serve multiple repos is to create individual unit files for each.
|
|
|
|
If you want to schedule them, you also have to create a timer unit for each.
|
|
|
|
|
|
|
|
The more efficient solution is to use templates.
|
|
|
|
To make a unit template, there are only a handful of requirements:
|
|
|
|
|
|
|
|
- Addition of =%i= to represent the template value.
|
|
|
|
- The unit file name has to end with =@= (e.g., =unit-name@.service=, =unit-name@.timer=).
|
|
|
|
|
|
|
|
This could be compressed into a template for a service unit.
|
|
|
|
The following code shows how to create one.
|
|
|
|
|
|
|
|
#+begin_src ini
|
|
|
|
[Unit]
|
|
|
|
Description=Periodic safety backup for %i
|
|
|
|
Documentation=man:borg(1) https://www.borgbackup.org/
|
|
|
|
|
|
|
|
[Service]
|
|
|
|
Type=simple
|
|
|
|
ExecStart=borgmatic --config %i --verbose
|
|
|
|
|
|
|
|
[Install]
|
|
|
|
WantedBy=default.target
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
To use the service, you have to give it a value — e.g., ~systemctl --user start borg-backup@test.yaml.service~.
|
|
|
|
|
|
|
|
That's all good but what about scheduling them?
|
|
|
|
What if you want to create an archive every hour starting at 08:00?
|
|
|
|
You can just create a templated timer unit.
|
|
|
|
|
|
|
|
#+begin_src ini
|
|
|
|
[Unit]
|
|
|
|
Description=Periodic safety backup for %i
|
|
|
|
Documentation=man:borg(1) https://www.borgbackup.org/
|
|
|
|
|
|
|
|
[Timer]
|
|
|
|
Unit=borg-backup@%i.service
|
|
|
|
Calendar=08/1:00:00
|
|
|
|
Persistent=true
|
|
|
|
|
|
|
|
[Install]
|
|
|
|
WantedBy=default.target
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Transient units
|
|
|
|
|
|
|
|
You can create units on-the-go with =systemd-run=.
|
|
|
|
It generates transient unit files.
|
|
|
|
Though, this is oriented around service units, making it useful for one-time configurations and task scheduling.
|
|
|
|
|
|
|
|
Like most systemd-related binaries, this can configure in system- and user-level.
|
|
|
|
|
2021-06-13 04:20:18 +00:00
|
|
|
#+begin_src shell
|
2021-05-31 15:37:32 +00:00
|
|
|
# This will create a user-level service file with the given command as the task.
|
|
|
|
systemd-run --user borgmatic --config emergency-config.yaml --verbose
|
|
|
|
|
|
|
|
# Create a transient timer for the service.
|
|
|
|
systemd-run --user borg-backup@external-drive.service --on-calendar=12:00
|
|
|
|
#+end_src
|