diff --git a/src/models/alert_rule.go b/src/models/alert_rule.go index 1fc9ed63..71a30cf5 100644 --- a/src/models/alert_rule.go +++ b/src/models/alert_rule.go @@ -16,7 +16,7 @@ import ( type AlertRule struct { Id int64 `json:"id" gorm:"primaryKey"` GroupId int64 `json:"group_id"` // busi group id - Cluster string `json:"cluster"` // take effect by cluster + Cluster string `json:"cluster"` // take effect by clusters, seperated by space Name string `json:"name"` // rule name Note string `json:"note"` // will sent in notify Prod string `json:"prod"` // product empty means n9e @@ -124,7 +124,7 @@ func (ar *AlertRule) Add() error { return err } - exists, err := AlertRuleExists("group_id=? and cluster=? and name=?", ar.GroupId, ar.Cluster, ar.Name) + exists, err := AlertRuleExists(0, ar.GroupId, ar.Cluster, ar.Name) if err != nil { return err } @@ -142,7 +142,7 @@ func (ar *AlertRule) Add() error { func (ar *AlertRule) Update(arf AlertRule) error { if ar.Name != arf.Name { - exists, err := AlertRuleExists("group_id=? and cluster=? and name=? and id <> ?", ar.GroupId, ar.Cluster, arf.Name, ar.Id) + exists, err := AlertRuleExists(ar.Id, ar.GroupId, ar.Cluster, arf.Name) if err != nil { return err } @@ -262,8 +262,25 @@ func AlertRuleDels(ids []int64, bgid ...int64) error { return nil } -func AlertRuleExists(where string, args ...interface{}) (bool, error) { - return Exists(DB().Model(&AlertRule{}).Where(where, args...)) +func AlertRuleExists(id, groupId int64, cluster, name string) (bool, error) { + session := DB().Where("id <> ? and group_id = ? and name = ?", id, groupId, name) + + var lst []AlertRule + err := session.Find(&lst).Error + if err != nil { + return false, err + } + if len(lst) == 0 { + return false, nil + } + + // match cluster + for _, r := range lst { + if MatchCluster(r.Cluster, cluster) { + return true, nil + } + } + return false, nil } func AlertRuleGets(groupId int64) ([]AlertRule, error) { @@ -284,18 +301,35 @@ func AlertRuleGetsByCluster(cluster string) ([]*AlertRule, error) { session := DB().Where("disabled = ? and prod = ?", 0, "") if cluster != "" { - session = session.Where("cluster = ?", cluster) + session = session.Where("(cluster like ? or cluster like ?)", "%"+cluster+"%", "%"+ClusterAll+"%") } var lst []*AlertRule err := session.Find(&lst).Error - if err == nil { + if err != nil { + return lst, err + } + + if len(lst) == 0 { + return lst, nil + } + + if cluster == "" { for i := 0; i < len(lst); i++ { lst[i].DB2FE() } + return lst, nil } - return lst, err + lr := make([]*AlertRule, 0, len(lst)) + for _, r := range lst { + if MatchCluster(r.Cluster, cluster) { + r.DB2FE() + lr = append(lr, r) + } + } + + return lr, err } func AlertRulesGetsBy(prods []string, query string) ([]*AlertRule, error) { @@ -358,7 +392,8 @@ func AlertRuleStatistics(cluster string) (*Statistics, error) { session := DB().Model(&AlertRule{}).Select("count(*) as total", "max(update_at) as last_updated").Where("disabled = ? and prod = ?", 0, "") if cluster != "" { - session = session.Where("cluster = ?", cluster) + // 简略的判断,当一个clustername是另一个clustername的substring的时候,会出现stats与预期不符,不影响使用 + session = session.Where("(cluster like ? or cluster like ?)", "%"+cluster+"%", "%"+ClusterAll+"%") } var stats []*Statistics diff --git a/src/models/common.go b/src/models/common.go index faee06c3..7014ce35 100644 --- a/src/models/common.go +++ b/src/models/common.go @@ -1,6 +1,8 @@ package models import ( + "strings" + "github.com/toolkits/pkg/str" "gorm.io/gorm" @@ -9,6 +11,9 @@ import ( const AdminRole = "Admin" +// if rule's cluster field contains `ClusterAll`, means it take effect in all clusters +const ClusterAll = "$all" + func DB() *gorm.DB { return storage.DB } @@ -42,3 +47,16 @@ type Statistics struct { Total int64 `gorm:"total"` LastUpdated int64 `gorm:"last_updated"` } + +func MatchCluster(ruleCluster, targetCluster string) bool { + if targetCluster == ClusterAll { + return true + } + clusters := strings.Fields(ruleCluster) + for _, c := range clusters { + if c == ClusterAll || c == targetCluster { + return true + } + } + return false +} diff --git a/src/models/recording_rule.go b/src/models/recording_rule.go index d309fd10..07c5ee56 100644 --- a/src/models/recording_rule.go +++ b/src/models/recording_rule.go @@ -13,7 +13,7 @@ import ( type RecordingRule struct { Id int64 `json:"id" gorm:"primaryKey"` GroupId int64 `json:"group_id"` // busi group id - Cluster string `json:"cluster"` // take effect by cluster + Cluster string `json:"cluster"` // take effect by cluster, seperated by space Name string `json:"name"` // new metric name Note string `json:"note"` // note Disabled int `json:"disabled"` // 0: enabled, 1: disabled @@ -40,6 +40,7 @@ func (re *RecordingRule) DB2FE() { //re.ClusterJSON = strings.Fields(re.Cluster) re.AppendTagsJSON = strings.Fields(re.AppendTags) } + func (re *RecordingRule) Verify() error { if re.GroupId < 0 { return fmt.Errorf("GroupId(%d) invalid", re.GroupId) @@ -78,7 +79,7 @@ func (re *RecordingRule) Add() error { return err } - exists, err := RecordingRuleExists("group_id=? and cluster=? and name=?", re.GroupId, re.Cluster, re.Name) + exists, err := RecordingRuleExists(0, re.GroupId, re.Cluster, re.Name) if err != nil { return err } @@ -96,7 +97,7 @@ func (re *RecordingRule) Add() error { func (re *RecordingRule) Update(ref RecordingRule) error { if re.Name != ref.Name { - exists, err := RecordingRuleExists("group_id=? and cluster=? and name=? and id <> ?", re.GroupId, re.Cluster, ref.Name, re.Id) + exists, err := RecordingRuleExists(re.Id, re.GroupId, re.Cluster, ref.Name) if err != nil { return err } @@ -133,9 +134,27 @@ func RecordingRuleDels(ids []int64, groupId int64) error { return nil } -func RecordingRuleExists(where string, regs ...interface{}) (bool, error) { - return Exists(DB().Model(&RecordingRule{}).Where(where, regs...)) +func RecordingRuleExists(id, groupId int64, cluster, name string) (bool, error) { + session := DB().Where("id <> ? and group_id = ? and name =? ", id, groupId, name) + + var lst []RecordingRule + err := session.Find(&lst).Error + if err != nil { + return false, err + } + if len(lst) == 0 { + return false, nil + } + + // match cluster + for _, r := range lst { + if MatchCluster(r.Cluster, cluster) { + return true, nil + } + } + return false, nil } + func RecordingRuleGets(groupId int64) ([]RecordingRule, error) { session := DB().Where("group_id=?", groupId).Order("name") @@ -171,26 +190,45 @@ func RecordingRuleGetById(id int64) (*RecordingRule, error) { } func RecordingRuleGetsByCluster(cluster string) ([]*RecordingRule, error) { - session := DB() + session := DB().Where("disabled = ? and prod = ?", 0, "") + if cluster != "" { - session = session.Where("cluster = ?", cluster) + session = session.Where("(cluster like ? or cluster like ?)", "%"+cluster+"%", "%"+ClusterAll+"%") } var lst []*RecordingRule err := session.Find(&lst).Error - if err == nil { + if err != nil { + return lst, err + } + + if len(lst) == 0 { + return lst, nil + } + + if cluster == "" { for i := 0; i < len(lst); i++ { lst[i].DB2FE() } + return lst, nil } - return lst, err + lr := make([]*RecordingRule, 0, len(lst)) + for _, r := range lst { + if MatchCluster(r.Cluster, cluster) { + r.DB2FE() + lr = append(lr, r) + } + } + + return lr, err } func RecordingRuleStatistics(cluster string) (*Statistics, error) { session := DB().Model(&RecordingRule{}).Select("count(*) as total", "max(update_at) as last_updated") if cluster != "" { - session = session.Where("cluster = ?", cluster) + // 简略的判断,当一个clustername是另一个clustername的substring的时候,会出现stats与预期不符,不影响使用 + session = session.Where("(cluster like ? or cluster like ?)", "%"+cluster+"%", "%"+ClusterAll+"%") } var stats []*Statistics