Files
aiops/backend/controller/alert_silence.go
T
2026-07-09 14:16:56 +08:00

261 lines
8.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package controller
import (
"encoding/json"
"net/http"
"strconv"
"time"
"ezops/model"
"github.com/gin-gonic/gin"
)
// 告警静默规则 CRUD(AlertHandler 方法接收者) // Logan.Li
// CreateSilenceRequest 创建静默规则请求
type CreateSilenceRequest struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
RuleIDs []uint `json:"rule_ids"`
TargetIDs []uint `json:"target_ids"`
Matchers []model.AlertSilenceMatcher `json:"matchers"`
SilenceType string `json:"silence_type"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time" binding:"required"`
Weekdays []int `json:"weekdays"`
Status *int `json:"status"`
}
// UpdateSilenceRequest 更新静默规则请求
type UpdateSilenceRequest struct {
Name string `json:"name"`
Description string `json:"description"`
RuleIDs []uint `json:"rule_ids"`
TargetIDs []uint `json:"target_ids"`
Matchers []model.AlertSilenceMatcher `json:"matchers"`
SilenceType string `json:"silence_type"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
Weekdays []int `json:"weekdays"`
Status *int `json:"status"`
}
// ListSilences GET /alerts/silences
func (h *AlertHandler) ListSilences(c *gin.Context) {
var silences []model.AlertSilence
query := h.db.Order("created_at DESC")
if status := c.Query("status"); status != "" {
if status == "active" {
now := time.Now()
query = query.Where("status = ? AND start_time <= ? AND end_time >= ?", 1, now, now)
} else if s, err := strconv.Atoi(status); err == nil {
query = query.Where("status = ?", s)
}
}
query.Find(&silences)
// 解析 JSON 字段为前端友好的格式
type SilenceWithParsed struct {
model.AlertSilence
RuleIDList []uint `json:"rule_id_list"`
TargetIDList []uint `json:"target_id_list"`
MatcherList []model.AlertSilenceMatcher `json:"matcher_list"`
WeekdayList []int `json:"weekday_list"`
IsActive bool `json:"is_active"`
}
var result []SilenceWithParsed
now := time.Now()
for _, s := range silences {
item := SilenceWithParsed{AlertSilence: s}
if s.RuleIDs != "" {
json.Unmarshal([]byte(s.RuleIDs), &item.RuleIDList)
}
if s.TargetIDs != "" {
json.Unmarshal([]byte(s.TargetIDs), &item.TargetIDList)
}
if s.Matchers != "" {
json.Unmarshal([]byte(s.Matchers), &item.MatcherList)
}
if s.Weekdays != "" {
json.Unmarshal([]byte(s.Weekdays), &item.WeekdayList)
}
item.IsActive = s.Status == 1 && now.After(s.StartTime) && now.Before(s.EndTime)
result = append(result, item)
}
c.JSON(http.StatusOK, model.Response{
Code: 200,
Message: "success",
Data: model.ListResponse{List: result, Total: int64(len(result))},
})
}
// CreateSilence POST /alerts/silences
func (h *AlertHandler) CreateSilence(c *gin.Context) {
var req CreateSilenceRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "请求参数错误: " + err.Error()})
return
}
silenceType := model.AlertSilenceOneTime
if req.SilenceType != "" {
silenceType = model.AlertSilenceType(req.SilenceType)
}
// 解析时间
var startTime, endTime time.Time
var err error
if req.StartTime != "" {
startTime, err = time.Parse(time.RFC3339, req.StartTime)
if err != nil {
startTime, err = time.ParseInLocation("2006-01-02 15:04:05", req.StartTime, time.Local)
if err != nil {
startTime = time.Now()
}
}
} else {
startTime = time.Now()
}
endTime, err = time.Parse(time.RFC3339, req.EndTime)
if err != nil {
endTime, err = time.ParseInLocation("2006-01-02 15:04:05", req.EndTime, time.Local)
if err != nil {
c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "结束时间格式错误"})
return
}
}
ruleIDsJSON, _ := json.Marshal(req.RuleIDs)
targetIDsJSON, _ := json.Marshal(req.TargetIDs)
matchersJSON, _ := json.Marshal(req.Matchers)
weekdaysJSON, _ := json.Marshal(req.Weekdays)
silence := model.AlertSilence{
Name: req.Name,
Description: req.Description,
RuleIDs: string(ruleIDsJSON),
TargetIDs: string(targetIDsJSON),
Matchers: string(matchersJSON),
SilenceType: silenceType,
StartTime: startTime,
EndTime: endTime,
Weekdays: string(weekdaysJSON),
Status: 1,
}
// 获取创建人 ID
if userID, exists := c.Get("userID"); exists {
if uid, ok := userID.(uint); ok {
silence.CreatedBy = uid
}
}
if err := h.db.Create(&silence).Error; err != nil {
c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "创建失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, model.Response{Code: 200, Message: "创建成功", Data: silence})
}
// UpdateSilence PUT /alerts/silences/:id
func (h *AlertHandler) UpdateSilence(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
var req UpdateSilenceRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "请求参数错误"})
return
}
var silence model.AlertSilence
if err := h.db.First(&silence, 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.SilenceType != "" {
updates["silence_type"] = req.SilenceType
}
if len(req.RuleIDs) > 0 || req.RuleIDs != nil {
ruleIDsJSON, _ := json.Marshal(req.RuleIDs)
updates["rule_ids"] = string(ruleIDsJSON)
}
if len(req.TargetIDs) > 0 || req.TargetIDs != nil {
targetIDsJSON, _ := json.Marshal(req.TargetIDs)
updates["target_ids"] = string(targetIDsJSON)
}
if len(req.Matchers) > 0 || req.Matchers != nil {
matchersJSON, _ := json.Marshal(req.Matchers)
updates["matchers"] = string(matchersJSON)
}
if len(req.Weekdays) > 0 || req.Weekdays != nil {
weekdaysJSON, _ := json.Marshal(req.Weekdays)
updates["weekdays"] = string(weekdaysJSON)
}
if req.StartTime != "" {
if st, err := time.Parse(time.RFC3339, req.StartTime); err == nil {
updates["start_time"] = st
} else if st, err := time.ParseInLocation("2006-01-02 15:04:05", req.StartTime, time.Local); err == nil {
updates["start_time"] = st
}
}
if req.EndTime != "" {
if et, err := time.Parse(time.RFC3339, req.EndTime); err == nil {
updates["end_time"] = et
} else if et, err := time.ParseInLocation("2006-01-02 15:04:05", req.EndTime, time.Local); err == nil {
updates["end_time"] = et
}
}
if req.Status != nil {
updates["status"] = *req.Status
}
h.db.Model(&silence).Updates(updates)
h.db.First(&silence, id)
c.JSON(http.StatusOK, model.Response{Code: 200, Message: "更新成功", Data: silence})
}
// DeleteSilence DELETE /alerts/silences/:id
func (h *AlertHandler) DeleteSilence(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
if err := h.db.Delete(&model.AlertSilence{}, id).Error; err != nil {
c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "删除失败"})
return
}
c.JSON(http.StatusOK, model.Response{Code: 200, Message: "删除成功"})
}
// ToggleSilence POST /alerts/silences/:id/toggle
func (h *AlertHandler) ToggleSilence(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
var silence model.AlertSilence
if err := h.db.First(&silence, id).Error; err != nil {
c.JSON(http.StatusNotFound, model.Response{Code: 404, Message: "静默规则不存在"})
return
}
newStatus := 0
if silence.Status == 0 {
newStatus = 1
}
h.db.Model(&silence).Update("status", newStatus)
h.db.First(&silence, id)
c.JSON(http.StatusOK, model.Response{Code: 200, Message: "切换成功", Data: silence})
}