package controller import ( "fmt" "net/http" "strconv" "ezops/model" "github.com/gin-gonic/gin" ) // 告警规则 CRUD(AlertHandler 方法接收者,与 alert.go 同包共享) // Logan.Li // ListRules 获取告警规则列表 // Logan.Li // @Summary 获取告警规则列表 // @Description 获取所有告警规则列表 // @Tags 告警 // @Produce json // @Security Bearer // @Param page query int false "页码" // @Param page_size query int false "每页数量" // @Success 200 {object} model.Response{data=model.ListResponse} // @Router /alerts/rules [get] func (h *AlertHandler) ListRules(c *gin.Context) { var query model.PageQuery c.ShouldBindQuery(&query) var total int64 h.db.Model(&model.AlertRule{}).Count(&total) var rules []model.AlertRule h.db.Offset(query.GetOffset()).Limit(query.GetLimit()).Find(&rules) c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "success", Data: model.ListResponse{ List: rules, Total: total, }, }) } // CreateRule 创建告警规则 // Logan.Li // @Summary 创建告警规则 // @Description 创建新告警规则 // @Tags 告警 // @Accept json // @Produce json // @Security Bearer // @Param request body model.CreateAlertRuleRequest true "创建请求" // @Success 200 {object} model.Response{data=model.AlertRule} // @Router /alerts/rules [post] func (h *AlertHandler) CreateRule(c *gin.Context) { var req model.CreateAlertRuleRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Response{ Code: 400, Message: "请求参数错误: " + err.Error(), }) return } rule := model.AlertRule{ Name: req.Name, Description: req.Description, Type: req.Type, Source: req.Source, Expression: req.Expression, Severity: req.Severity, Duration: req.Duration, DatasourceID: req.DatasourceID, Labels: req.Labels, Annotations: req.Annotations, NotifyChannels: toJSON(req.NotifyChannels), Enabled: true, } if err := h.db.Create(&rule).Error; err != nil { c.JSON(http.StatusInternalServerError, model.Response{ Code: 500, Message: "创建失败", }) return } c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "创建成功", Data: rule, }) } // UpdateRule 更新告警规则 // Logan.Li // @Summary 更新告警规则 // @Description 更新指定告警规则 // @Tags 告警 // @Accept json // @Produce json // @Security Bearer // @Param id path int true "规则ID" // @Param request body model.UpdateAlertRuleRequest true "更新请求" // @Success 200 {object} model.Response{data=model.AlertRule} // @Router /alerts/rules/{id} [put] func (h *AlertHandler) UpdateRule(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var req model.UpdateAlertRuleRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Response{ Code: 400, Message: "请求参数错误: " + err.Error(), }) return } var rule model.AlertRule if err := h.db.First(&rule, id).Error; err != nil { c.JSON(http.StatusNotFound, model.Response{ Code: 404, Message: "规则不存在", }) return } updates := map[string]interface{}{} if req.Name != "" { updates["name"] = req.Name } if req.Description != "" { updates["description"] = req.Description } if req.Expression != "" { updates["expression"] = req.Expression } if req.Severity != "" { updates["severity"] = req.Severity } if req.Duration > 0 { updates["duration"] = req.Duration } if req.DatasourceID > 0 { updates["datasource_id"] = req.DatasourceID } if req.Labels != "" { updates["labels"] = req.Labels } if req.Annotations != "" { updates["annotations"] = req.Annotations } if len(req.NotifyChannels) > 0 { updates["notify_channels"] = toJSON(req.NotifyChannels) } if req.Enabled != nil { updates["enabled"] = *req.Enabled } if err := h.db.Model(&rule).Updates(updates).Error; err != nil { c.JSON(http.StatusInternalServerError, model.Response{ Code: 500, Message: "更新失败", }) return } h.db.First(&rule, id) c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "更新成功", Data: rule, }) } // DeleteRule 删除告警规则 // Logan.Li // @Summary 删除告警规则 // @Description 删除指定告警规则 // @Tags 告警 // @Produce json // @Security Bearer // @Param id path int true "规则ID" // @Success 200 {object} model.Response // @Router /alerts/rules/{id} [delete] func (h *AlertHandler) DeleteRule(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) if err := h.db.Delete(&model.AlertRule{}, id).Error; err != nil { c.JSON(http.StatusInternalServerError, model.Response{ Code: 500, Message: "删除失败", }) return } c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "删除成功", }) } // BatchDeleteRules 批量删除告警规则 // Logan.Li // @Summary 批量删除告警规则 // @Description 批量删除指定告警规则 // @Tags 告警 // @Accept json // @Produce json // @Security Bearer // @Param request body model.IDsRequest true "删除请求" // @Success 200 {object} model.Response // @Router /alerts/rules/batch-delete [delete] func (h *AlertHandler) BatchDeleteRules(c *gin.Context) { var req model.IDsRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Response{ Code: 400, Message: "请求参数错误", }) return } if len(req.IDs) == 0 { c.JSON(http.StatusBadRequest, model.Response{ Code: 400, Message: "请选择要删除的规则", }) return } if err := h.db.Delete(&model.AlertRule{}, req.IDs).Error; err != nil { c.JSON(http.StatusInternalServerError, model.Response{ Code: 500, Message: "删除失败", }) return } c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "删除成功", }) } // ToggleRule 切换告警规则状态 // Logan.Li // @Summary 切换告警规则状态 // @Description 启用或禁用告警规则 // @Tags 告警 // @Produce json // @Security Bearer // @Param id path int true "规则ID" // @Success 200 {object} model.Response{data=model.AlertRule} // @Router /alerts/rules/{id}/toggle [post] func (h *AlertHandler) ToggleRule(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var rule model.AlertRule if err := h.db.First(&rule, id).Error; err != nil { c.JSON(http.StatusNotFound, model.Response{ Code: 404, Message: "规则不存在", }) return } rule.Enabled = !rule.Enabled if err := h.db.Save(&rule).Error; err != nil { c.JSON(http.StatusInternalServerError, model.Response{ Code: 500, Message: "操作失败", }) return } c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "操作成功", Data: rule, }) } // QuickSetupRules 一键创建测试告警规则(飞书Webhook测试用) // Logan.Li // @Summary 一键创建测试告警规则 // @Tags 告警 // @Router /alerts/quick-setup [post] func (h *AlertHandler) QuickSetupRules(c *gin.Context) { type ruleDef struct { Name string `json:"name"` Metric string `json:"metric"` Operator string `json:"operator"` Threshold float64 `json:"threshold"` Port int `json:"port,omitempty"` } var req struct { Rules []ruleDef `json:"rules"` } c.ShouldBindJSON(&req) // 默认规则:CPU 80%, 内存 80%, 磁盘 90%, TIME_WAIT 15000, CLOSE_WAIT 200, 端口Down, 进程检测 defaultRules := []ruleDef{ {Name: "CPU使用率", Metric: "cpu", Operator: ">", Threshold: 80}, {Name: "内存使用率", Metric: "mem", Operator: ">", Threshold: 80}, {Name: "磁盘使用率", Metric: "disk", Operator: ">", Threshold: 90}, {Name: "TIME_WAIT连接数", Metric: "tcp_time_wait", Operator: ">", Threshold: 15000}, {Name: "CLOSE_WAIT连接数", Metric: "tcp_close_wait", Operator: ">", Threshold: 200}, {Name: "进程异常退出", Metric: "service_process", Operator: "==", Threshold: 0}, } rules := req.Rules if len(rules) == 0 { rules = defaultRules } created := 0 for _, def := range rules { var existing model.AgentRule h.db.Where("name = ?", def.Name).First(&existing) if existing.ID > 0 { continue } rule := model.AgentRule{ Name: def.Name, Metric: def.Metric, Operator: def.Operator, Threshold: def.Threshold, Port: def.Port, Enabled: true, } if err := h.db.Create(&rule).Error; err != nil { continue } created++ } c.JSON(http.StatusOK, model.Response{ Code: 200, Message: fmt.Sprintf("已创建 %d 条告警规则", created), Data: gin.H{"created": created}, }) }