Alerting: Add method to reset notification policy tree back to the default (#51934) (#52004)

* Define route and run codegen

* Wire up HTTP layer

* Update API layer and test fakes

* Implement reset of policy tree

* Implement service layer test and authorization bindings

* API layer testing

* Be more specific when injecting settings

(cherry picked from commit fce283d73e)

Co-authored-by: Alexander Weaver <weaver.alex.d@gmail.com>
This commit is contained in:
Grot (@grafanabot)
2022-07-08 16:39:49 -05:00
committed by GitHub
co-authored by Alexander Weaver
parent 08f72f214e
commit 7e5a7fc7fc
12 changed files with 191 additions and 3 deletions
@@ -40,6 +40,7 @@ type TemplateService interface {
type NotificationPolicyService interface {
GetPolicyTree(ctx context.Context, orgID int64) (definitions.Route, error)
UpdatePolicyTree(ctx context.Context, orgID int64, tree definitions.Route, p alerting_models.Provenance) error
ResetPolicyTree(ctx context.Context, orgID int64) (definitions.Route, error)
}
type MuteTimingService interface {
@@ -85,6 +86,14 @@ func (srv *ProvisioningSrv) RoutePutPolicyTree(c *models.ReqContext, tree defini
return response.JSON(http.StatusAccepted, util.DynMap{"message": "policies updated"})
}
func (srv *ProvisioningSrv) RouteResetPolicyTree(c *models.ReqContext) response.Response {
tree, err := srv.policies.ResetPolicyTree(c.Req.Context(), c.OrgId)
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
return response.JSON(http.StatusAccepted, tree)
}
func (srv *ProvisioningSrv) RouteGetContactPoints(c *models.ReqContext) response.Response {
cps, err := srv.contactPointService.GetContactPoints(c.Req.Context(), c.OrgId)
if err != nil {
@@ -44,6 +44,15 @@ func TestProvisioningApi(t *testing.T) {
require.Equal(t, 202, response.Status())
})
t.Run("successful DELETE returns 202", func(t *testing.T) {
sut := createProvisioningSrvSut(t)
rc := createTestRequestCtx()
response := sut.RouteResetPolicyTree(&rc)
require.Equal(t, 202, response.Status())
})
t.Run("when new policy tree is invalid", func(t *testing.T) {
t.Run("PUT returns 400", func(t *testing.T) {
sut := createProvisioningSrvSut(t)
@@ -106,6 +115,18 @@ func TestProvisioningApi(t *testing.T) {
require.NotEmpty(t, response.Body())
require.Contains(t, string(response.Body()), "something went wrong")
})
t.Run("DELETE returns 500", func(t *testing.T) {
sut := createProvisioningSrvSut(t)
sut.policies = &fakeFailingNotificationPolicyService{}
rc := createTestRequestCtx()
response := sut.RouteResetPolicyTree(&rc)
require.Equal(t, 500, response.Status())
require.NotEmpty(t, response.Body())
require.Contains(t, string(response.Body()), "something went wrong")
})
})
})
@@ -335,6 +356,11 @@ func (f *fakeNotificationPolicyService) UpdatePolicyTree(ctx context.Context, or
return nil
}
func (f *fakeNotificationPolicyService) ResetPolicyTree(ctx context.Context, orgID int64) (definitions.Route, error) {
f.tree = definitions.Route{} // TODO
return f.tree, nil
}
type fakeFailingNotificationPolicyService struct{}
func (f *fakeFailingNotificationPolicyService) GetPolicyTree(ctx context.Context, orgID int64) (definitions.Route, error) {
@@ -345,6 +371,10 @@ func (f *fakeFailingNotificationPolicyService) UpdatePolicyTree(ctx context.Cont
return fmt.Errorf("something went wrong")
}
func (f *fakeFailingNotificationPolicyService) ResetPolicyTree(ctx context.Context, orgID int64) (definitions.Route, error) {
return definitions.Route{}, fmt.Errorf("something went wrong")
}
type fakeRejectingNotificationPolicyService struct{}
func (f *fakeRejectingNotificationPolicyService) GetPolicyTree(ctx context.Context, orgID int64) (definitions.Route, error) {
@@ -355,6 +385,10 @@ func (f *fakeRejectingNotificationPolicyService) UpdatePolicyTree(ctx context.Co
return fmt.Errorf("%w: invalid policy tree", provisioning.ErrValidation)
}
func (f *fakeRejectingNotificationPolicyService) ResetPolicyTree(ctx context.Context, orgID int64) (definitions.Route, error) {
return definitions.Route{}, nil
}
func createInvalidContactPoint() definitions.EmbeddedContactPoint {
settings, _ := simplejson.NewJson([]byte(`{}`))
return definitions.EmbeddedContactPoint{
@@ -191,6 +191,7 @@ func (api *API) authorize(method, path string) web.Handler {
eval = ac.EvalPermission(ac.ActionAlertingProvisioningRead) // organization scope
case http.MethodPut + "/api/v1/provisioning/policies",
http.MethodDelete + "/api/v1/provisioning/policies",
http.MethodPost + "/api/v1/provisioning/contact-points",
http.MethodPut + "/api/v1/provisioning/contact-points/{UID}",
http.MethodDelete + "/api/v1/provisioning/contact-points/{UID}",
@@ -27,6 +27,10 @@ func (f *ForkedProvisioningApi) forkRoutePutPolicyTree(ctx *models.ReqContext, r
return f.svc.RoutePutPolicyTree(ctx, route)
}
func (f *ForkedProvisioningApi) forkRouteResetPolicyTree(ctx *models.ReqContext) response.Response {
return f.svc.RouteResetPolicyTree(ctx)
}
func (f *ForkedProvisioningApi) forkRouteGetContactpoints(ctx *models.ReqContext) response.Response {
return f.svc.RouteGetContactPoints(ctx)
}
@@ -40,6 +40,7 @@ type ProvisioningApiForkingService interface {
RoutePutMuteTiming(*models.ReqContext) response.Response
RoutePutPolicyTree(*models.ReqContext) response.Response
RoutePutTemplate(*models.ReqContext) response.Response
RouteResetPolicyTree(*models.ReqContext) response.Response
}
func (f *ForkedProvisioningApi) RouteDeleteAlertRule(ctx *models.ReqContext) response.Response {
@@ -156,6 +157,9 @@ func (f *ForkedProvisioningApi) RoutePutTemplate(ctx *models.ReqContext) respons
}
return f.forkRoutePutTemplate(ctx, conf, nameParam)
}
func (f *ForkedProvisioningApi) RouteResetPolicyTree(ctx *models.ReqContext) response.Response {
return f.forkRouteResetPolicyTree(ctx)
}
func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApiForkingService, m *metrics.API) {
api.RouteRegister.Group("", func(group routing.RouteRegister) {
@@ -369,5 +373,15 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApiForkingServi
m,
),
)
group.Delete(
toMacaronPath("/api/v1/provisioning/policies"),
api.authorize(http.MethodDelete, "/api/v1/provisioning/policies"),
metrics.Instrument(
http.MethodDelete,
"/api/v1/provisioning/policies",
srv.RouteResetPolicyTree,
m,
),
)
}, middleware.ReqSignedIn)
}
+18 -1
View File
@@ -3780,7 +3780,6 @@
"type": "object"
},
"receiver": {
"description": "Receiver receiver",
"properties": {
"name": {
"description": "name",
@@ -4369,6 +4368,24 @@
}
},
"/api/v1/provisioning/policies": {
"delete": {
"consumes": [
"application/json"
],
"operationId": "RouteResetPolicyTree",
"responses": {
"202": {
"description": "Ack",
"schema": {
"$ref": "#/definitions/Ack"
}
}
},
"summary": "Clears the notification policy tree.",
"tags": [
"provisioning"
]
},
"get": {
"operationId": "RouteGetPolicyTree",
"responses": {
@@ -19,6 +19,16 @@ package definitions
// 202: Ack
// 400: ValidationError
// swagger:route DELETE /api/v1/provisioning/policies provisioning stable RouteResetPolicyTree
//
// Clears the notification policy tree.
//
// Consumes:
// - application/json
//
// Responses:
// 202: Ack
// swagger:parameters RoutePutPolicyTree
type Policytree struct {
// The new notification routing tree to use
@@ -6019,6 +6019,24 @@
}
},
"/api/v1/provisioning/policies": {
"delete": {
"consumes": [
"application/json"
],
"operationId": "RouteResetPolicyTree",
"responses": {
"202": {
"description": "Ack",
"schema": {
"$ref": "#/definitions/Ack"
}
}
},
"summary": "Clears the notification policy tree.",
"tags": [
"provisioning"
]
},
"get": {
"operationId": "RouteGetPolicyTree",
"responses": {
@@ -2196,6 +2196,25 @@
}
}
}
},
"delete": {
"consumes": [
"application/json"
],
"tags": [
"provisioning",
"stable"
],
"summary": "Clears the notification policy tree.",
"operationId": "RouteResetPolicyTree",
"responses": {
"202": {
"description": "Ack",
"schema": {
"$ref": "#/definitions/Ack"
}
}
}
}
},
"/api/v1/provisioning/templates": {
@@ -6130,6 +6149,7 @@
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
},
"postableSilence": {
"description": "PostableSilence postable silence",
"type": "object",
"required": [
"comment",