Check condition command for systemd backups and forget/prune

I’m writing systemd services and timers to automate restic backups and forget/prune operations.
I’m doing weekly backups but forget/prune takes much longer than that.
I would like to use systemd's ExecCondition to check whether the repository is currently locked before actually attempting the backup. This option allows for the unit to skip running instead of failing.
Which commands could I use?

Below the current backup service:

[Unit]
Description=Restic backup

[Service]
Type=exec
EnvironmentFile=-/etc/restic.env
ExecCondition={{ command missing }}
ExecStart=/usr/local/bin/restic -o rclone.args='serve restic --stdio --b2-hard-delete --drive-use-trash=false --tpslimit 3 --tpslimit-burst 6 --fast-list' --exclude-file=/etc/restic.excludes --files-from=/etc/restic.includes --verbose backup
OnFailure=failure-email@%n.service
# Resource control
Nice=19
IOSchedulingClass=best-effort
IOSchedulingPriority=7

The current forget/prune service:

[Unit]
Description=Restic forget and prune

[Service]
Type=exec
EnvironmentFile=-/etc/restic.env
ExecCondition={{ command missing }}
ExecStart=/usr/local/bin/restic -o rclone.args='serve restic --stdio --b2-hard-delete --drive-use-trash=false --tpslimit 3 --tpslimit-burst 6 --fast-list' --verbose forget --prune --keep-weekly=8 --keep-monthly 12
OnFailure=failure-email@%n.service
# Resource control
Nice=19
IOSchedulingClass=best-effort
IOSchedulingPriority=7

And timer (identical for all):

[Unit]
Description=Restic backup timer

[Timer]
OnCalendar=weekly
RandomizedDelaySec=8h

[Install]
WantedBy=timers.target

restic list locks --no-lock does list all active locks. Note that this commands creates (and displays) its own lock, hence the --no-lock.

2 Likes

That’s a neat command, although I guess it could work even without the --no-lock.
ExecCondition states that:

[…] when the command exits with code 1 through 254 (inclusive), the remaining commands are skipped and the unit is not marked as failed. However, if an ExecCondition= command exits with 255 or abnormally (e.g. timeout, killed by a signal, etc.), the unit will be considered failed (and remaining commands will be skipped). Exit code of 0 or those matching SuccessExitStatus= will continue execution to the next command(s).

As the intended outcome is to skip execution, simply running restic list locks would fail if the repo is locked.
As an alternative the following would work:

if [ "$(wc -l <<< "$(restic list locks --no-lock --quiet)")" -ge 1 ]
then
    exit 1
else
    exit 0
fi

Oneline:

if [ "$(wc -l <<< "$(restic list locks --no-lock -q)")" -ge 1 ]; then exit 1; else exit 0; fi
1 Like

How about test -z "$(restic list locks --no-lock --quiet)" && exit 0 || exit 1

Isn’t && exit 0 || exit 1 redundant?

1 Like

Should this behaviour be considered a bug?

No, restic list can be used for any object type, not just locks. A read lock is taken to prevent disruption by concurrent activities that write to the repository, same as any restic command that reads from the repository.