#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck disable=SC1091 source "${SCRIPT_DIR}/lib_ops_center.sh" ops_center_load_config "${SCRIPT_DIR}" usage() { cat <<'EOF' usage: bash domain-api/deploy/multi-region/drive_release_hub.sh [args...] commands: launchpad latest-package latest-release preview-latest preview-latest-smart preview-release create-latest-release list-releases [limit] list-rollouts [limit] smart-latest [confirm] smart-release [confirm] examples: bash domain-api/deploy/multi-region/drive_release_hub.sh http://127.0.0.1:8100 launchpad bash domain-api/deploy/multi-region/drive_release_hub.sh http://127.0.0.1:8100 latest-package bash domain-api/deploy/multi-region/drive_release_hub.sh http://127.0.0.1:8100 preview-latest bash domain-api/deploy/multi-region/drive_release_hub.sh http://127.0.0.1:8100 preview-latest-smart worker bash domain-api/deploy/multi-region/drive_release_hub.sh http://127.0.0.1:8100 create-latest-release bash domain-api/deploy/multi-region/drive_release_hub.sh http://127.0.0.1:8100 smart-latest worker bash domain-api/deploy/multi-region/drive_release_hub.sh http://127.0.0.1:8100 preview-release 18 control bash domain-api/deploy/multi-region/drive_release_hub.sh http://127.0.0.1:8100 smart-release 18 control confirm EOF } BASE_URL="${1:-$(ops_center_resolve_mainland_api_base_url)}" COMMAND="${2:-}" ARG1="${3:-}" ARG2="${4:-}" ARG3="${5:-}" REQUESTED_BY="${REQUESTED_BY:-$(ops_center_resolve_requested_by)}" print_json_or_raw() { local raw_text="${1:-}" python3 - "${raw_text}" <<'PY' import json import sys raw_text = str(sys.argv[1] or "") try: payload = json.loads(raw_text) except Exception: print(raw_text) else: print(json.dumps(payload, ensure_ascii=False, indent=2)) PY } request_with_status() { local method="$1" local url="$2" local body="${3:-}" if [[ "${method}" == "POST" ]]; then curl -sS -X POST "${url}" \ -H 'Content-Type: application/json' \ -d "${body}" \ -w $'\nHTTP_STATUS=%{http_code}' else curl -sS "${url}" -w $'\nHTTP_STATUS=%{http_code}' fi } if [[ -z "${COMMAND}" ]]; then usage exit 1 fi METHOD="GET" PATH_SUFFIX="" REQUEST_JSON="" confirm_to_bool() { local raw_value="${1:-}" case "$(printf '%s' "${raw_value}" | tr '[:upper:]' '[:lower:]')" in 1|true|yes|y|confirm|confirmed) printf 'true' ;; *) printf 'false' ;; esac } case "${COMMAND}" in launchpad) CHANNEL="${ARG1:-stable}" PATH_SUFFIX="/api/v1/ops/releases/launchpad?channel=${CHANNEL}" ;; latest-package) PATH_SUFFIX="/api/v1/ops/releases/package-metadata/latest" ;; latest-release) PATH_SUFFIX="/api/v1/ops/releases/latest" ;; preview-latest) METHOD="POST" PATH_SUFFIX="/api/v1/ops/releases/from-package/latest/preview" REQUEST_JSON="$(python3 - <<'PY' "${REQUESTED_BY}" import json import sys requested_by = str(sys.argv[1] or "").strip() or "cli/drive_release_hub" payload = { "created_by": f"{requested_by}/latest-package-preview", } print(json.dumps(payload, ensure_ascii=False)) PY )" ;; preview-latest-smart) MODE="${ARG1:-}" if [[ "${MODE}" != "worker" && "${MODE}" != "control" ]]; then echo "mode must be worker or control" >&2 usage exit 1 fi METHOD="POST" PATH_SUFFIX="/api/v1/ops/releases/from-package/latest/smart-rollout-preview" REQUEST_JSON="$(python3 - <<'PY' "${MODE}" "${REQUESTED_BY}" import json import sys mode = str(sys.argv[1] or "").strip() requested_by = str(sys.argv[2] or "").strip() or "cli/drive_release_hub" payload = { "mode": mode, "created_by": f"{requested_by}/latest-package-preview", "rollout_created_by": f"{requested_by}/latest-package-preview/rollout", } print(json.dumps(payload, ensure_ascii=False)) PY )" ;; create-latest-release) METHOD="POST" PATH_SUFFIX="/api/v1/ops/releases/from-package/latest" REQUEST_JSON="$(python3 - <<'PY' "${REQUESTED_BY}" import json import sys requested_by = str(sys.argv[1] or "").strip() or "cli/drive_release_hub" payload = { "created_by": f"{requested_by}/latest-package", } print(json.dumps(payload, ensure_ascii=False)) PY )" ;; list-releases) RELEASE_LIMIT="${ARG1:-10}" PATH_SUFFIX="/api/v1/ops/releases?limit=${RELEASE_LIMIT}" ;; list-rollouts) RELEASE_ID="${ARG1:-}" ROLLOUT_LIMIT="${ARG2:-10}" if [[ -z "${RELEASE_ID}" ]]; then echo "release_id is required for list-rollouts" >&2 usage exit 1 fi PATH_SUFFIX="/api/v1/ops/releases/${RELEASE_ID}/rollouts?limit=${ROLLOUT_LIMIT}" ;; smart-latest) MODE="${ARG1:-}" if [[ "${MODE}" != "worker" && "${MODE}" != "control" ]]; then echo "mode must be worker or control" >&2 usage exit 1 fi METHOD="POST" PATH_SUFFIX="/api/v1/ops/releases/from-package/latest/smart-rollout" CONFIRM_RISKY="$(confirm_to_bool "${ARG2:-}")" REQUEST_JSON="$(python3 - <<'PY' "${MODE}" "${CONFIRM_RISKY}" "${REQUESTED_BY}" import json import sys mode = str(sys.argv[1] or "").strip() confirm_risky = str(sys.argv[2] or "").strip().lower() == "true" requested_by = str(sys.argv[3] or "").strip() or "cli/drive_release_hub" payload = { "mode": mode, "confirm_risky": confirm_risky, "created_by": f"{requested_by}/latest-package", "rollout_created_by": f"{requested_by}/latest-package/rollout", } print(json.dumps(payload, ensure_ascii=False)) PY )" ;; preview-release) RELEASE_ID="${ARG1:-}" MODE="${ARG2:-}" if [[ -z "${RELEASE_ID}" ]]; then echo "release_id is required for preview-release" >&2 usage exit 1 fi if [[ "${MODE}" != "worker" && "${MODE}" != "control" ]]; then echo "mode must be worker or control" >&2 usage exit 1 fi METHOD="POST" PATH_SUFFIX="/api/v1/ops/releases/${RELEASE_ID}/smart-rollout-preview" REQUEST_JSON="$(python3 - <<'PY' "${MODE}" "${REQUESTED_BY}" import json import sys mode = str(sys.argv[1] or "").strip() requested_by = str(sys.argv[2] or "").strip() or "cli/drive_release_hub" payload = { "mode": mode, "created_by": f"{requested_by}/existing-release-preview", "rollout_created_by": f"{requested_by}/existing-release-preview/rollout", } print(json.dumps(payload, ensure_ascii=False)) PY )" ;; smart-release) RELEASE_ID="${ARG1:-}" MODE="${ARG2:-}" if [[ -z "${RELEASE_ID}" ]]; then echo "release_id is required for smart-release" >&2 usage exit 1 fi if [[ "${MODE}" != "worker" && "${MODE}" != "control" ]]; then echo "mode must be worker or control" >&2 usage exit 1 fi METHOD="POST" PATH_SUFFIX="/api/v1/ops/releases/${RELEASE_ID}/smart-rollout" CONFIRM_RISKY="$(confirm_to_bool "${ARG3:-}")" REQUEST_JSON="$(python3 - <<'PY' "${MODE}" "${CONFIRM_RISKY}" "${REQUESTED_BY}" import json import sys mode = str(sys.argv[1] or "").strip() confirm_risky = str(sys.argv[2] or "").strip().lower() == "true" requested_by = str(sys.argv[3] or "").strip() or "cli/drive_release_hub" payload = { "mode": mode, "confirm_risky": confirm_risky, "created_by": f"{requested_by}/existing-release", "rollout_created_by": f"{requested_by}/existing-release/rollout", } print(json.dumps(payload, ensure_ascii=False)) PY )" ;; *) echo "unknown command: ${COMMAND}" >&2 usage exit 1 ;; esac echo "[1/3] request" printf '%s\n' "method=${METHOD}" printf '%s\n' "url=${BASE_URL}${PATH_SUFFIX}" if [[ -n "${REQUEST_JSON}" ]]; then print_json_or_raw "${REQUEST_JSON}" else echo "(no request body)" fi echo echo RAW_HTTP_RESPONSE="$(request_with_status "${METHOD}" "${BASE_URL}${PATH_SUFFIX}" "${REQUEST_JSON}")" HTTP_STATUS="${RAW_HTTP_RESPONSE##*$'\n'HTTP_STATUS=}" RESPONSE_JSON="${RAW_HTTP_RESPONSE%$'\n'HTTP_STATUS=*}" echo "[2/3] raw response" printf '%s\n' "http_status=${HTTP_STATUS}" print_json_or_raw "${RESPONSE_JSON}" echo echo echo "[3/3] condensed summary" python3 - "${RESPONSE_JSON}" "${HTTP_STATUS}" <<'PY' import json import sys raw_response = str(sys.argv[1] or "") http_status = int(sys.argv[2] or 0) try: payload = json.loads(raw_response) except Exception: print(json.dumps({ "http_status": http_status, "code": 1, "message": "response is not valid json", "raw_response": raw_response[:500], }, ensure_ascii=False, indent=2)) sys.exit(0 if 200 <= http_status < 300 else 1) data = payload.get("data") or {} raw_code = payload.get("code", 1) if raw_code in (0, "0", False): normalized_code = 0 else: normalized_code = int(raw_code or 1) summary = { "http_status": http_status, "code": normalized_code, "message": str(payload.get("message") or ""), } if isinstance(data, dict) and "package" in data: package = dict(data.get("package") or {}) summary["package"] = { "available": bool(package.get("available", False)), "package_name": str(package.get("package_name") or ""), "package_type": str(package.get("package_type") or ""), "generated_at": str(package.get("generated_at") or ""), "smoke_test_ok": bool(package.get("smoke_test_ok", False)), "smoke_test_message": str(package.get("smoke_test_message") or ""), } if isinstance(data, dict) and "launchpad_status" in data: launchpad_status = dict(data.get("launchpad_status") or {}) worker_preview = dict(data.get("worker_rollout_preview") or {}) worker_smart_rollout = dict(worker_preview.get("smart_rollout") or {}) control_preview = dict(data.get("control_rollout_preview") or {}) control_smart_rollout = dict(control_preview.get("smart_rollout") or {}) summary["launchpad"] = { "channel": str(data.get("channel") or ""), "status": str(launchpad_status.get("status") or ""), "status_label": str(launchpad_status.get("status_label") or ""), "summary": str(launchpad_status.get("summary") or ""), "recommended_action_code": str(launchpad_status.get("recommended_action_code") or ""), "recommended_target_node_code": str(launchpad_status.get("recommended_target_node_code") or ""), "recommended_recovery_label": str(launchpad_status.get("recommended_recovery_label") or ""), "recommended_recovery_summary": str(launchpad_status.get("recommended_recovery_summary") or ""), "onboarding_bootstrap_pending_nodes": int(launchpad_status.get("onboarding_bootstrap_pending_nodes", 0) or 0), "onboarding_acceptance_ready_nodes": int(launchpad_status.get("onboarding_acceptance_ready_nodes", 0) or 0), "recommended_command": str(launchpad_status.get("recommended_command") or ""), "recommended_execution_mode": str(launchpad_status.get("recommended_execution_mode") or ""), "recommended_execution_mode_label": str(launchpad_status.get("recommended_execution_mode_label") or ""), "focus_ref": dict(launchpad_status.get("focus_ref") or {}), "latest_package": dict(data.get("latest_package") or {}), "latest_release": { "id": int(((data.get("latest_release") or {}).get("id") or 0)), "release_version": str((data.get("latest_release") or {}).get("release_version") or ""), "status": str((data.get("latest_release") or {}).get("status") or ""), }, "worker_rollout_preview": { "message": str(worker_preview.get("message") or ""), "available": bool(worker_smart_rollout.get("available", False)), "requires_confirmation": bool(worker_preview.get("requires_confirmation", False)), "blocked": bool(worker_preview.get("blocked", False)), "execution_mode": str(worker_smart_rollout.get("execution_mode") or ""), "execution_mode_label": str(worker_smart_rollout.get("execution_mode_label") or ""), "target_node_codes": list(worker_smart_rollout.get("target_node_codes") or []), }, "control_rollout_preview": { "message": str(control_preview.get("message") or ""), "available": bool(control_smart_rollout.get("available", False)), "requires_confirmation": bool(control_preview.get("requires_confirmation", False)), "blocked": bool(control_preview.get("blocked", False)), "execution_mode": str(control_smart_rollout.get("execution_mode") or ""), "execution_mode_label": str(control_smart_rollout.get("execution_mode_label") or ""), "target_node_codes": list(control_smart_rollout.get("target_node_codes") or []), }, } print(json.dumps(summary, ensure_ascii=False, indent=2)) sys.exit(0) if isinstance(data, dict) and "available" in data: summary["latest_package"] = { "available": bool(data.get("available", False)), "package_name": str(data.get("package_name") or ""), "package_type": str(data.get("package_type") or ""), "generated_at": str(data.get("generated_at") or ""), "commit_sha": str(data.get("commit_sha") or ""), "smoke_test_ok": bool(data.get("smoke_test_ok", False)), "smoke_test_message": str(data.get("smoke_test_message") or ""), "reason": str(data.get("reason") or ""), } elif isinstance(data, dict) and "releases" in data: releases = list(data.get("releases") or []) summary["releases"] = { "count": len(releases), "items": [ { "id": int(item.get("id") or 0), "release_version": str(item.get("release_version") or ""), "channel": str(item.get("channel") or ""), "status": str(item.get("status") or ""), } for item in releases[:5] ], } elif isinstance(data, dict) and "rollouts" in data: rollouts = list(data.get("rollouts") or []) summary["rollouts"] = { "count": len(rollouts), "items": [ { "id": int(item.get("id") or 0), "rollout_code": str(item.get("rollout_code") or ""), "status": str(item.get("status") or ""), "jobs_total": int(item.get("jobs_total") or 0), "jobs_created": int(item.get("jobs_created") or 0), } for item in rollouts[:5] ], } else: release = data.get("release") or data rollout = data.get("rollout") or {} smart_rollout = data.get("smart_rollout") or {} preview = data.get("preview") or {} summary["preview_source"] = str(data.get("preview_source") or "") summary["release"] = { "id": int(release.get("id") or 0), "release_version": str(release.get("release_version") or ""), "channel": str(release.get("channel") or ""), "status": str(release.get("status") or ""), "is_preview": bool(release.get("is_preview", False)), } if rollout: summary["rollout"] = { "id": int(rollout.get("id") or 0), "rollout_code": str(rollout.get("rollout_code") or ""), "status": str(rollout.get("status") or ""), } if smart_rollout: summary["smart_rollout"] = { "available": bool(smart_rollout.get("available", False)), "mode": str(smart_rollout.get("mode") or ""), "mode_label": str(smart_rollout.get("mode_label") or ""), "target_node_codes": list((smart_rollout.get("target_selector") or {}).get("node_codes") or []), "summary": str(smart_rollout.get("summary") or smart_rollout.get("reason") or ""), } if preview: summary["preview"] = { "blocked": bool(preview.get("blocked", False)), "approval_required": bool(preview.get("approval_required", False)), "warnings": list(preview.get("warnings") or []), } summary["result_flags"] = { "release_created": bool(data.get("release_created", False)), "release_deduplicated": bool(data.get("release_deduplicated", False)), "rollout_created": bool(data.get("rollout_created", False)), "requires_confirmation": bool(data.get("requires_confirmation", False)), "blocked": bool(data.get("blocked", False)), } print(json.dumps(summary, ensure_ascii=False, indent=2)) PY if [[ "${HTTP_STATUS}" -lt 200 || "${HTTP_STATUS}" -ge 300 ]]; then exit 1 fi