diff options
| author | Colin Wilk <colin@wilk.cx> | 2026-07-02 18:10:04 +0200 |
|---|---|---|
| committer | Colin Wilk <colin@wilk.cx> | 2026-07-02 18:10:04 +0200 |
| commit | 50b914e77695fd1cdb294653f20143747e7e3b01 (patch) | |
| tree | b667145cd04e39abb52d1680fc61a17513ae0af6 /molecule/delete/tests/test_delete.py | |
| parent | 66e46df3d2a840bf62ef8084ad171041772db65e (diff) | |
| download | ansible-role-borgbackup-50b914e77695fd1cdb294653f20143747e7e3b01.tar.gz ansible-role-borgbackup-50b914e77695fd1cdb294653f20143747e7e3b01.zip | |
Add state: absent variable
Allow removing configuration for repositories.
Diffstat (limited to 'molecule/delete/tests/test_delete.py')
| -rw-r--r-- | molecule/delete/tests/test_delete.py | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/molecule/delete/tests/test_delete.py b/molecule/delete/tests/test_delete.py new file mode 100644 index 0000000..4c0d859 --- /dev/null +++ b/molecule/delete/tests/test_delete.py @@ -0,0 +1,318 @@ +"""Tests for state: absent functionality.""" + +import os + + +testinfra_hosts = [ + "borg-client-single-delete", + "borg-client-multi-delete", + "borg-client-per-repo-delete", + "borg-client-nonroot-delete", + "borg-client-never-delete", + "borg-server-delete", +] + + +def _scenario_file(filename): + scenario_dir = os.environ.get("MOLECULE_SCENARIO_DIRECTORY") + if scenario_dir: + return os.path.join(scenario_dir, filename) + test_dir = os.path.dirname(os.path.abspath(__file__)) + return os.path.join(test_dir, "..", filename) + + +def _read_local_file(filename): + with open(_scenario_file(filename), "r", encoding="utf-8") as file_handle: + return file_handle.read() + + +class TestSingleRepoDelete: + def test_systemd_units_removed(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-single-delete": + return + + timer = host.file("/etc/systemd/system/borg_backup@single-backup.timer") + service = host.file("/etc/systemd/system/borg_backup@single-backup.service") + assert not timer.exists + assert not service.exists + + def test_backup_scripts_removed(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-single-delete": + return + + repo_script = host.file("/usr/local/bin/run_borg_backup@single-backup") + base_script = host.file("/usr/local/bin/run_borg_backup") + assert not repo_script.exists + assert not base_script.exists + + def test_shared_ssh_key_kept(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-single-delete": + return + + key = host.file("/root/.ssh/id_rsa") + assert key.exists + + def test_repository_data_deleted(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-server-delete": + return + + repo = host.file("/opt/borg/single-backup") + assert not repo.exists + + def test_authorized_keys_entry_removed(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-server-delete": + return + + auth_keys = host.file("/opt/borg/.ssh/authorized_keys") + assert auth_keys.exists + assert "root@borg-client-single-delete" not in auth_keys.content_string + + +class TestMultiInstanceDelete: + def test_removed_repo_units_removed(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-multi-delete": + return + + timer = host.file("/etc/systemd/system/borg_backup@multi-repo-a.timer") + service = host.file("/etc/systemd/system/borg_backup@multi-repo-a.service") + script = host.file("/usr/local/bin/run_borg_backup@multi-repo-a") + assert not timer.exists + assert not service.exists + assert not script.exists + + def test_remaining_repo_artifacts_exist(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-multi-delete": + return + + timer = host.file("/etc/systemd/system/borg_backup@multi-repo-b.timer") + service = host.file("/etc/systemd/system/borg_backup@multi-repo-b.service") + script = host.file("/usr/local/bin/run_borg_backup@multi-repo-b") + assert timer.exists + assert service.exists + assert script.exists + + def test_base_script_keeps_only_remaining_block(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-multi-delete": + return + + base_script = host.file("/usr/local/bin/run_borg_backup") + assert base_script.exists + content = base_script.content_string + assert "/opt/borg/multi-repo-b" in content + assert "/opt/borg/multi-repo-a" not in content + assert content.count("borg create") == 1 + + def test_shared_ssh_key_kept(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-multi-delete": + return + + key = host.file("/root/.ssh/id_rsa") + assert key.exists + + def test_repository_data_kept(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-server-delete": + return + + removed_repo = host.file("/opt/borg/multi-repo-a") + remaining_repo = host.file("/opt/borg/multi-repo-b") + assert removed_repo.exists + assert removed_repo.is_directory + assert remaining_repo.exists + assert remaining_repo.is_directory + + def test_authorized_keys_keeps_only_remaining_repo(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-server-delete": + return + + auth_keys = host.file("/opt/borg/.ssh/authorized_keys") + content = auth_keys.content_string + host_entries = [ + line + for line in content.splitlines() + if "root@borg-client-multi-delete" in line + ] + assert len(host_entries) == 1 + assert "--restrict-to-repository /opt/borg/multi-repo-b" in host_entries[0] + assert "--restrict-to-repository /opt/borg/multi-repo-a" not in host_entries[0] + + +class TestPerRepoKeyDelete: + def test_removed_repo_artifacts_removed(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-per-repo-delete": + return + + timer = host.file("/etc/systemd/system/borg_backup@per-repo-a.timer") + service = host.file("/etc/systemd/system/borg_backup@per-repo-a.service") + script = host.file("/usr/local/bin/run_borg_backup@per-repo-a") + assert not timer.exists + assert not service.exists + assert not script.exists + + def test_remaining_repo_untouched(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-per-repo-delete": + return + + timer = host.file("/etc/systemd/system/borg_backup@per-repo-b.timer") + service = host.file("/etc/systemd/system/borg_backup@per-repo-b.service") + script = host.file("/usr/local/bin/run_borg_backup@per-repo-b") + base_script = host.file("/usr/local/bin/run_borg_backup") + assert timer.exists + assert service.exists + assert script.exists + assert base_script.exists + assert "/opt/borg/per-repo-b" in base_script.content_string + assert "/opt/borg/per-repo-a" not in base_script.content_string + + def test_per_repo_ssh_key_removed(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-per-repo-delete": + return + + key = host.file( + "/root/.ssh/id_ed25519_borgbackup_borg_server_delete_per_repo_a" + ) + key_pub = host.file( + "/root/.ssh/id_ed25519_borgbackup_borg_server_delete_per_repo_a.pub" + ) + assert not key.exists + assert not key_pub.exists + + def test_other_repo_ssh_key_kept(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-per-repo-delete": + return + + key = host.file( + "/root/.ssh/id_ed25519_borgbackup_borg_server_delete_per_repo_b" + ) + key_pub = host.file( + "/root/.ssh/id_ed25519_borgbackup_borg_server_delete_per_repo_b.pub" + ) + assert key.exists + assert key_pub.exists + + def test_repository_data_deleted_and_remaining_kept(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-server-delete": + return + + removed_repo = host.file("/opt/borg/per-repo-a") + remaining_repo = host.file("/opt/borg/per-repo-b") + assert not removed_repo.exists + assert remaining_repo.exists + + def test_authorized_keys_per_repo_entry_removed(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-server-delete": + return + + auth_keys = host.file("/opt/borg/.ssh/authorized_keys") + content = auth_keys.content_string + assert "--restrict-to-repository /opt/borg/per-repo-a" not in content + assert "--restrict-to-repository /opt/borg/per-repo-b" in content + + +class TestNonRootDelete: + def test_removed_repo_artifacts_removed(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-nonroot-delete": + return + + timer = host.file("/etc/systemd/system/borg_backup@nonroot-a.timer") + service = host.file("/etc/systemd/system/borg_backup@nonroot-a.service") + script = host.file("/usr/local/bin/run_borg_backup@nonroot-a") + assert not timer.exists + assert not service.exists + assert not script.exists + + def test_remaining_repo_and_shared_key_kept(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-nonroot-delete": + return + + timer = host.file("/etc/systemd/system/borg_backup@nonroot-b.timer") + service = host.file("/etc/systemd/system/borg_backup@nonroot-b.service") + script = host.file("/usr/local/bin/run_borg_backup@nonroot-b") + key = host.file("/home/backupuser/.ssh/id_rsa") + assert timer.exists + assert service.exists + assert script.exists + assert key.exists + + def test_authorized_keys_preserves_nonroot_comment(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-server-delete": + return + + auth_keys = host.file("/opt/borg/.ssh/authorized_keys") + content = auth_keys.content_string + host_entries = [ + line + for line in content.splitlines() + if "backupuser@borg-client-nonroot-delete" in line + ] + assert len(host_entries) == 1 + assert "root@borg-client-nonroot-delete" not in host_entries[0] + assert "--restrict-to-repository /opt/borg/nonroot-b" in host_entries[0] + assert "--restrict-to-repository /opt/borg/nonroot-a" not in host_entries[0] + + +class TestDecryptionKeyCleanup: + def test_deleted_entries_removed_and_remaining_kept(self): + content = _read_local_file("decryption_keys_delete.yml") + assert "borg-client-single-delete_single-backup:" not in content + assert "borg-client-multi-delete_multi-repo-a:" not in content + assert "borg-client-per-repo-delete_per-repo-a:" not in content + assert "borg-client-nonroot-delete_nonroot-a:" not in content + assert "borg-client-multi-delete_multi-repo-b:" in content + assert "borg-client-per-repo-delete_per-repo-b:" in content + assert "borg-client-nonroot-delete_nonroot-b:" in content + + def test_empty_decryption_keys_file_stays_valid(self): + content = _read_local_file("decryption_keys_empty_delete.yml") + assert content.strip() == "{}" + + +class TestNeverConfiguredDelete: + def test_no_artifacts_created(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-client-never-delete": + return + + timer = host.file("/etc/systemd/system/borg_backup@never-configured.timer") + service = host.file("/etc/systemd/system/borg_backup@never-configured.service") + script = host.file("/usr/local/bin/run_borg_backup@never-configured") + base_script = host.file("/usr/local/bin/run_borg_backup") + assert not timer.exists + assert not service.exists + assert not script.exists + assert not base_script.exists + + def test_server_repo_not_created(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-server-delete": + return + + repo = host.file("/opt/borg/never-configured") + assert not repo.exists + + def test_no_authorized_keys_entry_created(self, host): + hostname = host.backend.get_hostname() + if hostname != "borg-server-delete": + return + + auth_keys = host.file("/opt/borg/.ssh/authorized_keys") + assert "borg-client-never-delete" not in auth_keys.content_string |