246 lines
11 KiB
Python
246 lines
11 KiB
Python
"""
|
|
GUARDiA 클라우드 네이티브 인프라 — Gen6
|
|
eBPF 계측·Wasm 엣지·서비스 메시·이벤트 소싱·시크릿 관리·멀티런타임
|
|
"""
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Any, Dict, List, Optional
|
|
from fastapi import APIRouter, HTTPException, Query
|
|
from pydantic import BaseModel
|
|
|
|
router = APIRouter(prefix="/api/infra", tags=["Cloud Native Infra"])
|
|
|
|
_ebpf_probes: Dict[str, Dict] = {}
|
|
_wasm_modules: Dict[str, Dict] = {}
|
|
_mesh_services: Dict[str, Dict] = {}
|
|
_events: List[Dict] = []
|
|
_secrets: Dict[str, Dict] = {}
|
|
_runtimes: Dict[str, Dict] = {}
|
|
|
|
class EBPFProbe(BaseModel):
|
|
name: str; program_type: str = "kprobe" # kprobe|tracepoint|xdp|tc
|
|
target: str; filter_expr: str = ""; owner: str = "platform"
|
|
|
|
class WasmModule(BaseModel):
|
|
name: str; wasm_binary_url: str = ""
|
|
runtime: str = "wasmtime"; memory_mb: int = 64
|
|
env: Dict[str, str] = {}
|
|
|
|
class MeshService(BaseModel):
|
|
service: str; version: str = "v1"
|
|
protocol: str = "http2"; mtls: bool = True
|
|
circuit_breaker: bool = True; retries: int = 3
|
|
|
|
class EventCreate(BaseModel):
|
|
aggregate_id: str; aggregate_type: str
|
|
event_type: str; payload: Dict[str, Any] = {}
|
|
correlation_id: Optional[str] = None
|
|
|
|
class SecretCreate(BaseModel):
|
|
name: str; value: str; engine: str = "vault" # vault|k8s|env
|
|
rotate_days: int = 90; owner: str = ""
|
|
|
|
class RuntimeCreate(BaseModel):
|
|
name: str; runtime_type: str = "wasmtime" # wasmtime|spin|containerd|gvisor
|
|
config: Dict[str, Any] = {}
|
|
|
|
# ── eBPF 계측 ─────────────────────────────────────────────────────────────
|
|
@router.post("/ebpf/probes")
|
|
async def create_ebpf_probe(probe: EBPFProbe):
|
|
pid = f"EBPF-{uuid.uuid4().hex[:8].upper()}"
|
|
_ebpf_probes[pid] = {**probe.model_dump(), "id": pid, "status": "attached",
|
|
"created_at": datetime.utcnow().isoformat(), "events_captured": 0}
|
|
return _ebpf_probes[pid]
|
|
|
|
@router.get("/ebpf/probes")
|
|
async def list_ebpf_probes():
|
|
probes = list(_ebpf_probes.values()) or [
|
|
{"id": "EBPF-SYS001", "name": "syscall_monitor", "type": "kprobe", "status": "attached"},
|
|
{"id": "EBPF-NET001", "name": "network_flow", "type": "xdp", "status": "attached"},
|
|
]
|
|
return {"probes": probes, "total": len(probes)}
|
|
|
|
@router.get("/ebpf/probes/{pid}/metrics")
|
|
async def ebpf_probe_metrics(pid: str):
|
|
return {"probe_id": pid, "events_per_sec": 1240, "latency_p99_us": 45,
|
|
"cpu_overhead_pct": 0.3, "ts": datetime.utcnow().isoformat()}
|
|
|
|
@router.delete("/ebpf/probes/{pid}")
|
|
async def detach_ebpf_probe(pid: str):
|
|
_ebpf_probes.pop(pid, None); return {"detached": pid}
|
|
|
|
@router.get("/ebpf/trace")
|
|
async def live_trace(program: str = "syscall", duration_sec: int = 5):
|
|
return {"program": program, "duration_sec": duration_sec,
|
|
"trace": [
|
|
{"ts": datetime.utcnow().isoformat(), "pid": 1234, "comm": "guardia-api", "event": "tcp_connect", "latency_ns": 4500},
|
|
{"ts": datetime.utcnow().isoformat(), "pid": 1234, "comm": "guardia-api", "event": "sys_read", "latency_ns": 120},
|
|
]}
|
|
|
|
@router.get("/ebpf/topology")
|
|
async def network_topology():
|
|
return {"nodes": [
|
|
{"id": "guardia-itsm", "type": "service", "ip": "10.0.1.10"},
|
|
{"id": "guardia-manager", "type": "service", "ip": "10.0.1.11"},
|
|
{"id": "postgres", "type": "database", "ip": "10.0.1.20"},
|
|
], "edges": [
|
|
{"from": "guardia-itsm", "to": "postgres", "protocol": "tcp", "port": 5432},
|
|
{"from": "guardia-manager", "to": "guardia-itsm", "protocol": "tcp", "port": 8001},
|
|
], "captured_by": "eBPF XDP"}
|
|
|
|
# ── Wasm 엣지 모듈 ───────────────────────────────────────────────────────
|
|
@router.post("/wasm/modules")
|
|
async def deploy_wasm(module: WasmModule):
|
|
mid = f"WASM-{uuid.uuid4().hex[:8].upper()}"
|
|
_wasm_modules[mid] = {**module.model_dump(), "id": mid, "status": "running",
|
|
"deployed_at": datetime.utcnow().isoformat()}
|
|
return _wasm_modules[mid]
|
|
|
|
@router.get("/wasm/modules")
|
|
async def list_wasm():
|
|
modules = list(_wasm_modules.values()) or [
|
|
{"id": "WASM-EDGE01", "name": "request-validator", "runtime": "wasmtime", "status": "running"},
|
|
]
|
|
return {"modules": modules, "total": len(modules)}
|
|
|
|
@router.get("/wasm/modules/{mid}/logs")
|
|
async def wasm_logs(mid: str, lines: int = 50):
|
|
return {"module_id": mid, "logs": [
|
|
f"[2026-06-06T00:00:00Z] Module {mid} started",
|
|
f"[2026-06-06T00:00:01Z] Processed 1240 requests",
|
|
][-lines:]}
|
|
|
|
@router.post("/wasm/modules/{mid}/invoke")
|
|
async def invoke_wasm(mid: str, input: Dict[str, Any] = {}):
|
|
m = _wasm_modules.get(mid)
|
|
if not m: raise HTTPException(404)
|
|
return {"module_id": mid, "input": input, "output": {"result": "ok", "processed": True},
|
|
"exec_time_ms": 1.2, "ts": datetime.utcnow().isoformat()}
|
|
|
|
# ── 서비스 메시 ────────────────────────────────────────────────────────────
|
|
@router.post("/mesh/services")
|
|
async def register_mesh_service(svc: MeshService):
|
|
sid = f"MESH-{uuid.uuid4().hex[:8].upper()}"
|
|
_mesh_services[sid] = {**svc.model_dump(), "id": sid, "status": "enrolled",
|
|
"enrolled_at": datetime.utcnow().isoformat()}
|
|
return _mesh_services[sid]
|
|
|
|
@router.get("/mesh/services")
|
|
async def list_mesh_services():
|
|
svcs = list(_mesh_services.values()) or [
|
|
{"service": "guardia-itsm", "mtls": True, "status": "enrolled"},
|
|
{"service": "guardia-manager", "mtls": True, "status": "enrolled"},
|
|
]
|
|
return {"services": svcs, "total": len(svcs)}
|
|
|
|
@router.get("/mesh/traffic")
|
|
async def mesh_traffic():
|
|
return {"services": [
|
|
{"from": "guardia-manager", "to": "guardia-itsm", "rps": 142, "error_rate": 0.1, "p99_ms": 45},
|
|
{"from": "guardia-itsm", "to": "postgres", "rps": 520, "error_rate": 0.0, "p99_ms": 12},
|
|
]}
|
|
|
|
@router.get("/mesh/policies")
|
|
async def mesh_policies():
|
|
return {"policies": [
|
|
{"type": "circuit_breaker", "service": "guardia-itsm", "threshold": 50, "window_sec": 10},
|
|
{"type": "retry", "service": "guardia-manager", "max_attempts": 3, "backoff_ms": 100},
|
|
]}
|
|
|
|
@router.post("/mesh/policies")
|
|
async def create_mesh_policy(service: str, policy_type: str, rules: Dict[str, Any] = {}):
|
|
return {"id": f"POL-{uuid.uuid4().hex[:8].upper()}", "service": service,
|
|
"type": policy_type, "rules": rules, "applied": True,
|
|
"ts": datetime.utcnow().isoformat()}
|
|
|
|
# ── 이벤트 소싱 ────────────────────────────────────────────────────────────
|
|
@router.post("/events/publish")
|
|
async def publish_event(event: EventCreate):
|
|
eid = f"EVT-{uuid.uuid4().hex[:8].upper()}"
|
|
record = {**event.model_dump(), "id": eid, "sequence": len(_events) + 1,
|
|
"published_at": datetime.utcnow().isoformat()}
|
|
_events.append(record)
|
|
return record
|
|
|
|
@router.get("/events/stream")
|
|
async def get_event_stream(aggregate_id: Optional[str] = None,
|
|
event_type: Optional[str] = None, limit: int = 100):
|
|
evts = _events
|
|
if aggregate_id: evts = [e for e in evts if e["aggregate_id"] == aggregate_id]
|
|
if event_type: evts = [e for e in evts if e["event_type"] == event_type]
|
|
return {"events": evts[-limit:], "total": len(evts)}
|
|
|
|
@router.get("/events/replay/{aggregate_id}")
|
|
async def replay_events(aggregate_id: str, from_sequence: int = 0):
|
|
evts = [e for e in _events if e["aggregate_id"] == aggregate_id
|
|
and e.get("sequence", 0) >= from_sequence]
|
|
return {"aggregate_id": aggregate_id, "events": evts, "replayed": len(evts)}
|
|
|
|
@router.get("/events/projections")
|
|
async def list_projections():
|
|
return {"projections": [
|
|
{"name": "sr-read-model", "last_event": len(_events), "status": "up-to-date"},
|
|
{"name": "server-state", "last_event": len(_events), "status": "up-to-date"},
|
|
]}
|
|
|
|
# ── 시크릿 관리 ────────────────────────────────────────────────────────────
|
|
@router.post("/secrets")
|
|
async def create_secret(secret: SecretCreate):
|
|
sid = f"SEC-{uuid.uuid4().hex[:8].upper()}"
|
|
_secrets[sid] = {"id": sid, "name": secret.name, "engine": secret.engine,
|
|
"rotate_days": secret.rotate_days, "owner": secret.owner,
|
|
"value": "***ENCRYPTED***",
|
|
"created_at": datetime.utcnow().isoformat()}
|
|
return {k: v for k, v in _secrets[sid].items() if k != "value"}
|
|
|
|
@router.get("/secrets")
|
|
async def list_secrets():
|
|
return {"secrets": [{k: v for k, v in s.items() if k != "value"}
|
|
for s in _secrets.values()]}
|
|
|
|
@router.post("/secrets/{name}/rotate")
|
|
async def rotate_secret(name: str):
|
|
return {"name": name, "rotated": True, "new_version": f"v{uuid.uuid4().hex[:4]}",
|
|
"ts": datetime.utcnow().isoformat()}
|
|
|
|
@router.get("/secrets/{name}/audit")
|
|
async def secret_audit(name: str):
|
|
return {"name": name, "access_log": [
|
|
{"user": "guardia-itsm", "action": "read", "ts": datetime.utcnow().isoformat()},
|
|
], "rotation_history": [{"version": "v1", "ts": datetime.utcnow().isoformat()}]}
|
|
|
|
# ── 멀티 런타임 관리 ──────────────────────────────────────────────────────
|
|
@router.post("/runtimes")
|
|
async def create_runtime(rt: RuntimeCreate):
|
|
rid = f"RT-{uuid.uuid4().hex[:8].upper()}"
|
|
_runtimes[rid] = {**rt.model_dump(), "id": rid, "status": "ready",
|
|
"created_at": datetime.utcnow().isoformat()}
|
|
return _runtimes[rid]
|
|
|
|
@router.get("/runtimes")
|
|
async def list_runtimes():
|
|
rts = list(_runtimes.values()) or [
|
|
{"id": "RT-WASM01", "name": "wasmtime-edge", "type": "wasmtime", "status": "ready"},
|
|
{"id": "RT-CONT01", "name": "containerd-shim", "type": "containerd", "status": "ready"},
|
|
]
|
|
return {"runtimes": rts, "total": len(rts)}
|
|
|
|
@router.get("/runtimes/{rid}/stats")
|
|
async def runtime_stats(rid: str):
|
|
return {"runtime_id": rid, "cpu_cores": 4, "memory_used_mb": 512,
|
|
"modules_running": len(_wasm_modules), "uptime_sec": 86400,
|
|
"ts": datetime.utcnow().isoformat()}
|
|
|
|
# ── 클라우드 네이티브 상태 ────────────────────────────────────────────────
|
|
@router.get("/native/health")
|
|
async def native_health():
|
|
return {"status": "healthy", "ebpf_probes": len(_ebpf_probes),
|
|
"wasm_modules": len(_wasm_modules), "mesh_services": len(_mesh_services),
|
|
"events_stored": len(_events), "secrets": len(_secrets), "runtimes": len(_runtimes)}
|
|
|
|
@router.get("/native/overview")
|
|
async def native_overview():
|
|
return {"gen": 6, "capabilities": ["eBPF", "Wasm Edge", "Service Mesh", "Event Sourcing",
|
|
"Secret Manager", "Multi-Runtime"],
|
|
"maturity": "production", "last_updated": datetime.utcnow().isoformat()}
|