diff --git a/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@cn/DEFAULT b/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@cn/DEFAULT index 0d444f4ac4..df4b0d3d6e 100644 --- a/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@cn/DEFAULT +++ b/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@cn/DEFAULT @@ -6,4 +6,4 @@ 资源数量:{{len .matches}} 资源名称:{{.resource_name}} -详情地址: {{.web_url}}/commonalerts \ No newline at end of file +详情地址: {{.web_url}} \ No newline at end of file diff --git a/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@cn/DEFAULT.email b/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@cn/DEFAULT.email index 5042b578c9..35127eeb08 100644 --- a/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@cn/DEFAULT.email +++ b/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@cn/DEFAULT.email @@ -92,7 +92,7 @@ -
若要查看详情信息,若要查看详情信息,请登录平台进行查看
diff --git a/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@en/DEFAULT b/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@en/DEFAULT index 0cfd74b27b..723fd671e2 100644 --- a/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@en/DEFAULT +++ b/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@en/DEFAULT @@ -6,4 +6,4 @@ TriggerCondition: {{.description | unescaped}} ResourceCount: {{len .matches}} ResourceName: {{.resource_name}} -WebUrl: {{.web_url}}/commonalerts +WebUrl: {{.web_url}} diff --git a/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@en/DEFAULT.email b/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@en/DEFAULT.email index 173666faa0..2906601ab9 100644 --- a/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@en/DEFAULT.email +++ b/build/monitor/root/opt/yunion/share/notify_templates/monitor/content@en/DEFAULT.email @@ -33,7 +33,7 @@ font-weight: bold; } .td { - width: 80px; + width: 120px; padding-left: 20px; height: 35px; font-weight: 400; @@ -92,8 +92,8 @@ - +
To view details,Please log in to the platform to viewTo view details,Please login to the platform to view
diff --git a/pkg/monitor/alerting/eval_context.go b/pkg/monitor/alerting/eval_context.go index 071e15ae72..68e841da14 100644 --- a/pkg/monitor/alerting/eval_context.go +++ b/pkg/monitor/alerting/eval_context.go @@ -128,7 +128,7 @@ func (c *EvalContext) GetCallbackURLPrefix() string { return "" } url, _ := config.GetString("config", "default", "api_server") - return url + return url + "/alertrecord" } // GetNewState returns the new state from the alert rule evaluation. @@ -207,7 +207,11 @@ func (c *EvalContext) GetNotificationTemplateConfig() monitor.NotificationTempla func (c *EvalContext) GetEvalMatches() []monitor.EvalMatch { ret := make([]monitor.EvalMatch, 0) - for _, c := range c.EvalMatches { + matches := c.EvalMatches + if !c.Firing { + matches = c.AlertOkEvalMatches + } + for _, c := range matches { ret = append(ret, monitor.EvalMatch{ Condition: c.Condition, Value: c.Value, diff --git a/pkg/monitor/alerting/notifier.go b/pkg/monitor/alerting/notifier.go index ad21f4b431..6bfd0ba80a 100644 --- a/pkg/monitor/alerting/notifier.go +++ b/pkg/monitor/alerting/notifier.go @@ -170,10 +170,23 @@ func (n *notificationService) createAlertRecordWhenNotify(evalCtx *EvalContext) } recordCreateInput.ResType = recordCreateInput.AlertRule.ResType createData := recordCreateInput.JSON(recordCreateInput) - record, err := db.DoCreate(models.AlertRecordManager, evalCtx.Ctx, evalCtx.UserCred, jsonutils.NewDict(), createData, evalCtx.UserCred) + alert, _ := models.CommonAlertManager.GetAlert(evalCtx.Rule.Id) + log.Errorf("alert:%v", jsonutils.Marshal(alert)) + record, err := db.DoCreate(models.AlertRecordManager, evalCtx.Ctx, evalCtx.UserCred, jsonutils.NewDict(), + createData, evalCtx.UserCred) if err != nil { log.Errorf("create alert record err:%v", err) } + alertData := jsonutils.Marshal(alert) + alertData.(*jsonutils.JSONDict).Set("project_id", jsonutils.NewString(alert.GetProjectId())) + db.PerformSetScope(evalCtx.Ctx, record.(*models.SAlertRecord), evalCtx.UserCred, alertData) + dbMatches, _ := record.(*models.SAlertRecord).GetEvalData() + if !evalCtx.Firing { + evalCtx.AlertOkEvalMatches = make([]*monitor.EvalMatch, len(dbMatches)) + for i, _ := range dbMatches { + evalCtx.AlertOkEvalMatches[i] = &dbMatches[i] + } + } record.PostCreate(evalCtx.Ctx, evalCtx.UserCred, evalCtx.UserCred, nil, createData) } diff --git a/pkg/monitor/alerting/notifiers/onecloud.go b/pkg/monitor/alerting/notifiers/onecloud.go index 7e84b83198..bda0765e1a 100644 --- a/pkg/monitor/alerting/notifiers/onecloud.go +++ b/pkg/monitor/alerting/notifiers/onecloud.go @@ -17,7 +17,9 @@ package notifiers import ( "context" "fmt" + "strings" + "golang.org/x/sync/errgroup" "golang.org/x/text/language" "yunion.io/x/jsonutils" @@ -32,6 +34,7 @@ import ( "yunion.io/x/onecloud/pkg/i18n" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" + "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/mcclient/modules/notify" "yunion.io/x/onecloud/pkg/monitor/alerting" "yunion.io/x/onecloud/pkg/monitor/alerting/notifiers/templates" @@ -39,7 +42,18 @@ import ( "yunion.io/x/onecloud/pkg/monitor/options" ) +const ( + SUFFIX = "onecloudNotifier" +) + +var ( + i18nTable = i18n.Table{} + i18nEnTry = i18n.NewTableEntry().EN("en").CN("cn") +) + func init() { + i18nTable.Set(SUFFIX, i18nEnTry) + alerting.RegisterNotifier(&alerting.NotifierPlugin{ Type: monitor.AlertNotificationTypeOneCloud, Factory: newOneCloudNotifier, @@ -153,16 +167,42 @@ func GetNotifyTemplateConfigOfEN(ctx *alerting.EvalContext) monitor.Notification // Notify sends the alert notification. func (oc *OneCloudNotifier) Notify(ctx *alerting.EvalContext, _ jsonutils.JSONObject) error { log.Infof("Sending alert notification %s to onecloud", ctx.GetRuleTitle()) - oc.Ctx = i18n.WithLangTag(oc.Ctx, language.Chinese) + langIdsMap, err := GetUserLangIdsMap(oc.Setting.UserIds) + if err != nil { + return errors.Wrapf(err, "OneCloudNotifier getIds:%s userLang err", oc.Setting.UserIds) + } + langNotifyGroup, _ := errgroup.WithContext(ctx.Ctx) + for lang, _ := range langIdsMap { + ids := langIdsMap[lang] + langTag, _ := language.Parse(lang) + langStr := i18nTable.LookupByLang(langTag, SUFFIX) + langContext := i18n.WithLangTag(context.Background(), getLangBystr(langStr)) + langNotifyGroup.Go(func() error { + return oc.notifyByContextLang(langContext, ctx, ids) + }) + } + return langNotifyGroup.Wait() +} + +func getLangBystr(str string) language.Tag { + for lang, val := range i18nEnTry { + if val == str { + return lang + } + } + return language.English +} + +func (oc *OneCloudNotifier) notifyByContextLang(ctx context.Context, evalCtx *alerting.EvalContext, uids []string) error { var config monitor.NotificationTemplateConfig - lang := i18n.Lang(oc.Ctx) + lang := i18n.Lang(ctx) switch lang { case language.English: - config = GetNotifyTemplateConfigOfEN(ctx) + config = GetNotifyTemplateConfigOfEN(evalCtx) default: - config = GetNotifyTemplateConfig(ctx) + config = GetNotifyTemplateConfig(evalCtx) } - oc.filterMatchTagsForConfig(&config) + oc.filterMatchTagsForConfig(&config, ctx) contentConfig := oc.buildContent(config) @@ -179,7 +219,7 @@ func (oc *OneCloudNotifier) Notify(ctx *alerting.EvalContext, _ jsonutils.JSONOb } msg := notify.SNotifyMessage{ - Uid: oc.Setting.UserIds, + Uid: uids, ContactType: notify.TNotifyChannel(oc.Setting.Channel), Topic: config.Title, Priority: notify.TNotifyPriority(config.Priority), @@ -192,12 +232,36 @@ func (oc *OneCloudNotifier) Notify(ctx *alerting.EvalContext, _ jsonutils.JSONOb return sendImp.send() } +func GetUserLangIdsMap(ids []string) (map[string][]string, error) { + session := auth.GetAdminSession(context.Background(), "", "") + langIdsMap := make(map[string][]string) + params := jsonutils.NewDict() + params.Set("filter", jsonutils.NewString(fmt.Sprintf("id.in(%s)", strings.Join(ids, ",")))) + params.Set("details", jsonutils.JSONFalse) + params.Set("scope", jsonutils.NewString("system")) + params.Set("system", jsonutils.JSONTrue) + ret, err := modules.UsersV3.List(session, params) + if err != nil { + return nil, err + } + for i := range ret.Data { + id, _ := ret.Data[i].GetString("id") + langStr, _ := ret.Data[i].GetString("lang") + if _, ok := langIdsMap[langStr]; ok { + langIdsMap[langStr] = append(langIdsMap[langStr], id) + continue + } + langIdsMap[langStr] = []string{id} + } + return langIdsMap, nil +} + var ( companyInfo models.SCompanyInfo ) -func (oc *OneCloudNotifier) filterMatchTagsForConfig(config *monitor.NotificationTemplateConfig) { - sCompanyInfo, err := models.GetCompanyInfo(oc.Ctx) +func (oc *OneCloudNotifier) filterMatchTagsForConfig(config *monitor.NotificationTemplateConfig, ctx context.Context) { + sCompanyInfo, err := models.GetCompanyInfo(ctx) if err != nil { log.Errorf("GetCompanyInfo error:%#v", err) return diff --git a/pkg/monitor/models/alertrecord.go b/pkg/monitor/models/alertrecord.go index c84a3d63da..8401235802 100644 --- a/pkg/monitor/models/alertrecord.go +++ b/pkg/monitor/models/alertrecord.go @@ -9,7 +9,6 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/timeutils" - "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/apis/monitor" @@ -108,45 +107,6 @@ func (manager *SAlertRecordManager) ListItemFilter( return q, nil } -func (man *SAlertRecordManager) CustomizeFilterList( - ctx context.Context, q *sqlchemy.SQuery, - userCred mcclient.TokenCredential, query jsonutils.JSONObject) ( - *db.CustomizeListFilters, error) { - filters := db.NewCustomizeListFilters() - input := new(monitor.AlertRecordListInput) - if err := query.Unmarshal(input); err != nil { - return nil, err - } - wrapF := func(f func(obj *SAlertRecord) (bool, error)) func(object jsonutils.JSONObject) (bool, error) { - return func(data jsonutils.JSONObject) (bool, error) { - id, err := data.GetString("id") - if err != nil { - return false, err - } - obj, err := man.GetAlertRecord(id) - if err != nil { - return false, err - } - return f(obj) - } - } - - if len(input.ResType) != 0 { - mF := func(obj *SAlertRecord) (bool, error) { - rule := new(monitor.AlertRecordRule) - if err := obj.AlertRule.Unmarshal(rule); err != nil { - return false, errors.Wrapf(err, "alert %s unmarshal", obj.GetId()) - } - if ok, _ := utils.InStringArray(rule.ResType, input.ResType); ok { - return true, nil - } - return false, nil - } - filters.Append(wrapF(mF)) - } - return filters, nil -} - func (man *SAlertRecordManager) GetAlertRecord(id string) (*SAlertRecord, error) { obj, err := man.FetchById(id) if err != nil { @@ -251,6 +211,10 @@ func (record *SAlertRecord) CustomizeCreate( query jsonutils.JSONObject, data jsonutils.JSONObject, ) error { + err := record.SMonitorScopedResource.CustomizeCreate(ctx, userCred, ownerId, query, data) + if err != nil { + return err + } obj, err := db.NewModelObject(AlertRecordManager) if err != nil { return errors.Wrapf(err, "NewModelObject %s", AlertRecordManager.Keyword()) diff --git a/pkg/monitor/models/commonalert.go b/pkg/monitor/models/commonalert.go index d0a562aa3c..cad792c1a3 100644 --- a/pkg/monitor/models/commonalert.go +++ b/pkg/monitor/models/commonalert.go @@ -7,6 +7,8 @@ import ( "strings" "time" + "golang.org/x/text/language" + "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -20,6 +22,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/hostman/hostinfo/hostconsts" "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/i18n" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules" @@ -36,7 +39,7 @@ const ( CommonAlertMetadataPointStr = "point_str" CommonAlertMetadataName = "meta_name" - COMPANY_COPYRIGHT_ONECLOUD = "北京云联万维技术有限公司" + COMPANY_COPYRIGHT_ONECLOUD = "云联" BRAND_ONECLOUD_NAME_CN = "云联壹云" BRAND_ONECLOUD_NAME_EN = "YunionCloud" ) @@ -1101,13 +1104,13 @@ func GetCompanyInfo(ctx context.Context) (SCompanyInfo, error) { return SCompanyInfo{}, err } if strings.Contains(info.Copyright, COMPANY_COPYRIGHT_ONECLOUD) { - //lang := i18n.Lang(ctx) - //switch lang { - //case language.English: - // info.Name = BRAND_ONECLOUD_NAME_EN - //default: - //} - info.Name = BRAND_ONECLOUD_NAME_CN + lang := i18n.Lang(ctx) + switch lang { + case language.English: + info.Name = BRAND_ONECLOUD_NAME_EN + default: + info.Name = BRAND_ONECLOUD_NAME_CN + } } return info, nil } diff --git a/pkg/monitor/models/query_signature.go b/pkg/monitor/models/query_signature.go index de4326db7b..d0de13a495 100644 --- a/pkg/monitor/models/query_signature.go +++ b/pkg/monitor/models/query_signature.go @@ -32,6 +32,7 @@ func ValidateQuerySignature(input jsonutils.JSONObject) error { return errors.Wrap(err, "get signature") } if signature != digestQuerySignature(data) { + return httperrors.NewBadRequestError("signature error") } return nil diff --git a/pkg/monitor/models/unifiedmonitor.go b/pkg/monitor/models/unifiedmonitor.go index a78d31167f..431513ac22 100644 --- a/pkg/monitor/models/unifiedmonitor.go +++ b/pkg/monitor/models/unifiedmonitor.go @@ -190,7 +190,9 @@ func (self *SUnifiedMonitorManager) AllowPerformQuery(ctx context.Context, userC } func (self *SUnifiedMonitorManager) PerformQuery(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if err := ValidateQuerySignature(data); err != nil { + tmp := jsonutils.DeepCopy(data) + self.handleDataPreSignature(tmp) + if err := ValidateQuerySignature(tmp); err != nil { return nil, errors.Wrap(err, "ValidateQuerySignature") } inputQuery := new(monitor.MetricInputQuery) @@ -233,6 +235,25 @@ func (self *SUnifiedMonitorManager) PerformQuery(ctx context.Context, userCred m return jsonutils.Marshal(rtn), nil } +func (self *SUnifiedMonitorManager) handleDataPreSignature(data jsonutils.JSONObject) { + scope, _ := data.GetString("scope") + switch scope { + case "system": + case "domain": + domain, err := data.GetString("project_domain") + if err == nil { + data.(*jsonutils.JSONDict).Remove("project_domain") + data.(*jsonutils.JSONDict).Set("domain_id", jsonutils.NewString(domain)) + } + default: + project, err := data.GetString("project") + if err == nil { + data.(*jsonutils.JSONDict).Remove("project") + data.(*jsonutils.JSONDict).Set("project_id", jsonutils.NewString(project)) + } + } +} + func doQuery(query monitor.MetricInputQuery) (*mq.Metrics, error) { conditions := make([]*monitor.AlertCondition, 0) for _, q := range query.MetricQuery {