From 5e363249cefafdc0aea32735fd2d9828ac124021 Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Wed, 17 Jun 2026 14:05:06 +0800 Subject: [PATCH] feat(ai-workspace): add encrypted backup and restore playbooks --- roles/vhosts/ai-workspace/tasks/backup.yml | 39 ++++++++++++++++ roles/vhosts/ai-workspace/tasks/restore.yml | 51 +++++++++++++++++++++ setup-ai-workspace-backup.yml | 11 +++++ setup-ai-workspace-restore.yml | 11 +++++ 4 files changed, 112 insertions(+) create mode 100644 roles/vhosts/ai-workspace/tasks/backup.yml create mode 100644 roles/vhosts/ai-workspace/tasks/restore.yml create mode 100644 setup-ai-workspace-backup.yml create mode 100644 setup-ai-workspace-restore.yml diff --git a/roles/vhosts/ai-workspace/tasks/backup.yml b/roles/vhosts/ai-workspace/tasks/backup.yml new file mode 100644 index 0000000..efce5cc --- /dev/null +++ b/roles/vhosts/ai-workspace/tasks/backup.yml @@ -0,0 +1,39 @@ +--- +- name: Set backup staging directory + ansible.builtin.set_fact: + backup_staging_dir: "/tmp/xworkspace_backup_{{ 999999 | random }}" + +- name: Create backup staging directories + ansible.builtin.file: + path: "{{ backup_staging_dir }}/data" + state: directory + mode: '0700' + +- name: Copy user configuration directories to staging + ansible.builtin.shell: | + cp -a {{ ansible_env.HOME }}/.config/xworkspace {{ backup_staging_dir }}/data/.config_xworkspace || true + cp -a {{ ansible_env.HOME }}/.local/state/xworkspace {{ backup_staging_dir }}/data/.local_state_xworkspace || true + cp -a {{ ansible_env.HOME }}/.openclaw {{ backup_staging_dir }}/data/.openclaw || true + cp -a {{ ansible_env.HOME }}/.cache/qmd {{ backup_staging_dir }}/data/.cache_qmd || true + cp -a {{ ansible_env.HOME }}/.config/qmd {{ backup_staging_dir }}/data/.config_qmd || true + cp {{ ansible_env.HOME }}/.ai_workspace_auth_token {{ backup_staging_dir }}/data/.ai_workspace_auth_token || true + cp {{ ansible_env.HOME }}/.vault_password {{ backup_staging_dir }}/data/.vault_password || true + args: + executable: /bin/bash + +- name: Dump LiteLLM database to staging + ansible.builtin.shell: > + pg_dump -U {{ migrate_litellm_db_user }} -h {{ migrate_litellm_db_host }} -Fc {{ migrate_litellm_db }} > {{ backup_staging_dir }}/data/litellm.dump || true + args: + executable: /bin/bash + +- name: Archive and Encrypt backup + ansible.builtin.shell: > + tar -czf - -C {{ backup_staging_dir }} data | openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:"backup 归档打包为冷备文件" > {{ backup_output_file }} + args: + executable: /bin/bash + +- name: Cleanup backup staging directory + ansible.builtin.file: + path: "{{ backup_staging_dir }}" + state: absent diff --git a/roles/vhosts/ai-workspace/tasks/restore.yml b/roles/vhosts/ai-workspace/tasks/restore.yml new file mode 100644 index 0000000..a9bd1c6 --- /dev/null +++ b/roles/vhosts/ai-workspace/tasks/restore.yml @@ -0,0 +1,51 @@ +--- +- name: Set restore staging directory + ansible.builtin.set_fact: + restore_staging_dir: "/tmp/xworkspace_restore_{{ 999999 | random }}" + +- name: Create restore staging directory + ansible.builtin.file: + path: "{{ restore_staging_dir }}" + state: directory + mode: '0700' + +- name: Decrypt and extract backup archive + ansible.builtin.shell: > + openssl enc -d -aes-256-cbc -pbkdf2 -salt -pass pass:"backup 归档打包为冷备文件" -in {{ backup_input_file }} | tar -xzf - -C {{ restore_staging_dir }} + args: + executable: /bin/bash + +- name: Ensure target config directories exist + ansible.builtin.file: + path: "{{ item }}" + state: directory + mode: '0755' + loop: + - "{{ ansible_env.HOME }}/.config" + - "{{ ansible_env.HOME }}/.local/state" + - "{{ ansible_env.HOME }}/.cache" + +- name: Restore configuration directories + ansible.builtin.shell: | + [ -d {{ restore_staging_dir }}/data/.config_xworkspace ] && cp -a {{ restore_staging_dir }}/data/.config_xworkspace {{ ansible_env.HOME }}/.config/xworkspace || true + [ -d {{ restore_staging_dir }}/data/.local_state_xworkspace ] && cp -a {{ restore_staging_dir }}/data/.local_state_xworkspace {{ ansible_env.HOME }}/.local/state/xworkspace || true + [ -d {{ restore_staging_dir }}/data/.openclaw ] && cp -a {{ restore_staging_dir }}/data/.openclaw {{ ansible_env.HOME }}/.openclaw || true + [ -d {{ restore_staging_dir }}/data/.cache_qmd ] && cp -a {{ restore_staging_dir }}/data/.cache_qmd {{ ansible_env.HOME }}/.cache/qmd || true + [ -d {{ restore_staging_dir }}/data/.config_qmd ] && cp -a {{ restore_staging_dir }}/data/.config_qmd {{ ansible_env.HOME }}/.config/qmd || true + [ -f {{ restore_staging_dir }}/data/.ai_workspace_auth_token ] && cp {{ restore_staging_dir }}/data/.ai_workspace_auth_token {{ ansible_env.HOME }}/.ai_workspace_auth_token || true + [ -f {{ restore_staging_dir }}/data/.vault_password ] && cp {{ restore_staging_dir }}/data/.vault_password {{ ansible_env.HOME }}/.vault_password || true + args: + executable: /bin/bash + +- name: Restore LiteLLM database + ansible.builtin.shell: | + if [ -f {{ restore_staging_dir }}/data/litellm.dump ]; then + pg_restore -U {{ migrate_litellm_db_user }} -h {{ migrate_litellm_db_host }} -d {{ migrate_litellm_db }} -1 --clean {{ restore_staging_dir }}/data/litellm.dump || true + fi + args: + executable: /bin/bash + +- name: Cleanup restore staging directory + ansible.builtin.file: + path: "{{ restore_staging_dir }}" + state: absent diff --git a/setup-ai-workspace-backup.yml b/setup-ai-workspace-backup.yml new file mode 100644 index 0000000..4ced230 --- /dev/null +++ b/setup-ai-workspace-backup.yml @@ -0,0 +1,11 @@ +--- +- name: Backup AI Workspace Data + hosts: localhost + connection: local + become: no + gather_facts: false + tasks: + - name: Run AI Workspace Backup Tasks + ansible.builtin.include_role: + name: roles/vhosts/ai-workspace + tasks_from: backup.yml diff --git a/setup-ai-workspace-restore.yml b/setup-ai-workspace-restore.yml new file mode 100644 index 0000000..5c3aafb --- /dev/null +++ b/setup-ai-workspace-restore.yml @@ -0,0 +1,11 @@ +--- +- name: Restore AI Workspace Data + hosts: localhost + connection: local + become: no + gather_facts: false + tasks: + - name: Run AI Workspace Restore Tasks + ansible.builtin.include_role: + name: roles/vhosts/ai-workspace + tasks_from: restore.yml