You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
blog/_posts/2019-07-04-from-crontabs-to...

180 lines
4.7 KiB

3 years ago
---
title: From crontabs to Systemd timers
1 year ago
tags: [tutorial, bash, shell, crontab, cronie, systemd, timer]
updated: 2021-09-13 14:07:00
description: The steps I followed to migrate from crontabs to systemd timers.
3 years ago
---
## Introduction
<!--excerpt_start-->
3 years ago
Since I started my own server at home I have always use crontabs to handle
recurring tasks such as backups.
<!--excerpt-end-->
3 years ago
*Please note that every step described here is directly related to the
[automated-tasks](https://github.com/frnmst/automated-tasks) repository.*
3 years ago
The problem of this method is that you cannot
easily control running processes and you are not provided with a uniform interface.
Systemd service and timer unit files seem to solve these issues. As usual,
I followed the [Arch](https://wiki.archlinux.org/index.php/Systemd/Timers)
3 years ago
[wiki](https://wiki.archlinux.org/index.php/Systemd#Writing_unit_files).
## Preparation
To avoid complications, I prefer having all relevant scripts of all the users
3 years ago
in one place.
### Users and groups
I created a new user and group called `jobs`
# useradd -m -s /bin/bash -U jobs
3 years ago
Every user `${user}` that needs to perform some task must be added to the
`jobs` group.
# usermod -aG jobs ${user}
### New directories
Scripts and services are separated into two different directories. We will make
these directories accessible to the `jobs` group only.
# mkdir -p /home/jobs/{scripts,services}/by-user
# chmod -R 070 /home/jobs
# chown -R jobs:jobs /home/jobs
## Example
As an example I will show you the unit files I wrote for one
of my [daily backups]({{ site.baseurl }}/notes/my-backup-system.html).
### Script
Copy the [backup script]({{ site.baseurl }}/notes/my-backup-system.html#incremental-backup-script)
and the [configuration file]({{ site.baseurl }}/notes/my-backup-system.html#configuration-file)
3 years ago
in `/home/jobs/scripts/by-user/root`, and change ownerships and permissions
# chmod -R 700 /home/jobs/scripts/by-user/root
# chown -R root:root /home/jobs/scripts/by-user/root
Use the appropriate user and group for the ownership.
### Service unit file
The service file is called `backup-data.service` and needs to be placed in
`/home/jobs/services/by-user/root`
```shell
[Unit]
Description=data backup
Requires=mnt-backup_data.mount
Requires=data.mount
After=mnt-backup_data.mount
After=data.mount
[Service]
Type=simple
ExecStart=-/home/jobs/scripts/by-user/root/backup.sh '/data/*' /mnt/backup_data
User=root
Group=root
[Install]
WantedBy=multi-user.target
```
### Timer unit file
Place the following timer file, called `backup-data.timer`,
under `/home/jobs/services/by-user/root`
```shell
[Unit]
Description=Once a day backup data
[Timer]
OnCalendar=*-*-* 4:00:00
Persistent=true
[Install]
WantedBy=timers.target
```
### Set the permissions and ownership
Since the backup-data files must be run by `root` we must fix the permissions
and ownerships
# chmod -R 700 /home/jobs/services/by-user/root
# chown -R root:root /home/jobs/services/by-user/root
Fix the ownerships with the appropriate user depending on the directory. These
steps are useful just to prevent mistakes. All these files
will be loaded by systemd and accessible from other users anyway, for example
via `/etc/systemd/system/backup-data.service`.
## Deployment
To simplify the deployment of the services and timers I wrote this script,
called `deploy.sh`, which needs to be placed in `/home/jobs/services`.
```shell
#!/usr/bin/env bash
set -euo pipefail
SRC_DIR='by-user/'
DST_DIR='/etc/systemd/system'
3 years ago
[ ${UID} -eq 0 ]
find "${SRC_DIR}" \( -name "*.service" -o -name "*.timer" \) \
-type f -exec cp {} "${DST_DIR}" \;
3 years ago
systemctl daemon-reload
timers=$(find "${SRC_DIR}" -name "*.timer" -type f -printf "%f\n")
3 years ago
systemctl start ${timers}
systemctl enable ${timers}
```
This script will copy the service and timer files in the appropriate directory and
enable the new timers. Before running it, change its permissions and ownership
# chown root:root /home/jobs/services/deploy.sh
# chmod 700 /home/jobs/services/deploy.sh
Now, run the previous script and check the status of the systemd timers
# cd /home/jobs/services
# ./deploy.sh
$ systemctl list-timers --all
You should see something like
NEXT LEFT LAST PASSED UNIT ACTIVATE
Fri 2019-07-05 04:00:00 CEST 9h left n/a n/a backup-data.timer backup-data.service
1 timer listed.
## File and directory structure
Here is a representation of the files and directories mentioned in this post
```
/home/jobs
|-- scripts
| |-- by-user
| `-- root
| |-- backup.conf
| |-- backup.sh
`-- services
|-- by-user
| `-- root
| |-- backup-data.service
| |-- backup-data.timer
`-- deploy.sh
```
~