P0 - DIAGNOSE Privacy-First Routing: - ai_router.py: _local_fallback_chain [NEMOTRON→OLLAMA→REJECT] - DIAGNOSE 意圖 override 改為 NEMOTRON (原 OLLAMA) - DIAGNOSE fallback 使用 local-only 鏈,不觸碰雲端 - 全部失敗時 REJECT + Telegram 通知 - config.py: NEMOTRON_DIAGNOSE_TIMEOUT_SECONDS=30, OLLAMA_DIAGNOSE_TIMEOUT_SECONDS=60 - nemotron.py: 根據 context[task_type] 選擇 timeout P1 - Knowledge Auto-Harvesting: - models/knowledge.py: EntryType.AUTO_RUNBOOK + ANTI_PATTERN + symptoms_hash - EntryStatus.PUBLISHED (ANTI_PATTERN 直接發布,無需審核) - models/playbook.py: SymptomPattern.compute_hash() (16字元確定性 hash) - services/runbook_generator.py: NemotronRunbookGenerator (v1.1) - generate_runbook() → AUTO_RUNBOOK (DRAFT) + Telegram 審核 card - generate_anti_pattern() → ANTI_PATTERN (PUBLISHED) + Telegram 通知 - 使用 nvidia.chat() (正確介面),Nemotron 超時時 Minimal fallback - knowledge_service.py: check_anti_pattern(symptoms_hash, days=7) - db/models.py: symptoms_hash VARCHAR(16) + ix_knowledge_symptoms_hash - repositories/knowledge_repository.py: create() 支援 symptoms_hash + status - auto_repair_service.py: anti_pattern_gate 在 decide() + runbook hook 在 execute() - migrations/phase8_symptoms_hash.sql: ALTER TABLE + partial index + PUBLISHED constraint P2 - Config Drift Detection: - models/drift.py: DriftItem/DriftReport/DriftLevel/DriftIntent/DriftStatus - services/drift_detector.py: GitStateReader + K8sStateReader + DriftDetector - services/drift_analyzer.py: 白名單過濾 + DriftLevel 分級 - services/drift_interpreter.py: NemotronDriftInterpreter(意圖分析,不生成修復指令) - services/drift_remediator.py: rollback(kubectl apply) + adopt(git push gitea) - api/v1/drift.py: POST /scan, GET /reports, POST /rollback, POST /adopt - migrations/phase9_drift_reports.sql: drift_reports 表 - k8s/drift-cronjob.yaml: 每小時自動掃描 CronJob Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
72 lines
2.7 KiB
YAML
72 lines
2.7 KiB
YAML
# Config Drift Detection CronJob - Phase 25 P2
|
||
# 每小時掃描 awoooi-prod namespace 的配置漂移
|
||
#
|
||
# 建立時間: 2026-04-04 (台北時區)
|
||
# 建立者: Claude Code (Phase 25 P2)
|
||
# 關聯設計: docs/superpowers/specs/2026-04-04-nemotron-active-defense-design.md 方向三
|
||
# 關聯 ADR: 待起草 ADR-057
|
||
#
|
||
# 部署: kubectl apply -f k8s/drift-cronjob.yaml -n awoooi-prod
|
||
# 手動觸發: kubectl create job --from=cronjob/drift-scanner drift-scan-manual -n awoooi-prod
|
||
# 查看 log: kubectl logs -l job-name=drift-scanner -n awoooi-prod
|
||
|
||
apiVersion: batch/v1
|
||
kind: CronJob
|
||
metadata:
|
||
name: drift-scanner
|
||
namespace: awoooi-prod
|
||
labels:
|
||
app: awoooi
|
||
component: drift-scanner
|
||
phase: "25"
|
||
annotations:
|
||
# 2026-04-04 ogt: Phase 25 P2 — Config Drift Detection
|
||
description: "每小時掃描 K8s 配置漂移,由 Nemotron 做意圖分析"
|
||
spec:
|
||
# 每小時整點執行(台北時間 = UTC+8,schedule 用 UTC)
|
||
schedule: "0 * * * *"
|
||
concurrencyPolicy: Forbid # 禁止並發:上次未完成則跳過
|
||
successfulJobsHistoryLimit: 3
|
||
failedJobsHistoryLimit: 5
|
||
startingDeadlineSeconds: 60 # 錯過時間窗口超過 60s 則跳過
|
||
jobTemplate:
|
||
spec:
|
||
backoffLimit: 0 # 失敗不重試(漂移掃描冪等,下次 cron 自動補掃)
|
||
activeDeadlineSeconds: 300 # 最長 5 分鐘
|
||
template:
|
||
metadata:
|
||
labels:
|
||
app: awoooi
|
||
component: drift-scanner
|
||
spec:
|
||
restartPolicy: Never
|
||
serviceAccountName: awoooi-api # 使用 API 的 ServiceAccount(有 kubectl 權限)
|
||
containers:
|
||
- name: drift-scanner
|
||
# 使用 awoooi-api 鏡像(含 kubectl + Python 環境)
|
||
image: harbor.wooo.work/awoooi/api:latest
|
||
imagePullPolicy: Always
|
||
command:
|
||
- python
|
||
- -c
|
||
- |
|
||
import asyncio, httpx, os
|
||
API_URL = os.environ.get("INTERNAL_API_URL", "http://awoooi-api:8000")
|
||
async def run():
|
||
async with httpx.AsyncClient(timeout=240) as c:
|
||
r = await c.post(f"{API_URL}/api/v1/drift/internal/scan")
|
||
print(f"status={r.status_code} body={r.text[:200]}")
|
||
asyncio.run(run())
|
||
env:
|
||
- name: INTERNAL_API_URL
|
||
value: "http://awoooi-api.awoooi-prod.svc.cluster.local:8000"
|
||
- name: DRIFT_SCAN_NAMESPACES
|
||
value: "awoooi-prod"
|
||
resources:
|
||
requests:
|
||
cpu: "50m"
|
||
memory: "64Mi"
|
||
limits:
|
||
cpu: "200m"
|
||
memory: "256Mi"
|