[Unit] Description=Local CI/CD — weekly backup of VMware templates Documentation=file:///opt/ci/local-ci-cd-system/deploy/systemd/README.md After=network-online.target [Service] Type=oneshot User=root EnvironmentFile=/etc/ci/environment WorkingDirectory=/opt/ci/local-ci-cd-system # This service runs as root (to restart act-runner.service via ExecStopPost), # but the backups dir is shared with ci-web.service, which runs as ci-runner # and offers a manual "backup template" action. Guarantee the dir exists owned # by ci-runner *before* the root-owned backup writes into it, otherwise a first # root run would create /var/lib/ci/backups as root:root and lock ci-runner # (the web UI) out with errno=13. Idempotent; -o/-g re-assert ownership. ExecStartPre=/usr/bin/install -d -o ci-runner -g ci-runner -m 750 /var/lib/ci/backups # --keep-count 1: three generations of Windows templates cost ~195 GB and the # archives were byte-identical between runs (the templates rarely change), so # the extra generations bought nothing. --exclude WinBuildTest: retired test # template, ~26 GB per generation. ExecStart=/opt/ci/venv/bin/python -m ci_orchestrator template backup --all-templates --keep-count 1 --exclude WinBuildTest # Safety net: bring act-runner.service back up on any exit path (success, # failure, signal). The Python `finally` block can be skipped if the # service is killed mid-run, and a runner left stopped by a killed # backup would cause the next backup to skip the restart too. ExecStopPost=-/bin/systemctl start act-runner.service TimeoutStartSec=4h IOSchedulingClass=best-effort IOSchedulingPriority=7 Nice=19 ProtectSystem=strict ProtectHome=true PrivateTmp=true NoNewPrivileges=true ReadWritePaths=/var/lib/ci [Install] WantedBy=multi-user.target