feat(console): 로컬 앱 설정·재배포·삭제·스케일·연결표시(에이전트 릴레이) — 0.23.0
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -460,6 +460,50 @@ def _h_kube(action: str, params: dict) -> dict:
|
||||
"ready": (d.get("status", {}) or {}).get("readyReplicas", 0) or 0,
|
||||
"image": conts[0]["image"] if conts else ""})
|
||||
return {"workloads": wls}
|
||||
# ── 쓰기 액션(콘솔 앱 카드 설정/재배포/삭제 릴레이). 로컬 dev: ns=프로젝트명, 라벨 app=<name> ──
|
||||
if action in ("app_scale", "app_restart", "app_delete", "app_edit"):
|
||||
app = params.get("app") or ""
|
||||
if not app:
|
||||
raise DsErr("BAD_REQUEST")
|
||||
items = json.loads(_kubectl(["get", "deploy", "-A", "-l", f"app={app}", "-o", "json"]) or "{}").get("items", [])
|
||||
if not items:
|
||||
raise DsErr("NOT_FOUND")
|
||||
d = items[0]
|
||||
ns = d["metadata"]["namespace"]
|
||||
conts = (d.get("spec", {}).get("template", {}).get("spec", {}) or {}).get("containers", []) or []
|
||||
cont = conts[0]["name"] if conts else app
|
||||
if action == "app_scale":
|
||||
n = int(params.get("replicas", 1))
|
||||
_kubectl(["-n", ns, "scale", f"deploy/{app}", f"--replicas={n}"])
|
||||
return {"app": app, "replicas": n}
|
||||
if action == "app_restart":
|
||||
_kubectl(["-n", ns, "rollout", "restart", f"deploy/{app}"])
|
||||
return {"app": app, "restarted": True}
|
||||
if action == "app_delete":
|
||||
# 앱 리소스만 제거(라벨 app=<name> = workload). 공유 소스(role=source)는 건드리지 않음.
|
||||
_kubectl(["-n", ns, "delete", "deploy,svc,ingress", "-l", f"app={app}", "--ignore-not-found"])
|
||||
return {"app": app, "deleted": True}
|
||||
# app_edit — 런타임 조정만 라이브 반영(replicas/image/resources/health/env). 구조변경(포트/도메인/경로)은
|
||||
# 매니페스트+dev deploy 소관(로컬은 매니페스트가 진실). 각 필드는 있을 때만 적용.
|
||||
applied = []
|
||||
if params.get("replicas") is not None:
|
||||
_kubectl(["-n", ns, "scale", f"deploy/{app}", f"--replicas={int(params['replicas'])}"]); applied.append("replicas")
|
||||
if params.get("image"):
|
||||
_kubectl(["-n", ns, "set", "image", f"deploy/{app}", f"{cont}={params['image']}"]); applied.append("image")
|
||||
cpu, mem = params.get("cpu"), params.get("mem")
|
||||
if cpu or mem:
|
||||
req = ",".join([x for x in [f"cpu={cpu}" if cpu else "", f"memory={mem}" if mem else ""] if x])
|
||||
_kubectl(["-n", ns, "set", "resources", f"deploy/{app}", f"--requests={req}"]); applied.append("resources")
|
||||
if params.get("health"):
|
||||
hp = params["health"]
|
||||
patch = json.dumps({"spec": {"template": {"spec": {"containers": [
|
||||
{"name": cont, "readinessProbe": {"httpGet": {"path": hp}}, "livenessProbe": {"httpGet": {"path": hp}}}]}}}})
|
||||
_kubectl(["-n", ns, "patch", f"deploy/{app}", "--type=strategic", "-p", patch]); applied.append("health")
|
||||
env = params.get("env") or []
|
||||
kv = [f"{e['key']}={e.get('value', '')}" for e in env if isinstance(e, dict) and e.get("key")]
|
||||
if kv:
|
||||
_kubectl(["-n", ns, "set", "env", f"deploy/{app}", *kv]); applied.append("env")
|
||||
return {"app": app, "applied": applied}
|
||||
raise DsErr("FORBIDDEN_ACTION")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user