From beff4578c900ad371aac963ea3a3b361fd0ec274 Mon Sep 17 00:00:00 2001 From: zhaoxiangchun <1422928955@qq.com> Date: Sun, 28 Mar 2021 18:52:12 +0800 Subject: [PATCH] fix(monitor): filter alertquery result according to onecloud resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.排除已经删除的资源 2.对已经删除的资源不再持续报警 --- pkg/apis/monitor/alertquery_const.go | 136 +++++++ .../alerting/conditions/metricquery.go | 23 +- .../alerting/conditions/nodataquery.go | 337 +----------------- pkg/monitor/alerting/conditions/query.go | 273 +++++++++++++- pkg/monitor/models/unifiedmonitor.go | 20 +- 5 files changed, 432 insertions(+), 357 deletions(-) create mode 100644 pkg/apis/monitor/alertquery_const.go diff --git a/pkg/apis/monitor/alertquery_const.go b/pkg/apis/monitor/alertquery_const.go new file mode 100644 index 0000000000..1dec844f1b --- /dev/null +++ b/pkg/apis/monitor/alertquery_const.go @@ -0,0 +1,136 @@ +package monitor + +var ( + ServerTags = map[string]string{ + "host": "host", + "host_id": "host_id", + "vm_id": "id", + "vm_ip": "ips", + "vm_name": "name", + "zone": "zone", + "zone_id": "zone_id", + "zone_ext_id": "zone_ext_id", + "os_type": "os_type", + "status": "status", + "cloudregion": "cloudregion", + "cloudregion_id": "cloudregion_id", + "region_ext_id": "region_ext_id", + "tenant": "tenant", + "tenant_id": "tenant_id", + "brand": "brand", + "scaling_group_id": "vm_scaling_group_id", + "domain_id": "domain_id", + "project_domain": "project_domain", + } + + HostTags = map[string]string{ + "host_id": "id", + "host_ip": "ips", + "host": "name", + "zone": "zone", + "zone_id": "zone_id", + "zone_ext_id": "zone_ext_id", + "os_type": "os_type", + "status": "status", + "cloudregion": "cloudregion", + "cloudregion_id": "cloudregion_id", + "region_ext_id": "region_ext_id", + "tenant": "tenant", + "tenant_id": "tenant_id", + "brand": "brand", + "domain_id": "domain_id", + "project_domain": "project_domain", + } + + RdsTags = map[string]string{ + "host": "host", + "host_id": "host_id", + "rds_id": "id", + "rds_ip": "ips", + "rds_name": "name", + "zone": "zone", + "zone_id": "zone_id", + "zone_ext_id": "zone_ext_id", + "os_type": "os_type", + "status": "status", + "cloudregion": "cloudregion", + "cloudregion_id": "cloudregion_id", + "region_ext_id": "region_ext_id", + "tenant": "tenant", + "tenant_id": "tenant_id", + "brand": "brand", + "domain_id": "domain_id", + "project_domain": "project_domain", + } + + RedisTags = map[string]string{ + "host": "host", + "host_id": "host_id", + "redis_id": "id", + "redis_ip": "ips", + "redis_name": "name", + "zone": "zone", + "zone_id": "zone_id", + "zone_ext_id": "zone_ext_id", + "os_type": "os_type", + "status": "status", + "cloudregion": "cloudregion", + "cloudregion_id": "cloudregion_id", + "region_ext_id": "region_ext_id", + "tenant": "tenant", + "tenant_id": "tenant_id", + "brand": "brand", + "domain_id": "domain_id", + "project_domain": "project_domain", + } + + OssTags = map[string]string{ + "host": "host", + "host_id": "host_id", + "oss_id": "id", + "oss_ip": "ips", + "oss_name": "name", + "zone": "zone", + "zone_id": "zone_id", + "zone_ext_id": "zone_ext_id", + "os_type": "os_type", + "status": "status", + "cloudregion": "cloudregion", + "cloudregion_id": "cloudregion_id", + "region_ext_id": "region_ext_id", + "tenant": "tenant", + "tenant_id": "tenant_id", + "brand": "brand", + "domain_id": "domain_id", + "project_domain": "project_domain", + } + + ElbTags = map[string]string{ + "host": "host", + "host_id": "host_id", + "elb_id": "id", + "elb_ip": "ips", + "elb_name": "name", + "zone": "zone", + "zone_id": "zone_id", + "zone_ext_id": "zone_ext_id", + "os_type": "os_type", + "status": "status", + "region": "region", + "cloudregion": "cloudregion", + "cloudregion_id": "cloudregion_id", + "tenant": "tenant", + "tenant_id": "tenant_id", + "brand": "brand", + "domain_id": "domain_id", + "project_domain": "project_domain", + } + + CloudAccountTags = map[string]string{ + "cloudaccount_id": "id", + "cloudaccount_name": "name", + "brand": "brand", + "domain_id": "domain_id", + "project_domain": "project_domain", + } +) diff --git a/pkg/monitor/alerting/conditions/metricquery.go b/pkg/monitor/alerting/conditions/metricquery.go index d4f70b40de..2e153ca8f2 100644 --- a/pkg/monitor/alerting/conditions/metricquery.go +++ b/pkg/monitor/alerting/conditions/metricquery.go @@ -45,6 +45,7 @@ func NewMetricQueryCondition(models []*monitor.AlertCondition) (*MetricQueryCond if err := validators.ValidateToValue(qc.Query.To); err != nil { return nil, errors.Wrapf(err, "to value %q", qc.Query.To) } + qc.setResType() qc.Query.DataSourceId = q.DataSourceId cond.QueryCons = append(cond.QueryCons, *qc) } @@ -63,10 +64,24 @@ func (query *MetricQueryCondition) ExecuteQuery() (*mq.Metrics, error) { if err != nil { return nil, err } - return &mq.Metrics{ - Series: queryResult.series, - Metas: queryResult.metas, - }, nil + allResources, err := query.QueryCons[0].GetQueryResources() + if err != nil { + return nil, errors.Wrap(err, "MetricQueryCondition GetQueryResources err") + } + metrics := mq.Metrics{ + Series: make(tsdb.TimeSeriesSlice, 0), + Metas: nil, + } + for _, serie := range queryResult.series { + isLatestOfSerie, resource := query.QueryCons[0].serieIsLatestResource(allResources, serie) + if !isLatestOfSerie { + continue + } + query.QueryCons[0].FillSerieByResourceField(resource, serie) + metrics.Series = append(metrics.Series, serie) + } + metrics.Metas = queryResult.metas + return &metrics, nil } func (c *MetricQueryCondition) executeQuery(context *alerting.EvalContext, timeRange *tsdb.TimeRange) (*queryResult, error) { diff --git a/pkg/monitor/alerting/conditions/nodataquery.go b/pkg/monitor/alerting/conditions/nodataquery.go index 9108ecc0f3..e4482b418b 100644 --- a/pkg/monitor/alerting/conditions/nodataquery.go +++ b/pkg/monitor/alerting/conditions/nodataquery.go @@ -1,18 +1,13 @@ package conditions import ( - "context" "fmt" - "sort" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis/monitor" "yunion.io/x/onecloud/pkg/hostman/hostinfo/hostconsts" - "yunion.io/x/onecloud/pkg/mcclient/auth" - "yunion.io/x/onecloud/pkg/mcclient/modulebase" - mc_mds "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/monitor/alerting" "yunion.io/x/onecloud/pkg/monitor/models" "yunion.io/x/onecloud/pkg/monitor/tsdb" @@ -77,12 +72,11 @@ serLoop: } } } - allHosts, err := c.getOnecloudResources(context) - allHosts = c.filterAllResources(context, allHosts) + allResources, err := c.GetQueryResources() if err != nil { - return nil, errors.Wrap(err, "NoDataQueryCondition getOnecloudHosts error") + return nil, errors.Wrap(err, "GetQueryResources err") } - for _, host := range allHosts { + for _, host := range allResources { id, _ := host.GetString("id") evalMatch, err := c.NewNoDataEvalMatch(context, host) if err != nil { @@ -105,168 +99,6 @@ serLoop: }, nil } -func (c *NoDataQueryCondition) filterAllResources(context *alerting.EvalContext, - resources []jsonutils.JSONObject) []jsonutils.JSONObject { - if len(c.Query.Model.Tags) == 0 { - return resources - } - filterIdMap := make(map[string]jsonutils.JSONObject) - filterQuery := c.getFilterQuery() - intKey := make([]int, 0) - if len(filterQuery) != 0 { - for key, _ := range filterQuery { - intKey = append(intKey, key) - } - sort.Ints(intKey) - minKey := intKey[0] - if minKey != 0 { - filterQuery[0] = minKey - 1 - } - } else { - filterQuery[0] = len(c.Query.Model.Tags) - 1 - } - for start, end := range filterQuery { - filterResources := c.getFilterResources(context, start, end, resources) - filterIdMap = c.fillFilterRes(filterResources, filterIdMap) - } - filterRes := make([]jsonutils.JSONObject, 0) - for _, obj := range filterIdMap { - filterRes = append(filterRes, obj) - } - return filterRes -} - -func (c *NoDataQueryCondition) fillFilterRes(filterRes []jsonutils.JSONObject, - filterIdMap map[string]jsonutils.JSONObject) map[string]jsonutils.JSONObject { - for _, res := range filterRes { - id, _ := res.GetString("id") - if _, ok := filterIdMap[id]; !ok { - filterIdMap[id] = res - } - } - return filterIdMap -} - -func (c *NoDataQueryCondition) getFilterQuery() map[int]int { - length := len(c.Query.Model.Tags) - tagIndexMap := make(map[int]int) - for i := 0; i < length; i++ { - if c.Query.Model.Tags[i].Condition == "OR" { - andIndex := c.getTheAndOfConditionor(i + 1) - if andIndex == i+1 { - tagIndexMap[i] = i - continue - } - if andIndex == length { - for j := i; j < length; j++ { - tagIndexMap[j] = j - } - break - } - tagIndexMap[i] = andIndex - i = andIndex - } - } - return tagIndexMap -} - -func (c *NoDataQueryCondition) getTheAndOfConditionor(start int) int { - for i := start; i < len(c.Query.Model.Tags); i++ { - if c.Query.Model.Tags[i].Condition != "AND" { - return i - } - } - return len(c.Query.Model.Tags) -} - -func (c *NoDataQueryCondition) getFilterResources(evalContext *alerting.EvalContext, start int, end int, - resources []jsonutils.JSONObject) []jsonutils.JSONObject { - relationMap := c.getTagKeyRelationMap(evalContext) - tmp := resources - for i := start; i <= end; i++ { - tag := c.Query.Model.Tags[i] - relationKey := relationMap[tag.Key] - filterObj := make([]jsonutils.JSONObject, 0) - for _, res := range tmp { - val, _ := res.GetString(relationKey) - if c.Query.Model.Tags[i].Operator == "=" { - if val == c.Query.Model.Tags[i].Value { - filterObj = append(filterObj, res) - } - } - if c.Query.Model.Tags[i].Operator == "!=" { - if val != c.Query.Model.Tags[i].Value { - filterObj = append(filterObj, res) - } - } - } - tmp = filterObj - if len(tmp) == 0 { - return tmp - } - } - return tmp -} - -func (c *NoDataQueryCondition) getTagKeyRelationMap(evalContext *alerting.EvalContext) map[string]string { - relationMap := make(map[string]string) - switch evalContext.Rule.RuleDescription[0].ResType { - case monitor.METRIC_RES_TYPE_HOST: - relationMap = HostTags - case monitor.METRIC_RES_TYPE_GUEST: - relationMap = ServerTags - case monitor.METRIC_RES_TYPE_RDS: - relationMap = RdsTags - case monitor.METRIC_RES_TYPE_REDIS: - relationMap = RedisTags - case monitor.METRIC_RES_TYPE_OSS: - relationMap = OssTags - default: - relationMap = HostTags - } - return relationMap -} - -func (c *NoDataQueryCondition) getOnecloudResources(evalContext *alerting.EvalContext) ([]jsonutils.JSONObject, error) { - var err error - allResources := make([]jsonutils.JSONObject, 0) - if len(evalContext.Rule.RuleDescription) == 0 { - return []jsonutils.JSONObject{}, nil - } - query := jsonutils.NewDict() - query.Add(jsonutils.NewStringArray([]string{"running", "ready"}), "status") - query.Add(jsonutils.NewString("true"), "admin") - //if len(c.Query.Model.Tags) != 0 { - // query, err = c.convertTagsQuery(evalContext, query) - // if err != nil { - // return nil, errors.Wrap(err, "NoDataQueryCondition convertTagsQuery error") - // } - //} - switch evalContext.Rule.RuleDescription[0].ResType { - 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) - 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 (c *NoDataQueryCondition) convertTagsQuery(evalContext *alerting.EvalContext, query *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { alertDetails, err := c.GetCommonAlertDetails(evalContext) @@ -290,34 +122,6 @@ func (c *NoDataQueryCondition) convertTagsQuery(evalContext *alerting.EvalContex return query, 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 -} - func (c *NoDataQueryCondition) NewNoDataEvalMatch(context *alerting.EvalContext, host jsonutils.JSONObject) (*monitor.EvalMatch, error) { evalMatch := new(monitor.EvalMatch) alert, err := models.CommonAlertManager.GetAlert(context.Rule.Id) @@ -379,138 +183,3 @@ func newNoDataQueryCondition(model *monitor.AlertCondition, index int) (*NoDataQ condition.QueryCondition = queryCondition return condition, nil } - -var ( - ServerTags = map[string]string{ - "host": "host", - "host_id": "host_id", - "vm_id": "id", - "vm_ip": "ips", - "vm_name": "name", - "zone": "zone", - "zone_id": "zone_id", - "zone_ext_id": "zone_ext_id", - "os_type": "os_type", - "status": "status", - "cloudregion": "cloudregion", - "cloudregion_id": "cloudregion_id", - "region_ext_id": "region_ext_id", - "tenant": "tenant", - "tenant_id": "tenant_id", - "brand": "brand", - "scaling_group_id": "vm_scaling_group_id", - "domain_id": "domain_id", - "project_domain": "project_domain", - } - - HostTags = map[string]string{ - "host_id": "id", - "host_ip": "ips", - "host": "name", - "zone": "zone", - "zone_id": "zone_id", - "zone_ext_id": "zone_ext_id", - "os_type": "os_type", - "status": "status", - "cloudregion": "cloudregion", - "cloudregion_id": "cloudregion_id", - "region_ext_id": "region_ext_id", - "tenant": "tenant", - "tenant_id": "tenant_id", - "brand": "brand", - "domain_id": "domain_id", - "project_domain": "project_domain", - } - - RdsTags = map[string]string{ - "host": "host", - "host_id": "host_id", - "rds_id": "id", - "rds_ip": "ips", - "rds_name": "name", - "zone": "zone", - "zone_id": "zone_id", - "zone_ext_id": "zone_ext_id", - "os_type": "os_type", - "status": "status", - "cloudregion": "cloudregion", - "cloudregion_id": "cloudregion_id", - "region_ext_id": "region_ext_id", - "tenant": "tenant", - "tenant_id": "tenant_id", - "brand": "brand", - "domain_id": "domain_id", - "project_domain": "project_domain", - } - - RedisTags = map[string]string{ - "host": "host", - "host_id": "host_id", - "redis_id": "id", - "redis_ip": "ips", - "redis_name": "name", - "zone": "zone", - "zone_id": "zone_id", - "zone_ext_id": "zone_ext_id", - "os_type": "os_type", - "status": "status", - "cloudregion": "cloudregion", - "cloudregion_id": "cloudregion_id", - "region_ext_id": "region_ext_id", - "tenant": "tenant", - "tenant_id": "tenant_id", - "brand": "brand", - "domain_id": "domain_id", - "project_domain": "project_domain", - } - - OssTags = map[string]string{ - "host": "host", - "host_id": "host_id", - "oss_id": "id", - "oss_ip": "ips", - "oss_name": "name", - "zone": "zone", - "zone_id": "zone_id", - "zone_ext_id": "zone_ext_id", - "os_type": "os_type", - "status": "status", - "cloudregion": "cloudregion", - "cloudregion_id": "cloudregion_id", - "region_ext_id": "region_ext_id", - "tenant": "tenant", - "tenant_id": "tenant_id", - "brand": "brand", - "domain_id": "domain_id", - "project_domain": "project_domain", - } - - ElbTags = map[string]string{ - "host": "host", - "host_id": "host_id", - "elb_id": "id", - "elb_ip": "ips", - "elb_name": "name", - "zone": "zone", - "zone_id": "zone_id", - "zone_ext_id": "zone_ext_id", - "os_type": "os_type", - "status": "status", - "region": "region", - "cloudregion": "cloudregion", - "cloudregion_id": "cloudregion_id", - "tenant": "tenant", - "tenant_id": "tenant_id", - "brand": "brand", - "domain_id": "domain_id", - "project_domain": "project_domain", - } - - CloudAccountTags = map[string]string{ - "cloudaccount_id": "id", - "cloudaccount_name": "name", - "brand": "brand", - "domain_id": "domain_id", - "project_domain": "project_domain", - } -) diff --git a/pkg/monitor/alerting/conditions/query.go b/pkg/monitor/alerting/conditions/query.go index 89e91163ef..3f3cab1901 100644 --- a/pkg/monitor/alerting/conditions/query.go +++ b/pkg/monitor/alerting/conditions/query.go @@ -15,8 +15,9 @@ package conditions import ( - gocontext "context" + "context" "fmt" + "sort" "strings" "yunion.io/x/jsonutils" @@ -24,6 +25,10 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis/monitor" + "yunion.io/x/onecloud/pkg/hostman/hostinfo/hostconsts" + "yunion.io/x/onecloud/pkg/mcclient/auth" + "yunion.io/x/onecloud/pkg/mcclient/modulebase" + mc_mds "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/monitor/alerting" "yunion.io/x/onecloud/pkg/monitor/models" "yunion.io/x/onecloud/pkg/monitor/tsdb" @@ -46,6 +51,7 @@ type QueryCondition struct { Evaluator AlertEvaluator Operator string HandleRequest tsdb.HandleRequestFunc + ResType string } // AlertQuery contains information about what datasource a query @@ -150,7 +156,16 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.Conditio var matches []*monitor.EvalMatch var alertOkmatches []*monitor.EvalMatch + allResources, err := c.GetQueryResources() + if err != nil { + return nil, errors.Wrap(err, "GetQueryResources err") + } for _, series := range seriesList { + isLatestOfSerie, resource := c.serieIsLatestResource(allResources, series) + if !isLatestOfSerie { + continue + } + c.FillSerieByResourceField(resource, series) reducedValue, valStrArr := c.Reducer.Reduce(series) evalMatch := c.Evaluator.Eval(reducedValue) @@ -217,6 +232,36 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.Conditio }, nil } +func (c *QueryCondition) serieIsLatestResource(resources []jsonutils.JSONObject, + series *tsdb.TimeSeries) (bool, jsonutils.JSONObject) { + tagId := monitor.MEASUREMENT_TAG_ID[c.ResType] + if len(tagId) == 0 { + tagId = "host_id" + } + seriId := series.Tags[tagId] + for _, resource := range resources { + id, _ := resource.GetString("id") + if seriId == id { + return true, resource + } + } + return false, nil +} + +func (c *QueryCondition) FillSerieByResourceField(resource jsonutils.JSONObject, + series *tsdb.TimeSeries) { + tagKeyRelationMap := c.getTagKeyRelationMap() + fieldMap, _ := resource.GetMap() + for field, v := range fieldMap { + val, _ := v.GetString() + for tagKey, resourceKey := range tagKeyRelationMap { + if resourceKey == field { + series.Tags[tagKey] = val + } + } + } +} + func (c *QueryCondition) NewEvalMatch(context *alerting.EvalContext, series tsdb.TimeSeries, meta *tsdb.QueryResultMeta, value *float64, valStrArr []string) (*monitor.EvalMatch, error) { evalMatch := new(monitor.EvalMatch) @@ -307,17 +352,17 @@ type queryResult struct { metas []tsdb.QueryResultMeta } -func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timeRange *tsdb.TimeRange) (*queryResult, error) { +func (c *QueryCondition) executeQuery(evalCtx *alerting.EvalContext, timeRange *tsdb.TimeRange) (*queryResult, error) { ds, err := models.DataSourceManager.GetSource(c.Query.DataSourceId) if err != nil { return nil, errors.Wrapf(err, "Cound not find datasource %v", c.Query.DataSourceId) } - req := c.getRequestForAlertRule(ds, timeRange, context.IsDebug) + req := c.getRequestForAlertRule(ds, timeRange, evalCtx.IsDebug) result := make(tsdb.TimeSeriesSlice, 0) metas := make([]tsdb.QueryResultMeta, 0) - if context.IsDebug { + if evalCtx.IsDebug { data := jsonutils.NewDict() if req.TimeRange != nil { data.Set("from", jsonutils.NewInt(req.TimeRange.GetFromAsMsEpoch())) @@ -345,15 +390,15 @@ func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timeRange * data.Set("queries", jsonutils.Marshal(queries)) - context.Logs = append(context.Logs, &monitor.ResultLogEntry{ + evalCtx.Logs = append(evalCtx.Logs, &monitor.ResultLogEntry{ Message: fmt.Sprintf("Condition[%d]: Query", c.Index), Data: data, }) } - resp, err := c.HandleRequest(context.Ctx, ds.ToTSDBDataSource(c.Query.Model.Database), req) + resp, err := c.HandleRequest(evalCtx.Ctx, ds.ToTSDBDataSource(c.Query.Model.Database), req) if err != nil { - if err == gocontext.DeadlineExceeded { + if err == context.DeadlineExceeded { return nil, errors.Error("Alert execution exceeded the timeout") } @@ -369,16 +414,16 @@ func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timeRange * queryResultData := map[string]interface{}{} - if context.IsTestRun { + if evalCtx.IsTestRun { queryResultData["series"] = v.Series } - if context.IsDebug { + if evalCtx.IsDebug { queryResultData["meta"] = v.Meta } - if context.IsTestRun || context.IsDebug { - context.Logs = append(context.Logs, &monitor.ResultLogEntry{ + if evalCtx.IsTestRun || evalCtx.IsDebug { + evalCtx.Logs = append(evalCtx.Logs, &monitor.ResultLogEntry{ Message: fmt.Sprintf("Condition[%d]: Query Result", c.Index), Data: queryResultData, }) @@ -442,6 +487,212 @@ func newQueryCondition(model *monitor.AlertCondition, index int) (*QueryConditio operator = "and" } cond.Operator = operator + cond.setResType() return cond, nil } + +func (c *QueryCondition) setResType() { + var resType = "" + metricMeasurement, _ := models.MetricMeasurementManager.GetCache().Get(c.Query.Model.Measurement) + if metricMeasurement != nil { + resType = metricMeasurement.ResType + } + c.ResType = resType +} + +func (c *QueryCondition) GetQueryResources() ([]jsonutils.JSONObject, error) { + allHosts, err := c.getOnecloudResources() + if err != nil { + return nil, errors.Wrap(err, "getOnecloudHosts error") + } + allHosts = c.filterAllResources(allHosts) + return allHosts, nil +} + +func (c *QueryCondition) getOnecloudResources() ([]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") + //if len(c.Query.Model.Tags) != 0 { + // query, err = c.convertTagsQuery(evalContext, query) + // if err != nil { + // return nil, errors.Wrap(err, "NoDataQueryCondition convertTagsQuery error") + // } + //} + switch c.ResType { + 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) + 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 +} + +func (c *QueryCondition) filterAllResources(resources []jsonutils.JSONObject) []jsonutils.JSONObject { + if len(c.Query.Model.Tags) == 0 { + return resources + } + filterIdMap := make(map[string]jsonutils.JSONObject) + filterQuery := c.getFilterQuery() + intKey := make([]int, 0) + if len(filterQuery) != 0 { + for key, _ := range filterQuery { + intKey = append(intKey, key) + } + sort.Ints(intKey) + minKey := intKey[0] + if minKey != 0 { + filterQuery[0] = minKey - 1 + } + } else { + filterQuery[0] = len(c.Query.Model.Tags) - 1 + } + for start, end := range filterQuery { + filterResources := c.getFilterResources(start, end, resources) + filterIdMap = c.fillFilterRes(filterResources, filterIdMap) + } + filterRes := make([]jsonutils.JSONObject, 0) + for _, obj := range filterIdMap { + filterRes = append(filterRes, obj) + } + return filterRes +} + +func (c *QueryCondition) getFilterQuery() map[int]int { + length := len(c.Query.Model.Tags) + tagIndexMap := make(map[int]int) + for i := 0; i < length; i++ { + if c.Query.Model.Tags[i].Condition == "OR" { + andIndex := c.getTheAndOfConditionor(i + 1) + if andIndex == i+1 { + tagIndexMap[i] = i + continue + } + if andIndex == length { + for j := i; j < length; j++ { + tagIndexMap[j] = j + } + break + } + tagIndexMap[i] = andIndex + i = andIndex + } + } + return tagIndexMap +} + +func (c *QueryCondition) getFilterResources(start int, end int, + resources []jsonutils.JSONObject) []jsonutils.JSONObject { + relationMap := c.getTagKeyRelationMap() + tmp := resources + for i := start; i <= end; i++ { + tag := c.Query.Model.Tags[i] + relationKey := relationMap[tag.Key] + filterObj := make([]jsonutils.JSONObject, 0) + for _, res := range tmp { + val, _ := res.GetString(relationKey) + if c.Query.Model.Tags[i].Operator == "=" { + if val == c.Query.Model.Tags[i].Value { + filterObj = append(filterObj, res) + } + } + if c.Query.Model.Tags[i].Operator == "!=" { + if val != c.Query.Model.Tags[i].Value { + filterObj = append(filterObj, res) + } + } + } + tmp = filterObj + if len(tmp) == 0 { + return tmp + } + } + return tmp +} + +func (c *QueryCondition) fillFilterRes(filterRes []jsonutils.JSONObject, + filterIdMap map[string]jsonutils.JSONObject) map[string]jsonutils.JSONObject { + for _, res := range filterRes { + id, _ := res.GetString("id") + if _, ok := filterIdMap[id]; !ok { + filterIdMap[id] = res + } + } + return filterIdMap +} + +func (c *QueryCondition) getTheAndOfConditionor(start int) int { + for i := start; i < len(c.Query.Model.Tags); i++ { + if c.Query.Model.Tags[i].Condition != "AND" { + return i + } + } + return len(c.Query.Model.Tags) +} + +func (c *QueryCondition) getTagKeyRelationMap() map[string]string { + relationMap := make(map[string]string) + switch c.ResType { + case monitor.METRIC_RES_TYPE_HOST: + relationMap = monitor.HostTags + case monitor.METRIC_RES_TYPE_GUEST: + relationMap = monitor.ServerTags + case monitor.METRIC_RES_TYPE_RDS: + relationMap = monitor.RdsTags + case monitor.METRIC_RES_TYPE_REDIS: + relationMap = monitor.RedisTags + case monitor.METRIC_RES_TYPE_OSS: + relationMap = monitor.OssTags + default: + relationMap = monitor.HostTags + } + return relationMap +} diff --git a/pkg/monitor/models/unifiedmonitor.go b/pkg/monitor/models/unifiedmonitor.go index c11d6f586e..c369fe27ad 100644 --- a/pkg/monitor/models/unifiedmonitor.go +++ b/pkg/monitor/models/unifiedmonitor.go @@ -311,15 +311,20 @@ func setDefaultValue(query *monitor.AlertQuery, inputQuery *monitor.MetricInputQ query.To = inputQuery.To query.Model.Interval = inputQuery.Interval - if len(query.Model.GroupBy) == 0 { - if !inputQuery.Unit { - query.Model.GroupBy = append(query.Model.GroupBy, - monitor.MetricQueryPart{ - Type: "field", - Params: []string{"*"}, - }) + metricMeasurement, _ := MetricMeasurementManager.GetCache().Get(query.Model.Measurement) + + if true { + tagId := "host_id" + if metricMeasurement != nil { + tagId = monitor.MEASUREMENT_TAG_ID[metricMeasurement.ResType] } + query.Model.GroupBy = append(query.Model.GroupBy, + monitor.MetricQueryPart{ + Type: "field", + Params: []string{tagId}, + }) } + if len(inputQuery.Interval) != 0 { query.Model.GroupBy = append(query.Model.GroupBy, monitor.MetricQueryPart{ @@ -332,7 +337,6 @@ func setDefaultValue(query *monitor.AlertQuery, inputQuery *monitor.MetricInputQ }) } - metricMeasurement, _ := MetricMeasurementManager.GetCache().Get(query.Model.Measurement) if query.Model.Database == "" { database := "" if metricMeasurement == nil {