Skip to content

Commit

Permalink
Merge pull request #185 from K-Phoen/alerts-deletion
Browse files Browse the repository at this point in the history
Delete related alerts when deleting a dashboard
  • Loading branch information
K-Phoen authored Jun 19, 2022
2 parents c8391d6 + f3742a1 commit 29bccd2
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 8 deletions.
14 changes: 13 additions & 1 deletion dashboards.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (client *Client) UpsertDashboard(ctx context.Context, folder *Folder, build
}
for _, ref := range alertRefs {
if err := client.DeleteAlertGroup(ctx, ref.Namespace, ref.RuleGroup); err != nil {
return nil, fmt.Errorf("could not delete of previous alerts for dashboard: %w", err)
return nil, fmt.Errorf("could not delete previous alerts for dashboard: %w", err)
}
}

Expand Down Expand Up @@ -174,6 +174,18 @@ func (client *Client) persistDashboard(ctx context.Context, folder *Folder, buil

// DeleteDashboard deletes a dashboard given its UID.
func (client *Client) DeleteDashboard(ctx context.Context, uid string) error {
// first: delete existing alerts associated to that dashboard
alertRefs, err := client.listAlertsForDashboard(ctx, uid)
if err != nil {
return fmt.Errorf("could not prepare deletion of alerts for dashboard: %w", err)
}
for _, ref := range alertRefs {
if err := client.DeleteAlertGroup(ctx, ref.Namespace, ref.RuleGroup); err != nil {
return fmt.Errorf("could not delete alerts for dashboard: %w", err)
}
}

// then: delete the dashboard itself
resp, err := client.delete(ctx, "/api/dashboards/uid/"+uid)
if err != nil {
return err
Expand Down
93 changes: 86 additions & 7 deletions dashboards_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,85 @@ func TestFetchingAnUnknownDashboardByUIDFailsCleanly(t *testing.T) {
req.ErrorIs(err, ErrDashboardNotFound)
}

func TestDeleteDashboard(t *testing.T) {
func TestDeleteDashboardWithNoAlerts(t *testing.T) {
req := require.New(t)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintln(w, `{"title": "Production Overview"}`)
// Potential existing alerts retrieval
if r.Method == http.MethodGet && r.URL.String() == "/api/ruler/grafana/api/v1/rules?dashboard_uid=some-uid" {
_, _ = fmt.Fprintln(w, `{}`)
return
}

// Dashboard deletion
if r.Method == http.MethodDelete && r.URL.String() == "/api/dashboards/uid/some-uid" {
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintln(w, `{"title": "Production Overview"}`)
return
}

w.WriteHeader(http.StatusInternalServerError)
_, _ = fmt.Fprintf(w, `{"message": "oh noes, we should not get here", "method": "%s", "path": "%s"}\n`, r.Method, r.URL.String())
}))
defer ts.Close()

client := NewClient(http.DefaultClient, ts.URL)

err := client.DeleteDashboard(context.TODO(), "some uid")
err := client.DeleteDashboard(context.TODO(), "some-uid")

req.NoError(err)
}

func TestDeleteDashboardWithAlerts(t *testing.T) {
req := require.New(t)
firstAlertDeleted := false
secondAlertDeleted := false
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Potential existing alerts retrieval
if r.Method == http.MethodGet && r.URL.String() == "/api/ruler/grafana/api/v1/rules?dashboard_uid=some-uid" {
_, _ = fmt.Fprintln(w, `{
"test ns 1": [
{"name": "alert 1"}
],
"test ns 2": [
{"name": "alert 2"}
]
}`)
return
}

// First alert deletion
if r.Method == http.MethodDelete && r.URL.String() == "/api/ruler/grafana/api/v1/rules/test%20ns%201/alert%201" {
firstAlertDeleted = true
w.WriteHeader(http.StatusAccepted)
return
}

// Second alert deletion
if r.Method == http.MethodDelete && r.URL.String() == "/api/ruler/grafana/api/v1/rules/test%20ns%202/alert%202" {
secondAlertDeleted = true
w.WriteHeader(http.StatusAccepted)
return
}

// Dashboard deletion
if r.Method == http.MethodDelete && r.URL.String() == "/api/dashboards/uid/some-uid" {
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintln(w, `{"title": "Production Overview"}`)
return
}

w.WriteHeader(http.StatusInternalServerError)
_, _ = fmt.Fprintf(w, `{"message": "oh noes, we should not get here", "method": "%s", "path": "%s"}\n`, r.Method, r.URL.String())
}))
defer ts.Close()

client := NewClient(http.DefaultClient, ts.URL)

err := client.DeleteDashboard(context.TODO(), "some-uid")

req.NoError(err)
req.True(firstAlertDeleted)
req.True(secondAlertDeleted)
}

func TestDeleteDashboardCanFail(t *testing.T) {
Expand All @@ -178,14 +244,27 @@ func TestDeleteDashboardCanFail(t *testing.T) {
func TestDeletingANonExistingDashboardReturnsSpecificError(t *testing.T) {
req := require.New(t)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
_, _ = fmt.Fprintln(w, `{"message": "oh noes, does not exist"}`)
// Potential existing alerts retrieval
if r.Method == http.MethodGet && r.URL.String() == "/api/ruler/grafana/api/v1/rules?dashboard_uid=some-uid" {
_, _ = fmt.Fprintln(w, `{}`)
return
}

// Dashboard deletion
if r.Method == http.MethodDelete && r.URL.String() == "/api/dashboards/uid/some-uid" {
w.WriteHeader(http.StatusNotFound)
_, _ = fmt.Fprintln(w, `{"message": "oh noes, does not exist"}`)
return
}

w.WriteHeader(http.StatusInternalServerError)
_, _ = fmt.Fprintf(w, `{"message": "oh noes, we should not get here", "method": "%s", "path": "%s"}\n`, r.Method, r.URL.String())
}))
defer ts.Close()

client := NewClient(http.DefaultClient, ts.URL)

err := client.DeleteDashboard(context.TODO(), "some uid")
err := client.DeleteDashboard(context.TODO(), "some-uid")

req.Equal(ErrDashboardNotFound, err)
}
Expand Down

0 comments on commit 29bccd2

Please sign in to comment.