mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
fix(monitor): filter alertquery result according to onecloud resources
1.排除已经删除的资源 2.对已经删除的资源不再持续报警
This commit is contained in:
@@ -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",
|
||||
}
|
||||
)
|
||||
@@ -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) {
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user