From abd3d770e99c1ccf070a1ce5239b0589dec4d363 Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Wed, 1 Jul 2026 09:29:45 +0800 Subject: [PATCH] refactor: rename toolkit to site-migration-toolkit and rewrite wrapper in Python --- .github/workflows/deploy-env-migration.yaml | 26 +++---- Makefile | 6 +- README.md | 2 +- docs/BackUP/Site-Migration/walkthrough.md | 8 +-- scripts/run_toolkit.py | 80 +++++++++++++++++++++ scripts/run_toolkit.sh | 50 ------------- 6 files changed, 101 insertions(+), 71 deletions(-) create mode 100755 scripts/run_toolkit.py delete mode 100755 scripts/run_toolkit.sh diff --git a/.github/workflows/deploy-env-migration.yaml b/.github/workflows/deploy-env-migration.yaml index 088c1d1..f518f55 100644 --- a/.github/workflows/deploy-env-migration.yaml +++ b/.github/workflows/deploy-env-migration.yaml @@ -2,7 +2,7 @@ name: Deploy Environment & Migrate Data (Data Sync) # ============================================================================= # IaC ↔ 数据流单向迁移流水线 (Site Recovery) -# 1. 动态 Provision (基于 Terraform 创建新环境 site-recovery) +# 1. 动态 Provision (基于 Terraform 创建新环境 site-migration-toolkit) # 2. 部署基础服务 (Bootstrap 部署,跑空环境) # 3. 生产环境克隆与单向同步 (通过 site_migration Ansible 角色) # ============================================================================= @@ -63,12 +63,12 @@ concurrency: env: VAULT_ADDR: https://vault.svc.plus - VAULT_ROLE: github-actions-site-recovery + VAULT_ROLE: github-actions-site-migration-toolkit VAULT_KV: kv/data/CICD VAULT_KV_OPENCLAW: kv/data/openclaw VPS_ROOT: infra/iac_modules/terraform-hcl-standard/vultr-vps - # 指向 site-recovery 的 Terraform 目录 - ENV_DIR: infra/iac_modules/terraform-hcl-standard/vultr-vps/envs/site-recovery + # 指向 site-migration-toolkit 的 Terraform 目录 + ENV_DIR: infra/iac_modules/terraform-hcl-standard/vultr-vps/envs/site-migration-toolkit PLAYBOOKS_DIR: infra/playbooks jobs: @@ -127,8 +127,8 @@ jobs: - name: generate.py render working-directory: ${{ env.VPS_ROOT }} - # 强制指定 envs/site-recovery 生成 tfvars 和显式 HCL - run: python3 scripts/generate.py render --resources config/resources/site-recovery.yaml --workdir envs/site-recovery + # 强制指定 envs/site-migration-toolkit 生成 tfvars 和显式 HCL + run: python3 scripts/generate.py render --resources config/resources/site-migration-toolkit.yaml --workdir envs/site-migration-toolkit - name: Terraform init working-directory: ${{ env.ENV_DIR }} @@ -141,7 +141,7 @@ jobs: run: | terraform init -input=false \ -backend-config="bucket=${TF_STATE_BUCKET}" \ - -backend-config="key=site-recovery/terraform.tfstate" \ + -backend-config="key=site-migration-toolkit/terraform.tfstate" \ -backend-config="region=${TF_STATE_REGION}" - name: Terraform Apply / Destroy @@ -158,8 +158,8 @@ jobs: env: AWS_ACCESS_KEY_ID: ${{ steps.vault.outputs.TF_STATE_ACCESS_KEY }} AWS_SECRET_ACCESS_KEY: ${{ steps.vault.outputs.TF_STATE_SECRET_KEY }} - # 同样指定 envs/site-recovery - run: python3 scripts/generate.py inventory --resources config/resources/site-recovery.yaml --workdir envs/site-recovery + # 同样指定 envs/site-migration-toolkit + run: python3 scripts/generate.py inventory --resources config/resources/site-migration-toolkit.yaml --workdir envs/site-migration-toolkit - name: Build deploy matrix id: matrix @@ -174,7 +174,7 @@ jobs: if: ${{ github.event.inputs.terraform_action == 'apply' }} uses: actions/upload-artifact@v7 with: - name: site-recovery-cmdb + name: site-migration-toolkit-cmdb path: | ${{ env.ENV_DIR }}/cmdb.json ${{ env.ENV_DIR }}/inventory.ini @@ -201,7 +201,7 @@ jobs: - name: Download CMDB uses: actions/download-artifact@v8 with: - name: site-recovery-cmdb + name: site-migration-toolkit-cmdb path: cmdb - name: Load Vault secrets @@ -256,7 +256,7 @@ jobs: if: ${{ github.event.inputs.run_provision_and_deploy == 'true' }} uses: actions/download-artifact@v8 with: - name: site-recovery-cmdb + name: site-migration-toolkit-cmdb path: cmdb - name: Checkout playbooks @@ -317,7 +317,7 @@ jobs: - name: Download CMDB uses: actions/download-artifact@v8 with: - name: site-recovery-cmdb + name: site-migration-toolkit-cmdb path: cmdb - name: Checkout playbooks diff --git a/Makefile b/Makefile index a6f8cca..9763270 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,10 @@ help: @echo " make restore - Execute offline restore on the target host" migrate: - @bash scripts/run_toolkit.sh migrate $(RUN_ARGS) + @python3 scripts/run_toolkit.py migrate $(RUN_ARGS) backup: - @bash scripts/run_toolkit.sh backup $(RUN_ARGS) + @python3 scripts/run_toolkit.py backup $(RUN_ARGS) restore: - @bash scripts/run_toolkit.sh restore $(RUN_ARGS) + @python3 scripts/run_toolkit.py restore $(RUN_ARGS) diff --git a/README.md b/README.md index 8ef9ec9..dc202cc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Site Migration & Backup Toolkit (site-recovery) +# Site Migration & Backup Toolkit (site-migration-toolkit) *🇨🇳 中文版在下方 | Chinese version below* diff --git a/docs/BackUP/Site-Migration/walkthrough.md b/docs/BackUP/Site-Migration/walkthrough.md index 8f04bf6..6da07d2 100644 --- a/docs/BackUP/Site-Migration/walkthrough.md +++ b/docs/BackUP/Site-Migration/walkthrough.md @@ -30,21 +30,21 @@ ### 4. 运行前置条件 (Vault OIDC 授权) -由于我们新建了独立的 `site-recovery` 仓库,该仓库需要通过 GitHub Actions 的 OIDC 身份认证到 Vault 获取凭证。在首次运行流水线之前,你必须使用拥有管理员权限的凭据在你的终端(或 Vault 所在的 `vault.svc.plus` 主机)执行以下操作,以授权新的流水线拉取密钥: +由于我们新建了独立的 `site-migration-toolkit` 仓库,该仓库需要通过 GitHub Actions 的 OIDC 身份认证到 Vault 获取凭证。在首次运行流水线之前,你必须使用拥有管理员权限的凭据在你的终端(或 Vault 所在的 `vault.svc.plus` 主机)执行以下操作,以授权新的流水线拉取密钥: ```bash export VAULT_ADDR=https://vault.svc.plus export VAULT_TOKEN="hvs.xxxxxxxxx" # 请替换为你拥有管理员权限的真实 Token -vault write auth/jwt/role/github-actions-site-recovery - < Path: + """Resolve the location of the Ansible inventory.""" + # 1. Inside toolkit root (e.g. CI/CD environment or manual copy) + if (toolkit_root / "cmdb" / "inventory").is_file(): + return toolkit_root / "cmdb" / "inventory" + if (toolkit_root / "cmdb" / "inventory.ini").is_file(): + return toolkit_root / "cmdb" / "inventory.ini" + + # 2. Adjacent cmdb directory (local execution structure) + adjacent_cmdb = toolkit_root.parent / "cmdb" + if (adjacent_cmdb / "inventory").is_file(): + return adjacent_cmdb / "inventory" + if (adjacent_cmdb / "inventory.ini").is_file(): + return adjacent_cmdb / "inventory.ini" + + return None + +def main(): + parser = argparse.ArgumentParser(description="AI Workspace Site Migration & Backup Toolkit Wrapper") + parser.add_argument("action", choices=["migrate", "backup", "restore"], help="Toolkit action to execute") + + # Capture all remaining arguments (e.g., -e "var=value") to pass seamlessly to ansible-playbook + args, unknown_args = parser.parse_known_args() + + # Resolve paths dynamically + script_dir = Path(__file__).resolve().parent + toolkit_root = script_dir.parent + playbooks_dir = toolkit_root.parent / "playbooks" + + if not playbooks_dir.is_dir(): + print(f"[ERROR] Cannot find playbooks directory at {playbooks_dir}") + print("Ensure 'playbooks' repository is checked out adjacently.") + sys.exit(1) + + playbook_file = f"{args.action}_site.yml" + if not (playbooks_dir / playbook_file).is_file(): + print(f"[ERROR] Playbook '{playbook_file}' not found in {playbooks_dir}") + sys.exit(1) + + inventory_path = get_inventory_path(toolkit_root) + + print("=" * 60) + print(f"[INFO] Action: {args.action.upper()}") + print(f"[INFO] Playbook: {playbook_file}") + if inventory_path: + print(f"[INFO] Inventory: {inventory_path}") + print("=" * 60) + + cmd = ["ansible-playbook"] + if inventory_path: + cmd.extend(["-i", str(inventory_path)]) + else: + print("[WARNING] No valid cmdb/inventory file found. Proceeding without explicit -i flag.") + + cmd.append(playbook_file) + if unknown_args: + cmd.extend(unknown_args) + + print(f"[EXEC] {' '.join(cmd)}\n") + + try: + # Execute Ansible directly from the playbooks directory + subprocess.run(cmd, cwd=playbooks_dir, check=True) + print(f"\n[SUCCESS] Toolkit action '{args.action}' completed.") + except subprocess.CalledProcessError as e: + print(f"\n[FATAL] Toolkit action '{args.action}' failed (Exit Code: {e.returncode}).") + sys.exit(e.returncode) + except KeyboardInterrupt: + print(f"\n[WARN] Toolkit action '{args.action}' interrupted by user.") + sys.exit(130) + +if __name__ == "__main__": + main() diff --git a/scripts/run_toolkit.sh b/scripts/run_toolkit.sh deleted file mode 100755 index 1244bf2..0000000 --- a/scripts/run_toolkit.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -set -euo pipefail - -ACTION=$1 - -if [[ -z "$ACTION" ]]; then - echo "Usage: $0 " - exit 1 -fi - -PLAYBOOK_DIR="../playbooks" -INVENTORY_DIR="../cmdb" - -if [[ ! -d "$PLAYBOOK_DIR" ]]; then - echo "[ERROR] Cannot find playbooks directory at $PLAYBOOK_DIR" - echo "Make sure ai-workspace-infra/playbooks is checked out." - exit 1 -fi - -if [[ ! -f "$INVENTORY_DIR/inventory" ]] && [[ ! -f "$INVENTORY_DIR/inventory.ini" ]] && [[ ! -f "cmdb/inventory" ]]; then - echo "[WARNING] Cannot find cmdb/inventory. Assuming manual inventory or default." -fi - -# In GitHub Actions, cmdb is at the root of site-recovery. Locally it might be ../cmdb. -INV_PATH="cmdb/inventory" -if [[ ! -f "$INV_PATH" ]]; then - if [[ -f "../cmdb/inventory" ]]; then - INV_PATH="../cmdb/inventory" - elif [[ -f "../cmdb/inventory.ini" ]]; then - INV_PATH="../cmdb/inventory.ini" - fi -fi - -PLAYBOOK_FILE="${ACTION}_site.yml" - -echo "[INFO] Starting Toolkit Action: $ACTION" -echo "[INFO] Playbook: $PLAYBOOK_DIR/$PLAYBOOK_FILE" - -cd "$PLAYBOOK_DIR" - -if [[ -f "../site-recovery/$INV_PATH" ]]; then - ansible-playbook -i "../site-recovery/$INV_PATH" "$PLAYBOOK_FILE" "${@:2}" -elif [[ -f "../cmdb/inventory" ]]; then - ansible-playbook -i "../cmdb/inventory" "$PLAYBOOK_FILE" "${@:2}" -else - echo "[WARNING] No inventory found. Running playbook without explicit inventory flag." - ansible-playbook "$PLAYBOOK_FILE" "${@:2}" -fi - -echo "[INFO] Toolkit Action $ACTION completed."