initial a2a-pack
This commit is contained in:
133
a2a_pack/cli/manifests.py
Normal file
133
a2a_pack/cli/manifests.py
Normal file
@@ -0,0 +1,133 @@
|
||||
"""Generate Kubernetes manifests for a deployed agent.
|
||||
|
||||
Targets the existing local cluster: namespace ``agents``, registry at
|
||||
``localhost:30500``, traefik ingress at ``<name>.127-0-0-1.nip.io``.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import yaml
|
||||
|
||||
from ..agent import A2AAgent
|
||||
|
||||
NAMESPACE = "agents"
|
||||
INGRESS_HOST_TEMPLATE = "{name}.127-0-0-1.nip.io"
|
||||
|
||||
|
||||
def render_manifests(
|
||||
agent_cls: type[A2AAgent],
|
||||
*,
|
||||
image: str,
|
||||
public: bool = True,
|
||||
) -> str:
|
||||
"""Return a multi-doc YAML string ready for ``kubectl apply -f -``."""
|
||||
rt = agent_cls.runtime()
|
||||
name = agent_cls.name
|
||||
docs: list[dict[str, Any]] = []
|
||||
|
||||
docs.append(
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Namespace",
|
||||
"metadata": {"name": NAMESPACE},
|
||||
}
|
||||
)
|
||||
|
||||
docs.append(
|
||||
{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": {
|
||||
"name": name,
|
||||
"namespace": NAMESPACE,
|
||||
"labels": {
|
||||
"app": name,
|
||||
"a2a/version": agent_cls.version,
|
||||
"a2a/lifecycle": rt.lifecycle.value,
|
||||
},
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {"matchLabels": {"app": name}},
|
||||
"template": {
|
||||
"metadata": {"labels": {"app": name}},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "agent",
|
||||
"image": image,
|
||||
"imagePullPolicy": "Always",
|
||||
"ports": [{"containerPort": 8000, "name": "http"}],
|
||||
"readinessProbe": {
|
||||
"httpGet": {"path": "/healthz", "port": 8000},
|
||||
"initialDelaySeconds": 2,
|
||||
"periodSeconds": 5,
|
||||
},
|
||||
"livenessProbe": {
|
||||
"httpGet": {"path": "/healthz", "port": 8000},
|
||||
"initialDelaySeconds": 10,
|
||||
"periodSeconds": 15,
|
||||
},
|
||||
"resources": {
|
||||
"requests": {
|
||||
"cpu": rt.resources.cpu,
|
||||
"memory": rt.resources.memory,
|
||||
},
|
||||
"limits": {
|
||||
"cpu": rt.resources.cpu,
|
||||
"memory": rt.resources.memory,
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
docs.append(
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Service",
|
||||
"metadata": {"name": name, "namespace": NAMESPACE},
|
||||
"spec": {
|
||||
"type": "ClusterIP",
|
||||
"selector": {"app": name},
|
||||
"ports": [{"name": "http", "port": 80, "targetPort": 8000}],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if public:
|
||||
docs.append(
|
||||
{
|
||||
"apiVersion": "networking.k8s.io/v1",
|
||||
"kind": "Ingress",
|
||||
"metadata": {"name": name, "namespace": NAMESPACE},
|
||||
"spec": {
|
||||
"rules": [
|
||||
{
|
||||
"host": INGRESS_HOST_TEMPLATE.format(name=name),
|
||||
"http": {
|
||||
"paths": [
|
||||
{
|
||||
"path": "/",
|
||||
"pathType": "Prefix",
|
||||
"backend": {
|
||||
"service": {
|
||||
"name": name,
|
||||
"port": {"number": 80},
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
return "---\n".join(yaml.safe_dump(d, sort_keys=False) for d in docs)
|
||||
Reference in New Issue
Block a user