feat(drift): B4 drift_reports DB 持久化 + CronJob 修復
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 12m17s
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 12m17s
- drift_repository.py: DriftReportRepository (save/get/list/update) - drift.py router: 移除 in-memory dict,改用 DB repository - drift-cronjob.yaml: 修正 SA/NetworkPolicy/NodePort 問題 - allow-intra-namespace NetworkPolicy (已套用至 prod) - migrate-phase8/9: symptoms_hash + drift_reports migration Job YAML Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -40,11 +40,13 @@ spec:
|
||||
component: drift-scanner
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
serviceAccountName: awoooi-api # 使用 API 的 ServiceAccount(有 kubectl 權限)
|
||||
# 2026-04-09 Claude Sonnet 4.6: awoooi-api SA 不存在,改用 default(只需呼叫內部 API,不需 K8s 權限)
|
||||
serviceAccountName: default
|
||||
containers:
|
||||
- name: drift-scanner
|
||||
# 使用 awoooi-api 鏡像(含 kubectl + Python 環境)
|
||||
image: harbor.wooo.work/awoooi/api:latest
|
||||
# 2026-04-09 Claude Sonnet 4.6: 改用內網 registry + 固定 SHA tag (禁止 latest)
|
||||
image: 192.168.0.110:5000/awoooi/api:21567a7a6dbee7db2c0f59c265f80713ff5e6fe4
|
||||
imagePullPolicy: Always
|
||||
command:
|
||||
- python
|
||||
@@ -58,8 +60,10 @@ spec:
|
||||
print(f"status={r.status_code} body={r.text[:200]}")
|
||||
asyncio.run(run())
|
||||
env:
|
||||
# 2026-04-09 Claude Sonnet 4.6: ClusterIP 和 DNS 在 Job Pod 均不可達
|
||||
# 改用 NodePort 直連 K3s worker node(同 K8s_API_SERVER_URL 解法)
|
||||
- name: INTERNAL_API_URL
|
||||
value: "http://awoooi-api.awoooi-prod.svc.cluster.local:8000"
|
||||
value: "http://192.168.0.121:32334"
|
||||
- name: DRIFT_SCAN_NAMESPACES
|
||||
value: "awoooi-prod"
|
||||
resources:
|
||||
|
||||
84
k8s/jobs/migrate-phase8-symptoms-hash.yaml
Normal file
84
k8s/jobs/migrate-phase8-symptoms-hash.yaml
Normal file
@@ -0,0 +1,84 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: migrate-phase8-symptoms-hash
|
||||
namespace: awoooi-prod
|
||||
labels:
|
||||
app: awoooi-migration
|
||||
phase: phase25
|
||||
spec:
|
||||
ttlSecondsAfterFinished: 300
|
||||
backoffLimit: 1
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: migrate
|
||||
image: postgres:15-alpine
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
echo "=========================================="
|
||||
echo "Phase 25 P1: knowledge_entries symptoms_hash Migration"
|
||||
echo "=========================================="
|
||||
|
||||
DB_HOST=$(echo $DATABASE_URL | sed 's/.*@\([^:]*\):.*/\1/')
|
||||
DB_PORT=$(echo $DATABASE_URL | sed 's/.*:\([0-9]*\)\/.*/\1/')
|
||||
DB_NAME=$(echo $DATABASE_URL | sed 's/.*\/\([^?]*\).*/\1/')
|
||||
DB_USER=$(echo $DATABASE_URL | sed 's/.*\/\/\([^:]*\):.*/\1/')
|
||||
DB_PASS=$(echo $DATABASE_URL | sed 's/.*:\/\/[^:]*:\([^@]*\)@.*/\1/')
|
||||
|
||||
echo "Connecting to: $DB_HOST:$DB_PORT/$DB_NAME"
|
||||
export PGPASSWORD="$DB_PASS"
|
||||
|
||||
psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" <<'EOSQL'
|
||||
-- Phase 25 P1: Anti-Pattern symptoms_hash 欄位
|
||||
-- 2026-04-09 Claude Sonnet 4.6
|
||||
|
||||
ALTER TABLE knowledge_entries
|
||||
ADD COLUMN IF NOT EXISTS symptoms_hash VARCHAR(16);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_knowledge_anti_pattern_hash
|
||||
ON knowledge_entries (entry_type, symptoms_hash, created_at)
|
||||
WHERE entry_type = 'anti_pattern' AND symptoms_hash IS NOT NULL;
|
||||
|
||||
-- 自動處理 CHECK constraint(若有)
|
||||
DO $$
|
||||
DECLARE
|
||||
v_conname text;
|
||||
BEGIN
|
||||
SELECT conname INTO v_conname
|
||||
FROM pg_constraint
|
||||
WHERE conrelid = 'knowledge_entries'::regclass AND contype = 'c' AND conname LIKE '%status%';
|
||||
|
||||
IF v_conname IS NOT NULL THEN
|
||||
EXECUTE format('ALTER TABLE knowledge_entries DROP CONSTRAINT %I', v_conname);
|
||||
ALTER TABLE knowledge_entries ADD CONSTRAINT knowledge_entries_status_check
|
||||
CHECK (status IN ('draft', 'review', 'approved', 'archived', 'published'));
|
||||
RAISE NOTICE 'Updated status CHECK constraint: % → added published', v_conname;
|
||||
ELSE
|
||||
RAISE NOTICE 'No status CHECK constraint found, skipping';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 驗證
|
||||
SELECT column_name, data_type
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'knowledge_entries'
|
||||
ORDER BY ordinal_position;
|
||||
EOSQL
|
||||
|
||||
echo "=========================================="
|
||||
echo "Migration completed!"
|
||||
echo "=========================================="
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: awoooi-secrets
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "200m"
|
||||
83
k8s/jobs/migrate-phase9-drift-reports.yaml
Normal file
83
k8s/jobs/migrate-phase9-drift-reports.yaml
Normal file
@@ -0,0 +1,83 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: migrate-phase9-drift-reports
|
||||
namespace: awoooi-prod
|
||||
labels:
|
||||
app: awoooi-migration
|
||||
phase: phase25
|
||||
spec:
|
||||
ttlSecondsAfterFinished: 300
|
||||
backoffLimit: 1
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: migrate
|
||||
image: postgres:15-alpine
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
echo "=========================================="
|
||||
echo "Phase 25 P2: drift_reports 資料表 Migration"
|
||||
echo "=========================================="
|
||||
|
||||
DB_HOST=$(echo $DATABASE_URL | sed 's/.*@\([^:]*\):.*/\1/')
|
||||
DB_PORT=$(echo $DATABASE_URL | sed 's/.*:\([0-9]*\)\/.*/\1/')
|
||||
DB_NAME=$(echo $DATABASE_URL | sed 's/.*\/\([^?]*\).*/\1/')
|
||||
DB_USER=$(echo $DATABASE_URL | sed 's/.*\/\/\([^:]*\):.*/\1/')
|
||||
DB_PASS=$(echo $DATABASE_URL | sed 's/.*:\/\/[^:]*:\([^@]*\)@.*/\1/')
|
||||
|
||||
echo "Connecting to: $DB_HOST:$DB_PORT/$DB_NAME"
|
||||
export PGPASSWORD="$DB_PASS"
|
||||
|
||||
psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" <<'EOSQL'
|
||||
-- Phase 25 P2: Config Drift Detection — drift_reports 資料表
|
||||
-- 2026-04-09 Claude Sonnet 4.6
|
||||
|
||||
CREATE TABLE IF NOT EXISTS drift_reports (
|
||||
report_id VARCHAR(32) PRIMARY KEY,
|
||||
namespace VARCHAR(128) NOT NULL,
|
||||
triggered_by VARCHAR(64) NOT NULL DEFAULT 'cron',
|
||||
scanned_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
high_count INT NOT NULL DEFAULT 0,
|
||||
medium_count INT NOT NULL DEFAULT 0,
|
||||
info_count INT NOT NULL DEFAULT 0,
|
||||
items JSONB NOT NULL DEFAULT '[]',
|
||||
interpretation JSONB,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
resolved_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_drift_reports_namespace
|
||||
ON drift_reports(namespace);
|
||||
CREATE INDEX IF NOT EXISTS idx_drift_reports_status
|
||||
ON drift_reports(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_drift_reports_created_at
|
||||
ON drift_reports(created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_drift_reports_high_count
|
||||
ON drift_reports(high_count)
|
||||
WHERE high_count > 0;
|
||||
|
||||
-- 驗證
|
||||
SELECT column_name, data_type
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'drift_reports'
|
||||
ORDER BY ordinal_position;
|
||||
EOSQL
|
||||
|
||||
echo "=========================================="
|
||||
echo "Migration completed!"
|
||||
echo "=========================================="
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: awoooi-secrets
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "200m"
|
||||
Reference in New Issue
Block a user