Files
awoooi/scripts/reboot-recovery/build-windows99-vmx-source-repair-package.py
Your Name 36536adcfa
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m12s
AWOOOI Harbor 110 Local Repair / workflow-shape (push) Successful in 0s
AWOOOI Harbor 110 Local Repair / harbor-110-local-repair (push) Successful in 16s
CD Pipeline / build-and-deploy (push) Successful in 4m13s
CD Pipeline / post-deploy-checks (push) Successful in 1m55s
fix(reboot): keep vmx repair package cli no-db
2026-07-03 17:14:57 +08:00

104 lines
3.4 KiB
Python

#!/usr/bin/env python3
"""Build a no-secret Windows99 VMX source repair check-mode package.
This package turns the reboot SLO scorecard's Windows99 VMX blockers into a
bounded source-repair plan. It never starts VMs, edits Windows, restarts
services, reads secrets, or applies registry/task changes.
"""
from __future__ import annotations
import argparse
import json
import os
import sys
import urllib.request
from pathlib import Path
from typing import Any
_REPO_ROOT = Path(__file__).resolve().parents[2]
_API_ROOT = _REPO_ROOT / "apps" / "api"
if str(_API_ROOT) not in sys.path:
sys.path.insert(0, str(_API_ROOT))
# This CLI is a no-DB, check-mode reboot recovery tool. The API package import
# still validates settings, so provide a harmless placeholder when running
# outside the service container.
os.environ.setdefault("DATABASE_URL", "postgresql+asyncpg://test:test@localhost/test")
from src.services.reboot_auto_recovery_slo_scorecard import ( # noqa: E402
_build_windows99_vmx_source_repair_package,
_taipei_now_iso,
)
DEFAULT_SCORECARD_URL = (
"https://awoooi.wooo.work/api/v1/agents/reboot-auto-recovery-slo-scorecard"
)
def _dict(value: Any) -> dict[str, Any]:
return value if isinstance(value, dict) else {}
def _load_json_file(path: Path) -> dict[str, Any]:
with path.open(encoding="utf-8") as handle:
payload = json.load(handle)
return payload if isinstance(payload, dict) else {}
def _fetch_json_url(url: str, timeout_seconds: float) -> dict[str, Any]:
request = urllib.request.Request(
url,
headers={"User-Agent": "awoooi-windows99-vmx-package/1.0"},
)
with urllib.request.urlopen(request, timeout=timeout_seconds) as response:
payload = json.load(response)
return payload if isinstance(payload, dict) else {}
def build_package(scorecard: dict[str, Any], *, generated_at: str | None = None) -> dict[str, Any]:
existing_package = _dict(scorecard.get("windows99_vmx_source_repair_package"))
if existing_package and generated_at is None:
return existing_package
return _build_windows99_vmx_source_repair_package(
_dict(scorecard.get("windows99_vmware_autostart")),
generated_at=generated_at
or str(scorecard.get("generated_at") or _taipei_now_iso()),
)
def parse_args(argv: list[str]) -> argparse.Namespace:
parser = argparse.ArgumentParser(
description=(
"Build a no-secret Windows99 VMX source repair check-mode package "
"from a reboot SLO scorecard."
)
)
parser.add_argument("--scorecard-file", type=Path)
parser.add_argument("--scorecard-url", default=DEFAULT_SCORECARD_URL)
parser.add_argument("--timeout-seconds", type=float, default=20.0)
parser.add_argument("--generated-at")
parser.add_argument("--output", type=Path)
return parser.parse_args(argv)
def main(argv: list[str]) -> int:
args = parse_args(argv)
scorecard = (
_load_json_file(args.scorecard_file)
if args.scorecard_file
else _fetch_json_url(args.scorecard_url, args.timeout_seconds)
)
package = build_package(scorecard, generated_at=args.generated_at)
text = json.dumps(package, ensure_ascii=False, indent=2) + "\n"
if args.output:
args.output.write_text(text, encoding="utf-8")
else:
sys.stdout.write(text)
return 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))