Files
tracer-cloud--opensre/tests/synthetic/mock_eks_backend/backend.py
T
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

204 lines
7.8 KiB
Python

"""EKSBackend Protocol and FixtureEKSBackend for synthetic K8s testing.
The Protocol defines the minimal surface the Kubernetes investigation agent
uses to query EKS workload state. FixtureEKSBackend satisfies it by serving
scenario fixture data in the exact shape the EKS tools under ``tools/EKS*/``
return — no HTTP calls, no AWS credentials required.
Usage
-----
resolved_integrations = {
"eks": {
"cluster_name": "",
"role_arn": "",
"_backend": FixtureEKSBackend(fixture),
}
}
Each tool's production resolver checks the ``_backend`` key first and delegates
to it when present, falling back to real EKS API calls when absent.
"""
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
if TYPE_CHECKING:
from tests.synthetic.eks.scenario_loader import K8sScenarioFixture
@runtime_checkable
class EKSBackend(Protocol):
"""Minimal EKS interface used by the Kubernetes investigation agent.
One method per evidence source under ``tools/EKS*/``:
list_pods → EKSListPodsTool response shape
get_events → EKSEventsTool response shape
list_deployments → EKSListDeploymentsTool response shape
get_node_health → EKSNodeHealthTool response shape
get_pod_logs → EKSPodLogsTool response shape
"""
def list_pods(
self, cluster_name: str = "", namespace: str = "", **kwargs: Any
) -> dict[str, Any]:
"""Return a response matching ``list_eks_pods``."""
def get_events(
self, cluster_name: str = "", namespace: str = "", **kwargs: Any
) -> dict[str, Any]:
"""Return a response matching ``get_eks_events``."""
def list_deployments(
self, cluster_name: str = "", namespace: str = "", **kwargs: Any
) -> dict[str, Any]:
"""Return a response matching ``list_eks_deployments``."""
def get_node_health(self, cluster_name: str = "", **kwargs: Any) -> dict[str, Any]:
"""Return a response matching ``get_eks_node_health``."""
def get_pod_logs(
self, cluster_name: str = "", namespace: str = "", pod_name: str = "", **kwargs: Any
) -> dict[str, Any]:
"""Return a response matching ``get_eks_pod_logs``."""
class FixtureEKSBackend:
"""EKSBackend implementation backed by a K8sScenarioFixture.
Each method wraps the corresponding fixture file in the envelope that the
real tool function returns. Calling a method for an evidence source that
the scenario did not declare in ``available_evidence`` raises ValueError.
"""
def __init__(self, fixture: K8sScenarioFixture) -> None:
self._fixture = fixture
def _cluster_name(self, override: str) -> str:
return override or self._fixture.metadata.cluster_name
def _namespace(self, override: str) -> str:
return override or self._fixture.metadata.namespace
def list_pods(self, cluster_name: str = "", namespace: str = "", **_: Any) -> dict[str, Any]:
pods_fixture = self._fixture.evidence.eks_pods
if pods_fixture is None:
raise ValueError(
f"{self._fixture.scenario_id}: list_pods called but "
"'eks_pods' is not declared in available_evidence"
)
pods = list(pods_fixture.get("pods", []))
failing_pods = [p for p in pods if p.get("phase") not in ("Running", "Succeeded")]
high_restart_pods = [
p for p in pods if any(c.get("restart_count", 0) > 3 for c in p.get("containers", []))
]
return {
"source": "eks",
"available": True,
"cluster_name": self._cluster_name(cluster_name),
"namespace": self._namespace(namespace),
"total_pods": len(pods),
"pods": pods,
"failing_pods": failing_pods,
"high_restart_pods": high_restart_pods,
"error": None,
}
def get_events(self, cluster_name: str = "", namespace: str = "", **_: Any) -> dict[str, Any]:
events_fixture = self._fixture.evidence.eks_events
if events_fixture is None:
raise ValueError(
f"{self._fixture.scenario_id}: get_events called but "
"'eks_events' is not declared in available_evidence"
)
warning_events = list(events_fixture.get("warning_events", []))
return {
"source": "eks",
"available": True,
"cluster_name": self._cluster_name(cluster_name),
"namespace": self._namespace(namespace),
"warning_events": warning_events,
"total_warning_count": len(warning_events),
"error": None,
}
def list_deployments(
self, cluster_name: str = "", namespace: str = "", **_: Any
) -> dict[str, Any]:
deployments_fixture = self._fixture.evidence.eks_deployments
if deployments_fixture is None:
raise ValueError(
f"{self._fixture.scenario_id}: list_deployments called but "
"'eks_deployments' is not declared in available_evidence"
)
deployments: list[dict[str, Any]] = []
for raw in deployments_fixture.get("deployments", []):
desired = int(raw.get("desired", 0))
ready = int(raw.get("ready", 0))
available = int(raw.get("available", 0))
unavailable = int(raw.get("unavailable", 0))
deployments.append(
{
"name": raw.get("name", ""),
"namespace": raw.get("namespace", ""),
"desired": desired,
"ready": ready,
"available": available,
"unavailable": unavailable,
"degraded": unavailable > 0 or ready < desired,
}
)
degraded = [d for d in deployments if d["degraded"]]
return {
"source": "eks",
"available": True,
"cluster_name": self._cluster_name(cluster_name),
"namespace": self._namespace(namespace),
"total_deployments": len(deployments),
"deployments": deployments,
"degraded_deployments": degraded,
"error": None,
}
def get_node_health(self, cluster_name: str = "", **_: Any) -> dict[str, Any]:
nodes_fixture = self._fixture.evidence.eks_node_health
if nodes_fixture is None:
raise ValueError(
f"{self._fixture.scenario_id}: get_node_health called but "
"'eks_node_health' is not declared in available_evidence"
)
nodes = list(nodes_fixture.get("nodes", []))
not_ready_count = sum(1 for n in nodes if n.get("ready") != "True")
return {
"source": "eks",
"available": True,
"cluster_name": self._cluster_name(cluster_name),
"nodes": nodes,
"total_nodes": len(nodes),
"not_ready_count": not_ready_count,
"error": None,
}
def get_pod_logs(
self,
cluster_name: str = "",
namespace: str = "",
pod_name: str = "",
**_: Any,
) -> dict[str, Any]:
logs_fixture = self._fixture.evidence.eks_pod_logs
if logs_fixture is None:
raise ValueError(
f"{self._fixture.scenario_id}: get_pod_logs called but "
"'eks_pod_logs' is not declared in available_evidence"
)
return {
"source": "eks",
"available": True,
"cluster_name": self._cluster_name(cluster_name),
"namespace": self._namespace(namespace) or logs_fixture.get("namespace", ""),
"pod_name": pod_name or logs_fixture.get("pod_name", ""),
"logs": logs_fixture.get("logs", ""),
"error": None,
}