diff --git a/cmd/climc/shell/monitor/monitor_resource.go b/cmd/climc/shell/monitor/monitor_resource.go new file mode 100644 index 0000000000..2d49808217 --- /dev/null +++ b/cmd/climc/shell/monitor/monitor_resource.go @@ -0,0 +1,13 @@ +package monitor + +import ( + "yunion.io/x/onecloud/cmd/climc/shell" + "yunion.io/x/onecloud/pkg/mcclient/modules" + options "yunion.io/x/onecloud/pkg/mcclient/options/monitor" +) + +func init() { + cmd := shell.NewResourceCmd(modules.MonitorResourceManager) + cmd.Get("", new(options.MonitorResourceJointAlertOptions)) + +} diff --git a/pkg/apis/monitor/monitor_resource.go b/pkg/apis/monitor/monitor_resource.go new file mode 100644 index 0000000000..961ee6bcbe --- /dev/null +++ b/pkg/apis/monitor/monitor_resource.go @@ -0,0 +1,38 @@ +package monitor + +import ( + "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/apis/compute" +) + +const ( + MONITOR_RESOURCE_ALERT_STATUS_INIT = "init" + MONITOR_RESOURCE_ALERT_STATUS_ATTACH = "attach" + MONITOR_RESOURCE_ALERT_STATUS_ALERTING = "alerting" +) + +type MonitorResourceCreateInput struct { + apis.VirtualResourceCreateInput + apis.EnabledBaseResourceCreateInput + + ResId string `json:"res_id"` + ResType string `json:"res_type"` + AlertStatus string `json:"alert_status"` +} + +type MonitorResourceListInput struct { + apis.VirtualResourceListInput + apis.EnabledResourceBaseListInput + compute.ManagedResourceListInput + + ResId []string `json:"res_id"` + ResType string `json:"res_type"` + OnlyResId bool `json:"only_res_id"` +} + +type MonitorResourceDetails struct { + apis.VirtualResourceDetails + compute.CloudregionResourceInfo + + AttachAlertCount int64 `json:"attach_alert_count"` +} diff --git a/pkg/apis/monitor/monitor_resource_alert.go b/pkg/apis/monitor/monitor_resource_alert.go new file mode 100644 index 0000000000..a7b488be44 --- /dev/null +++ b/pkg/apis/monitor/monitor_resource_alert.go @@ -0,0 +1,23 @@ +package monitor + +import ( + "time" + + "yunion.io/x/onecloud/pkg/apis" +) + +type MonitorResourceJointListInput struct { + MonitorResourceId string `json:"monitor_resource_id"` + AlertId string `json:"alert_id"` +} + +type MonitorResourceJointCreateInput struct { + apis.Meta + MonitorResourceId string `json:"monitor_resource_id"` + AlertId string `json:"alert_id"` + + AlertRecordId string `width:"36" charset:"ascii" list:"user" update:"user"` + AlertState string `width:"18" charset:"ascii" list:"user" update:"user"` + TriggerTime time.Time `list:"user" update:"user" json:"trigger_time"` + Data EvalMatch `json:"data"` +} diff --git a/pkg/cloudcommon/db/opslog_const.go b/pkg/cloudcommon/db/opslog_const.go index deeabbfbde..308a7fd0eb 100644 --- a/pkg/cloudcommon/db/opslog_const.go +++ b/pkg/cloudcommon/db/opslog_const.go @@ -282,6 +282,9 @@ const ( ACT_UPDATE_RULE = "update_config" ACT_UPDATE_TAGS = "update_tags" + ACT_UPDATE_MONITOR_RESOURCE_JOINT = "update_monitor_resource_joint" + ACT_DETACH_MONITOR_RESOURCE_JOINT = "detach_monitor_resource_joint" + ACT_MERGE_NETWORK = "merge_network" ACT_MERGE_NETWORK_FAILED = "merge_network_failed" ) diff --git a/pkg/mcclient/modules/mod_monitor_resource.go b/pkg/mcclient/modules/mod_monitor_resource.go new file mode 100644 index 0000000000..a4916fc9d8 --- /dev/null +++ b/pkg/mcclient/modules/mod_monitor_resource.go @@ -0,0 +1,26 @@ +package modules + +import "yunion.io/x/onecloud/pkg/mcclient/modulebase" + +var ( + MonitorResourceManager *SMonitorResourceManager +) + +type SMonitorResourceManager struct { + *modulebase.ResourceManager +} + +func init() { + MonitorResourceManager = NewMonitorResourceManager() + + register(MonitorResourceManager) +} + +func NewMonitorResourceManager() *SMonitorResourceManager { + man := NewMonitorV2Manager("monitorresource", "monitorresources", + []string{"id", "name", "res_type", "res_id", "alert_state"}, + []string{}) + return &SMonitorResourceManager{ + ResourceManager: &man, + } +} diff --git a/pkg/mcclient/options/monitor/monitor_resource.go b/pkg/mcclient/options/monitor/monitor_resource.go new file mode 100644 index 0000000000..b01591aef3 --- /dev/null +++ b/pkg/mcclient/options/monitor/monitor_resource.go @@ -0,0 +1,18 @@ +package monitor + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient/options" +) + +type MonitorResourceJointAlertOptions struct { +} + +func (o *MonitorResourceJointAlertOptions) Params() (jsonutils.JSONObject, error) { + return options.ListStructToParams(o) +} + +func (o *MonitorResourceJointAlertOptions) GetId() string { + return "alert" +} diff --git a/pkg/monitor/alerting/notifier.go b/pkg/monitor/alerting/notifier.go index c8dc76a049..55f0294944 100644 --- a/pkg/monitor/alerting/notifier.go +++ b/pkg/monitor/alerting/notifier.go @@ -145,10 +145,14 @@ func (n *notificationService) getNeededNotifiers(nIds []string, evalCtx *EvalCon } } if shouldNotify || evalCtx.Rule.State == monitor.AlertStateAlerting { - n.createAlertRecordWhenNotify(evalCtx, shouldNotify) + go func() { + n.createAlertRecordWhenNotify(evalCtx, shouldNotify) + }() } if !shouldNotify && evalCtx.shouldUpdateAlertState() && evalCtx.NoDataFound { - n.detachAlertResourceWhenNodata(evalCtx) + go func() { + n.detachAlertResourceWhenNodata(evalCtx) + }() } return result, nil diff --git a/pkg/monitor/models/alert.go b/pkg/monitor/models/alert.go index 8594001c02..f27a9b9761 100644 --- a/pkg/monitor/models/alert.go +++ b/pkg/monitor/models/alert.go @@ -138,6 +138,7 @@ type SAlert struct { LastStateChange time.Time `list:"user"` StateChanges int `default:"0" nullable:"false" list:"user"` CustomizeConfig jsonutils.JSONObject `list:"user" create:"optional" update:"user"` + ResType string `width:"32" list:"user" update:"user"` } func (alert *SAlert) IsEnable() bool { diff --git a/pkg/monitor/models/alertrecord.go b/pkg/monitor/models/alertrecord.go index 8c173952cd..5de39c3a26 100644 --- a/pkg/monitor/models/alertrecord.go +++ b/pkg/monitor/models/alertrecord.go @@ -301,6 +301,10 @@ func (record *SAlertRecord) PostCreate(ctx context.Context, userCred mcclient.To log.Errorf("NotifyAlertResourceCount error: %v", err) return } + err = MonitorResourceManager.UpdateMonitorResourceAttachJoint(ctx, userCred, record) + if err != nil { + log.Errorf("UpdateMonitorResourceAttachJoint error: %v", err) + } } func (record *SAlertRecord) GetState() monitor.AlertStateType { diff --git a/pkg/monitor/models/commonalert.go b/pkg/monitor/models/commonalert.go index 90c0f9beca..cf38dd6e35 100644 --- a/pkg/monitor/models/commonalert.go +++ b/pkg/monitor/models/commonalert.go @@ -54,6 +54,7 @@ func init() { SAlertManager: *NewAlertManager(SCommonAlert{}, "commonalert", "commonalerts"), } CommonAlertManager.SetVirtualObject(CommonAlertManager) + //registry.RegisterService(CommonAlertManager) } type ISubscriptionManager interface { @@ -86,6 +87,41 @@ func (man *SCommonAlertManager) NamespaceScope() rbacutils.TRbacScope { return rbacutils.ScopeSystem } +func (manager *SCommonAlertManager) Init() error { + return nil +} + +func (man *SCommonAlertManager) Run(ctx context.Context) error { + alerts, err := man.GetAlerts(monitor.CommonAlertListInput{}) + if err != nil { + return err + } + errs := make([]error, 0) + for _, alert := range alerts { + err := alert.UpdateMonitorResourceJoint(ctx, auth.AdminCredential()) + if err != nil { + errs = append(errs, err) + } + + } + return errors.NewAggregate(errs) +} + +func (man *SCommonAlertManager) UpdateAlertsResType(ctx context.Context, userCred mcclient.TokenCredential) error { + alerts, err := man.GetAlerts(monitor.CommonAlertListInput{}) + if err != nil { + return err + } + errs := make([]error, 0) + for _, alert := range alerts { + err := alert.UpdateResType() + if err != nil { + errs = append(errs, err) + } + } + return errors.NewAggregate(errs) +} + func (man *SCommonAlertManager) ValidateCreateData( ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, @@ -336,6 +372,7 @@ func (alert *SCommonAlert) PostCreate(ctx context.Context, log.Errorln(errors.Wrap(err, "Alert PerformSetScope")) } CommonAlertManager.SetSubscriptionAlert(alert) + alert.StartUpdateMonitorAlertJointTask(ctx, userCred) } func (man *SCommonAlertManager) ListItemFilter( @@ -347,15 +384,19 @@ func (man *SCommonAlertManager) ListItemFilter( if err != nil { return nil, err } - q.Filter(sqlchemy.IsNull(q.Field("used_by"))) - - if len(query.Level) > 0 { - q.Equals("level", query.Level) - } + man.FieldListFilter(q, query) return q, nil } +func (man *SCommonAlertManager) FieldListFilter(q *sqlchemy.SQuery, input monitor.CommonAlertListInput) { + q.Filter(sqlchemy.IsNull(q.Field("used_by"))) + + if len(input.Level) > 0 { + q.Equals("level", input.Level) + } +} + func (manager *SCommonAlertManager) GetExportExtraKeys(ctx context.Context, keys stringutils2.SSortedStrings, rowMap map[string]string) *jsonutils.JSONDict { res := manager.SResourceBaseManager.GetExportExtraKeys(ctx, keys, rowMap) if keys.Contains("tenant") { @@ -482,6 +523,17 @@ func (man *SCommonAlertManager) GetAlert(id string) (*SCommonAlert, error) { return obj.(*SCommonAlert), nil } +func (manager *SCommonAlertManager) GetAlerts(input monitor.CommonAlertListInput) ([]SCommonAlert, error) { + alerts := make([]SCommonAlert, 0) + query := manager.Query() + manager.FieldListFilter(query, input) + err := db.FetchModelObjects(manager, query, &alerts) + if err != nil { + return nil, errors.Wrap(err, "SCommonAlertManagerGetAlerts err") + } + return alerts, nil +} + func (man *SCommonAlertManager) FetchCustomizeColumns( ctx context.Context, userCred mcclient.TokenCredential, @@ -918,6 +970,7 @@ func (alert *SCommonAlert) PostUpdate( alert.setMetaName(ctx, userCred, updateInput.MetaName) } CommonAlertManager.SetSubscriptionAlert(alert) + alert.StartUpdateMonitorAlertJointTask(ctx, userCred) } func (alert *SCommonAlert) UpdateNotification(ctx context.Context, userCred mcclient.TokenCredential, @@ -957,6 +1010,7 @@ func (alert *SCommonAlert) CustomizeDelete( return errors.Wrap(err, "customizeDeleteNotis") } alert.StartDeleteTask(ctx, userCred) + alert.StartDetachMonitorAlertJointTask(ctx, userCred) return alert.SAlert.CustomizeDelete(ctx, userCred, query, data) } @@ -1181,6 +1235,113 @@ func (manager *SCommonAlertManager) DetachAlertResourceByAlertId(ctx context.Con return } +func (alert *SCommonAlert) StartUpdateMonitorAlertJointTask(ctx context.Context, userCred mcclient.TokenCredential) error { + task, err := taskman.TaskManager.NewTask(ctx, "UpdateMonitorResourceJointTask", alert, userCred, jsonutils.NewDict(), "", "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (alert *SCommonAlert) UpdateMonitorResourceJoint(ctx context.Context, userCred mcclient.TokenCredential) error { + setting, _ := alert.GetSettings() + inputQuery := monitor.MetricInputQuery{ + MetricQuery: make([]*monitor.AlertQuery, 0), + } + var resType string + for _, con := range setting.Conditions { + measurement, _ := MetricMeasurementManager.GetCache().Get(con.Query.Model.Measurement) + if measurement == nil { + continue + } + if !utils.IsInStringArray(measurement.ResType, []string{monitor.METRIC_RES_TYPE_HOST, + monitor.METRIC_RES_TYPE_GUEST}) { + continue + } + resType = measurement.ResType + inputQuery.MetricQuery = append(inputQuery.MetricQuery, &con.Query) + } + if len(inputQuery.MetricQuery) == 0 { + return nil + } + metrics, err := doQuery(inputQuery) + if err != nil { + return errors.Wrap(err, "doQuery err") + } + resourceIds := make([]string, 0) + for _, serie := range metrics.Series { + resourceKeyId := monitor.MEASUREMENT_TAG_ID[resType] + resourceId := serie.Tags[resourceKeyId] + if len(resourceId) == 0 { + continue + } + resourceIds = append(resourceIds, resourceId) + } + joints, _ := MonitorResourceAlertManager.GetJoinsByListInput(monitor.MonitorResourceJointListInput{AlertId: alert.GetId()}) +jointLoop: + for _, joint := range joints { + for i, resId := range resourceIds { + if resId == joint.MonitorResourceId { + resourceIds = append(resourceIds[0:i], resourceIds[i+1:]...) + continue jointLoop + } + } + joint.Detach(ctx, userCred) + } + if len(resourceIds) == 0 { + return nil + } + monitorResources, _ := MonitorResourceManager.GetMonitorResources(monitor.MonitorResourceListInput{ResId: resourceIds}) + errs := make([]error, 0) + for _, monRes := range monitorResources { + err := monRes.AttachAlert(ctx, userCred, alert.GetId()) + if err != nil { + errs = append(errs, err) + } + monRes.UpdateAlertState() + } + + if len(errs) != 0 { + return errors.NewAggregate(errs) + } + return nil +} + +func (alert *SCommonAlert) StartDetachMonitorAlertJointTask(ctx context.Context, + userCred mcclient.TokenCredential) error { + task, err := taskman.TaskManager.NewTask(ctx, "DetachMonitorResourceJointTask", alert, userCred, jsonutils.NewDict(), "", "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (alert *SCommonAlert) DetachMonitorResourceJoint(ctx context.Context, userCred mcclient.TokenCredential) error { + err := MonitorResourceAlertManager.DetachJoint(ctx, userCred, monitor.MonitorResourceJointListInput{AlertId: alert.GetId()}) + if err != nil { + return errors.Wrap(err, "SCommonAlert DetachJoint err") + } + return nil +} + +func (alert *SCommonAlert) UpdateResType() error { + setting, _ := alert.GetSettings() + measurement, _ := MetricMeasurementManager.GetCache().Get(setting.Conditions[0].Query.Model.Measurement) + if measurement == nil { + return nil + } + _, err := db.Update(alert, func() error { + alert.ResType = measurement.ResType + return nil + }) + if err != nil { + return errors.Wrapf(err, "alert:%s UpdateResType err", alert.Name) + } + return nil +} + type SCompanyInfo struct { Copyright string `json:"copyright"` Name string `json:"name"` diff --git a/pkg/monitor/models/metric.go b/pkg/monitor/models/metric.go index 748f74957a..2f587260ca 100644 --- a/pkg/monitor/models/metric.go +++ b/pkg/monitor/models/metric.go @@ -409,6 +409,11 @@ func (man *SMetricMeasurementManager) Run(ctx context.Context) error { return errors.Wrap(err, "init metric json error") } log.Infoln("========metric_measurement_field init finish==========") + err = CommonAlertManager.UpdateAlertsResType(ctx, auth.AdminCredential()) + if err != nil { + return errors.Wrap(err, "CommonAlertManager UpdateAlertsResType err") + } + log.Infoln("========UpdateAlertsResType Finish==========") return nil } diff --git a/pkg/monitor/models/monitor_resource.go b/pkg/monitor/models/monitor_resource.go new file mode 100644 index 0000000000..fb4b86e935 --- /dev/null +++ b/pkg/monitor/models/monitor_resource.go @@ -0,0 +1,338 @@ +package models + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + "yunion.io/x/sqlchemy" + + "yunion.io/x/onecloud/pkg/apis/monitor" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +var ( + MonitorResourceManager *SMonitorResourceManager +) + +func init() { + MonitorResourceManager = &SMonitorResourceManager{ + SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager( + &SMonitorResource{}, + "monitor_resource_tbl", + "monitorresource", + "monitorresources", + ), + } + MonitorResourceManager.SetVirtualObject(MonitorResourceManager) + RegistryResourceSync(NewGuestResourceSync()) + RegistryResourceSync(NewHostResourceSync()) +} + +type SMonitorResourceManager struct { + db.SVirtualResourceBaseManager + db.SEnabledResourceBaseManager +} + +type SMonitorResource struct { + db.SVirtualResourceBase + db.SEnabledResourceBase + + AlertState string `width:"36" charset:"ascii" list:"user" default:"init" update:"user" json:"alert_state"` + ResId string `width:"256" charset:"ascii" index:"true" list:"user" update:"user" json:"res_id"` + ResType string `width:"36" charset:"ascii" list:"user" update:"user" json:"res_type"` +} + +func (manager *SMonitorResourceManager) SyncResources(ctx context.Context, userCred mcclient.TokenCredential, + isStart bool) { + for _, sync := range GetResourceSyncMap() { + err := sync.SyncResources(ctx, userCred, jsonutils.NewDict()) + if err != nil { + log.Errorf("resType:%s SyncResources err:%v", sync.SyncType(), err) + } + } + err := CommonAlertManager.Run(ctx) + if err != nil { + log.Errorf("CommonAlertManager UpdateMonitorResourceJoint err:%v", err) + return + } + log.Infoln("====SMonitorResourceManager SyncResources End====") +} + +func (manager *SMonitorResourceManager) GetMonitorResources(input monitor.MonitorResourceListInput) ([]SMonitorResource, error) { + monitorResources := make([]SMonitorResource, 0) + query := manager.Query() + if input.OnlyResId { + query = query.AppendField(query.Field("id"), query.Field("res_id")) + } + query = manager.FieldListFilter(query, input) + err := db.FetchModelObjects(manager, query, &monitorResources) + if err != nil { + return nil, errors.Wrap(err, "SMonitorResourceManager FetchModelObjects err") + } + return monitorResources, nil +} + +func (manager *SMonitorResourceManager) GetMonitorResourceById(id string) (*SMonitorResource, error) { + iModel, err := db.FetchById(manager, id) + if err != nil { + return nil, errors.Wrapf(err, fmt.Sprintf("GetMonitorResourceById:%s err", id)) + } + return iModel.(*SMonitorResource), nil +} + +func (manager *SMonitorResourceManager) ListItemFilter( + ctx context.Context, q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query monitor.MonitorResourceListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") + } + q, err = manager.SEnabledResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledResourceBaseManager.ListItemFilter") + } + + q = manager.FieldListFilter(q, query) + + return q, nil +} + +func (manager *SMonitorResourceManager) FieldListFilter(q *sqlchemy.SQuery, query monitor.MonitorResourceListInput) *sqlchemy.SQuery { + if len(query.ResType) != 0 { + q.Equals("res_type", query.ResType) + } + if len(query.ResId) != 0 { + q.In("res_id", query.ResId) + } + return q +} + +func (man *SMonitorResourceManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input monitor.SuggestSysAlertListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (man *SMonitorResourceManager) HasName() bool { + return false +} + +func (man *SMonitorResourceManager) ValidateCreateData( + ctx context.Context, userCred mcclient.TokenCredential, + ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, + data monitor.MonitorResourceCreateInput) (monitor.MonitorResourceCreateInput, error) { + //rule 查询到资源信息后没有将资源id,进行转换 + if len(data.ResId) == 0 { + return data, httperrors.NewInputParameterError("not found res_id %q", data.ResId) + } + if len(data.ResType) == 0 { + return data, httperrors.NewInputParameterError("not found res_type %q", data.ResType) + } + return data, nil +} + +func (self *SMonitorResource) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, + ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error { + return nil +} + +func (man *SMonitorResourceManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []monitor.MonitorResourceDetails { + rows := make([]monitor.MonitorResourceDetails, len(objs)) + virtRows := man.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = monitor.MonitorResourceDetails{ + VirtualResourceDetails: virtRows[i], + } + rows[i] = objs[i].(*SMonitorResource).getMoreDetails(rows[i]) + } + return rows +} + +func (self *SMonitorResource) AttachAlert(ctx context.Context, userCred mcclient.TokenCredential, alertId string) error { + iModel, _ := db.NewModelObject(MonitorResourceAlertManager) + input := monitor.MonitorResourceJointCreateInput{ + MonitorResourceId: self.ResId, + AlertId: alertId, + AlertState: monitor.MONITOR_RESOURCE_ALERT_STATUS_ATTACH, + } + data := input.JSON(&input) + err := data.Unmarshal(iModel) + if err != nil { + return errors.Wrap(err, "MonitorResourceJointCreateInput unmarshal to joint err") + } + if err := MonitorResourceAlertManager.TableSpec().Insert(ctx, iModel); err != nil { + return errors.Wrap(err, "insert MonitorResourceJoint model err") + } + return nil +} + +func (self *SMonitorResource) UpdateAlertState() error { + joints, _ := MonitorResourceAlertManager.GetJoinsByListInput(monitor.MonitorResourceJointListInput{MonitorResourceId: self.ResId}) + jointState := monitor.MONITOR_RESOURCE_ALERT_STATUS_ATTACH + if len(joints) == 0 { + jointState = monitor.MONITOR_RESOURCE_ALERT_STATUS_INIT + } + for _, joint := range joints { + if joint.AlertState == monitor.MONITOR_RESOURCE_ALERT_STATUS_ALERTING && time.Now().Sub(joint. + TriggerTime) < time.Minute*30 { + jointState = monitor.MONITOR_RESOURCE_ALERT_STATUS_ALERTING + } + } + _, err := db.Update(self, func() error { + self.AlertState = jointState + return nil + }) + if err != nil { + return errors.Wrapf(err, "SMonitorResource:%s UpdateAlertState err", self.Name) + } + return nil +} + +func (self *SMonitorResource) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error { + err := self.DetachJoint(ctx, userCred) + if err != nil { + return err + } + return self.SVirtualResourceBase.Delete(ctx, userCred) +} + +func (self *SMonitorResource) DetachJoint(ctx context.Context, userCred mcclient.TokenCredential) error { + err := MonitorResourceAlertManager.DetachJoint(ctx, userCred, + monitor.MonitorResourceJointListInput{MonitorResourceId: self.ResId}) + if err != nil { + return errors.Wrap(err, "SMonitorResource DetachJoint err") + } + return nil +} + +func (self *SMonitorResource) getMoreDetails(out monitor.MonitorResourceDetails) monitor.MonitorResourceDetails { + joints, err := MonitorResourceAlertManager.GetJoinsByListInput(monitor. + MonitorResourceJointListInput{MonitorResourceId: self.ResId}) + if err != nil { + log.Errorf("getMoreDetails err:%v", err) + } + out.AttachAlertCount = int64(len(joints)) + return out +} + +func (manager *SMonitorResourceManager) AllowGetPropertyAlert(ctx context.Context, userCred mcclient.TokenCredential, + query jsonutils.JSONObject) bool { + return true +} + +type AlertStatusCount struct { + CountId int64 + AlertState string +} + +func (manager *SMonitorResourceManager) GetPropertyAlert(ctx context.Context, userCred mcclient.TokenCredential, + query jsonutils.JSONObject) (jsonutils.JSONObject, error) { + scope, _ := query.GetString("scope") + if len(scope) == 0 { + scope = "system" + } + result := jsonutils.NewDict() + for resType, _ := range GetResourceSyncMap() { + query := manager.Query("alert_state") + manager.FilterByOwner(query, userCred, rbacutils.TRbacScope(scope)) + query.AppendField(sqlchemy.COUNT("count_id", query.Field("id"))) + input := monitor.MonitorResourceListInput{ResType: resType} + query = manager.FieldListFilter(query, input) + query.GroupBy(query.Field("alert_state")) + log.Errorf("query:%s", query.String()) + rows, err := query.Rows() + if err != nil { + return nil, errors.Wrap(err, "getMonitorResourceAlert query err") + } + total := int64(0) + resTypeDict := jsonutils.NewDict() + for rows.Next() { + row := new(AlertStatusCount) + err := query.Row2Struct(rows, row) + if err != nil { + return nil, errors.Wrap(err, "MonitorResource Row2Struct err") + } + resTypeDict.Add(jsonutils.NewInt(row.CountId), row.AlertState) + total += row.CountId + } + resTypeDict.Add(jsonutils.NewInt(total), "total") + result.Add(resTypeDict, resType) + } + return result, nil +} + +func (manager *SMonitorResourceManager) UpdateMonitorResourceAttachJoint(ctx context.Context, + userCred mcclient.TokenCredential, alertRecord *SAlertRecord) error { + if !utils.IsInStringArray(alertRecord.ResType, []string{monitor.METRIC_RES_TYPE_HOST, + monitor.METRIC_RES_TYPE_GUEST}) { + return nil + } + + matches, _ := alertRecord.GetEvalData() + errs := make([]error, 0) + for _, matche := range matches { + resId := matche.Tags[monitor.MEASUREMENT_TAG_ID[alertRecord.ResType]] + if len(resId) == 0 { + continue + } + monitorResources, err := manager.GetMonitorResources(monitor.MonitorResourceListInput{ResType: alertRecord.ResType, ResId: []string{resId}}) + if err != nil { + errs = append(errs, errors.Wrapf(err, "SMonitorResourceManager GetMonitorResources by resId:%s err", resId)) + continue + } + for _, res := range monitorResources { + err := res.UpdateAttachJoint(alertRecord, matche) + if err != nil { + errs = append(errs, err) + } + } + } + return errors.NewAggregate(errs) +} + +func (self *SMonitorResource) UpdateAttachJoint(alertRecord *SAlertRecord, match monitor.EvalMatch) error { + joints, err := MonitorResourceAlertManager.GetJoinsByListInput(monitor.MonitorResourceJointListInput{MonitorResourceId: self. + ResId, AlertId: alertRecord.AlertId}) + if err != nil { + return errors.Wrapf(err, "SMonitorResource:%s UpdateAttachJoint err", self.Name) + } + errs := make([]error, 0) + for _, joint := range joints { + err := joint.UpdateAlertRecordData(alertRecord, &match) + if err != nil { + errs = append(errs, errors.Wrapf(err, "joint %s:%s %s:%s UpdateAlertRecordData err", + MonitorResourceAlertManager.GetMasterFieldName(), self.ResId, + MonitorResourceAlertManager.GetSlaveFieldName(), alertRecord.AlertId)) + } + } + self.UpdateAlertState() + return errors.NewAggregate(errs) + +} diff --git a/pkg/monitor/models/monitor_resource_alert.go b/pkg/monitor/models/monitor_resource_alert.go new file mode 100644 index 0000000000..dc7f9ebb33 --- /dev/null +++ b/pkg/monitor/models/monitor_resource_alert.go @@ -0,0 +1,123 @@ +package models + +import ( + "context" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/apis/monitor" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/mcclient" +) + +var ( + MonitorResourceAlertManager *SMonitorResourceAlertManager +) + +func init() { + MonitorResourceAlertManager = &SMonitorResourceAlertManager{ + SJointResourceBaseManager: db.NewJointResourceBaseManager( + SMonitorResourceAlert{}, + "monitor_resource_alert_tbl", + "monitorresourcealert", + "monitorresourcealerts", + MonitorResourceManager, CommonAlertManager), + } + MonitorResourceAlertManager.SetVirtualObject(MonitorResourceAlertManager) +} + +type SMonitorResourceAlertManager struct { + db.SJointResourceBaseManager +} + +type SMonitorResourceAlert struct { + db.SJointResourceBase + + MonitorResourceId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true" json:"monitor_resource_id"` + AlertId string `width:"36" charset:"ascii" list:"user" create:"required" index:"true"` + AlertRecordId string `width:"36" charset:"ascii" list:"user" update:"user"` + AlertState string `width:"18" charset:"ascii" default:"init" list:"user" update:"user"` + TriggerTime time.Time `list:"user" update:"user" json:"trigger_time"` + Data jsonutils.JSONObject `list:"user" update:"user"` +} + +func (manager *SMonitorResourceAlertManager) GetMasterFieldName() string { + return "monitor_resource_id" +} + +func (manager *SMonitorResourceAlertManager) GetSlaveFieldName() string { + return "alert_id" +} + +func (manager *SMonitorResourceAlertManager) DetachJoint(ctx context.Context, userCred mcclient.TokenCredential, + input monitor.MonitorResourceJointListInput) error { + joints, err := manager.GetJoinsByListInput(input) + if err != nil { + return errors.Wrapf(err, "SMonitorResourceAlertManager DetachJoint when GetJoinsByListInput err,input:%v", input) + } + errs := make([]error, 0) + for _, joint := range joints { + err := joint.Delete(ctx, userCred) + if err != nil { + errs = append(errs, errors.Wrapf(err, "joint %s:%s ,%s:%s", manager.GetMasterFieldName(), + joint.MonitorResourceId, manager.GetSlaveFieldName(), joint.AlertId)) + continue + } + resources, err := MonitorResourceManager.GetMonitorResources(monitor.MonitorResourceListInput{ResId: []string{joint. + MonitorResourceId}}) + if err != nil { + errs = append(errs, err) + } + for _, res := range resources { + err := res.UpdateAlertState() + if err != nil { + errs = append(errs, err) + } + } + } + return errors.NewAggregate(errs) +} + +func (obj *SMonitorResourceAlert) Detach(ctx context.Context, userCred mcclient.TokenCredential) error { + return db.DetachJoint(ctx, userCred, obj) +} + +func (obj *SMonitorResourceAlert) GetAlert() (*SCommonAlert, error) { + sObj, err := CommonAlertManager.FetchById(obj.AlertId) + if err != nil { + return nil, err + } + return sObj.(*SCommonAlert), nil +} + +func (manager *SMonitorResourceAlertManager) GetJoinsByListInput(input monitor.MonitorResourceJointListInput) ([]SMonitorResourceAlert, error) { + joints := make([]SMonitorResourceAlert, 0) + query := manager.Query() + + if len(input.MonitorResourceId) != 0 { + query.Equals(manager.GetMasterFieldName(), input.MonitorResourceId) + } + if len(input.AlertId) != 0 { + query.Equals(manager.GetSlaveFieldName(), input.AlertId) + } + err := db.FetchModelObjects(manager, query, &joints) + if err != nil { + return nil, errors.Wrapf(err, "FetchModelObjects by GetJoinsByMasterId:%s err", input) + } + return joints, nil +} + +func (obj *SMonitorResourceAlert) UpdateAlertRecordData(record *SAlertRecord, match *monitor.EvalMatch) error { + if _, err := db.Update(obj, func() error { + obj.AlertRecordId = record.GetId() + obj.AlertState = record.State + obj.TriggerTime = record.CreatedAt + obj.Data = jsonutils.Marshal(match) + return nil + }); err != nil { + return err + } + return nil +} diff --git a/pkg/monitor/models/monitor_resource_sync.go b/pkg/monitor/models/monitor_resource_sync.go new file mode 100644 index 0000000000..3b2b2f5a12 --- /dev/null +++ b/pkg/monitor/models/monitor_resource_sync.go @@ -0,0 +1,242 @@ +package models + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/apis/monitor" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/hostman/hostinfo/hostconsts" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + "yunion.io/x/onecloud/pkg/mcclient/modulebase" + mc_mds "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var ( + resourceSyncMap map[string]IResourceSync + guestResourceSync IResourceSync + hostResourceSync IResourceSync +) + +func RegistryResourceSync(sync IResourceSync) error { + if resourceSyncMap == nil { + resourceSyncMap = make(map[string]IResourceSync) + } + if _, ok := resourceSyncMap[sync.SyncType()]; ok { + return errors.Errorf(fmt.Sprintf("syncType:%s has registered", sync.SyncType())) + } + resourceSyncMap[sync.SyncType()] = sync + return nil +} + +func GetResourceSyncByType(syncType string) IResourceSync { + if resourceSyncMap == nil { + resourceSyncMap = make(map[string]IResourceSync) + } + return resourceSyncMap[syncType] +} + +func GetResourceSyncMap() map[string]IResourceSync { + if resourceSyncMap == nil { + resourceSyncMap = make(map[string]IResourceSync) + } + return resourceSyncMap +} + +type SyncObject struct { + sync IResourceSync +} + +type IResourceSync interface { + SyncResources(ctx context.Context, userCred mcclient.TokenCredential, param jsonutils.JSONObject) error + SyncType() string +} + +type GuestResourceSync struct { + SyncObject +} + +func NewGuestResourceSync() IResourceSync { + if guestResourceSync == nil { + sync := new(GuestResourceSync) + obj := newSyncObj(sync) + sync.SyncObject = obj + guestResourceSync = sync + } + + return guestResourceSync +} + +func (g *GuestResourceSync) SyncType() string { + return monitor.METRIC_RES_TYPE_GUEST +} + +type HostResourceSync struct { + SyncObject +} + +func (self *HostResourceSync) SyncType() string { + return monitor.METRIC_RES_TYPE_HOST +} + +func NewHostResourceSync() IResourceSync { + if hostResourceSync == nil { + sync := new(HostResourceSync) + obj := newSyncObj(sync) + sync.SyncObject = obj + hostResourceSync = sync + } + return hostResourceSync +} + +func newSyncObj(sync IResourceSync) SyncObject { + return SyncObject{sync: sync} +} + +func (self *SyncObject) SyncResources(ctx context.Context, userCred mcclient.TokenCredential, + param jsonutils.JSONObject) error { + log.Errorf("start sync %s", self.sync.SyncType()) + resources, err := GetOnecloudResources(self.sync.SyncType()) + if err != nil { + return errors.Wrapf(err, fmt.Sprintf("syncType:%s GetOnecloudResources err", self.sync.SyncType())) + } + input := monitor.MonitorResourceListInput{ + OnlyResId: true, + ResType: self.sync.SyncType(), + } + monResources, err := MonitorResourceManager.GetMonitorResources(input) + if err != nil { + return errors.Wrap(err, "GetMonitorResources err") + } + errs := make([]error, 0) +monLoop: + for i, _ := range monResources { + for index, res := range resources { + resId, _ := res.GetString("id") + if resId == monResources[i].ResId { + resource, err := MonitorResourceManager.GetMonitorResourceById(monResources[i].GetId()) + if err != nil { + errs = append(errs, err) + continue monLoop + } + _, err = db.Update(resource, func() error { + res.Unmarshal(resource) + return nil + }) + if err != nil { + errs = append(errs, errors.Wrapf(err, "monitorResource:%s Update err", resource.Name)) + continue monLoop + } + if index == len(resources)-1 { + resources = resources[0:index] + } else { + resources = append(resources[0:index], resources[index+1:]...) + } + + index-- + continue monLoop + } + } + resource, _ := MonitorResourceManager.GetMonitorResourceById(monResources[i].GetId()) + err := resource.RealDelete(ctx, userCred) + if err != nil { + errs = append(errs, errors.Wrapf(err, "delete monitorResource:%s err", resource.GetId())) + } + } + for _, res := range resources { + createData := self.newMonitorResourceCreateInput(res) + _, err = db.DoCreate(MonitorResourceManager, ctx, userCred, nil, createData, + userCred) + if err != nil { + name, _ := createData.GetString("name") + errs = append(errs, errors.Wrapf(err, "monitorResource:%s resType:%s DoCreate err", name, self.sync.SyncType())) + } + } + return errors.NewAggregate(errs) +} + +func (self *SyncObject) newMonitorResourceCreateInput(input jsonutils.JSONObject) jsonutils.JSONObject { + monitorResource := jsonutils.DeepCopy(input).(*jsonutils.JSONDict) + id, _ := monitorResource.GetString("id") + monitorResource.Add(jsonutils.NewString(id), "res_id") + monitorResource.Remove("id") + monitorResource.Add(jsonutils.NewString(self.sync.SyncType()), "res_type") + + return monitorResource +} + +func GetOnecloudResources(resTyep string) ([]jsonutils.JSONObject, error) { + var err error + allResources := make([]jsonutils.JSONObject, 0) + + query := jsonutils.NewDict() + query.Add(jsonutils.NewStringArray([]string{"running", "ready"}), "status") + query.Add(jsonutils.NewString("true"), "admin") + switch resTyep { + case monitor.METRIC_RES_TYPE_HOST: + query.Set("host-type", jsonutils.NewString(hostconsts.TELEGRAF_TAG_KEY_HYPERVISOR)) + allResources, err = ListAllResources(&mc_mds.Hosts, query) + case monitor.METRIC_RES_TYPE_GUEST: + allResources, err = ListAllResources(&mc_mds.Servers, query) + case monitor.METRIC_RES_TYPE_RDS: + allResources, err = ListAllResources(&mc_mds.DBInstance, query) + case monitor.METRIC_RES_TYPE_REDIS: + allResources, err = ListAllResources(&mc_mds.ElasticCache, query) + case monitor.METRIC_RES_TYPE_OSS: + allResources, err = ListAllResources(&mc_mds.Buckets, query) + case monitor.METRIC_RES_TYPE_CLOUDACCOUNT: + query.Remove("status") + query.Add(jsonutils.NewBool(true), "enabled") + allResources, err = ListAllResources(&mc_mds.Cloudaccounts, query) + case monitor.METRIC_RES_TYPE_TENANT: + allResources, err = ListAllResources(&mc_mds.Projects, query) + case monitor.METRIC_RES_TYPE_DOMAIN: + allResources, err = ListAllResources(&mc_mds.Domains, query) + case monitor.METRIC_RES_TYPE_STORAGE: + query.Remove("status") + allResources, err = ListAllResources(&mc_mds.Storages, query) + default: + query := jsonutils.NewDict() + query.Set("brand", jsonutils.NewString(hostconsts.TELEGRAF_TAG_ONECLOUD_BRAND)) + query.Set("host-type", jsonutils.NewString(hostconsts.TELEGRAF_TAG_KEY_HYPERVISOR)) + allResources, err = ListAllResources(&mc_mds.Hosts, query) + } + + if err != nil { + return nil, errors.Wrap(err, "NoDataQueryCondition Host list error") + } + return allResources, nil +} + +func ListAllResources(manager modulebase.Manager, params *jsonutils.JSONDict) ([]jsonutils.JSONObject, error) { + if params == nil { + params = jsonutils.NewDict() + } + params.Add(jsonutils.NewString("system"), "scope") + params.Add(jsonutils.NewInt(0), "limit") + params.Add(jsonutils.NewBool(true), "details") + var count int + session := auth.GetAdminSession(context.Background(), "", "") + objs := make([]jsonutils.JSONObject, 0) + for { + params.Set("offset", jsonutils.NewInt(int64(count))) + result, err := manager.List(session, params) + if err != nil { + return nil, errors.Wrapf(err, "list %s resources with params %s", manager.KeyString(), params.String()) + } + for _, data := range result.Data { + objs = append(objs, data) + } + total := result.Total + count = count + len(result.Data) + if count >= total { + break + } + } + return objs, nil +} diff --git a/pkg/monitor/options/options.go b/pkg/monitor/options/options.go index e0eabe20d1..c6a15917d6 100644 --- a/pkg/monitor/options/options.go +++ b/pkg/monitor/options/options.go @@ -29,6 +29,7 @@ type AlerterOptions struct { AlertingNotificationTimeoutSeconds int64 `help:"alerting notification timeout" default:"30"` InitScopeSuggestConfigIntervalSeconds int `help:"internal to init scope suggest configs" default:"900"` InitAlertResourceAdminRoleUsersIntervalSeconds int `help:"internal to init alert resource admin role users " default:"3600"` + MonitorResourceSyncIntervalSeconds int `help:"internal to sync monitor resource,unit: h " default:"1"` } var ( diff --git a/pkg/monitor/service/handlers.go b/pkg/monitor/service/handlers.go index e5c1355532..3153aec316 100644 --- a/pkg/monitor/service/handlers.go +++ b/pkg/monitor/service/handlers.go @@ -62,6 +62,7 @@ func InitHandlers(app *appsrv.Application) { models.AlertDashBoardManager, models.GetAlertResourceManager(), models.AlertPanelManager, + models.MonitorResourceManager, } { db.RegisterModelManager(manager) handler := db.NewModelHandler(manager) @@ -80,6 +81,7 @@ func InitHandlers(app *appsrv.Application) { models.MetricManager, models.GetAlertResourceAlertManager(), models.AlertDashBoardPanelManager, + models.MonitorResourceAlertManager, } { db.RegisterModelManager(manager) handler := db.NewJointModelHandler(manager) diff --git a/pkg/monitor/service/service.go b/pkg/monitor/service/service.go index 4cd0112e1b..5de287e3ce 100644 --- a/pkg/monitor/service/service.go +++ b/pkg/monitor/service/service.go @@ -66,6 +66,7 @@ func StartService() { cron.AddJobAtIntervalsWithStartRun("InitAlertResourceAdminRoleUsers", time.Duration(opts.InitAlertResourceAdminRoleUsersIntervalSeconds)*time.Second, models.GetAlertResourceManager().GetAdminRoleUsers, true) cron.AddJobEveryFewDays("DeleteRecordsOfThirtyDaysAgoRecords", 1, 0, 0, 0, models.AlertRecordManager.DeleteRecordsOfThirtyDaysAgo, false) + cron.AddJobAtIntervalsWithStartRun("MonitorResourceSync", time.Duration(opts.MonitorResourceSyncIntervalSeconds)*time.Minute*60, models.MonitorResourceManager.SyncResources, true) cron.Start() defer cron.Stop() diff --git a/pkg/monitor/tasks/detach_monitor_resource_task.go b/pkg/monitor/tasks/detach_monitor_resource_task.go new file mode 100644 index 0000000000..c2bfe51e0c --- /dev/null +++ b/pkg/monitor/tasks/detach_monitor_resource_task.go @@ -0,0 +1,40 @@ +package tasks + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/monitor/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type DetachMonitorResourceJointTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(&DetachMonitorResourceJointTask{}) +} + +func (self *DetachMonitorResourceJointTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) { + alert := obj.(*models.SCommonAlert) + err := alert.DetachMonitorResourceJoint(ctx, self.GetUserCred()) + if err != nil { + msg := jsonutils.NewString(fmt.Sprintf("alert:%s DetachMonitorResourceJoint err:%v", alert.Name, err)) + self.taskFail(ctx, alert, msg) + return + } + logclient.AddActionLogWithStartable(self, alert, logclient.ACT_DETACH_MONITOR_RESOURCE_JOINT, nil, self.UserCred, true) + self.SetStageComplete(ctx, nil) +} + +func (self *DetachMonitorResourceJointTask) taskFail(ctx context.Context, alert *models.SCommonAlert, msg jsonutils.JSONObject) { + db.OpsLog.LogEvent(alert, db.ACT_DETACH_MONITOR_RESOURCE_JOINT, msg, self.GetUserCred()) + logclient.AddActionLogWithStartable(self, alert, logclient.ACT_DETACH_MONITOR_RESOURCE_JOINT, msg, self.UserCred, false) + self.SetStageFailed(ctx, msg) + return +} diff --git a/pkg/monitor/tasks/update_monitor_resource_task.go b/pkg/monitor/tasks/update_monitor_resource_task.go new file mode 100644 index 0000000000..67f3ae79c5 --- /dev/null +++ b/pkg/monitor/tasks/update_monitor_resource_task.go @@ -0,0 +1,40 @@ +package tasks + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/monitor/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type UpdateMonitorResourceJointTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(&UpdateMonitorResourceJointTask{}) +} + +func (self *UpdateMonitorResourceJointTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) { + alert := obj.(*models.SCommonAlert) + err := alert.UpdateMonitorResourceJoint(ctx, self.GetUserCred()) + if err != nil { + msg := jsonutils.NewString(fmt.Sprintf("alert:%s UpdateMonitorResourceJoint err:%v", alert.Name, err)) + self.taskFail(ctx, alert, msg) + return + } + logclient.AddActionLogWithStartable(self, alert, logclient.ACT_UPDATE_MONITOR_RESOURCE_JOINT, nil, self.UserCred, true) + self.SetStageComplete(ctx, nil) +} + +func (self *UpdateMonitorResourceJointTask) taskFail(ctx context.Context, alert *models.SCommonAlert, msg jsonutils.JSONObject) { + db.OpsLog.LogEvent(alert, db.ACT_UPDATE_MONITOR_RESOURCE_JOINT, msg, self.GetUserCred()) + logclient.AddActionLogWithStartable(self, alert, logclient.ACT_UPDATE_MONITOR_RESOURCE_JOINT, msg, self.UserCred, false) + self.SetStageFailed(ctx, msg) + return +} diff --git a/pkg/util/logclient/consts.go b/pkg/util/logclient/consts.go index 6fad750bf0..50895d9b04 100644 --- a/pkg/util/logclient/consts.go +++ b/pkg/util/logclient/consts.go @@ -191,10 +191,12 @@ const ( ACT_SYNC_VPCS = "sync_vpcs" ACT_SYNC_RECORD_SETS = "sync_record_sets" - ACT_DETACH_ALERTRESOURCE = "detach_alertresoruce" - ACT_NETWORK_ADD_VPC = "network_add_vpc" - ACT_NETWORK_REMOVE_VPC = "network_remove_vpc" - ACT_NETWORK_MODIFY_ROUTE = "network_modify_route" + ACT_DETACH_ALERTRESOURCE = "detach_alertresoruce" + ACT_NETWORK_ADD_VPC = "network_add_vpc" + ACT_NETWORK_REMOVE_VPC = "network_remove_vpc" + ACT_NETWORK_MODIFY_ROUTE = "network_modify_route" + ACT_UPDATE_MONITOR_RESOURCE_JOINT = "update_monitor_resource_joint" + ACT_DETACH_MONITOR_RESOURCE_JOINT = "detach_monitor_resource_joint" ACT_UPDATE_RULE = "update_config" ACT_UPDATE_TAGS = "update_tags" diff --git a/pkg/util/logclient/consts_i18n.go b/pkg/util/logclient/consts_i18n.go index 0d1e3298bf..2938aaf117 100644 --- a/pkg/util/logclient/consts_i18n.go +++ b/pkg/util/logclient/consts_i18n.go @@ -1293,4 +1293,13 @@ func init() { CN("虚拟机套餐"), ) + o.Set(ACT_UPDATE_MONITOR_RESOURCE_JOINT, i18n.NewTableEntry(). + EN("Update Monitor Resource joint"). + CN("更新监控资源关联报警策略"), + ) + + o.Set(ACT_DETACH_MONITOR_RESOURCE_JOINT, i18n.NewTableEntry(). + EN("Update Monitor Resource joint"). + CN("解绑监控资源关联报警策略"), + ) }