fix(asset_scanner): kubectl 改 subprocess — K8sProvider 不支援 --all-namespaces
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 9m9s
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 9m9s
5b9b36f 部署後 asset_scanner 跑 3 次但 total=0, new=0:
- asset_inventory 仍 0 筆
- Pod 手動 kubectl get pods --all-namespaces -o json 可取 JSON
- 真因: K8sProvider._kubectl_get 把 namespace 參數塞進 '-n $ns',
所以 '--all-namespaces' 變成 '-n --all-namespaces' (kubectl 拒絕)
修復:
- 不走 K8sProvider,直接 asyncio.create_subprocess_exec
- kubectl get pods --all-namespaces -o json
- 30s timeout,rc != 0 拋 RuntimeError 觸發 aol status='failed'
驗證: 部署後 asset_inventory 應在 1 分鐘內開始有 pods 寫入
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -169,34 +169,30 @@ async def scan_once(
|
||||
|
||||
async def _collect_k8s_assets() -> list[dict[str, Any]]:
|
||||
"""
|
||||
用 K8sProvider 列出全 namespace 的 pods,轉成 asset_inventory 結構。
|
||||
直接 subprocess 執行 kubectl get pods --all-namespaces.
|
||||
|
||||
2026-04-19 ogt + Claude Opus 4.7 v2: 不走 K8sProvider._kubectl_get,
|
||||
因為它把 namespace 參數當 -n 旗標,無法處理 '--all-namespaces'.
|
||||
直接 subprocess 最可靠 + Pod 內 /usr/local/bin/kubectl 已確認可用.
|
||||
|
||||
回傳每筆: {asset_key, asset_type, host, namespace, name, metadata, tags}
|
||||
"""
|
||||
from src.plugins.mcp.providers.k8s_provider import K8sProvider
|
||||
|
||||
provider = K8sProvider()
|
||||
result = await asyncio.wait_for(
|
||||
provider.execute(
|
||||
tool_name="kubectl_get",
|
||||
parameters={"namespace": "--all-namespaces", "resource": "pods"},
|
||||
proc = await asyncio.wait_for(
|
||||
asyncio.create_subprocess_exec(
|
||||
"kubectl", "get", "pods", "--all-namespaces", "-o", "json",
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
),
|
||||
timeout=_KUBECTL_TIMEOUT_SEC,
|
||||
)
|
||||
if not result.success:
|
||||
raise RuntimeError(f"kubectl get pods failed: {result.error}")
|
||||
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=_KUBECTL_TIMEOUT_SEC)
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError(f"kubectl failed rc={proc.returncode}: {stderr.decode('utf-8', errors='replace')[:500]}")
|
||||
|
||||
raw = result.output
|
||||
# k8s_provider _kubectl_get 回傳 stdout 字串 (line 299)
|
||||
if isinstance(raw, str):
|
||||
try:
|
||||
payload = _json.loads(raw)
|
||||
except _json.JSONDecodeError as e:
|
||||
raise RuntimeError(f"kubectl JSON parse failed: {e}") from e
|
||||
elif isinstance(raw, dict):
|
||||
payload = raw
|
||||
else:
|
||||
raise RuntimeError(f"unexpected kubectl output type: {type(raw)}")
|
||||
try:
|
||||
payload = _json.loads(stdout.decode("utf-8", errors="replace"))
|
||||
except _json.JSONDecodeError as e:
|
||||
raise RuntimeError(f"kubectl JSON parse failed: {e}") from e
|
||||
|
||||
items = payload.get("items", []) if isinstance(payload, dict) else []
|
||||
assets: list[dict[str, Any]] = []
|
||||
|
||||
Reference in New Issue
Block a user