diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index a91365d..cde4cb3 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"` @@ -415,6 +437,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 +452,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 +463,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.CronCoverAlertTrigger { + 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 +487,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 @@ -596,11 +634,14 @@ func (ma *memberAPI) addOrEditNotification(c *gin.Context) { } type alertRuleForm struct { - ID uint64 - Name string - RulesRaw string - NotificationTag string - 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) { @@ -640,11 +681,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/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/alertrule.go b/model/alertrule.go index 032e616..ca3710b 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 @@ -20,24 +25,49 @@ type CycleTransferStats struct { type AlertRule struct { Common - Name string - RulesRaw string - Enable *bool - NotificationTag string // 该报警规则所在的通知组 - Rules []Rule `gorm:"-" json:"-"` + Name string + RulesRaw string + Enable *bool + 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 } 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/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/cron.go b/model/cron.go index a8e756c..253b440 100644 --- a/model/cron.go +++ b/model/cron.go @@ -11,11 +11,15 @@ import ( const ( CronCoverIgnoreAll = iota CronCoverAll + CronCoverAlertTrigger + 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/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)) } diff --git a/resource/l10n/zh-CN.toml b/resource/l10n/zh-CN.toml index d6d434f..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 = "计划的格式为:" @@ -148,6 +160,21 @@ other = "添加报警规则" [Rules] other = "规则" +[NotificationTriggerMode] +other = "通知触发模式" + +[ModeAlwaysTrigger] +other = "始终触发" + +[ModeOnetimeTrigger] +other = "单次触发" + +[FailTriggerTasks] +other = "故障时触发任务" + +[RecoverTriggerTasks] +other = "恢复时触发任务" + [Enable] other = "启用" @@ -196,6 +223,9 @@ other = "覆盖所有" [IgnoreAll] other = "忽略所有" +[ByTrigger] +other = "触发执行" + [DeleteScheduledTask] other = "删除计划任务" diff --git a/resource/static/main.js b/resource/static/main.js index d7da66e..bc15d25 100644 --- a/resource/static/main.js +++ b/resource/static/main.js @@ -69,6 +69,8 @@ function showFormModal(modelSelector, formID, URL, getData) { item.name === "ID" || item.name === "RequestType" || item.name === "RequestMethod" || + item.name === "TriggerMode" || + item.name === "TaskType" || item.name === "DisplayIndex" || item.name === "Type" || item.name === "Cover" || @@ -89,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)) @@ -130,12 +142,51 @@ 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"); } 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"); } @@ -262,6 +313,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; @@ -293,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) => { @@ -430,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 @@ +