Files
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

182 lines
6.2 KiB
Python

"""Centralized config manager for Kubernetes trigger API URL."""
from __future__ import annotations
import json
from contextlib import suppress
from datetime import UTC, datetime
from pathlib import Path
from typing import Any
from tests.e2e.kubernetes.infrastructure_sdk.eks import (
ECR_REPO_NAME,
REGION,
STACK_NAME,
TRIGGER_LAMBDA_NAME,
)
from tests.shared.infrastructure_sdk.config import OUTPUTS_DIR, load_outputs
from tests.shared.infrastructure_sdk.deployer import get_boto3_client
TRIGGER_CONFIG_NAME = "tracer-k8s-trigger"
TRIGGER_CONFIG_PATH = OUTPUTS_DIR / f"{TRIGGER_CONFIG_NAME}.json"
def load_trigger_config() -> dict[str, Any]:
if not TRIGGER_CONFIG_PATH.exists():
raise FileNotFoundError(
f"Missing trigger config: {TRIGGER_CONFIG_PATH}. Run: make regen-trigger-config"
)
with open(TRIGGER_CONFIG_PATH) as f:
payload = json.load(f)
trigger_api_url = (payload.get("trigger_api_url") or "").strip()
if not trigger_api_url:
raise ValueError(
f"Invalid trigger config (missing trigger_api_url): {TRIGGER_CONFIG_PATH}. "
"Run: make regen-trigger-config"
)
return payload
def save_trigger_config(trigger_api_url: str) -> Path:
OUTPUTS_DIR.mkdir(parents=True, exist_ok=True)
payload = {
"stack_name": STACK_NAME,
"region": REGION,
"trigger_api_url": trigger_api_url.rstrip("/"),
"updated_at": datetime.now(UTC).isoformat(),
}
with open(TRIGGER_CONFIG_PATH, "w") as f:
json.dump(payload, f, indent=2)
return TRIGGER_CONFIG_PATH
def _discover_trigger_api_url() -> str | None:
# First: check SDK outputs file if it has trigger API URL
with suppress(FileNotFoundError):
outputs = load_outputs(STACK_NAME)
from_outputs = (outputs.get("trigger_api_url") or "").strip().rstrip("/")
if from_outputs:
return from_outputs
# Fallback: discover API Gateway via AWS tags
tagger = get_boto3_client("resourcegroupstaggingapi", REGION)
rest_api_id = None
paginator = tagger.get_paginator("get_resources")
for page in paginator.paginate(
TagFilters=[
{"Key": "tracer:stack", "Values": [STACK_NAME]},
{"Key": "tracer:managed", "Values": ["sdk"]},
],
ResourceTypeFilters=["apigateway:restapis"],
):
for resource in page.get("ResourceTagMappingList", []):
arn = resource.get("ResourceARN", "")
marker = "/restapis/"
if marker in arn:
rest_api_id = arn.split(marker, 1)[1].split("/", 1)[0]
break
if rest_api_id:
break
if not rest_api_id:
return None
api_client = get_boto3_client("apigateway", REGION)
stages = api_client.get_stages(restApiId=rest_api_id).get("item", [])
stage_name = "prod"
if not any(stage.get("stageName") == "prod" for stage in stages):
stage_name = stages[0]["stageName"] if stages else "prod"
return f"https://{rest_api_id}.execute-api.{REGION}.amazonaws.com/{stage_name}"
def discover_runtime_outputs() -> dict[str, str] | None:
"""Discover runtime outputs without mutating infrastructure."""
with suppress(FileNotFoundError):
outputs = load_outputs(STACK_NAME)
if (
outputs.get("landing_bucket")
and outputs.get("processed_bucket")
and outputs.get("ecr_image_uri")
):
return {
"landing_bucket": outputs["landing_bucket"],
"processed_bucket": outputs["processed_bucket"],
"ecr_image_uri": outputs["ecr_image_uri"],
}
lambda_client = get_boto3_client("lambda", REGION)
try:
env = (
lambda_client.get_function_configuration(FunctionName=TRIGGER_LAMBDA_NAME)
.get("Environment", {})
.get("Variables", {})
)
except Exception:
env = {}
landing = (env.get("LANDING_BUCKET") or "").strip()
processed = (env.get("PROCESSED_BUCKET") or "").strip()
image_uri = (env.get("IMAGE_URI") or "").strip()
if landing and processed and image_uri:
return {
"landing_bucket": landing,
"processed_bucket": processed,
"ecr_image_uri": image_uri,
}
tagger = get_boto3_client("resourcegroupstaggingapi", REGION)
s3_client = get_boto3_client("s3", REGION)
ecr_client = get_boto3_client("ecr", REGION)
created_at = {
bucket["Name"]: bucket["CreationDate"]
for bucket in s3_client.list_buckets().get("Buckets", [])
}
bucket_names: list[str] = []
paginator = tagger.get_paginator("get_resources")
for page in paginator.paginate(
TagFilters=[
{"Key": "tracer:stack", "Values": [STACK_NAME]},
{"Key": "tracer:managed", "Values": ["sdk"]},
],
ResourceTypeFilters=["s3"],
):
for resource in page.get("ResourceTagMappingList", []):
arn = resource.get("ResourceARN", "")
if arn.startswith("arn:aws:s3:::"):
bucket_names.append(arn.split(":::")[1])
landing_buckets = [b for b in bucket_names if b.startswith("tracer-k8s-landing-")]
processed_buckets = [b for b in bucket_names if b.startswith("tracer-k8s-processed-")]
if not landing_buckets or not processed_buckets:
return None
def _latest_bucket(names: list[str]) -> str:
return max(names, key=lambda n: created_at.get(n))
try:
repo = ecr_client.describe_repositories(repositoryNames=[ECR_REPO_NAME])
repo_uri = repo["repositories"][0]["repositoryUri"]
image_uri = f"{repo_uri}:latest"
except Exception:
return None
return {
"landing_bucket": _latest_bucket(landing_buckets),
"processed_bucket": _latest_bucket(processed_buckets),
"ecr_image_uri": image_uri,
}
def regenerate_trigger_config() -> Path:
trigger_api_url = _discover_trigger_api_url()
if not trigger_api_url:
raise RuntimeError(
"Could not discover trigger API URL from AWS tags. "
"Ensure trigger API exists and is tagged with tracer:stack=tracer-eks-k8s-test."
)
return save_trigger_config(trigger_api_url)