import json import os import sys import time import urllib.parse from proof_client import auth0_token, cluster_query, request, request_json KONG_PROXY = os.environ["CP9_PUBLIC_HTTPS_URL"].rstrip("/") METRIC = "cp9_o11y_gateway_ready" BIZ_TYPE = os.environ["CP9_SESSION_NAME"] REGION = os.environ["CP9_TARGET_REGION"] CLUSTER_ID = os.environ["CP9_CLUSTER_ID"] GLOBAL_CLUSTERS_URL = "http://globalserver.observability.svc.cluster.local:8080/api/v1/clusters" def check_global_api(token): url = f"{GLOBAL_CLUSTERS_URL}/?{cluster_query(REGION, BIZ_TYPE)}" unauth_status, _ = request("GET", url, expected=(401,)) wrong_token_status, _ = request( "GET", url, headers={"authorization": "Bearer wrong-token"}, expected=(401,), ) status, response = request_json( "GET", url, headers={"authorization": f"Bearer {token}"}, ) clusters = response.get("data", {}).get("clusters") if not isinstance(clusters, list): raise RuntimeError("gateway response did not contain data.clusters") if not any(cluster.get("id") == CLUSTER_ID for cluster in clusters): raise RuntimeError("platform-readiness cluster was absent from gateway response") return unauth_status, wrong_token_status, status, len(clusters) def delete_cluster(token): request( "DELETE", f"{GLOBAL_CLUSTERS_URL}/{urllib.parse.quote(CLUSTER_ID)}" f"?{cluster_query(REGION, BIZ_TYPE)}", headers={"authorization": f"Bearer {token}"}, expected=(200, 202), ) def wait_for_zero(token): for _ in range(60): _, response = request_json( "GET", f"{GLOBAL_CLUSTERS_URL}/?{cluster_query(REGION, BIZ_TYPE)}", headers={"authorization": f"Bearer {token}"}, ) clusters = response.get("data", {}).get("clusters") if isinstance(clusters, list) and not clusters: return time.sleep(2) raise RuntimeError("gateway-owned GS cluster remained after delete") def check_metrics(): account_id = urllib.parse.quote(os.environ["VM_ACCOUNT_ID"]) project_id = urllib.parse.quote(os.environ["VM_PROJECT_ID"]) key = os.environ["CP9_METRICS_WRITE_TOKEN"] query = urllib.parse.urlencode({"query": f'{METRIC}{{proof="kong-gateway"}}'}) select_url = ( f"{KONG_PROXY}/o11y/select/{account_id}:{project_id}" f"/prometheus/api/v1/query?{query}" ) timestamp_ms = int(time.time() * 1000) metric_line = ( f'{METRIC}{{proof="kong-gateway",session="{BIZ_TYPE}"}} 1 {timestamp_ms}' ).encode() insert_url = ( f"{KONG_PROXY}/o11y/insert/{account_id}:{project_id}" "/prometheus/api/v1/import/prometheus" ) unauth_status, _ = request( "POST", insert_url, body=metric_line, expected=(401,), ) wrong_token_status, _ = request( "POST", insert_url, body=metric_line, headers={"x-cp9-o11y-token": "wrong-token"}, expected=(401,), ) headers = { "content-type": "text/plain", "x-cp9-o11y-token": key, } unknown_path_status, _ = request( "POST", f"{KONG_PROXY}/o11y/unknown/{account_id}:{project_id}", body=metric_line, headers=headers, # The DBaaS UI catch-all rejects an unmatched POST with 405. expected=(404, 405), ) write_status, _ = request( "POST", insert_url, body=metric_line, headers=headers, expected=(200, 204), ) for _ in range(30): query_status, response = request_json( "GET", select_url, headers={"x-cp9-o11y-token": key}, ) result = response.get("data", {}).get("result", []) if any( item.get("metric", {}).get("proof") == "kong-gateway" and item.get("metric", {}).get("session") == BIZ_TYPE for item in result ): return ( unauth_status, wrong_token_status, unknown_path_status, write_status, query_status, ) time.sleep(2) raise RuntimeError("VictoriaMetrics gateway query did not return the proof marker") def main(): auth0_status, token = auth0_token() deleted = False try: ( global_unauth_status, global_wrong_token_status, global_status, cluster_count, ) = check_global_api(token) ( unauth_status, wrong_token_status, unknown_path_status, write_status, query_status, ) = check_metrics() delete_cluster(token) wait_for_zero(token) deleted = True print( json.dumps( { "status": "passed", "auth0_status": auth0_status, "global_api_unauth_status": global_unauth_status, "global_api_wrong_token_status": global_wrong_token_status, "global_api_status": global_status, "cluster_list_count": cluster_count, "metrics_unauth_status": unauth_status, "metrics_wrong_token_status": wrong_token_status, "metrics_unknown_path_status": unknown_path_status, "metrics_write_status": write_status, "metrics_query_status": query_status, "metrics_marker": METRIC, "vm_account_id": os.environ["VM_ACCOUNT_ID"], "vm_project_id": os.environ["VM_PROJECT_ID"], "active_clusters_after_delete": 0, }, sort_keys=True, ) ) finally: if not deleted: try: delete_cluster(token) wait_for_zero(token) except Exception as cleanup_error: print(f"gateway proof cleanup failed: {cleanup_error}", file=sys.stderr) if __name__ == "__main__": main()