From 7f0002448ddd4a190ba787142d343ad2e7a4e137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Qu=C3=A9m=C3=A9ner?= Date: Fri, 12 Aug 2022 00:58:02 +0200 Subject: [PATCH] Alerting: use duration model for alert rule provisioning api (#53196) --- pkg/services/ngalert/api/api_provisioning.go | 13 ++++++++++--- pkg/services/ngalert/api/api_provisioning_test.go | 13 ++++++++----- .../definitions/provisioning_alert_rules.go | 15 ++++++++++----- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/pkg/services/ngalert/api/api_provisioning.go b/pkg/services/ngalert/api/api_provisioning.go index cfbe388dcb3..af4f2c210c9 100644 --- a/pkg/services/ngalert/api/api_provisioning.go +++ b/pkg/services/ngalert/api/api_provisioning.go @@ -254,7 +254,11 @@ func (srv *ProvisioningSrv) RouteRouteGetAlertRule(c *models.ReqContext, UID str } func (srv *ProvisioningSrv) RoutePostAlertRule(c *models.ReqContext, ar definitions.ProvisionedAlertRule) response.Response { - createdAlertRule, err := srv.alertRules.CreateAlertRule(c.Req.Context(), ar.UpstreamModel(), alerting_models.ProvenanceAPI, c.UserID) + upstreamModel, err := ar.UpstreamModel() + if err != nil { + ErrResp(http.StatusBadRequest, err, "") + } + createdAlertRule, err := srv.alertRules.CreateAlertRule(c.Req.Context(), upstreamModel, alerting_models.ProvenanceAPI, c.UserID) if errors.Is(err, alerting_models.ErrAlertRuleFailedValidation) { return ErrResp(http.StatusBadRequest, err, "") } @@ -274,9 +278,12 @@ func (srv *ProvisioningSrv) RoutePostAlertRule(c *models.ReqContext, ar definiti } func (srv *ProvisioningSrv) RoutePutAlertRule(c *models.ReqContext, ar definitions.ProvisionedAlertRule, UID string) response.Response { - updated := ar.UpstreamModel() + updated, err := ar.UpstreamModel() + if err != nil { + ErrResp(http.StatusBadRequest, err, "") + } updated.UID = UID - updatedAlertRule, err := srv.alertRules.UpdateAlertRule(c.Req.Context(), ar.UpstreamModel(), alerting_models.ProvenanceAPI) + updatedAlertRule, err := srv.alertRules.UpdateAlertRule(c.Req.Context(), updated, alerting_models.ProvenanceAPI) if errors.Is(err, alerting_models.ErrAlertRuleNotFound) { return response.Empty(http.StatusNotFound) } diff --git a/pkg/services/ngalert/api/api_provisioning_test.go b/pkg/services/ngalert/api/api_provisioning_test.go index 9558f40dbc3..4b61272ae0f 100644 --- a/pkg/services/ngalert/api/api_provisioning_test.go +++ b/pkg/services/ngalert/api/api_provisioning_test.go @@ -10,6 +10,7 @@ import ( prometheus "github.com/prometheus/alertmanager/config" "github.com/prometheus/alertmanager/timeinterval" + "github.com/prometheus/common/model" "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/components/simplejson" @@ -243,11 +244,13 @@ func TestProvisioningApi(t *testing.T) { t.Run("PUT returns 400", func(t *testing.T) { sut := createProvisioningSrvSut(t) rc := createTestRequestCtx() - insertRule(t, sut, createTestAlertRule("rule", 1)) - rule := createInvalidAlertRule() - - response := sut.RoutePutAlertRule(&rc, rule, "rule") + uid := "123123" + rule := createTestAlertRule("rule", 1) + rule.UID = uid + insertRule(t, sut, rule) + rule = createInvalidAlertRule() + response := sut.RoutePutAlertRule(&rc, rule, uid) require.Equal(t, 400, response.Status()) require.NotEmpty(t, response.Body()) require.Contains(t, string(response.Body()), "invalid alert rule") @@ -533,7 +536,7 @@ func createTestAlertRule(title string, orgID int64) definitions.ProvisionedAlert }, RuleGroup: "my-cool-group", FolderUID: "folder-uid", - For: time.Second * 60, + For: model.Duration(60), NoDataState: models.OK, ExecErrState: models.OkErrState, } diff --git a/pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules.go b/pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules.go index 2c9363e888e..60333b0b66d 100644 --- a/pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules.go +++ b/pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules.go @@ -4,6 +4,7 @@ import ( "time" "github.com/grafana/grafana/pkg/services/ngalert/models" + "github.com/prometheus/common/model" ) // swagger:route GET /api/v1/provisioning/alert-rules/{UID} provisioning stable RouteGetAlertRule @@ -87,7 +88,7 @@ type ProvisionedAlertRule struct { // required: true ExecErrState models.ExecutionErrorState `json:"execErrState"` // required: true - For time.Duration `json:"for"` + For model.Duration `json:"for"` // example: {"runbook_url": "https://supercoolrunbook.com/page/13"} Annotations map[string]string `json:"annotations,omitempty"` // example: {"team": "sre-team-1"} @@ -96,7 +97,11 @@ type ProvisionedAlertRule struct { Provenance models.Provenance `json:"provenance,omitempty"` } -func (a *ProvisionedAlertRule) UpstreamModel() models.AlertRule { +func (a *ProvisionedAlertRule) UpstreamModel() (models.AlertRule, error) { + forDur, err := time.ParseDuration(a.For.String()) + if err != nil { + return models.AlertRule{}, err + } return models.AlertRule{ ID: a.ID, UID: a.UID, @@ -109,10 +114,10 @@ func (a *ProvisionedAlertRule) UpstreamModel() models.AlertRule { Updated: a.Updated, NoDataState: a.NoDataState, ExecErrState: a.ExecErrState, - For: a.For, + For: forDur, Annotations: a.Annotations, Labels: a.Labels, - } + }, nil } func NewAlertRule(rule models.AlertRule, provenance models.Provenance) ProvisionedAlertRule { @@ -123,7 +128,7 @@ func NewAlertRule(rule models.AlertRule, provenance models.Provenance) Provision FolderUID: rule.NamespaceUID, RuleGroup: rule.RuleGroup, Title: rule.Title, - For: rule.For, + For: model.Duration(rule.For.Seconds()), Condition: rule.Condition, Data: rule.Data, Updated: rule.Updated,