From 592a1956764499b4599f1c4ccd3c418a51962db8 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 18 Jul 2026 18:10:20 +0800 Subject: [PATCH] feat(backup): add bounded host110 runtime deploy --- .../playbooks/110-backup-runtime-deploy.yml | 70 +++++++++++++++++++ ...test_110_backup_runtime_deploy_playbook.py | 56 +++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 infra/ansible/playbooks/110-backup-runtime-deploy.yml create mode 100644 scripts/backup/tests/test_110_backup_runtime_deploy_playbook.py diff --git a/infra/ansible/playbooks/110-backup-runtime-deploy.yml b/infra/ansible/playbooks/110-backup-runtime-deploy.yml new file mode 100644 index 000000000..96edcc0ab --- /dev/null +++ b/infra/ansible/playbooks/110-backup-runtime-deploy.yml @@ -0,0 +1,70 @@ +--- +- name: Deploy the bounded backup runtime to host 110 + hosts: host_110 + gather_facts: false + become: true + serial: 1 + any_errors_fatal: true + + vars: + backup_runtime_root: /backup/scripts + backup_runtime_files: + - common.sh + - backup-all.sh + - backup-awoooi.sh + - backup-awoooi-frequent.sh + - backup-clawbot.sh + - backup-sentry.sh + + pre_tasks: + - name: Verify the fixed host boundary + ansible.builtin.assert: + that: + - inventory_hostname == "host_110" + - backup_runtime_files | length == 6 + - backup_runtime_files | unique | length == backup_runtime_files | length + fail_msg: backup_runtime_deploy_boundary_failed + + tasks: + - name: Ensure the backup runtime directory exists + ansible.builtin.file: + path: "{{ backup_runtime_root }}" + state: directory + owner: wooo + group: wooo + mode: "0755" + + - name: Validate and deploy the fixed backup runtime files + ansible.builtin.copy: + src: "{{ playbook_dir }}/../../../scripts/backup/{{ item }}" + dest: "{{ backup_runtime_root }}/{{ item }}" + owner: wooo + group: wooo + mode: "0755" + backup: true + force: true + validate: "/bin/bash -n %s" + loop: "{{ backup_runtime_files }}" + register: backup_runtime_copy + + - name: Read back deployed backup runtime metadata + ansible.builtin.stat: + path: "{{ backup_runtime_root }}/{{ item }}" + checksum_algorithm: sha256 + loop: "{{ backup_runtime_files }}" + register: backup_runtime_stat + changed_when: false + + - name: Verify deployed backup runtime identity + ansible.builtin.assert: + that: + - item.stat.exists + - item.stat.isreg + - item.stat.pw_name == "wooo" + - item.stat.gr_name == "wooo" + - item.stat.mode == "0755" + - item.stat.checksum == (lookup('ansible.builtin.file', playbook_dir + '/../../../scripts/backup/' + item.item, rstrip=false) | hash('sha256')) + fail_msg: "backup_runtime_identity_failed:{{ item.item }}" + loop: "{{ backup_runtime_stat.results }}" + loop_control: + label: "{{ item.item }}" diff --git a/scripts/backup/tests/test_110_backup_runtime_deploy_playbook.py b/scripts/backup/tests/test_110_backup_runtime_deploy_playbook.py new file mode 100644 index 000000000..27c1b6d05 --- /dev/null +++ b/scripts/backup/tests/test_110_backup_runtime_deploy_playbook.py @@ -0,0 +1,56 @@ +from __future__ import annotations + +from pathlib import Path + +import yaml + + +ROOT = Path(__file__).resolve().parents[3] +PLAYBOOK = ROOT / "infra" / "ansible" / "playbooks" / "110-backup-runtime-deploy.yml" + +EXPECTED_FILES = { + "common.sh", + "backup-all.sh", + "backup-awoooi.sh", + "backup-awoooi-frequent.sh", + "backup-clawbot.sh", + "backup-sentry.sh", +} + + +def test_backup_runtime_deploy_is_fixed_to_host_110_and_six_files() -> None: + plays = yaml.safe_load(PLAYBOOK.read_text(encoding="utf-8")) + assert len(plays) == 1 + play = plays[0] + + assert play["hosts"] == "host_110" + assert play["gather_facts"] is False + assert play["become"] is True + assert play["serial"] == 1 + assert play["any_errors_fatal"] is True + assert play["vars"]["backup_runtime_root"] == "/backup/scripts" + assert set(play["vars"]["backup_runtime_files"]) == EXPECTED_FILES + + +def test_backup_runtime_deploy_has_validation_rollback_and_identity_readback() -> None: + source = PLAYBOOK.read_text(encoding="utf-8") + + assert 'inventory_hostname == "host_110"' in source + assert 'validate: "/bin/bash -n %s"' in source + assert "backup: true" in source + assert "checksum_algorithm: sha256" in source + assert "rstrip=false" in source + assert "backup_runtime_identity_failed" in source + assert "changed_when: false" in source + + for forbidden in ( + "ansible.builtin.service:", + "ansible.builtin.systemd:", + "ansible.builtin.cron:", + "ansible.builtin.shell:", + "ansible.builtin.command:", + "ansible.builtin.git:", + "docker_container", + "kubectl", + ): + assert forbidden not in source