Alerting: Fix incorrect embedded DTO being returned when handling rule groups (#53701)

* Fix DTO embedding when getting/putting alert rule groups

* Drop usage of word 'Domain'

* Rename var as well
pull/53704/head
Alexander Weaver 3 years ago committed by GitHub
parent a19b3136c9
commit f093c249ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      pkg/services/ngalert/api/api_provisioning.go
  2. 2
      pkg/services/ngalert/api/api_provisioning_test.go
  3. 167
      pkg/services/ngalert/api/tooling/api.json
  4. 38
      pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules.go
  5. 169
      pkg/services/ngalert/api/tooling/post.json
  6. 169
      pkg/services/ngalert/api/tooling/spec.json
  7. 9
      pkg/services/ngalert/models/alert_rule.go
  8. 13
      pkg/services/ngalert/provisioning/alert_rules.go
  9. 5
      pkg/services/ngalert/provisioning/alert_rules_test.go

@ -55,8 +55,8 @@ type AlertRuleService interface {
CreateAlertRule(ctx context.Context, rule alerting_models.AlertRule, provenance alerting_models.Provenance, userID int64) (alerting_models.AlertRule, error)
UpdateAlertRule(ctx context.Context, rule alerting_models.AlertRule, provenance alerting_models.Provenance) (alerting_models.AlertRule, error)
DeleteAlertRule(ctx context.Context, orgID int64, ruleUID string, provenance alerting_models.Provenance) error
GetRuleGroup(ctx context.Context, orgID int64, folder, group string) (definitions.AlertRuleGroup, error)
ReplaceRuleGroup(ctx context.Context, orgID int64, group definitions.AlertRuleGroup, userID int64, provenance alerting_models.Provenance) error
GetRuleGroup(ctx context.Context, orgID int64, folder, group string) (alerting_models.AlertRuleGroup, error)
ReplaceRuleGroup(ctx context.Context, orgID int64, group alerting_models.AlertRuleGroup, userID int64, provenance alerting_models.Provenance) error
}
func (srv *ProvisioningSrv) RouteGetPolicyTree(c *models.ReqContext) response.Response {
@ -316,13 +316,17 @@ func (srv *ProvisioningSrv) RouteGetAlertRuleGroup(c *models.ReqContext, folder
}
return ErrResp(http.StatusInternalServerError, err, "")
}
return response.JSON(http.StatusOK, g)
return response.JSON(http.StatusOK, definitions.NewAlertRuleGroupFromModel(g))
}
func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *models.ReqContext, ag definitions.AlertRuleGroup, folderUID string, group string) response.Response {
ag.FolderUID = folderUID
ag.Title = group
err := srv.alertRules.ReplaceRuleGroup(c.Req.Context(), c.OrgID, ag, c.UserID, alerting_models.ProvenanceAPI)
groupModel, err := ag.ToModel()
if err != nil {
ErrResp(http.StatusBadRequest, err, "")
}
err = srv.alertRules.ReplaceRuleGroup(c.Req.Context(), c.OrgID, groupModel, c.UserID, alerting_models.ProvenanceAPI)
if errors.Is(err, alerting_models.ErrAlertRuleFailedValidation) {
return ErrResp(http.StatusBadRequest, err, "")
}

@ -515,7 +515,7 @@ func createInvalidAlertRuleGroup() definitions.AlertRuleGroup {
return definitions.AlertRuleGroup{
Title: "invalid",
Interval: 10,
Rules: []models.AlertRule{{}},
Rules: []definitions.ProvisionedAlertRule{{}},
}
}

@ -7,27 +7,6 @@
"Ack": {
"type": "object"
},
"AddApiKeyCommand": {
"description": "COMMANDS",
"properties": {
"name": {
"type": "string"
},
"role": {
"enum": [
"Viewer",
"Editor",
"Admin"
],
"type": "string"
},
"secondsToLive": {
"format": "int64",
"type": "integer"
}
},
"type": "object"
},
"Alert": {
"properties": {
"activeAt": {
@ -162,95 +141,6 @@
],
"type": "object"
},
"AlertRule": {
"properties": {
"Annotations": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"Condition": {
"type": "string"
},
"DashboardUID": {
"type": "string"
},
"Data": {
"items": {
"$ref": "#/definitions/AlertQuery"
},
"type": "array"
},
"ExecErrState": {
"enum": [
"Alerting",
"Error",
"OK"
],
"type": "string"
},
"For": {
"$ref": "#/definitions/Duration"
},
"ID": {
"format": "int64",
"type": "integer"
},
"IntervalSeconds": {
"format": "int64",
"type": "integer"
},
"Labels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"NamespaceUID": {
"type": "string"
},
"NoDataState": {
"enum": [
"Alerting",
"NoData",
"OK"
],
"type": "string"
},
"OrgID": {
"format": "int64",
"type": "integer"
},
"PanelID": {
"format": "int64",
"type": "integer"
},
"RuleGroup": {
"type": "string"
},
"RuleGroupIndex": {
"format": "int64",
"type": "integer"
},
"Title": {
"type": "string"
},
"UID": {
"type": "string"
},
"Updated": {
"format": "date-time",
"type": "string"
},
"Version": {
"format": "int64",
"type": "integer"
}
},
"title": "AlertRule is the model for alert rules in unified alerting.",
"type": "object"
},
"AlertRuleGroup": {
"properties": {
"folderUid": {
@ -262,7 +152,7 @@
},
"rules": {
"items": {
"$ref": "#/definitions/AlertRule"
"$ref": "#/definitions/ProvisionedAlertRule"
},
"type": "array"
},
@ -994,6 +884,12 @@
},
"type": "array"
},
"telegram_configs": {
"items": {
"$ref": "#/definitions/TelegramConfig"
},
"type": "array"
},
"victorops_configs": {
"items": {
"$ref": "#/definitions/VictorOpsConfig"
@ -1294,6 +1190,9 @@
"smtp_smarthost": {
"$ref": "#/definitions/HostPort"
},
"telegram_api_url": {
"$ref": "#/definitions/URL"
},
"victorops_api_key": {
"$ref": "#/definitions/Secret"
},
@ -1977,6 +1876,12 @@
},
"type": "array"
},
"telegram_configs": {
"items": {
"$ref": "#/definitions/TelegramConfig"
},
"type": "array"
},
"victorops_configs": {
"items": {
"$ref": "#/definitions/VictorOpsConfig"
@ -2470,6 +2375,12 @@
},
"type": "array"
},
"telegram_configs": {
"items": {
"$ref": "#/definitions/TelegramConfig"
},
"type": "array"
},
"victorops_configs": {
"items": {
"$ref": "#/definitions/VictorOpsConfig"
@ -2981,6 +2892,37 @@
"title": "TLSConfig configures the options for TLS connections.",
"type": "object"
},
"TelegramConfig": {
"properties": {
"api_url": {
"$ref": "#/definitions/URL"
},
"chat": {
"format": "int64",
"type": "integer"
},
"disable_notifications": {
"type": "boolean"
},
"http_config": {
"$ref": "#/definitions/HTTPClientConfig"
},
"message": {
"type": "string"
},
"parse_mode": {
"type": "string"
},
"send_resolved": {
"type": "boolean"
},
"token": {
"$ref": "#/definitions/Secret"
}
},
"title": "TelegramConfig configures notifications via Telegram.",
"type": "object"
},
"TestReceiverConfigResult": {
"properties": {
"error": {
@ -3568,6 +3510,7 @@
"type": "object"
},
"gettableAlerts": {
"description": "GettableAlerts gettable alerts",
"items": {
"$ref": "#/definitions/gettableAlert"
},
@ -3622,7 +3565,6 @@
"type": "object"
},
"gettableSilences": {
"description": "GettableSilences gettable silences",
"items": {
"$ref": "#/definitions/gettableSilence"
},
@ -3770,6 +3712,7 @@
"type": "object"
},
"receiver": {
"description": "Receiver receiver",
"properties": {
"name": {
"description": "name",

@ -184,8 +184,38 @@ type AlertRuleGroupMetadata struct {
// swagger:model
type AlertRuleGroup struct {
Title string `json:"title"`
FolderUID string `json:"folderUid"`
Interval int64 `json:"interval"`
Rules []models.AlertRule `json:"rules"`
Title string `json:"title"`
FolderUID string `json:"folderUid"`
Interval int64 `json:"interval"`
Rules []ProvisionedAlertRule `json:"rules"`
}
func (a *AlertRuleGroup) ToModel() (models.AlertRuleGroup, error) {
rules := make([]models.AlertRule, 0, len(a.Rules))
for i := range a.Rules {
converted, err := a.Rules[i].UpstreamModel()
if err != nil {
return models.AlertRuleGroup{}, err
}
rules = append(rules, converted)
}
return models.AlertRuleGroup{
Title: a.Title,
FolderUID: a.FolderUID,
Interval: a.Interval,
Rules: rules,
}, nil
}
func NewAlertRuleGroupFromModel(d models.AlertRuleGroup) AlertRuleGroup {
rules := make([]ProvisionedAlertRule, 0, len(d.Rules))
for i := range d.Rules {
rules = append(rules, NewAlertRule(d.Rules[i], d.Provenance))
}
return AlertRuleGroup{
Title: d.Title,
FolderUID: d.FolderUID,
Interval: d.Interval,
Rules: rules,
}
}

@ -7,27 +7,6 @@
"Ack": {
"type": "object"
},
"AddApiKeyCommand": {
"description": "COMMANDS",
"properties": {
"name": {
"type": "string"
},
"role": {
"enum": [
"Viewer",
"Editor",
"Admin"
],
"type": "string"
},
"secondsToLive": {
"format": "int64",
"type": "integer"
}
},
"type": "object"
},
"Alert": {
"properties": {
"activeAt": {
@ -162,95 +141,6 @@
],
"type": "object"
},
"AlertRule": {
"properties": {
"Annotations": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"Condition": {
"type": "string"
},
"DashboardUID": {
"type": "string"
},
"Data": {
"items": {
"$ref": "#/definitions/AlertQuery"
},
"type": "array"
},
"ExecErrState": {
"enum": [
"Alerting",
"Error",
"OK"
],
"type": "string"
},
"For": {
"$ref": "#/definitions/Duration"
},
"ID": {
"format": "int64",
"type": "integer"
},
"IntervalSeconds": {
"format": "int64",
"type": "integer"
},
"Labels": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"NamespaceUID": {
"type": "string"
},
"NoDataState": {
"enum": [
"Alerting",
"NoData",
"OK"
],
"type": "string"
},
"OrgID": {
"format": "int64",
"type": "integer"
},
"PanelID": {
"format": "int64",
"type": "integer"
},
"RuleGroup": {
"type": "string"
},
"RuleGroupIndex": {
"format": "int64",
"type": "integer"
},
"Title": {
"type": "string"
},
"UID": {
"type": "string"
},
"Updated": {
"format": "date-time",
"type": "string"
},
"Version": {
"format": "int64",
"type": "integer"
}
},
"title": "AlertRule is the model for alert rules in unified alerting.",
"type": "object"
},
"AlertRuleGroup": {
"properties": {
"folderUid": {
@ -262,7 +152,7 @@
},
"rules": {
"items": {
"$ref": "#/definitions/AlertRule"
"$ref": "#/definitions/ProvisionedAlertRule"
},
"type": "array"
},
@ -994,6 +884,12 @@
},
"type": "array"
},
"telegram_configs": {
"items": {
"$ref": "#/definitions/TelegramConfig"
},
"type": "array"
},
"victorops_configs": {
"items": {
"$ref": "#/definitions/VictorOpsConfig"
@ -1294,6 +1190,9 @@
"smtp_smarthost": {
"$ref": "#/definitions/HostPort"
},
"telegram_api_url": {
"$ref": "#/definitions/URL"
},
"victorops_api_key": {
"$ref": "#/definitions/Secret"
},
@ -1977,6 +1876,12 @@
},
"type": "array"
},
"telegram_configs": {
"items": {
"$ref": "#/definitions/TelegramConfig"
},
"type": "array"
},
"victorops_configs": {
"items": {
"$ref": "#/definitions/VictorOpsConfig"
@ -2470,6 +2375,12 @@
},
"type": "array"
},
"telegram_configs": {
"items": {
"$ref": "#/definitions/TelegramConfig"
},
"type": "array"
},
"victorops_configs": {
"items": {
"$ref": "#/definitions/VictorOpsConfig"
@ -2981,6 +2892,37 @@
"title": "TLSConfig configures the options for TLS connections.",
"type": "object"
},
"TelegramConfig": {
"properties": {
"api_url": {
"$ref": "#/definitions/URL"
},
"chat": {
"format": "int64",
"type": "integer"
},
"disable_notifications": {
"type": "boolean"
},
"http_config": {
"$ref": "#/definitions/HTTPClientConfig"
},
"message": {
"type": "string"
},
"parse_mode": {
"type": "string"
},
"send_resolved": {
"type": "boolean"
},
"token": {
"$ref": "#/definitions/Secret"
}
},
"title": "TelegramConfig configures notifications via Telegram.",
"type": "object"
},
"TestReceiverConfigResult": {
"properties": {
"error": {
@ -3381,7 +3323,6 @@
"type": "object"
},
"alertGroup": {
"description": "AlertGroup alert group",
"properties": {
"alerts": {
"description": "alerts",
@ -3405,7 +3346,6 @@
"type": "object"
},
"alertGroups": {
"description": "AlertGroups alert groups",
"items": {
"$ref": "#/definitions/alertGroup"
},
@ -3575,7 +3515,6 @@
"type": "array"
},
"gettableSilence": {
"description": "GettableSilence gettable silence",
"properties": {
"comment": {
"description": "comment",
@ -3624,6 +3563,7 @@
"type": "object"
},
"gettableSilences": {
"description": "GettableSilences gettable silences",
"items": {
"$ref": "#/definitions/gettableSilence"
},
@ -3734,6 +3674,7 @@
"type": "array"
},
"postableSilence": {
"description": "PostableSilence postable silence",
"properties": {
"comment": {
"description": "comment",

@ -2508,27 +2508,6 @@
"Ack": {
"type": "object"
},
"AddApiKeyCommand": {
"description": "COMMANDS",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"role": {
"type": "string",
"enum": [
"Viewer",
"Editor",
"Admin"
]
},
"secondsToLive": {
"type": "integer",
"format": "int64"
}
}
},
"Alert": {
"type": "object",
"title": "Alert has info for an alert.",
@ -2663,95 +2642,6 @@
}
}
},
"AlertRule": {
"type": "object",
"title": "AlertRule is the model for alert rules in unified alerting.",
"properties": {
"Annotations": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"Condition": {
"type": "string"
},
"DashboardUID": {
"type": "string"
},
"Data": {
"type": "array",
"items": {
"$ref": "#/definitions/AlertQuery"
}
},
"ExecErrState": {
"type": "string",
"enum": [
"Alerting",
"Error",
"OK"
]
},
"For": {
"$ref": "#/definitions/Duration"
},
"ID": {
"type": "integer",
"format": "int64"
},
"IntervalSeconds": {
"type": "integer",
"format": "int64"
},
"Labels": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"NamespaceUID": {
"type": "string"
},
"NoDataState": {
"type": "string",
"enum": [
"Alerting",
"NoData",
"OK"
]
},
"OrgID": {
"type": "integer",
"format": "int64"
},
"PanelID": {
"type": "integer",
"format": "int64"
},
"RuleGroup": {
"type": "string"
},
"RuleGroupIndex": {
"type": "integer",
"format": "int64"
},
"Title": {
"type": "string"
},
"UID": {
"type": "string"
},
"Updated": {
"type": "string",
"format": "date-time"
},
"Version": {
"type": "integer",
"format": "int64"
}
}
},
"AlertRuleGroup": {
"type": "object",
"properties": {
@ -2765,7 +2655,7 @@
"rules": {
"type": "array",
"items": {
"$ref": "#/definitions/AlertRule"
"$ref": "#/definitions/ProvisionedAlertRule"
}
},
"title": {
@ -3499,6 +3389,12 @@
"$ref": "#/definitions/SNSConfig"
}
},
"telegram_configs": {
"type": "array",
"items": {
"$ref": "#/definitions/TelegramConfig"
}
},
"victorops_configs": {
"type": "array",
"items": {
@ -3799,6 +3695,9 @@
"smtp_smarthost": {
"$ref": "#/definitions/HostPort"
},
"telegram_api_url": {
"$ref": "#/definitions/URL"
},
"victorops_api_key": {
"$ref": "#/definitions/Secret"
},
@ -4483,6 +4382,12 @@
"$ref": "#/definitions/SNSConfig"
}
},
"telegram_configs": {
"type": "array",
"items": {
"$ref": "#/definitions/TelegramConfig"
}
},
"victorops_configs": {
"type": "array",
"items": {
@ -4977,6 +4882,12 @@
"$ref": "#/definitions/SNSConfig"
}
},
"telegram_configs": {
"type": "array",
"items": {
"$ref": "#/definitions/TelegramConfig"
}
},
"victorops_configs": {
"type": "array",
"items": {
@ -5486,6 +5397,37 @@
}
}
},
"TelegramConfig": {
"type": "object",
"title": "TelegramConfig configures notifications via Telegram.",
"properties": {
"api_url": {
"$ref": "#/definitions/URL"
},
"chat": {
"type": "integer",
"format": "int64"
},
"disable_notifications": {
"type": "boolean"
},
"http_config": {
"$ref": "#/definitions/HTTPClientConfig"
},
"message": {
"type": "string"
},
"parse_mode": {
"type": "string"
},
"send_resolved": {
"type": "boolean"
},
"token": {
"$ref": "#/definitions/Secret"
}
}
},
"TestReceiverConfigResult": {
"type": "object",
"properties": {
@ -5886,7 +5828,6 @@
}
},
"alertGroup": {
"description": "AlertGroup alert group",
"type": "object",
"required": [
"alerts",
@ -5911,7 +5852,6 @@
"$ref": "#/definitions/alertGroup"
},
"alertGroups": {
"description": "AlertGroups alert groups",
"type": "array",
"items": {
"$ref": "#/definitions/alertGroup"
@ -6084,7 +6024,6 @@
"$ref": "#/definitions/gettableAlerts"
},
"gettableSilence": {
"description": "GettableSilence gettable silence",
"type": "object",
"required": [
"comment",
@ -6134,6 +6073,7 @@
"$ref": "#/definitions/gettableSilence"
},
"gettableSilences": {
"description": "GettableSilences gettable silences",
"type": "array",
"items": {
"$ref": "#/definitions/gettableSilence"
@ -6245,6 +6185,7 @@
}
},
"postableSilence": {
"description": "PostableSilence postable silence",
"type": "object",
"required": [
"comment",

@ -113,6 +113,15 @@ var (
}
)
// AlertRuleGroup is the base model for a rule group in unified alerting.
type AlertRuleGroup struct {
Title string
FolderUID string
Interval int64
Provenance Provenance
Rules []AlertRule
}
// AlertRule is the model for alert rules in unified alerting.
type AlertRule struct {
ID int64 `xorm:"pk autoincr 'id'"`

@ -7,7 +7,6 @@ import (
"time"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/quota"
@ -103,19 +102,19 @@ func (service *AlertRuleService) CreateAlertRule(ctx context.Context, rule model
return rule, nil
}
func (service *AlertRuleService) GetRuleGroup(ctx context.Context, orgID int64, folder, group string) (definitions.AlertRuleGroup, error) {
func (service *AlertRuleService) GetRuleGroup(ctx context.Context, orgID int64, folder, group string) (models.AlertRuleGroup, error) {
q := models.ListAlertRulesQuery{
OrgID: orgID,
NamespaceUIDs: []string{folder},
RuleGroup: group,
}
if err := service.ruleStore.ListAlertRules(ctx, &q); err != nil {
return definitions.AlertRuleGroup{}, err
return models.AlertRuleGroup{}, err
}
if len(q.Result) == 0 {
return definitions.AlertRuleGroup{}, store.ErrAlertRuleGroupNotFound
return models.AlertRuleGroup{}, store.ErrAlertRuleGroupNotFound
}
res := definitions.AlertRuleGroup{
res := models.AlertRuleGroup{
Title: q.Result[0].RuleGroup,
FolderUID: q.Result[0].NamespaceUID,
Interval: q.Result[0].IntervalSeconds,
@ -160,7 +159,7 @@ func (service *AlertRuleService) UpdateRuleGroup(ctx context.Context, orgID int6
})
}
func (service *AlertRuleService) ReplaceRuleGroup(ctx context.Context, orgID int64, group definitions.AlertRuleGroup, userID int64, provenance models.Provenance) error {
func (service *AlertRuleService) ReplaceRuleGroup(ctx context.Context, orgID int64, group models.AlertRuleGroup, userID int64, provenance models.Provenance) error {
if err := models.ValidateRuleGroupInterval(group.Interval, service.baseIntervalSeconds); err != nil {
return err
}
@ -353,7 +352,7 @@ func (service *AlertRuleService) deleteRules(ctx context.Context, orgID int64, t
}
// syncRuleGroupFields synchronizes calculated fields across multiple rules in a group.
func syncGroupRuleFields(group *definitions.AlertRuleGroup, orgID int64) *definitions.AlertRuleGroup {
func syncGroupRuleFields(group *models.AlertRuleGroup, orgID int64) *models.AlertRuleGroup {
for i := range group.Rules {
group.Rules[i].IntervalSeconds = group.Interval
group.Rules[i].RuleGroup = group.Title

@ -7,7 +7,6 @@ import (
"time"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/sqlstore"
@ -365,8 +364,8 @@ func createTestRule(title string, groupTitle string, orgID int64) models.AlertRu
}
}
func createDummyGroup(title string, orgID int64) definitions.AlertRuleGroup {
return definitions.AlertRuleGroup{
func createDummyGroup(title string, orgID int64) models.AlertRuleGroup {
return models.AlertRuleGroup{
Title: title,
Interval: 60,
FolderUID: "my-namespace",

Loading…
Cancel
Save