From 82f7490f7e9a40864851571091622fb1a1561050 Mon Sep 17 00:00:00 2001 From: "Grot (@grafanabot)" <43478413+grafanabot@users.noreply.github.com> Date: Tue, 12 Jul 2022 00:26:35 +0200 Subject: [PATCH] Alerting: Allow filtering of contact points by name (#51933) (#52070) * Define query param and regenerate * Add query struct for contact points * Filter contact points by name in query * Document that name filter is optional (cherry picked from commit 0e066dd5f8736a124cbaaf10381b19ba2e96b81b) Co-authored-by: Alexander Weaver --- pkg/services/ngalert/api/api_provisioning.go | 8 +++- pkg/services/ngalert/api/tooling/api.json | 8 ++++ .../definitions/provisioning_contactpoints.go | 8 ++++ pkg/services/ngalert/api/tooling/post.json | 9 +++- pkg/services/ngalert/api/tooling/spec.json | 11 ++++- .../ngalert/provisioning/contactpoints.go | 17 ++++++-- .../provisioning/contactpoints_test.go | 43 ++++++++++++++----- 7 files changed, 86 insertions(+), 18 deletions(-) diff --git a/pkg/services/ngalert/api/api_provisioning.go b/pkg/services/ngalert/api/api_provisioning.go index 0df026601ca..861a479b183 100644 --- a/pkg/services/ngalert/api/api_provisioning.go +++ b/pkg/services/ngalert/api/api_provisioning.go @@ -25,7 +25,7 @@ type ProvisioningSrv struct { } type ContactPointService interface { - GetContactPoints(ctx context.Context, orgID int64) ([]definitions.EmbeddedContactPoint, error) + GetContactPoints(ctx context.Context, q provisioning.ContactPointQuery) ([]definitions.EmbeddedContactPoint, error) CreateContactPoint(ctx context.Context, orgID int64, contactPoint definitions.EmbeddedContactPoint, p alerting_models.Provenance) (definitions.EmbeddedContactPoint, error) UpdateContactPoint(ctx context.Context, orgID int64, contactPoint definitions.EmbeddedContactPoint, p alerting_models.Provenance) error DeleteContactPoint(ctx context.Context, orgID int64, uid string) error @@ -95,7 +95,11 @@ func (srv *ProvisioningSrv) RouteResetPolicyTree(c *models.ReqContext) response. } func (srv *ProvisioningSrv) RouteGetContactPoints(c *models.ReqContext) response.Response { - cps, err := srv.contactPointService.GetContactPoints(c.Req.Context(), c.OrgId) + q := provisioning.ContactPointQuery{ + Name: c.Query("name"), + OrgID: c.OrgId, + } + cps, err := srv.contactPointService.GetContactPoints(c.Req.Context(), q) if err != nil { return ErrResp(http.StatusInternalServerError, err, "") } diff --git a/pkg/services/ngalert/api/tooling/api.json b/pkg/services/ngalert/api/tooling/api.json index 0f4e9824ddd..374700193af 100644 --- a/pkg/services/ngalert/api/tooling/api.json +++ b/pkg/services/ngalert/api/tooling/api.json @@ -4032,6 +4032,14 @@ "/api/v1/provisioning/contact-points": { "get": { "operationId": "RouteGetContactpoints", + "parameters": [ + { + "description": "Filter by name", + "in": "query", + "name": "name", + "type": "string" + } + ], "responses": { "200": { "description": "ContactPoints", diff --git a/pkg/services/ngalert/api/tooling/definitions/provisioning_contactpoints.go b/pkg/services/ngalert/api/tooling/definitions/provisioning_contactpoints.go index 08245794a3f..894271203ee 100644 --- a/pkg/services/ngalert/api/tooling/definitions/provisioning_contactpoints.go +++ b/pkg/services/ngalert/api/tooling/definitions/provisioning_contactpoints.go @@ -53,6 +53,14 @@ type ContactPointUIDReference struct { UID string } +// swagger:parameters RouteGetContactpoints +type ContactPointParams struct { + // Filter by name + // in: query + // required: false + Name string `json:"name"` +} + // swagger:parameters RoutePostContactpoints RoutePutContactpoint type ContactPointPayload struct { // in:body diff --git a/pkg/services/ngalert/api/tooling/post.json b/pkg/services/ngalert/api/tooling/post.json index 7f1692a3e83..382aa0216ca 100644 --- a/pkg/services/ngalert/api/tooling/post.json +++ b/pkg/services/ngalert/api/tooling/post.json @@ -3327,7 +3327,6 @@ "x-go-package": "github.com/prometheus/alertmanager/api/v2/models" }, "alertGroup": { - "description": "AlertGroup alert group", "properties": { "alerts": { "description": "alerts", @@ -5683,6 +5682,14 @@ "/api/v1/provisioning/contact-points": { "get": { "operationId": "RouteGetContactpoints", + "parameters": [ + { + "description": "Filter by name", + "in": "query", + "name": "name", + "type": "string" + } + ], "responses": { "200": { "description": "ContactPoints", diff --git a/pkg/services/ngalert/api/tooling/spec.json b/pkg/services/ngalert/api/tooling/spec.json index 5a3b278d10a..011b10c202b 100644 --- a/pkg/services/ngalert/api/tooling/spec.json +++ b/pkg/services/ngalert/api/tooling/spec.json @@ -1804,6 +1804,14 @@ ], "summary": "Get all the contact points.", "operationId": "RouteGetContactpoints", + "parameters": [ + { + "type": "string", + "description": "Filter by name", + "name": "name", + "in": "query" + } + ], "responses": { "200": { "description": "ContactPoints", @@ -5734,7 +5742,6 @@ "x-go-package": "github.com/prometheus/alertmanager/api/v2/models" }, "alertGroup": { - "description": "AlertGroup alert group", "type": "object", "required": [ "alerts", @@ -5760,6 +5767,7 @@ "$ref": "#/definitions/alertGroup" }, "alertGroups": { + "description": "AlertGroups alert groups", "type": "array", "items": { "$ref": "#/definitions/alertGroup" @@ -6195,7 +6203,6 @@ "$ref": "#/definitions/postableSilence" }, "receiver": { - "description": "Receiver receiver", "type": "object", "required": [ "name" diff --git a/pkg/services/ngalert/provisioning/contactpoints.go b/pkg/services/ngalert/provisioning/contactpoints.go index 879666d5f4c..e948eb649d5 100644 --- a/pkg/services/ngalert/provisioning/contactpoints.go +++ b/pkg/services/ngalert/provisioning/contactpoints.go @@ -34,17 +34,27 @@ func NewContactPointService(store AMConfigStore, encryptionService secrets.Servi } } -func (ecp *ContactPointService) GetContactPoints(ctx context.Context, orgID int64) ([]apimodels.EmbeddedContactPoint, error) { - revision, err := getLastConfiguration(ctx, orgID, ecp.amStore) +type ContactPointQuery struct { + // Optionally filter by name. + Name string + OrgID int64 +} + +func (ecp *ContactPointService) GetContactPoints(ctx context.Context, q ContactPointQuery) ([]apimodels.EmbeddedContactPoint, error) { + revision, err := getLastConfiguration(ctx, q.OrgID, ecp.amStore) if err != nil { return nil, err } - provenances, err := ecp.provenanceStore.GetProvenances(ctx, orgID, "contactPoint") + provenances, err := ecp.provenanceStore.GetProvenances(ctx, q.OrgID, "contactPoint") if err != nil { return nil, err } contactPoints := []apimodels.EmbeddedContactPoint{} for _, contactPoint := range revision.cfg.GetGrafanaReceiverMap() { + if q.Name != "" && contactPoint.Name != q.Name { + continue + } + embeddedContactPoint := apimodels.EmbeddedContactPoint{ UID: contactPoint.UID, Type: contactPoint.Type, @@ -66,6 +76,7 @@ func (ecp *ContactPointService) GetContactPoints(ctx context.Context, orgID int6 } embeddedContactPoint.Settings.Set(k, apimodels.RedactedValue) } + contactPoints = append(contactPoints, embeddedContactPoint) } sort.SliceStable(contactPoints, func(i, j int) bool { diff --git a/pkg/services/ngalert/provisioning/contactpoints_test.go b/pkg/services/ngalert/provisioning/contactpoints_test.go index 17a24735a34..1ee91f59b1b 100644 --- a/pkg/services/ngalert/provisioning/contactpoints_test.go +++ b/pkg/services/ngalert/provisioning/contactpoints_test.go @@ -22,7 +22,24 @@ func TestContactPointService(t *testing.T) { t.Run("service gets contact points from AM config", func(t *testing.T) { sut := createContactPointServiceSut(secretsService) - cps, err := sut.GetContactPoints(context.Background(), 1) + cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1)) + require.NoError(t, err) + + require.Len(t, cps, 1) + require.Equal(t, "email receiver", cps[0].Name) + }) + + t.Run("service filters contact points by name", func(t *testing.T) { + sut := createContactPointServiceSut(secretsService) + newCp := createTestContactPoint() + _, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI) + require.NoError(t, err) + + q := ContactPointQuery{ + OrgID: 1, + Name: "email receiver", + } + cps, err := sut.GetContactPoints(context.Background(), q) require.NoError(t, err) require.Len(t, cps, 1) @@ -36,7 +53,7 @@ func TestContactPointService(t *testing.T) { _, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI) require.NoError(t, err) - cps, err := sut.GetContactPoints(context.Background(), 1) + cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1)) require.NoError(t, err) require.Len(t, cps, 2) require.Equal(t, "test-contact-point", cps[1].Name) @@ -52,7 +69,7 @@ func TestContactPointService(t *testing.T) { _, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI) require.NoError(t, err) - cps, err := sut.GetContactPoints(context.Background(), 1) + cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1)) require.NoError(t, err) require.Len(t, cps, 2) require.Equal(t, customUID, cps[1].UID) @@ -120,7 +137,7 @@ func TestContactPointService(t *testing.T) { t.Run("default provenance of contact points is none", func(t *testing.T) { sut := createContactPointServiceSut(secretsService) - cps, err := sut.GetContactPoints(context.Background(), 1) + cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1)) require.NoError(t, err) require.Equal(t, models.ProvenanceNone, models.Provenance(cps[0].Provenance)) @@ -133,7 +150,7 @@ func TestContactPointService(t *testing.T) { newCp, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceNone) require.NoError(t, err) - cps, err := sut.GetContactPoints(context.Background(), 1) + cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1)) require.NoError(t, err) require.Equal(t, newCp.UID, cps[1].UID) require.Equal(t, models.ProvenanceNone, models.Provenance(cps[1].Provenance)) @@ -141,7 +158,7 @@ func TestContactPointService(t *testing.T) { err = sut.UpdateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI) require.NoError(t, err) - cps, err = sut.GetContactPoints(context.Background(), 1) + cps, err = sut.GetContactPoints(context.Background(), cpsQuery(1)) require.NoError(t, err) require.Equal(t, newCp.UID, cps[1].UID) require.Equal(t, models.ProvenanceAPI, models.Provenance(cps[1].Provenance)) @@ -154,7 +171,7 @@ func TestContactPointService(t *testing.T) { newCp, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceNone) require.NoError(t, err) - cps, err := sut.GetContactPoints(context.Background(), 1) + cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1)) require.NoError(t, err) require.Equal(t, newCp.UID, cps[1].UID) require.Equal(t, models.ProvenanceNone, models.Provenance(cps[1].Provenance)) @@ -162,7 +179,7 @@ func TestContactPointService(t *testing.T) { err = sut.UpdateContactPoint(context.Background(), 1, newCp, models.ProvenanceFile) require.NoError(t, err) - cps, err = sut.GetContactPoints(context.Background(), 1) + cps, err = sut.GetContactPoints(context.Background(), cpsQuery(1)) require.NoError(t, err) require.Equal(t, newCp.UID, cps[1].UID) require.Equal(t, models.ProvenanceFile, models.Provenance(cps[1].Provenance)) @@ -175,7 +192,7 @@ func TestContactPointService(t *testing.T) { newCp, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceFile) require.NoError(t, err) - cps, err := sut.GetContactPoints(context.Background(), 1) + cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1)) require.NoError(t, err) require.Equal(t, newCp.UID, cps[1].UID) require.Equal(t, models.ProvenanceFile, models.Provenance(cps[1].Provenance)) @@ -191,7 +208,7 @@ func TestContactPointService(t *testing.T) { newCp, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI) require.NoError(t, err) - cps, err := sut.GetContactPoints(context.Background(), 1) + cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1)) require.NoError(t, err) require.Equal(t, newCp.UID, cps[1].UID) require.Equal(t, models.ProvenanceAPI, models.Provenance(cps[1].Provenance)) @@ -269,6 +286,12 @@ func createTestContactPoint() definitions.EmbeddedContactPoint { } } +func cpsQuery(orgID int64) ContactPointQuery { + return ContactPointQuery{ + OrgID: orgID, + } +} + func TestStitchReceivers(t *testing.T) { type testCase struct { name string