Merge pull request #8586 from zhaoxiangchun/feature/zxc-commonalert-dashboard

modify monitor dashboard save:
This commit is contained in:
yunion-ci-robot
2020-11-03 14:28:46 +08:00
committed by GitHub
13 changed files with 650 additions and 200 deletions
+15
View File
@@ -0,0 +1,15 @@
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.AlertPanelManager)
cmd.Create(new(options.AlertPanelCreateOptions))
cmd.List(new(options.AlertPanelListOptions))
cmd.Show(new(options.AlertPanelShowOptions))
cmd.Delete(new(options.AlertPanelDeleteOptions))
}
+15 -12
View File
@@ -1,12 +1,15 @@
package monitor
import "yunion.io/x/onecloud/pkg/apis"
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/apis"
)
type AlertDashBoardCreateInput struct {
apis.ScopedResourceInput
CommonMetricInputQuery
AlertCreateInput
apis.Meta
apis.ScopedResourceCreateInput
apis.StandaloneResourceCreateInput
Refresh string `json:"refresh"`
}
@@ -17,13 +20,13 @@ type AlertDashBoardListInput struct {
type AlertDashBoardDetails struct {
AlertDetails
CommonAlertMetricDetails []*CommonAlertMetricDetails `json:"common_alert_metric_details"`
AlertPanelDetails []AlertPanelDetail `json:"alert_panel_details"`
}
type AlertDashBoardUpdateInput struct {
CommonMetricInputQuery
V1AlertUpdateInput
Refresh string `json:"refresh"`
type AlertPanelDetail struct {
PanelName string `json:"panel_name"`
PanelId string `json:"panel_id"`
Refresh string `json:"refresh"`
Setting jsonutils.JSONObject
PanelDetails
}
+31
View File
@@ -0,0 +1,31 @@
package monitor
import "yunion.io/x/onecloud/pkg/apis"
type AlertPanelCreateInput struct {
apis.ScopedResourceInput
CommonMetricInputQuery
AlertCreateInput
Refresh string `json:"refresh"`
DashboardId string `json:"dashboard_id"`
}
type AlertPanelListInput struct {
AlertListInput
DashboardId string `json:"dashboard_id"`
}
type AlertPanelUpdateInput struct {
apis.ScopedResourceBaseInfo
CommonMetricInputQuery
V1AlertUpdateInput
Refresh string `json:"refresh"`
}
type PanelDetails struct {
AlertDetails
CommonAlertMetricDetails []*CommonAlertMetricDetails `json:"common_alert_metric_details"`
}
+1 -1
View File
@@ -36,7 +36,7 @@ type SScopedResourceBaseManager struct {
// +onecloud:model-api-gen
type SScopedResourceBase struct {
SProjectizedResourceBase
SProjectizedResourceBase `"domain_id->default":""`
}
type sUniqValues struct {
+1 -1
View File
@@ -16,7 +16,7 @@ func init() {
}
func NewAlertDashBoardManager() *SAlertDashBoardManager {
man := NewMonitorV2Manager("alertdashboard", "alertdashboards",
[]string{"id", "name", "refresh", "common_alert_metric_details"},
[]string{"id", "name", "refresh", "alert_panel_details"},
[]string{})
return &SAlertDashBoardManager{
ResourceManager: &man,
+24
View File
@@ -0,0 +1,24 @@
package modules
import "yunion.io/x/onecloud/pkg/mcclient/modulebase"
type SAlertPanelManager struct {
*modulebase.ResourceManager
}
var (
AlertPanelManager *SAlertPanelManager
)
func init() {
AlertPanelManager = NewAlertPanelManager()
}
func NewAlertPanelManager() *SAlertPanelManager {
man := NewMonitorV2Manager("alertpanel", "alertpanels",
[]string{"id", "name", "setting", "common_alert_metric_details"},
[]string{})
return &SAlertPanelManager{
ResourceManager: &man,
}
}
+5 -43
View File
@@ -1,58 +1,20 @@
package monitor
import (
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/apis/monitor"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type AlertDashBoardCreateOptions struct {
NAME string `help:"Name of bashboard"`
Metric string `help:"Metric name, include measurement and field, e.g. vm_cpu.usage_active" required:"true"`
Database string
Interval string `help:"query aggregation interval e.g. 1m|5s"`
From string `help:"query start time e.g. 5m|6h"`
To string `help:"query end time"`
Refresh string `help:"dashboard query refresh priod e.g. 1m|5m"`
Scope string
apis.ScopedResourceCreateInput
NAME string `help:"Name of bashboard"`
Refresh string `help:"dashboard query refresh priod e.g. 1m|5m"`
}
func (o *AlertDashBoardCreateOptions) Params() (jsonutils.JSONObject, error) {
createInput := new(monitor.AlertDashBoardCreateInput)
createInput.Name = o.NAME
createInput.Scope = o.Scope
createInput.Refresh = o.Refresh
createInput.From = o.From
createInput.To = o.To
alertQuery := new(monitor.CommonAlertQuery)
metrics := strings.Split(o.Metric, ".")
if len(metrics) != 2 {
return nil, errors.Wrap(httperrors.ErrBadRequest, "metric")
}
measurement := metrics[0]
field := metrics[1]
sels := make([]monitor.MetricQuerySelect, 0)
sels = append(sels, monitor.NewMetricQuerySelect(
monitor.MetricQueryPart{
Type: "field",
Params: []string{field},
}))
q := monitor.MetricQuery{
Database: o.Database,
Measurement: measurement,
Selects: sels,
}
tmp := new(monitor.AlertQuery)
tmp.Model = q
alertQuery.AlertQuery = tmp
createInput.MetricQuery = make([]*monitor.CommonAlertQuery, 0)
createInput.MetricQuery = append(createInput.MetricQuery, alertQuery)
return jsonutils.Marshal(createInput), nil
return options.StructToParams(o)
}
type AlertDashBoardListOptions struct {
@@ -0,0 +1,92 @@
package monitor
import (
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/apis/monitor"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type AlertPanelCreateOptions struct {
apis.ScopedResourceCreateInput
DashboardId string `help:"id of attached dashboard"`
NAME string `help:"Name of bashboard"`
Metric string `help:"Metric name, include measurement and field, e.g. vm_cpu.usage_active" required:"true"`
Database string
Interval string `help:"query aggregation interval e.g. 1m|5s"`
From string `help:"query start time e.g. 5m|6h"`
To string `help:"query end time"`
}
func (o *AlertPanelCreateOptions) Params() (jsonutils.JSONObject, error) {
createInput := new(monitor.AlertPanelCreateInput)
createInput.Name = o.NAME
createInput.Scope = o.Scope
createInput.From = o.From
createInput.To = o.To
createInput.DashboardId = o.DashboardId
createInput.Interval = o.Interval
alertQuery := new(monitor.CommonAlertQuery)
metrics := strings.Split(o.Metric, ".")
if len(metrics) != 2 {
return nil, errors.Wrap(httperrors.ErrBadRequest, "metric")
}
measurement := metrics[0]
field := metrics[1]
sels := make([]monitor.MetricQuerySelect, 0)
sels = append(sels, monitor.NewMetricQuerySelect(
monitor.MetricQueryPart{
Type: "field",
Params: []string{field},
}))
q := monitor.MetricQuery{
Database: o.Database,
Measurement: measurement,
Selects: sels,
}
tmp := new(monitor.AlertQuery)
tmp.Model = q
alertQuery.AlertQuery = tmp
createInput.MetricQuery = make([]*monitor.CommonAlertQuery, 0)
createInput.MetricQuery = append(createInput.MetricQuery, alertQuery)
return jsonutils.Marshal(createInput), nil
}
type AlertPanelListOptions struct {
options.BaseListOptions
DashboardId string `help:"id of attached dashboard"`
}
func (o *AlertPanelListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(o)
}
type AlertPanelShowOptions struct {
ID string `help:"ID of Metric " json:"-"`
}
func (o *AlertPanelShowOptions) Params() (jsonutils.JSONObject, error) {
return options.StructToParams(o)
}
func (o *AlertPanelShowOptions) GetId() string {
return o.ID
}
type AlertPanelDeleteOptions struct {
ID string `json:"-"`
}
func (o *AlertPanelDeleteOptions) GetId() string {
return o.ID
}
func (o *AlertPanelDeleteOptions) Params() (jsonutils.JSONObject, error) {
return options.StructToParams(o)
}
+61 -142
View File
@@ -6,15 +6,12 @@ import (
"yunion.io/x/jsonutils"
"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"
merrors "yunion.io/x/onecloud/pkg/monitor/errors"
"yunion.io/x/onecloud/pkg/monitor/validators"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
@@ -31,9 +28,7 @@ type SAlertDashBoard struct {
db.SStatusStandaloneResourceBase
db.SScopedResourceBase
Refresh string `nullable:"false" list:"user" create:"required" update:"user"`
Settings jsonutils.JSONObject `nullable:"false" list:"user" create:"required" update:"user"`
Message string `charset:"utf8" list:"user" create:"optional" update:"user"`
Refresh string `nullable:"false" list:"user" create:"required" update:"user"`
}
var AlertDashBoardManager *SAlertDashBoardManager
@@ -90,69 +85,21 @@ func (man *SAlertDashBoardManager) ValidateCreateData(
ctx context.Context, userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject,
data monitor.AlertDashBoardCreateInput) (monitor.AlertDashBoardCreateInput, error) {
if len(data.Refresh) != 0 {
if _, err := time.ParseDuration(data.Refresh); err != nil {
return data, httperrors.NewInputParameterError("Invalid refresh format: %s", data.Refresh)
}
if len(data.Refresh) == 0 {
data.Refresh = "1m"
}
if len(data.CommonMetricInputQuery.MetricQuery) == 0 {
return data, merrors.NewArgIsEmptyErr("metric_query")
} else {
for _, query := range data.CommonMetricInputQuery.MetricQuery {
if len(query.Comparator) != 0 {
if !utils.IsInStringArray(getQueryEvalType(query.Comparator), validators.EvaluatorDefaultTypes) {
return data, httperrors.NewInputParameterError("the Comparator is illegal: %s", query.Comparator)
}
}
if len(query.Reduce) != 0 {
if _, ok := monitor.AlertReduceFunc[query.Reduce]; !ok {
return data, httperrors.NewInputParameterError("the reduce is illegal %s", query.Reduce)
}
}
}
err := CommonAlertManager.ValidateMetricQuery(&data.CommonMetricInputQuery, data.Scope, ownerId)
if err != nil {
return data, errors.Wrap(err, "metric query error")
}
if _, err := time.ParseDuration(data.Refresh); err != nil {
return data, httperrors.NewInputParameterError("Invalid refresh format: %s", data.Refresh)
}
name, err := CommonAlertManager.genName(ownerId, data.Name)
generateName, err := db.GenerateName(man, ownerId, data.Name)
if err != nil {
return data, err
}
data.Name = name
alertCreateInput := man.toAlertCreateInput(data)
//alertCreateInput, err = AlertManager.ValidateCreateData(ctx, userCred, ownerId, query, alertCreateInput)
//if err != nil {
// return data, err
//}
data.AlertCreateInput = alertCreateInput
enable := true
if data.Enabled == nil {
data.Enabled = &enable
}
data.Name = generateName
return data, nil
}
func (man *SAlertDashBoardManager) toAlertCreateInput(input monitor.AlertDashBoardCreateInput) monitor.AlertCreateInput {
ret := new(monitor.AlertCreateInput)
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",
}
if metricquery.FieldOpt != "" {
condition.Reducer.Operators = []string{metricquery.FieldOpt}
}
ret.Settings.Conditions = append(ret.Settings.Conditions, condition)
}
return *ret
}
func (dash *SAlertDashBoard) CustomizeCreate(
ctx context.Context, userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
@@ -192,39 +139,45 @@ func (man *SAlertDashBoardManager) FetchCustomizeColumns(
}
func (dash *SAlertDashBoard) GetMoreDetails(out monitor.AlertDashBoardDetails) (monitor.AlertDashBoardDetails, error) {
setting, err := dash.GetSettings()
panels, err := dash.getAttachPanels()
if err != nil {
return out, err
return out, errors.Wrapf(err, "dashboard:%s GetMoreDetails error", dash.Name)
}
if len(setting.Conditions) == 0 {
return out, nil
}
out.CommonAlertMetricDetails = make([]*monitor.CommonAlertMetricDetails, len(setting.Conditions))
for i, cond := range setting.Conditions {
metricDetails := dash.GetCommonAlertMetricDetailsFromAlertCondition(i, cond)
out.CommonAlertMetricDetails[i] = metricDetails
out.AlertPanelDetails = make([]monitor.AlertPanelDetail, len(panels))
for i, panel := range panels {
//out.AlertPanelDetail[i].PanelDetails = monitor.PanelDetails{}
out.AlertPanelDetails[i].PanelDetails, err = panel.GetMoreDetails(out.AlertPanelDetails[i].PanelDetails)
if err != nil {
return out, errors.Wrapf(err, "dashboard:%s get panel:%s details error", dash.Name, panel.Name)
}
out.AlertPanelDetails[i].Setting = panel.Settings
out.AlertPanelDetails[i].PanelId = panel.Id
out.AlertPanelDetails[i].PanelName = panel.Name
}
return out, nil
}
func (dash *SAlertDashBoard) GetCommonAlertMetricDetailsFromAlertCondition(index int,
cond monitor.AlertCondition) *monitor.
CommonAlertMetricDetails {
metricDetails := new(monitor.CommonAlertMetricDetails)
getCommonAlertMetricDetailsFromCondition(&cond, metricDetails)
return metricDetails
func (dash *SAlertDashBoard) getJointPanels() ([]SAlertDashboardPanel, error) {
joints := make([]SAlertDashboardPanel, 0)
q := AlertDashBoardPanelManager.Query().Equals(AlertDashBoardPanelManager.GetMasterFieldName(), dash.Id)
err := db.FetchModelObjects(AlertDashBoardPanelManager, q, &joints)
if err != nil {
return joints, errors.Wrapf(err, "get dash:%s joint panel err")
}
return joints, err
}
func (dash *SAlertDashBoard) GetSettings() (*monitor.AlertSetting, error) {
setting := new(monitor.AlertSetting)
if dash.Settings == nil {
return setting, nil
func (dash *SAlertDashBoard) getAttachPanels() ([]SAlertPanel, error) {
panels := make([]SAlertPanel, 0)
panelQuery := AlertPanelManager.Query()
sq := AlertDashBoardPanelManager.Query(AlertDashBoardPanelManager.GetSlaveFieldName()).Equals(
AlertDashBoardPanelManager.GetMasterFieldName(), dash.Id).SubQuery()
panelQuery = panelQuery.In("id", sq)
err := db.FetchModelObjects(AlertPanelManager, panelQuery, &panels)
if err != nil {
return panels, errors.Wrapf(err, "dashboard:%s get attach panels error", dash.Name)
}
if err := dash.Settings.Unmarshal(setting); err != nil {
return nil, errors.Wrapf(err, "dashboard %s unmarshal", dash.GetId())
}
return setting, nil
return panels, nil
}
func (dash *SAlertDashBoard) ValidateUpdateData(
@@ -233,71 +186,37 @@ func (dash *SAlertDashBoard) ValidateUpdateData(
query jsonutils.JSONObject,
data *jsonutils.JSONDict,
) (*jsonutils.JSONDict, error) {
updataInput := new(monitor.AlertDashBoardUpdateInput)
if refresh, _ := data.GetString("refresh"); len(refresh) > 0 {
if refresh, err := data.GetString("refresh"); err == nil && len(refresh) != 0 {
if _, err := time.ParseDuration(refresh); err != nil {
return data, httperrors.NewInputParameterError("Invalid refresh format: %s", refresh)
}
}
if metric_query, _ := data.GetArray("metric_query"); len(metric_query) > 0 {
for i, _ := range metric_query {
query := new(monitor.CommonAlertQuery)
err := metric_query[i].Unmarshal(query)
if err != nil {
return data, errors.Wrap(err, "metric_query Unmarshal error")
}
if len(query.Comparator) != 0 {
if !utils.IsInStringArray(getQueryEvalType(query.Comparator), validators.EvaluatorDefaultTypes) {
return data, httperrors.NewInputParameterError("the Comparator is illegal: %s", query.Comparator)
}
}
if len(query.Reduce) != 0 {
if _, ok := monitor.AlertReduceFunc[query.Reduce]; !ok {
return data, httperrors.NewInputParameterError("the reduce is illegal: %s", query.Reduce)
}
}
}
metricQuery := new(monitor.CommonMetricInputQuery)
err := data.Unmarshal(metricQuery)
if err != nil {
return data, errors.Wrap(err, "metric_query Unmarshal error")
}
ownerId, _ := AlertDashBoardManager.FetchOwnerId(ctx, data)
if ownerId == nil {
ownerId = userCred
}
scope, _ := data.GetString("scope")
err = CommonAlertManager.ValidateMetricQuery(metricQuery, scope, ownerId)
if err != nil {
return data, errors.Wrap(err, "metric query error")
}
data.Update(jsonutils.Marshal(metricQuery))
err = data.Unmarshal(updataInput)
if err != nil {
return data, errors.Wrap(err, "updataInput Unmarshal err")
}
alertCreateInput := dash.getUpdateAlertInput(*updataInput)
//alertCreateInput, err = AlertManager.ValidateCreateData(ctx, userCred, nil, query, alertCreateInput)
//if err != nil {
// return data, err
//}
data.Set("settings", jsonutils.Marshal(&alertCreateInput.Settings))
updataInput.StandaloneResourceBaseUpdateInput, err = dash.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred,
query, updataInput.StandaloneResourceBaseUpdateInput)
if err != nil {
return data, errors.Wrap(err, "SAlertDashBoard.ValidateUpdateData")
}
data.Update(jsonutils.Marshal(updataInput))
}
return data, nil
}
func (dash *SAlertDashBoard) getUpdateAlertInput(updateInput monitor.AlertDashBoardUpdateInput) monitor.AlertCreateInput {
input := monitor.AlertDashBoardCreateInput{
CommonMetricInputQuery: updateInput.CommonMetricInputQuery,
func (dash *SAlertDashBoard) CustomizeDelete(
ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data jsonutils.JSONObject) error {
panels, err := dash.getAttachPanels()
if err != nil {
return errors.Wrapf(err, "dash:%s,when exec customizedelete to get attach panels error")
}
createInput := AlertDashBoardManager.toAlertCreateInput(input)
return createInput
for _, panel := range panels {
if err := panel.CustomizeDelete(ctx, userCred, query, data); err != nil {
return errors.Wrap(err, "dashboard exec panel CustomizeDelete error")
}
if err := panel.Delete(ctx, userCred); err != nil {
return errors.Wrap(err, "dashboard exec panel Delete error")
}
}
return nil
}
func (manager *SAlertDashBoardManager) getDashboardByid(id string) (*SAlertDashBoard, error) {
iModel, err := db.FetchById(manager, id)
if err != nil {
return nil, err
}
return iModel.(*SAlertDashBoard), nil
}
@@ -0,0 +1,52 @@
package models
import (
"context"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/mcclient"
)
var (
AlertDashBoardPanelManager *SAlertDashboardPanelManager
)
type SAlertDashboardPanelManager struct {
db.SJointResourceBaseManager
}
func init() {
db.InitManager(func() {
AlertDashBoardPanelManager = &SAlertDashboardPanelManager{
SJointResourceBaseManager: db.NewJointResourceBaseManager(
SAlertDashboardPanel{},
"alertdashboardpanel_tbl",
"alertdashboardpanel",
"alertdashboardpanels",
AlertDashBoardManager,
AlertPanelManager,
),
}
AlertDashBoardPanelManager.SetVirtualObject(AlertDashBoardPanelManager)
AlertDashBoardPanelManager.TableSpec().AddIndex(true, AlertDashBoardPanelManager.GetMasterFieldName(), AlertDashBoardPanelManager.GetSlaveFieldName())
})
}
type SAlertDashboardPanel struct {
db.SVirtualJointResourceBase
DashboardId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
PanelId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
}
func (man *SAlertDashboardPanelManager) GetMasterFieldName() string {
return "dashboard_Id"
}
func (man *SAlertDashboardPanelManager) GetSlaveFieldName() string {
return "panel_id"
}
func (joint *SAlertDashboardPanel) Detach(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DetachJoint(ctx, userCred, joint)
}
+347
View File
@@ -0,0 +1,347 @@
package models
import (
"context"
"time"
"yunion.io/x/jsonutils"
"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"
merrors "yunion.io/x/onecloud/pkg/monitor/errors"
"yunion.io/x/onecloud/pkg/monitor/validators"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
var (
AlertPanelManager *SAlertPanelManager
)
func init() {
AlertPanelManager = &SAlertPanelManager{
SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(
SAlertPanel{},
"alertpanel_tbl",
"alertpanel",
"alertpanels",
),
}
AlertPanelManager.SetVirtualObject(AlertPanelManager)
}
type SAlertPanelManager struct {
db.SStatusStandaloneResourceBaseManager
db.SScopedResourceBaseManager
}
type SAlertPanel struct {
db.SStatusStandaloneResourceBase
db.SScopedResourceBase
Settings jsonutils.JSONObject `nullable:"false" list:"user" create:"required" update:"user"`
Message string `charset:"utf8" list:"user" create:"optional" update:"user"`
}
func (manager *SAlertPanelManager) NamespaceScope() rbacutils.TRbacScope {
return rbacutils.ScopeSystem
}
func (manager *SAlertPanelManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential,
keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
q, err := manager.SStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemExportKeys")
}
q, err = manager.SScopedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SScopedResourceBaseManager.ListItemExportKeys")
}
return q, nil
}
func (man *SAlertPanelManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
input monitor.AlertPanelListInput,
) (*sqlchemy.SQuery, error) {
var err error
q, err = man.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.StatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields")
}
q, err = man.SScopedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.ScopedResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SScopedResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (man *SAlertPanelManager) ValidateCreateData(
ctx context.Context, userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject,
data monitor.AlertPanelCreateInput) (monitor.AlertPanelCreateInput, error) {
if len(data.DashboardId) == 0 {
return data, httperrors.NewInputParameterError("dashboard_id is empty")
} else {
_, err := AlertDashBoardManager.getDashboardByid(data.DashboardId)
if err != nil {
return data, httperrors.NewInputParameterError("can not find dashboard:%s", data.DashboardId)
}
}
if len(data.CommonMetricInputQuery.MetricQuery) == 0 {
return data, merrors.NewArgIsEmptyErr("metric_query")
} else {
for _, query := range data.CommonMetricInputQuery.MetricQuery {
if len(query.Comparator) != 0 {
if !utils.IsInStringArray(getQueryEvalType(query.Comparator), validators.EvaluatorDefaultTypes) {
return data, httperrors.NewInputParameterError("the Comparator is illegal: %s", query.Comparator)
}
}
if len(query.Reduce) != 0 {
if _, ok := monitor.AlertReduceFunc[query.Reduce]; !ok {
return data, httperrors.NewInputParameterError("the reduce is illegal %s", query.Reduce)
}
}
}
err := CommonAlertManager.ValidateMetricQuery(&data.CommonMetricInputQuery, data.Scope, ownerId)
if err != nil {
return data, errors.Wrap(err, "metric query error")
}
}
name, err := CommonAlertManager.genName(ownerId, data.Name)
if err != nil {
return data, err
}
data.Name = name
alertCreateInput := man.toAlertCreateInput(data)
data.AlertCreateInput = alertCreateInput
enable := true
if data.Enabled == nil {
data.Enabled = &enable
}
return data, nil
}
func (man *SAlertPanelManager) toAlertCreateInput(input monitor.AlertPanelCreateInput) monitor.AlertCreateInput {
ret := new(monitor.AlertCreateInput)
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",
}
ret.Settings.Conditions = append(ret.Settings.Conditions, condition)
}
return *ret
}
func (panel *SAlertPanel) CustomizeCreate(
ctx context.Context, userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
data jsonutils.JSONObject,
) error {
err := panel.SScopedResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
if err != nil {
return errors.Wrap(err, "alertPanel SScopedResourceBase CustomizeCreate error")
}
dashboardId, err := data.GetString("dashboard_id")
if len(dashboardId) == 0 {
return errors.Wrap(err, "panel CustomizeCreate can not get dashboard_id")
}
return panel.attachDashboard(ctx, dashboardId)
}
func (panel *SAlertPanel) attachDashboard(ctx context.Context, dashboardId string) error {
joint := new(SAlertDashboardPanel)
joint.DashboardId = dashboardId
if panel.Id == "" {
panel.Id = db.DefaultUUIDGenerator()
}
joint.PanelId = panel.Id
err := AlertDashBoardPanelManager.TableSpec().Insert(ctx, joint)
if err != nil {
return errors.Wrap(err, "panel attach dashboard error")
}
return nil
}
func (man *SAlertPanelManager) ListItemFilter(
ctx context.Context, q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query monitor.AlertPanelListInput,
) (*sqlchemy.SQuery, error) {
q, err := AlertManager.ListItemFilter(ctx, q, userCred, query.AlertListInput)
if err != nil {
return nil, err
}
if len(query.DashboardId) != 0 {
joinq := AlertDashBoardPanelManager.Query(AlertDashBoardPanelManager.GetSlaveFieldName()).Equals(
AlertDashBoardPanelManager.GetMasterFieldName(), query.DashboardId).SubQuery()
q = q.In("id", joinq)
}
return q, nil
}
func (man *SAlertPanelManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []monitor.PanelDetails {
rows := make([]monitor.PanelDetails, len(objs))
alertRows := AlertManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i].AlertDetails = alertRows[i]
rows[i], _ = objs[i].(*SAlertPanel).GetMoreDetails(rows[i])
}
return rows
}
func (dash *SAlertPanel) GetMoreDetails(out monitor.PanelDetails) (monitor.PanelDetails, error) {
setting, err := dash.GetSettings()
if err != nil {
return out, err
}
if len(setting.Conditions) == 0 {
return out, nil
}
out.CommonAlertMetricDetails = make([]*monitor.CommonAlertMetricDetails, len(setting.Conditions))
for i, cond := range setting.Conditions {
metricDetails := dash.GetCommonAlertMetricDetailsFromAlertCondition(i, cond)
out.CommonAlertMetricDetails[i] = metricDetails
}
return out, nil
}
func (dash *SAlertPanel) GetCommonAlertMetricDetailsFromAlertCondition(index int,
cond monitor.AlertCondition) *monitor.
CommonAlertMetricDetails {
metricDetails := new(monitor.CommonAlertMetricDetails)
getCommonAlertMetricDetailsFromCondition(&cond, metricDetails)
return metricDetails
}
func (dash *SAlertPanel) GetSettings() (*monitor.AlertSetting, error) {
setting := new(monitor.AlertSetting)
if dash.Settings == nil {
return setting, nil
}
if err := dash.Settings.Unmarshal(setting); err != nil {
return nil, errors.Wrapf(err, "dashboard %s unmarshal", dash.GetId())
}
return setting, nil
}
func (dash *SAlertPanel) ValidateUpdateData(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
data *jsonutils.JSONDict,
) (*jsonutils.JSONDict, error) {
updataInput := new(monitor.AlertPanelUpdateInput)
if refresh, _ := data.GetString("refresh"); len(refresh) > 0 {
if _, err := time.ParseDuration(refresh); err != nil {
return data, httperrors.NewInputParameterError("Invalid refresh format: %s", refresh)
}
}
if metric_query, _ := data.GetArray("metric_query"); len(metric_query) > 0 {
for i, _ := range metric_query {
query := new(monitor.CommonAlertQuery)
err := metric_query[i].Unmarshal(query)
if err != nil {
return data, errors.Wrap(err, "metric_query Unmarshal error")
}
if len(query.Comparator) != 0 {
if !utils.IsInStringArray(getQueryEvalType(query.Comparator), validators.EvaluatorDefaultTypes) {
return data, httperrors.NewInputParameterError("the Comparator is illegal: %s", query.Comparator)
}
}
if len(query.Reduce) != 0 {
if _, ok := monitor.AlertReduceFunc[query.Reduce]; !ok {
return data, httperrors.NewInputParameterError("the reduce is illegal: %s", query.Reduce)
}
}
}
metricQuery := new(monitor.CommonMetricInputQuery)
err := data.Unmarshal(metricQuery)
if err != nil {
return data, errors.Wrap(err, "metric_query Unmarshal error")
}
ownerId, _ := AlertDashBoardManager.FetchOwnerId(ctx, data)
if ownerId == nil {
ownerId = userCred
}
scope, _ := data.GetString("scope")
err = CommonAlertManager.ValidateMetricQuery(metricQuery, scope, ownerId)
if err != nil {
return data, errors.Wrap(err, "metric query error")
}
data.Update(jsonutils.Marshal(metricQuery))
err = data.Unmarshal(updataInput)
if err != nil {
return data, errors.Wrap(err, "updataInput Unmarshal err")
}
alertCreateInput := dash.getUpdateAlertInput(*updataInput)
data.Set("settings", jsonutils.Marshal(&alertCreateInput.Settings))
updataInput.StandaloneResourceBaseUpdateInput, err = dash.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred,
query, updataInput.StandaloneResourceBaseUpdateInput)
if err != nil {
return data, errors.Wrap(err, "SAlertPanel.ValidateUpdateData")
}
data.Update(jsonutils.Marshal(updataInput))
}
return data, nil
}
func (panel *SAlertPanel) getUpdateAlertInput(updateInput monitor.AlertPanelUpdateInput) monitor.AlertCreateInput {
input := monitor.AlertPanelCreateInput{
CommonMetricInputQuery: updateInput.CommonMetricInputQuery,
}
createInput := AlertPanelManager.toAlertCreateInput(input)
return createInput
}
func (panel *SAlertPanel) CustomizeDelete(
ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data jsonutils.JSONObject) error {
dashboardPanel, err := panel.getPanelJoint()
if err != nil {
return errors.Wrap(err, "panel getPanelJoint error")
}
err = dashboardPanel.Detach(ctx, userCred)
if err != nil {
return errors.Wrap(err, "dashboardPanel do detach error")
}
return nil
}
func (panel *SAlertPanel) getPanelJoint() (*SAlertDashboardPanel, error) {
iModel, err := db.NewModelObject(AlertDashBoardPanelManager)
if err != nil {
return nil, errors.Wrap(err, "panel NewModelObject error")
}
query := AlertDashBoardPanelManager.Query().Equals(AlertDashBoardPanelManager.GetSlaveFieldName(), panel.Id)
err = query.First(iModel)
if err != nil {
return nil, errors.Wrapf(err, "alertdashboardpanelmanager exc first query by panel:%s error", panel.Id)
}
return iModel.(*SAlertDashboardPanel), nil
}
+4 -1
View File
@@ -503,7 +503,10 @@ func getCommonAlertMetricDetailsFromCondition(cond *monitor.AlertCondition,
cmp = "<="
}
metricDetails.Comparator = cmp
metricDetails.Threshold = cond.Evaluator.Params[0]
if len(cond.Evaluator.Params) != 0 {
metricDetails.Threshold = cond.Evaluator.Params[0]
}
metricDetails.Reduce = cond.Reducer.Type
q := cond.Query
+2
View File
@@ -64,6 +64,7 @@ func InitHandlers(app *appsrv.Application) {
models.AlertRecordManager,
models.AlertDashBoardManager,
models.GetAlertResourceManager(),
models.AlertPanelManager,
} {
db.RegisterModelManager(manager)
handler := db.NewModelHandler(manager)
@@ -81,6 +82,7 @@ func InitHandlers(app *appsrv.Application) {
models.AlertNotificationManager,
models.MetricManager,
models.GetAlertResourceAlertManager(),
models.AlertDashBoardPanelManager,
} {
db.RegisterModelManager(manager)
handler := db.NewJointModelHandler(manager)