#+TITLE: =systemd= services and timers #+SETUPFILE: ./setup/org-setup-file.org https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units * =braingit= - Automatic commit and push new brain pages ** Service :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/braingit.service :header-args+: :comments both :mkdirp yes :END: #+BEGIN_SRC conf [Unit] Description=Sync Brain Website everyday RefuseManualStart=no RefuseManualStop=yes OnFailure=notify-via-gotify@%i.service [Service] Environment="PASSWORD_STORE_DIR=/home/thomas/.local/share/pass" Environment="GNUPGHOME=/home/thomas/.local/share/gnupg" Type=oneshot ExecStart=%h/.local/bin/brain_git_push #+END_SRC ** Timer :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/braingit.timer :header-args+: :comments both :mkdirp yes :END: #+BEGIN_SRC conf [Unit] Description=Sync Brain Website everyday RefuseManualStart=no RefuseManualStop=no Wants=network-online.target After=network-online.target [Timer] Persistent=false OnBootSec=30min OnUnitActiveSec=1d Unit=braingit.service [Install] WantedBy=default.target #+END_SRC ** Script :PROPERTIES: :header-args: :tangle ~/.local/bin/brain_git_push :header-args+: :comments both :mkdirp yes :header-args+: :shebang "#!/usr/bin/env bash" :END: #+begin_src bash cd /home/thomas/Cloud/programming/brain-website/ if [[ ! -z $(git status -s content/) ]] then git add content static && \ git commit -m "Update Content - $(date +%F)" && \ git push exit fi #+end_src * =notify-via-gotify= - Notify ** Service :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/notify-via-gotify@.service :header-args+: :comments both :mkdirp yes :END: #+begin_src conf [Unit] Description=%i failure notification over gotify [Service] Environment="PASSWORD_STORE_DIR=/home/thomas/.local/share/pass" Environment="GNUPGHOME=/home/thomas/.local/share/gnupg" Type=oneshot ExecStart=/bin/bash -c "systemctl status -n10 %i | ~/.local/bin/create-gotify-notification-for-systemd --unit %i --host %H | curl -XPOST \"https://gotify.tdehaeze.xyz/message?token=$(pass nas/gotify_notif_token | sed -n 1p)\" -H \"Content-Type: application/json\" --data-binary @-" #+end_src ** Script :PROPERTIES: :header-args: :tangle ~/.local/bin/create-gotify-notification-for-systemd :header-args+: :comments both :mkdirp yes :header-args+: :shebang "#!/usr/bin/env python3" :END: #+begin_src python import json import argparse import sys TITLE_TEMPLATE = "Systemd unit failed" MESSAGE_TEMPLATE = "Systemd unit {unit} failed on host {host}." def main(): arguments = parse_arguments() status = "\n".join(" " + line.rstrip() for line in sys.stdin.readlines()) message = MESSAGE_TEMPLATE.format(unit=arguments.unit, host=arguments.host, status=status) title = TITLE_TEMPLATE.format(unit=arguments.unit, host=arguments.host) output = create_gotify_json(title, message, arguments.priority) print(output) def parse_arguments(): parser = argparse.ArgumentParser( description="Create Gotify notification for failing systemd unit", ) parser.add_argument( "--unit", default="unknown", help="the failing systemd unit name", ) parser.add_argument( "--host", default="unknown", help="the failing systemd unit host", ) parser.add_argument( "--priority", default="5", type=int, help="the notification priority", ) return parser.parse_args() def create_gotify_json(title, message, priority): data = { "title": title, "message": message, "priority": priority, "extras": { "client::display": { "contentType": "text/markdown" }, }, } return json.dumps(data) if __name__ == '__main__': main() #+end_src * =checkmail= - Check new mails ** Service :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/checkmail.service :header-args+: :comments both :mkdirp yes :END: #+BEGIN_SRC conf [Unit] Description=Check new mails RefuseManualStart=no RefuseManualStop=yes OnFailure=notify-via-gotify@%i.service [Service] Environment="PASSWORD_STORE_DIR=/home/thomas/.local/share/pass" Environment="GNUPGHOME=/home/thomas/.local/share/gnupg" Type=oneshot ExecStart=%h/.local/bin/checkmail -q #+END_SRC ** Timer :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/checkmail.timer :header-args+: :comments both :mkdirp yes :END: #+BEGIN_SRC conf [Unit] Description=Check Mail every x minutes RefuseManualStart=no RefuseManualStop=no Wants=network-online.target After=network-online.target [Timer] Persistent=false OnBootSec=2min OnUnitActiveSec=5min AccuracySec=2min Unit=checkmail.service [Install] WantedBy=default.target #+END_SRC ** Script :PROPERTIES: :header-args: :tangle ~/.local/bin/checkmail :header-args+: :comments both :mkdirp yes :header-args+: :shebang "#!/usr/bin/env bash" :END: #+begin_src bash while [ -n "$1" ]; do # while loop starts case "$1" in -a) opt_all='--all' ;; # Check All inboxes -v) opt_verbose='--verbose' ;; # Verbose -q) opt_quiet='--quiet' ;; # Quiet ,*) echo "Option $1 not recognized" ;; # In case you typed a different option esac shift done # Count number of new mails before retreiving mails gmail_old="$(ls ~/.local/share/mails/gmail/Inbox/new | wc -l)" esrf_old="$(ls ~/.local/share/mails/esrf/Inbox/new | wc -l)" # Retreive mails mbsync -c /home/thomas/.config/isync/mbsyncrc $opt_all $opt_verbose gmail-Home esrf-Home 2>/tmp/mbsync.log # Count number of new mails after retreiving mails gmail_new="$(ls ~/.local/share/mails/gmail/Inbox/new | wc -l)" esrf_new="$(ls ~/.local/share/mails/esrf/Inbox/new | wc -l)" # Notification if there are new retreive mails if [ "$(($esrf_new+$gmail_new))" -gt "$(($esrf_old+$gmail_old))" ]; then dunstify --replace=98465 'Mails ' "$(($gmail_new+$esrf_new)) new mail(s)" fi # Indexation and Tags mu index $opt_verbose $opt_quiet #+end_src * =syncmail= - Synchronize all mails ** Service :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/syncmail.service :header-args+: :comments both :mkdirp yes :END: #+BEGIN_SRC conf [Unit] Description=Sync all mails RefuseManualStart=no RefuseManualStop=yes OnFailure=notify-via-gotify@%i.service [Service] Environment="PASSWORD_STORE_DIR=/home/thomas/.local/share/pass" Environment="GNUPGHOME=/home/thomas/.local/share/gnupg" Type=oneshot ExecStart=%h/.local/bin/checkmail -a -q #+END_SRC ** Timer :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/syncmail.timer :header-args+: :comments both :mkdirp yes :END: #+BEGIN_SRC conf [Unit] Description=Sync All Mails every x hours RefuseManualStart=no RefuseManualStop=no Wants=network-online.target After=network-online.target [Timer] Persistent=false OnBootSec=30min OnUnitActiveSec=300min AccuracySec=10min Unit=syncmail.service [Install] WantedBy=default.target #+END_SRC * =vdirsyncer= - Synchronize calendar and contacts ** Service :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/vdirsyncer.service :header-args+: :comments both :mkdirp yes :END: #+begin_src conf [Unit] Description=Synchronize calendars and contacts Documentation=https://vdirsyncer.readthedocs.org/ Wants=network-online.target After=network-online.target OnFailure=notify-via-gotify@%i.service [Service] Environment="PASSWORD_STORE_DIR=/home/thomas/.local/share/pass" Environment="GNUPGHOME=/home/thomas/.local/share/gnupg" ExecStart=/usr/bin/vdirsyncer --verbosity "ERROR" sync Type=oneshot #+end_src ** Timer :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/vdirsyncer.timer :header-args+: :comments both :mkdirp yes :END: #+begin_src conf [Unit] Description=Synchronize vdirs [Timer] OnBootSec=5m OnUnitActiveSec=15m AccuracySec=5m [Install] WantedBy=timers.target #+end_src * =syncthing= - Synchronize =Cloud= directory ** Service :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/syncthing.service :header-args+: :comments both :mkdirp yes :END: #+begin_src conf [Unit] Description=Syncthing - Open Source Continuous File Synchronization for %I Documentation=man:syncthing(1) After=network.target [Service] Environment="all_proxy=socks5://localhost:8080" ExecStart=/usr/bin/syncthing --no-browser --gui-address="0.0.0.0:8384" --no-restart --logflags=0 Restart=on-failure SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=default.target #+end_src * =restic-backup= - Backup Home Directory ** Backup *** Service :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/restic-backup.service :header-args+: :comments both :mkdirp yes :END: #+BEGIN_SRC conf [Unit] Description=Backup Home Directory RefuseManualStart=no RefuseManualStop=no OnFailure=notify-via-gotify@%i.service [Service] Environment="PASSWORD_STORE_DIR=/home/thomas/.local/share/pass" Environment="GNUPGHOME=/home/thomas/.local/share/gnupg" Type=oneshot ExecStart=%h/.local/bin/restic-backup ExecStartPost=/bin/sleep 30 ExecStartPost=%h/.local/bin/restic-forget #+END_SRC *** Timer :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/restic-backup.timer :header-args+: :comments both :mkdirp yes :END: #+BEGIN_SRC conf [Unit] Description=Backup Home Directory Everyday RefuseManualStart=no RefuseManualStop=no Wants=network-online.target [Timer] Persistent=true OnCalendar=daily Unit=restic-backup.service [Install] WantedBy=default.target #+END_SRC *** Script - Backup :PROPERTIES: :header-args: :tangle ~/.local/bin/restic-backup :header-args+: :comments both :mkdirp yes :header-args+: :shebang "#!/usr/bin/env bash" :END: #+begin_src bash restic backup \ -r sftp:thomas@homelab:/srv/storage/Backups/esrf-laptop \ --password-command "pass show restic" \ --verbose --one-file-system --tag systemd.timer \ --exclude "/home/thomas/.cache" \ --exclude "/home/thomas/.local/data/docker" \ --exclude "/home/thomas/.local/soft" \ --exclude "/home/thomas/Cloud" \ --exclude "/home/thomas/mnt" \ /home/thomas #+end_src *** Script - Forget :PROPERTIES: :header-args: :tangle ~/.local/bin/restic-forget :header-args+: :comments both :mkdirp yes :header-args+: :shebang "#!/usr/bin/env bash" :END: #+begin_src bash restic unlock \ -r sftp:thomas@homelab:/srv/storage/Backups/esrf-laptop \ --password-command "pass show restic" && \ restic forget \ -r sftp:thomas@homelab:/srv/storage/Backups/esrf-laptop \ --password-command "pass show restic" \ --verbose --tag systemd.timer \ --group-by "paths,tags" \ --keep-daily 7 \ --keep-weekly 4 \ --keep-monthly 1 \ --keep-yearly 1 #+end_src ** Prune *** Service :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/restic-prune.service :header-args+: :comments both :mkdirp yes :END: #+BEGIN_SRC conf [Unit] Description=Prune restic backup RefuseManualStart=no RefuseManualStop=no OnFailure=notify-via-gotify@%i.service [Service] Environment="PASSWORD_STORE_DIR=/home/thomas/.local/share/pass" Environment="GNUPGHOME=/home/thomas/.local/share/gnupg" Type=oneshot ExecStart=%h/.local/bin/restic-prune #+END_SRC *** Timer :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/restic-prune.timer :header-args+: :comments both :mkdirp yes :END: #+BEGIN_SRC conf [Unit] Description=Prune Restic Backup RefuseManualStart=no RefuseManualStop=no Wants=network-online.target [Timer] Persistent=true OnCalendar=monthly Unit=restic-prune.service [Install] WantedBy=default.target #+END_SRC *** Script :PROPERTIES: :header-args: :tangle ~/.local/bin/restic-prune :header-args+: :comments both :mkdirp yes :header-args+: :shebang "#!/usr/bin/env bash" :END: #+begin_src bash restic prune \ -r sftp:thomas@homelab:/srv/storage/Backups/esrf-laptop \ --password-command "pass show restic" \ #+end_src * =homelab-tunnel= - SSH Tunnel Useful to bypass firewalls. This can we used on the browser: - for =qutebrowser=, use =:set content.proxy socks5://localhost:8080= (can setup a shortcut for that) This is also used for Syncthing. ** Service :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/homelab-tunnel.service :header-args+: :comments both :mkdirp yes :END: #+begin_src conf [Unit] Description=Setup a secure tunnel with homelab After=network.target [Service] ExecStart=/usr/bin/ssh -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -D 8080 -q -N -T homelab # Restart every >2 seconds to avoid StartLimitInterval failure RestartSec=5 Restart=always [Install] WantedBy=default.target #+end_src * =esrf-tunnel= - SSH Tunnel ** Service :PROPERTIES: :header-args: :tangle ~/.config/systemd/user/esrf-tunnel.service :header-args+: :comments both :mkdirp yes :END: #+begin_src conf [Unit] Description=Setup a secure tunnel with ESRF After=network.target [Service] ExecStart=/usr/bin/ssh -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -D 8081 -q -N -T firewall.esrf.fr # Restart every >2 seconds to avoid StartLimitInterval failure RestartSec=5 Restart=always [Install] WantedBy=default.target #+end_src