mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-31 01:35:56 +08:00
Merge pull request #8586 from zhaoxiangchun/feature/zxc-commonalert-dashboard
modify monitor dashboard save:
This commit is contained in:
@@ -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))
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -36,7 +36,7 @@ type SScopedResourceBaseManager struct {
|
||||
|
||||
// +onecloud:model-api-gen
|
||||
type SScopedResourceBase struct {
|
||||
SProjectizedResourceBase
|
||||
SProjectizedResourceBase `"domain_id->default":""`
|
||||
}
|
||||
|
||||
type sUniqValues struct {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user