This commit adds the missing Provenance field to responses for /api/v1/provisioning/alert-rules.
388 lines
11 KiB
Go
388 lines
11 KiB
Go
package alerting
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
|
"github.com/grafana/grafana/pkg/services/org"
|
|
"github.com/grafana/grafana/pkg/services/user"
|
|
"github.com/grafana/grafana/pkg/tests/testinfra"
|
|
)
|
|
|
|
func TestIntegrationProvisioning(t *testing.T) {
|
|
testinfra.SQLiteIntegrationTest(t)
|
|
|
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
|
DisableLegacyAlerting: true,
|
|
EnableUnifiedAlerting: true,
|
|
DisableAnonymous: true,
|
|
AppModeProduction: true,
|
|
})
|
|
|
|
grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path)
|
|
|
|
// Create a users to make authenticated requests
|
|
createUser(t, store, user.CreateUserCommand{
|
|
DefaultOrgRole: string(org.RoleViewer),
|
|
Password: "viewer",
|
|
Login: "viewer",
|
|
})
|
|
createUser(t, store, user.CreateUserCommand{
|
|
DefaultOrgRole: string(org.RoleEditor),
|
|
Password: "editor",
|
|
Login: "editor",
|
|
})
|
|
createUser(t, store, user.CreateUserCommand{
|
|
DefaultOrgRole: string(org.RoleAdmin),
|
|
Password: "admin",
|
|
Login: "admin",
|
|
})
|
|
|
|
apiClient := newAlertingApiClient(grafanaListedAddr, "editor", "editor")
|
|
// Create the namespace we'll save our alerts to.
|
|
namespaceUID := "default"
|
|
apiClient.CreateFolder(t, namespaceUID, namespaceUID)
|
|
|
|
t.Run("when provisioning notification policies", func(t *testing.T) {
|
|
url := fmt.Sprintf("http://%s/api/v1/provisioning/policies", grafanaListedAddr)
|
|
body := `
|
|
{
|
|
"receiver": "test-receiver",
|
|
"group_by": [
|
|
"..."
|
|
],
|
|
"routes": []
|
|
}`
|
|
|
|
// As we check if the receiver exists that is referenced in the policy,
|
|
// we first need to create it, so the tests passes correctly.
|
|
urlReceiver := fmt.Sprintf("http://%s/api/v1/provisioning/contact-points", grafanaListedAddr)
|
|
bodyReceiver := `
|
|
{
|
|
"name": "test-receiver",
|
|
"type": "slack",
|
|
"settings": {
|
|
"recipient": "value_recipient",
|
|
"token": "value_token"
|
|
}
|
|
}`
|
|
|
|
req := createTestRequest("POST", urlReceiver, "admin", bodyReceiver)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
require.Equal(t, 202, resp.StatusCode)
|
|
|
|
t.Run("un-authenticated GET should 401", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 401, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("viewer GET should 403", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "viewer", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 403, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("editor GET should 403", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "editor", "")
|
|
|
|
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 GET should succeed", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "admin", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 200, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("un-authenticated PUT should 401", func(t *testing.T) {
|
|
req := createTestRequest("PUT", url, "", body)
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 401, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("viewer PUT should 403", func(t *testing.T) {
|
|
req := createTestRequest("PUT", url, "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("editor PUT should 403", func(t *testing.T) {
|
|
req := createTestRequest("PUT", url, "editor", 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 PUT should succeed", func(t *testing.T) {
|
|
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("when provisioning contactpoints", func(t *testing.T) {
|
|
url := fmt.Sprintf("http://%s/api/v1/provisioning/contact-points", grafanaListedAddr)
|
|
body := `
|
|
{
|
|
"name": "my-contact-point",
|
|
"type": "slack",
|
|
"settings": {
|
|
"recipient": "value_recipient",
|
|
"token": "value_token"
|
|
}
|
|
}`
|
|
|
|
t.Run("un-authenticated GET should 401", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 401, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("viewer GET should 403", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "viewer", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 403, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("editor GET should 403", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "editor", "")
|
|
|
|
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 GET should succeed", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "admin", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 200, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("un-authenticated POST should 401", func(t *testing.T) {
|
|
req := createTestRequest("POST", url, "", body)
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 401, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("viewer POST should 403", func(t *testing.T) {
|
|
req := createTestRequest("POST", url, "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("editor POST should 403", func(t *testing.T) {
|
|
req := createTestRequest("POST", url, "editor", 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 POST should succeed", func(t *testing.T) {
|
|
req := createTestRequest("POST", 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("when provisioning templates", func(t *testing.T) {
|
|
url := fmt.Sprintf("http://%s/api/v1/provisioning/templates", grafanaListedAddr)
|
|
|
|
t.Run("un-authenticated GET should 401", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 401, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("viewer GET should 403", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "viewer", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 403, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("editor GET should 403", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "editor", "")
|
|
|
|
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 GET should succeed", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "admin", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 200, resp.StatusCode)
|
|
})
|
|
})
|
|
|
|
t.Run("when provisioning mute timings", func(t *testing.T) {
|
|
url := fmt.Sprintf("http://%s/api/v1/provisioning/mute-timings", grafanaListedAddr)
|
|
|
|
t.Run("un-authenticated GET should 401", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 401, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("viewer GET should 403", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "viewer", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 403, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("editor GET should 403", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "editor", "")
|
|
|
|
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 GET should succeed", func(t *testing.T) {
|
|
req := createTestRequest("GET", url, "admin", "")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Equal(t, 200, resp.StatusCode)
|
|
})
|
|
})
|
|
|
|
t.Run("when provisioning alert rules", func(t *testing.T) {
|
|
url := fmt.Sprintf("http://%s/api/v1/provisioning/alert-rules", grafanaListedAddr)
|
|
body := `{"orgID":1,"folderUID":"default","ruleGroup":"Test Group","title":"Provisioned","condition":"A","data":[{"refId":"A","queryType":"","relativeTimeRange":{"from":600,"to":0},"datasourceUid":"f558c85f-66ad-4fd1-b31d-7979e6c93db4","model":{"editorMode":"code","exemplar":false,"expr":"sum(rate(low_card[5m])) \u003e 0","format":"time_series","instant":true,"intervalMs":1000,"legendFormat":"__auto","maxDataPoints":43200,"range":false,"refId":"A"}}],"noDataState":"NoData","execErrState":"Error","for":"0s"}`
|
|
req := createTestRequest("POST", url, "admin", body)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
require.NoError(t, resp.Body.Close())
|
|
require.Equal(t, 201, resp.StatusCode)
|
|
|
|
// We want to check the provenances of both provisioned and non-provisioned rules
|
|
createRule(t, apiClient, namespaceUID)
|
|
|
|
req = createTestRequest("GET", url, "admin", "")
|
|
resp, err = http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
|
|
var rules definitions.ProvisionedAlertRules
|
|
require.NoError(t, json.NewDecoder(resp.Body).Decode(&rules))
|
|
require.NoError(t, resp.Body.Close())
|
|
|
|
require.Len(t, rules, 2)
|
|
sort.Slice(rules, func(i, j int) bool {
|
|
return rules[i].ID < rules[j].ID
|
|
})
|
|
require.Equal(t, definitions.Provenance("api"), rules[0].Provenance)
|
|
require.Equal(t, definitions.Provenance(""), rules[1].Provenance)
|
|
})
|
|
}
|
|
|
|
func createTestRequest(method string, url string, user string, body string) *http.Request {
|
|
var bodyBuf io.Reader
|
|
if body != "" {
|
|
bodyBuf = bytes.NewReader([]byte(body))
|
|
}
|
|
req, _ := http.NewRequest(method, url, bodyBuf)
|
|
if bodyBuf != nil {
|
|
req.Header.Set("Content-Type", "application/json")
|
|
}
|
|
if user != "" {
|
|
req.SetBasicAuth(user, user)
|
|
}
|
|
return req
|
|
}
|