aboutsummaryrefslogtreecommitdiffstats
path: root/molecule/delete
diff options
context:
space:
mode:
Diffstat (limited to 'molecule/delete')
-rw-r--r--molecule/delete/converge.yml143
-rw-r--r--molecule/delete/molecule.yml68
-rw-r--r--molecule/delete/prepare.yml153
-rw-r--r--molecule/delete/tests/test_delete.py318
4 files changed, 682 insertions, 0 deletions
diff --git a/molecule/delete/converge.yml b/molecule/delete/converge.yml
new file mode 100644
index 0000000..00de93d
--- /dev/null
+++ b/molecule/delete/converge.yml
@@ -0,0 +1,143 @@
+---
+- name: Setup - Fetch SSH key for server
+ hosts:
+ - borg-client-single-delete
+ - borg-client-multi-delete
+ - borg-client-per-repo-delete
+ - borg-client-nonroot-delete
+ - borg-client-never-delete
+
+ pre_tasks:
+ - name: Fetch ssh_key for borg-server-delete
+ ansible.builtin.command: >-
+ ssh-keyscan -t rsa borg-server-delete | sed "s/^[^ ]* //"
+ register: borg_server_ssh_keyscan
+ changed_when: false
+
+ - name: Set ssh_key for borg-server-delete
+ ansible.builtin.set_fact:
+ borg_server_host_ssh_key: >-
+ {{ borg_server_ssh_keyscan.stdout
+ | split(" ")
+ | reject("search", "borg-server-delete")
+ | join(" ") }}
+
+- name: Delete single repo backup (with data deletion)
+ hosts: borg-client-single-delete
+
+ roles:
+ - role: kliwniloc.borgbackup
+ vars:
+ state: absent
+ borg_server_host: borg-server-delete
+ borg_server_host_ssh_key: "{{ borg_server_host_ssh_key }}"
+ borg_repo_name: single-backup
+ borg_backup_argument: single-backup
+ borg_dangerously_delete_backups: true
+ borg_decryption_keys_yaml_path: "{{ playbook_dir }}/decryption_keys_delete.yml"
+
+- name: Delete one repo from multi-instance (keep data)
+ hosts: borg-client-multi-delete
+
+ roles:
+ - role: kliwniloc.borgbackup
+ vars:
+ state: absent
+ borg_server_host: borg-server-delete
+ borg_server_host_ssh_key: "{{ borg_server_host_ssh_key }}"
+ borg_repo_name: multi-repo-a
+ borg_backup_argument: multi-repo-a
+ borg_dangerously_delete_backups: false
+ borg_decryption_keys_yaml_path: "{{ playbook_dir }}/decryption_keys_delete.yml"
+
+- name: Delete one repo from per-repo (with data deletion)
+ hosts: borg-client-per-repo-delete
+
+ roles:
+ - role: kliwniloc.borgbackup
+ vars:
+ state: absent
+ borg_server_host: borg-server-delete
+ borg_server_host_ssh_key: "{{ borg_server_host_ssh_key }}"
+ borg_repo_name: per-repo-a
+ borg_backup_argument: per-repo-a
+ borg_ssh_key_per_repo: true
+ borg_ssh_key_type: ed25519
+ borg_dangerously_delete_backups: true
+ borg_decryption_keys_yaml_path: "{{ playbook_dir }}/decryption_keys_delete.yml"
+
+- name: Delete one repo from non-root shared-key setup
+ hosts: borg-client-nonroot-delete
+
+ roles:
+ - role: kliwniloc.borgbackup
+ vars:
+ state: absent
+ borg_server_host: borg-server-delete
+ borg_server_host_ssh_key: "{{ borg_server_host_ssh_key }}"
+ borg_client_user: backupuser
+ borg_repo_name: nonroot-a
+ borg_backup_argument: nonroot-a
+ borg_dangerously_delete_backups: false
+ borg_decryption_keys_yaml_path: "{{ playbook_dir }}/decryption_keys_delete.yml"
+
+- name: Delete never-configured backup with empty key file
+ hosts: borg-client-never-delete
+
+ roles:
+ - role: kliwniloc.borgbackup
+ vars:
+ state: absent
+ borg_server_host: borg-server-delete
+ borg_server_host_ssh_key: "{{ borg_server_host_ssh_key }}"
+ borg_repo_name: never-configured
+ borg_backup_argument: never-configured
+ borg_dangerously_delete_backups: false
+ borg_decryption_keys_yaml_path: "{{ playbook_dir }}/decryption_keys_empty_delete.yml"
+
+- name: Re-run absent for idempotency
+ hosts:
+ - borg-client-single-delete
+ - borg-client-multi-delete
+ - borg-client-per-repo-delete
+ - borg-client-nonroot-delete
+ - borg-client-never-delete
+
+ roles:
+ - role: kliwniloc.borgbackup
+ vars:
+ state: absent
+ borg_server_host: borg-server-delete
+ borg_server_host_ssh_key: "{{ borg_server_host_ssh_key }}"
+ borg_repo_name: >-
+ {{
+ {
+ 'borg-client-single-delete': 'single-backup',
+ 'borg-client-multi-delete': 'multi-repo-a',
+ 'borg-client-per-repo-delete': 'per-repo-a',
+ 'borg-client-nonroot-delete': 'nonroot-a',
+ 'borg-client-never-delete': 'never-configured'
+ }[inventory_hostname]
+ }}
+ borg_backup_argument: >-
+ {{
+ {
+ 'borg-client-single-delete': 'single-backup',
+ 'borg-client-multi-delete': 'multi-repo-a',
+ 'borg-client-per-repo-delete': 'per-repo-a',
+ 'borg-client-nonroot-delete': 'nonroot-a',
+ 'borg-client-never-delete': 'never-configured'
+ }[inventory_hostname]
+ }}
+ borg_client_user: >-
+ {{ 'backupuser' if inventory_hostname == 'borg-client-nonroot-delete' else 'root' }}
+ borg_ssh_key_per_repo: "{{ inventory_hostname == 'borg-client-per-repo-delete' }}"
+ borg_ssh_key_type: "{{ 'ed25519' if inventory_hostname == 'borg-client-per-repo-delete' else 'rsa' }}"
+ borg_dangerously_delete_backups: >-
+ {{ inventory_hostname in ['borg-client-single-delete', 'borg-client-per-repo-delete'] }}
+ borg_decryption_keys_yaml_path: >-
+ {{
+ (playbook_dir ~ '/decryption_keys_empty_delete.yml')
+ if inventory_hostname == 'borg-client-never-delete'
+ else (playbook_dir ~ '/decryption_keys_delete.yml')
+ }}
diff --git a/molecule/delete/molecule.yml b/molecule/delete/molecule.yml
new file mode 100644
index 0000000..bc75ff0
--- /dev/null
+++ b/molecule/delete/molecule.yml
@@ -0,0 +1,68 @@
+---
+dependency:
+ name: galaxy
+
+driver:
+ name: docker
+
+platforms:
+ - name: borg-server-delete
+ image: ${MOLECULE_DISTRO_SERVER:-debian:12}
+ dockerfile: ../Dockerfile.j2
+ pre_build_image: false
+ privileged: true
+ docker_networks:
+ - name: molecule-delete-net
+ driver_options:
+ com.docker.network.driver.mtu: 1420
+ networks:
+ - name: molecule-delete-net
+
+ - name: borg-client-single-delete
+ image: ${MOLECULE_DISTRO_CLIENT:-debian:12}
+ dockerfile: ../Dockerfile.j2
+ pre_build_image: false
+ privileged: true
+ networks:
+ - name: molecule-delete-net
+
+ - name: borg-client-multi-delete
+ image: ${MOLECULE_DISTRO_CLIENT:-debian:12}
+ dockerfile: ../Dockerfile.j2
+ pre_build_image: false
+ privileged: true
+ networks:
+ - name: molecule-delete-net
+
+ - name: borg-client-per-repo-delete
+ image: ${MOLECULE_DISTRO_CLIENT:-debian:12}
+ dockerfile: ../Dockerfile.j2
+ pre_build_image: false
+ privileged: true
+ networks:
+ - name: molecule-delete-net
+
+ - name: borg-client-nonroot-delete
+ image: ${MOLECULE_DISTRO_CLIENT:-debian:12}
+ dockerfile: ../Dockerfile.j2
+ pre_build_image: false
+ privileged: true
+ networks:
+ - name: molecule-delete-net
+
+ - name: borg-client-never-delete
+ image: ${MOLECULE_DISTRO_CLIENT:-debian:12}
+ dockerfile: ../Dockerfile.j2
+ pre_build_image: false
+ privileged: true
+ networks:
+ - name: molecule-delete-net
+
+provisioner:
+ name: ansible
+ playbooks:
+ prepare: prepare.yml
+ converge: ${MOLECULE_PLAYBOOK:-converge.yml}
+
+verifier:
+ name: testinfra
diff --git a/molecule/delete/prepare.yml b/molecule/delete/prepare.yml
new file mode 100644
index 0000000..98a94a1
--- /dev/null
+++ b/molecule/delete/prepare.yml
@@ -0,0 +1,153 @@
+---
+- name: Prepare - Configure SSH keys for delete setup
+ hosts:
+ - borg-client-single-delete
+ - borg-client-multi-delete
+ - borg-client-per-repo-delete
+ - borg-client-nonroot-delete
+ - borg-client-never-delete
+
+ pre_tasks:
+ - name: Start ssh on borg-server-delete
+ ansible.builtin.systemd:
+ name: sshd
+ state: started
+ become: true
+ delegate_to: borg-server-delete
+
+ - name: Fetch ssh_key for borg-server-delete
+ ansible.builtin.command: >-
+ ssh-keyscan -t rsa borg-server-delete | sed "s/^[^ ]* //"
+ register: borg_server_ssh_keyscan
+ changed_when: false
+
+ - name: Set ssh_key for borg-server-delete
+ ansible.builtin.set_fact:
+ borg_server_host_ssh_key: >-
+ {{ borg_server_ssh_keyscan.stdout
+ | split(" ")
+ | reject("search", "borg-server-delete")
+ | join(" ") }}
+
+- name: Create single repo backup
+ hosts: borg-client-single-delete
+
+ roles:
+ - role: kliwniloc.borgbackup
+ vars:
+ state: present
+ borg_server_host: borg-server-delete
+ borg_server_host_ssh_key: "{{ hostvars[inventory_hostname].borg_server_host_ssh_key }}"
+ borg_repo_name: single-backup
+ borg_backup_argument: single-backup
+ borg_decryption_keys_yaml_path: "{{ playbook_dir }}/decryption_keys_delete.yml"
+ borg_included_dirs:
+ - /etc
+ borg_excluded_dirs: []
+
+- name: Create multi-instance backup (shared key)
+ hosts: borg-client-multi-delete
+
+ vars:
+ borg_server_host: borg-server-delete
+ borg_server_host_ssh_key: "{{ hostvars[inventory_hostname].borg_server_host_ssh_key }}"
+ borg_decryption_keys_yaml_path: "{{ playbook_dir }}/decryption_keys_delete.yml"
+ borg_ssh_key_per_repo: false
+
+ roles:
+ - role: kliwniloc.borgbackup
+ vars:
+ state: present
+ borg_repo_name: multi-repo-a
+ borg_backup_argument: multi-repo-a
+ borg_included_dirs:
+ - /etc
+ borg_systemd_oncalendar: "*-*-* 02:00:00"
+
+ - role: kliwniloc.borgbackup
+ vars:
+ state: present
+ borg_repo_name: multi-repo-b
+ borg_backup_argument: multi-repo-b
+ borg_included_dirs:
+ - /home
+ borg_systemd_oncalendar: "*-*-* 04:00:00"
+
+- name: Create per-repo SSH key backup
+ hosts: borg-client-per-repo-delete
+
+ vars:
+ borg_server_host: borg-server-delete
+ borg_server_host_ssh_key: "{{ hostvars[inventory_hostname].borg_server_host_ssh_key }}"
+ borg_decryption_keys_yaml_path: "{{ playbook_dir }}/decryption_keys_delete.yml"
+ borg_ssh_key_per_repo: true
+
+ roles:
+ - role: kliwniloc.borgbackup
+ vars:
+ state: present
+ borg_repo_name: per-repo-a
+ borg_backup_argument: per-repo-a
+ borg_ssh_key_type: ed25519
+ borg_included_dirs:
+ - /etc
+ borg_systemd_oncalendar: "*-*-* 02:00:00"
+
+ - role: kliwniloc.borgbackup
+ vars:
+ state: present
+ borg_repo_name: per-repo-b
+ borg_backup_argument: per-repo-b
+ borg_ssh_key_type: ed25519
+ borg_included_dirs:
+ - /home
+ borg_systemd_oncalendar: "*-*-* 04:00:00"
+
+- name: Create non-root shared-key backup
+ hosts: borg-client-nonroot-delete
+
+ pre_tasks:
+ - name: Create backup user for non-root delete test
+ ansible.builtin.user:
+ name: backupuser
+ home: /home/backupuser
+ shell: /bin/bash
+ state: present
+ become: true
+
+ roles:
+ - role: kliwniloc.borgbackup
+ vars:
+ state: present
+ borg_server_host: borg-server-delete
+ borg_server_host_ssh_key: "{{ hostvars[inventory_hostname].borg_server_host_ssh_key }}"
+ borg_client_user: backupuser
+ borg_repo_name: nonroot-a
+ borg_backup_argument: nonroot-a
+ borg_decryption_keys_yaml_path: "{{ playbook_dir }}/decryption_keys_delete.yml"
+ borg_included_dirs:
+ - /etc
+ borg_excluded_dirs: []
+
+ - role: kliwniloc.borgbackup
+ vars:
+ state: present
+ borg_server_host: borg-server-delete
+ borg_server_host_ssh_key: "{{ hostvars[inventory_hostname].borg_server_host_ssh_key }}"
+ borg_client_user: backupuser
+ borg_repo_name: nonroot-b
+ borg_backup_argument: nonroot-b
+ borg_decryption_keys_yaml_path: "{{ playbook_dir }}/decryption_keys_delete.yml"
+ borg_included_dirs:
+ - /home
+ borg_excluded_dirs: []
+
+- name: Prepare empty decryption keys file for never-configured host
+ hosts: localhost
+ gather_facts: false
+ tasks:
+ - name: Create empty decryption keys file
+ ansible.builtin.copy:
+ content: ""
+ dest: "{{ playbook_dir }}/decryption_keys_empty_delete.yml"
+ mode: "0600"
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