From 32d15e116e7d81568a4ec9aa4704a059a3d17900 Mon Sep 17 00:00:00 2001 From: Akkia Date: Tue, 13 Sep 2022 04:01:08 +0800 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20=E8=A7=A6=E5=8F=91=E6=8A=A5?= =?UTF-8?q?=E8=AD=A6=E5=90=8E=E7=9A=84=E9=80=9A=E7=9F=A5=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=BB=85=E5=8F=91=E9=80=81=E4=B8=80=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/dashboard/controller/member_api.go | 2 ++ model/alertrule.go | 6 ++++++ service/singleton/alertsentinel.go | 16 +++++++++++----- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index a91365d..b02c49e 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -600,6 +600,7 @@ type alertRuleForm struct { Name string RulesRaw string NotificationTag string + TriggerMode int Enable string } @@ -642,6 +643,7 @@ func (ma *memberAPI) addOrEditAlertRule(c *gin.Context) { r.RulesRaw = arf.RulesRaw r.NotificationTag = arf.NotificationTag enable := arf.Enable == "on" + r.TriggerMode = arf.TriggerMode r.Enable = &enable r.ID = arf.ID //保证NotificationTag不为空 diff --git a/model/alertrule.go b/model/alertrule.go index 032e616..126289a 100644 --- a/model/alertrule.go +++ b/model/alertrule.go @@ -7,6 +7,11 @@ import ( "gorm.io/gorm" ) +const ( + ModeAlwaysTrigger = 0 + ModeOnetimeTrigger = 1 +) + type CycleTransferStats struct { Name string From time.Time @@ -23,6 +28,7 @@ type AlertRule struct { Name string RulesRaw string Enable *bool + TriggerMode int `gorm:"default:0"` // 触发模式: 0-始终触发(默认) 1-单次触发 NotificationTag string // 该报警规则所在的通知组 Rules []Rule `gorm:"-" json:"-"` } diff --git a/service/singleton/alertsentinel.go b/service/singleton/alertsentinel.go index f178ae1..5d5b244 100644 --- a/service/singleton/alertsentinel.go +++ b/service/singleton/alertsentinel.go @@ -153,13 +153,19 @@ func checkStatus() { // 保存当前服务器状态信息 curServer := model.Server{} copier.Copy(&curServer, server) + + // 本次未通过检查 if !passed { - alertsPrevState[alert.ID][server.ID] = _RuleCheckFail - message := fmt.Sprintf("[%s] %s(%s) %s", Localizer.MustLocalize(&i18n.LocalizeConfig{ - MessageID: "Incident", - }), server.Name, IPDesensitize(server.Host.IP), alert.Name) - go SendNotification(alert.NotificationTag, message, true, &curServer) + // 始终触发模式或上次检查不为失败时触发报警(跳过单次触发+上次失败的情况) + if alert.TriggerMode == model.ModeAlwaysTrigger || alertsPrevState[alert.ID][server.ID] != _RuleCheckFail { + alertsPrevState[alert.ID][server.ID] = _RuleCheckFail + message := fmt.Sprintf("[%s] %s(%s) %s", Localizer.MustLocalize(&i18n.LocalizeConfig{ + MessageID: "Incident", + }), server.Name, IPDesensitize(server.Host.IP), alert.Name) + go SendNotification(alert.NotificationTag, message, true, &curServer) + } } else { + // 本次通过检查但上一次的状态为失败,则发送恢复通知 if alertsPrevState[alert.ID][server.ID] == _RuleCheckFail { message := fmt.Sprintf("[%s] %s(%s) %s", Localizer.MustLocalize(&i18n.LocalizeConfig{ MessageID: "Resolved", From 4f26f36c8ebcb73e06caae7d1b9bb62c89f6321a Mon Sep 17 00:00:00 2001 From: Akkia Date: Tue, 13 Sep 2022 04:02:34 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=9B=B4=E6=96=B0:=20?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E6=96=B0=E7=9A=84=E6=8A=A5=E8=AD=A6=E8=A7=84?= =?UTF-8?q?=E5=88=99=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resource/l10n/zh-CN.toml | 9 +++++++++ resource/static/main.js | 2 ++ resource/template/component/rule.html | 7 +++++++ resource/template/dashboard-default/notification.html | 2 ++ 4 files changed, 20 insertions(+) diff --git a/resource/l10n/zh-CN.toml b/resource/l10n/zh-CN.toml index d6d434f..ce842f0 100644 --- a/resource/l10n/zh-CN.toml +++ b/resource/l10n/zh-CN.toml @@ -148,6 +148,15 @@ other = "添加报警规则" [Rules] other = "规则" +[NotificationTriggerMode] +other = "通知触发模式" + +[ModeAlwaysTrigger] +other = "始终触发" + +[ModeOnetimeTrigger] +other = "单次触发" + [Enable] other = "启用" diff --git a/resource/static/main.js b/resource/static/main.js index d7da66e..581ae5d 100644 --- a/resource/static/main.js +++ b/resource/static/main.js @@ -69,6 +69,7 @@ function showFormModal(modelSelector, formID, URL, getData) { item.name === "ID" || item.name === "RequestType" || item.name === "RequestMethod" || + item.name === "TriggerMode" || item.name === "DisplayIndex" || item.name === "Type" || item.name === "Cover" || @@ -130,6 +131,7 @@ function addOrEditAlertRule(rule) { modal.find("input[name=ID]").val(rule ? rule.ID : null); modal.find("input[name=Name]").val(rule ? rule.Name : null); modal.find("textarea[name=RulesRaw]").val(rule ? rule.RulesRaw : null); + modal.find("select[name=TriggerMode]").val(rule ? rule.TriggerMode : 0); modal.find("input[name=NotificationTag]").val(rule ? rule.NotificationTag : null); if (rule && rule.Enable) { modal.find(".ui.rule-enable.checkbox").checkbox("set checked"); diff --git a/resource/template/component/rule.html b/resource/template/component/rule.html index ca49976..c0f79d8 100644 --- a/resource/template/component/rule.html +++ b/resource/template/component/rule.html @@ -16,6 +16,13 @@ +
+ + +
diff --git a/resource/template/dashboard-default/notification.html b/resource/template/dashboard-default/notification.html index 17cdc97..9c331a2 100644 --- a/resource/template/dashboard-default/notification.html +++ b/resource/template/dashboard-default/notification.html @@ -58,6 +58,7 @@ ID {{tr "Name"}} {{tr "NotificationMethodGroup"}} + {{tr "NotificationTriggerMode"}} {{tr "Rules"}} {{tr "Enable"}} {{tr "Administration"}} @@ -69,6 +70,7 @@ {{$rule.ID}} {{$rule.Name}} {{$rule.NotificationTag}} + {{if eq $rule.TriggerMode 0}}{{tr "ModeAlwaysTrigger"}}{{else}}{{tr "ModeOnetimeTrigger"}}{{end}} {{$rule.RulesRaw}} {{$rule.Enable}} From 7228f334a5dd9aecb4d9f69d5af2ba71d0b0736b Mon Sep 17 00:00:00 2001 From: Akkia Date: Tue, 13 Sep 2022 06:14:47 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=A7=A6=E5=8F=91?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/dashboard/controller/member_api.go | 18 ++++++++++++++- model/cron.go | 6 ++++- service/singleton/crontask.go | 31 +++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index b02c49e..9e246ad 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -415,6 +415,7 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) { type cronForm struct { ID uint64 + TaskType uint8 // 0:计划任务 1:触发任务 Name string Scheduler string Command string @@ -429,6 +430,7 @@ func (ma *memberAPI) addOrEditCron(c *gin.Context) { var cr model.Cron err := c.ShouldBindJSON(&cf) if err == nil { + cr.TaskType = cf.TaskType cr.Name = cf.Name cr.Scheduler = cf.Scheduler cr.Command = cf.Command @@ -439,6 +441,17 @@ func (ma *memberAPI) addOrEditCron(c *gin.Context) { cr.Cover = cf.Cover err = utils.Json.Unmarshal([]byte(cf.ServersRaw), &cr.Servers) } + + // 计划任务类型不得使用触发服务器执行方式 + if cr.TaskType == model.CronTypeCronTask && cr.Cover == model.CronCoverSelf { + err = errors.New("计划任务类型不得使用触发服务器执行方式") + c.JSON(http.StatusOK, model.Response{ + Code: http.StatusBadRequest, + Message: fmt.Sprintf("请求错误:%s", err), + }) + return + } + tx := singleton.DB.Begin() if err == nil { // 保证NotificationTag不为空 @@ -452,7 +465,10 @@ func (ma *memberAPI) addOrEditCron(c *gin.Context) { } } if err == nil { - cr.CronJobID, err = singleton.Cron.AddFunc(cr.Scheduler, singleton.CronTrigger(cr)) + // 对于计划任务类型,需要更新CronJob + if cf.TaskType == model.CronTypeCronTask { + cr.CronJobID, err = singleton.Cron.AddFunc(cr.Scheduler, singleton.CronTrigger(cr)) + } } if err == nil { err = tx.Commit().Error diff --git a/model/cron.go b/model/cron.go index a8e756c..2ae4f44 100644 --- a/model/cron.go +++ b/model/cron.go @@ -11,11 +11,15 @@ import ( const ( CronCoverIgnoreAll = iota CronCoverAll + CronCoverSelf + CronTypeCronTask = 0 + CronTypeTriggerTask = 1 ) type Cron struct { Common Name string + TaskType uint8 `gorm:"default:0"` // 0:计划任务 1:触发任务 Scheduler string //分钟 小时 天 月 星期 Command string Servers []uint64 `gorm:"-"` @@ -23,7 +27,7 @@ type Cron struct { NotificationTag string // 指定通知方式的分组 LastExecutedAt time.Time // 最后一次执行时间 LastResult bool // 最后一次执行结果 - Cover uint8 // 计划任务覆盖范围 (0:仅覆盖特定服务器 1:仅忽略特定服务器) + Cover uint8 // 计划任务覆盖范围 (0:仅覆盖特定服务器 1:仅忽略特定服务器 2:由触发该计划任务的服务器执行) CronJobID cron.EntryID `gorm:"-"` ServersRaw string diff --git a/service/singleton/crontask.go b/service/singleton/crontask.go index 8cd26d7..bfba6b6 100644 --- a/service/singleton/crontask.go +++ b/service/singleton/crontask.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "github.com/jinzhu/copier" + "log" "sync" "github.com/robfig/cron/v3" @@ -32,6 +33,10 @@ func LoadCronTasks() { var notificationTagList []string notificationMsgMap := make(map[string]*bytes.Buffer) for i := 0; i < len(crons); i++ { + // 触发任务类型无需注册 + if crons[i].TaskType == model.CronTypeTriggerTask { + continue + } // 旧版本计划任务可能不存在通知组 为其添加默认通知组 if crons[i].NotificationTag == "" { crons[i].NotificationTag = "default" @@ -63,12 +68,36 @@ func ManualTrigger(c model.Cron) { CronTrigger(c)() } -func CronTrigger(cr model.Cron) func() { +func CronTrigger(cr model.Cron, triggerServer ...uint64) func() { crIgnoreMap := make(map[uint64]bool) for j := 0; j < len(cr.Servers); j++ { crIgnoreMap[cr.Servers[j]] = true } return func() { + if cr.Cover == model.CronCoverSelf { + if len(triggerServer) == 0 { + log.Println("触发任务未指定触发服务器") + return + } + ServerLock.RLock() + defer ServerLock.RUnlock() + if s, ok := ServerList[triggerServer[0]]; ok { + if s.TaskStream != nil { + s.TaskStream.Send(&pb.Task{ + Id: cr.ID, + Data: cr.Command, + Type: model.TaskTypeCommand, + }) + } else { + // 保存当前服务器状态信息 + curServer := model.Server{} + copier.Copy(&curServer, s) + SendNotification(cr.NotificationTag, fmt.Sprintf("[任务失败] %s,服务器 %s 离线,无法执行。", cr.Name, s.Name), false, &curServer) + } + } + return + } + ServerLock.RLock() defer ServerLock.RUnlock() for _, s := range ServerList { From ceb1b74834d17f92a172a80f80699048f22c427a Mon Sep 17 00:00:00 2001 From: Akkia Date: Wed, 14 Sep 2022 11:06:59 +0800 Subject: [PATCH 04/11] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=9B=91=E6=8E=A7=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E7=94=9F=E6=88=90=E7=9A=84id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resource/static/main.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resource/static/main.js b/resource/static/main.js index 581ae5d..557866c 100644 --- a/resource/static/main.js +++ b/resource/static/main.js @@ -264,6 +264,9 @@ function addOrEditMonitor(monitor) { } else { modal.find(".ui.nb-notify.checkbox").checkbox("set unchecked"); } + modal.find("a.ui.label.visible").each((i, el) => { + el.remove(); + }); var servers; if (monitor) { servers = monitor.SkipServersRaw; From 13d1be59b644c6d3a7507706906a28e2f722ed80 Mon Sep 17 00:00:00 2001 From: Akkia Date: Wed, 14 Sep 2022 11:14:23 +0800 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=E6=8A=A5=E8=AD=A6=E8=A7=84?= =?UTF-8?q?=E5=88=99=E6=94=AF=E6=8C=81=E7=BB=91=E5=AE=9A=E8=A7=A6=E5=8F=91?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/dashboard/controller/member_api.go | 26 +++++++++++---- model/alertrule.go | 44 ++++++++++++++++++++------ service/singleton/alertsentinel.go | 2 ++ service/singleton/crontask.go | 19 ++++++++++- 4 files changed, 73 insertions(+), 18 deletions(-) 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() From 93e1d58bcb69aad1c7dee99c12b75a7e9a3cb0d3 Mon Sep 17 00:00:00 2001 From: Akkia Date: Wed, 14 Sep 2022 11:32:15 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=9B=B4=E6=96=B0:=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=8A=A5=E8=AD=A6=E8=A7=84=E5=88=99=E7=BB=91?= =?UTF-8?q?=E5=AE=9A=E8=A7=A6=E5=8F=91=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/dashboard/controller/member_api.go | 22 +++++++ resource/l10n/zh-CN.toml | 21 +++++++ resource/static/main.js | 63 +++++++++++++++++++ resource/template/component/cron.html | 8 +++ resource/template/component/rule.html | 19 ++++++ resource/template/dashboard-default/cron.html | 4 +- .../dashboard-default/notification.html | 4 ++ 7 files changed, 140 insertions(+), 1 deletion(-) diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index 2d6a24f..fedf50f 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -33,6 +33,7 @@ func (ma *memberAPI) serve() { })) mr.GET("/search-server", ma.searchServer) + mr.GET("/search-tasks", ma.searchTask) mr.POST("/server", ma.addOrEditServer) mr.POST("/monitor", ma.addOrEditMonitor) mr.POST("/cron", ma.addOrEditCron) @@ -275,6 +276,27 @@ func (ma *memberAPI) searchServer(c *gin.Context) { }) } +func (ma *memberAPI) searchTask(c *gin.Context) { + var tasks []model.Cron + likeWord := "%" + c.Query("word") + "%" + singleton.DB.Select("id,name").Where("id = ? OR name LIKE ?", + c.Query("word"), likeWord).Find(&tasks) + + var resp []searchResult + for i := 0; i < len(tasks); i++ { + resp = append(resp, searchResult{ + Value: tasks[i].ID, + Name: tasks[i].Name, + Text: tasks[i].Name, + }) + } + + c.JSON(http.StatusOK, map[string]interface{}{ + "success": true, + "results": resp, + }) +} + type serverForm struct { ID uint64 Name string `binding:"required"` diff --git a/resource/l10n/zh-CN.toml b/resource/l10n/zh-CN.toml index ce842f0..4da8ff1 100644 --- a/resource/l10n/zh-CN.toml +++ b/resource/l10n/zh-CN.toml @@ -70,6 +70,9 @@ other = "忽略所有,仅通过特定服务器执行" [AllIncludedOnlySpecificServersAreNotExecuted] other = "覆盖所有,仅特定服务器不执行" +[ExecuteByTriggerServer] +other = "由触发的服务器执行" + [SpecificServers] other = "特定服务器" @@ -82,6 +85,15 @@ other = "通知方式组" [PushSuccessMessages] other = "推送成功的消息" +[TaskType] +other = "任务类型" + +[CronTask] +other = "计划任务" + +[TriggerTask] +other = "触发任务" + [TheFormaOfTheScheduleIs] other = "计划的格式为:" @@ -157,6 +169,12 @@ other = "始终触发" [ModeOnetimeTrigger] other = "单次触发" +[FailTriggerTasks] +other = "故障时触发任务" + +[RecoverTriggerTasks] +other = "恢复时触发任务" + [Enable] other = "启用" @@ -205,6 +223,9 @@ other = "覆盖所有" [IgnoreAll] other = "忽略所有" +[ByTrigger] +other = "触发执行" + [DeleteScheduledTask] other = "删除计划任务" diff --git a/resource/static/main.js b/resource/static/main.js index 557866c..bc15d25 100644 --- a/resource/static/main.js +++ b/resource/static/main.js @@ -70,6 +70,7 @@ function showFormModal(modelSelector, formID, URL, getData) { item.name === "RequestType" || item.name === "RequestMethod" || item.name === "TriggerMode" || + item.name === "TaskType" || item.name === "DisplayIndex" || item.name === "Type" || item.name === "Cover" || @@ -90,6 +91,16 @@ function showFormModal(modelSelector, formID, URL, getData) { } } + if (item.name.endsWith("TasksRaw")) { + if (item.value.length > 2) { + obj[item.name] = JSON.stringify( + [...item.value.matchAll(/\d+/gm)].map((k) => + parseInt(k[0]) + ) + ); + } + } + return obj; }, {}); $.post(URL, JSON.stringify(data)) @@ -138,6 +149,44 @@ function addOrEditAlertRule(rule) { } else { modal.find(".ui.rule-enable.checkbox").checkbox("set unchecked"); } + modal.find("a.ui.label.visible").each((i, el) => { + el.remove(); + }); + var failTriggerTasks; + var recoverTriggerTasks; + if (rule) { + failTriggerTasks = rule.FailTriggerTasksRaw; + recoverTriggerTasks = rule.RecoverTriggerTasksRaw; + const failTriggerTasksList = JSON.parse(failTriggerTasks || "[]"); + const recoverTriggerTasksList = JSON.parse(recoverTriggerTasks || "[]"); + const node1 = modal.find("i.dropdown.icon.1"); + const node2 = modal.find("i.dropdown.icon.2"); + for (let i = 0; i < failTriggerTasksList.length; i++) { + node1.after( + 'ID:' + + failTriggerTasksList[i] + + '' + ); + } + for (let i = 0; i < recoverTriggerTasksList.length; i++) { + node2.after( + 'ID:' + + recoverTriggerTasksList[i] + + '' + ); + } + } + modal + .find("input[name=FailTriggerTasksRaw]") + .val(rule ? "[]," + failTriggerTasks.substr(1, failTriggerTasks.length - 2) : "[]"); + modal + .find("input[name=RecoverTriggerTasksRaw]") + .val(rule ? "[]," + recoverTriggerTasks.substr(1, recoverTriggerTasks.length - 2) : "[]"); + showFormModal(".rule.modal", "#ruleForm", "/api/alert-rule"); } @@ -298,6 +347,8 @@ function addOrEditCron(cron) { ); modal.find("input[name=ID]").val(cron ? cron.ID : null); modal.find("input[name=Name]").val(cron ? cron.Name : null); + modal.find("select[name=TaskType]").val(cron ? cron.TaskType : 0); + modal.find("select[name=Cover]").val(cron ? cron.Cover : 0); modal.find("input[name=NotificationTag]").val(cron ? cron.NotificationTag : null); modal.find("input[name=Scheduler]").val(cron ? cron.Scheduler : null); modal.find("a.ui.label.visible").each((i, el) => { @@ -435,3 +486,15 @@ $(document).ready(() => { }); } catch (error) { } }); + +$(document).ready(() => { + try { + $(".ui.tasks.search.dropdown").dropdown({ + clearable: true, + apiSettings: { + url: "/api/search-tasks?word={query}", + cache: false, + }, + }); + } catch (error) { } +}); diff --git a/resource/template/component/cron.html b/resource/template/component/cron.html index 79cd0c6..1ac3463 100644 --- a/resource/template/component/cron.html +++ b/resource/template/component/cron.html @@ -8,6 +8,13 @@
+
+ + +
@@ -21,6 +28,7 @@
diff --git a/resource/template/component/rule.html b/resource/template/component/rule.html index c0f79d8..918931e 100644 --- a/resource/template/component/rule.html +++ b/resource/template/component/rule.html @@ -23,6 +23,25 @@
+
+ + +
+
+ + +
+
diff --git a/resource/template/dashboard-default/cron.html b/resource/template/dashboard-default/cron.html index 67619d5..d136e76 100644 --- a/resource/template/dashboard-default/cron.html +++ b/resource/template/dashboard-default/cron.html @@ -15,6 +15,7 @@ ID {{tr "Name"}} + {{tr "TaskType"}} {{tr "Scheduler"}} {{tr "Command"}} {{tr "NotificationMethodGroup"}} @@ -31,11 +32,12 @@ {{$cron.ID}} {{$cron.Name}} + {{if eq $cron.TaskType 0}}{{tr "CronTask"}}{{else}}{{tr "TriggerTask"}}{{end}} {{$cron.Scheduler}} {{$cron.Command}} {{$cron.NotificationTag}} {{$cron.PushSuccessful}} - {{if eq $cron.Cover 0}}{{tr "IgnoreAll"}}{{else}}{{tr "CoverAll"}}{{end}} + {{if eq $cron.Cover 0}}{{tr "IgnoreAll"}}{{else if eq $cron.Cover 1}}{{tr "CoverAll"}}{{else}}{{tr "ByTrigger"}}{{end}} {{$cron.ServersRaw}} {{$cron.LastExecutedAt|tf}} {{$cron.LastResult}} diff --git a/resource/template/dashboard-default/notification.html b/resource/template/dashboard-default/notification.html index 9c331a2..133aa8e 100644 --- a/resource/template/dashboard-default/notification.html +++ b/resource/template/dashboard-default/notification.html @@ -60,6 +60,8 @@ {{tr "NotificationMethodGroup"}} {{tr "NotificationTriggerMode"}} {{tr "Rules"}} + {{tr "FailTriggerTasks"}} + {{tr "RecoverTriggerTasks"}} {{tr "Enable"}} {{tr "Administration"}} @@ -72,6 +74,8 @@ {{$rule.NotificationTag}} {{if eq $rule.TriggerMode 0}}{{tr "ModeAlwaysTrigger"}}{{else}}{{tr "ModeOnetimeTrigger"}}{{end}} {{$rule.RulesRaw}} + {{$rule.FailTriggerTasksRaw}} + {{$rule.RecoverTriggerTasksRaw}} {{$rule.Enable}}
From 0aaf642f69d77c6883819706e08438fd5754dcde Mon Sep 17 00:00:00 2001 From: Akkia Date: Wed, 14 Sep 2022 11:37:00 +0800 Subject: [PATCH 07/11] update for CodeQL --- service/singleton/crontask.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/service/singleton/crontask.go b/service/singleton/crontask.go index 247b9b1..e8019e7 100644 --- a/service/singleton/crontask.go +++ b/service/singleton/crontask.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "github.com/jinzhu/copier" - "log" "sync" "github.com/robfig/cron/v3" @@ -93,7 +92,6 @@ func CronTrigger(cr model.Cron, triggerServer ...uint64) func() { return func() { if cr.Cover == model.CronCoverSelf { if len(triggerServer) == 0 { - log.Println("触发任务", cr.Name, "未指定触发服务器") return } ServerLock.RLock() From 13abf2af1386c4810b7feb919bb32084149c76bb Mon Sep 17 00:00:00 2001 From: Akkia Date: Wed, 14 Sep 2022 12:16:24 +0800 Subject: [PATCH 08/11] =?UTF-8?q?=E4=B8=BA=E6=96=B0=E5=A2=9E=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=8F=90=E4=BE=9B=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- model/alertrule.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/model/alertrule.go b/model/alertrule.go index 37c7b77..ca3710b 100644 --- a/model/alertrule.go +++ b/model/alertrule.go @@ -28,10 +28,10 @@ type AlertRule struct { Name string RulesRaw string Enable *bool - TriggerMode int `gorm:"default:0"` // 触发模式: 0-始终触发(默认) 1-单次触发 - NotificationTag string // 该报警规则所在的通知组 - FailTriggerTasksRaw string - RecoverTriggerTasksRaw string + TriggerMode int `gorm:"default:0"` // 触发模式: 0-始终触发(默认) 1-单次触发 + NotificationTag string // 该报警规则所在的通知组 + FailTriggerTasksRaw string `gorm:"default:'[]'"` + RecoverTriggerTasksRaw string `gorm:"default:'[]'"` Rules []Rule `gorm:"-" json:"-"` FailTriggerTasks []uint64 `gorm:"-" json:"-"` // 失败时执行的触发任务id RecoverTriggerTasks []uint64 `gorm:"-" json:"-"` // 恢复时执行的触发任务id From a5ddafbd8b0070df293118e75be7c020c297b099 Mon Sep 17 00:00:00 2001 From: naiba Date: Wed, 14 Sep 2022 22:14:47 +0800 Subject: [PATCH 09/11] rename `CronCoverSelf` to `CronCoverAlertTrigger` --- cmd/dashboard/controller/member_api.go | 2 +- model/cron.go | 2 +- service/singleton/crontask.go | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index fedf50f..cde4cb3 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -465,7 +465,7 @@ func (ma *memberAPI) addOrEditCron(c *gin.Context) { } // 计划任务类型不得使用触发服务器执行方式 - if cr.TaskType == model.CronTypeCronTask && cr.Cover == model.CronCoverSelf { + if cr.TaskType == model.CronTypeCronTask && cr.Cover == model.CronCoverAlertTrigger { err = errors.New("计划任务类型不得使用触发服务器执行方式") c.JSON(http.StatusOK, model.Response{ Code: http.StatusBadRequest, diff --git a/model/cron.go b/model/cron.go index 2ae4f44..253b440 100644 --- a/model/cron.go +++ b/model/cron.go @@ -11,7 +11,7 @@ import ( const ( CronCoverIgnoreAll = iota CronCoverAll - CronCoverSelf + CronCoverAlertTrigger CronTypeCronTask = 0 CronTypeTriggerTask = 1 ) diff --git a/service/singleton/crontask.go b/service/singleton/crontask.go index e8019e7..bf721ea 100644 --- a/service/singleton/crontask.go +++ b/service/singleton/crontask.go @@ -3,9 +3,10 @@ package singleton import ( "bytes" "fmt" - "github.com/jinzhu/copier" "sync" + "github.com/jinzhu/copier" + "github.com/robfig/cron/v3" "github.com/naiba/nezha/model" @@ -90,7 +91,7 @@ func CronTrigger(cr model.Cron, triggerServer ...uint64) func() { crIgnoreMap[cr.Servers[j]] = true } return func() { - if cr.Cover == model.CronCoverSelf { + if cr.Cover == model.CronCoverAlertTrigger { if len(triggerServer) == 0 { return } From 87e1b8efcad3f89610c76188cc03ec7a1d53061c Mon Sep 17 00:00:00 2001 From: naiba Date: Wed, 14 Sep 2022 22:14:53 +0800 Subject: [PATCH 10/11] fix typo --- resource/template/dashboard-default/redirect.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resource/template/dashboard-default/redirect.html b/resource/template/dashboard-default/redirect.html index 4f43eef..90d8f07 100644 --- a/resource/template/dashboard-default/redirect.html +++ b/resource/template/dashboard-default/redirect.html @@ -6,11 +6,11 @@ - Redireting.. + Redirecting.. -

Please click here if you are not redirected.

+

If you are not redirected, please click here.

From 1561ccb2fbe376c37455da347903f0d9c7ffbf6e Mon Sep 17 00:00:00 2001 From: naiba Date: Wed, 14 Sep 2022 22:26:14 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20upgrade=20dependenci?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 22 +++++++++++----------- go.sum | 43 ++++++++++++++++++++++--------------------- model/config.go | 5 ++--- model/notification.go | 4 ++-- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/go.mod b/go.mod index cfc3729..d797993 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( code.cloudfoundry.org/bytefmt v0.0.0-20211005130812-5bb3c17173e5 - github.com/AlecAivazis/survey/v2 v2.3.5 + github.com/AlecAivazis/survey/v2 v2.3.6 github.com/BurntSushi/toml v1.2.0 github.com/Erope/goss v0.0.0-20211230093305-df3c03fd1ed4 github.com/artdarek/go-unzip v1.0.0 @@ -25,16 +25,16 @@ require ( github.com/ory/graceful v0.1.3 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/robfig/cron/v3 v3.0.1 - github.com/shirou/gopsutil/v3 v3.22.7 + github.com/shirou/gopsutil/v3 v3.22.8 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.12.0 + github.com/spf13/viper v1.13.0 github.com/stretchr/testify v1.8.0 - github.com/xanzy/go-gitlab v0.72.0 - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa - golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7 - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 + github.com/xanzy/go-gitlab v0.73.1 + golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 + golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 + golang.org/x/sync v0.0.0-20220907140024-f12130a52804 golang.org/x/text v0.3.7 - google.golang.org/grpc v1.48.0 + google.golang.org/grpc v1.49.0 google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/sqlite v1.3.6 @@ -70,14 +70,14 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.1 // indirect + github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/subosito/gotenv v1.3.0 // indirect + github.com/subosito/gotenv v1.4.1 // indirect github.com/tcnksm/go-gitconfig v0.1.2 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/numcpus v0.4.0 // indirect @@ -90,6 +90,6 @@ require ( golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect - gopkg.in/ini.v1 v1.66.4 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index df27f5f..d1b22e9 100644 --- a/go.sum +++ b/go.sum @@ -38,8 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f code.cloudfoundry.org/bytefmt v0.0.0-20211005130812-5bb3c17173e5 h1:tM5+dn2C9xZw1RzgI6WTQW1rGqdUimKB3RFbyu4h6Hc= code.cloudfoundry.org/bytefmt v0.0.0-20211005130812-5bb3c17173e5/go.mod h1:v4VVB6oBMz/c9fRY6vZrwr5xKRWOH5NPDjQZlPk0Gbs= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AlecAivazis/survey/v2 v2.3.5 h1:A8cYupsAZkjaUmhtTYv3sSqc7LO5mp1XDfqe5E/9wRQ= -github.com/AlecAivazis/survey/v2 v2.3.5/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI= +github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw= +github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= @@ -273,8 +273,9 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -291,8 +292,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/shirou/gopsutil/v3 v3.22.7 h1:flKnuCMfUUrO+oAvwAd6GKZgnPzr098VA/UJ14nhJd4= -github.com/shirou/gopsutil/v3 v3.22.7/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI= +github.com/shirou/gopsutil/v3 v3.22.8 h1:a4s3hXogo5mE2PfdfJIonDbstO/P+9JszdfhAHSzD9Y= +github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= @@ -301,8 +302,8 @@ github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmq github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= -github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= +github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -314,8 +315,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= -github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw= github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE= github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= @@ -327,8 +328,8 @@ github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0 github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/xanzy/go-gitlab v0.72.0 h1:/9BQTftUE7GRK/RO1eeWxG1cOE+tjwBrvRdpkeSOq6w= -github.com/xanzy/go-gitlab v0.72.0/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA= +github.com/xanzy/go-gitlab v0.73.1 h1:UMagqUZLJdjss1SovIC+kJCH4k2AZWXl58gJd38Y/hI= +github.com/xanzy/go-gitlab v0.73.1/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -350,8 +351,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -432,8 +433,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7 h1:dtndE8FcEta75/4kHF3AbpuWzV6f1LjnLrM4pe2SZrw= -golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -445,8 +446,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220907140024-f12130a52804 h1:0SH2R3f1b1VmIMG7BXbEZCBUu2dKmHschSmjqGUrW8A= +golang.org/x/sync v0.0.0-20220907140024-f12130a52804/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -658,8 +659,8 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -682,8 +683,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= -gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/model/config.go b/model/config.go index 8bc2a93..5e117b2 100644 --- a/model/config.go +++ b/model/config.go @@ -1,7 +1,6 @@ package model import ( - "io/ioutil" "os" "strconv" "strings" @@ -67,7 +66,7 @@ func (c *AgentConfig) Save() error { if err != nil { return err } - return ioutil.WriteFile(c.v.ConfigFileUsed(), data, os.ModePerm) + return os.WriteFile(c.v.ConfigFileUsed(), data, os.ModePerm) } // Config 站点配置 @@ -159,5 +158,5 @@ func (c *Config) Save() error { if err != nil { return err } - return ioutil.WriteFile(c.v.ConfigFileUsed(), data, os.ModePerm) + return os.WriteFile(c.v.ConfigFileUsed(), data, os.ModePerm) } diff --git a/model/notification.go b/model/notification.go index 4606c52..11ddac4 100644 --- a/model/notification.go +++ b/model/notification.go @@ -4,7 +4,7 @@ import ( "crypto/tls" "errors" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "strings" @@ -150,7 +150,7 @@ func (ns *NotificationServerBundle) Send(message string) error { if resp.StatusCode < 200 || resp.StatusCode > 299 { defer resp.Body.Close() - body, _ := ioutil.ReadAll(resp.Body) + body, _ := io.ReadAll(resp.Body) return fmt.Errorf("%d@%s %s", resp.StatusCode, resp.Status, string(body)) }