From 0d9389e1f45e9d82ae210274c8efb649b7544f7f Mon Sep 17 00:00:00 2001 From: Alexander Weaver Date: Thu, 23 Jun 2022 15:13:39 -0500 Subject: [PATCH] Alerting: Code-gen parsing of URL parameters and fix related bugs (#50731) * Extend template and generate * Generate and fix up alertmanager endpoints * Prometheus routes * fix up Testing endpoints * touch up ruler API * Update provisioning and fix 500 * Drop dead code * Remove more dead code * Resolve merge conflicts --- pkg/services/ngalert/api/api_alertmanager.go | 7 +- pkg/services/ngalert/api/api_provisioning.go | 60 +++++-------- .../ngalert/api/api_provisioning_test.go | 33 +++---- pkg/services/ngalert/api/api_ruler.go | 20 ++--- pkg/services/ngalert/api/api_ruler_test.go | 88 +++++++------------ pkg/services/ngalert/api/api_testing.go | 4 +- pkg/services/ngalert/api/fork_ruler.go | 42 ++++----- pkg/services/ngalert/api/forked_am.go | 36 ++++---- pkg/services/ngalert/api/forked_prom.go | 4 +- .../ngalert/api/forked_provisioning.go | 48 +++++----- pkg/services/ngalert/api/forked_testing.go | 4 +- .../api/generated_base_api_alertmanager.go | 44 +++++++--- .../api/generated_base_api_prometheus.go | 7 +- .../api/generated_base_api_provisioning.go | 37 +++++--- .../ngalert/api/generated_base_api_ruler.go | 42 ++++++--- .../ngalert/api/generated_base_api_testing.go | 3 +- pkg/services/ngalert/api/lotex_am.go | 8 +- pkg/services/ngalert/api/lotex_ruler.go | 23 +++-- .../templates/controller-api.mustache | 8 +- .../ngalert/provisioning/contactpoints.go | 5 +- .../provisioning/{validate.go => errors.go} | 1 + 21 files changed, 262 insertions(+), 262 deletions(-) rename pkg/services/ngalert/provisioning/{validate.go => errors.go} (66%) diff --git a/pkg/services/ngalert/api/api_alertmanager.go b/pkg/services/ngalert/api/api_alertmanager.go index 1f9cdce877e..3db7af04b7c 100644 --- a/pkg/services/ngalert/api/api_alertmanager.go +++ b/pkg/services/ngalert/api/api_alertmanager.go @@ -18,7 +18,6 @@ import ( "github.com/grafana/grafana/pkg/services/ngalert/notifier" "github.com/grafana/grafana/pkg/services/ngalert/store" "github.com/grafana/grafana/pkg/util" - "github.com/grafana/grafana/pkg/web" ) const ( @@ -103,13 +102,12 @@ func (srv AlertmanagerSrv) RouteDeleteAlertingConfig(c *models.ReqContext) respo return response.JSON(http.StatusAccepted, util.DynMap{"message": "configuration deleted; the default is applied"}) } -func (srv AlertmanagerSrv) RouteDeleteSilence(c *models.ReqContext) response.Response { +func (srv AlertmanagerSrv) RouteDeleteSilence(c *models.ReqContext, silenceID string) response.Response { am, errResp := srv.AlertmanagerFor(c.OrgId) if errResp != nil { return errResp } - silenceID := web.Params(c.Req)[":SilenceId"] if err := am.DeleteSilence(silenceID); err != nil { if errors.Is(err, notifier.ErrSilenceNotFound) { return ErrResp(http.StatusNotFound, err, "") @@ -181,13 +179,12 @@ func (srv AlertmanagerSrv) RouteGetAMAlerts(c *models.ReqContext) response.Respo return response.JSON(http.StatusOK, alerts) } -func (srv AlertmanagerSrv) RouteGetSilence(c *models.ReqContext) response.Response { +func (srv AlertmanagerSrv) RouteGetSilence(c *models.ReqContext, silenceID string) response.Response { am, errResp := srv.AlertmanagerFor(c.OrgId) if errResp != nil { return errResp } - silenceID := web.Params(c.Req)[":SilenceId"] gettableSilence, err := am.GetSilence(silenceID) if err != nil { if errors.Is(err, notifier.ErrSilenceNotFound) { diff --git a/pkg/services/ngalert/api/api_provisioning.go b/pkg/services/ngalert/api/api_provisioning.go index d6a103a11c7..d1a6a1f1d59 100644 --- a/pkg/services/ngalert/api/api_provisioning.go +++ b/pkg/services/ngalert/api/api_provisioning.go @@ -13,14 +13,6 @@ import ( "github.com/grafana/grafana/pkg/services/ngalert/provisioning" "github.com/grafana/grafana/pkg/services/ngalert/store" "github.com/grafana/grafana/pkg/util" - "github.com/grafana/grafana/pkg/web" -) - -const ( - namePathParam = ":name" - uidPathParam = ":UID" - groupPathParam = ":Group" - folderUIDPathParam = ":FolderUID" ) type ProvisioningSrv struct { @@ -112,20 +104,22 @@ func (srv *ProvisioningSrv) RoutePostContactPoint(c *models.ReqContext, cp defin return response.JSON(http.StatusAccepted, contactPoint) } -func (srv *ProvisioningSrv) RoutePutContactPoint(c *models.ReqContext, cp definitions.EmbeddedContactPoint) response.Response { - cp.UID = pathParam(c, uidPathParam) +func (srv *ProvisioningSrv) RoutePutContactPoint(c *models.ReqContext, cp definitions.EmbeddedContactPoint, UID string) response.Response { + cp.UID = UID err := srv.contactPointService.UpdateContactPoint(c.Req.Context(), c.OrgId, cp, alerting_models.ProvenanceAPI) if errors.Is(err, provisioning.ErrValidation) { return ErrResp(http.StatusBadRequest, err, "") } + if errors.Is(err, provisioning.ErrNotFound) { + return ErrResp(http.StatusNotFound, err, "") + } if err != nil { return ErrResp(http.StatusInternalServerError, err, "") } return response.JSON(http.StatusAccepted, util.DynMap{"message": "contactpoint updated"}) } -func (srv *ProvisioningSrv) RouteDeleteContactPoint(c *models.ReqContext) response.Response { - UID := pathParam(c, uidPathParam) +func (srv *ProvisioningSrv) RouteDeleteContactPoint(c *models.ReqContext, UID string) response.Response { err := srv.contactPointService.DeleteContactPoint(c.Req.Context(), c.OrgId, UID) if err != nil { return ErrResp(http.StatusInternalServerError, err, "") @@ -145,8 +139,7 @@ func (srv *ProvisioningSrv) RouteGetTemplates(c *models.ReqContext) response.Res return response.JSON(http.StatusOK, result) } -func (srv *ProvisioningSrv) RouteGetTemplate(c *models.ReqContext) response.Response { - name := pathParam(c, namePathParam) +func (srv *ProvisioningSrv) RouteGetTemplate(c *models.ReqContext, name string) response.Response { templates, err := srv.templates.GetTemplates(c.Req.Context(), c.OrgId) if err != nil { return ErrResp(http.StatusInternalServerError, err, "") @@ -157,8 +150,7 @@ func (srv *ProvisioningSrv) RouteGetTemplate(c *models.ReqContext) response.Resp return response.Empty(http.StatusNotFound) } -func (srv *ProvisioningSrv) RoutePutTemplate(c *models.ReqContext, body definitions.MessageTemplateContent) response.Response { - name := pathParam(c, namePathParam) +func (srv *ProvisioningSrv) RoutePutTemplate(c *models.ReqContext, body definitions.MessageTemplateContent, name string) response.Response { tmpl := definitions.MessageTemplate{ Name: name, Template: body.Template, @@ -174,8 +166,7 @@ func (srv *ProvisioningSrv) RoutePutTemplate(c *models.ReqContext, body definiti return response.JSON(http.StatusAccepted, modified) } -func (srv *ProvisioningSrv) RouteDeleteTemplate(c *models.ReqContext) response.Response { - name := pathParam(c, namePathParam) +func (srv *ProvisioningSrv) RouteDeleteTemplate(c *models.ReqContext, name string) response.Response { err := srv.templates.DeleteTemplate(c.Req.Context(), c.OrgId, name) if err != nil { return ErrResp(http.StatusInternalServerError, err, "") @@ -183,8 +174,7 @@ func (srv *ProvisioningSrv) RouteDeleteTemplate(c *models.ReqContext) response.R return response.JSON(http.StatusNoContent, nil) } -func (srv *ProvisioningSrv) RouteGetMuteTiming(c *models.ReqContext) response.Response { - name := pathParam(c, namePathParam) +func (srv *ProvisioningSrv) RouteGetMuteTiming(c *models.ReqContext, name string) response.Response { timings, err := srv.muteTimings.GetMuteTimings(c.Req.Context(), c.OrgId) if err != nil { return ErrResp(http.StatusInternalServerError, err, "") @@ -217,8 +207,7 @@ func (srv *ProvisioningSrv) RoutePostMuteTiming(c *models.ReqContext, mt definit return response.JSON(http.StatusCreated, created) } -func (srv *ProvisioningSrv) RoutePutMuteTiming(c *models.ReqContext, mt definitions.MuteTimeInterval) response.Response { - name := pathParam(c, namePathParam) +func (srv *ProvisioningSrv) RoutePutMuteTiming(c *models.ReqContext, mt definitions.MuteTimeInterval, name string) response.Response { mt.Name = name mt.Provenance = alerting_models.ProvenanceAPI updated, err := srv.muteTimings.UpdateMuteTiming(c.Req.Context(), mt, c.OrgId) @@ -234,8 +223,7 @@ func (srv *ProvisioningSrv) RoutePutMuteTiming(c *models.ReqContext, mt definiti return response.JSON(http.StatusAccepted, updated) } -func (srv *ProvisioningSrv) RouteDeleteMuteTiming(c *models.ReqContext) response.Response { - name := pathParam(c, namePathParam) +func (srv *ProvisioningSrv) RouteDeleteMuteTiming(c *models.ReqContext, name string) response.Response { err := srv.muteTimings.DeleteMuteTiming(c.Req.Context(), name, c.OrgId) if err != nil { return ErrResp(http.StatusInternalServerError, err, "") @@ -243,9 +231,8 @@ func (srv *ProvisioningSrv) RouteDeleteMuteTiming(c *models.ReqContext) response return response.JSON(http.StatusNoContent, nil) } -func (srv *ProvisioningSrv) RouteRouteGetAlertRule(c *models.ReqContext) response.Response { - uid := pathParam(c, uidPathParam) - rule, provenace, err := srv.alertRules.GetAlertRule(c.Req.Context(), c.OrgId, uid) +func (srv *ProvisioningSrv) RouteRouteGetAlertRule(c *models.ReqContext, UID string) response.Response { + rule, provenace, err := srv.alertRules.GetAlertRule(c.Req.Context(), c.OrgId, UID) if err != nil { return ErrResp(http.StatusInternalServerError, err, "") } @@ -269,7 +256,9 @@ func (srv *ProvisioningSrv) RoutePostAlertRule(c *models.ReqContext, ar definiti return response.JSON(http.StatusCreated, ar) } -func (srv *ProvisioningSrv) RoutePutAlertRule(c *models.ReqContext, ar definitions.AlertRule) response.Response { +func (srv *ProvisioningSrv) RoutePutAlertRule(c *models.ReqContext, ar definitions.AlertRule, UID string) response.Response { + updated := ar.UpstreamModel() + updated.UID = UID updatedAlertRule, err := srv.alertRules.UpdateAlertRule(c.Req.Context(), ar.UpstreamModel(), alerting_models.ProvenanceAPI) if errors.Is(err, alerting_models.ErrAlertRuleNotFound) { return response.Empty(http.StatusNotFound) @@ -287,19 +276,16 @@ func (srv *ProvisioningSrv) RoutePutAlertRule(c *models.ReqContext, ar definitio return response.JSON(http.StatusOK, ar) } -func (srv *ProvisioningSrv) RouteDeleteAlertRule(c *models.ReqContext) response.Response { - uid := pathParam(c, uidPathParam) - err := srv.alertRules.DeleteAlertRule(c.Req.Context(), c.OrgId, uid, alerting_models.ProvenanceAPI) +func (srv *ProvisioningSrv) RouteDeleteAlertRule(c *models.ReqContext, UID string) response.Response { + err := srv.alertRules.DeleteAlertRule(c.Req.Context(), c.OrgId, UID, alerting_models.ProvenanceAPI) if err != nil { return ErrResp(http.StatusInternalServerError, err, "") } return response.JSON(http.StatusNoContent, "") } -func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *models.ReqContext, ag definitions.AlertRuleGroup) response.Response { - rulegroup := pathParam(c, groupPathParam) - folderUID := pathParam(c, folderUIDPathParam) - err := srv.alertRules.UpdateRuleGroup(c.Req.Context(), c.OrgId, folderUID, rulegroup, ag.Interval) +func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *models.ReqContext, ag definitions.AlertRuleGroup, folderUID string, group string) response.Response { + err := srv.alertRules.UpdateRuleGroup(c.Req.Context(), c.OrgId, folderUID, group, ag.Interval) if err != nil { if errors.Is(err, store.ErrOptimisticLock) { return ErrResp(http.StatusConflict, err, "") @@ -308,7 +294,3 @@ func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *models.ReqContext, ag defi } return response.JSON(http.StatusOK, ag) } - -func pathParam(c *models.ReqContext, param string) string { - return web.Params(c.Req)[param] -} diff --git a/pkg/services/ngalert/api/api_provisioning_test.go b/pkg/services/ngalert/api/api_provisioning_test.go index 814fe633918..118dd0edb27 100644 --- a/pkg/services/ngalert/api/api_provisioning_test.go +++ b/pkg/services/ngalert/api/api_provisioning_test.go @@ -128,13 +128,23 @@ func TestProvisioningApi(t *testing.T) { rc := createTestRequestCtx() cp := createInvalidContactPoint() - response := sut.RoutePutContactPoint(&rc, cp) + response := sut.RoutePutContactPoint(&rc, cp, "email-uid") require.Equal(t, 400, response.Status()) require.NotEmpty(t, response.Body()) require.Contains(t, string(response.Body()), "recipient must be specified") }) }) + + t.Run("are missing, PUT returns 404", func(t *testing.T) { + sut := createProvisioningSrvSut(t) + rc := createTestRequestCtx() + cp := createInvalidContactPoint() + + response := sut.RoutePutContactPoint(&rc, cp, "does not exist") + + require.Equal(t, 404, response.Status()) + }) }) t.Run("templates", func(t *testing.T) { @@ -142,10 +152,9 @@ func TestProvisioningApi(t *testing.T) { t.Run("PUT returns 400", func(t *testing.T) { sut := createProvisioningSrvSut(t) rc := createTestRequestCtx() - withURLParams(rc, namePathParam, "test") tmpl := definitions.MessageTemplateContent{Template: ""} - response := sut.RoutePutTemplate(&rc, tmpl) + response := sut.RoutePutTemplate(&rc, tmpl, "test") require.Equal(t, 400, response.Status()) require.NotEmpty(t, response.Body()) @@ -171,10 +180,9 @@ func TestProvisioningApi(t *testing.T) { t.Run("PUT returns 400", func(t *testing.T) { sut := createProvisioningSrvSut(t) rc := createTestRequestCtx() - withURLParams(rc, namePathParam, "interval") mti := createInvalidMuteTiming() - response := sut.RoutePutMuteTiming(&rc, mti) + response := sut.RoutePutMuteTiming(&rc, mti, "interval") require.Equal(t, 400, response.Status()) require.NotEmpty(t, response.Body()) @@ -185,10 +193,9 @@ func TestProvisioningApi(t *testing.T) { t.Run("are missing, PUT returns 404", func(t *testing.T) { sut := createProvisioningSrvSut(t) rc := createTestRequestCtx() - withURLParams(rc, namePathParam, "does not exist") mti := definitions.MuteTimeInterval{} - response := sut.RoutePutMuteTiming(&rc, mti) + response := sut.RoutePutMuteTiming(&rc, mti, "does not exist") require.Equal(t, 404, response.Status()) }) @@ -214,7 +221,7 @@ func TestProvisioningApi(t *testing.T) { insertRule(t, sut, createTestAlertRule("rule", 1)) rule := createInvalidAlertRule() - response := sut.RoutePutAlertRule(&rc, rule) + response := sut.RoutePutAlertRule(&rc, rule, "rule") require.Equal(t, 400, response.Status()) require.NotEmpty(t, response.Body()) @@ -227,7 +234,7 @@ func TestProvisioningApi(t *testing.T) { rc := createTestRequestCtx() rule := createTestAlertRule("rule", 1) - response := sut.RoutePutAlertRule(&rc, rule) + response := sut.RoutePutAlertRule(&rc, rule, "does not exist") require.Equal(t, 404, response.Status()) }) @@ -274,12 +281,6 @@ func createTestRequestCtx() gfcore.ReqContext { } } -func withURLParams(rc gfcore.ReqContext, key, value string) { - params := web.Params(rc.Req) - params[key] = value - rc.Req = web.SetURLParams(rc.Req, params) -} - type fakeNotificationPolicyService struct { tree definitions.Route prov models.Provenance @@ -407,7 +408,7 @@ var testConfig = ` "receivers": [{ "name": "grafana-default-email", "grafana_managed_receiver_configs": [{ - "uid": "", + "uid": "email-uid", "name": "email receiver", "type": "email", "isDefault": true, diff --git a/pkg/services/ngalert/api/api_ruler.go b/pkg/services/ngalert/api/api_ruler.go index 3bbe6dcf87d..6dd093c66d4 100644 --- a/pkg/services/ngalert/api/api_ruler.go +++ b/pkg/services/ngalert/api/api_ruler.go @@ -26,7 +26,6 @@ import ( ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/schedule" "github.com/grafana/grafana/pkg/util" - "github.com/grafana/grafana/pkg/web" ) type RulerSrv struct { @@ -46,10 +45,9 @@ var ( errProvisionedResource = errors.New("request affects resources created via provisioning API") ) -// RouteDeleteAlertRules deletes all alert rules user is authorized to access in the namespace (request parameter :Namespace) -// or, if specified, a group of rules (request parameter :Groupname) in the namespace -func (srv RulerSrv) RouteDeleteAlertRules(c *models.ReqContext) response.Response { - namespaceTitle := web.Params(c.Req)[":Namespace"] +// RouteDeleteAlertRules deletes all alert rules user is authorized to access in the given namespace +// or, if non-empty, a specific group of rules in the namespace +func (srv RulerSrv) RouteDeleteAlertRules(c *models.ReqContext, namespaceTitle string, group string) response.Response { namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgId, c.SignedInUser, true) if err != nil { return toNamespaceErrorResponse(err) @@ -59,7 +57,7 @@ func (srv RulerSrv) RouteDeleteAlertRules(c *models.ReqContext) response.Respons namespace.Title, } var ruleGroup string - if group, ok := web.Params(c.Req)[":Groupname"]; ok { + if group != "" { ruleGroup = group loggerCtx = append(loggerCtx, "group", group) } @@ -158,8 +156,7 @@ func (srv RulerSrv) RouteDeleteAlertRules(c *models.ReqContext) response.Respons } // RouteGetNamespaceRulesConfig returns all rules in a specific folder that user has access to -func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *models.ReqContext) response.Response { - namespaceTitle := web.Params(c.Req)[":Namespace"] +func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *models.ReqContext, namespaceTitle string) response.Response { namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgId, c.SignedInUser, false) if err != nil { return toNamespaceErrorResponse(err) @@ -201,14 +198,12 @@ func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *models.ReqContext) response. // RouteGetRulesGroupConfig returns rules that belong to a specific group in a specific namespace (folder). // If user does not have access to at least one of the rule in the group, returns status 401 Unauthorized -func (srv RulerSrv) RouteGetRulesGroupConfig(c *models.ReqContext) response.Response { - namespaceTitle := web.Params(c.Req)[":Namespace"] +func (srv RulerSrv) RouteGetRulesGroupConfig(c *models.ReqContext, namespaceTitle string, ruleGroup string) response.Response { namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgId, c.SignedInUser, false) if err != nil { return toNamespaceErrorResponse(err) } - ruleGroup := web.Params(c.Req)[":Groupname"] q := ngmodels.ListAlertRulesQuery{ OrgID: c.SignedInUser.OrgId, NamespaceUIDs: []string{namespace.Uid}, @@ -307,8 +302,7 @@ func (srv RulerSrv) RouteGetRulesConfig(c *models.ReqContext) response.Response return response.JSON(http.StatusOK, result) } -func (srv RulerSrv) RoutePostNameRulesConfig(c *models.ReqContext, ruleGroupConfig apimodels.PostableRuleGroupConfig) response.Response { - namespaceTitle := web.Params(c.Req)[":Namespace"] +func (srv RulerSrv) RoutePostNameRulesConfig(c *models.ReqContext, ruleGroupConfig apimodels.PostableRuleGroupConfig, namespaceTitle string) response.Response { namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgId, c.SignedInUser, true) if err != nil { return toNamespaceErrorResponse(err) diff --git a/pkg/services/ngalert/api/api_ruler_test.go b/pkg/services/ngalert/api/api_ruler_test.go index d624620c88f..1521838bef8 100644 --- a/pkg/services/ngalert/api/api_ruler_test.go +++ b/pkg/services/ngalert/api/api_ruler_test.go @@ -336,10 +336,8 @@ func TestRouteDeleteAlertRules(t *testing.T) { scheduler.On("DeleteAlertRule", mock.Anything).Panic("should not be called") ac := acMock.New().WithDisabled() - request := createRequestContext(orgID, models2.ROLE_VIEWER, map[string]string{ - ":Namespace": folder.Title, - }) - response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request) + request := createRequestContext(orgID, models2.ROLE_VIEWER, nil) + response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request, folder.Title, "") require.Equalf(t, 401, response.Status(), "Expected 403 but got %d: %v", response.Status(), string(response.Body())) scheduler.AssertNotCalled(t, "DeleteAlertRule") @@ -358,10 +356,8 @@ func TestRouteDeleteAlertRules(t *testing.T) { scheduler.On("DeleteAlertRule", mock.Anything) ac := acMock.New().WithDisabled() - request := createRequestContext(orgID, models2.ROLE_EDITOR, map[string]string{ - ":Namespace": folder.Title, - }) - response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request) + request := createRequestContext(orgID, models2.ROLE_EDITOR, nil) + response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request, folder.Title, "") require.Equalf(t, 202, response.Status(), "Expected 202 but got %d: %v", response.Status(), string(response.Body())) assertRulesDeleted(t, rulesInFolder, ruleStore, scheduler) }) @@ -382,11 +378,8 @@ func TestRouteDeleteAlertRules(t *testing.T) { scheduler.On("DeleteAlertRule", mock.Anything) ac := acMock.New().WithDisabled() - request := createRequestContext(orgID, models2.ROLE_EDITOR, map[string]string{ - ":Namespace": folder.Title, - ":Groupname": groupName, - }) - response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request) + request := createRequestContext(orgID, models2.ROLE_EDITOR, nil) + response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request, folder.Title, groupName) require.Equalf(t, 202, response.Status(), "Expected 202 but got %d: %v", response.Status(), string(response.Body())) assertRulesDeleted(t, rulesInFolderInGroup, ruleStore, scheduler) }) @@ -409,10 +402,8 @@ func TestRouteDeleteAlertRules(t *testing.T) { err := svc.provenanceStore.SetProvenance(context.Background(), rulesInFolder[0], orgID, models.ProvenanceAPI) require.NoError(t, err) - request := createRequestContext(orgID, models2.ROLE_EDITOR, map[string]string{ - ":Namespace": folder.Title, - }) - response := svc.RouteDeleteAlertRules(request) + request := createRequestContext(orgID, models2.ROLE_EDITOR, nil) + response := svc.RouteDeleteAlertRules(request, folder.Title, "") require.Equalf(t, 202, response.Status(), "Expected 202 but got %d: %v", response.Status(), string(response.Body())) assertRulesDeleted(t, rulesInFolder[1:], ruleStore, scheduler) }) @@ -430,10 +421,8 @@ func TestRouteDeleteAlertRules(t *testing.T) { scheduler.On("DeleteAlertRule", mock.Anything).Panic("should not be called") ac := acMock.New() - request := createRequestContext(orgID, "None", map[string]string{ - ":Namespace": folder.Title, - }) - response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request) + request := createRequestContext(orgID, "None", nil) + response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request, folder.Title, "") require.Equalf(t, 401, response.Status(), "Expected 403 but got %d: %v", response.Status(), string(response.Body())) scheduler.AssertNotCalled(t, "DeleteAlertRule") @@ -453,11 +442,9 @@ func TestRouteDeleteAlertRules(t *testing.T) { scheduler.On("DeleteAlertRule", mock.Anything) ac := acMock.New().WithPermissions(createPermissionsForRules(rulesInFolder)) - request := createRequestContext(orgID, "None", map[string]string{ - ":Namespace": folder.Title, - }) + request := createRequestContext(orgID, "None", nil) - response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request) + response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request, folder.Title, "") require.Equalf(t, 202, response.Status(), "Expected 202 but got %d: %v", response.Status(), string(response.Body())) assertRulesDeleted(t, rulesInFolder, ruleStore, scheduler) }) @@ -479,11 +466,9 @@ func TestRouteDeleteAlertRules(t *testing.T) { err := svc.provenanceStore.SetProvenance(context.Background(), rulesInFolder[0], orgID, models.ProvenanceAPI) require.NoError(t, err) - request := createRequestContext(orgID, "None", map[string]string{ - ":Namespace": folder.Title, - }) + request := createRequestContext(orgID, "None", nil) - response := svc.RouteDeleteAlertRules(request) + response := svc.RouteDeleteAlertRules(request, folder.Title, "") require.Equalf(t, 202, response.Status(), "Expected 202 but got %d: %v", response.Status(), string(response.Body())) assertRulesDeleted(t, rulesInFolder[1:], ruleStore, scheduler) }) @@ -504,11 +489,9 @@ func TestRouteDeleteAlertRules(t *testing.T) { scheduler.On("DeleteAlertRule", mock.Anything) ac := acMock.New().WithPermissions(createPermissionsForRules(authorizedRulesInFolder)) - request := createRequestContext(orgID, "None", map[string]string{ - ":Namespace": folder.Title, - }) + request := createRequestContext(orgID, "None", nil) - response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request) + response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request, folder.Title, "") require.Equalf(t, 202, response.Status(), "Expected 202 but got %d: %v", response.Status(), string(response.Body())) assertRulesDeleted(t, authorizedRulesInFolder, ruleStore, scheduler) }) @@ -531,11 +514,8 @@ func TestRouteDeleteAlertRules(t *testing.T) { scheduler.On("DeleteAlertRule", mock.Anything) ac := acMock.New().WithPermissions(createPermissionsForRules(authorizedRulesInGroup)) - request := createRequestContext(orgID, "None", map[string]string{ - ":Namespace": folder.Title, - ":Groupname": groupName, - }) - response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request) + request := createRequestContext(orgID, "None", nil) + response := createService(ac, ruleStore, scheduler).RouteDeleteAlertRules(request, folder.Title, groupName) require.Equalf(t, 202, response.Status(), "Expected 202 but got %d: %v", response.Status(), string(response.Body())) assertRulesDeleted(t, authorizedRulesInGroup, ruleStore, scheduler) }) @@ -555,9 +535,8 @@ func TestRouteGetNamespaceRulesConfig(t *testing.T) { ruleStore.PutRule(context.Background(), models.GenerateAlertRules(rand.Intn(4)+2, models.AlertRuleGen(withOrgID(orgID), withNamespace(folder)))...) ac := acMock.New().WithPermissions(createPermissionsForRules(expectedRules)) - response := createService(ac, ruleStore, nil).RouteGetNamespaceRulesConfig(createRequestContext(orgID, "", map[string]string{ - ":Namespace": folder.Title, - })) + req := createRequestContext(orgID, "", nil) + response := createService(ac, ruleStore, nil).RouteGetNamespaceRulesConfig(req, folder.Title) require.Equal(t, http.StatusAccepted, response.Status()) result := &apimodels.NamespaceConfigResponse{} @@ -591,9 +570,8 @@ func TestRouteGetNamespaceRulesConfig(t *testing.T) { ruleStore.PutRule(context.Background(), expectedRules...) ac := acMock.New().WithDisabled() - response := createService(ac, ruleStore, nil).RouteGetNamespaceRulesConfig(createRequestContext(orgID, models2.ROLE_VIEWER, map[string]string{ - ":Namespace": folder.Title, - })) + req := createRequestContext(orgID, models2.ROLE_VIEWER, nil) + response := createService(ac, ruleStore, nil).RouteGetNamespaceRulesConfig(req, folder.Title) require.Equal(t, http.StatusAccepted, response.Status()) result := &apimodels.NamespaceConfigResponse{} @@ -635,9 +613,8 @@ func TestRouteGetNamespaceRulesConfig(t *testing.T) { err := svc.provenanceStore.SetProvenance(context.Background(), rule, orgID, models.ProvenanceAPI) require.NoError(t, err) - response := svc.RouteGetNamespaceRulesConfig(createRequestContext(orgID, models2.ROLE_VIEWER, map[string]string{ - ":Namespace": folder.Title, - })) + req := createRequestContext(orgID, models2.ROLE_VIEWER, nil) + response := svc.RouteGetNamespaceRulesConfig(req, folder.Title) require.Equal(t, http.StatusAccepted, response.Status()) result := &apimodels.NamespaceConfigResponse{} @@ -671,9 +648,7 @@ func TestRouteGetNamespaceRulesConfig(t *testing.T) { ruleStore.PutRule(context.Background(), expectedRules...) ac := acMock.New().WithDisabled() - response := createService(ac, ruleStore, nil).RouteGetNamespaceRulesConfig(createRequestContext(orgID, models2.ROLE_VIEWER, map[string]string{ - ":Namespace": folder.Title, - })) + response := createService(ac, ruleStore, nil).RouteGetNamespaceRulesConfig(createRequestContext(orgID, models2.ROLE_VIEWER, nil), folder.Title) require.Equal(t, http.StatusAccepted, response.Status()) result := &apimodels.NamespaceConfigResponse{} @@ -806,13 +781,13 @@ func TestRouteGetRulesGroupConfig(t *testing.T) { t.Run("and return 401 if user does not have access one of rules", func(t *testing.T) { ac := acMock.New().WithPermissions(createPermissionsForRules(expectedRules[1:])) - response := createService(ac, ruleStore, nil).RouteGetRulesGroupConfig(request) + response := createService(ac, ruleStore, nil).RouteGetRulesGroupConfig(request, folder.Title, groupKey.RuleGroup) require.Equal(t, http.StatusUnauthorized, response.Status()) }) t.Run("and return rules if user has access to all of them", func(t *testing.T) { ac := acMock.New().WithPermissions(createPermissionsForRules(expectedRules)) - response := createService(ac, ruleStore, nil).RouteGetRulesGroupConfig(request) + response := createService(ac, ruleStore, nil).RouteGetRulesGroupConfig(request, folder.Title, groupKey.RuleGroup) require.Equal(t, http.StatusAccepted, response.Status()) result := &apimodels.RuleGroupConfigResponse{} @@ -835,10 +810,7 @@ func TestRouteGetRulesGroupConfig(t *testing.T) { ruleStore.PutRule(context.Background(), expectedRules...) ac := acMock.New().WithDisabled() - response := createService(ac, ruleStore, nil).RouteGetRulesGroupConfig(createRequestContext(orgID, models2.ROLE_VIEWER, map[string]string{ - ":Namespace": folder.Title, - ":Groupname": groupKey.RuleGroup, - })) + response := createService(ac, ruleStore, nil).RouteGetRulesGroupConfig(createRequestContext(orgID, models2.ROLE_VIEWER, nil), folder.Title, groupKey.RuleGroup) require.Equal(t, http.StatusAccepted, response.Status()) result := &apimodels.RuleGroupConfigResponse{} @@ -1079,7 +1051,9 @@ func createRequestContext(orgID int64, role models2.RoleType, params map[string] ctx := web.Context{Req: &http.Request{ URL: uri, }} - ctx.Req = web.SetURLParams(ctx.Req, params) + if params != nil { + ctx.Req = web.SetURLParams(ctx.Req, params) + } return &models2.ReqContext{ IsSignedIn: true, diff --git a/pkg/services/ngalert/api/api_testing.go b/pkg/services/ngalert/api/api_testing.go index 6b0a472fec2..b5fc1234424 100644 --- a/pkg/services/ngalert/api/api_testing.go +++ b/pkg/services/ngalert/api/api_testing.go @@ -20,7 +20,6 @@ import ( "github.com/grafana/grafana/pkg/services/ngalert/eval" ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/util" - "github.com/grafana/grafana/pkg/web" ) type TestingApiSrv struct { @@ -69,13 +68,12 @@ func (srv TestingApiSrv) RouteTestGrafanaRuleConfig(c *models.ReqContext, body a }) } -func (srv TestingApiSrv) RouteTestRuleConfig(c *models.ReqContext, body apimodels.TestRulePayload) response.Response { +func (srv TestingApiSrv) RouteTestRuleConfig(c *models.ReqContext, body apimodels.TestRulePayload, datasourceUID string) response.Response { if body.Type() != apimodels.LoTexRulerBackend { return ErrResp(http.StatusBadRequest, errors.New("unexpected payload"), "") } var path string - datasourceUID := web.Params(c.Req)[":DatasourceUID"] ds, err := srv.DatasourceCache.GetDatasourceByUID(context.Background(), datasourceUID, c.SignedInUser, c.SkipCache) if err != nil { return ErrResp(http.StatusInternalServerError, err, "failed to get datasource") diff --git a/pkg/services/ngalert/api/fork_ruler.go b/pkg/services/ngalert/api/fork_ruler.go index 6b6ffb8919c..739370d3a04 100644 --- a/pkg/services/ngalert/api/fork_ruler.go +++ b/pkg/services/ngalert/api/fork_ruler.go @@ -25,59 +25,59 @@ func NewForkedRuler(datasourceCache datasources.CacheService, lotex *LotexRuler, } } -func (f *ForkedRulerApi) forkRouteDeleteNamespaceRulesConfig(ctx *models.ReqContext) response.Response { +func (f *ForkedRulerApi) forkRouteDeleteNamespaceRulesConfig(ctx *models.ReqContext, dsUID, namespace string) response.Response { t, err := backendTypeByUID(ctx, f.DatasourceCache) if err != nil { return ErrResp(400, err, "") } switch t { case apimodels.LoTexRulerBackend: - return f.LotexRuler.RouteDeleteNamespaceRulesConfig(ctx) + return f.LotexRuler.RouteDeleteNamespaceRulesConfig(ctx, namespace) default: return ErrResp(400, fmt.Errorf("unexpected backend type (%v)", t), "") } } -func (f *ForkedRulerApi) forkRouteDeleteRuleGroupConfig(ctx *models.ReqContext) response.Response { +func (f *ForkedRulerApi) forkRouteDeleteRuleGroupConfig(ctx *models.ReqContext, dsUID, namespace, group string) response.Response { t, err := backendTypeByUID(ctx, f.DatasourceCache) if err != nil { return ErrResp(400, err, "") } switch t { case apimodels.LoTexRulerBackend: - return f.LotexRuler.RouteDeleteRuleGroupConfig(ctx) + return f.LotexRuler.RouteDeleteRuleGroupConfig(ctx, namespace, group) default: return ErrResp(400, fmt.Errorf("unexpected backend type (%v)", t), "") } } -func (f *ForkedRulerApi) forkRouteGetNamespaceRulesConfig(ctx *models.ReqContext) response.Response { +func (f *ForkedRulerApi) forkRouteGetNamespaceRulesConfig(ctx *models.ReqContext, dsUID, namespace string) response.Response { t, err := backendTypeByUID(ctx, f.DatasourceCache) if err != nil { return ErrResp(400, err, "") } switch t { case apimodels.LoTexRulerBackend: - return f.LotexRuler.RouteGetNamespaceRulesConfig(ctx) + return f.LotexRuler.RouteGetNamespaceRulesConfig(ctx, namespace) default: return ErrResp(400, fmt.Errorf("unexpected backend type (%v)", t), "") } } -func (f *ForkedRulerApi) forkRouteGetRulegGroupConfig(ctx *models.ReqContext) response.Response { +func (f *ForkedRulerApi) forkRouteGetRulegGroupConfig(ctx *models.ReqContext, dsUID, namespace, group string) response.Response { t, err := backendTypeByUID(ctx, f.DatasourceCache) if err != nil { return ErrResp(400, err, "") } switch t { case apimodels.LoTexRulerBackend: - return f.LotexRuler.RouteGetRulegGroupConfig(ctx) + return f.LotexRuler.RouteGetRulegGroupConfig(ctx, namespace, group) default: return ErrResp(400, fmt.Errorf("unexpected backend type (%v)", t), "") } } -func (f *ForkedRulerApi) forkRouteGetRulesConfig(ctx *models.ReqContext) response.Response { +func (f *ForkedRulerApi) forkRouteGetRulesConfig(ctx *models.ReqContext, dsUID string) response.Response { t, err := backendTypeByUID(ctx, f.DatasourceCache) if err != nil { return ErrResp(400, err, "") @@ -90,7 +90,7 @@ func (f *ForkedRulerApi) forkRouteGetRulesConfig(ctx *models.ReqContext) respons } } -func (f *ForkedRulerApi) forkRoutePostNameRulesConfig(ctx *models.ReqContext, conf apimodels.PostableRuleGroupConfig) response.Response { +func (f *ForkedRulerApi) forkRoutePostNameRulesConfig(ctx *models.ReqContext, conf apimodels.PostableRuleGroupConfig, dsUID, namespace string) response.Response { backendType, err := backendTypeByUID(ctx, f.DatasourceCache) if err != nil { return ErrResp(400, err, "") @@ -103,36 +103,36 @@ func (f *ForkedRulerApi) forkRoutePostNameRulesConfig(ctx *models.ReqContext, co switch backendType { case apimodels.LoTexRulerBackend: - return f.LotexRuler.RoutePostNameRulesConfig(ctx, conf) + return f.LotexRuler.RoutePostNameRulesConfig(ctx, conf, namespace) default: return ErrResp(400, fmt.Errorf("unexpected backend type (%v)", backendType), "") } } -func (f *ForkedRulerApi) forkRouteDeleteNamespaceGrafanaRulesConfig(ctx *models.ReqContext) response.Response { - return f.GrafanaRuler.RouteDeleteAlertRules(ctx) +func (f *ForkedRulerApi) forkRouteDeleteNamespaceGrafanaRulesConfig(ctx *models.ReqContext, namespace string) response.Response { + return f.GrafanaRuler.RouteDeleteAlertRules(ctx, namespace, "") } -func (f *ForkedRulerApi) forkRouteDeleteGrafanaRuleGroupConfig(ctx *models.ReqContext) response.Response { - return f.GrafanaRuler.RouteDeleteAlertRules(ctx) +func (f *ForkedRulerApi) forkRouteDeleteGrafanaRuleGroupConfig(ctx *models.ReqContext, namespace, groupName string) response.Response { + return f.GrafanaRuler.RouteDeleteAlertRules(ctx, namespace, groupName) } -func (f *ForkedRulerApi) forkRouteGetNamespaceGrafanaRulesConfig(ctx *models.ReqContext) response.Response { - return f.GrafanaRuler.RouteGetNamespaceRulesConfig(ctx) +func (f *ForkedRulerApi) forkRouteGetNamespaceGrafanaRulesConfig(ctx *models.ReqContext, namespace string) response.Response { + return f.GrafanaRuler.RouteGetNamespaceRulesConfig(ctx, namespace) } -func (f *ForkedRulerApi) forkRouteGetGrafanaRuleGroupConfig(ctx *models.ReqContext) response.Response { - return f.GrafanaRuler.RouteGetRulesGroupConfig(ctx) +func (f *ForkedRulerApi) forkRouteGetGrafanaRuleGroupConfig(ctx *models.ReqContext, namespace, group string) response.Response { + return f.GrafanaRuler.RouteGetRulesGroupConfig(ctx, namespace, group) } func (f *ForkedRulerApi) forkRouteGetGrafanaRulesConfig(ctx *models.ReqContext) response.Response { return f.GrafanaRuler.RouteGetRulesConfig(ctx) } -func (f *ForkedRulerApi) forkRoutePostNameGrafanaRulesConfig(ctx *models.ReqContext, conf apimodels.PostableRuleGroupConfig) response.Response { +func (f *ForkedRulerApi) forkRoutePostNameGrafanaRulesConfig(ctx *models.ReqContext, conf apimodels.PostableRuleGroupConfig, namespace string) response.Response { payloadType := conf.Type() if payloadType != apimodels.GrafanaBackend { return ErrResp(400, fmt.Errorf("unexpected backend type (%v) vs payload type (%v)", apimodels.GrafanaBackend, payloadType), "") } - return f.GrafanaRuler.RoutePostNameRulesConfig(ctx, conf) + return f.GrafanaRuler.RoutePostNameRulesConfig(ctx, conf, namespace) } diff --git a/pkg/services/ngalert/api/forked_am.go b/pkg/services/ngalert/api/forked_am.go index 069a0bce6c5..28ad7442f7d 100644 --- a/pkg/services/ngalert/api/forked_am.go +++ b/pkg/services/ngalert/api/forked_am.go @@ -38,7 +38,7 @@ func (f *ForkedAlertmanagerApi) getService(ctx *models.ReqContext) (*LotexAM, er } } -func (f *ForkedAlertmanagerApi) forkRouteGetAMStatus(ctx *models.ReqContext) response.Response { +func (f *ForkedAlertmanagerApi) forkRouteGetAMStatus(ctx *models.ReqContext, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return response.Error(400, err.Error(), nil) @@ -47,7 +47,7 @@ func (f *ForkedAlertmanagerApi) forkRouteGetAMStatus(ctx *models.ReqContext) res return s.RouteGetAMStatus(ctx) } -func (f *ForkedAlertmanagerApi) forkRouteCreateSilence(ctx *models.ReqContext, body apimodels.PostableSilence) response.Response { +func (f *ForkedAlertmanagerApi) forkRouteCreateSilence(ctx *models.ReqContext, body apimodels.PostableSilence, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return ErrResp(400, err, "") @@ -56,7 +56,7 @@ func (f *ForkedAlertmanagerApi) forkRouteCreateSilence(ctx *models.ReqContext, b return s.RouteCreateSilence(ctx, body) } -func (f *ForkedAlertmanagerApi) forkRouteDeleteAlertingConfig(ctx *models.ReqContext) response.Response { +func (f *ForkedAlertmanagerApi) forkRouteDeleteAlertingConfig(ctx *models.ReqContext, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return ErrResp(400, err, "") @@ -65,16 +65,16 @@ func (f *ForkedAlertmanagerApi) forkRouteDeleteAlertingConfig(ctx *models.ReqCon return s.RouteDeleteAlertingConfig(ctx) } -func (f *ForkedAlertmanagerApi) forkRouteDeleteSilence(ctx *models.ReqContext) response.Response { +func (f *ForkedAlertmanagerApi) forkRouteDeleteSilence(ctx *models.ReqContext, silenceID string, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return ErrResp(400, err, "") } - return s.RouteDeleteSilence(ctx) + return s.RouteDeleteSilence(ctx, silenceID) } -func (f *ForkedAlertmanagerApi) forkRouteGetAlertingConfig(ctx *models.ReqContext) response.Response { +func (f *ForkedAlertmanagerApi) forkRouteGetAlertingConfig(ctx *models.ReqContext, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return ErrResp(400, err, "") @@ -83,7 +83,7 @@ func (f *ForkedAlertmanagerApi) forkRouteGetAlertingConfig(ctx *models.ReqContex return s.RouteGetAlertingConfig(ctx) } -func (f *ForkedAlertmanagerApi) forkRouteGetAMAlertGroups(ctx *models.ReqContext) response.Response { +func (f *ForkedAlertmanagerApi) forkRouteGetAMAlertGroups(ctx *models.ReqContext, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return ErrResp(400, err, "") @@ -92,7 +92,7 @@ func (f *ForkedAlertmanagerApi) forkRouteGetAMAlertGroups(ctx *models.ReqContext return s.RouteGetAMAlertGroups(ctx) } -func (f *ForkedAlertmanagerApi) forkRouteGetAMAlerts(ctx *models.ReqContext) response.Response { +func (f *ForkedAlertmanagerApi) forkRouteGetAMAlerts(ctx *models.ReqContext, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return ErrResp(400, err, "") @@ -101,16 +101,16 @@ func (f *ForkedAlertmanagerApi) forkRouteGetAMAlerts(ctx *models.ReqContext) res return s.RouteGetAMAlerts(ctx) } -func (f *ForkedAlertmanagerApi) forkRouteGetSilence(ctx *models.ReqContext) response.Response { +func (f *ForkedAlertmanagerApi) forkRouteGetSilence(ctx *models.ReqContext, silenceID string, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return ErrResp(400, err, "") } - return s.RouteGetSilence(ctx) + return s.RouteGetSilence(ctx, silenceID) } -func (f *ForkedAlertmanagerApi) forkRouteGetSilences(ctx *models.ReqContext) response.Response { +func (f *ForkedAlertmanagerApi) forkRouteGetSilences(ctx *models.ReqContext, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return ErrResp(400, err, "") @@ -119,7 +119,7 @@ func (f *ForkedAlertmanagerApi) forkRouteGetSilences(ctx *models.ReqContext) res return s.RouteGetSilences(ctx) } -func (f *ForkedAlertmanagerApi) forkRoutePostAlertingConfig(ctx *models.ReqContext, body apimodels.PostableUserConfig) response.Response { +func (f *ForkedAlertmanagerApi) forkRoutePostAlertingConfig(ctx *models.ReqContext, body apimodels.PostableUserConfig, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return ErrResp(400, err, "") @@ -137,7 +137,7 @@ func (f *ForkedAlertmanagerApi) forkRoutePostAlertingConfig(ctx *models.ReqConte return s.RoutePostAlertingConfig(ctx, body) } -func (f *ForkedAlertmanagerApi) forkRoutePostAMAlerts(ctx *models.ReqContext, body apimodels.PostableAlerts) response.Response { +func (f *ForkedAlertmanagerApi) forkRoutePostAMAlerts(ctx *models.ReqContext, body apimodels.PostableAlerts, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return ErrResp(400, err, "") @@ -146,7 +146,7 @@ func (f *ForkedAlertmanagerApi) forkRoutePostAMAlerts(ctx *models.ReqContext, bo return s.RoutePostAMAlerts(ctx, body) } -func (f *ForkedAlertmanagerApi) forkRoutePostTestReceivers(ctx *models.ReqContext, body apimodels.TestReceiversConfigBodyParams) response.Response { +func (f *ForkedAlertmanagerApi) forkRoutePostTestReceivers(ctx *models.ReqContext, body apimodels.TestReceiversConfigBodyParams, dsUID string) response.Response { s, err := f.getService(ctx) if err != nil { return ErrResp(400, err, "") @@ -155,8 +155,8 @@ func (f *ForkedAlertmanagerApi) forkRoutePostTestReceivers(ctx *models.ReqContex return s.RoutePostTestReceivers(ctx, body) } -func (f *ForkedAlertmanagerApi) forkRouteDeleteGrafanaSilence(ctx *models.ReqContext) response.Response { - return f.GrafanaSvc.RouteDeleteSilence(ctx) +func (f *ForkedAlertmanagerApi) forkRouteDeleteGrafanaSilence(ctx *models.ReqContext, id string) response.Response { + return f.GrafanaSvc.RouteDeleteSilence(ctx, id) } func (f *ForkedAlertmanagerApi) forkRouteDeleteGrafanaAlertingConfig(ctx *models.ReqContext) response.Response { @@ -183,8 +183,8 @@ func (f *ForkedAlertmanagerApi) forkRouteGetGrafanaAlertingConfig(ctx *models.Re return f.GrafanaSvc.RouteGetAlertingConfig(ctx) } -func (f *ForkedAlertmanagerApi) forkRouteGetGrafanaSilence(ctx *models.ReqContext) response.Response { - return f.GrafanaSvc.RouteGetSilence(ctx) +func (f *ForkedAlertmanagerApi) forkRouteGetGrafanaSilence(ctx *models.ReqContext, id string) response.Response { + return f.GrafanaSvc.RouteGetSilence(ctx, id) } func (f *ForkedAlertmanagerApi) forkRouteGetGrafanaSilences(ctx *models.ReqContext) response.Response { diff --git a/pkg/services/ngalert/api/forked_prom.go b/pkg/services/ngalert/api/forked_prom.go index b0a617ff5fb..7009969c43a 100644 --- a/pkg/services/ngalert/api/forked_prom.go +++ b/pkg/services/ngalert/api/forked_prom.go @@ -24,7 +24,7 @@ func NewForkedProm(datasourceCache datasources.CacheService, proxy *LotexProm, g } } -func (f *ForkedPrometheusApi) forkRouteGetAlertStatuses(ctx *models.ReqContext) response.Response { +func (f *ForkedPrometheusApi) forkRouteGetAlertStatuses(ctx *models.ReqContext, dsUID string) response.Response { t, err := backendTypeByUID(ctx, f.DatasourceCache) if err != nil { return ErrResp(400, err, "") @@ -38,7 +38,7 @@ func (f *ForkedPrometheusApi) forkRouteGetAlertStatuses(ctx *models.ReqContext) } } -func (f *ForkedPrometheusApi) forkRouteGetRuleStatuses(ctx *models.ReqContext) response.Response { +func (f *ForkedPrometheusApi) forkRouteGetRuleStatuses(ctx *models.ReqContext, dsUID string) response.Response { t, err := backendTypeByUID(ctx, f.DatasourceCache) if err != nil { return ErrResp(400, err, "") diff --git a/pkg/services/ngalert/api/forked_provisioning.go b/pkg/services/ngalert/api/forked_provisioning.go index a0a94c76e1e..6446ef47bb5 100644 --- a/pkg/services/ngalert/api/forked_provisioning.go +++ b/pkg/services/ngalert/api/forked_provisioning.go @@ -35,32 +35,32 @@ func (f *ForkedProvisioningApi) forkRoutePostContactpoints(ctx *models.ReqContex return f.svc.RoutePostContactPoint(ctx, cp) } -func (f *ForkedProvisioningApi) forkRoutePutContactpoint(ctx *models.ReqContext, cp apimodels.EmbeddedContactPoint) response.Response { - return f.svc.RoutePutContactPoint(ctx, cp) +func (f *ForkedProvisioningApi) forkRoutePutContactpoint(ctx *models.ReqContext, cp apimodels.EmbeddedContactPoint, UID string) response.Response { + return f.svc.RoutePutContactPoint(ctx, cp, UID) } -func (f *ForkedProvisioningApi) forkRouteDeleteContactpoints(ctx *models.ReqContext) response.Response { - return f.svc.RouteDeleteContactPoint(ctx) +func (f *ForkedProvisioningApi) forkRouteDeleteContactpoints(ctx *models.ReqContext, UID string) response.Response { + return f.svc.RouteDeleteContactPoint(ctx, UID) } func (f *ForkedProvisioningApi) forkRouteGetTemplates(ctx *models.ReqContext) response.Response { return f.svc.RouteGetTemplates(ctx) } -func (f *ForkedProvisioningApi) forkRouteGetTemplate(ctx *models.ReqContext) response.Response { - return f.svc.RouteGetTemplate(ctx) +func (f *ForkedProvisioningApi) forkRouteGetTemplate(ctx *models.ReqContext, name string) response.Response { + return f.svc.RouteGetTemplate(ctx, name) } -func (f *ForkedProvisioningApi) forkRoutePutTemplate(ctx *models.ReqContext, body apimodels.MessageTemplateContent) response.Response { - return f.svc.RoutePutTemplate(ctx, body) +func (f *ForkedProvisioningApi) forkRoutePutTemplate(ctx *models.ReqContext, body apimodels.MessageTemplateContent, name string) response.Response { + return f.svc.RoutePutTemplate(ctx, body, name) } -func (f *ForkedProvisioningApi) forkRouteDeleteTemplate(ctx *models.ReqContext) response.Response { - return f.svc.RouteDeleteTemplate(ctx) +func (f *ForkedProvisioningApi) forkRouteDeleteTemplate(ctx *models.ReqContext, name string) response.Response { + return f.svc.RouteDeleteTemplate(ctx, name) } -func (f *ForkedProvisioningApi) forkRouteGetMuteTiming(ctx *models.ReqContext) response.Response { - return f.svc.RouteGetMuteTiming(ctx) +func (f *ForkedProvisioningApi) forkRouteGetMuteTiming(ctx *models.ReqContext, name string) response.Response { + return f.svc.RouteGetMuteTiming(ctx, name) } func (f *ForkedProvisioningApi) forkRouteGetMuteTimings(ctx *models.ReqContext) response.Response { @@ -71,30 +71,30 @@ func (f *ForkedProvisioningApi) forkRoutePostMuteTiming(ctx *models.ReqContext, return f.svc.RoutePostMuteTiming(ctx, mt) } -func (f *ForkedProvisioningApi) forkRoutePutMuteTiming(ctx *models.ReqContext, mt apimodels.MuteTimeInterval) response.Response { - return f.svc.RoutePutMuteTiming(ctx, mt) +func (f *ForkedProvisioningApi) forkRoutePutMuteTiming(ctx *models.ReqContext, mt apimodels.MuteTimeInterval, name string) response.Response { + return f.svc.RoutePutMuteTiming(ctx, mt, name) } -func (f *ForkedProvisioningApi) forkRouteDeleteMuteTiming(ctx *models.ReqContext) response.Response { - return f.svc.RouteDeleteMuteTiming(ctx) +func (f *ForkedProvisioningApi) forkRouteDeleteMuteTiming(ctx *models.ReqContext, name string) response.Response { + return f.svc.RouteDeleteMuteTiming(ctx, name) } -func (f *ForkedProvisioningApi) forkRouteGetAlertRule(ctx *models.ReqContext) response.Response { - return f.svc.RouteRouteGetAlertRule(ctx) +func (f *ForkedProvisioningApi) forkRouteGetAlertRule(ctx *models.ReqContext, UID string) response.Response { + return f.svc.RouteRouteGetAlertRule(ctx, UID) } func (f *ForkedProvisioningApi) forkRoutePostAlertRule(ctx *models.ReqContext, ar apimodels.AlertRule) response.Response { return f.svc.RoutePostAlertRule(ctx, ar) } -func (f *ForkedProvisioningApi) forkRoutePutAlertRule(ctx *models.ReqContext, ar apimodels.AlertRule) response.Response { - return f.svc.RoutePutAlertRule(ctx, ar) +func (f *ForkedProvisioningApi) forkRoutePutAlertRule(ctx *models.ReqContext, ar apimodels.AlertRule, UID string) response.Response { + return f.svc.RoutePutAlertRule(ctx, ar, UID) } -func (f *ForkedProvisioningApi) forkRouteDeleteAlertRule(ctx *models.ReqContext) response.Response { - return f.svc.RouteDeleteAlertRule(ctx) +func (f *ForkedProvisioningApi) forkRouteDeleteAlertRule(ctx *models.ReqContext, UID string) response.Response { + return f.svc.RouteDeleteAlertRule(ctx, UID) } -func (f *ForkedProvisioningApi) forkRoutePutAlertRuleGroup(ctx *models.ReqContext, ag apimodels.AlertRuleGroup) response.Response { - return f.svc.RoutePutAlertRuleGroup(ctx, ag) +func (f *ForkedProvisioningApi) forkRoutePutAlertRuleGroup(ctx *models.ReqContext, ag apimodels.AlertRuleGroup, folder, group string) response.Response { + return f.svc.RoutePutAlertRuleGroup(ctx, ag, folder, group) } diff --git a/pkg/services/ngalert/api/forked_testing.go b/pkg/services/ngalert/api/forked_testing.go index 17d4b0675eb..6b41961e770 100644 --- a/pkg/services/ngalert/api/forked_testing.go +++ b/pkg/services/ngalert/api/forked_testing.go @@ -18,8 +18,8 @@ func NewForkedTestingApi(svc *TestingApiSrv) *ForkedTestingApi { } } -func (f *ForkedTestingApi) forkRouteTestRuleConfig(c *models.ReqContext, body apimodels.TestRulePayload) response.Response { - return f.svc.RouteTestRuleConfig(c, body) +func (f *ForkedTestingApi) forkRouteTestRuleConfig(c *models.ReqContext, body apimodels.TestRulePayload, dsUID string) response.Response { + return f.svc.RouteTestRuleConfig(c, body, dsUID) } func (f *ForkedTestingApi) forkRouteTestRuleGrafanaConfig(c *models.ReqContext, body apimodels.TestRulePayload) response.Response { diff --git a/pkg/services/ngalert/api/generated_base_api_alertmanager.go b/pkg/services/ngalert/api/generated_base_api_alertmanager.go index 368c0d2d547..c983f3f85fd 100644 --- a/pkg/services/ngalert/api/generated_base_api_alertmanager.go +++ b/pkg/services/ngalert/api/generated_base_api_alertmanager.go @@ -53,35 +53,44 @@ func (f *ForkedAlertmanagerApi) RouteCreateGrafanaSilence(ctx *models.ReqContext return f.forkRouteCreateGrafanaSilence(ctx, conf) } func (f *ForkedAlertmanagerApi) RouteCreateSilence(ctx *models.ReqContext) response.Response { + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] conf := apimodels.PostableSilence{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRouteCreateSilence(ctx, conf) + return f.forkRouteCreateSilence(ctx, conf, datasourceUIDParam) } func (f *ForkedAlertmanagerApi) RouteDeleteAlertingConfig(ctx *models.ReqContext) response.Response { - return f.forkRouteDeleteAlertingConfig(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + return f.forkRouteDeleteAlertingConfig(ctx, datasourceUIDParam) } func (f *ForkedAlertmanagerApi) RouteDeleteGrafanaAlertingConfig(ctx *models.ReqContext) response.Response { return f.forkRouteDeleteGrafanaAlertingConfig(ctx) } func (f *ForkedAlertmanagerApi) RouteDeleteGrafanaSilence(ctx *models.ReqContext) response.Response { - return f.forkRouteDeleteGrafanaSilence(ctx) + silenceIdParam := web.Params(ctx.Req)[":SilenceId"] + return f.forkRouteDeleteGrafanaSilence(ctx, silenceIdParam) } func (f *ForkedAlertmanagerApi) RouteDeleteSilence(ctx *models.ReqContext) response.Response { - return f.forkRouteDeleteSilence(ctx) + silenceIdParam := web.Params(ctx.Req)[":SilenceId"] + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + return f.forkRouteDeleteSilence(ctx, silenceIdParam, datasourceUIDParam) } func (f *ForkedAlertmanagerApi) RouteGetAMAlertGroups(ctx *models.ReqContext) response.Response { - return f.forkRouteGetAMAlertGroups(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + return f.forkRouteGetAMAlertGroups(ctx, datasourceUIDParam) } func (f *ForkedAlertmanagerApi) RouteGetAMAlerts(ctx *models.ReqContext) response.Response { - return f.forkRouteGetAMAlerts(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + return f.forkRouteGetAMAlerts(ctx, datasourceUIDParam) } func (f *ForkedAlertmanagerApi) RouteGetAMStatus(ctx *models.ReqContext) response.Response { - return f.forkRouteGetAMStatus(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + return f.forkRouteGetAMStatus(ctx, datasourceUIDParam) } func (f *ForkedAlertmanagerApi) RouteGetAlertingConfig(ctx *models.ReqContext) response.Response { - return f.forkRouteGetAlertingConfig(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + return f.forkRouteGetAlertingConfig(ctx, datasourceUIDParam) } func (f *ForkedAlertmanagerApi) RouteGetGrafanaAMAlertGroups(ctx *models.ReqContext) response.Response { return f.forkRouteGetGrafanaAMAlertGroups(ctx) @@ -96,30 +105,36 @@ func (f *ForkedAlertmanagerApi) RouteGetGrafanaAlertingConfig(ctx *models.ReqCon return f.forkRouteGetGrafanaAlertingConfig(ctx) } func (f *ForkedAlertmanagerApi) RouteGetGrafanaSilence(ctx *models.ReqContext) response.Response { - return f.forkRouteGetGrafanaSilence(ctx) + silenceIdParam := web.Params(ctx.Req)[":SilenceId"] + return f.forkRouteGetGrafanaSilence(ctx, silenceIdParam) } func (f *ForkedAlertmanagerApi) RouteGetGrafanaSilences(ctx *models.ReqContext) response.Response { return f.forkRouteGetGrafanaSilences(ctx) } func (f *ForkedAlertmanagerApi) RouteGetSilence(ctx *models.ReqContext) response.Response { - return f.forkRouteGetSilence(ctx) + silenceIdParam := web.Params(ctx.Req)[":SilenceId"] + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + return f.forkRouteGetSilence(ctx, silenceIdParam, datasourceUIDParam) } func (f *ForkedAlertmanagerApi) RouteGetSilences(ctx *models.ReqContext) response.Response { - return f.forkRouteGetSilences(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + return f.forkRouteGetSilences(ctx, datasourceUIDParam) } func (f *ForkedAlertmanagerApi) RoutePostAMAlerts(ctx *models.ReqContext) response.Response { + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] conf := apimodels.PostableAlerts{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRoutePostAMAlerts(ctx, conf) + return f.forkRoutePostAMAlerts(ctx, conf, datasourceUIDParam) } func (f *ForkedAlertmanagerApi) RoutePostAlertingConfig(ctx *models.ReqContext) response.Response { + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] conf := apimodels.PostableUserConfig{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRoutePostAlertingConfig(ctx, conf) + return f.forkRoutePostAlertingConfig(ctx, conf, datasourceUIDParam) } func (f *ForkedAlertmanagerApi) RoutePostGrafanaAMAlerts(ctx *models.ReqContext) response.Response { conf := apimodels.PostableAlerts{} @@ -143,11 +158,12 @@ func (f *ForkedAlertmanagerApi) RoutePostTestGrafanaReceivers(ctx *models.ReqCon return f.forkRoutePostTestGrafanaReceivers(ctx, conf) } func (f *ForkedAlertmanagerApi) RoutePostTestReceivers(ctx *models.ReqContext) response.Response { + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] conf := apimodels.TestReceiversConfigBodyParams{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRoutePostTestReceivers(ctx, conf) + return f.forkRoutePostTestReceivers(ctx, conf, datasourceUIDParam) } func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApiForkingService, m *metrics.API) { diff --git a/pkg/services/ngalert/api/generated_base_api_prometheus.go b/pkg/services/ngalert/api/generated_base_api_prometheus.go index 32198a858bb..f9018b7b6ff 100644 --- a/pkg/services/ngalert/api/generated_base_api_prometheus.go +++ b/pkg/services/ngalert/api/generated_base_api_prometheus.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/ngalert/metrics" + "github.com/grafana/grafana/pkg/web" ) type PrometheusApiForkingService interface { @@ -24,7 +25,8 @@ type PrometheusApiForkingService interface { } func (f *ForkedPrometheusApi) RouteGetAlertStatuses(ctx *models.ReqContext) response.Response { - return f.forkRouteGetAlertStatuses(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + return f.forkRouteGetAlertStatuses(ctx, datasourceUIDParam) } func (f *ForkedPrometheusApi) RouteGetGrafanaAlertStatuses(ctx *models.ReqContext) response.Response { return f.forkRouteGetGrafanaAlertStatuses(ctx) @@ -33,7 +35,8 @@ func (f *ForkedPrometheusApi) RouteGetGrafanaRuleStatuses(ctx *models.ReqContext return f.forkRouteGetGrafanaRuleStatuses(ctx) } func (f *ForkedPrometheusApi) RouteGetRuleStatuses(ctx *models.ReqContext) response.Response { - return f.forkRouteGetRuleStatuses(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + return f.forkRouteGetRuleStatuses(ctx, datasourceUIDParam) } func (api *API) RegisterPrometheusApiEndpoints(srv PrometheusApiForkingService, m *metrics.API) { diff --git a/pkg/services/ngalert/api/generated_base_api_provisioning.go b/pkg/services/ngalert/api/generated_base_api_provisioning.go index ff854805509..b449a168658 100644 --- a/pkg/services/ngalert/api/generated_base_api_provisioning.go +++ b/pkg/services/ngalert/api/generated_base_api_provisioning.go @@ -42,25 +42,31 @@ type ProvisioningApiForkingService interface { } func (f *ForkedProvisioningApi) RouteDeleteAlertRule(ctx *models.ReqContext) response.Response { - return f.forkRouteDeleteAlertRule(ctx) + uIDParam := web.Params(ctx.Req)[":UID"] + return f.forkRouteDeleteAlertRule(ctx, uIDParam) } func (f *ForkedProvisioningApi) RouteDeleteContactpoints(ctx *models.ReqContext) response.Response { - return f.forkRouteDeleteContactpoints(ctx) + uIDParam := web.Params(ctx.Req)[":UID"] + return f.forkRouteDeleteContactpoints(ctx, uIDParam) } func (f *ForkedProvisioningApi) RouteDeleteMuteTiming(ctx *models.ReqContext) response.Response { - return f.forkRouteDeleteMuteTiming(ctx) + nameParam := web.Params(ctx.Req)[":name"] + return f.forkRouteDeleteMuteTiming(ctx, nameParam) } func (f *ForkedProvisioningApi) RouteDeleteTemplate(ctx *models.ReqContext) response.Response { - return f.forkRouteDeleteTemplate(ctx) + nameParam := web.Params(ctx.Req)[":name"] + return f.forkRouteDeleteTemplate(ctx, nameParam) } func (f *ForkedProvisioningApi) RouteGetAlertRule(ctx *models.ReqContext) response.Response { - return f.forkRouteGetAlertRule(ctx) + uIDParam := web.Params(ctx.Req)[":UID"] + return f.forkRouteGetAlertRule(ctx, uIDParam) } func (f *ForkedProvisioningApi) RouteGetContactpoints(ctx *models.ReqContext) response.Response { return f.forkRouteGetContactpoints(ctx) } func (f *ForkedProvisioningApi) RouteGetMuteTiming(ctx *models.ReqContext) response.Response { - return f.forkRouteGetMuteTiming(ctx) + nameParam := web.Params(ctx.Req)[":name"] + return f.forkRouteGetMuteTiming(ctx, nameParam) } func (f *ForkedProvisioningApi) RouteGetMuteTimings(ctx *models.ReqContext) response.Response { return f.forkRouteGetMuteTimings(ctx) @@ -69,7 +75,8 @@ func (f *ForkedProvisioningApi) RouteGetPolicyTree(ctx *models.ReqContext) respo return f.forkRouteGetPolicyTree(ctx) } func (f *ForkedProvisioningApi) RouteGetTemplate(ctx *models.ReqContext) response.Response { - return f.forkRouteGetTemplate(ctx) + nameParam := web.Params(ctx.Req)[":name"] + return f.forkRouteGetTemplate(ctx, nameParam) } func (f *ForkedProvisioningApi) RouteGetTemplates(ctx *models.ReqContext) response.Response { return f.forkRouteGetTemplates(ctx) @@ -96,32 +103,37 @@ func (f *ForkedProvisioningApi) RoutePostMuteTiming(ctx *models.ReqContext) resp return f.forkRoutePostMuteTiming(ctx, conf) } func (f *ForkedProvisioningApi) RoutePutAlertRule(ctx *models.ReqContext) response.Response { + uIDParam := web.Params(ctx.Req)[":UID"] conf := apimodels.AlertRule{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRoutePutAlertRule(ctx, conf) + return f.forkRoutePutAlertRule(ctx, conf, uIDParam) } func (f *ForkedProvisioningApi) RoutePutAlertRuleGroup(ctx *models.ReqContext) response.Response { + folderUIDParam := web.Params(ctx.Req)[":FolderUID"] + groupParam := web.Params(ctx.Req)[":Group"] conf := apimodels.AlertRuleGroup{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRoutePutAlertRuleGroup(ctx, conf) + return f.forkRoutePutAlertRuleGroup(ctx, conf, folderUIDParam, groupParam) } func (f *ForkedProvisioningApi) RoutePutContactpoint(ctx *models.ReqContext) response.Response { + uIDParam := web.Params(ctx.Req)[":UID"] conf := apimodels.EmbeddedContactPoint{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRoutePutContactpoint(ctx, conf) + return f.forkRoutePutContactpoint(ctx, conf, uIDParam) } func (f *ForkedProvisioningApi) RoutePutMuteTiming(ctx *models.ReqContext) response.Response { + nameParam := web.Params(ctx.Req)[":name"] conf := apimodels.MuteTimeInterval{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRoutePutMuteTiming(ctx, conf) + return f.forkRoutePutMuteTiming(ctx, conf, nameParam) } func (f *ForkedProvisioningApi) RoutePutPolicyTree(ctx *models.ReqContext) response.Response { conf := apimodels.Route{} @@ -131,11 +143,12 @@ func (f *ForkedProvisioningApi) RoutePutPolicyTree(ctx *models.ReqContext) respo return f.forkRoutePutPolicyTree(ctx, conf) } func (f *ForkedProvisioningApi) RoutePutTemplate(ctx *models.ReqContext) response.Response { + nameParam := web.Params(ctx.Req)[":name"] conf := apimodels.MessageTemplateContent{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRoutePutTemplate(ctx, conf) + return f.forkRoutePutTemplate(ctx, conf, nameParam) } func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApiForkingService, m *metrics.API) { diff --git a/pkg/services/ngalert/api/generated_base_api_ruler.go b/pkg/services/ngalert/api/generated_base_api_ruler.go index 7b2c8967d39..3c2ac808b9b 100644 --- a/pkg/services/ngalert/api/generated_base_api_ruler.go +++ b/pkg/services/ngalert/api/generated_base_api_ruler.go @@ -34,48 +34,68 @@ type RulerApiForkingService interface { } func (f *ForkedRulerApi) RouteDeleteGrafanaRuleGroupConfig(ctx *models.ReqContext) response.Response { - return f.forkRouteDeleteGrafanaRuleGroupConfig(ctx) + namespaceParam := web.Params(ctx.Req)[":Namespace"] + groupnameParam := web.Params(ctx.Req)[":Groupname"] + return f.forkRouteDeleteGrafanaRuleGroupConfig(ctx, namespaceParam, groupnameParam) } func (f *ForkedRulerApi) RouteDeleteNamespaceGrafanaRulesConfig(ctx *models.ReqContext) response.Response { - return f.forkRouteDeleteNamespaceGrafanaRulesConfig(ctx) + namespaceParam := web.Params(ctx.Req)[":Namespace"] + return f.forkRouteDeleteNamespaceGrafanaRulesConfig(ctx, namespaceParam) } func (f *ForkedRulerApi) RouteDeleteNamespaceRulesConfig(ctx *models.ReqContext) response.Response { - return f.forkRouteDeleteNamespaceRulesConfig(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + namespaceParam := web.Params(ctx.Req)[":Namespace"] + return f.forkRouteDeleteNamespaceRulesConfig(ctx, datasourceUIDParam, namespaceParam) } func (f *ForkedRulerApi) RouteDeleteRuleGroupConfig(ctx *models.ReqContext) response.Response { - return f.forkRouteDeleteRuleGroupConfig(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + namespaceParam := web.Params(ctx.Req)[":Namespace"] + groupnameParam := web.Params(ctx.Req)[":Groupname"] + return f.forkRouteDeleteRuleGroupConfig(ctx, datasourceUIDParam, namespaceParam, groupnameParam) } func (f *ForkedRulerApi) RouteGetGrafanaRuleGroupConfig(ctx *models.ReqContext) response.Response { - return f.forkRouteGetGrafanaRuleGroupConfig(ctx) + namespaceParam := web.Params(ctx.Req)[":Namespace"] + groupnameParam := web.Params(ctx.Req)[":Groupname"] + return f.forkRouteGetGrafanaRuleGroupConfig(ctx, namespaceParam, groupnameParam) } func (f *ForkedRulerApi) RouteGetGrafanaRulesConfig(ctx *models.ReqContext) response.Response { return f.forkRouteGetGrafanaRulesConfig(ctx) } func (f *ForkedRulerApi) RouteGetNamespaceGrafanaRulesConfig(ctx *models.ReqContext) response.Response { - return f.forkRouteGetNamespaceGrafanaRulesConfig(ctx) + namespaceParam := web.Params(ctx.Req)[":Namespace"] + return f.forkRouteGetNamespaceGrafanaRulesConfig(ctx, namespaceParam) } func (f *ForkedRulerApi) RouteGetNamespaceRulesConfig(ctx *models.ReqContext) response.Response { - return f.forkRouteGetNamespaceRulesConfig(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + namespaceParam := web.Params(ctx.Req)[":Namespace"] + return f.forkRouteGetNamespaceRulesConfig(ctx, datasourceUIDParam, namespaceParam) } func (f *ForkedRulerApi) RouteGetRulegGroupConfig(ctx *models.ReqContext) response.Response { - return f.forkRouteGetRulegGroupConfig(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + namespaceParam := web.Params(ctx.Req)[":Namespace"] + groupnameParam := web.Params(ctx.Req)[":Groupname"] + return f.forkRouteGetRulegGroupConfig(ctx, datasourceUIDParam, namespaceParam, groupnameParam) } func (f *ForkedRulerApi) RouteGetRulesConfig(ctx *models.ReqContext) response.Response { - return f.forkRouteGetRulesConfig(ctx) + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + return f.forkRouteGetRulesConfig(ctx, datasourceUIDParam) } func (f *ForkedRulerApi) RoutePostNameGrafanaRulesConfig(ctx *models.ReqContext) response.Response { + namespaceParam := web.Params(ctx.Req)[":Namespace"] conf := apimodels.PostableRuleGroupConfig{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRoutePostNameGrafanaRulesConfig(ctx, conf) + return f.forkRoutePostNameGrafanaRulesConfig(ctx, conf, namespaceParam) } func (f *ForkedRulerApi) RoutePostNameRulesConfig(ctx *models.ReqContext) response.Response { + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] + namespaceParam := web.Params(ctx.Req)[":Namespace"] conf := apimodels.PostableRuleGroupConfig{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRoutePostNameRulesConfig(ctx, conf) + return f.forkRoutePostNameRulesConfig(ctx, conf, datasourceUIDParam, namespaceParam) } func (api *API) RegisterRulerApiEndpoints(srv RulerApiForkingService, m *metrics.API) { diff --git a/pkg/services/ngalert/api/generated_base_api_testing.go b/pkg/services/ngalert/api/generated_base_api_testing.go index 1dd46c6eb81..b181e73ba49 100644 --- a/pkg/services/ngalert/api/generated_base_api_testing.go +++ b/pkg/services/ngalert/api/generated_base_api_testing.go @@ -32,11 +32,12 @@ func (f *ForkedTestingApi) RouteEvalQueries(ctx *models.ReqContext) response.Res return f.forkRouteEvalQueries(ctx, conf) } func (f *ForkedTestingApi) RouteTestRuleConfig(ctx *models.ReqContext) response.Response { + datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"] conf := apimodels.TestRulePayload{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.forkRouteTestRuleConfig(ctx, conf) + return f.forkRouteTestRuleConfig(ctx, conf, datasourceUIDParam) } func (f *ForkedTestingApi) RouteTestRuleGrafanaConfig(ctx *models.ReqContext) response.Response { conf := apimodels.TestRulePayload{} diff --git a/pkg/services/ngalert/api/lotex_am.go b/pkg/services/ngalert/api/lotex_am.go index f1bff2af68f..9b3169a8916 100644 --- a/pkg/services/ngalert/api/lotex_am.go +++ b/pkg/services/ngalert/api/lotex_am.go @@ -148,12 +148,12 @@ func (am *LotexAM) RouteDeleteAlertingConfig(ctx *models.ReqContext) response.Re ) } -func (am *LotexAM) RouteDeleteSilence(ctx *models.ReqContext) response.Response { +func (am *LotexAM) RouteDeleteSilence(ctx *models.ReqContext, silenceID string) response.Response { return am.withAMReq( ctx, http.MethodDelete, "silence", - []string{web.Params(ctx.Req)[":SilenceId"]}, + []string{silenceID}, nil, messageExtractor, nil, @@ -196,12 +196,12 @@ func (am *LotexAM) RouteGetAMAlerts(ctx *models.ReqContext) response.Response { ) } -func (am *LotexAM) RouteGetSilence(ctx *models.ReqContext) response.Response { +func (am *LotexAM) RouteGetSilence(ctx *models.ReqContext, silenceID string) response.Response { return am.withAMReq( ctx, http.MethodGet, "silence", - []string{web.Params(ctx.Req)[":SilenceId"]}, + []string{silenceID}, nil, jsonExtractor(&apimodels.GettableSilence{}), nil, diff --git a/pkg/services/ngalert/api/lotex_ruler.go b/pkg/services/ngalert/api/lotex_ruler.go index bf0e643fb79..ac9366ed43f 100644 --- a/pkg/services/ngalert/api/lotex_ruler.go +++ b/pkg/services/ngalert/api/lotex_ruler.go @@ -55,7 +55,7 @@ func NewLotexRuler(proxy *AlertingProxy, log log.Logger) *LotexRuler { } } -func (r *LotexRuler) RouteDeleteNamespaceRulesConfig(ctx *models.ReqContext) response.Response { +func (r *LotexRuler) RouteDeleteNamespaceRulesConfig(ctx *models.ReqContext, namespace string) response.Response { legacyRulerPrefix, err := r.validateAndGetPrefix(ctx) if err != nil { return ErrResp(500, err, "") @@ -65,7 +65,7 @@ func (r *LotexRuler) RouteDeleteNamespaceRulesConfig(ctx *models.ReqContext) res http.MethodDelete, withPath( *ctx.Req.URL, - fmt.Sprintf("%s/%s", legacyRulerPrefix, web.Params(ctx.Req)[":Namespace"]), + fmt.Sprintf("%s/%s", legacyRulerPrefix, namespace), ), nil, messageExtractor, @@ -73,7 +73,7 @@ func (r *LotexRuler) RouteDeleteNamespaceRulesConfig(ctx *models.ReqContext) res ) } -func (r *LotexRuler) RouteDeleteRuleGroupConfig(ctx *models.ReqContext) response.Response { +func (r *LotexRuler) RouteDeleteRuleGroupConfig(ctx *models.ReqContext, namespace string, group string) response.Response { legacyRulerPrefix, err := r.validateAndGetPrefix(ctx) if err != nil { return ErrResp(500, err, "") @@ -86,8 +86,8 @@ func (r *LotexRuler) RouteDeleteRuleGroupConfig(ctx *models.ReqContext) response fmt.Sprintf( "%s/%s/%s", legacyRulerPrefix, - web.Params(ctx.Req)[":Namespace"], - web.Params(ctx.Req)[":Groupname"], + namespace, + group, ), ), nil, @@ -96,7 +96,7 @@ func (r *LotexRuler) RouteDeleteRuleGroupConfig(ctx *models.ReqContext) response ) } -func (r *LotexRuler) RouteGetNamespaceRulesConfig(ctx *models.ReqContext) response.Response { +func (r *LotexRuler) RouteGetNamespaceRulesConfig(ctx *models.ReqContext, namespace string) response.Response { legacyRulerPrefix, err := r.validateAndGetPrefix(ctx) if err != nil { return ErrResp(500, err, "") @@ -109,7 +109,7 @@ func (r *LotexRuler) RouteGetNamespaceRulesConfig(ctx *models.ReqContext) respon fmt.Sprintf( "%s/%s", legacyRulerPrefix, - web.Params(ctx.Req)[":Namespace"], + namespace, ), ), nil, @@ -118,7 +118,7 @@ func (r *LotexRuler) RouteGetNamespaceRulesConfig(ctx *models.ReqContext) respon ) } -func (r *LotexRuler) RouteGetRulegGroupConfig(ctx *models.ReqContext) response.Response { +func (r *LotexRuler) RouteGetRulegGroupConfig(ctx *models.ReqContext, namespace string, group string) response.Response { legacyRulerPrefix, err := r.validateAndGetPrefix(ctx) if err != nil { return ErrResp(500, err, "") @@ -131,8 +131,8 @@ func (r *LotexRuler) RouteGetRulegGroupConfig(ctx *models.ReqContext) response.R fmt.Sprintf( "%s/%s/%s", legacyRulerPrefix, - web.Params(ctx.Req)[":Namespace"], - web.Params(ctx.Req)[":Groupname"], + namespace, + group, ), ), nil, @@ -160,7 +160,7 @@ func (r *LotexRuler) RouteGetRulesConfig(ctx *models.ReqContext) response.Respon ) } -func (r *LotexRuler) RoutePostNameRulesConfig(ctx *models.ReqContext, conf apimodels.PostableRuleGroupConfig) response.Response { +func (r *LotexRuler) RoutePostNameRulesConfig(ctx *models.ReqContext, conf apimodels.PostableRuleGroupConfig, ns string) response.Response { legacyRulerPrefix, err := r.validateAndGetPrefix(ctx) if err != nil { return ErrResp(500, err, "") @@ -169,7 +169,6 @@ func (r *LotexRuler) RoutePostNameRulesConfig(ctx *models.ReqContext, conf apimo if err != nil { return ErrResp(500, err, "Failed marshal rule group") } - ns := web.Params(ctx.Req)[":Namespace"] u := withPath(*ctx.Req.URL, fmt.Sprintf("%s/%s", legacyRulerPrefix, ns)) return r.withReq(ctx, http.MethodPost, u, bytes.NewBuffer(yml), jsonExtractor(nil), nil) } diff --git a/pkg/services/ngalert/api/tooling/swagger-codegen/templates/controller-api.mustache b/pkg/services/ngalert/api/tooling/swagger-codegen/templates/controller-api.mustache index fd4885996b8..0ab26e5596a 100644 --- a/pkg/services/ngalert/api/tooling/swagger-codegen/templates/controller-api.mustache +++ b/pkg/services/ngalert/api/tooling/swagger-codegen/templates/controller-api.mustache @@ -19,16 +19,16 @@ type {{classname}}ForkingService interface { {{#operation}} {{#operations}}{{#operation}} func (f *Forked{{classname}}) {{nickname}}(ctx *models.ReqContext) response.Response { + {{#pathParams}} + {{paramName}}Param := web.Params(ctx.Req)[":{{baseName}}"] + {{/pathParams}} {{#bodyParams}} conf := apimodels.{{dataType}}{} if err := web.Bind(ctx.Req, &conf); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - return f.fork{{nickname}}(ctx, conf) - {{/bodyParams}} - {{^bodyParams}} - return f.fork{{nickname}}(ctx) {{/bodyParams}} + return f.fork{{nickname}}(ctx{{#bodyParams}}, conf{{/bodyParams}}{{#pathParams}}, {{paramName}}Param{{/pathParams}}) } {{/operation}}{{/operations}} diff --git a/pkg/services/ngalert/provisioning/contactpoints.go b/pkg/services/ngalert/provisioning/contactpoints.go index 17774b9ea64..411ca8ef2b9 100644 --- a/pkg/services/ngalert/provisioning/contactpoints.go +++ b/pkg/services/ngalert/provisioning/contactpoints.go @@ -74,7 +74,8 @@ func (ecp *ContactPointService) GetContactPoints(ctx context.Context, orgID int6 return contactPoints, nil } -// internal only +// getContactPointDecrypted is an internal-only function that gets full contact point info, included encrypted fields. +// nil is returned if no matching contact point exists. func (ecp *ContactPointService) getContactPointDecrypted(ctx context.Context, orgID int64, uid string) (apimodels.EmbeddedContactPoint, error) { revision, err := getLastConfiguration(ctx, orgID, ecp.amStore) if err != nil { @@ -104,7 +105,7 @@ func (ecp *ContactPointService) getContactPointDecrypted(ctx context.Context, or } return embeddedContactPoint, nil } - return apimodels.EmbeddedContactPoint{}, fmt.Errorf("contact point with uid '%s' not found", uid) + return apimodels.EmbeddedContactPoint{}, fmt.Errorf("%w: contact point with uid '%s' not found", ErrNotFound, uid) } func (ecp *ContactPointService) CreateContactPoint(ctx context.Context, orgID int64, diff --git a/pkg/services/ngalert/provisioning/validate.go b/pkg/services/ngalert/provisioning/errors.go similarity index 66% rename from pkg/services/ngalert/provisioning/validate.go rename to pkg/services/ngalert/provisioning/errors.go index a764f449d81..ed1ed372671 100644 --- a/pkg/services/ngalert/provisioning/validate.go +++ b/pkg/services/ngalert/provisioning/errors.go @@ -3,3 +3,4 @@ package provisioning import "fmt" var ErrValidation = fmt.Errorf("invalid object specification") +var ErrNotFound = fmt.Errorf("object not found")