package service import ( "context" "errors" "fmt" "github.com/jinzhu/copier" json "github.com/json-iterator/go" "github.com/opensearch-project/opensearch-go/opensearchapi" "github.com/thoas/go-funk" "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/common/conf" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/jsontime" "go.uber.org/zap" "io" "net/http" "strings" "xorm.io/xorm" ) type AlertListSvc struct { User entity.SystemUserInfo } var ( OpenSearchIndex = "so_alert" Mapping = strings.NewReader(`{ "settings": { "number_of_shards": 1, "number_of_replicas": 0, "index.max_result_window": "1000000" }, "mappings": { "properties": { "id": { "type": "integer" }, "alert_point": { "type": "keyword" }, "alert_rules_id": { "type": "keyword" }, "risk_level": { "type": "integer" }, "alert_time": { "type": "date", "ignore_malformed": true, "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" }, "class_id": { "type": "integer" }, "class_parent_name": { "type": "keyword" }, "class_name": { "type": "keyword" }, "metric_config_id": { "type": "keyword" }, "metric_config_name": { "type": "keyword" }, "alert_rule_type": { "type": "keyword" }, "alert_rule_type_name": { "type": "keyword" }, "current_value": { "type": "integer" }, "notification_count": { "type": "integer" }, "push_count": { "type": "integer" }, "last_push_time": { "type": "date", "ignore_malformed": true, "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" }, "status": { "type": "integer" }, "disposed_list": { "type": "nested", "properties": { "is_disposed": { "type": "integer" }, "disposal_content": { "type": "keyword" }, "disposal_user": { "type": "keyword" }, "disposal_time": { "type": "date", "ignore_malformed": true, "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } }, "is_disposed": { "type": "integer" }, "close_remark": { "type": "keyword" }, "close_user": { "type": "keyword" }, "close_time": { "type": "date", "ignore_malformed": true, "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" }, "defer_push": { "type": "integer" }, "created_by": { "type": "keyword" }, "created_at": { "type": "date", "ignore_malformed": true, "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" }, "updated_by": { "type": "keyword" }, "updated_at": { "type": "date", "ignore_malformed": true, "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" }, "alert_condition": { "properties": { "thresholds_min": { "type": "integer" }, "thresholds_max": { "type": "integer" }, "risk_level": { "type": "integer" } } } } } }`) ) func (a *AlertListSvc) CreateIndex() error { cli, err := client.GetOpenSearch() if err != nil { return err } res := opensearchapi.IndicesCreateRequest{ Index: OpenSearchIndex, Body: Mapping, } do, err := res.Do(context.Background(), cli) if err != nil { return err } defer do.Body.Close() if do.StatusCode != http.StatusOK { return errors.New(do.String()) } return nil } func (a *AlertListSvc) DeleteIndex() error { cli, err := client.GetOpenSearch() if err != nil { return err } res := opensearchapi.IndicesDeleteRequest{ Index: []string{OpenSearchIndex}, } do, err := res.Do(context.Background(), cli) if err != nil { return err } defer do.Body.Close() if do.StatusCode != http.StatusOK { return errors.New(do.String()) } return nil } func (a *AlertListSvc) Indices() (indices []string, err error) { var ( catIndicesList []response.CatIndices ) cli, err := client.GetOpenSearch() if err != nil { return } res := opensearchapi.CatIndicesRequest{Format: "json"} do, err := res.Do(context.Background(), cli) if err != nil { return } defer do.Body.Close() if do.StatusCode != http.StatusOK { err = errors.New(do.String()) return } body, err := io.ReadAll(do.Body) if err != nil { return } err = json.Unmarshal(body, &catIndicesList) if err != nil { return } funkGet := funk.Get(catIndicesList, "Index") //取一层 indices, ok := funkGet.([]string) if !ok { err = errors.New("funk.Get failed") return } return } func (a *AlertListSvc) IndexSearch(req request.ListAlertList) (resp response.AlertListList, err error) { var ( sources response.OpenSearchSource ) cli, err := client.GetOpenSearch() if err != nil { return } content := strings.NewReader(fmt.Sprintf(`{ "query": { "match_all": {} }, "from": %d, "size": %d }`, req.GetPageSize()*(req.GetPage()-1), req.GetPageSize())) res := opensearchapi.SearchRequest{ Index: []string{OpenSearchIndex}, Body: content, } do, err := res.Do(context.Background(), cli) if err != nil { return } defer do.Body.Close() if do.StatusCode != http.StatusOK { err = errors.New(do.String()) return } body, err := io.ReadAll(do.Body) if err != nil { return } err = json.Unmarshal(body, &sources) if err != nil { return } for _, hit := range sources.Hits.Hits { resp.List = append(resp.List, hit.Source) } return } func (a *AlertListSvc) Update(session *xorm.Session, req request.UpdateAlertList) error { now := jsontime.Now() data := entity.AlertList{ UpdatedBy: a.User.SystemAccount, UpdatedAt: now, } _ = copier.Copy(&data, &req) _, err := session.Cols("class_name", "updated_by", "updated_at").ID(data.ClassId).Update(&data) if err != nil { return err } return nil } func (a *AlertListSvc) BatchPushAlertList(session *xorm.Session, req request.BatchPushAlertList) error { now := jsontime.Now() _ = now // TODO 批量推送用户告警 conf.Logger.Info("batch push", zap.Any("payload", req)) return nil } func (a *AlertListSvc) BatchCloseAlertList(session *xorm.Session, req request.BatchCloseAlertList) error { now := jsontime.Now() _ = now // TODO 批量推送用户告警 conf.Logger.Info("batch close", zap.Any("payload", req)) return nil } func (a *AlertListSvc) GetDataById(req request.DetailAlertList) (resp response.AlertListItem, err error) { now := jsontime.Now() data := response.AlertListItem{ AlertList: entity.AlertList{ Id: 123, AlertPoint: "容器云/kube-apiserver", AlertRulesId: "762ed641-6c0e-4c39-bf7c-7463abb0f8a2", RiskLevel: 4, AlertTime: now, ClassId: 14, ClassParentName: "预警分类", ClassName: "预警对象", MetricConfigId: "d773b37b-dbb4-4a7b-be11-ab40f8acc00e", MetricConfigName: "CPU负载过高", AlertRuleType: "51a2cc1e-eb24-4b16-b106-3dc9db963a49", AlertRuleTypeName: "%", CurrentValue: 85, AlertCondition: "", NotificationCount: 3, PushCount: 3, LastPushTime: now, Status: 2, DisposedList: []entity.DisposedList{ { IsDisposed: 1, DisposalContent: "处置记录", DisposalUser: "xiaowang", DisposalTime: now, }, }, IsDisposed: 2, CloseRemark: "", CloseUser: "", DeferPush: 0, CreatedBy: "admin", CreatedAt: now, UpdatedBy: "admin", UpdatedAt: now, }, AlertCondition: entity.AlertCondition{ ThresholdsMax: 100, ThresholdsMin: 80, RiskLevel: 4, }, PushRecords: []response.PushRecordItem{ { PushRecord: entity.PushRecord{ Id: 1, AlertId: 1, AlertRulesId: "47f7a57f-7a67-4876-8c89-ea074d040858", RiskLevel: 1, SystemAccount: "xiaowang", PushTime: now, PushType: 1, Status: 1, CreatedBy: "admin", CreatedAt: now, UpdatedBy: "admin", UpdatedAt: now, }, NotifyMethod: []string{"dingtalk", "sms"}, }, { PushRecord: entity.PushRecord{ Id: 2, AlertId: 3, AlertRulesId: "47f7a57f-7a67-4876-8c89-ea074d040858", RiskLevel: 2, SystemAccount: "xiaowang", PushTime: now, PushType: 2, Status: 2, CreatedBy: "admin", CreatedAt: now, UpdatedBy: "admin", UpdatedAt: now, }, NotifyMethod: []string{"dingtalk", "sms"}, }, }, } resp = data return } func (a *AlertListSvc) List(req request.ListAlertList) (resp response.AlertListList, err error) { /*now := jsontime.Now() data1 := response.AlertListItem{ AlertList: entity.AlertList{ Id: 123, AlertPoint: "容器云/kube-apiserver", AlertRulesId: "762ed641-6c0e-4c39-bf7c-7463abb0f8a2", RiskLevel: 4, AlertTime: now, ClassId: 14, ClassParentName: "预警分类", ClassName: "预警对象", MetricConfigId: "d773b37b-dbb4-4a7b-be11-ab40f8acc00e", MetricConfigName: "磁盘空间不足", AlertRuleType: "51a2cc1e-eb24-4b16-b106-3dc9db963a49", AlertRuleTypeName: "%", CurrentValue: 85, AlertCondition: "", NotificationCount: 3, PushCount: 3, LastPushTime: now, Status: 1, DisposedList: []entity.DisposedList{ { IsDisposed: 2, DisposalContent: "未恢复处置", DisposalUser: "xiaozhang", DisposalTime: now, }, { IsDisposed: 1, DisposalContent: "已恢复处置", DisposalUser: "lisi", DisposalTime: now, }, }, IsDisposed: 2, CloseRemark: "", CloseUser: "", DeferPush: 0, CreatedBy: "admin", CreatedAt: now, UpdatedBy: "admin", UpdatedAt: now, }, AlertCondition: entity.AlertCondition{ ThresholdsMax: 100, ThresholdsMin: 80, RiskLevel: 4, }, PushRecords: []response.PushRecordItem{ { PushRecord: entity.PushRecord{ Id: 1, AlertId: 1, AlertRulesId: "47f7a57f-7a67-4876-8c89-ea074d040858", RiskLevel: 1, SystemAccount: "xiaozhang", PushTime: now, PushType: 1, Status: 1, CreatedBy: "admin", CreatedAt: now, UpdatedBy: "admin", UpdatedAt: now, }, NotifyMethod: []string{"dingtalk", "sms"}, }, { PushRecord: entity.PushRecord{ Id: 2, AlertId: 3, AlertRulesId: "47f7a57f-7a67-4876-8c89-ea074d040858", RiskLevel: 2, SystemAccount: "xiaowang", PushTime: now, PushType: 2, Status: 2, CreatedBy: "admin", CreatedAt: now, UpdatedBy: "admin", UpdatedAt: now, }, NotifyMethod: []string{"dingtalk", "sms"}, }, }, } data2 := response.AlertListItem{ AlertList: entity.AlertList{ Id: 125, AlertPoint: "容器云/apaas", AlertRulesId: "762ed641-6c0e-4c39-bf7c-7463abb0f8a2", RiskLevel: 3, AlertTime: now, ClassId: 14, ClassParentName: "预警分类", ClassName: "预警对象", MetricConfigId: "d773b37b-dbb4-4a7b-be11-ab40f8acc00e", MetricConfigName: "响应时间超时", AlertRuleType: "51a2cc1e-eb24-4b16-b106-3dc9db963a49", AlertRuleTypeName: "%", CurrentValue: 85, AlertCondition: "", NotificationCount: 1, PushCount: 1, LastPushTime: now, Status: 3, DisposedList: []entity.DisposedList{ { IsDisposed: 1, DisposalContent: "已做处置", DisposalUser: "xiaowang", DisposalTime: now, }, }, IsDisposed: 1, CloseRemark: "关闭备注", CloseUser: "xiaowang", CloseTime: now, DeferPush: 1, CreatedBy: "admin", CreatedAt: now, UpdatedBy: "admin", UpdatedAt: now, }, AlertCondition: entity.AlertCondition{ ThresholdsMax: 80, ThresholdsMin: 50, RiskLevel: 3, }, PushRecords: []response.PushRecordItem{ { PushRecord: entity.PushRecord{ Id: 1, AlertId: 1, AlertRulesId: "47f7a57f-7a67-4876-8c89-ea074d040858", RiskLevel: 1, SystemAccount: "xiaozhang", PushTime: now, PushType: 1, Status: 1, CreatedBy: "admin", CreatedAt: now, UpdatedBy: "admin", UpdatedAt: now, }, NotifyMethod: []string{"dingtalk", "sms"}, }, { PushRecord: entity.PushRecord{ Id: 2, AlertId: 3, AlertRulesId: "47f7a57f-7a67-4876-8c89-ea074d040858", RiskLevel: 2, SystemAccount: "xiaowang", PushTime: now, PushType: 2, Status: 2, CreatedBy: "admin", CreatedAt: now, UpdatedBy: "admin", UpdatedAt: now, }, NotifyMethod: []string{"dingtalk", "sms"}, }, }, } resp.List = append(resp.List, data1, data2) resp.TotalCount = int64(len(resp.List))*/ resp, err = a.IndexSearch(req) resp.TotalCount = int64(len(resp.List)) return } func (a *AlertListSvc) DisposeAlertList(session *xorm.Session, req request.DisposeAlertList) error { now := jsontime.Now() _ = now // TODO 我的预警工单处置 conf.Logger.Info("dispose alert", zap.Any("payload", req)) return nil }