Merge pull request #11444 from zhaoxiangchun/automated-cherry-pick-of-#11428-upstream-release-3.7-1624013747

Automated cherry pick of #11428: feat(monitor) 3.7 add monitor resource overview
This commit is contained in:
Zexi Li
2021-06-21 00:33:57 +08:00
committed by GitHub
21 changed files with 1105 additions and 11 deletions
@@ -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))
}
+38
View File
@@ -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"`
}
@@ -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"`
}
+3
View File
@@ -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"
)
@@ -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,
}
}
@@ -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"
}
+6 -2
View File
@@ -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
+1
View File
@@ -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 {
+4
View File
@@ -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 {
+166 -5
View File
@@ -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"`
+5
View File
@@ -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
}
+338
View File
@@ -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)
}
@@ -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
}
+242
View File
@@ -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
}
+1
View File
@@ -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 (
+2
View File
@@ -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)
+1
View File
@@ -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()
@@ -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
}
@@ -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
}
+6 -4
View File
@@ -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"
+9
View File
@@ -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("解绑监控资源关联报警策略"),
)
}