diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index 9e246ad..2d6a24f 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -612,12 +612,14 @@ func (ma *memberAPI) addOrEditNotification(c *gin.Context) { } type alertRuleForm struct { - ID uint64 - Name string - RulesRaw string - NotificationTag string - TriggerMode int - Enable string + ID uint64 + Name string + RulesRaw string + FailTriggerTasksRaw string // 失败时触发的任务id + RecoverTriggerTasksRaw string // 恢复时触发的任务id + NotificationTag string + TriggerMode int + Enable string } func (ma *memberAPI) addOrEditAlertRule(c *gin.Context) { @@ -657,12 +659,22 @@ func (ma *memberAPI) addOrEditAlertRule(c *gin.Context) { if err == nil { r.Name = arf.Name r.RulesRaw = arf.RulesRaw + r.FailTriggerTasksRaw = arf.FailTriggerTasksRaw + r.RecoverTriggerTasksRaw = arf.RecoverTriggerTasksRaw r.NotificationTag = arf.NotificationTag enable := arf.Enable == "on" r.TriggerMode = arf.TriggerMode r.Enable = &enable r.ID = arf.ID - //保证NotificationTag不为空 + } + if err == nil { + err = utils.Json.Unmarshal([]byte(arf.FailTriggerTasksRaw), &r.FailTriggerTasks) + } + if err == nil { + err = utils.Json.Unmarshal([]byte(arf.RecoverTriggerTasksRaw), &r.RecoverTriggerTasks) + } + //保证NotificationTag不为空 + if err == nil { if r.NotificationTag == "" { r.NotificationTag = "default" } diff --git a/model/alertrule.go b/model/alertrule.go index 126289a..37c7b77 100644 --- a/model/alertrule.go +++ b/model/alertrule.go @@ -25,25 +25,49 @@ type CycleTransferStats struct { type AlertRule struct { Common - Name string - RulesRaw string - Enable *bool - TriggerMode int `gorm:"default:0"` // 触发模式: 0-始终触发(默认) 1-单次触发 - NotificationTag string // 该报警规则所在的通知组 - Rules []Rule `gorm:"-" json:"-"` + Name string + RulesRaw string + Enable *bool + TriggerMode int `gorm:"default:0"` // 触发模式: 0-始终触发(默认) 1-单次触发 + NotificationTag string // 该报警规则所在的通知组 + FailTriggerTasksRaw string + RecoverTriggerTasksRaw string + Rules []Rule `gorm:"-" json:"-"` + FailTriggerTasks []uint64 `gorm:"-" json:"-"` // 失败时执行的触发任务id + RecoverTriggerTasks []uint64 `gorm:"-" json:"-"` // 恢复时执行的触发任务id } func (r *AlertRule) BeforeSave(tx *gorm.DB) error { - data, err := utils.Json.Marshal(r.Rules) - if err != nil { + if data, err := utils.Json.Marshal(r.Rules); err != nil { return err + } else { + r.RulesRaw = string(data) + } + if data, err := utils.Json.Marshal(r.FailTriggerTasks); err != nil { + return err + } else { + r.FailTriggerTasksRaw = string(data) + } + if data, err := utils.Json.Marshal(r.RecoverTriggerTasks); err != nil { + return err + } else { + r.RecoverTriggerTasksRaw = string(data) } - r.RulesRaw = string(data) return nil } func (r *AlertRule) AfterFind(tx *gorm.DB) error { - return utils.Json.Unmarshal([]byte(r.RulesRaw), &r.Rules) + var err error + if err = utils.Json.Unmarshal([]byte(r.RulesRaw), &r.Rules); err != nil { + return err + } + if err = utils.Json.Unmarshal([]byte(r.FailTriggerTasksRaw), &r.FailTriggerTasks); err != nil { + return err + } + if err = utils.Json.Unmarshal([]byte(r.RecoverTriggerTasksRaw), &r.RecoverTriggerTasks); err != nil { + return err + } + return nil } func (r *AlertRule) Enabled() bool { diff --git a/service/singleton/alertsentinel.go b/service/singleton/alertsentinel.go index 5d5b244..eb95fc3 100644 --- a/service/singleton/alertsentinel.go +++ b/service/singleton/alertsentinel.go @@ -162,6 +162,7 @@ func checkStatus() { message := fmt.Sprintf("[%s] %s(%s) %s", Localizer.MustLocalize(&i18n.LocalizeConfig{ MessageID: "Incident", }), server.Name, IPDesensitize(server.Host.IP), alert.Name) + go SendTriggerTasks(alert.FailTriggerTasks, curServer.ID) go SendNotification(alert.NotificationTag, message, true, &curServer) } } else { @@ -170,6 +171,7 @@ func checkStatus() { message := fmt.Sprintf("[%s] %s(%s) %s", Localizer.MustLocalize(&i18n.LocalizeConfig{ MessageID: "Resolved", }), server.Name, IPDesensitize(server.Host.IP), alert.Name) + go SendTriggerTasks(alert.RecoverTriggerTasks, curServer.ID) go SendNotification(alert.NotificationTag, message, true, &curServer) } alertsPrevState[alert.ID][server.ID] = _RuleCheckPass diff --git a/service/singleton/crontask.go b/service/singleton/crontask.go index bfba6b6..247b9b1 100644 --- a/service/singleton/crontask.go +++ b/service/singleton/crontask.go @@ -35,6 +35,7 @@ func LoadCronTasks() { for i := 0; i < len(crons); i++ { // 触发任务类型无需注册 if crons[i].TaskType == model.CronTypeTriggerTask { + Crons[crons[i].ID] = &crons[i] continue } // 旧版本计划任务可能不存在通知组 为其添加默认通知组 @@ -68,6 +69,22 @@ func ManualTrigger(c model.Cron) { CronTrigger(c)() } +func SendTriggerTasks(taskIDs []uint64, triggerServer uint64) { + CronLock.RLock() + var cronLists []*model.Cron + for _, taskID := range taskIDs { + if c, ok := Crons[taskID]; ok { + cronLists = append(cronLists, c) + } + } + CronLock.RUnlock() + + // 依次调用CronTrigger发送任务 + for _, c := range cronLists { + go CronTrigger(*c, triggerServer)() + } +} + func CronTrigger(cr model.Cron, triggerServer ...uint64) func() { crIgnoreMap := make(map[uint64]bool) for j := 0; j < len(cr.Servers); j++ { @@ -76,7 +93,7 @@ func CronTrigger(cr model.Cron, triggerServer ...uint64) func() { return func() { if cr.Cover == model.CronCoverSelf { if len(triggerServer) == 0 { - log.Println("触发任务未指定触发服务器") + log.Println("触发任务", cr.Name, "未指定触发服务器") return } ServerLock.RLock()