"""Tests for systemd service and timer configuration""" import pytest testinfra_hosts = [ "borg-client", "borg-client-2", "borg-client-multi", "borg-client-nonroot", "borg-client-multi-keys", ] CLIENT_CONFIGS = { "borg-client": { "user": "root", "server": "borg-server", "schedule": "*-*-* 02:00:00", "success_exit_status": False, }, "borg-client-2": { "user": "root", "server": "borg-server-2", "schedule": "*-*-* 03:00:00", "success_exit_status": True, }, "borg-client-nonroot": { "user": "backupuser", "server": "borg-server", "schedule": "*-*-* 02:00:00", "success_exit_status": False, }, } MULTI_INSTANCE_CONFIGS = { "borg-client-multi": { "user": "root", "repos": ["configs", "home-data"], "schedules": { "configs": "*-*-* 02:00:00", "home-data": "*-*-* 04:00:00", }, }, "borg-client-multi-keys": { "user": "root", "repos": ["configs-keys", "home-data-keys"], "schedules": { "configs-keys": "*-*-* 02:00:00", "home-data-keys": "*-*-* 04:00:00", }, }, } @pytest.fixture def config(host): hostname = host.backend.hostname if hostname in CLIENT_CONFIGS: return {"type": "single", **CLIENT_CONFIGS[hostname]} return {"type": "multi", **MULTI_INSTANCE_CONFIGS[hostname]} class TestSystemdServiceFile: def test_service_file_exists(self, host, config): if config["type"] == "single": service = host.file( f"/etc/systemd/system/borg_backup@{config['server']}.service" ) assert service.exists assert service.user == "root" assert service.group == "root" assert service.mode == 0o644 else: for repo in config["repos"]: service = host.file(f"/etc/systemd/system/borg_backup@{repo}.service") assert service.exists assert service.user == "root" assert service.group == "root" def test_service_content(self, host, config): if config["type"] == "single": service = host.file( f"/etc/systemd/system/borg_backup@{config['server']}.service" ) assert service.contains("[Unit]") assert service.contains("[Service]") assert service.contains("[Install]") assert service.contains("Type=oneshot") assert service.contains("ExecStart=/usr/local/bin/run_borg_backup") else: for repo in config["repos"]: service = host.file(f"/etc/systemd/system/borg_backup@{repo}.service") assert service.contains("[Unit]") assert service.contains("[Service]") assert service.contains("[Install]") assert service.contains("Type=oneshot") def test_service_user(self, host, config): if config["type"] == "single": service = host.file( f"/etc/systemd/system/borg_backup@{config['server']}.service" ) assert service.contains(f"User={config['user']}") assert service.contains(f"Group={config['user']}") else: for repo in config["repos"]: service = host.file(f"/etc/systemd/system/borg_backup@{repo}.service") assert service.contains(f"User={config['user']}") assert service.contains(f"Group={config['user']}") def test_success_exit_status(self, host, config): if config["type"] != "single": return service = host.file( f"/etc/systemd/system/borg_backup@{config['server']}.service" ) assert service.exists if config["success_exit_status"]: assert service.contains("SuccessExitStatus=1 TEMPFAIL") else: assert not service.contains("SuccessExitStatus=") class TestSystemdTimerFile: def test_timer_file_exists(self, host, config): if config["type"] == "single": timer = host.file( f"/etc/systemd/system/borg_backup@{config['server']}.timer" ) assert timer.exists assert timer.user == "root" assert timer.group == "root" assert timer.mode == 0o644 else: for repo in config["repos"]: timer = host.file(f"/etc/systemd/system/borg_backup@{repo}.timer") assert timer.exists def test_timer_content(self, host, config): if config["type"] == "single": timer = host.file( f"/etc/systemd/system/borg_backup@{config['server']}.timer" ) assert timer.contains("[Unit]") assert timer.contains("[Timer]") assert timer.contains("[Install]") assert timer.contains("OnCalendar=") assert timer.contains("AccuracySec=") else: for repo in config["repos"]: timer = host.file(f"/etc/systemd/system/borg_backup@{repo}.timer") assert timer.contains("[Unit]") assert timer.contains("[Timer]") assert timer.contains("[Install]") assert timer.contains("OnCalendar=") assert timer.contains("AccuracySec=") def test_timer_schedule(self, host, config): if config["type"] == "single": timer = host.file( f"/etc/systemd/system/borg_backup@{config['server']}.timer" ) assert f"OnCalendar={config['schedule']}" in timer.content_string else: for repo in config["repos"]: timer = host.file(f"/etc/systemd/system/borg_backup@{repo}.timer") assert f"OnCalendar={config['schedules'][repo]}" in timer.content_string class TestSystemdState: def test_timer_enabled(self, host, config): if config["type"] == "single": timer_name = f"borg_backup@{config['server']}.timer" c = host.run(f"systemctl is-enabled {timer_name}") assert c.rc == 0 assert c.stdout.strip() == "enabled" else: for repo in config["repos"]: c = host.run(f"systemctl is-enabled borg_backup@{repo}.timer") assert c.rc == 0 assert c.stdout.strip() == "enabled" def test_timer_active(self, host, config): if config["type"] == "single": timer_name = f"borg_backup@{config['server']}.timer" c = host.run(f"systemctl is-active {timer_name}") assert c.rc == 0 else: for repo in config["repos"]: c = host.run(f"systemctl is-active borg_backup@{repo}.timer") assert c.rc == 0 def test_daemon_reload_ok(self, host, config): c = host.run("systemctl daemon-reload") assert c.rc == 0