From 1b54766c9cfd62aba107bfc8f4407e301e04e906 Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Tue, 3 Mar 2020 16:13:11 +0800 Subject: [PATCH] alert notification use joint model --- cmd/climc/shell/monitor/alert.go | 14 ++ cmd/climc/shell/monitor/notification.go | 23 ++- pkg/apis/monitor/alert.go | 37 +++-- pkg/apis/monitor/meteralert.go | 15 +- pkg/apis/monitor/nodealert.go | 11 +- pkg/apis/monitor/notification.go | 13 +- pkg/apis/monitor/template.go | 1 + pkg/mcclient/modules/monitor/alert.go | 10 +- pkg/mcclient/options/monitor/alert.go | 57 +++++++ pkg/mcclient/options/monitor/ds.go | 28 ++-- pkg/monitor/alerting/eval_context.go | 4 +- pkg/monitor/alerting/interfaces.go | 2 +- pkg/monitor/alerting/notifier.go | 23 ++- pkg/monitor/alerting/notifiers/base.go | 2 +- pkg/monitor/alerting/notifiers/dingding.go | 2 +- pkg/monitor/alerting/notifiers/feishu.go | 2 +- pkg/monitor/alerting/notifiers/onecloud.go | 5 +- pkg/monitor/alerting/rule.go | 12 +- pkg/monitor/models/alert.go | 180 ++++++++++++++++---- pkg/monitor/models/alertjoint.go | 46 ++++++ pkg/monitor/models/alertnotification.go | 135 +++++++++++++++ pkg/monitor/models/meteralert.go | 157 ++++++++++++++---- pkg/monitor/models/nodealert.go | 169 +++++++++++-------- pkg/monitor/models/notification.go | 183 +++------------------ pkg/monitor/notifydrivers/drivers.go | 2 +- pkg/monitor/service/handlers.go | 14 +- 26 files changed, 763 insertions(+), 384 deletions(-) create mode 100644 pkg/mcclient/options/monitor/alert.go create mode 100644 pkg/monitor/models/alertjoint.go create mode 100644 pkg/monitor/models/alertnotification.go diff --git a/cmd/climc/shell/monitor/alert.go b/cmd/climc/shell/monitor/alert.go index 4996d06c85..d37147dfa4 100644 --- a/cmd/climc/shell/monitor/alert.go +++ b/cmd/climc/shell/monitor/alert.go @@ -46,6 +46,20 @@ func init() { return nil }) + R(&options.AlertUpdateOptions{}, aN("update"), "Update a alert rule", + func(s *mcclient.ClientSession, args *options.AlertUpdateOptions) error { + params, err := args.Params() + if err != nil { + return err + } + ret, err := monitor.Alerts.Update(s, args.ID, params.JSON(params)) + if err != nil { + return err + } + printObject(ret) + return nil + }) + R(&options.AlertDeleteOptions{}, aN("delete"), "Delete alerts", func(s *mcclient.ClientSession, args *options.AlertDeleteOptions) error { ret := monitor.Alerts.BatchDelete(s, args.ID, nil) diff --git a/cmd/climc/shell/monitor/notification.go b/cmd/climc/shell/monitor/notification.go index 9f19bb4e20..b30f8c6f62 100644 --- a/cmd/climc/shell/monitor/notification.go +++ b/cmd/climc/shell/monitor/notification.go @@ -28,11 +28,11 @@ func init() { if err != nil { return err } - ret, err := monitor.AlertNotifications.List(s, params) + ret, err := monitor.Notifications.List(s, params) if err != nil { return err } - printList(ret, monitor.AlertNotifications.GetColumns(s)) + printList(ret, monitor.Notifications.GetColumns(s)) return nil }) @@ -43,7 +43,7 @@ func init() { if err != nil { return err } - ret, err := monitor.AlertNotifications.Create(s, params.JSON(params)) + ret, err := monitor.Notifications.Create(s, params.JSON(params)) if err != nil { return err } @@ -58,7 +58,7 @@ func init() { if err != nil { return err } - ret, err := monitor.AlertNotifications.Create(s, params.JSON(params)) + ret, err := monitor.Notifications.Create(s, params.JSON(params)) if err != nil { return err } @@ -68,7 +68,7 @@ func init() { R(&options.NotificationShowOptions{}, nN("show"), "Show alert notification", func(s *mcclient.ClientSession, args *options.NotificationShowOptions) error { - ret, err := monitor.AlertNotifications.Get(s, args.ID, nil) + ret, err := monitor.Notifications.Get(s, args.ID, nil) if err != nil { return err } @@ -82,7 +82,7 @@ func init() { if err != nil { return err } - ret, err := monitor.AlertNotifications.Update(s, args.ID, params.JSON(params)) + ret, err := monitor.Notifications.Update(s, args.ID, params.JSON(params)) if err != nil { return err } @@ -90,13 +90,10 @@ func init() { return nil }) - R(&options.NotificationShowOptions{}, nN("delete"), "Show delete notification", - func(s *mcclient.ClientSession, args *options.NotificationShowOptions) error { - ret, err := monitor.AlertNotifications.Delete(s, args.ID, nil) - if err != nil { - return err - } - printObject(ret) + R(&options.NotificationDeleteOptions{}, nN("delete"), "Show delete notification", + func(s *mcclient.ClientSession, args *options.NotificationDeleteOptions) error { + ret := monitor.Notifications.BatchDelete(s, args.ID, nil) + printBatchResults(ret, monitor.Notifications.GetColumns(s)) return nil }) } diff --git a/pkg/apis/monitor/alert.go b/pkg/apis/monitor/alert.go index 8a3ef6e2b2..b1a36be26f 100644 --- a/pkg/apis/monitor/alert.go +++ b/pkg/apis/monitor/alert.go @@ -78,9 +78,7 @@ func (s ExecutionErrorOption) ToAlertState() AlertStateType { // AlertSettings contains alert conditions type AlertSetting struct { - Conditions []AlertCondition `json:"conditions"` - Notifications []string `json:"notifications"` - Level string `json:"level"` + Conditions []AlertCondition `json:"conditions"` } type AlertCondition struct { @@ -101,31 +99,36 @@ type AlertQuery struct { type AlertCreateInput struct { apis.Meta - Name string `json:"name"` - Frequency int64 `json:"frequency"` - Settings AlertSetting `json:"settings"` - Enabled *bool `json:"enabled"` + // 报警名称 + Name string `json:"name"` + // 报警执行频率 + Frequency int64 `json:"frequency"` + // 报警设置 + Settings AlertSetting `json:"settings"` + // 启用报警 + Enabled *bool `json:"enabled"` + // 报警级别 + Level string `json:"level"` } type AlertUpdateInput struct { apis.Meta - Name *string `json:"name"` - Frequency *int64 `json:"frequency"` - Settings *AlertSetting `json:"settings"` - ResourceId *string `json:"resource_id"` - ResourceType *string `json:"resource_type"` - Message *string `json:"message"` - Enabled *bool `json:"enabled"` + // 报警名称 + Name *string `json:"name"` + // 报警执行频率 + Frequency *int64 `json:"frequency"` + // 报警设置 + Settings *AlertSetting `json:"settings"` + // 启用报警 + Enabled *bool `json:"enabled"` + Message *string `json:"message"` } type AlertListInput struct { apis.VirtualResourceListInput apis.EnabledResourceBaseListInput - // 监控指标名称 - Metric string `json:"metric"` - // 以报警是否启用/禁用过滤列表 // Enabled *bool `json:"enabled"` } diff --git a/pkg/apis/monitor/meteralert.go b/pkg/apis/monitor/meteralert.go index 86f5df03e5..c19381152b 100644 --- a/pkg/apis/monitor/meteralert.go +++ b/pkg/apis/monitor/meteralert.go @@ -46,7 +46,7 @@ type MeterAlertListInput struct { Provider string `json:"provider"` // 云账号 Id AccountId string `json:"account_id"` - // 项目 Id string + // 项目 Id ProjectId string `json:"project_id"` } @@ -58,3 +58,16 @@ type MeterAlertDetails struct { AccountId string `json:"account_id"` Provider string `json:"provider"` } + +type MeterAlertUpdateInput struct { + // 比较运算符, 比如: >, <, >=, <= + Comparator *string `json:"comparator"` + // 报警阀值 + Threshold *float64 `json:"threshold"` + // 通知接受者 + Recipients *string `json:"recipients"` + // 项目 Id + ProjectId *string `json:"project_id"` + // 通知方式, 比如: email, mobile + Channel *string `json:"channel"` +} diff --git a/pkg/apis/monitor/nodealert.go b/pkg/apis/monitor/nodealert.go index a3ab04c333..82e4975361 100644 --- a/pkg/apis/monitor/nodealert.go +++ b/pkg/apis/monitor/nodealert.go @@ -26,7 +26,7 @@ const ( ) type ResourceAlertV1CreateInput struct { - *AlertCreateInput + AlertCreateInput // 查询指标周期 Period string `json:"period"` @@ -36,8 +36,6 @@ type ResourceAlertV1CreateInput struct { Comparator string `json:"comparator"` // 报警阀值 Threshold float64 `json:"threshold"` - // 报警级别 - Level string `json:"level"` // 通知方式, 比如: email, mobile Channel string `json:"channel"` // 通知接受者 @@ -61,15 +59,13 @@ func (input NodeAlertCreateInput) ToAlertCreateInput( name string, field string, measurement string, - db string, - notifications []string) AlertCreateInput { + db string) AlertCreateInput { freq, _ := time.ParseDuration(input.Window) ret := AlertCreateInput{ Name: name, Frequency: int64(freq / time.Second), + Level: input.Level, Settings: AlertSetting{ - Level: input.Level, - Notifications: notifications, Conditions: []AlertCondition{ { Type: "query", @@ -157,7 +153,6 @@ type NodeAlertListInput struct { func (input NodeAlertListInput) ToAlertListInput() AlertListInput { return AlertListInput{ VirtualResourceListInput: input.VirtualResourceListInput, - Metric: input.Metric, } } diff --git a/pkg/apis/monitor/notification.go b/pkg/apis/monitor/notification.go index c66298a134..762c559786 100644 --- a/pkg/apis/monitor/notification.go +++ b/pkg/apis/monitor/notification.go @@ -36,7 +36,7 @@ const ( AlertNotificationTypeFeishu = "feishu" ) -type AlertNotificationCreateInput struct { +type NotificationCreateInput struct { apis.Meta // 报警通知名称 @@ -55,7 +55,7 @@ type AlertNotificationCreateInput struct { Settings jsonutils.JSONObject `json:"settings"` } -type AlertNotificationUpdateInput struct { +type NotificationUpdateInput struct { apis.Meta // 报警通知名称 @@ -95,12 +95,3 @@ type NotificationSettingFeishu struct { AppId string `json:"app_id"` AppSecret string `json:"app_secret"` } - -type AlertNotificationStateCreateInput struct { - apis.Meta - - Name string `json:"name"` - AlertId string `json:"alert_id"` - NotifierId string `json:"notifier_id"` - State AlertNotificationStateType `json:"state"` -} diff --git a/pkg/apis/monitor/template.go b/pkg/apis/monitor/template.go index 86ced38626..2d13763156 100644 --- a/pkg/apis/monitor/template.go +++ b/pkg/apis/monitor/template.go @@ -24,6 +24,7 @@ type NotificationTemplateConfig struct { Matches []EvalMatch `json:"matches"` // PrevAlertState AlertStateType `json:"prev_alert_state"` // State AlertStateType `json:"state"` + NoDataFound bool `json:"no_data"` StartTime string `json:"start_time"` EndTime string `json:"end_time"` Description string `json:"description"` diff --git a/pkg/mcclient/modules/monitor/alert.go b/pkg/mcclient/modules/monitor/alert.go index 9347998aa6..070a1a6b44 100644 --- a/pkg/mcclient/modules/monitor/alert.go +++ b/pkg/mcclient/modules/monitor/alert.go @@ -20,21 +20,21 @@ import ( ) var ( - Alerts modulebase.ResourceManager - AlertNotifications modulebase.ResourceManager + Alerts modulebase.ResourceManager + Notifications modulebase.ResourceManager ) func init() { Alerts = modules.NewMonitorV2Manager("alert", "alerts", - []string{"id", "name", "settings"}, + []string{"id", "name", "state", "frequency", "enabled", "settings"}, []string{}) - AlertNotifications = modules.NewMonitorV2Manager( + Notifications = modules.NewMonitorV2Manager( "alert_notification", "alert_notifications", []string{"id", "name", "type", "is_default", "disable_resolve_message", "send_reminder", "settings"}, []string{}) for _, m := range []modulebase.ResourceManager{ Alerts, - AlertNotifications, + Notifications, } { modules.Register(&m) } diff --git a/pkg/mcclient/options/monitor/alert.go b/pkg/mcclient/options/monitor/alert.go new file mode 100644 index 0000000000..9ca1e508cb --- /dev/null +++ b/pkg/mcclient/options/monitor/alert.go @@ -0,0 +1,57 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package monitor + +import ( + "fmt" + "time" + + "yunion.io/x/onecloud/pkg/apis/monitor" + "yunion.io/x/onecloud/pkg/mcclient/options" +) + +type AlertListOptions struct { + options.BaseListOptions +} + +type AlertShowOptions struct { + ID string `help:"ID or name of the alert" json:"-"` +} + +type AlertDeleteOptions struct { + ID []string `help:"ID of alert to delete"` +} + +type AlertUpdateOptions struct { + ID string `help:"ID or name of the alert"` + Name string `help:"Update alert name"` + Frequency string `help:"Alert execute frequency, e.g. '5m', '1h'"` +} + +func (opt AlertUpdateOptions) Params() (*monitor.AlertUpdateInput, error) { + input := new(monitor.AlertUpdateInput) + if opt.Name != "" { + input.Name = &opt.Name + } + if opt.Frequency != "" { + freq, err := time.ParseDuration(opt.Frequency) + if err != nil { + return nil, fmt.Errorf("Invalid frequency time format %s: %v", opt.Frequency, err) + } + f := int64(freq / time.Second) + input.Frequency = &f + } + return input, nil +} diff --git a/pkg/mcclient/options/monitor/ds.go b/pkg/mcclient/options/monitor/ds.go index 84446a4a6e..9d978c7771 100644 --- a/pkg/mcclient/options/monitor/ds.go +++ b/pkg/mcclient/options/monitor/ds.go @@ -41,6 +41,10 @@ type NotificationShowOptions struct { ID string `help:"ID or name of the alert notification config" json:"-"` } +type NotificationDeleteOptions struct { + ID []string `help:"ID or name of the alert notification config" json:"-"` +} + type NotificationFields struct { Frequency string `help:"notify frequency, e.g. 5m, 1h"` IsDefault *bool `help:"set as default notification"` @@ -53,8 +57,8 @@ type NotificationCreateOptions struct { NotificationFields } -func (opt NotificationCreateOptions) Params() (*monitor.AlertNotificationCreateInput, error) { - ret := &monitor.AlertNotificationCreateInput{ +func (opt NotificationCreateOptions) Params() (*monitor.NotificationCreateInput, error) { + ret := &monitor.NotificationCreateInput{ Name: opt.NAME, SendReminder: opt.SendReminder, DisableResolveMessage: opt.DisableResolveMessage, @@ -71,7 +75,7 @@ type NotificationDingDingCreateOptions struct { MsgType string `help:"message type" choices:"markdown|actionCard" default:"markdown"` } -func (opt NotificationDingDingCreateOptions) Params() (*monitor.AlertNotificationCreateInput, error) { +func (opt NotificationDingDingCreateOptions) Params() (*monitor.NotificationCreateInput, error) { out, err := opt.NotificationCreateOptions.Params() if err != nil { return nil, err @@ -90,7 +94,7 @@ type NotificationFeishuCreateOptions struct { APPSECRET string `help:"feishu robt appSecret"` } -func (opt NotificationFeishuCreateOptions) Params() (*monitor.AlertNotificationCreateInput, error) { +func (opt NotificationFeishuCreateOptions) Params() (*monitor.NotificationCreateInput, error) { out, err := opt.NotificationCreateOptions.Params() if err != nil { return nil, err @@ -112,7 +116,7 @@ type NotificationUpdateOptions struct { DisableSendReminder *bool `help:"disable send reminder" json:"-"` } -func (opt NotificationUpdateOptions) Params() (*monitor.AlertNotificationUpdateInput, error) { +func (opt NotificationUpdateOptions) Params() (*monitor.NotificationUpdateInput, error) { if opt.DisableDefault != nil && *opt.DisableDefault { tmp := false opt.IsDefault = &tmp @@ -125,22 +129,10 @@ func (opt NotificationUpdateOptions) Params() (*monitor.AlertNotificationUpdateI tmp := false opt.SendReminder = &tmp } - ret := &monitor.AlertNotificationUpdateInput{ + ret := &monitor.NotificationUpdateInput{ IsDefault: opt.IsDefault, DisableResolveMessage: opt.DisableResolveMessage, SendReminder: opt.SendReminder, } return ret, nil } - -type AlertListOptions struct { - options.BaseListOptions -} - -type AlertShowOptions struct { - ID string `help:"ID or name of the alert" json:"-"` -} - -type AlertDeleteOptions struct { - ID []string `help:"ID of alert to delete"` -} diff --git a/pkg/monitor/alerting/eval_context.go b/pkg/monitor/alerting/eval_context.go index ae5b256a48..dbcbef5538 100644 --- a/pkg/monitor/alerting/eval_context.go +++ b/pkg/monitor/alerting/eval_context.go @@ -16,6 +16,7 @@ package alerting import ( "context" + "fmt" "time" "yunion.io/x/log" @@ -83,7 +84,7 @@ func (c *EvalContext) GetStateModel() *StateDescription { Text: "Unknown", } default: - panic("Unknown rule state for alert " + c.Rule.State) + panic(fmt.Sprintf("Unknown rule state %q for alert %s", c.Rule.State, c.Rule.Name)) } } @@ -177,6 +178,7 @@ func (c *EvalContext) GetNotificationTemplateConfig() monitor.NotificationTempla EndTime: c.EndTime.Format(time.RFC3339), Description: desc, Level: c.Rule.Level, + NoDataFound: c.NoDataFound, } } diff --git a/pkg/monitor/alerting/interfaces.go b/pkg/monitor/alerting/interfaces.go index 9bc8efd5bc..82445c5edd 100644 --- a/pkg/monitor/alerting/interfaces.go +++ b/pkg/monitor/alerting/interfaces.go @@ -50,5 +50,5 @@ type Notifier interface { Notify(evalContext *EvalContext) error // ShouldNotify checks this evaluation should send an alert notification - ShouldNotify(ctx context.Context, evalContext *EvalContext, notificationState *models.SAlertNotificationState) bool + ShouldNotify(ctx context.Context, evalContext *EvalContext, notificationState *models.SAlertnotification) bool } diff --git a/pkg/monitor/alerting/notifier.go b/pkg/monitor/alerting/notifier.go index 764a9ac9c0..826583ca78 100644 --- a/pkg/monitor/alerting/notifier.go +++ b/pkg/monitor/alerting/notifier.go @@ -15,6 +15,7 @@ package alerting import ( + "database/sql" "time" "yunion.io/x/log" @@ -48,7 +49,7 @@ func (n *notificationService) SendIfNeeded(evalCtx *EvalContext) error { type notifierState struct { notifier Notifier - state *models.SAlertNotificationState + state *models.SAlertnotification } type notifierStateSlice []*notifierState @@ -92,7 +93,7 @@ func (n *notificationService) sendNotifications(evalCtx *EvalContext, states not } func (n *notificationService) getNeededNotifiers(nIds []string, evalCtx *EvalContext) (notifierStateSlice, error) { - notis, err := models.AlertNotificationManager.GetNotificationsWithDefault(nIds) + notis, err := models.NotificationManager.GetNotificationsWithDefault(nIds) if err != nil { return nil, err } @@ -109,13 +110,21 @@ func (n *notificationService) getNeededNotifiers(nIds []string, evalCtx *EvalCon Settings: obj.Settings, }) if err != nil { - log.Errorf("Could not creat enotifier %s, error: %v", obj.GetId(), err) + log.Errorf("Could not create notifier %s, error: %v", obj.GetId(), err) continue } - state, err := models.AlertNotificationStateManager.GetOrCreateState(evalCtx.Ctx, evalCtx.UserCred, evalCtx.Rule.Id, obj.GetId()) + state, err := models.AlertNotificationManager.Get(evalCtx.Rule.Id, obj.GetId()) if err != nil { - log.Errorf("Get alert state: %v, alertId %s, notifierId: %s", err, evalCtx.Rule.Id, obj.GetId()) - continue + if errors.Cause(err) == sql.ErrNoRows { + state, err = obj.AttachToAlert(evalCtx.Ctx, evalCtx.UserCred, evalCtx.Rule.Id) + if err != nil { + log.Errorf("Attach notification %s to alert %s error: %v", obj.GetName(), evalCtx.Rule.Id, err) + continue + } + } else { + log.Errorf("Get alert state: %v, alertId %s, notifierId: %s", err, evalCtx.Rule.Id, obj.GetId()) + continue + } } if not.ShouldNotify(evalCtx.Ctx, evalCtx, state) { @@ -132,7 +141,7 @@ func (n *notificationService) getNeededNotifiers(nIds []string, evalCtx *EvalCon type NotifierPlugin struct { Type string Factory NotifierFactory - ValidateCreateData func(cred mcclient.IIdentityProvider, input monitor.AlertNotificationCreateInput) (monitor.AlertNotificationCreateInput, error) + ValidateCreateData func(cred mcclient.IIdentityProvider, input monitor.NotificationCreateInput) (monitor.NotificationCreateInput, error) } type NotificationConfig notifydrivers.NotificationConfig diff --git a/pkg/monitor/alerting/notifiers/base.go b/pkg/monitor/alerting/notifiers/base.go index 235fdb2fab..cfc54ba895 100644 --- a/pkg/monitor/alerting/notifiers/base.go +++ b/pkg/monitor/alerting/notifiers/base.go @@ -48,7 +48,7 @@ func NewNotifierBase(config alerting.NotificationConfig) NotifierBase { } // ShouldNotify checks this evaluation should send an alert notification -func (n *NotifierBase) ShouldNotify(_ context.Context, evalCtx *alerting.EvalContext, state *models.SAlertNotificationState) bool { +func (n *NotifierBase) ShouldNotify(_ context.Context, evalCtx *alerting.EvalContext, state *models.SAlertnotification) bool { prevState := evalCtx.PrevAlertState newState := evalCtx.Rule.State diff --git a/pkg/monitor/alerting/notifiers/dingding.go b/pkg/monitor/alerting/notifiers/dingding.go index e6f6c9a2c9..4ac3d9e50e 100644 --- a/pkg/monitor/alerting/notifiers/dingding.go +++ b/pkg/monitor/alerting/notifiers/dingding.go @@ -41,7 +41,7 @@ func init() { alerting.RegisterNotifier(&alerting.NotifierPlugin{ Type: monitor.AlertNotificationTypeDingding, Factory: newDingdingNotifier, - ValidateCreateData: func(cred mcclient.IIdentityProvider, input monitor.AlertNotificationCreateInput) (monitor.AlertNotificationCreateInput, error) { + ValidateCreateData: func(cred mcclient.IIdentityProvider, input monitor.NotificationCreateInput) (monitor.NotificationCreateInput, error) { settings := new(monitor.NotificationSettingDingding) if err := input.Settings.Unmarshal(settings); err != nil { return input, errors.Wrap(err, "unmarshal setting") diff --git a/pkg/monitor/alerting/notifiers/feishu.go b/pkg/monitor/alerting/notifiers/feishu.go index f5bc352950..3c819d2c81 100644 --- a/pkg/monitor/alerting/notifiers/feishu.go +++ b/pkg/monitor/alerting/notifiers/feishu.go @@ -34,7 +34,7 @@ func init() { alerting.RegisterNotifier(&alerting.NotifierPlugin{ Type: monitor.AlertNotificationTypeFeishu, Factory: newFeishuNotifier, - ValidateCreateData: func(cred mcclient.IIdentityProvider, input monitor.AlertNotificationCreateInput) (monitor.AlertNotificationCreateInput, error) { + ValidateCreateData: func(cred mcclient.IIdentityProvider, input monitor.NotificationCreateInput) (monitor.NotificationCreateInput, error) { settings := new(monitor.NotificationSettingFeishu) if err := input.Settings.Unmarshal(settings); err != nil { return input, errors.Wrap(err, "unmarshal setting") diff --git a/pkg/monitor/alerting/notifiers/onecloud.go b/pkg/monitor/alerting/notifiers/onecloud.go index ebbbf98132..81d3c50c79 100644 --- a/pkg/monitor/alerting/notifiers/onecloud.go +++ b/pkg/monitor/alerting/notifiers/onecloud.go @@ -37,7 +37,7 @@ func init() { alerting.RegisterNotifier(&alerting.NotifierPlugin{ Type: monitor.AlertNotificationTypeOneCloud, Factory: newOneCloudNotifier, - ValidateCreateData: func(cred mcclient.IIdentityProvider, input monitor.AlertNotificationCreateInput) (monitor.AlertNotificationCreateInput, error) { + ValidateCreateData: func(cred mcclient.IIdentityProvider, input monitor.NotificationCreateInput) (monitor.NotificationCreateInput, error) { settings := new(monitor.NotificationSettingOneCloud) if err := input.Settings.Unmarshal(settings); err != nil { return input, errors.Wrap(err, "unmarshal setting") @@ -99,6 +99,8 @@ func GetNotifyTemplateConfig(ctx *alerting.EvalContext) monitor.NotificationTemp if ctx.Rule.State == monitor.AlertStateOK { isRecovery = true topic = fmt.Sprintf("%s %s 告警已恢复", topic, ctx.GetRuleTitle()) + } else if ctx.NoDataFound { + topic = fmt.Sprintf("%s %s 暂无数据", topic, ctx.GetRuleTitle()) } else { topic = fmt.Sprintf("%s %s 发生告警", topic, ctx.GetRuleTitle()) } @@ -128,7 +130,6 @@ func (oc *OneCloudNotifier) Notify(ctx *alerting.EvalContext) error { Msg: content, } - log.Errorf("---send msg: %s", jsonutils.Marshal(msg)) return notify.Notifications.Send(oc.session, msg) } diff --git a/pkg/monitor/alerting/rule.go b/pkg/monitor/alerting/rule.go index 4d43d663e3..ca858bd780 100644 --- a/pkg/monitor/alerting/rule.go +++ b/pkg/monitor/alerting/rule.go @@ -121,8 +121,16 @@ func NewRuleFromDBAlert(ruleDef *models.SAlert) (*Rule, error) { return nil, err } - model.Level = settings.Level - model.Notifications = settings.Notifications + model.Level = ruleDef.Level + nIds := []string{} + notis, err := ruleDef.GetNotifications() + if err != nil { + return nil, err + } + for _, n := range notis { + nIds = append(nIds, n.NotificationId) + } + model.Notifications = nIds // model.AlertRuleTags = ruleDef.GetTagsFromSettings() for index, condition := range settings.Conditions { diff --git a/pkg/monitor/models/alert.go b/pkg/monitor/models/alert.go index 7ed8d402f9..7eb0903676 100644 --- a/pkg/monitor/models/alert.go +++ b/pkg/monitor/models/alert.go @@ -21,12 +21,14 @@ import ( "time" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/apis/monitor" "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/monitor/validators" @@ -77,20 +79,49 @@ type SAlert struct { Frequency int64 `nullable:"false" list:"user" create:"required" update:"user"` Settings jsonutils.JSONObject `nullable:"false" list:"user" create:"required" update:"user"` - // Enabled bool `nullable:"false" default:"false" list:"user" create:"optional"` + Level string `charset:"ascii" width:"36"nullable:"false" default:"normal" list:"user"` + Message string `charset:"utf8" list:"user" update:"user"` + UsedBy string `charset:"ascii" list:"user"` - Message string `charset:"utf8" list:"user" update:"user"` - State string `width:"36" charset:"ascii" list:"user"` // Silenced bool - ExecutionError string `charset:"utf8" list:"user"` - For int64 `nullable:"false" list:"user"` + ExecutionError string `charset:"utf8" list:"user"` + For int64 `nullable:"false" list:"user"` + EvalData jsonutils.JSONObject `list:"user" list:"user"` + State string `width:"36" charset:"ascii" nullable:"false" default:"unknown" list:"user"` + NoDataState string `width:"36" charset:"ascii" nullable:"false" default:"pending" list:"user"` + ExecutionErrorState string `width:"36" charset:"ascii" nullable:"false" default:"alerting" list:"user"` + LastStateChange time.Time `list:"user"` + StateChanges int `default:"0" nullable:"false" list:"user"` +} - EvalData jsonutils.JSONObject `list:"user"` - LastStateChange time.Time `json:"last_state_change" list:"user"` - StateChanges int `default:"0" nullable:"false" list:"user" json:"state_changes"` +func (alert *SAlert) IsEnable() bool { + return alert.Enabled.Bool() +} - NoDataState string `charset:"utf8" list:"user"` - ExecutionErrorState string `charset:"utf8" list:"user"` +func (alert *SAlert) SetEnable() error { + _, err := db.Update(alert, func() error { + alert.SetEnabled(true) + alert.State = string(monitor.AlertStatePending) + return nil + }) + return err +} + +func (alert *SAlert) SetDisable() error { + _, err := db.Update(alert, func() error { + alert.SEnabledResourceBase.SetEnabled(false) + alert.State = string(monitor.AlertStatePaused) + return nil + }) + return err +} + +func (alert *SAlert) SetUsedBy(usedBy string) error { + _, err := db.Update(alert, func() error { + alert.UsedBy = usedBy + return nil + }) + return err } func (alert *SAlert) SetTitle(ctx context.Context, t string) error { @@ -251,22 +282,6 @@ func (alert *SAlert) PerformDisable(ctx context.Context, userCred mcclient.Token return nil, nil } -func (alert *SAlert) GetNotifications() ([]SAlertNotification, error) { - settings, err := alert.GetSettings() - if err != nil { - return nil, errors.Wrap(err, "get settings") - } - nIds := settings.Notifications - notis, err := AlertNotificationManager.GetNotifications(nIds) - if err != nil { - if errors.Cause(err) == sql.ErrNoRows { - return nil, nil - } - return nil, err - } - return notis, nil -} - const ( ErrAlertChannotChangeStateOnPaused = errors.Error("Cannot change state on pause alert") ) @@ -296,10 +311,115 @@ func (alert *SAlert) SetState(input AlertSetStateInput) error { } func (alert *SAlert) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input monitor.AlertUpdateInput) (*jsonutils.JSONDict, error) { - if input.Enabled == nil { - enable := true - input.Enabled = &enable + if input.Settings != nil { + if err := jsonutils.Update(alert.Settings, jsonutils.Marshal(input.Settings)); err != nil { + return nil, err + } + if err := jsonutils.Update(input.Settings, alert.Settings); err != nil { + return nil, err + } } - input.Settings = setAlertDefaultSetting(input.Settings, "") return alert.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.JSON(input)) } + +func (alert *SAlert) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) { + input := new(monitor.AlertUpdateInput) + if err := data.Unmarshal(input); err != nil { + log.Errorf("update unmarshal error: %v", err) + return + } + if _, err := db.Update(alert, func() error { + alert.Settings = jsonutils.Marshal(input) + return nil + }); err != nil { + log.Errorf("update setting error: %v", err) + } +} + +func (alert *SAlert) IsAttachNotification(noti *SNotification) (bool, error) { + q := AlertNotificationManager.Query().Equals("notification_id", noti.GetId()).Equals("alert_id", alert.GetId()) + cnt, err := q.CountWithError() + if err != nil { + return false, err + } + return cnt > 0, nil +} + +func (alert *SAlert) GetNotificationsQuery() *sqlchemy.SQuery { + return AlertNotificationManager.Query().Equals("alert_id", alert.GetId()) +} + +func (alert *SAlert) GetNotifications() ([]SAlertnotification, error) { + notis := make([]SAlertnotification, 0) + q := alert.GetNotificationsQuery().Asc("index") + if err := db.FetchModelObjects(AlertNotificationManager, q, ¬is); err != nil { + return nil, err + } + return notis, nil +} + +func (alert *SAlert) getNotificationIndex() (int8, error) { + notis, err := alert.GetNotifications() + if err != nil { + return -1, err + } + var max uint + for i := 0; i < len(notis); i++ { + if uint(notis[i].Index) > max { + max = uint(notis[i].Index) + } + } + + idxs := make([]int, max+1) + for i := 0; i < len(notis); i++ { + idxs[notis[i].Index] = 1 + } + + // find first idx not set + for i := 0; i < len(idxs); i++ { + if idxs[i] != 1 { + return int8(i), nil + } + } + + return int8(max + 1), nil +} + +func (alert *SAlert) AttachNotification( + ctx context.Context, + userCred mcclient.TokenCredential, + noti *SNotification, + state monitor.AlertNotificationStateType, + usedBy string) (*SAlertnotification, error) { + attached, err := alert.IsAttachNotification(noti) + if err != nil { + return nil, err + } + if attached { + return nil, httperrors.NewNotAcceptableError("alert already attached to notification") + } + + defer lockman.ReleaseObject(ctx, alert) + lockman.LockObject(ctx, alert) + alertNoti := new(SAlertnotification) + alertNoti.AlertId = alert.GetId() + alertNoti.Index, err = alert.getNotificationIndex() + alertNoti.NotificationId = noti.GetId() + if err != nil { + return nil, err + } + alertNoti.State = string(state) + alertNoti.UsedBy = usedBy + if err := alertNoti.DoSave(ctx, userCred); err != nil { + return nil, err + } + return alertNoti, nil +} + +func (alert *SAlert) SetFor(forTime time.Duration) error { + _, err := db.Update(alert, func() error { + alert.For = int64(forTime) + return nil + }) + return err +} diff --git a/pkg/monitor/models/alertjoint.go b/pkg/monitor/models/alertjoint.go new file mode 100644 index 0000000000..87e6612664 --- /dev/null +++ b/pkg/monitor/models/alertjoint.go @@ -0,0 +1,46 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package models + +import "yunion.io/x/onecloud/pkg/cloudcommon/db" + +type SAlertJointsManager struct { + db.SVirtualJointResourceBaseManager +} + +func NewAlertJointsManager( + dt interface{}, tableName string, + keyword string, keywordPlural string, + slave db.IVirtualModelManager) SAlertJointsManager { + return SAlertJointsManager{ + db.NewVirtualJointResourceBaseManager( + dt, tableName, keyword, keywordPlural, AlertManager, slave), + } +} + +type SAlertJointsBase struct { + db.SVirtualJointResourceBase + + AlertId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` +} + +func (b *SAlertJointsBase) getAlert() *SAlert { + alert, _ := AlertManager.GetAlert(b.AlertId) + return alert +} + +func (man *SAlertJointsManager) GetMasterFieldName() string { + return "alert_id" +} diff --git a/pkg/monitor/models/alertnotification.go b/pkg/monitor/models/alertnotification.go new file mode 100644 index 0000000000..6b458ef5cd --- /dev/null +++ b/pkg/monitor/models/alertnotification.go @@ -0,0 +1,135 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package models + +import ( + "context" + + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/apis/monitor" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/mcclient" +) + +const ( + AlertNotificationUsedByMeterAlert = "meter_alert" + AlertNotificationUsedByNodeAlert = "node_alert" +) + +type SAlertNotificationManager struct { + SAlertJointsManager +} + +var AlertNotificationManager *SAlertNotificationManager + +func init() { + db.InitManager(func() { + AlertNotificationManager = &SAlertNotificationManager{ + SAlertJointsManager: NewAlertJointsManager( + SAlertnotification{}, + "alertnotifications_tbl", + "alertnotification", + "alertnotifications", + NotificationManager), + } + AlertNotificationManager.SetVirtualObject(AlertNotificationManager) + AlertNotificationManager.TableSpec().AddIndex(true, "notification_id", "alert_id") + }) +} + +type SAlertnotification struct { + SAlertJointsBase + NotificationId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` + State string `nullable:"false" list:"user" create:"required"` + Index int8 `nullable:"false" default:"0" list:"user" list:"user" update:"user"` + UsedBy string `width:"36" charset:"ascii" nullable:"true" list:"user"` +} + +func (man *SAlertNotificationManager) GetSlaveFieldName() string { + return "notification_id" +} + +func (man *SAlertNotificationManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return false +} + +func (man *SAlertNotificationManager) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return false +} + +func (man *SAlertNotificationManager) Get(alertId string, notiId string) (*SAlertnotification, error) { + q := man.Query().Equals("alert_id", alertId).Equals("notification_id", notiId) + obj := new(SAlertnotification) + err := q.First(obj) + obj.SetModelManager(man, obj) + return obj, err +} + +func (joint *SAlertnotification) DoSave(ctx context.Context, userCred mcclient.TokenCredential) error { + if err := AlertNotificationManager.TableSpec().Insert(joint); err != nil { + return err + } + joint.SetModelManager(AlertNotificationManager, joint) + return nil +} + +func (joint *SAlertnotification) Master() db.IStandaloneModel { + return db.JointMaster(joint) +} + +func (joint *SAlertnotification) Slave() db.IStandaloneModel { + return db.JointSlave(joint) +} + +func (joint *SAlertnotification) GetNotification() (*SNotification, error) { + noti, err := NotificationManager.GetNotification(joint.NotificationId) + if err != nil { + return nil, err + } + return noti, nil +} + +func (joint *SAlertnotification) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { + return db.DeleteModel(ctx, userCred, joint) +} + +func (joint *SAlertnotification) Detach(ctx context.Context, userCred mcclient.TokenCredential) error { + return db.DetachJoint(ctx, userCred, joint) +} + +func (joint *SAlertnotification) GetUsedBy() string { + return joint.UsedBy +} + +func (state *SAlertnotification) SetToPending() error { + return state.setState(monitor.AlertNotificationStatePending) +} + +func (state *SAlertnotification) SetToCompleted() error { + return state.setState(monitor.AlertNotificationStateCompleted) +} + +func (state *SAlertnotification) setState(changeState monitor.AlertNotificationStateType) error { + _, err := db.Update(state, func() error { + state.State = string(changeState) + return nil + }) + return err +} + +func (state *SAlertnotification) GetState() monitor.AlertNotificationStateType { + return monitor.AlertNotificationStateType(state.State) +} diff --git a/pkg/monitor/models/meteralert.go b/pkg/monitor/models/meteralert.go index bb493c3bf1..ca833544b8 100644 --- a/pkg/monitor/models/meteralert.go +++ b/pkg/monitor/models/meteralert.go @@ -48,7 +48,8 @@ func init() { type IMeterAlertDriver interface { GetType() string GetName() string - ToAlertCreateInput(input monitor.MeterAlertCreateInput, notificatoins []string, allAccountIds []string) monitor.AlertCreateInput + GetFor() time.Duration + ToAlertCreateInput(input monitor.MeterAlertCreateInput, dsId string, allAccountIds []string, level string) monitor.AlertCreateInput } type SMeterAlertManager struct { @@ -139,18 +140,6 @@ func (man *SMeterAlertManager) ValidateCreateData( if _, err := time.ParseDuration(data.Period); err != nil { return nil, httperrors.NewInputParameterError("Invalid period format: %s", data.Period) } - if data.Recipients == "" { - return nil, httperrors.NewInputParameterError("recipients is empty") - } - notification, err := man.CreateNotification(ctx, userCred, data.Type, data.Channel, data.Recipients) - if err != nil { - return nil, errors.Wrap(err, "create notification") - } - - if data.ProjectId == "" { - return nil, httperrors.NewInputParameterError("project_id is empty") - } - drv := man.GetDriver(data.Type) if drv == nil { return nil, httperrors.NewInputParameterError("not support type %q", data.Type) @@ -166,15 +155,22 @@ func (man *SMeterAlertManager) ValidateCreateData( return nil, err } } - alertInput := drv.ToAlertCreateInput( - data, []string{notification.GetId()}, - allAccountIds) + if data.Recipients == "" { + return nil, httperrors.NewInputParameterError("recipients is empty") + } + + ds, err := DataSourceManager.GetDefaultSource() + if err != nil { + return nil, err + } + + alertInput := drv.ToAlertCreateInput(data, ds.GetId(), allAccountIds, data.Level) alertInput, err = AlertManager.ValidateCreateData(ctx, userCred, ownerId, query, alertInput) if err != nil { return nil, err } data.Name = name - data.AlertCreateInput = &alertInput + data.AlertCreateInput = alertInput return &data, nil } @@ -188,16 +184,23 @@ func (_ *sMeterDailyFee) GetName() string { return "日消费" } +func (_ *sMeterDailyFee) GetFor() time.Duration { + return 12 * time.Hour +} + func (f *sMeterDailyFee) ToAlertCreateInput( input monitor.MeterAlertCreateInput, - notifications []string, + dsId string, allAccountIds []string, + level string, ) monitor.AlertCreateInput { freq, _ := time.ParseDuration(input.Window) ret := monitor.AlertCreateInput{ Name: f.GetName(), + Level: level, Frequency: int64(freq / time.Second), - Settings: GetMeterAlertSetting(input, notifications, + Settings: GetMeterAlertSetting(input, + dsId, "account_daily_resfee", "meter_db", allAccountIds, "sumDate"), } @@ -214,16 +217,23 @@ func (_ *sMeterMonthFee) GetName() string { return "月消费" } +func (_ *sMeterMonthFee) GetFor() time.Duration { + return 24 * time.Hour +} + func (f *sMeterMonthFee) ToAlertCreateInput( input monitor.MeterAlertCreateInput, - notifications []string, + dsId string, allAccountIds []string, + level string, ) monitor.AlertCreateInput { freq, _ := time.ParseDuration(input.Window) ret := monitor.AlertCreateInput{ Name: f.GetName(), + Level: level, Frequency: int64(freq / time.Second), - Settings: GetMeterAlertSetting(input, notifications, + Settings: GetMeterAlertSetting(input, + dsId, "account_month_resfee", "meter_db", allAccountIds, "sumMonth"), } @@ -232,7 +242,7 @@ func (f *sMeterMonthFee) ToAlertCreateInput( func GetMeterAlertSetting( input monitor.MeterAlertCreateInput, - ns []string, + dsId string, measurement string, db string, accountIds []string, @@ -240,16 +250,15 @@ func GetMeterAlertSetting( ) monitor.AlertSetting { q, reducer, eval := GetMeterAlertQuery(input, measurement, db, accountIds, groupByStr) return monitor.AlertSetting{ - Level: input.Level, - Notifications: ns, Conditions: []monitor.AlertCondition{ { Type: "query", Operator: "and", Query: monitor.AlertQuery{ - Model: q, - From: input.Period, - To: "now", + Model: q, + From: input.Period, + To: "now", + DataSourceId: dsId, }, Reducer: reducer, Evaluator: eval, @@ -306,7 +315,7 @@ func GetMeterAlertQuery( }) } - log.Debugf("==alertType: %s", alertType) + log.Debugf("meteralert alertType: %s", alertType) if input.ProjectId != "" { filters = append(filters, monitor.MetricQueryTag{ @@ -344,6 +353,18 @@ func (man *SMeterAlertManager) GetAlert(id string) (*SMeterAlert, error) { return obj.(*SMeterAlert), nil } +func (man *SMeterAlertManager) ListItemFilter( + ctx context.Context, q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query monitor.MeterAlertListInput) (*sqlchemy.SQuery, error) { + q, err := AlertManager.ListItemFilter(ctx, q, userCred, monitor.AlertListInput{}) + if err != nil { + return nil, err + } + q.Equals("used_by", AlertNotificationUsedByMeterAlert) + return q, nil +} + func (man *SMeterAlertManager) CustomizeFilterList( ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) ( @@ -397,6 +418,17 @@ func (man *SMeterAlertManager) CustomizeFilterList( return filters, nil } +func (alert *SMeterAlert) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error { + if err := alert.SVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data); err != nil { + return err + } + input := new(monitor.MeterAlertCreateInput) + if err := data.Unmarshal(input); err != nil { + return err + } + return alert.SV1Alert.CustomizeCreate(ctx, userCred, input.Type, input.Channel, input.Recipients, AlertNotificationUsedByMeterAlert) +} + func (alert *SMeterAlert) setType(ctx context.Context, userCred mcclient.TokenCredential, t string) error { return alert.SetMetadata(ctx, MeterAlertMetadataType, t, userCred) } @@ -458,12 +490,16 @@ func (alert *SMeterAlert) PostCreate(ctx context.Context, log.Errorf("set project_id: %v", err) } } + forTime := MeterAlertManager.GetDriver(alert.getType()).GetFor() + if err := alert.SetFor(forTime); err != nil { + log.Errorf("set for error: %v", err) + } } func (alert *SMeterAlert) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (monitor.MeterAlertDetails, error) { var err error out := monitor.MeterAlertDetails{} - commonDetails, err := alert.SV1Alert.GetExtraDetails(ctx, userCred, query, isList) + commonDetails, err := alert.SV1Alert.GetExtraDetails(ctx, userCred, query, isList, AlertNotificationUsedByMeterAlert) if err != nil { return out, err } @@ -476,3 +512,66 @@ func (alert *SMeterAlert) GetExtraDetails(ctx context.Context, userCred mcclient return out, nil } + +func (alert *SMeterAlert) ValidateUpdateData( + ctx context.Context, userCred mcclient.TokenCredential, + query jsonutils.JSONObject, input monitor.MeterAlertUpdateInput) (*jsonutils.JSONDict, error) { + ret := new(monitor.AlertUpdateInput) + details, err := alert.GetExtraDetails(ctx, userCred, query, false) + if err != nil { + return nil, err + } + if input.Threshold != nil && *input.Threshold != details.Threshold { + details.Threshold = *input.Threshold + } + + if input.Comparator != nil && *input.Comparator != details.Comparator { + details.Comparator = *input.Comparator + } + + ds, err := DataSourceManager.GetDefaultSource() + if err != nil { + return nil, errors.Wrap(err, "get default data source") + } + // hack: update notification here + if err := alert.UpdateNotification(AlertNotificationUsedByMeterAlert, input.Channel, input.Recipients); err != nil { + return nil, errors.Wrap(err, "update notification") + } + allAccountIds := []string{} + if details.AccountId == "" { + allAccountIds, err = MeterAlertManager.getAllBillAccountIds(ctx) + if err != nil { + return nil, err + } + } + tmpS := alert.getUpdateSetting(details, ds.GetId(), allAccountIds) + ret.Settings = &tmpS + return alert.SAlert.ValidateUpdateData(ctx, userCred, query, *ret) +} + +func (alert *SMeterAlert) getUpdateSetting(details monitor.MeterAlertDetails, dsId string, accountIds []string) monitor.AlertSetting { + drv := MeterAlertManager.GetDriver(alert.getType()) + input := monitor.MeterAlertCreateInput{ + ResourceAlertV1CreateInput: monitor.ResourceAlertV1CreateInput{ + Period: details.Period, + Window: details.Window, + Comparator: details.Comparator, + Threshold: details.Threshold, + Channel: details.Channel, + Recipients: details.Recipients, + }, + Type: details.Type, + Provider: details.Provider, + ProjectId: details.ProjectId, + AccountId: details.AccountId, + } + input.Level = details.Level + out := drv.ToAlertCreateInput(input, dsId, accountIds, details.Level) + return out.Settings +} + +func (alert *SMeterAlert) CustomizeDelete( + ctx context.Context, userCred mcclient.TokenCredential, + query jsonutils.JSONObject, data jsonutils.JSONObject) error { + return alert.SV1Alert.CustomizeDelete(ctx, userCred, query, data) +} diff --git a/pkg/monitor/models/nodealert.go b/pkg/monitor/models/nodealert.go index e8723e35d7..de83601320 100644 --- a/pkg/monitor/models/nodealert.go +++ b/pkg/monitor/models/nodealert.go @@ -78,9 +78,9 @@ func (v1man *SV1AlertManager) CreateNotification( userCred mcclient.TokenCredential, alertName string, channel string, - recipients string) (*SAlertNotification, error) { + recipients string) (*SNotification, error) { userIds := strings.Split(recipients, ",") - return AlertNotificationManager.CreateOneCloudNotification(ctx, userCred, alertName, channel, userIds) + return NotificationManager.CreateOneCloudNotification(ctx, userCred, alertName, channel, userIds) } func (man *SNodeAlertManager) ValidateCreateData( @@ -107,10 +107,6 @@ func (man *SNodeAlertManager) ValidateCreateData( if data.Recipients == "" { return nil, httperrors.NewInputParameterError("recipients is empty") } - notification, err := man.CreateNotification(ctx, userCred, data.Metric, data.Channel, data.Recipients) - if err != nil { - return nil, errors.Wrap(err, "create notification") - } if data.NodeId == "" { return nil, httperrors.NewInputParameterError("node_id is empty") } @@ -123,12 +119,12 @@ func (man *SNodeAlertManager) ValidateCreateData( if err != nil { return nil, err } - alertInput := data.ToAlertCreateInput(name, field, measurement, "telegraf", []string{notification.GetId()}) + alertInput := data.ToAlertCreateInput(name, field, measurement, "telegraf") alertInput, err = AlertManager.ValidateCreateData(ctx, userCred, ownerId, query, alertInput) if err != nil { return nil, err } - data.AlertCreateInput = &alertInput + data.AlertCreateInput = alertInput return &data, nil } @@ -187,11 +183,16 @@ func (man *SNodeAlertManager) ValidateListConditions(ctx context.Context, userCr return query, nil } -func (man *SV1AlertManager) ListItemFilter( +func (man *SNodeAlertManager) ListItemFilter( ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query monitor.NodeAlertListInput) (*sqlchemy.SQuery, error) { - return AlertManager.ListItemFilter(ctx, q, userCred, query.ToAlertListInput()) + q, err := AlertManager.ListItemFilter(ctx, q, userCred, query.ToAlertListInput()) + if err != nil { + return nil, err + } + q.Equals("used_by", AlertNotificationUsedByNodeAlert) + return q, nil } func (man *SNodeAlertManager) GetAlert(id string) (*SNodeAlert, error) { @@ -236,7 +237,7 @@ func (man *SNodeAlertManager) CustomizeFilterList( } mF := func(obj *SNodeAlert) (bool, error) { settings := new(monitor.AlertSetting) - if err := obj.Settings.Unmarshal(settings, "settings"); err != nil { + if err := obj.Settings.Unmarshal(settings); err != nil { return false, errors.Wrapf(err, "alert %s unmarshal", obj.GetId()) } for _, s := range settings.Conditions { @@ -273,6 +274,38 @@ func (man *SNodeAlertManager) CustomizeFilterList( return filters, nil } +func (alert *SV1Alert) CustomizeCreate( + ctx context.Context, userCred mcclient.TokenCredential, + notiName, channel, recipients, usedBy string) error { + noti, err := NodeAlertManager.CreateNotification(ctx, userCred, notiName, channel, recipients) + if err != nil { + return errors.Wrap(err, "create notification") + } + if alert.Id == "" { + alert.Id = db.DefaultUUIDGenerator() + } + alert.UsedBy = usedBy + _, err = alert.AttachNotification( + ctx, userCred, noti, + monitor.AlertNotificationStateUnknown, + usedBy) + return err +} + +func (alert *SNodeAlert) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error { + if err := alert.SVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data); err != nil { + return err + } + if err := alert.SVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data); err != nil { + return err + } + input := new(monitor.NodeAlertCreateInput) + if err := data.Unmarshal(input); err != nil { + return err + } + return alert.SV1Alert.CustomizeCreate(ctx, userCred, input.Metric, input.Channel, input.Recipients, AlertNotificationUsedByNodeAlert) +} + func (alert *SNodeAlert) getNodeId() string { return alert.GetMetadata(NodeAlertMetadataNodeId, nil) } @@ -320,7 +353,13 @@ func (alert *SNodeAlert) PostCreate(ctx context.Context, } } -func (alert *SV1Alert) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (monitor.AlertV1Details, error) { +func (alert *SV1Alert) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, + usedBy string, +) (monitor.AlertV1Details, error) { var err error out := monitor.AlertV1Details{} out.VirtualResourceDetails, err = alert.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) @@ -349,15 +388,23 @@ func (alert *SV1Alert) GetExtraDetails(ctx context.Context, userCred mcclient.To case "lt": cmp = "<=" } - out.Level = setting.Level + out.Level = alert.Level out.Comparator = cmp out.Threshold = cond.Evaluator.Params[0] out.Period = cond.Query.From - notification := alert.GetNotificationBySetting(setting) - if notification != nil { - out.Recipients = strings.Join(notification.UserIds, ",") - out.Channel = notification.Channel + noti, err := alert.GetNotification(usedBy) + if err != nil { + return out, err + } + if noti != nil { + out.NotifierId = noti.GetId() + settings := new(monitor.NotificationSettingOneCloud) + if err := noti.Settings.Unmarshal(settings); err != nil { + return out, err + } + out.Recipients = strings.Join(settings.UserIds, ",") + out.Channel = settings.Channel } q := cond.Query @@ -367,20 +414,13 @@ func (alert *SV1Alert) GetExtraDetails(ctx context.Context, userCred mcclient.To out.Measurement = measurement out.Field = field out.DB = db - noti, err := alert.GetNotification() - if err != nil { - return out, err - } - if noti != nil { - out.NotifierId = noti.GetId() - } return out, nil } func (alert *SNodeAlert) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (monitor.NodeAlertDetails, error) { var err error out := monitor.NodeAlertDetails{} - commonDetails, err := alert.SV1Alert.GetExtraDetails(ctx, userCred, query, isList) + commonDetails, err := alert.SV1Alert.GetExtraDetails(ctx, userCred, query, isList, AlertNotificationUsedByNodeAlert) if err != nil { return out, err } @@ -402,26 +442,24 @@ func (alert *SNodeAlert) GetExtraDetails(ctx context.Context, userCred mcclient. return out, nil } -func (alert *SV1Alert) GetNotification() (*SAlertNotification, error) { - setting, err := alert.GetSettings() +func (alert *SV1Alert) GetNotification(usedby string) (*SNotification, error) { + alertNotis, err := alert.GetNotifications() if err != nil { return nil, err } - nIds := setting.Notifications - if len(nIds) == 0 { + if len(alertNotis) == 0 { return nil, nil } - // only get first notification setting - nId := nIds[0] - obj, err := AlertNotificationManager.GetNotification(nId) - if err != nil { - return nil, errors.Wrapf(err, "Get notificatoin %s", nId) + for _, an := range alertNotis { + if an.GetUsedBy() == usedby { + return an.GetNotification() + } } - return obj, nil + return nil, httperrors.NewNotFoundError("not found alert notification used by %s", usedby) } -func (alert *SV1Alert) UpdateNotification(channel, recipients *string) error { - obj, err := alert.GetNotification() +func (alert *SV1Alert) UpdateNotification(usedBy string, channel, recipients *string) error { + obj, err := alert.GetNotification(usedBy) if err != nil { return errors.Wrap(err, "Get notification when update") } @@ -445,30 +483,7 @@ func (alert *SV1Alert) UpdateNotification(channel, recipients *string) error { return err } -func (alert *SV1Alert) GetNotificationBySetting(setting *monitor.AlertSetting) *monitor.NotificationSettingOneCloud { - nIds := setting.Notifications - if len(nIds) == 0 { - return nil - } - // only get first notification setting - nId := nIds[0] - obj, err := AlertNotificationManager.GetNotification(nId) - if err != nil { - log.Errorf("Get notification by %s: %v", nId, err) - return nil - } - if obj == nil { - return nil - } - ocSetting := new(monitor.NotificationSettingOneCloud) - if err := obj.Settings.Unmarshal(ocSetting); err != nil { - log.Errorf("Unmarshal notification %s setting: %v", nId, err) - return nil - } - return ocSetting -} - -func (alert *SNodeAlert) CustomizeDelete( +func (alert *SV1Alert) CustomizeDelete( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { notis, err := alert.GetNotifications() @@ -476,10 +491,19 @@ func (alert *SNodeAlert) CustomizeDelete( return err } for _, noti := range notis { - if err := noti.CustomizeDelete(ctx, userCred, query, data); err != nil { + conf, err := noti.GetNotification() + if err != nil { return err } - if err := noti.Delete(ctx, userCred); err != nil { + if !conf.IsDefault { + if err := conf.CustomizeDelete(ctx, userCred, query, data); err != nil { + return err + } + if err := conf.Delete(ctx, userCred); err != nil { + return err + } + } + if err := noti.Detach(ctx, userCred); err != nil { return err } } @@ -498,7 +522,6 @@ func (alert *SNodeAlert) ValidateUpdateData( nameChange := false if input.NodeId != nil && *input.NodeId != details.NodeId { nameChange = true - ret.ResourceId = input.NodeId details.NodeId = *input.NodeId if err := alert.setNodeId(ctx, userCred, details.NodeId); err != nil { return nil, err @@ -506,7 +529,6 @@ func (alert *SNodeAlert) ValidateUpdateData( } if input.Type != nil && *input.Type != details.Type { nameChange = true - ret.ResourceType = input.Type details.Type = *input.Type if err := alert.setType(ctx, userCred, details.Type); err != nil { return nil, err @@ -573,15 +595,10 @@ func (alert *SNodeAlert) ValidateUpdateData( return nil, errors.Wrap(err, "get default data source") } // hack: update notification here - if err := alert.UpdateNotification(input.Channel, input.Recipients); err != nil { + if err := alert.UpdateNotification(AlertNotificationUsedByNodeAlert, input.Channel, input.Recipients); err != nil { return nil, errors.Wrap(err, "update notification") } tmpS := alert.getUpdateSetting(name, details, ds.GetId()) - os, err := alert.GetSettings() - if err != nil { - return nil, errors.Wrap(err, "get origin setting") - } - tmpS.Notifications = os.Notifications ret.Settings = &tmpS return alert.SAlert.ValidateUpdateData(ctx, userCred, query, ret) } @@ -597,7 +614,6 @@ func (alert *SNodeAlert) getUpdateSetting( Window: details.Window, Comparator: details.Comparator, Threshold: details.Threshold, - Level: details.Level, Channel: details.Channel, Recipients: details.Recipients, }, @@ -605,7 +621,14 @@ func (alert *SNodeAlert) getUpdateSetting( Type: details.Type, NodeId: details.NodeId, } - out := data.ToAlertCreateInput(name, details.Field, details.Measurement, details.DB, []string{details.NotifierId}) + data.Level = details.Level + out := data.ToAlertCreateInput(name, details.Field, details.Measurement, details.DB) out.Settings = *setAlertDefaultSetting(&out.Settings, dsId) return out.Settings } + +func (alert *SNodeAlert) CustomizeDelete( + ctx context.Context, userCred mcclient.TokenCredential, + query jsonutils.JSONObject, data jsonutils.JSONObject) error { + return alert.SV1Alert.CustomizeDelete(ctx, userCred, query, data) +} diff --git a/pkg/monitor/models/notification.go b/pkg/monitor/models/notification.go index 433137a60b..23551e9001 100644 --- a/pkg/monitor/models/notification.go +++ b/pkg/monitor/models/notification.go @@ -17,7 +17,6 @@ package models import ( "context" "database/sql" - "fmt" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -31,16 +30,14 @@ import ( ) var ( - AlertNotificationManager *SAlertNotificationManager - AlertNotificationStateManager *SAlertNotificationStateManager + NotificationManager *SNotificationManager ) func init() { - AlertNotificationManager = NewAlertNotificationManager() - AlertNotificationStateManager = NewAlertNotificationStateManager() + NotificationManager = NewNotificationManager() } -type SAlertNotificationManager struct { +type SNotificationManager struct { db.SVirtualResourceBaseManager } @@ -48,11 +45,11 @@ type SAlertNotificationStateManager struct { db.SStandaloneResourceBaseManager } -func NewAlertNotificationManager() *SAlertNotificationManager { - man := &SAlertNotificationManager{ +func NewNotificationManager() *SNotificationManager { + man := &SNotificationManager{ SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager( - SAlertNotification{}, - "alert_notifications_tbl", + SNotification{}, + "notifications_tbl", "alert_notification", "alert_notifications", ), @@ -61,20 +58,7 @@ func NewAlertNotificationManager() *SAlertNotificationManager { return man } -func NewAlertNotificationStateManager() *SAlertNotificationStateManager { - man := &SAlertNotificationStateManager{ - SStandaloneResourceBaseManager: db.NewStandaloneResourceBaseManager( - SAlertNotificationState{}, - "alert_notification_states_tbl", - "alert_notification_state", - "alert_notification_states", - ), - } - man.SetVirtualObject(man) - return man -} - -type SAlertNotification struct { +type SNotification struct { db.SVirtualResourceBase Type string `nullable:"false" list:"user" create:"required"` @@ -85,15 +69,7 @@ type SAlertNotification struct { Settings jsonutils.JSONObject `nullable:"false" list:"user" create:"required" update:"user"` } -type SAlertNotificationState struct { - db.SStandaloneResourceBase - - AlertId string `nullable:"false" list:"user" create:"required"` - NotifierId string `nullable:"false" list:"user" create:"required"` - State string `nullable:"false" list:"user" create:"required"` -} - -func (man *SAlertNotificationManager) GetPlugin(typ string) (*notifydrivers.NotifierPlugin, error) { +func (man *SNotificationManager) GetPlugin(typ string) (*notifydrivers.NotifierPlugin, error) { drv, err := notifydrivers.GetPlugin(typ) if err != nil { if errors.Cause(err) == notifydrivers.ErrUnsupportedNotificationType { @@ -105,7 +81,7 @@ func (man *SAlertNotificationManager) GetPlugin(typ string) (*notifydrivers.Noti return drv, nil } -func (man *SAlertNotificationManager) GetNotification(id string) (*SAlertNotification, error) { +func (man *SNotificationManager) GetNotification(id string) (*SNotification, error) { obj, err := man.FetchById(id) if err != nil { if errors.Cause(err) == sql.ErrNoRows { @@ -113,11 +89,11 @@ func (man *SAlertNotificationManager) GetNotification(id string) (*SAlertNotific } return nil, err } - return obj.(*SAlertNotification), nil + return obj.(*SNotification), nil } -func (man *SAlertNotificationManager) GetNotifications(ids []string) ([]SAlertNotification, error) { - objs := make([]SAlertNotification, 0) +func (man *SNotificationManager) GetNotifications(ids []string) ([]SNotification, error) { + objs := make([]SNotification, 0) notis := man.Query().SubQuery() q := notis.Query().Filter(sqlchemy.In(notis.Field("id"), ids)) if err := db.FetchModelObjects(man, q, &objs); err != nil { @@ -129,8 +105,8 @@ func (man *SAlertNotificationManager) GetNotifications(ids []string) ([]SAlertNo return objs, nil } -func (man *SAlertNotificationManager) GetNotificationsWithDefault(ids []string) ([]SAlertNotification, error) { - objs := make([]SAlertNotification, 0) +func (man *SNotificationManager) GetNotificationsWithDefault(ids []string) ([]SNotification, error) { + objs := make([]SNotification, 0) notis := man.Query().SubQuery() q := notis.Query().Filter( sqlchemy.OR( @@ -145,7 +121,7 @@ func (man *SAlertNotificationManager) GetNotificationsWithDefault(ids []string) return objs, nil } -func (man *SAlertNotificationManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, _ jsonutils.JSONObject, input monitor.AlertNotificationCreateInput) (monitor.AlertNotificationCreateInput, error) { +func (man *SNotificationManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, _ jsonutils.JSONObject, input monitor.NotificationCreateInput) (monitor.NotificationCreateInput, error) { if input.Type == "" { return input, httperrors.NewInputParameterError("notification type is empty") } @@ -164,12 +140,12 @@ func (man *SAlertNotificationManager) ValidateCreateData(ctx context.Context, us return plug.ValidateCreateData(userCred, input) } -func (man *SAlertNotificationManager) CreateOneCloudNotification( +func (man *SNotificationManager) CreateOneCloudNotification( ctx context.Context, userCred mcclient.TokenCredential, alertName string, channel string, - userIds []string) (*SAlertNotification, error) { + userIds []string) (*SNotification, error) { settings := &monitor.NotificationSettingOneCloud{ Channel: channel, UserIds: userIds, @@ -178,7 +154,7 @@ func (man *SAlertNotificationManager) CreateOneCloudNotification( if err != nil { return nil, errors.Wrapf(err, "generate name: %s", alertName) } - input := &monitor.AlertNotificationCreateInput{ + input := &monitor.NotificationCreateInput{ Name: newName, Type: monitor.AlertNotificationTypeOneCloud, Settings: jsonutils.Marshal(settings), @@ -187,127 +163,16 @@ func (man *SAlertNotificationManager) CreateOneCloudNotification( if err != nil { return nil, errors.Wrapf(err, "create notification input: %s", input.JSON(input)) } - return obj.(*SAlertNotification), nil + return obj.(*SNotification), nil } -func (n *SAlertNotification) GetStates() ([]SAlertNotificationState, error) { - states := AlertNotificationStateManager.Query().SubQuery() - q := states.Query().Filter(sqlchemy.Equals(states.Field("notifier_id"), n.GetId())) - objs := make([]SAlertNotificationState, 0) - if err := db.FetchModelObjects(AlertNotificationStateManager, q, &objs); err != nil { - return nil, err - } - return objs, nil -} - -func (n *SAlertNotification) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { - stats, err := n.GetStates() - if err != nil { - return err - } - for _, stat := range stats { - if err := stat.Delete(ctx, userCred); err != nil { - return err - } - } - return nil -} - -func (man *SAlertNotificationStateManager) ValidateCreateData( +func (n *SNotification) AttachToAlert( ctx context.Context, userCred mcclient.TokenCredential, - ownerId mcclient.IIdentityProvider, - _ jsonutils.JSONObject, - input monitor.AlertNotificationStateCreateInput) (monitor.AlertNotificationStateCreateInput, error) { - if input.AlertId == "" { - return input, httperrors.NewNotEmptyError("alert_id is empty") - } - if input.NotifierId == "" { - return input, httperrors.NewNotEmptyError("notifier_id is empty") - } - var name string - if obj, err := AlertManager.FetchById(input.AlertId); err != nil { - return input, err - } else { - name = obj.GetName() - } - if obj, err := AlertNotificationManager.FetchById(input.NotifierId); err != nil { - return input, err - } else { - name = fmt.Sprintf("%s_%s", name, obj.GetName()) - } - name, err := db.GenerateName(man, ownerId, name) - if err != nil { - return input, err - } - input.Name = name - return input, nil -} - -func (man *SAlertNotificationStateManager) CreateState( - ctx context.Context, - userCred mcclient.TokenCredential, - input monitor.AlertNotificationStateCreateInput) (*SAlertNotificationState, error) { - obj, err := db.DoCreate(man, ctx, userCred, nil, input.JSON(input), userCred) - if err != nil { - return nil, errors.Wrapf(err, "create notification state: %s", input.JSON(input)) - } - return obj.(*SAlertNotificationState), nil -} - -func (man *SAlertNotificationStateManager) GetState(alertId, notifierId string) (*SAlertNotificationState, error) { - state := man.Query().SubQuery() - q := state.Query().Filter(sqlchemy.AND( - sqlchemy.Equals(state.Field("alert_id"), alertId), - sqlchemy.Equals(state.Field("notifier_id"), notifierId))) - obj := new(SAlertNotificationState) - err := q.First(obj) - if err != nil { - if errors.Cause(err) == sql.ErrNoRows { - return nil, nil - } else { - return nil, err - } - } - return obj, nil -} - -func (man *SAlertNotificationStateManager) GetOrCreateState( - ctx context.Context, - userCred mcclient.TokenCredential, - alertId string, - notifierId string) (*SAlertNotificationState, error) { - state, err := man.GetState(alertId, notifierId) + alertId string) (*SAlertnotification, error) { + alert, err := AlertManager.GetAlert(alertId) if err != nil { return nil, err } - if state == nil { - return man.CreateState(ctx, userCred, monitor.AlertNotificationStateCreateInput{ - AlertId: alertId, - NotifierId: notifierId, - State: monitor.AlertNotificationStateUnknown, - }) - } - state.SetModelManager(man, state) - return state, nil -} - -func (state *SAlertNotificationState) SetToPending() error { - return state.setState(monitor.AlertNotificationStatePending) -} - -func (state *SAlertNotificationState) SetToCompleted() error { - return state.setState(monitor.AlertNotificationStateCompleted) -} - -func (state *SAlertNotificationState) setState(changeState monitor.AlertNotificationStateType) error { - _, err := db.Update(state, func() error { - state.State = string(changeState) - return nil - }) - return err -} - -func (state *SAlertNotificationState) GetState() monitor.AlertNotificationStateType { - return monitor.AlertNotificationStateType(state.State) + return alert.AttachNotification(ctx, userCred, n, monitor.AlertNotificationStateUnknown, "") } diff --git a/pkg/monitor/notifydrivers/drivers.go b/pkg/monitor/notifydrivers/drivers.go index ae3d38a908..3c716fdae0 100644 --- a/pkg/monitor/notifydrivers/drivers.go +++ b/pkg/monitor/notifydrivers/drivers.go @@ -56,7 +56,7 @@ var notifierFactories = make(map[string]*NotifierPlugin) type NotifierPlugin struct { Type string Factory NotifierFactory - ValidateCreateData func(cred mcclient.IIdentityProvider, input monitor.AlertNotificationCreateInput) (monitor.AlertNotificationCreateInput, error) + ValidateCreateData func(cred mcclient.IIdentityProvider, input monitor.NotificationCreateInput) (monitor.NotificationCreateInput, error) } func RegisterNotifier(plugin *NotifierPlugin) { diff --git a/pkg/monitor/service/handlers.go b/pkg/monitor/service/handlers.go index 3e80f2460b..4fea486e50 100644 --- a/pkg/monitor/service/handlers.go +++ b/pkg/monitor/service/handlers.go @@ -24,8 +24,9 @@ import ( func InitHandlers(app *appsrv.Application) { db.InitAllManagers() - db.RegisterModelManager(db.UserCacheManager) db.RegisterModelManager(db.TenantCacheManager) + db.RegisterModelManager(db.UserCacheManager) + db.RegistUserCredCacheUpdater() for _, manager := range []db.IModelManager{ db.OpsLog, db.Metadata, @@ -33,11 +34,18 @@ func InitHandlers(app *appsrv.Application) { models.AlertManager, models.NodeAlertManager, models.MeterAlertManager, - models.AlertNotificationManager, - models.AlertNotificationStateManager, + models.NotificationManager, } { db.RegisterModelManager(manager) handler := db.NewModelHandler(manager) dispatcher.AddModelDispatcher("", app, handler) } + + for _, manager := range []db.IJointModelManager{ + models.AlertNotificationManager, + } { + db.RegisterModelManager(manager) + handler := db.NewJointModelHandler(manager) + dispatcher.AddJointModelDispatcher("", app, handler) + } }