#!/usr/bin/env -S uv run -q # /// script # requires-python = ">=3.14" # dependencies = [] # /// """ List ArgoCD Application resources from GKE via kubectl (read-only). Authenticates to the appropriate GKE cluster for the given environment using gcloud, then reads Application CRDs from the argocd namespace via kubectl. No ArgoCD CLI or SSO login required. Output formats (--output): json (default) JSON array to stdout, no status lines table ASCII table to stdout, no status lines text JSON array to stdout, status lines to stderr Optionally filters by destination cluster name (spec.destination.name). """ from __future__ import annotations import argparse import json import subprocess import sys GKE_CLUSTER_BY_ENV: dict[str, tuple[str, str]] = { "dev": ("dev-cicd-cluster-us-central1", "us-central1"), "staging": ("staging-cicd-cluster-us-central1", "us-central1"), "prod": ("cicd-cluster-us-central1", "us-central1"), } GCP_PROJECT = "pingcap-dbaas-build" def _run(*args: str) -> str: result = subprocess.run(list(args), capture_output=True, text=True) if result.returncode != 0: raise RuntimeError( f"Command {list(args)} failed (exit {result.returncode}):\n" f"stdout: {result.stdout.strip()}\n" f"stderr: {result.stderr.strip()}" ) return result.stdout.strip() def _print_table(apps: list[dict]) -> None: if not apps: print("(no apps found)") return cols = ["name", "destination", "sync_status", "health_status"] headers = ["NAME", "DESTINATION", "SYNC", "HEALTH"] widths = [ max(len(headers[i]), max(len(a[c]) for a in apps)) for i, c in enumerate(cols) ] row_fmt = " ".join(f"{{:<{w}}}" for w in widths) print(row_fmt.format(*headers)) print(" ".join("-" * w for w in widths)) for app in apps: print(row_fmt.format(*[app[c] for c in cols])) def main() -> None: parser = argparse.ArgumentParser( description="List ArgoCD apps from GKE (read-only, no ArgoCD CLI needed)" ) parser.add_argument( "--env", required=True, choices=list(GKE_CLUSTER_BY_ENV), help="Environment: dev, staging, or prod", ) parser.add_argument( "--cluster", default="", help="Filter by ArgoCD destination cluster name (spec.destination.name)", ) parser.add_argument( "--output", choices=["json", "table", "text"], default="json", help="Output format: json (default), table, or text (json + stderr status lines)", ) args = parser.parse_args() verbose = args.output == "text" cluster_name, region = GKE_CLUSTER_BY_ENV[args.env] if verbose: print( f"[gcloud-gke] Getting credentials for {cluster_name}...", file=sys.stderr ) try: _run( "gcloud", "container", "clusters", "get-credentials", cluster_name, "--region", region, "--project", GCP_PROJECT, ) except RuntimeError as e: print(f"ERROR: {e}", file=sys.stderr) sys.exit(1) if verbose: print("[gcloud-gke] Listing ArgoCD applications...", file=sys.stderr) try: raw = _run( "kubectl", "get", "applications.argoproj.io", "-n", "argocd", "-o", "json", ) except RuntimeError as e: print(f"ERROR: {e}", file=sys.stderr) sys.exit(1) data: dict = json.loads(raw) items: list[dict] = data.get("items", []) apps = [] for item in items: dest = item.get("spec", {}).get("destination", {}).get("name", "") if args.cluster and dest != args.cluster: continue apps.append( { "name": item["metadata"]["name"], "destination": dest, "sync_status": item.get("status", {}) .get("sync", {}) .get("status", "Unknown"), "health_status": item.get("status", {}) .get("health", {}) .get("status", "Unknown"), } ) if verbose: print(f"[gcloud-gke] Found {len(apps)} app(s).", file=sys.stderr) if args.output == "table": _print_table(apps) else: print(json.dumps(apps, indent=2)) if __name__ == "__main__": main()