feat(audit): F1+F2 告警静默规则标记完成 + 审计日志CSV导出实现
F1 告警静默规则 [done]: - 后端 alert_silence.go: CRUD + Toggle (onetime/daily/weekly 三模式) - 告警引擎 isSilenced 集成 (alert_engine.go) - 前端 SilenceRuleTab + SilenceDialog - 路由 /alerts/silences 已注册 F2 审计日志导出 [done]: - 重写 ExportAuditLogs: 真正的 CSV 导出 (encoding/csv + UTF-8 BOM) - 支持 module/action/username/startTime/endTime 筛选 - 导出限制 10000 条防溢出,自动记录审计日志 - JSON 格式向后兼容 (format=json) - 前端 exportLogs 传递查询参数 同时包含累积的前期工作: - 目录重构 internal/ -> controller/model/router (v0.55-v0.57) - 后端分层架构 dto/repository/service/utils - 审计模块全功能 (终端审计/操作审计/登录日志) - asciicast v2 录制格式 - SFTP 文件浏览器 - StatStrip 紧凑统计条 - 在线会话自动刷新 - LiveMonitor WebSocket 诊断修复 验证: go build ✅ | npm run build ✅ | Docker 部署 ✅ | 10 回归端点 ✅ | CSV 导出 ✅ | 静默 CRUD ✅
This commit is contained in:
1 parent
e57718998a
commit
77c234b060
314 files changed
+10050
-4065
No files matched your search
Executable
+146
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
AIOps Integration Tests
|
||||
python3 tests/integration_test.py [--host HOST] [--port PORT]
|
||||
"""
|
||||
import urllib.request, urllib.error, json, sys, time, argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--host", default="localhost")
|
||||
parser.add_argument("--port", default="80")
|
||||
args = parser.parse_args()
|
||||
|
||||
BASE = "http://{}:{}".format(args.host, args.port)
|
||||
TOKEN = ""
|
||||
PASSED = 0
|
||||
FAILED = 0
|
||||
|
||||
def api(method, path, body=None, auth=True):
|
||||
url = BASE + path
|
||||
data = json.dumps(body).encode() if body else None
|
||||
req = urllib.request.Request(url, data=data, method=method)
|
||||
req.add_header("Content-Type", "application/json")
|
||||
if auth and TOKEN:
|
||||
req.add_header("Authorization", "Bearer " + TOKEN)
|
||||
try:
|
||||
resp = urllib.request.urlopen(req, timeout=10)
|
||||
return resp.status, json.loads(resp.read())
|
||||
except urllib.error.HTTPError as e:
|
||||
try:
|
||||
return e.code, json.loads(e.read().decode())
|
||||
except:
|
||||
return e.code, {}
|
||||
except Exception as e:
|
||||
return 0, {"error": str(e)[:100]}
|
||||
|
||||
def check(name, status, detail=""):
|
||||
global PASSED, FAILED
|
||||
ok = 200 <= status < 300
|
||||
mark = "PASS" if ok else "FAIL"
|
||||
if ok: PASSED += 1
|
||||
else: FAILED += 1
|
||||
d = str(detail)[:80] if detail else ""
|
||||
print(" [{}] {}: HTTP {} {}".format(mark, name, status, d))
|
||||
return ok
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("AIOps Integration Tests — " + BASE)
|
||||
print("=" * 60)
|
||||
|
||||
# [1] Health
|
||||
print("\n[1] Basic checks")
|
||||
s, d = api("GET", "/health", auth=False)
|
||||
check("Health check", s)
|
||||
s, d = api("GET", "/version", auth=False)
|
||||
check("Version API ", s)
|
||||
|
||||
# [2] Login
|
||||
print("\n[2] Authentication")
|
||||
s, d = api("POST", "/api/v1/auth/login",
|
||||
body={"username": "admin", "password": "123456"}, auth=False)
|
||||
if check("Login ", s):
|
||||
TOKEN = d.get("data", {}).get("token", "")
|
||||
if TOKEN:
|
||||
print(" [INFO] Token: " + TOKEN[:40] + "...")
|
||||
else:
|
||||
print(" [WARN] No token in response")
|
||||
FAILED += 1
|
||||
|
||||
if not TOKEN:
|
||||
print("[SKIP] No auth token, skipping authenticated tests\n")
|
||||
print("=" * 60)
|
||||
print("Result: {} passed, {} failed".format(PASSED, FAILED))
|
||||
print("=" * 60)
|
||||
sys.exit(1)
|
||||
|
||||
# [3] User
|
||||
print("\n[3] Users")
|
||||
s, d = api("GET", "/api/v1/admin/users")
|
||||
check("Profile ", s)
|
||||
s, d = api("GET", "/api/v1/admin/users")
|
||||
check("Admin users ", s)
|
||||
|
||||
# [4] Dashboard
|
||||
print("\n[4] Dashboard")
|
||||
s, d = api("GET", "/api/v1/dashboard/stats")
|
||||
check("Stats ", s)
|
||||
s, d = api("GET", "/api/v1/dashboard/recent-alerts")
|
||||
check("Recent alert", s)
|
||||
|
||||
# [5] Servers
|
||||
print("\n[5] Servers")
|
||||
s, d = api("GET", "/api/v1/servers")
|
||||
check("List ", s)
|
||||
s, d = api("GET", "/api/v1/servers/stats")
|
||||
check("Stats ", s)
|
||||
|
||||
# Create + Delete
|
||||
name = "test-" + str(int(time.time()))
|
||||
s, d = api("POST", "/api/v1/servers", body={
|
||||
"name": name, "hostname": "test.local",
|
||||
"ip": "10.0.0.99", "port": 22,
|
||||
"os_type": "Ubuntu", "status": "offline"
|
||||
})
|
||||
if check("Create ", s):
|
||||
sid = d.get("data", {}).get("id", 0)
|
||||
if sid:
|
||||
s, d = api("GET", "/api/v1/servers/" + str(sid))
|
||||
check("Get by ID ", s)
|
||||
s, d = api("DELETE", "/api/v1/servers/" + str(sid))
|
||||
check("Delete ", s)
|
||||
|
||||
# [6] Navigation
|
||||
print("\n[6] Navigation")
|
||||
s, d = api("GET", "/api/v1/navigations/groups")
|
||||
check("Tree ", s)
|
||||
|
||||
# [7] Credentials
|
||||
print("\n[7] Credentials")
|
||||
s, d = api("GET", "/api/v1/credentials")
|
||||
check("List ", s)
|
||||
|
||||
# [8] Pipelines
|
||||
print("\n[8] Pipelines")
|
||||
s, d = api("GET", "/api/v1/pipelines")
|
||||
check("List ", s)
|
||||
|
||||
# [9] Environments
|
||||
print("\n[9] Deploy Environments")
|
||||
s, d = api("GET", "/api/v1/deploy/environments")
|
||||
check("List ", s)
|
||||
|
||||
# [10] Roles
|
||||
print("\n[10] Roles")
|
||||
s, d = api("GET", "/api/v1/admin/roles")
|
||||
check("Roles ", s)
|
||||
|
||||
# Summary
|
||||
total = PASSED + FAILED
|
||||
print("\n" + "=" * 60)
|
||||
print("Result: {}/{} passed, {} failed".format(PASSED, total, FAILED))
|
||||
if FAILED == 0:
|
||||
print("ALL TESTS PASSED!")
|
||||
else:
|
||||
print("WARNING: {} failures".format(FAILED))
|
||||
print("=" * 60 + "\n")
|
||||
sys.exit(0 if FAILED == 0 else 1)
|
||||
Reference in new issue
Block a user