Skip to content

Commit 1d0d130

Browse files
committed
Phase 3: 监控告警增强
3.1 自定义告警表达式引擎 — alertexpr package (compound AND/OR/parens), Expression field on AlertRule, AlertTemplate model/CRUD 3.2 告警升级机制 — Escalation rules (level/severity/interval/channels), Silence rules (time-based/matching), full CRUD APIs 3.3 智能巡检 — InspectionTemplate/Report models, generate report from template (health checks + active alerts scoring), CRUD APIs All backend build/tests pass.
1 parent 95133e6 commit 1d0d130

15 files changed

Lines changed: 2564 additions & 41 deletions

platform-backend/cmd/main.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,19 @@ func main() {
182182

183183
alertRuleRepo := repositories.NewAlertRuleRepository(db)
184184
alertNotificationRepo := repositories.NewAlertNotificationRepository(db)
185+
alertTemplateRepo := repositories.NewAlertTemplateRepository(db)
186+
escRepo := repositories.NewEscalationRepository(db)
187+
silenceRepo := repositories.NewSilenceRepository(db)
188+
inspectionTplRepo := repositories.NewInspectionTemplateRepository(db)
189+
inspectionRptRepo := repositories.NewInspectionReportRepository(db)
185190
alertService := services.NewAlertService(alertRuleRepo, alertNotificationRepo, monitorService)
191+
alertService.WithTemplateRepo(alertTemplateRepo).WithEscalationRepo(escRepo).WithSilenceRepo(silenceRepo)
192+
alertService.WithInspectionRepos(inspectionTplRepo, inspectionRptRepo)
186193
alertController := controllers.NewAlertController(alertService)
194+
alertTemplateController := controllers.NewAlertTemplateController(alertService)
195+
escalationController := controllers.NewEscalationController(alertService)
196+
silenceController := controllers.NewSilenceController(alertService)
197+
inspectionController := controllers.NewInspectionController(alertService)
187198

188199
approvalRepo := repositories.NewApprovalRequestRepository(db)
189200
approvalService := services.NewApprovalService(approvalRepo, auditRepo)
@@ -373,6 +384,8 @@ func main() {
373384
deployments := protected.Group("/deployments")
374385
{
375386
// B2: 集群部署是高危操作, 必须 admin.
387+
deployments.POST("", middleware.RequirePermission("admin"), clusterDeployController.DeployCluster)
388+
deployments.POST("/validate", middleware.RequirePermission("admin"), clusterDeployController.ValidateClusterDeploy)
376389
deployments.POST("/mha", middleware.RequirePermission("admin"), clusterDeployController.DeployMHA)
377390
deployments.POST("/mgr", middleware.RequirePermission("admin"), clusterDeployController.DeployMGR)
378391
deployments.POST("/pxc", middleware.RequirePermission("admin"), clusterDeployController.DeployPXC)
@@ -463,6 +476,28 @@ func main() {
463476
alerts.GET("/notifications/channels/:id", alertController.GetNotificationChannel)
464477
alerts.PUT("/notifications/channels/:id", middleware.RequirePermission("admin"), alertController.UpdateNotificationChannel)
465478
alerts.DELETE("/notifications/channels/:id", middleware.RequirePermission("admin"), alertController.DeleteNotificationChannel)
479+
alerts.GET("/templates", alertTemplateController.List)
480+
alerts.POST("/templates", middleware.RequirePermission("admin"), alertTemplateController.Create)
481+
alerts.GET("/templates/:id", alertTemplateController.Get)
482+
alerts.DELETE("/templates/:id", middleware.RequirePermission("admin"), alertTemplateController.Delete)
483+
alerts.GET("/escalations", escalationController.List)
484+
alerts.POST("/escalations", middleware.RequirePermission("admin"), escalationController.Create)
485+
alerts.GET("/escalations/:id", escalationController.Get)
486+
alerts.DELETE("/escalations/:id", middleware.RequirePermission("admin"), escalationController.Delete)
487+
alerts.GET("/silences", silenceController.List)
488+
alerts.POST("/silences", middleware.RequirePermission("admin"), silenceController.Create)
489+
alerts.GET("/silences/:id", silenceController.Get)
490+
alerts.PUT("/silences/:id", middleware.RequirePermission("admin"), silenceController.Update)
491+
alerts.DELETE("/silences/:id", middleware.RequirePermission("admin"), silenceController.Delete)
492+
alerts.GET("/inspection/templates", inspectionController.ListTemplates)
493+
alerts.POST("/inspection/templates", middleware.RequirePermission("admin"), inspectionController.CreateTemplate)
494+
alerts.GET("/inspection/templates/:id", inspectionController.GetTemplate)
495+
alerts.PUT("/inspection/templates/:id", middleware.RequirePermission("admin"), inspectionController.UpdateTemplate)
496+
alerts.DELETE("/inspection/templates/:id", middleware.RequirePermission("admin"), inspectionController.DeleteTemplate)
497+
alerts.POST("/inspection/generate", middleware.RequirePermission("admin"), inspectionController.GenerateReport)
498+
alerts.GET("/inspection/reports", inspectionController.ListReports)
499+
alerts.GET("/inspection/reports/:id", inspectionController.GetReport)
500+
alerts.DELETE("/inspection/reports/:id", middleware.RequirePermission("admin"), inspectionController.DeleteReport)
466501
}
467502

468503
approvals := protected.Group("/approvals")
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package controllers
2+
3+
import (
4+
"github.com/gin-gonic/gin"
5+
"github.com/monkeycode/mysql-ops-platform/internal/models"
6+
"github.com/monkeycode/mysql-ops-platform/internal/services"
7+
"github.com/monkeycode/mysql-ops-platform/pkg/utils"
8+
)
9+
10+
type AlertTemplateController struct {
11+
service *services.AlertService
12+
}
13+
14+
func NewAlertTemplateController(service *services.AlertService) *AlertTemplateController {
15+
return &AlertTemplateController{service: service}
16+
}
17+
18+
func (c *AlertTemplateController) List(ctx *gin.Context) {
19+
category := ctx.Query("category")
20+
templates, err := c.service.ListAlertTemplates(ctx.Request.Context(), category)
21+
if err != nil {
22+
utils.InternalServerErrorResponse(ctx, "Failed to list alert templates", err)
23+
return
24+
}
25+
utils.SuccessResponse(ctx, templates)
26+
}
27+
28+
func (c *AlertTemplateController) Create(ctx *gin.Context) {
29+
var tpl models.AlertTemplate
30+
if err := ctx.ShouldBindJSON(&tpl); err != nil {
31+
utils.BadRequestResponse(ctx, "Invalid request body: "+err.Error())
32+
return
33+
}
34+
if err := c.service.CreateAlertTemplate(ctx.Request.Context(), &tpl); err != nil {
35+
utils.InternalServerErrorResponse(ctx, "Failed to create alert template", err)
36+
return
37+
}
38+
utils.SuccessResponse(ctx, tpl)
39+
}
40+
41+
func (c *AlertTemplateController) Get(ctx *gin.Context) {
42+
id := ctx.Param("id")
43+
tpl, err := c.service.GetAlertTemplate(ctx.Request.Context(), id)
44+
if err != nil {
45+
utils.NotFoundResponse(ctx, "Alert template not found")
46+
return
47+
}
48+
utils.SuccessResponse(ctx, tpl)
49+
}
50+
51+
func (c *AlertTemplateController) Delete(ctx *gin.Context) {
52+
id := ctx.Param("id")
53+
if err := c.service.DeleteAlertTemplate(ctx.Request.Context(), id); err != nil {
54+
utils.InternalServerErrorResponse(ctx, "Failed to delete alert template", err)
55+
return
56+
}
57+
utils.SuccessResponse(ctx, gin.H{"id": id, "deleted": true})
58+
}

platform-backend/internal/controllers/cluster_deploy_controller.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,38 @@ func NewClusterDeployController(service *services.ClusterDeployService) *Cluster
1818
return &ClusterDeployController{service: service}
1919
}
2020

21+
func (c *ClusterDeployController) DeployCluster(ctx *gin.Context) {
22+
var req services.UniversalClusterDeployRequest
23+
if err := ctx.ShouldBindJSON(&req); err != nil {
24+
utils.BadRequestResponse(ctx, "Invalid request parameters")
25+
return
26+
}
27+
28+
response, err := c.service.DeployCluster(ctx.Request.Context(), req)
29+
if err != nil {
30+
utils.InternalServerErrorResponse(ctx, "Failed to deploy cluster", err)
31+
return
32+
}
33+
34+
utils.SuccessResponse(ctx, response)
35+
}
36+
37+
func (c *ClusterDeployController) ValidateClusterDeploy(ctx *gin.Context) {
38+
var req services.UniversalClusterDeployRequest
39+
if err := ctx.ShouldBindJSON(&req); err != nil {
40+
utils.BadRequestResponse(ctx, "Invalid request parameters")
41+
return
42+
}
43+
44+
response, err := c.service.ValidateClusterDeploy(ctx.Request.Context(), req)
45+
if err != nil {
46+
utils.BadRequestResponse(ctx, err.Error())
47+
return
48+
}
49+
50+
utils.SuccessResponse(ctx, response)
51+
}
52+
2153
func (c *ClusterDeployController) DeployMHA(ctx *gin.Context) {
2254
var req services.DeployMHARequest
2355
if err := ctx.ShouldBindJSON(&req); err != nil {
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package controllers
2+
3+
import (
4+
"github.com/gin-gonic/gin"
5+
"github.com/monkeycode/mysql-ops-platform/internal/models"
6+
"github.com/monkeycode/mysql-ops-platform/internal/services"
7+
"github.com/monkeycode/mysql-ops-platform/pkg/utils"
8+
)
9+
10+
type EscalationController struct {
11+
service *services.AlertService
12+
}
13+
14+
func NewEscalationController(service *services.AlertService) *EscalationController {
15+
return &EscalationController{service: service}
16+
}
17+
18+
func (c *EscalationController) List(ctx *gin.Context) {
19+
ruleID := ctx.Query("rule_id")
20+
list, err := c.service.ListEscalations(ctx.Request.Context(), ruleID)
21+
if err != nil {
22+
utils.InternalServerErrorResponse(ctx, "Failed to list escalations", err)
23+
return
24+
}
25+
utils.SuccessResponse(ctx, list)
26+
}
27+
28+
func (c *EscalationController) Create(ctx *gin.Context) {
29+
var e models.AlertEscalation
30+
if err := ctx.ShouldBindJSON(&e); err != nil {
31+
utils.BadRequestResponse(ctx, "Invalid request body: "+err.Error())
32+
return
33+
}
34+
if err := c.service.CreateEscalation(ctx.Request.Context(), &e); err != nil {
35+
utils.InternalServerErrorResponse(ctx, "Failed to create escalation", err)
36+
return
37+
}
38+
utils.SuccessResponse(ctx, e)
39+
}
40+
41+
func (c *EscalationController) Get(ctx *gin.Context) {
42+
id := ctx.Param("id")
43+
e, err := c.service.GetEscalation(ctx.Request.Context(), id)
44+
if err != nil {
45+
utils.NotFoundResponse(ctx, "Escalation not found")
46+
return
47+
}
48+
utils.SuccessResponse(ctx, e)
49+
}
50+
51+
func (c *EscalationController) Delete(ctx *gin.Context) {
52+
id := ctx.Param("id")
53+
if err := c.service.DeleteEscalation(ctx.Request.Context(), id); err != nil {
54+
utils.InternalServerErrorResponse(ctx, "Failed to delete escalation", err)
55+
return
56+
}
57+
utils.SuccessResponse(ctx, gin.H{"id": id, "deleted": true})
58+
}
59+
60+
type SilenceController struct {
61+
service *services.AlertService
62+
}
63+
64+
func NewSilenceController(service *services.AlertService) *SilenceController {
65+
return &SilenceController{service: service}
66+
}
67+
68+
func (c *SilenceController) List(ctx *gin.Context) {
69+
list, err := c.service.ListSilences(ctx.Request.Context())
70+
if err != nil {
71+
utils.InternalServerErrorResponse(ctx, "Failed to list silences", err)
72+
return
73+
}
74+
utils.SuccessResponse(ctx, list)
75+
}
76+
77+
func (c *SilenceController) Create(ctx *gin.Context) {
78+
var s models.AlertSilence
79+
if err := ctx.ShouldBindJSON(&s); err != nil {
80+
utils.BadRequestResponse(ctx, "Invalid request body: "+err.Error())
81+
return
82+
}
83+
if err := c.service.CreateSilence(ctx.Request.Context(), &s); err != nil {
84+
utils.InternalServerErrorResponse(ctx, "Failed to create silence", err)
85+
return
86+
}
87+
utils.SuccessResponse(ctx, s)
88+
}
89+
90+
func (c *SilenceController) Get(ctx *gin.Context) {
91+
id := ctx.Param("id")
92+
s, err := c.service.GetSilence(ctx.Request.Context(), id)
93+
if err != nil {
94+
utils.NotFoundResponse(ctx, "Silence not found")
95+
return
96+
}
97+
utils.SuccessResponse(ctx, s)
98+
}
99+
100+
func (c *SilenceController) Update(ctx *gin.Context) {
101+
id := ctx.Param("id")
102+
var s models.AlertSilence
103+
if err := ctx.ShouldBindJSON(&s); err != nil {
104+
utils.BadRequestResponse(ctx, "Invalid request body: "+err.Error())
105+
return
106+
}
107+
s.ID = id
108+
if err := c.service.UpdateSilence(ctx.Request.Context(), &s); err != nil {
109+
utils.InternalServerErrorResponse(ctx, "Failed to update silence", err)
110+
return
111+
}
112+
utils.SuccessResponse(ctx, s)
113+
}
114+
115+
func (c *SilenceController) Delete(ctx *gin.Context) {
116+
id := ctx.Param("id")
117+
if err := c.service.DeleteSilence(ctx.Request.Context(), id); err != nil {
118+
utils.InternalServerErrorResponse(ctx, "Failed to delete silence", err)
119+
return
120+
}
121+
utils.SuccessResponse(ctx, gin.H{"id": id, "deleted": true})
122+
}

0 commit comments

Comments
 (0)