mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
common alert bugfix/3.4
This commit is contained in:
@@ -92,11 +92,14 @@ func (c *QueryCondition) filterTags(tags map[string]string, details monitor.Comm
|
||||
ret["name"] = val
|
||||
}
|
||||
}
|
||||
if strings.Contains(key, "ip") {
|
||||
if strings.Contains(key, "ip") && key != "host_ip" {
|
||||
ret["ip"] = val
|
||||
}
|
||||
ret[key] = val
|
||||
}
|
||||
if _, ok := ret["ip"]; !ok {
|
||||
ret["ip"] = tags["host_ip"]
|
||||
}
|
||||
for _, tag := range []string{"brand", "platform", "hypervisor"} {
|
||||
if val, ok := ret[tag]; ok {
|
||||
ret["brand"] = val
|
||||
|
||||
@@ -18,6 +18,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
@@ -26,6 +28,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/i18n"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules/notify"
|
||||
@@ -113,10 +116,49 @@ func GetNotifyTemplateConfig(ctx *alerting.EvalContext) monitor.NotificationTemp
|
||||
return config
|
||||
}
|
||||
|
||||
func GetNotifyTemplateConfigOfEN(ctx *alerting.EvalContext) monitor.NotificationTemplateConfig {
|
||||
priority := notify.NotifyPriorityNormal
|
||||
level := "Normal"
|
||||
switch ctx.Rule.Level {
|
||||
case "", "normal":
|
||||
priority = notify.NotifyPriorityNormal
|
||||
case "important":
|
||||
priority = notify.NotifyPriorityImportant
|
||||
level = "Important"
|
||||
case "fatal", "critical":
|
||||
priority = notify.NotifyPriorityCritical
|
||||
level = "Critical"
|
||||
}
|
||||
topic := fmt.Sprintf("[%s]", level)
|
||||
|
||||
isRecovery := false
|
||||
if ctx.Rule.State == monitor.AlertStateOK {
|
||||
isRecovery = true
|
||||
topic = fmt.Sprintf("%s %s Alarm recovered", topic, ctx.GetRuleTitle())
|
||||
} else if ctx.NoDataFound {
|
||||
topic = fmt.Sprintf("%s %s No data available", topic, ctx.GetRuleTitle())
|
||||
} else {
|
||||
topic = fmt.Sprintf("%s %s Alarm", topic, ctx.GetRuleTitle())
|
||||
}
|
||||
config := ctx.GetNotificationTemplateConfig()
|
||||
config.Title = topic
|
||||
config.Level = level
|
||||
config.Priority = string(priority)
|
||||
config.IsRecovery = isRecovery
|
||||
return config
|
||||
}
|
||||
|
||||
// Notify sends the alert notification.
|
||||
func (oc *OneCloudNotifier) Notify(ctx *alerting.EvalContext, _ jsonutils.JSONObject) error {
|
||||
log.Infof("Sending alert notification %s to onecloud", ctx.GetRuleTitle())
|
||||
config := GetNotifyTemplateConfig(ctx)
|
||||
var config monitor.NotificationTemplateConfig
|
||||
lang := i18n.Lang(ctx.Ctx)
|
||||
switch lang {
|
||||
case language.English:
|
||||
config = GetNotifyTemplateConfigOfEN(ctx)
|
||||
default:
|
||||
config = GetNotifyTemplateConfig(ctx)
|
||||
}
|
||||
contentConfig := oc.buildContent(config)
|
||||
|
||||
var content string
|
||||
|
||||
@@ -120,7 +120,7 @@ type SAlert struct {
|
||||
Settings jsonutils.JSONObject `nullable:"false" list:"user" create:"required" update:"user"`
|
||||
Level string `charset:"ascii" width:"36" nullable:"false" default:"normal" list:"user" update:"user"`
|
||||
Message string `charset:"utf8" list:"user" create:"optional" update:"user"`
|
||||
UsedBy string `charset:"ascii" list:"user"`
|
||||
UsedBy string `charset:"ascii" create:"optional" list:"user"`
|
||||
|
||||
// Silenced bool
|
||||
ExecutionError string `charset:"utf8" list:"user"`
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"yunion.io/x/pkg/utils"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
"yunion.io/x/onecloud/pkg/apis/monitor"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
@@ -529,9 +530,6 @@ func getCommonAlertMetricDetailsFromCondition(cond *monitor.AlertCondition,
|
||||
|
||||
//fill measurement\field desciption info
|
||||
getMetricDescriptionDetails(metricDetails)
|
||||
if metricDetails.FieldOpt == "/" {
|
||||
metricDetails.FieldDescription.Unit = ""
|
||||
}
|
||||
}
|
||||
|
||||
func getMetricDescriptionDetails(metricDetails *monitor.CommonAlertMetricDetails) {
|
||||
@@ -557,15 +555,24 @@ func getMetricDescriptionDetails(metricDetails *monitor.CommonAlertMetricDetails
|
||||
return
|
||||
}
|
||||
if fieldDes, ok := influxdbMeasurements[0].FieldDescriptions[field]; ok {
|
||||
if len(metricDetails.FieldOpt) != 0 {
|
||||
fieldDes.Name = metricDetails.Field
|
||||
fieldDes.DisplayName = ""
|
||||
}
|
||||
metricDetails.FieldDescription = fieldDes
|
||||
if len(metricDetails.FieldOpt) != 0 {
|
||||
metricDetails.FieldDescription.Name = metricDetails.Field
|
||||
metricDetails.FieldDescription.DisplayName = metricDetails.Field
|
||||
getExtraFieldDetails(metricDetails)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getExtraFieldDetails(metricDetails *monitor.CommonAlertMetricDetails) {
|
||||
if metricDetails.FieldOpt == monitor.CommonAlertFieldOpt_Division && metricDetails.Threshold < float64(1) {
|
||||
metricDetails.Threshold = metricDetails.Threshold * float64(100)
|
||||
metricDetails.FieldDescription.Unit = "%"
|
||||
}
|
||||
}
|
||||
|
||||
func getQueryEvalType(evalType string) string {
|
||||
typ := ""
|
||||
switch evalType {
|
||||
@@ -586,11 +593,12 @@ func (man *SCommonAlertManager) toAlertCreatInput(input monitor.CommonAlertCreat
|
||||
//ret.Settings =monitor.AlertSetting{}
|
||||
for _, metricquery := range input.CommonMetricInputQuery.MetricQuery {
|
||||
condition := monitor.AlertCondition{
|
||||
Type: "query",
|
||||
Query: *metricquery.AlertQuery,
|
||||
Reducer: monitor.Condition{Type: metricquery.Reduce},
|
||||
Evaluator: monitor.Condition{Type: getQueryEvalType(metricquery.Comparator), Params: []float64{metricquery.Threshold}},
|
||||
Operator: "and",
|
||||
Type: "query",
|
||||
Query: *metricquery.AlertQuery,
|
||||
Reducer: monitor.Condition{Type: metricquery.Reduce},
|
||||
Evaluator: monitor.Condition{Type: getQueryEvalType(metricquery.Comparator),
|
||||
Params: []float64{fieldOperatorThreshold(metricquery.FieldOpt, metricquery.Threshold)}},
|
||||
Operator: "and",
|
||||
}
|
||||
if metricquery.FieldOpt != "" {
|
||||
condition.Reducer.Operators = []string{metricquery.FieldOpt}
|
||||
@@ -600,12 +608,33 @@ func (man *SCommonAlertManager) toAlertCreatInput(input monitor.CommonAlertCreat
|
||||
return *ret
|
||||
}
|
||||
|
||||
func fieldOperatorThreshold(opt string, threshold float64) float64 {
|
||||
if opt == monitor.CommonAlertFieldOpt_Division && threshold > 1 {
|
||||
return threshold / float64(100)
|
||||
}
|
||||
return threshold
|
||||
}
|
||||
|
||||
func (alert *SCommonAlert) ValidateUpdateData(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
data *jsonutils.JSONDict,
|
||||
) (*jsonutils.JSONDict, error) {
|
||||
generateName, _ := data.GetString("generate_name")
|
||||
if len(generateName) != 0 && alert.Name != generateName {
|
||||
name, err := db.GenerateName(CommonAlertManager, userCred, generateName)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
data.Set("name", jsonutils.NewString(name))
|
||||
}
|
||||
statusUpdate := apis.StatusStandaloneResourceBaseUpdateInput{}
|
||||
data.Unmarshal(&statusUpdate)
|
||||
_, err := alert.SAlert.SStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, statusUpdate)
|
||||
if err != nil {
|
||||
return data, errors.Wrap(err, "SStandaloneResourceBase.ValidateUpdateData")
|
||||
}
|
||||
updataInput := new(monitor.CommonAlertUpdateInput)
|
||||
if period, _ := data.GetString("period"); len(period) > 0 {
|
||||
if _, err := time.ParseDuration(period); err != nil {
|
||||
@@ -686,7 +715,9 @@ func (alert *SCommonAlert) PostUpdate(
|
||||
if err := alert.UpdateNotification(ctx, userCred, query, data); err != nil {
|
||||
log.Errorln("update notification", err)
|
||||
}
|
||||
_, err := alert.PerformSetScope(ctx, userCred, query, data)
|
||||
}
|
||||
if _, err := data.GetString("scope"); err == nil {
|
||||
_, err = alert.PerformSetScope(ctx, userCred, query, data)
|
||||
if err != nil {
|
||||
log.Errorln(errors.Wrap(err, "Alert PerformSetScope"))
|
||||
}
|
||||
@@ -784,6 +815,23 @@ func (alert *SCommonAlert) AllowPerformSetScope(ctx context.Context, userCred mc
|
||||
}
|
||||
|
||||
func (alert *SCommonAlert) PerformSetScope(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
domainId := jsonutils.GetAnyString(data, []string{"domain_id", "domain", "project_domain_id", "project_domain"})
|
||||
projectId := jsonutils.GetAnyString(data, []string{"project_id", "project"})
|
||||
if len(domainId) == 0 && len(projectId) == 0 {
|
||||
scope, _ := data.GetString("scope")
|
||||
if len(scope) != 0 {
|
||||
switch rbacutils.TRbacScope(scope) {
|
||||
case rbacutils.ScopeSystem:
|
||||
|
||||
case rbacutils.ScopeDomain:
|
||||
domainId = userCred.GetProjectDomainId()
|
||||
data.(*jsonutils.JSONDict).Set("domain_id", jsonutils.NewString(domainId))
|
||||
case rbacutils.ScopeProject:
|
||||
projectId = userCred.GetProjectId()
|
||||
data.(*jsonutils.JSONDict).Set("project_id", jsonutils.NewString(projectId))
|
||||
}
|
||||
}
|
||||
}
|
||||
return db.PerformSetScope(ctx, alert, userCred, data)
|
||||
}
|
||||
|
||||
|
||||
@@ -341,19 +341,19 @@ func (self *SDataSourceManager) getMetricDescriptions(influxdbMeasurements []mon
|
||||
if err != nil {
|
||||
log.Errorln(errors.Wrap(err, "DataSourceManager getMetricDescriptions error"))
|
||||
}
|
||||
measurements, err := MetricMeasurementManager.getMeasurement(query)
|
||||
if len(measurements) != 0 {
|
||||
descriMeasurements, err := MetricMeasurementManager.getMeasurement(query)
|
||||
if len(descriMeasurements) != 0 {
|
||||
|
||||
measurementsIns := make([]interface{}, len(measurements))
|
||||
for i, _ := range measurements {
|
||||
measurementsIns[i] = &measurements[i]
|
||||
measurementsIns := make([]interface{}, len(descriMeasurements))
|
||||
for i, _ := range descriMeasurements {
|
||||
measurementsIns[i] = &descriMeasurements[i]
|
||||
}
|
||||
details := MetricMeasurementManager.FetchCustomizeColumns(context.Background(), userCred, jsonutils.NewDict(), measurementsIns,
|
||||
stringutils2.NewSortedStrings([]string{}), true)
|
||||
if err != nil {
|
||||
log.Errorln(errors.Wrap(err, "DataSourceManager getMetricDescriptions error"))
|
||||
}
|
||||
for i, measureDes := range measurements {
|
||||
for i, measureDes := range descriMeasurements {
|
||||
for j, _ := range influxdbMeasurements {
|
||||
if measureDes.Name == influxdbMeasurements[j].Measurement {
|
||||
if len(measureDes.DisplayName) != 0 {
|
||||
@@ -495,13 +495,12 @@ func (self *SDataSourceManager) getFilterMeasurement(queryChan *influxdbQueryCha
|
||||
if value[i] == nil {
|
||||
continue
|
||||
}
|
||||
floatVal, err := value[i].Float()
|
||||
_, err := value[i].Float()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if !floatEquals(floatVal, float64(0)) {
|
||||
containsVal = true
|
||||
}
|
||||
containsVal = true
|
||||
break
|
||||
}
|
||||
if containsVal {
|
||||
rtnFields = append(rtnFields, strings.Replace(meanFieldArr[i], "last_", "", 1))
|
||||
@@ -820,6 +819,7 @@ func (self *SDataSourceManager) getFilterMeasurementTagValue(tagValueChan *influ
|
||||
buffer.WriteString(fmt.Sprintf(` AND %s `, tagFilter))
|
||||
}
|
||||
buffer.WriteString(fmt.Sprintf(` GROUP BY %q`, tagKey))
|
||||
log.Errorln(buffer.String())
|
||||
rtn, err := db.Query(buffer.String())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getFilterMeasurementTagValue query error")
|
||||
|
||||
@@ -59,22 +59,21 @@ func (self *SUnifiedMonitorManager) AllowGetPropertyMeasurements(ctx context.Con
|
||||
func (self *SUnifiedMonitorManager) GetPropertyMeasurements(ctx context.Context, userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
|
||||
filter, err := getTagFilterByRequestQuery(ctx, query)
|
||||
filter, err := getTagFilterByRequestQuery(ctx, userCred, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return DataSourceManager.GetMeasurementsWithDescriptionInfos(query, "", filter)
|
||||
}
|
||||
|
||||
func getTagFilterByRequestQuery(ctx context.Context, query jsonutils.JSONObject) (filter string, err error) {
|
||||
func getTagFilterByRequestQuery(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (filter string, err error) {
|
||||
|
||||
if scope, err := query.GetString("scope"); err == nil {
|
||||
filter, err = filterByScope(ctx, scope, query)
|
||||
}
|
||||
scope, _ := query.GetString("scope")
|
||||
filter, err = filterByScope(ctx, userCred, scope, query)
|
||||
return
|
||||
}
|
||||
|
||||
func filterByScope(ctx context.Context, scope string, data jsonutils.JSONObject) (string, error) {
|
||||
func filterByScope(ctx context.Context, userCred mcclient.TokenCredential, scope string, data jsonutils.JSONObject) (string, error) {
|
||||
domainId := jsonutils.GetAnyString(data, []string{"domain_id", "domain", "project_domain_id", "project_domain"})
|
||||
projectId := jsonutils.GetAnyString(data, []string{"project_id", "project"})
|
||||
if projectId != "" {
|
||||
@@ -98,17 +97,16 @@ func filterByScope(ctx context.Context, scope string, data jsonutils.JSONObject)
|
||||
return "", nil
|
||||
case "domain":
|
||||
if domainId == "" {
|
||||
return "", fmt.Errorf("scope is domain but domainId is null")
|
||||
domainId = userCred.GetProjectDomainId()
|
||||
}
|
||||
return getProjectIdsFilterByDomain(domainId)
|
||||
case "project":
|
||||
default:
|
||||
if projectId == "" {
|
||||
return "", fmt.Errorf("scope is project but projectId is null")
|
||||
projectId = userCred.GetProjectId()
|
||||
}
|
||||
return getProjectIdFilterByProject(projectId)
|
||||
|
||||
}
|
||||
return "", fmt.Errorf("scope is illegal")
|
||||
}
|
||||
|
||||
func getTenantIdStr(role string, userCred mcclient.TokenCredential) (string, error) {
|
||||
@@ -167,7 +165,7 @@ func (self *SUnifiedMonitorManager) GetPropertyMetricMeasurement(ctx context.Con
|
||||
GroupOptType: monitor.UNIFIED_MONITOR_GROUPBY_OPT_TYPE,
|
||||
GroupOptValue: monitor.UNIFIED_MONITOR_GROUPBY_OPT_VALUE,
|
||||
}
|
||||
filter, err := getTagFilterByRequestQuery(ctx, query)
|
||||
filter, err := getTagFilterByRequestQuery(ctx, userCred, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user