Alerting: Fix some status codes returned from provisioning API. (#90117)
The contact point deletion API was returning 500 when it should have been
returning a 4xx error, when the contact point is in use:
- When in use by a notificiation policy, we were missing
the `.Errorf("")` to convert `errutil.Base` into `errutil.Error`.
- When in use by an alert rule, an regular error was returned.
This commit is contained in:
@@ -10,13 +10,16 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
"github.com/prometheus/alertmanager/timeinterval"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/expr"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
@@ -24,6 +27,50 @@ import (
|
||||
"github.com/grafana/grafana/pkg/tests/testinfra"
|
||||
)
|
||||
|
||||
func createRuleWithNotificationSettings(t *testing.T, client apiClient, folder string, nfSettings *definitions.AlertRuleNotificationSettings) (definitions.PostableRuleGroupConfig, string) {
|
||||
t.Helper()
|
||||
|
||||
interval, err := model.ParseDuration("1m")
|
||||
require.NoError(t, err)
|
||||
doubleInterval := 2 * interval
|
||||
rules := definitions.PostableRuleGroupConfig{
|
||||
Name: "arulegroup",
|
||||
Interval: interval,
|
||||
Rules: []definitions.PostableExtendedRuleNode{
|
||||
{
|
||||
ApiRuleNode: &definitions.ApiRuleNode{
|
||||
For: &doubleInterval,
|
||||
Labels: map[string]string{"label1": "val1"},
|
||||
Annotations: map[string]string{"annotation1": "val1"},
|
||||
},
|
||||
GrafanaManagedAlert: &definitions.PostableGrafanaRule{
|
||||
Title: fmt.Sprintf("rule under folder %s", folder),
|
||||
Condition: "A",
|
||||
Data: []definitions.AlertQuery{
|
||||
{
|
||||
RefID: "A",
|
||||
RelativeTimeRange: definitions.RelativeTimeRange{
|
||||
From: definitions.Duration(time.Duration(5) * time.Hour),
|
||||
To: definitions.Duration(time.Duration(3) * time.Hour),
|
||||
},
|
||||
DatasourceUID: expr.DatasourceUID,
|
||||
Model: json.RawMessage(`{
|
||||
"type": "math",
|
||||
"expression": "2 + 3 > 1"
|
||||
}`),
|
||||
},
|
||||
},
|
||||
NotificationSettings: nfSettings,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
resp, status, _ := client.PostRulesGroupWithStatus(t, folder, &rules)
|
||||
assert.Equal(t, http.StatusAccepted, status)
|
||||
require.Len(t, resp.Created, 1)
|
||||
return rules, resp.Created[0]
|
||||
}
|
||||
|
||||
func TestIntegrationProvisioning(t *testing.T) {
|
||||
testinfra.SQLiteIntegrationTest(t)
|
||||
|
||||
@@ -258,6 +305,113 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
|
||||
require.Equal(t, 202, resp.StatusCode)
|
||||
})
|
||||
|
||||
createContactPoint := func(t *testing.T, name string) definitions.EmbeddedContactPoint {
|
||||
cpBody := fmt.Sprintf(`
|
||||
{
|
||||
"name": "%s",
|
||||
"type": "slack",
|
||||
"settings": {
|
||||
"recipient": "value_recipient",
|
||||
"token": "value_token"
|
||||
}
|
||||
}`, name)
|
||||
|
||||
req := createTestRequest("POST", url, "admin", cpBody)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 202, resp.StatusCode)
|
||||
|
||||
ecp := definitions.EmbeddedContactPoint{}
|
||||
require.NoError(t, json.NewDecoder(resp.Body).Decode(&ecp))
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
return ecp
|
||||
}
|
||||
|
||||
createPolicyForContactPoint := func(t *testing.T, receiver string) {
|
||||
url := fmt.Sprintf("http://%s/api/v1/provisioning/policies", grafanaListedAddr)
|
||||
body := fmt.Sprintf(`
|
||||
{
|
||||
"receiver": "%s",
|
||||
"group_by": [
|
||||
"..."
|
||||
],
|
||||
"routes": []
|
||||
}`, receiver)
|
||||
|
||||
req := createTestRequest("PUT", url, "admin", body)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
require.Equal(t, 202, resp.StatusCode)
|
||||
}
|
||||
|
||||
t.Run("viewer DELETE should 403", func(t *testing.T) {
|
||||
ecp := createContactPoint(t, "my-contact-point")
|
||||
|
||||
deleteURL := fmt.Sprintf("http://%s/api/v1/provisioning/contact-points/%s", grafanaListedAddr, ecp.UID)
|
||||
req := createTestRequest("DELETE", deleteURL, "viewer", body)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("admin DELETE should succeed", func(t *testing.T) {
|
||||
ecp := createContactPoint(t, "my-contact-point")
|
||||
|
||||
deleteURL := fmt.Sprintf("http://%s/api/v1/provisioning/contact-points/%s", grafanaListedAddr, ecp.UID)
|
||||
req := createTestRequest("DELETE", deleteURL, "admin", "")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
require.Equal(t, 202, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("admin DELETE should 409 when contact point used by notification policy", func(t *testing.T) {
|
||||
ecp := createContactPoint(t, "my-cp-used-by-policy")
|
||||
|
||||
createPolicyForContactPoint(t, "my-cp-used-by-policy")
|
||||
|
||||
deleteURL := fmt.Sprintf("http://%s/api/v1/provisioning/contact-points/%s", grafanaListedAddr, ecp.UID)
|
||||
deleteReq := createTestRequest("DELETE", deleteURL, "admin", "")
|
||||
|
||||
resp, err := http.DefaultClient.Do(deleteReq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 409, resp.StatusCode)
|
||||
var validationError errutil.PublicError
|
||||
assert.NoError(t, json.NewDecoder(resp.Body).Decode(&validationError))
|
||||
require.NoError(t, resp.Body.Close())
|
||||
assert.NotEmpty(t, validationError, validationError.Message)
|
||||
assert.Equal(t, "alerting.notifications.contact-points.referenced", validationError.MessageID)
|
||||
})
|
||||
|
||||
t.Run("admin DELETE should 409 when contact point used by rule", func(t *testing.T) {
|
||||
ecp := createContactPoint(t, "my-cp-used-by-rule")
|
||||
|
||||
nfSettings := &definitions.AlertRuleNotificationSettings{
|
||||
Receiver: "my-cp-used-by-rule",
|
||||
}
|
||||
apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "admin")
|
||||
createRuleWithNotificationSettings(t, apiClient, namespaceUID, nfSettings)
|
||||
|
||||
deleteURL := fmt.Sprintf("http://%s/api/v1/provisioning/contact-points/%s", grafanaListedAddr, ecp.UID)
|
||||
deleteReq := createTestRequest("DELETE", deleteURL, "admin", "")
|
||||
|
||||
resp, err := http.DefaultClient.Do(deleteReq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 409, resp.StatusCode)
|
||||
var validationError errutil.PublicError
|
||||
assert.NoError(t, json.NewDecoder(resp.Body).Decode(&validationError))
|
||||
require.NoError(t, resp.Body.Close())
|
||||
assert.NotEmpty(t, validationError, validationError.Message)
|
||||
assert.Equal(t, "alerting.notifications.contact-points.used-by-rule", validationError.MessageID)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("when provisioning templates", func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user