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

* 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
This commit is contained in:
Alexander Weaver
2022-07-08 16:23:18 -05:00
committed by GitHub
parent 05cdef5004
commit fce283d73e
12 changed files with 195 additions and 3 deletions

View File

@@ -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 {

View File

@@ -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{

View File

@@ -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}",

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -2785,6 +2785,7 @@
"type": "object"
},
"alertGroups": {
"description": "AlertGroups alert groups",
"items": {
"$ref": "#/definitions/alertGroup"
},
@@ -3113,6 +3114,7 @@
"type": "array"
},
"postableSilence": {
"description": "PostableSilence postable silence",
"properties": {
"comment": {
"description": "comment",
@@ -3150,7 +3152,6 @@
"type": "object"
},
"receiver": {
"description": "Receiver receiver",
"properties": {
"name": {
"description": "name",
@@ -3718,6 +3719,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": {

View File

@@ -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

View File

@@ -3003,6 +3003,7 @@
"type": "object"
},
"gettableSilences": {
"description": "GettableSilences gettable silences",
"items": {
"$ref": "#/definitions/gettableSilence"
},
@@ -5344,6 +5345,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": {

View File

@@ -2169,6 +2169,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": {
@@ -5366,6 +5385,7 @@
"$ref": "#/definitions/gettableSilence"
},
"gettableSilences": {
"description": "GettableSilences gettable silences",
"type": "array",
"items": {
"$ref": "#/definitions/gettableSilence"
@@ -5477,6 +5497,7 @@
}
},
"postableSilence": {
"description": "PostableSilence postable silence",
"type": "object",
"required": [
"comment",