package service import ( "errors" "github.com/google/uuid" "github.com/jinzhu/copier" json "github.com/json-iterator/go" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/entity" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/request" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/response" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/client" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/constant" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/jsontime" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/resp" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/util" "xorm.io/xorm" ) type AlertRulesSvc struct { User entity.SystemUserInfo } func (a *AlertRulesSvc) Add(req request.AddAlertRules) (err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return err } now := jsontime.Now() data := entity.AlertRules{ Id: uuid.New().String(), CreatedBy: a.User.SystemAccount, CreatedAt: now, UpdatedBy: a.User.SystemAccount, UpdatedAt: now, } _ = copier.Copy(&data, &req) data.AlertCondition = util.ConvertToString(req.AlertCondition) data.AlertRange = util.ConvertToString(req.AlertRange) data.NotifyMethod = util.ConvertToString(req.NotifyMethod) data.NotifyRecipients = util.ConvertToString(req.NotifyRecipients) switch req.DetectionType { case 1: _, err = db.Insert(&data) if err != nil { return err } case 2: // 自定义 _, err = db.Transaction(func(session *xorm.Session) (interface{}, error) { // 添加自定义分类 var ( classParentId int classId int addMetricConfig request.AddMetricConfig metricConfigId string ) alertClassSvc := AlertClassSvc{User: a.User} classParentId, err = alertClassSvc.Add(session, request.AddAlertClass{ ClassName: req.ClassParentName, SortOrder: -1, Source: constant.SourceCustom, }) if err != nil { return nil, err } classId, err = alertClassSvc.Add(session, request.AddAlertClass{ ClassName: req.ClassName, ParentId: classParentId, SortOrder: -1, Source: constant.SourceCustom, }) if err != nil { return nil, err } data.ClassId = classId req.ClassId = classId // 添加指标配置 metricConfigSvc := MetricConfigSvc{User: a.User} _ = copier.Copy(&addMetricConfig, &req) addMetricConfig.Source = constant.SourceCustom addMetricConfig.MetricName = req.MetricConfigName addMetricConfig.ClassId = classId metricConfigId, err = metricConfigSvc.Add(session, addMetricConfig) if err != nil { return nil, err } data.MetricConfigId = metricConfigId // 添加预警规则配置 _, err = session.Insert(&data) if err != nil { return nil, err } return nil, err }) err = a.CreatePrometheusRule(req.IsEnabled, data.Id, db, "") if err != nil { return err } } err = a.CreatePrometheusRule(req.IsEnabled, data.Id, db, "") if err != nil { return err } return nil } func (a *AlertRulesSvc) Update(req request.UpdateAlertRules) (err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return err } now := jsontime.Now() data := entity.AlertRules{ UpdatedBy: a.User.SystemAccount, UpdatedAt: now, } _ = copier.Copy(&data, &req) data.AlertCondition = util.ConvertToString(req.AlertCondition) data.AlertRange = util.ConvertToString(req.AlertRange) data.NotifyMethod = util.ConvertToString(req.NotifyMethod) data.NotifyRecipients = util.ConvertToString(req.NotifyRecipients) session := db.NewSession() defer session.Close() var dbAlertRules entity.AlertRules _, err = session.Table(data.TableName()).ID(data.Id).Get(&dbAlertRules) if err != nil { return err } switch req.DetectionType { case 1: _, err = db.ID(data.Id).MustCols("duration").Update(&data) if err != nil { return err } err = a.CreatePrometheusRule(req.IsEnabled, data.Id, db, "update") if err != nil { return err } case 2: // 自定义 _, err = db.Transaction(func(session *xorm.Session) (interface{}, error) { // 更新自定义分类 var ( updateMetricConfig request.UpdateMetricConfig alertClass response.AlertClassItem alertParentClass response.AlertClassItem ) alertClassSvc := AlertClassSvc{User: a.User} alertClass, err = alertClassSvc.GetDataById(request.DetailAlertClass{ClassId: dbAlertRules.ClassId}) if err != nil { return nil, err } err = alertClassSvc.Update(session, request.UpdateAlertClass{ ClassId: dbAlertRules.ClassId, ClassName: req.ClassName, ParentId: alertClass.ParentId, }) if err != nil { return nil, err } if alertClass.ParentId == 0 { return nil, errors.New("预警分类为空") } alertParentClass, err = alertClassSvc.GetDataById(request.DetailAlertClass{ClassId: alertClass.ParentId}) if err != nil { return nil, err } err = alertClassSvc.Update(session, request.UpdateAlertClass{ ClassId: alertClass.ParentId, ClassName: req.ClassParentName, ParentId: alertParentClass.ParentId, }) if err != nil { return nil, err } // 更新指标配置 metricConfigSvc := MetricConfigSvc{User: a.User} _ = copier.Copy(&updateMetricConfig, &req) updateMetricConfig.Source = constant.SourceCustom updateMetricConfig.Id = dbAlertRules.MetricConfigId err = metricConfigSvc.Update(session, updateMetricConfig) if err != nil { return nil, err } return nil, err }) // 更新预警策略配置 _, err = session.ID(data.Id).MustCols("duration").Update(&data) err = a.CreatePrometheusRule(req.IsEnabled, data.Id, db, "update") if err != nil { return err } } err = a.CreatePrometheusRule(req.IsEnabled, data.Id, db, "update") return nil } func (a *AlertRulesSvc) CreatePrometheusRule(isEnabled int, id string, db *xorm.Engine, operate string) (err error) { if isEnabled == 1 { var item response.AlertRulesItem item, err = a.GetDataById(request.DetailAlertRules{Id: id}) // 查询完整数据 if err != nil { return } prSvc := PrometheusRuleSvc{User: a.User} _, exist, _ := prSvc.Get(item) if exist { deleteErr := prSvc.Delete(item) if operate == "update" { return deleteErr } if deleteErr != nil { _, err = db.ID(id).Delete(&entity.AlertRules{}) if err != nil { return } return deleteErr } } createErr := prSvc.Create(item) if createErr != nil { if operate == "update" { return createErr } _, err = db.ID(id).Delete(&entity.AlertRules{}) if err != nil { return } return createErr } } return } func (a *AlertRulesSvc) UpdateIsEnabled(req request.UpdateIsEnabledAlertRules) (err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return err } now := jsontime.Now() data := entity.AlertRules{ Id: req.Id, IsEnabled: req.IsEnabled, UpdatedBy: a.User.SystemAccount, UpdatedAt: now, } var item response.AlertRulesItem item, err = a.GetDataById(request.DetailAlertRules{Id: req.Id}) if err != nil { return } if req.IsEnabled == 2 { prSvc := PrometheusRuleSvc{User: a.User} var exist bool _, exist, err = prSvc.Get(item) if exist { err = prSvc.Delete(item) if err != nil { return } } } else if req.IsEnabled == 1 { prSvc := PrometheusRuleSvc{User: a.User} var exist bool _, exist, err = prSvc.Get(item) if !exist { err = prSvc.Create(item) if err != nil { return } } } session := db.NewSession() defer session.Close() _, err = session.Table(data.TableName()).Cols("is_enabled,updated_by,updated_at").Where("id = ?", req.Id).Update(&data) return err } func (a *AlertRulesSvc) GetDataById(req request.DetailAlertRules) (resp response.AlertRulesItem, err error) { list, err := a.List(request.ListAlertRules{Id: req.Id}) if err != nil { return } if len(list.List) >= 1 { resp = list.List[0] } return } func (a *AlertRulesSvc) List(req request.ListAlertRules) (resp response.AlertRulesList, err error) { db, err := client.GetDbClient() if err != nil { return } session := db.NewSession() defer session.Close() session.Table(new(entity.AlertRules)).Alias("r").Select("r.*,acp.class_name class_parent_name,ac.class_name,mc.expr,mc.metric_name metric_config_name,mc.alert_rule_type,dict.name alert_rule_type_name") session.Join("LEFT", "metric_config mc", "mc.id = r.metric_config_id") session.Join("LEFT", "alert_class ac", "ac.class_id = r.class_id") session.Join("LEFT", "alert_class acp", "acp.class_id = ac.parent_id") session.Join("LEFT", "dict", "dict.id = mc.alert_rule_type") if req.Id != "" { session.Where("r.id = ?", req.Id) } if req.NotifyMethod != "" && req.NotifyMethod != "all" { session.Where("r.notify_method LIKE ?", "%\""+req.NotifyMethod+"\"%") // ["dingtalk","sms"] } if req.IsEnabled > 0 { session.Where("r.is_enabled = ?", req.IsEnabled) } if req.StartTime != "" { session.Where("r.created_at >= ?", req.StartTime) } if req.EndTime != "" { session.Where("r.created_at <= ?", req.EndTime) } if req.Keyword != "" { // 预警对象/预警分类/预警指标 session.Where("r.metric_name LIKE ?", "%"+req.Keyword+"%"). Or("mc.metric_name LIKE ?", "%"+req.Keyword+"%"). Or("ac.class_name LIKE ?", "%"+req.Keyword+"%"). Or("acp.class_name LIKE ?", "%"+req.Keyword+"%") } resp.TotalCount, err = session.Limit(req.GetPageSize(), (req.GetPage()-1)*req.GetPageSize()). OrderBy("r.is_enabled asc,r.created_at desc"). FindAndCount(&resp.List) for i := 0; i < len(resp.List); i++ { _ = json.Unmarshal([]byte(resp.List[i].AlertRules.AlertCondition), &resp.List[i].AlertCondition) _ = json.Unmarshal([]byte(resp.List[i].AlertRules.AlertRange), &resp.List[i].AlertRange) _ = json.Unmarshal([]byte(resp.List[i].AlertRules.NotifyMethod), &resp.List[i].NotifyMethod) _ = json.Unmarshal([]byte(resp.List[i].AlertRules.NotifyRecipients), &resp.List[i].NotifyRecipients) } return } func (a *AlertRulesSvc) Delete(ids []string) (err error) { var exist bool db, err := client.GetDbClient() if err != nil { return } alertSvc := AlertSvc{User: a.User} for _, id := range ids { exist, err = alertSvc.IndexDocExist(request.ExistAlert{AlertRulesId: id}) if err != nil { return } if !exist { prSvc := PrometheusRuleSvc{User: a.User} var has bool _, has, err = prSvc.Get(response.AlertRulesItem{AlertRules: entity.AlertRules{Id: id}}) if has { err = prSvc.Delete(response.AlertRulesItem{AlertRules: entity.AlertRules{Id: id}}) if err != nil { return } } _, err = db.NewSession().Where("id = ?", id).Delete(new(entity.AlertRules)) } else { return errors.New("alert_rules_id already exists in opensearch") } } return }