Initial commit

This commit is contained in:
Songhaoz666
2026-06-08 17:32:34 +08:00
commit d0fa193f79
91 changed files with 19645 additions and 0 deletions
+94
View File
@@ -0,0 +1,94 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: agent-runtime-config
namespace: swarm-system
data:
ORCHESTRATOR_URL: "ws://orchestrator-service:8000"
WORKSPACE_DIR: "/workspace"
GIT_REPO_URL: "git://git-test-server.swarm-system.svc.cluster.local/swarm-test.git"
GIT_BASE_BRANCH: "main"
AGENT_CAPABILITIES: "code_generation,git,python,filesystem,file-operations,editing,validation,verification,shell,reporting,repository-inspection"
ENABLE_SUBTASK_HANDOFF: "false"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: agent-full
namespace: swarm-system
labels:
app: agent-full
component: worker
spec:
replicas: 1
selector:
matchLabels:
app: agent-full
template:
metadata:
labels:
app: agent-full
component: worker
spec:
serviceAccountName: orchestrator-sa
containers:
- name: agent
image: python:3.11-slim
command:
- /bin/bash
- -c
- |
set -euxo pipefail
apt-get update
apt-get install -y git
pip install --no-cache-dir -r /app/agent/requirements.txt
cd /app
python -m agent.main
envFrom:
- configMapRef:
name: agent-runtime-config
env:
- name: AGENT_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: openai-api-key
key: api-key
- name: OPENAI_API_BASE
valueFrom:
secretKeyRef:
name: openai-api-key
key: api-base
optional: true
- name: OPENAI_MODEL
valueFrom:
secretKeyRef:
name: openai-api-key
key: model
optional: true
- name: PYTHONUNBUFFERED
value: "1"
- name: DEBIAN_FRONTEND
value: noninteractive
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
volumeMounts:
- name: agent-source
mountPath: /app/agent
- name: workspace
mountPath: /workspace
volumes:
- name: agent-source
configMap:
name: agent-source
- name: workspace
emptyDir: {}
restartPolicy: Always
+241
View File
@@ -0,0 +1,241 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: agent
namespace: swarm-system
labels:
app: agent
component: worker
spec:
replicas: 1
selector:
matchLabels:
app: agent
template:
metadata:
labels:
app: agent
component: worker
spec:
serviceAccountName: orchestrator-sa
containers:
- name: agent
image: python:3.11-slim
command:
- /bin/bash
- -c
- |
set -e
echo "Installing dependencies..."
pip install --no-cache-dir \
websockets \
prometheus-client \
gitpython \
openai
echo "Setting up agent code..."
mkdir -p /tmp/agent
cd /tmp/agent
echo "Starting agent..."
python3 -c "
import asyncio
import json
import logging
import os
import sys
import time
import uuid
from typing import Optional
import websockets
from websockets.exceptions import ConnectionClosed
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class SimpleAgent:
def __init__(self, orchestrator_url: str, agent_id: str):
self.orchestrator_url = orchestrator_url
self.agent_id = agent_id
self.api_key = os.getenv('OPENAI_API_KEY')
self.api_base = os.getenv('OPENAI_API_BASE', 'https://api.openai.com/v1')
self.model = os.getenv('OPENAI_MODEL', 'gpt-4o-mini')
self.ws = None
self.running = True
async def connect(self):
logger.info(f'Connecting to orchestrator at {self.orchestrator_url}')
self.ws = await websockets.connect(self.orchestrator_url)
# Register with orchestrator
register_msg = {
'type': 'register',
'agent_id': self.agent_id,
'capabilities': ['code_generation', 'code_review'],
'status': 'idle'
}
await self.ws.send(json.dumps(register_msg))
logger.info(f'Agent {self.agent_id} registered')
async def send_heartbeat(self):
while self.running:
try:
if self.ws:
heartbeat_msg = {
'type': 'heartbeat',
'agent_id': self.agent_id,
'status': 'idle',
'timestamp': time.time()
}
await self.ws.send(json.dumps(heartbeat_msg))
logger.debug(f'Heartbeat sent')
except Exception as e:
logger.error(f'Heartbeat error: {e}')
await asyncio.sleep(15)
async def execute_task(self, task_data):
task_id = task_data.get('task_id')
description = task_data.get('description')
logger.info(f'Executing task {task_id}: {description}')
try:
# Use OpenAI-compatible API
from openai import OpenAI
client = OpenAI(
api_key=self.api_key,
base_url=self.api_base
)
response = client.chat.completions.create(
model=self.model,
messages=[
{'role': 'system', 'content': 'You are a helpful coding assistant. Generate clean, working code.'},
{'role': 'user', 'content': description}
],
max_tokens=2000
)
result = response.choices[0].message.content
# Send result back
result_msg = {
'type': 'task_result',
'task_id': task_id,
'agent_id': self.agent_id,
'status': 'completed',
'result': result,
'timestamp': time.time()
}
await self.ws.send(json.dumps(result_msg))
logger.info(f'Task {task_id} completed')
except Exception as e:
logger.error(f'Task execution failed: {e}')
error_msg = {
'type': 'task_result',
'task_id': task_id,
'agent_id': self.agent_id,
'status': 'failed',
'error': str(e),
'timestamp': time.time()
}
await self.ws.send(json.dumps(error_msg))
async def listen(self):
while self.running:
try:
message = await self.ws.recv()
data = json.loads(message)
msg_type = data.get('type')
logger.info(f'Received message: {msg_type}')
if msg_type == 'task_assignment':
await self.execute_task(data)
elif msg_type == 'ping':
pong_msg = {'type': 'pong', 'agent_id': self.agent_id}
await self.ws.send(json.dumps(pong_msg))
except ConnectionClosed:
logger.warning('Connection closed, reconnecting...')
await asyncio.sleep(5)
await self.connect()
except Exception as e:
logger.error(f'Listen error: {e}')
await asyncio.sleep(1)
async def run(self):
await self.connect()
# Start heartbeat task
heartbeat_task = asyncio.create_task(self.send_heartbeat())
# Start listening
await self.listen()
heartbeat_task.cancel()
async def main():
orchestrator_url = os.getenv('ORCHESTRATOR_URL', 'ws://orchestrator-service:8000/ws')
agent_id = os.getenv('AGENT_ID', f'agent-{uuid.uuid4().hex[:8]}')
logger.info(f'Starting agent {agent_id}')
logger.info(f'Orchestrator URL: {orchestrator_url}')
agent = SimpleAgent(orchestrator_url, agent_id)
await agent.run()
if __name__ == '__main__':
asyncio.run(main())
"
env:
- name: AGENT_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: ORCHESTRATOR_URL
value: "ws://orchestrator-service:8000/ws/$(AGENT_ID)"
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: openai-api-key
key: api-key
- name: OPENAI_API_BASE
valueFrom:
secretKeyRef:
name: openai-api-key
key: api-base
optional: true
- name: OPENAI_MODEL
valueFrom:
secretKeyRef:
name: openai-api-key
key: model
optional: true
- name: PYTHONUNBUFFERED
value: "1"
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
volumeMounts:
- name: agent-source
mountPath: /app
- name: workspace
mountPath: /workspace
volumes:
- name: agent-source
configMap:
name: agent-source
- name: workspace
emptyDir: {}
restartPolicy: Always
+225
View File
@@ -0,0 +1,225 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: agent
namespace: swarm-system
labels:
app: agent
component: worker
spec:
replicas: 1
selector:
matchLabels:
app: agent
template:
metadata:
labels:
app: agent
component: worker
spec:
serviceAccountName: orchestrator-sa
containers:
- name: agent
image: python:3.11-slim
command:
- /bin/bash
- -c
- |
set -e
echo "Installing dependencies..."
pip install --no-cache-dir \
websockets \
openai \
prometheus-client
echo "Starting agent..."
python3 -c "
import asyncio
import json
import logging
import os
import sys
import time
import uuid
from typing import Optional
import websockets
from websockets.exceptions import ConnectionClosed
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class SimpleAgent:
def __init__(self, orchestrator_url: str, agent_id: str):
self.orchestrator_url = orchestrator_url
self.agent_id = agent_id
self.api_key = os.getenv('OPENAI_API_KEY')
self.api_base = os.getenv('OPENAI_API_BASE', 'https://api.openai.com/v1')
self.model = os.getenv('OPENAI_MODEL', 'gpt-4o-mini')
self.ws = None
self.running = True
async def connect(self):
logger.info(f'Connecting to orchestrator at {self.orchestrator_url}')
self.ws = await websockets.connect(self.orchestrator_url)
# Register with orchestrator
register_msg = {
'type': 'register',
'agent_id': self.agent_id,
'capabilities': ['code_generation', 'code_review'],
'status': 'idle'
}
await self.ws.send(json.dumps(register_msg))
logger.info(f'Agent {self.agent_id} registered')
async def send_heartbeat(self):
while self.running:
try:
if self.ws:
heartbeat_msg = {
'type': 'heartbeat',
'agent_id': self.agent_id,
'status': 'idle',
'timestamp': time.time()
}
await self.ws.send(json.dumps(heartbeat_msg))
logger.debug(f'Heartbeat sent')
except Exception as e:
logger.error(f'Heartbeat error: {e}')
await asyncio.sleep(15)
async def execute_task(self, task_data):
task_id = task_data.get('task_id')
description = task_data.get('description')
logger.info(f'Executing task {task_id}: {description}')
try:
# Use OpenAI-compatible API
from openai import OpenAI
client = OpenAI(
api_key=self.api_key,
base_url=self.api_base
)
response = client.chat.completions.create(
model=self.model,
messages=[
{'role': 'system', 'content': 'You are a helpful coding assistant. Generate clean, working code.'},
{'role': 'user', 'content': description}
],
max_tokens=2000
)
result = response.choices[0].message.content
# Send result back
result_msg = {
'type': 'task_result',
'task_id': task_id,
'agent_id': self.agent_id,
'status': 'completed',
'result': result,
'timestamp': time.time()
}
await self.ws.send(json.dumps(result_msg))
logger.info(f'Task {task_id} completed')
except Exception as e:
logger.error(f'Task execution failed: {e}')
error_msg = {
'type': 'task_result',
'task_id': task_id,
'agent_id': self.agent_id,
'status': 'failed',
'error': str(e),
'timestamp': time.time()
}
await self.ws.send(json.dumps(error_msg))
async def listen(self):
while self.running:
try:
message = await self.ws.recv()
data = json.loads(message)
msg_type = data.get('type')
logger.info(f'Received message: {msg_type}')
if msg_type == 'task_assignment':
await self.execute_task(data)
elif msg_type == 'ping':
pong_msg = {'type': 'pong', 'agent_id': self.agent_id}
await self.ws.send(json.dumps(pong_msg))
except ConnectionClosed:
logger.warning('Connection closed, reconnecting...')
await asyncio.sleep(5)
await self.connect()
except Exception as e:
logger.error(f'Listen error: {e}')
await asyncio.sleep(1)
async def run(self):
await self.connect()
# Start heartbeat task
heartbeat_task = asyncio.create_task(self.send_heartbeat())
# Start listening
await self.listen()
heartbeat_task.cancel()
async def main():
orchestrator_url = os.getenv('ORCHESTRATOR_URL', 'ws://orchestrator-service:8000/ws')
agent_id = os.getenv('AGENT_ID', f'agent-{uuid.uuid4().hex[:8]}')
logger.info(f'Starting agent {agent_id}')
logger.info(f'Orchestrator URL: {orchestrator_url}')
agent = SimpleAgent(orchestrator_url, agent_id)
await agent.run()
if __name__ == '__main__':
asyncio.run(main())
"
env:
- name: AGENT_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: ORCHESTRATOR_URL
value: "ws://orchestrator-service:8000/ws/$(AGENT_ID)"
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: openai-api-key
key: api-key
- name: OPENAI_API_BASE
valueFrom:
secretKeyRef:
name: openai-api-key
key: api-base
optional: true
- name: OPENAI_MODEL
valueFrom:
secretKeyRef:
name: openai-api-key
key: model
optional: true
- name: PYTHONUNBUFFERED
value: "1"
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
restartPolicy: Always
+158
View File
@@ -0,0 +1,158 @@
apiVersion: v1
kind: Pod
metadata:
name: agent-${AGENT_ID}
labels:
app: swarm-agent
agent-id: ${AGENT_ID}
spec:
restartPolicy: Never
# Init container to clone workspace
initContainers:
- name: git-clone
image: alpine/git:latest
command:
- sh
- -c
- |
if [ -n "$GIT_REPO_URL" ]; then
echo "Cloning repository from $GIT_REPO_URL"
git clone $GIT_REPO_URL /workspace
else
echo "No GIT_REPO_URL provided, skipping clone"
mkdir -p /workspace
fi
env:
- name: GIT_REPO_URL
valueFrom:
configMapKeyRef:
name: swarm-config
key: git-repo-url
optional: true
volumeMounts:
- name: workspace
mountPath: /workspace
containers:
- name: agent
image: swarm-agent:latest
imagePullPolicy: IfNotPresent
env:
# Agent configuration
- name: AGENT_ID
value: ${AGENT_ID}
- name: AGENT_CAPABILITIES
value: ${AGENT_CAPABILITIES}
# Orchestrator connection
- name: ORCHESTRATOR_URL
value: "ws://orchestrator-service:8000"
# Workspace configuration
- name: WORKSPACE_DIR
value: "/workspace"
- name: GIT_REPO_URL
valueFrom:
configMapKeyRef:
name: swarm-config
key: git-repo-url
optional: true
# Model API key (OpenAI-compatible) — inject via secret_ref, never commit
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: openai-secret
key: api-key
# Model configuration (OpenAI-compatible)
- name: OPENAI_API_BASE
valueFrom:
configMapKeyRef:
name: swarm-config
key: openai-api-base
optional: true
- name: OPENAI_MODEL
valueFrom:
configMapKeyRef:
name: swarm-config
key: openai-model
optional: true
# Git credentials for push access
- name: GIT_USERNAME
valueFrom:
secretKeyRef:
name: git-credentials
key: username
optional: true
- name: GIT_PASSWORD
valueFrom:
secretKeyRef:
name: git-credentials
key: password
optional: true
volumeMounts:
- name: workspace
mountPath: /workspace
# Resource limits
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "2Gi"
cpu: "1000m"
# Health check
livenessProbe:
exec:
command:
- python
- -c
- "import sys; sys.exit(0)"
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
volumes:
- name: workspace
emptyDir: {}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: swarm-config
data:
git-repo-url: "" # Set this to your Git repository URL
openai-model: "gpt-4o-mini"
openai-api-base: "https://api.openai.com/v1" # Override for an OpenAI-compatible endpoint
---
apiVersion: v1
kind: Secret
metadata:
name: openai-secret
type: Opaque
stringData:
api-key: "" # Set via secret_ref / kubectl — do NOT commit a real key
---
apiVersion: v1
kind: Secret
metadata:
name: git-credentials
type: Opaque
stringData:
username: "" # Set this to your Git username
password: "" # Set this to your Git password or token
+90
View File
@@ -0,0 +1,90 @@
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: agent-image-puller
namespace: swarm-system
labels:
app: agent-image-puller
component: optimization
spec:
selector:
matchLabels:
app: agent-image-puller
template:
metadata:
labels:
app: agent-image-puller
spec:
# Run on all nodes including control plane
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
# Use host network to avoid CNI overhead
hostNetwork: true
initContainers:
# Pre-pull the agent image
- name: pull-agent-image
image: ghcr.io/heicode/swarm-agent:latest
command: ['sh', '-c', 'echo "Agent image pulled successfully"']
resources:
limits:
memory: "128Mi"
cpu: "100m"
# Pre-pull common base images
- name: pull-python-base
image: python:3.11-slim
command: ['sh', '-c', 'echo "Python base image pulled"']
resources:
limits:
memory: "128Mi"
cpu: "100m"
containers:
# Keep-alive container (does nothing but keeps DaemonSet running)
- name: pause
image: gcr.io/google_containers/pause:3.9
resources:
limits:
memory: "32Mi"
cpu: "10m"
requests:
memory: "16Mi"
cpu: "5m"
# Optional: Periodic re-pull to get latest images
- name: periodic-puller
image: docker:24-cli
command:
- /bin/sh
- -c
- |
while true; do
echo "Checking for image updates..."
# This would require docker socket mount in production
# For now, just sleep
sleep 3600 # Re-check every hour
done
resources:
limits:
memory: "64Mi"
cpu: "50m"
volumeMounts:
- name: docker-socket
mountPath: /var/run/docker.sock
readOnly: true
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: Socket
# Ensure DaemonSet runs before agent pods
priorityClassName: system-node-critical
+91
View File
@@ -0,0 +1,91 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: git-test-server
namespace: swarm-system
labels:
app: git-test-server
spec:
replicas: 1
selector:
matchLabels:
app: git-test-server
template:
metadata:
labels:
app: git-test-server
spec:
initContainers:
- name: init-repo
image: alpine:3.20
command:
- /bin/sh
- -c
- |
set -e
apk add --no-cache git >/dev/null
rm -rf /git/swarm-test.git /tmp/swarm-test-src
mkdir -p /tmp/swarm-test-src
cd /tmp/swarm-test-src
git init -b main
git config user.name "Swarm Test"
git config user.email "swarm-test@example.com"
cat > hello.py <<'PY'
def hello_world():
return "hello"
PY
git add hello.py
git commit -m "Initial test repository"
mkdir -p /git
git clone --bare /tmp/swarm-test-src /git/swarm-test.git
git -C /git/swarm-test.git config daemon.receivepack true
touch /git/swarm-test.git/git-daemon-export-ok
volumeMounts:
- name: git-data
mountPath: /git
containers:
- name: git
image: alpine:3.20
command:
- /bin/sh
- -c
- |
set -e
apk add --no-cache git git-daemon >/dev/null
git daemon \
--verbose \
--reuseaddr \
--base-path=/git \
--export-all \
--enable=receive-pack \
/git
ports:
- containerPort: 9418
name: git
volumeMounts:
- name: git-data
mountPath: /git
volumes:
- name: git-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: git-test-server
namespace: swarm-system
labels:
app: git-test-server
spec:
type: ClusterIP
ports:
- port: 9418
targetPort: git
protocol: TCP
name: git
selector:
app: git-test-server
+488
View File
@@ -0,0 +1,488 @@
{
"dashboard": {
"title": "HeiCode Swarm System Health",
"tags": ["swarm", "k8s", "agents"],
"timezone": "browser",
"schemaVersion": 16,
"version": 1,
"refresh": "10s",
"time": {
"from": "now-1h",
"to": "now"
},
"panels": [
{
"id": 1,
"title": "Active Agents",
"type": "stat",
"gridPos": {"x": 0, "y": 0, "w": 6, "h": 4},
"targets": [
{
"expr": "swarm:agents:active:total",
"legendFormat": "Active Agents"
}
],
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"thresholds": {
"mode": "absolute",
"steps": [
{"value": 0, "color": "green"},
{"value": 10, "color": "yellow"},
{"value": 20, "color": "red"}
]
}
}
}
},
{
"id": 2,
"title": "Task Completion Rate",
"type": "stat",
"gridPos": {"x": 6, "y": 0, "w": 6, "h": 4},
"targets": [
{
"expr": "swarm:tasks:completion_rate:5m",
"legendFormat": "Tasks/sec"
}
],
"fieldConfig": {
"defaults": {
"unit": "ops",
"decimals": 2
}
}
},
{
"id": 3,
"title": "Average Task Duration",
"type": "stat",
"gridPos": {"x": 12, "y": 0, "w": 6, "h": 4},
"targets": [
{
"expr": "swarm:tasks:duration:avg",
"legendFormat": "Avg Duration"
}
],
"fieldConfig": {
"defaults": {
"unit": "s",
"decimals": 1
}
}
},
{
"id": 4,
"title": "Pod Startup Time (P95)",
"type": "stat",
"gridPos": {"x": 18, "y": 0, "w": 6, "h": 4},
"targets": [
{
"expr": "swarm:pod:startup:p95",
"legendFormat": "P95 Startup"
}
],
"fieldConfig": {
"defaults": {
"unit": "s",
"decimals": 1,
"color": {"mode": "thresholds"},
"thresholds": {
"mode": "absolute",
"steps": [
{"value": 0, "color": "green"},
{"value": 30, "color": "yellow"},
{"value": 60, "color": "red"}
]
}
}
}
},
{
"id": 5,
"title": "Agent Count Over Time",
"type": "graph",
"gridPos": {"x": 0, "y": 4, "w": 12, "h": 8},
"targets": [
{
"expr": "swarm:agents:count:by_status",
"legendFormat": "{{status}}"
}
],
"yaxes": [
{"format": "short", "label": "Agents"},
{"format": "short"}
],
"legend": {"show": true, "alignAsTable": true, "rightSide": false}
},
{
"id": 6,
"title": "Task Metrics",
"type": "graph",
"gridPos": {"x": 12, "y": 4, "w": 12, "h": 8},
"targets": [
{
"expr": "rate(swarm_tasks_completed_total[5m])",
"legendFormat": "Completed"
},
{
"expr": "rate(swarm_tasks_failed_total[5m])",
"legendFormat": "Failed"
}
],
"yaxes": [
{"format": "ops", "label": "Tasks/sec"},
{"format": "short"}
]
},
{
"id": 7,
"title": "Handoff Latency Distribution",
"type": "graph",
"gridPos": {"x": 0, "y": 12, "w": 12, "h": 8},
"targets": [
{
"expr": "histogram_quantile(0.50, rate(swarm_handoff_duration_seconds_bucket[5m]))",
"legendFormat": "P50"
},
{
"expr": "histogram_quantile(0.95, rate(swarm_handoff_duration_seconds_bucket[5m]))",
"legendFormat": "P95"
},
{
"expr": "histogram_quantile(0.99, rate(swarm_handoff_duration_seconds_bucket[5m]))",
"legendFormat": "P99"
}
],
"yaxes": [
{"format": "s", "label": "Latency"},
{"format": "short"}
]
},
{
"id": 8,
"title": "Agent Creation Rate",
"type": "graph",
"gridPos": {"x": 12, "y": 12, "w": 12, "h": 8},
"targets": [
{
"expr": "swarm:agents:creation_rate:5m",
"legendFormat": "Creation Rate"
}
],
"yaxes": [
{"format": "ops", "label": "Agents/sec"},
{"format": "short"}
]
},
{
"id": 9,
"title": "System Resource Usage",
"type": "graph",
"gridPos": {"x": 0, "y": 20, "w": 12, "h": 8},
"targets": [
{
"expr": "sum(rate(container_cpu_usage_seconds_total{namespace=\"swarm-system\"}[5m]))",
"legendFormat": "CPU Usage"
},
{
"expr": "sum(container_memory_working_set_bytes{namespace=\"swarm-system\"}) / 1024 / 1024 / 1024",
"legendFormat": "Memory Usage (GB)"
}
],
"yaxes": [
{"format": "short", "label": "Resources"},
{"format": "short"}
]
},
{
"id": 10,
"title": "Redis Operations",
"type": "graph",
"gridPos": {"x": 12, "y": 20, "w": 12, "h": 8},
"targets": [
{
"expr": "rate(redis_commands_processed_total[5m])",
"legendFormat": "Commands/sec"
},
{
"expr": "redis_connected_clients",
"legendFormat": "Connected Clients"
}
],
"yaxes": [
{"format": "ops", "label": "Operations"},
{"format": "short"}
]
},
{
"id": 11,
"title": "Pod Status by Phase",
"type": "piechart",
"gridPos": {"x": 0, "y": 28, "w": 8, "h": 8},
"targets": [
{
"expr": "count by (phase) (kube_pod_status_phase{namespace=\"swarm-system\"})",
"legendFormat": "{{phase}}"
}
]
},
{
"id": 12,
"title": "Error Rate",
"type": "graph",
"gridPos": {"x": 8, "y": 28, "w": 8, "h": 8},
"targets": [
{
"expr": "rate(swarm_errors_total[5m])",
"legendFormat": "{{error_type}}"
}
],
"yaxes": [
{"format": "ops", "label": "Errors/sec"},
{"format": "short"}
],
"alert": {
"conditions": [
{
"evaluator": {"params": [0.1], "type": "gt"},
"operator": {"type": "and"},
"query": {"params": ["A", "5m", "now"]},
"reducer": {"params": [], "type": "avg"},
"type": "query"
}
],
"executionErrorState": "alerting",
"frequency": "60s",
"handler": 1,
"name": "High Error Rate",
"noDataState": "no_data",
"notifications": []
}
},
{
"id": 13,
"title": "Network I/O",
"type": "graph",
"gridPos": {"x": 16, "y": 28, "w": 8, "h": 8},
"targets": [
{
"expr": "rate(container_network_receive_bytes_total{namespace=\"swarm-system\"}[5m])",
"legendFormat": "RX {{pod}}"
},
{
"expr": "rate(container_network_transmit_bytes_total{namespace=\"swarm-system\"}[5m])",
"legendFormat": "TX {{pod}}"
}
],
"yaxes": [
{"format": "Bps", "label": "Bytes/sec"},
{"format": "short"}
]
},
{
"id": 14,
"title": "Top Agents by Duration",
"type": "table",
"gridPos": {"x": 0, "y": 36, "w": 12, "h": 8},
"targets": [
{
"expr": "topk(10, swarm_agent_duration_seconds)",
"format": "table",
"instant": true
}
],
"transformations": [
{
"id": "organize",
"options": {
"excludeByName": {"Time": true},
"indexByName": {},
"renameByName": {
"agent_id": "Agent ID",
"task_id": "Task ID",
"Value": "Duration (s)"
}
}
}
]
},
{
"id": 15,
"title": "Recent Failures",
"type": "table",
"gridPos": {"x": 12, "y": 36, "w": 12, "h": 8},
"targets": [
{
"expr": "topk(10, swarm_agent_failures)",
"format": "table",
"instant": true
}
],
"transformations": [
{
"id": "organize",
"options": {
"excludeByName": {"Time": true},
"indexByName": {},
"renameByName": {
"agent_id": "Agent ID",
"task_id": "Task ID",
"error_type": "Error Type",
"Value": "Count"
}
}
}
]
},
{
"id": 16,
"title": "Orchestrator Health",
"type": "stat",
"gridPos": {"x": 0, "y": 44, "w": 6, "h": 4},
"targets": [
{
"expr": "up{job=\"orchestrator\"}",
"legendFormat": "Status"
}
],
"fieldConfig": {
"defaults": {
"mappings": [
{"type": "value", "value": "0", "text": "DOWN"},
{"type": "value", "value": "1", "text": "UP"}
],
"color": {"mode": "thresholds"},
"thresholds": {
"mode": "absolute",
"steps": [
{"value": 0, "color": "red"},
{"value": 1, "color": "green"}
]
}
}
}
},
{
"id": 17,
"title": "Redis Health",
"type": "stat",
"gridPos": {"x": 6, "y": 44, "w": 6, "h": 4},
"targets": [
{
"expr": "up{job=\"redis\"}",
"legendFormat": "Status"
}
],
"fieldConfig": {
"defaults": {
"mappings": [
{"type": "value", "value": "0", "text": "DOWN"},
{"type": "value", "value": "1", "text": "UP"}
],
"color": {"mode": "thresholds"},
"thresholds": {
"mode": "absolute",
"steps": [
{"value": 0, "color": "red"},
{"value": 1, "color": "green"}
]
}
}
}
},
{
"id": 18,
"title": "Kubernetes Cluster Health",
"type": "stat",
"gridPos": {"x": 12, "y": 44, "w": 6, "h": 4},
"targets": [
{
"expr": "up{job=\"kubernetes-apiservers\"}",
"legendFormat": "API Server"
}
],
"fieldConfig": {
"defaults": {
"mappings": [
{"type": "value", "value": "0", "text": "DOWN"},
{"type": "value", "value": "1", "text": "UP"}
],
"color": {"mode": "thresholds"},
"thresholds": {
"mode": "absolute",
"steps": [
{"value": 0, "color": "red"},
{"value": 1, "color": "green"}
]
}
}
}
},
{
"id": 19,
"title": "Total System Cost (Estimated)",
"type": "stat",
"gridPos": {"x": 18, "y": 44, "w": 6, "h": 4},
"targets": [
{
"expr": "sum(swarm_agent_cost_usd)",
"legendFormat": "Total Cost"
}
],
"fieldConfig": {
"defaults": {
"unit": "currencyUSD",
"decimals": 2
}
}
}
],
"templating": {
"list": [
{
"name": "namespace",
"type": "query",
"query": "label_values(swarm_agent_status, namespace)",
"current": {"text": "swarm-system", "value": "swarm-system"},
"hide": 0,
"includeAll": false,
"multi": false,
"options": [],
"refresh": 1,
"regex": "",
"sort": 0
},
{
"name": "task_id",
"type": "query",
"query": "label_values(swarm_agent_status{namespace=\"$namespace\"}, task_id)",
"current": {"text": "All", "value": "$__all"},
"hide": 0,
"includeAll": true,
"multi": true,
"options": [],
"refresh": 1,
"regex": "",
"sort": 0
}
]
},
"annotations": {
"list": [
{
"datasource": "Prometheus",
"enable": true,
"expr": "ALERTS{alertstate=\"firing\"}",
"iconColor": "red",
"name": "Alerts",
"step": "60s",
"tagKeys": "alertname",
"textFormat": "{{alertname}}",
"titleFormat": "Alert"
}
]
}
}
}
+108
View File
@@ -0,0 +1,108 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: orchestrator-config
namespace: swarm-system
data:
REDIS_HOST: "redis-service"
REDIS_PORT: "6379"
LOG_LEVEL: "INFO"
SWARM_RUNTIME_SOURCE: "heicode-swarm-runtime"
SWARM_RUNTIME_PLATFORM: "aks"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: orchestrator
namespace: swarm-system
labels:
app: orchestrator
spec:
replicas: 1
selector:
matchLabels:
app: orchestrator
template:
metadata:
labels:
app: orchestrator
spec:
serviceAccountName: orchestrator-sa
containers:
- name: orchestrator
image: python:3.11-slim
command: ["/bin/bash", "-c"]
args:
- |
apt-get update && apt-get install -y git
pip install --no-cache-dir -r /app/orchestrator/requirements.txt
cd /app
python -m uvicorn orchestrator.main:app --host 0.0.0.0 --port 8000
ports:
- containerPort: 8000
name: http
envFrom:
- configMapRef:
name: orchestrator-config
env:
- name: AGNET_RUNTIME_SERVICE_TOKEN
valueFrom:
secretKeyRef:
name: agnet-runtime-secrets
key: runtime-service-token
optional: true
- name: AGNET_CALLBACK_SERVICE_TOKEN
valueFrom:
secretKeyRef:
name: agnet-runtime-secrets
key: callback-service-token
optional: true
- name: AGNET_CALLBACK_SIGNING_SECRET
valueFrom:
secretKeyRef:
name: agnet-runtime-secrets
key: callback-signing-secret
optional: true
volumeMounts:
- name: orchestrator-code
mountPath: /app/orchestrator
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 5
volumes:
- name: orchestrator-code
configMap:
name: orchestrator-source
---
apiVersion: v1
kind: Service
metadata:
name: orchestrator-service
namespace: swarm-system
labels:
app: orchestrator
spec:
type: LoadBalancer
ports:
- port: 8000
targetPort: 8000
protocol: TCP
name: http
selector:
app: orchestrator
+73
View File
@@ -0,0 +1,73 @@
apiVersion: v1
kind: Service
metadata:
name: orchestrator-service
namespace: swarm-system
labels:
app: orchestrator
spec:
type: ClusterIP
ports:
- port: 8000
targetPort: 8000
name: http
selector:
app: orchestrator
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: orchestrator
namespace: swarm-system
labels:
app: orchestrator
spec:
replicas: 1
selector:
matchLabels:
app: orchestrator
template:
metadata:
labels:
app: orchestrator
spec:
serviceAccountName: swarm-orchestrator
containers:
- name: orchestrator
image: swarm-orchestrator:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8000
name: http
env:
- name: REDIS_HOST
value: "redis-service"
- name: REDIS_PORT
value: "6379"
- name: REDIS_DB
value: "0"
- name: LOG_LEVEL
value: "INFO"
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
File diff suppressed because it is too large Load Diff
+348
View File
@@ -0,0 +1,348 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
namespace: swarm-system
data:
prometheus.yml: |
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
cluster: 'swarm-k8s'
environment: 'production'
# Alerting configuration
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
# Scrape configurations
scrape_configs:
# Prometheus itself
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# Orchestrator metrics
- job_name: 'orchestrator'
kubernetes_sd_configs:
- role: pod
namespaces:
names:
- swarm-system
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
action: keep
regex: orchestrator
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
- source_labels: [__address__]
target_label: __address__
regex: ([^:]+)(?::\d+)?
replacement: $1:8000
# Agent pods metrics
- job_name: 'agents'
kubernetes_sd_configs:
- role: pod
namespaces:
names:
- swarm-system
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
action: keep
regex: swarm-agent
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
- source_labels: [__meta_kubernetes_pod_label_task_id]
target_label: task_id
- source_labels: [__meta_kubernetes_pod_label_agent_id]
target_label: agent_id
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
- source_labels: [__address__]
target_label: __address__
regex: ([^:]+)(?::\d+)?
replacement: $1:8080
# Redis metrics (via redis_exporter)
- job_name: 'redis'
static_configs:
- targets: ['redis-exporter:9121']
labels:
service: 'redis'
# Kubernetes API server
- job_name: 'kubernetes-apiservers'
kubernetes_sd_configs:
- role: endpoints
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
action: keep
regex: default;kubernetes;https
# Kubernetes nodes
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
# Kubernetes pods (general)
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
target_label: kubernetes_pod_name
# Recording rules for aggregations
rule_files:
- /etc/prometheus/rules/*.yml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-rules
namespace: swarm-system
data:
swarm_rules.yml: |
groups:
- name: swarm_metrics
interval: 30s
rules:
# Agent count by status
- record: swarm:agents:count:by_status
expr: count by (status) (swarm_agent_status)
# Total active agents
- record: swarm:agents:active:total
expr: count(swarm_agent_status{status="running"})
# Average task duration
- record: swarm:tasks:duration:avg
expr: avg(swarm_task_duration_seconds)
# Task completion rate (last 5m)
- record: swarm:tasks:completion_rate:5m
expr: rate(swarm_tasks_completed_total[5m])
# Agent creation rate (last 5m)
- record: swarm:agents:creation_rate:5m
expr: rate(swarm_agents_created_total[5m])
# Handoff latency p95
- record: swarm:handoff:latency:p95
expr: histogram_quantile(0.95, rate(swarm_handoff_duration_seconds_bucket[5m]))
# Pod startup time p95
- record: swarm:pod:startup:p95
expr: histogram_quantile(0.95, rate(swarm_pod_startup_seconds_bucket[5m]))
- name: swarm_alerts
interval: 30s
rules:
# Alert if too many agents are failing
- alert: HighAgentFailureRate
expr: rate(swarm_agents_failed_total[5m]) > 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "High agent failure rate detected"
description: "Agent failure rate is {{ $value }} failures/sec"
# Alert if orchestrator is down
- alert: OrchestratorDown
expr: up{job="orchestrator"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Orchestrator is down"
description: "Orchestrator has been down for more than 1 minute"
# Alert if Redis is down
- alert: RedisDown
expr: up{job="redis"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Redis is down"
description: "Redis has been down for more than 1 minute"
# Alert if pod startup is slow
- alert: SlowPodStartup
expr: swarm:pod:startup:p95 > 60
for: 10m
labels:
severity: warning
annotations:
summary: "Pod startup time is slow"
description: "P95 pod startup time is {{ $value }}s (target: <30s)"
# Alert if handoff latency is high
- alert: HighHandoffLatency
expr: swarm:handoff:latency:p95 > 5
for: 5m
labels:
severity: warning
annotations:
summary: "High handoff latency detected"
description: "P95 handoff latency is {{ $value }}s"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: prometheus
namespace: swarm-system
spec:
replicas: 1
selector:
matchLabels:
app: prometheus
template:
metadata:
labels:
app: prometheus
spec:
serviceAccountName: prometheus
containers:
- name: prometheus
image: prom/prometheus:v2.45.0
args:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=30d'
- '--web.enable-lifecycle'
ports:
- containerPort: 9090
name: web
volumeMounts:
- name: config
mountPath: /etc/prometheus
- name: rules
mountPath: /etc/prometheus/rules
- name: storage
mountPath: /prometheus
resources:
requests:
memory: "2Gi"
cpu: "500m"
limits:
memory: "4Gi"
cpu: "2000m"
volumes:
- name: config
configMap:
name: prometheus-config
- name: rules
configMap:
name: prometheus-rules
- name: storage
persistentVolumeClaim:
claimName: prometheus-storage
---
apiVersion: v1
kind: Service
metadata:
name: prometheus
namespace: swarm-system
spec:
type: ClusterIP
ports:
- port: 9090
targetPort: 9090
name: web
selector:
app: prometheus
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: prometheus-storage
namespace: swarm-system
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
namespace: swarm-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups: [""]
resources:
- nodes
- nodes/proxy
- services
- endpoints
- pods
verbs: ["get", "list", "watch"]
- apiGroups:
- extensions
resources:
- ingresses
verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus
subjects:
- kind: ServiceAccount
name: prometheus
namespace: swarm-system
+23
View File
@@ -0,0 +1,23 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: orchestrator-role
namespace: default
labels:
app: heicode-swarm
component: orchestrator
rules:
# Pod management permissions
- apiGroups: [""]
resources: ["pods"]
verbs: ["create", "delete", "list", "watch", "get"]
# Pod log access
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
# Pod status monitoring
- apiGroups: [""]
resources: ["pods/status"]
verbs: ["get"]
+16
View File
@@ -0,0 +1,16 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: orchestrator-rolebinding
namespace: default
labels:
app: heicode-swarm
component: orchestrator
subjects:
- kind: ServiceAccount
name: orchestrator-sa
namespace: default
roleRef:
kind: Role
name: orchestrator-role
apiGroup: rbac.authorization.k8s.io
@@ -0,0 +1,8 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: orchestrator-sa
namespace: default
labels:
app: heicode-swarm
component: orchestrator
+85
View File
@@ -0,0 +1,85 @@
apiVersion: v1
kind: Service
metadata:
name: redis-service
namespace: swarm-system
labels:
app: redis
spec:
ports:
- port: 6379
targetPort: 6379
name: redis
clusterIP: None
selector:
app: redis
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
namespace: swarm-system
labels:
app: redis
spec:
serviceName: redis-service
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
name: redis
command:
- redis-server
- --appendonly
- "yes"
- --appendfsync
- everysec
- --maxmemory-policy
- allkeys-lru
- --maxmemory
- 256mb
volumeMounts:
- name: redis-data
mountPath: /data
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
tcpSocket:
port: 6379
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command:
- redis-cli
- ping
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumeClaimTemplates:
- metadata:
name: redis-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
+235
View File
@@ -0,0 +1,235 @@
# Test namespace and RBAC for HeiCode-Swarm testing
# Provides isolation and resource limits for test runs
---
# Test namespace
apiVersion: v1
kind: Namespace
metadata:
name: heicode-swarm-test
labels:
environment: test
purpose: agent-testing
---
# Resource quota to prevent runaway tests
apiVersion: v1
kind: ResourceQuota
metadata:
name: test-resource-quota
namespace: heicode-swarm-test
spec:
hard:
# Limit total pods to prevent cluster overload
pods: "25"
# CPU limits (enough for 20 agents + orchestrator + redis)
requests.cpu: "22"
limits.cpu: "25"
# Memory limits
requests.memory: "44Gi"
limits.memory: "50Gi"
# Storage limits
persistentvolumeclaims: "5"
requests.storage: "10Gi"
---
# Limit range for individual pods
apiVersion: v1
kind: LimitRange
metadata:
name: test-limit-range
namespace: heicode-swarm-test
spec:
limits:
# Default limits for containers
- type: Container
default:
cpu: "1"
memory: "2Gi"
defaultRequest:
cpu: "500m"
memory: "1Gi"
max:
cpu: "2"
memory: "4Gi"
min:
cpu: "100m"
memory: "128Mi"
# Pod limits
- type: Pod
max:
cpu: "2"
memory: "4Gi"
---
# ServiceAccount for test orchestrator
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-orchestrator-sa
namespace: heicode-swarm-test
labels:
component: orchestrator
environment: test
---
# Role for orchestrator pod management
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: test-orchestrator-role
namespace: heicode-swarm-test
labels:
component: orchestrator
environment: test
rules:
# Pod management permissions
- apiGroups: [""]
resources: ["pods"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
# Pod logs access
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
# Pod exec for debugging (test only)
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
# ConfigMaps for agent configuration
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
# Secrets for API keys
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
# Services for orchestrator/redis
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch"]
---
# RoleBinding to grant orchestrator permissions
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-orchestrator-rolebinding
namespace: heicode-swarm-test
labels:
component: orchestrator
environment: test
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: test-orchestrator-role
subjects:
- kind: ServiceAccount
name: test-orchestrator-sa
namespace: heicode-swarm-test
---
# ServiceAccount for test agents
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-agent-sa
namespace: heicode-swarm-test
labels:
component: agent
environment: test
---
# Role for agent pods (minimal permissions)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: test-agent-role
namespace: heicode-swarm-test
labels:
component: agent
environment: test
rules:
# Agents can only read their own pod info
- apiGroups: [""]
resources: ["pods"]
verbs: ["get"]
resourceNames: [] # Will be restricted to self via admission controller
# Read ConfigMaps for configuration
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
# Read Secrets for API keys
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
# RoleBinding for agent permissions
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-agent-rolebinding
namespace: heicode-swarm-test
labels:
component: agent
environment: test
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: test-agent-role
subjects:
- kind: ServiceAccount
name: test-agent-sa
namespace: heicode-swarm-test
---
# NetworkPolicy to isolate test namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-isolation-policy
namespace: heicode-swarm-test
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
# Allow traffic within namespace
- from:
- namespaceSelector:
matchLabels:
environment: test
# Allow traffic from control plane (for kubectl exec, logs)
- from:
- namespaceSelector:
matchLabels:
name: kube-system
egress:
# Allow DNS
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- protocol: UDP
port: 53
# Allow traffic within namespace
- to:
- namespaceSelector:
matchLabels:
environment: test
# Allow external API calls (model API, OpenAI-compatible, over HTTPS)
- to:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 443
# Allow Git operations
- to:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 22
- protocol: TCP
port: 9418