refactor: rename toolkit to site-migration-toolkit and rewrite wrapper in Python
This commit is contained in:
parent
fbbf5d7b4f
commit
abd3d770e9
26
.github/workflows/deploy-env-migration.yaml
vendored
26
.github/workflows/deploy-env-migration.yaml
vendored
@ -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
|
||||
|
||||
6
Makefile
6
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)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# Site Migration & Backup Toolkit (site-recovery)
|
||||
# Site Migration & Backup Toolkit (site-migration-toolkit)
|
||||
|
||||
*🇨🇳 中文版在下方 | Chinese version below*
|
||||
|
||||
|
||||
@ -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 - <<EOF
|
||||
vault write auth/jwt/role/github-actions-site-migration-toolkit - <<EOF
|
||||
{
|
||||
"role_type": "jwt",
|
||||
"user_claim": "repository",
|
||||
"bound_audiences": ["vault"],
|
||||
"bound_claims_type": "glob",
|
||||
"bound_claims": {
|
||||
"repository": "ai-workspace-infra/site-recovery",
|
||||
"sub": "repo:ai-workspace-infra/site-recovery:*"
|
||||
"repository": "ai-workspace-infra/site-migration-toolkit",
|
||||
"sub": "repo:ai-workspace-infra/site-migration-toolkit:*"
|
||||
},
|
||||
"token_policies": ["github-actions-xworkspace-console"],
|
||||
"token_ttl": "20m",
|
||||
|
||||
80
scripts/run_toolkit.py
Executable file
80
scripts/run_toolkit.py
Executable file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
def get_inventory_path(toolkit_root: Path) -> 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()
|
||||
@ -1,50 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
ACTION=$1
|
||||
|
||||
if [[ -z "$ACTION" ]]; then
|
||||
echo "Usage: $0 <migrate|backup|restore>"
|
||||
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."
|
||||
Loading…
Reference in New Issue
Block a user