Skip to content

Commit 6b46e7e

Browse files
authored
feat: support clone rules by idents (#2095)
1 parent 514ccd5 commit 6b46e7e

File tree

5 files changed

+115
-0
lines changed

5 files changed

+115
-0
lines changed

center/router/router.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ func (rt *Router) Config(r *gin.Engine) {
324324
pages.GET("/alert-rule/:arid/pure", rt.auth(), rt.user(), rt.perm("/alert-rules"), rt.alertRulePureGet)
325325
pages.PUT("/busi-group/alert-rule/validate", rt.auth(), rt.user(), rt.perm("/alert-rules/put"), rt.alertRuleValidation)
326326
pages.POST("/relabel-test", rt.auth(), rt.user(), rt.relabelTest)
327+
pages.POST("/busi-group/:id/alert-rules/clone", rt.auth(), rt.user(), rt.perm("/alert-rules/post"), rt.bgrw(), rt.cloneToMachine)
327328

328329
pages.GET("/busi-groups/recording-rules", rt.auth(), rt.user(), rt.perm("/recording-rules"), rt.recordingRuleGetsByGids)
329330
pages.GET("/busi-group/:id/recording-rules", rt.auth(), rt.user(), rt.perm("/recording-rules"), rt.recordingRuleGets)

center/router/router_alert_rule.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"fmt"
66
"net/http"
7+
"regexp"
78
"strconv"
89
"strings"
910
"time"
@@ -13,6 +14,7 @@ import (
1314
"github.com/ccfos/nightingale/v6/pushgw/writer"
1415

1516
"github.com/gin-gonic/gin"
17+
"github.com/jinzhu/copier"
1618
"github.com/prometheus/prometheus/prompb"
1719
"github.com/toolkits/pkg/ginx"
1820
"github.com/toolkits/pkg/i18n"
@@ -295,6 +297,17 @@ func (rt *Router) alertRulePutFields(c *gin.Context) {
295297
continue
296298
}
297299

300+
if f.Action == "update_triggers" {
301+
if triggers, has := f.Fields["triggers"]; has {
302+
originRule := ar.RuleConfigJson.(map[string]interface{})
303+
originRule["triggers"] = triggers
304+
b, err := json.Marshal(originRule)
305+
ginx.Dangerous(err)
306+
ginx.Dangerous(ar.UpdateFieldsMap(rt.Ctx, map[string]interface{}{"rule_config": string(b)}))
307+
continue
308+
}
309+
}
310+
298311
if f.Action == "annotations_add" {
299312
if annotations, has := f.Fields["annotations"]; has {
300313
annotationsMap := annotations.(map[string]interface{})
@@ -499,3 +512,84 @@ func (rt *Router) relabelTest(c *gin.Context) {
499512

500513
ginx.NewRender(c).Data(tags, nil)
501514
}
515+
516+
type identListForm struct {
517+
Ids []int64 `json:"ids"`
518+
IdentList []string `json:"ident_list"`
519+
}
520+
521+
func (rt *Router) cloneToMachine(c *gin.Context) {
522+
var f identListForm
523+
ginx.BindJSON(c, &f)
524+
525+
if len(f.IdentList) == 0 {
526+
ginx.Bomb(http.StatusBadRequest, "ident_list is empty")
527+
}
528+
529+
alertRules, err := models.AlertRuleGetsByIds(rt.Ctx, f.Ids)
530+
ginx.Dangerous(err)
531+
532+
re := regexp.MustCompile("ident = \".*?\"")
533+
534+
user := c.MustGet("username").(string)
535+
now := time.Now().Unix()
536+
537+
newRules := make([]*models.AlertRule, 0)
538+
539+
reterr := make(map[string]map[string]string)
540+
541+
for i := range alertRules {
542+
reterr[alertRules[i].Name] = make(map[string]string)
543+
544+
if alertRules[i].Cate != "prometheus" {
545+
reterr[alertRules[i].Name]["all"] = "Only Prometheus rules can be cloned to machines"
546+
continue
547+
}
548+
var ruleConfig *models.PromRuleConfig
549+
if err := json.Unmarshal([]byte(alertRules[i].RuleConfig), &ruleConfig); err != nil {
550+
reterr[alertRules[i].Name]["all"] = "invalid rule, fail to unmarshal rule config"
551+
continue
552+
}
553+
554+
for j := range f.IdentList {
555+
556+
for q := range ruleConfig.Queries {
557+
ruleConfig.Queries[q].PromQl = re.ReplaceAllString(ruleConfig.Queries[q].PromQl, fmt.Sprintf("ident = \"%s\"", f.IdentList[j]))
558+
}
559+
560+
configJson, err := json.Marshal(ruleConfig)
561+
if err != nil {
562+
reterr[alertRules[i].Name][f.IdentList[j]] = fmt.Sprintf("invalid rule, fail to marshal rule config, err: %s", err)
563+
continue
564+
}
565+
566+
newRule := &models.AlertRule{}
567+
if err := copier.Copy(newRule, alertRules[i]); err != nil {
568+
reterr[alertRules[i].Name][f.IdentList[j]] = fmt.Sprintf("fail to clone rule, err: %s", err)
569+
continue
570+
}
571+
newRule.Id = 0
572+
newRule.Name = alertRules[i].Name + "_" + f.IdentList[j]
573+
newRule.CreateBy = user
574+
newRule.UpdateBy = user
575+
newRule.UpdateAt = now
576+
newRule.CreateAt = now
577+
newRule.RuleConfig = string(configJson)
578+
579+
exist, err := models.AlertRuleExists(rt.Ctx, 0, newRule.GroupId, newRule.DatasourceIdsJson, newRule.Name)
580+
if err != nil {
581+
reterr[alertRules[i].Name][f.IdentList[j]] = err.Error()
582+
continue
583+
}
584+
585+
if exist {
586+
reterr[alertRules[i].Name][f.IdentList[j]] = fmt.Sprintf("rule already exists, ruleName: %s", newRule.Name)
587+
continue
588+
}
589+
590+
newRules = append(newRules, newRule)
591+
}
592+
}
593+
594+
ginx.NewRender(c).Data(reterr, models.InsertAlertRule(rt.Ctx, newRules))
595+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ require (
1818
github.com/golang/snappy v0.0.4
1919
github.com/google/uuid v1.3.0
2020
github.com/hashicorp/go-version v1.6.0
21+
github.com/jinzhu/copier v0.4.0
2122
github.com/json-iterator/go v1.1.12
2223
github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7
2324
github.com/mailru/easyjson v0.7.7

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f
160160
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
161161
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
162162
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
163+
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
164+
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
163165
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
164166
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
165167
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=

models/alert_rule.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/ccfos/nightingale/v6/pkg/poster"
1212
"github.com/ccfos/nightingale/v6/pushgw/pconf"
1313

14+
"github.com/jinzhu/copier"
1415
"github.com/pkg/errors"
1516
"github.com/toolkits/pkg/logger"
1617
"github.com/toolkits/pkg/str"
@@ -1080,3 +1081,19 @@ func GetTargetsOfHostAlertRule(ctx *ctx.Context, engineName string) (map[string]
10801081

10811082
return m, nil
10821083
}
1084+
1085+
func (ar *AlertRule) Copy(ctx *ctx.Context) (*AlertRule, error) {
1086+
newAr := &AlertRule{}
1087+
err := copier.Copy(newAr, ar)
1088+
if err != nil {
1089+
logger.Errorf("copy alert rule failed, %v", err)
1090+
}
1091+
return newAr, err
1092+
}
1093+
1094+
func InsertAlertRule(ctx *ctx.Context, ars []*AlertRule) error {
1095+
if len(ars) == 0 {
1096+
return nil
1097+
}
1098+
return DB(ctx).Create(ars).Error
1099+
}

0 commit comments

Comments
 (0)