Alerting: Hook up GMA silence APIs to new authentication handler (#86625)
This PR connects the new RBAC authentication service to existing alertmanager API silence endpoints.
This commit is contained in:
@@ -0,0 +1,422 @@
|
||||
package alerting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/alertmanager/pkg/labels"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/alerting/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/tests/testinfra"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func TestIntegrationSilenceAuth(t *testing.T) {
|
||||
testinfra.SQLiteIntegrationTest(t)
|
||||
|
||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||
DisableLegacyAlerting: true,
|
||||
EnableUnifiedAlerting: true,
|
||||
DisableAnonymous: true,
|
||||
AppModeProduction: true,
|
||||
})
|
||||
|
||||
grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path)
|
||||
|
||||
createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{
|
||||
DefaultOrgRole: string(org.RoleAdmin),
|
||||
Password: "admin",
|
||||
Login: "admin",
|
||||
})
|
||||
|
||||
adminApiClient := newAlertingApiClient(grafanaListedAddr, "admin", "admin")
|
||||
|
||||
// Create the namespace we'll save our alerts to.
|
||||
f1 := folder.Folder{
|
||||
UID: util.GenerateShortUID(),
|
||||
Title: "Folder 1",
|
||||
}
|
||||
adminApiClient.CreateFolder(t, f1.UID, f1.Title)
|
||||
f2 := folder.Folder{
|
||||
UID: util.GenerateShortUID(),
|
||||
Title: "Folder 2",
|
||||
}
|
||||
adminApiClient.CreateFolder(t, f2.UID, f2.Title)
|
||||
|
||||
group1 := generateAlertRuleGroup(1, alertRuleGen())
|
||||
group2 := generateAlertRuleGroup(1, alertRuleGen())
|
||||
|
||||
respModel, status, _ := adminApiClient.PostRulesGroupWithStatus(t, f1.UID, &group1)
|
||||
require.Equal(t, http.StatusAccepted, status)
|
||||
ruleInFolder1UID := respModel.Created[0]
|
||||
respModel, status, _ = adminApiClient.PostRulesGroupWithStatus(t, f2.UID, &group2)
|
||||
require.Equal(t, http.StatusAccepted, status)
|
||||
ruleInFolder2UID := respModel.Created[0]
|
||||
|
||||
type silenceAction string
|
||||
const (
|
||||
readSilence silenceAction = "read"
|
||||
createSilence silenceAction = "create"
|
||||
updateSilence silenceAction = "update"
|
||||
deleteSilence silenceAction = "delete"
|
||||
)
|
||||
|
||||
type silenceType string
|
||||
const (
|
||||
generalSilence silenceType = "generalSilence"
|
||||
ruleSilenceInFolder1 silenceType = "ruleSilenceInFolder1"
|
||||
ruleSilenceInFolder2 silenceType = "ruleSilenceInFolder2"
|
||||
)
|
||||
|
||||
silenceGens := map[silenceType]func() ngmodels.Silence{
|
||||
generalSilence: ngmodels.SilenceGen(),
|
||||
ruleSilenceInFolder1: ngmodels.SilenceGen(ngmodels.SilenceMuts.WithMatcher(models.RuleUIDLabel, ruleInFolder1UID, labels.MatchEqual)),
|
||||
ruleSilenceInFolder2: ngmodels.SilenceGen(ngmodels.SilenceMuts.WithMatcher(models.RuleUIDLabel, ruleInFolder2UID, labels.MatchEqual)),
|
||||
}
|
||||
|
||||
defaultStatus := map[silenceAction]map[bool]int{
|
||||
updateSilence: {true: http.StatusAccepted, false: http.StatusForbidden},
|
||||
deleteSilence: {true: http.StatusOK, false: http.StatusForbidden},
|
||||
createSilence: {true: http.StatusAccepted, false: http.StatusForbidden},
|
||||
readSilence: {true: http.StatusOK, false: http.StatusForbidden},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
orgRole org.RoleType // default RoleNone
|
||||
permissions []resourcepermissions.SetResourcePermissionCommand
|
||||
defaultAllowed bool // Default allowed/forbidden for actions not in statusExceptions.
|
||||
statusExceptions map[silenceType]map[silenceAction]int // Exceptions to defaultAllowed.
|
||||
listContents []silenceType // nil = forbidden.
|
||||
}{
|
||||
// OSS Builtins
|
||||
{
|
||||
name: "Viewer permissions",
|
||||
orgRole: org.RoleViewer,
|
||||
statusExceptions: map[silenceType]map[silenceAction]int{
|
||||
generalSilence: {readSilence: http.StatusOK},
|
||||
ruleSilenceInFolder1: {readSilence: http.StatusOK},
|
||||
ruleSilenceInFolder2: {readSilence: http.StatusOK},
|
||||
},
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1, ruleSilenceInFolder2},
|
||||
},
|
||||
{
|
||||
name: "Viewer permissions with elevated access to folder1",
|
||||
orgRole: org.RoleViewer,
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: ossaccesscontrol.FolderEditActions, Resource: "folders", ResourceAttribute: "uid", ResourceID: f1.UID},
|
||||
},
|
||||
statusExceptions: map[silenceType]map[silenceAction]int{
|
||||
generalSilence: {readSilence: http.StatusOK},
|
||||
ruleSilenceInFolder1: {readSilence: http.StatusOK, updateSilence: http.StatusAccepted, createSilence: http.StatusAccepted, deleteSilence: http.StatusOK},
|
||||
ruleSilenceInFolder2: {readSilence: http.StatusOK},
|
||||
},
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1, ruleSilenceInFolder2},
|
||||
},
|
||||
{
|
||||
name: "Editor permissions",
|
||||
orgRole: org.RoleEditor,
|
||||
defaultAllowed: true,
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1, ruleSilenceInFolder2},
|
||||
},
|
||||
{
|
||||
name: "Admin permissions",
|
||||
orgRole: org.RoleAdmin,
|
||||
defaultAllowed: true,
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1, ruleSilenceInFolder2},
|
||||
},
|
||||
// RBAC
|
||||
{
|
||||
name: "No permissions",
|
||||
orgRole: org.RoleNone,
|
||||
},
|
||||
{
|
||||
name: "Global read",
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: []string{accesscontrol.ActionAlertingInstanceRead}},
|
||||
},
|
||||
statusExceptions: map[silenceType]map[silenceAction]int{
|
||||
generalSilence: {readSilence: http.StatusOK},
|
||||
ruleSilenceInFolder1: {readSilence: http.StatusOK},
|
||||
ruleSilenceInFolder2: {readSilence: http.StatusOK},
|
||||
},
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1, ruleSilenceInFolder2},
|
||||
},
|
||||
{
|
||||
name: "Global read + create permissions",
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: []string{
|
||||
accesscontrol.ActionAlertingInstanceRead,
|
||||
accesscontrol.ActionAlertingInstanceCreate,
|
||||
}},
|
||||
},
|
||||
defaultAllowed: true,
|
||||
statusExceptions: map[silenceType]map[silenceAction]int{
|
||||
generalSilence: {updateSilence: http.StatusForbidden, deleteSilence: http.StatusForbidden},
|
||||
ruleSilenceInFolder1: {updateSilence: http.StatusForbidden, deleteSilence: http.StatusForbidden},
|
||||
ruleSilenceInFolder2: {updateSilence: http.StatusForbidden, deleteSilence: http.StatusForbidden},
|
||||
},
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1, ruleSilenceInFolder2},
|
||||
},
|
||||
{
|
||||
name: "Global read + update permissions",
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: []string{
|
||||
accesscontrol.ActionAlertingInstanceRead,
|
||||
accesscontrol.ActionAlertingInstanceUpdate,
|
||||
}},
|
||||
},
|
||||
defaultAllowed: true,
|
||||
statusExceptions: map[silenceType]map[silenceAction]int{
|
||||
generalSilence: {createSilence: http.StatusForbidden},
|
||||
ruleSilenceInFolder1: {createSilence: http.StatusForbidden},
|
||||
ruleSilenceInFolder2: {createSilence: http.StatusForbidden},
|
||||
},
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1, ruleSilenceInFolder2},
|
||||
},
|
||||
{
|
||||
name: "Global read + update + create permissions",
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: []string{
|
||||
accesscontrol.ActionAlertingInstanceRead,
|
||||
accesscontrol.ActionAlertingInstanceUpdate,
|
||||
accesscontrol.ActionAlertingInstanceCreate,
|
||||
}},
|
||||
},
|
||||
defaultAllowed: true,
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1, ruleSilenceInFolder2},
|
||||
},
|
||||
{
|
||||
name: "Global update + create permissions, missing read",
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: []string{
|
||||
accesscontrol.ActionAlertingInstanceUpdate,
|
||||
accesscontrol.ActionAlertingInstanceCreate,
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Silence read in folder1",
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: []string{accesscontrol.ActionAlertingSilencesRead}, Resource: "folders", ResourceAttribute: "uid", ResourceID: f1.UID},
|
||||
},
|
||||
statusExceptions: map[silenceType]map[silenceAction]int{
|
||||
generalSilence: {readSilence: http.StatusOK},
|
||||
ruleSilenceInFolder1: {readSilence: http.StatusOK},
|
||||
},
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1},
|
||||
},
|
||||
{
|
||||
name: "Silence read in folder2",
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: []string{accesscontrol.ActionAlertingSilencesRead}, Resource: "folders", ResourceAttribute: "uid", ResourceID: f2.UID},
|
||||
},
|
||||
statusExceptions: map[silenceType]map[silenceAction]int{
|
||||
generalSilence: {readSilence: http.StatusOK},
|
||||
ruleSilenceInFolder2: {readSilence: http.StatusOK},
|
||||
},
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder2},
|
||||
},
|
||||
{
|
||||
name: "Silence read + create in folder1",
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: []string{
|
||||
accesscontrol.ActionAlertingSilencesRead,
|
||||
accesscontrol.ActionAlertingSilencesCreate,
|
||||
}, Resource: "folders", ResourceAttribute: "uid", ResourceID: f1.UID},
|
||||
},
|
||||
statusExceptions: map[silenceType]map[silenceAction]int{
|
||||
generalSilence: {readSilence: http.StatusOK},
|
||||
ruleSilenceInFolder1: {readSilence: http.StatusOK, createSilence: http.StatusAccepted},
|
||||
},
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1},
|
||||
},
|
||||
{
|
||||
name: "Silence read + write in folder1",
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: []string{
|
||||
accesscontrol.ActionAlertingSilencesRead,
|
||||
accesscontrol.ActionAlertingSilencesWrite,
|
||||
}, Resource: "folders", ResourceAttribute: "uid", ResourceID: f1.UID},
|
||||
},
|
||||
statusExceptions: map[silenceType]map[silenceAction]int{
|
||||
generalSilence: {readSilence: http.StatusOK},
|
||||
ruleSilenceInFolder1: {readSilence: http.StatusOK, updateSilence: http.StatusAccepted, deleteSilence: http.StatusOK},
|
||||
},
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1},
|
||||
},
|
||||
{
|
||||
name: "Silence read + write + create in folder1",
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: []string{
|
||||
accesscontrol.ActionAlertingSilencesRead,
|
||||
accesscontrol.ActionAlertingSilencesWrite,
|
||||
accesscontrol.ActionAlertingSilencesCreate,
|
||||
}, Resource: "folders", ResourceAttribute: "uid", ResourceID: f1.UID},
|
||||
},
|
||||
statusExceptions: map[silenceType]map[silenceAction]int{
|
||||
generalSilence: {readSilence: http.StatusOK},
|
||||
ruleSilenceInFolder1: {readSilence: http.StatusOK, updateSilence: http.StatusAccepted, createSilence: http.StatusAccepted, deleteSilence: http.StatusOK},
|
||||
},
|
||||
listContents: []silenceType{generalSilence, ruleSilenceInFolder1},
|
||||
},
|
||||
{
|
||||
name: "Silence read + write + create in other folder",
|
||||
permissions: []resourcepermissions.SetResourcePermissionCommand{
|
||||
{Actions: []string{
|
||||
accesscontrol.ActionAlertingSilencesRead,
|
||||
accesscontrol.ActionAlertingSilencesWrite,
|
||||
accesscontrol.ActionAlertingSilencesCreate,
|
||||
}, Resource: "folders", ResourceAttribute: "uid", ResourceID: "unknown"},
|
||||
},
|
||||
statusExceptions: map[silenceType]map[silenceAction]int{
|
||||
generalSilence: {readSilence: http.StatusOK},
|
||||
},
|
||||
listContents: []silenceType{generalSilence},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
randomLogin := util.GenerateShortUID()
|
||||
orgRole := org.RoleNone
|
||||
if tt.orgRole != "" {
|
||||
orgRole = tt.orgRole
|
||||
}
|
||||
testUserId := createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{
|
||||
DefaultOrgRole: string(orgRole),
|
||||
Password: user.Password(randomLogin),
|
||||
Login: randomLogin,
|
||||
})
|
||||
|
||||
apiClient := newAlertingApiClient(grafanaListedAddr, randomLogin, randomLogin)
|
||||
|
||||
// Set permissions.
|
||||
asService := resourcepermissions.NewActionSetService()
|
||||
permissionsStore := resourcepermissions.NewStore(env.SQLStore, featuremgmt.WithFeatures(), &asService)
|
||||
for _, cmd := range tt.permissions {
|
||||
_, err := permissionsStore.SetUserResourcePermission(
|
||||
context.Background(),
|
||||
1,
|
||||
accesscontrol.User{ID: testUserId},
|
||||
cmd,
|
||||
nil,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
apiClient.ReloadCachedPermissions(t)
|
||||
|
||||
expectedStatus := func(sType silenceType, action silenceAction) int {
|
||||
expectedStatus, ok := defaultStatus[action][tt.defaultAllowed]
|
||||
require.True(t, ok, "No default status for action")
|
||||
if st, ok := tt.statusExceptions[sType][action]; ok {
|
||||
expectedStatus = st
|
||||
}
|
||||
return expectedStatus
|
||||
}
|
||||
|
||||
persistSilence := func(gen func() ngmodels.Silence) apimodels.PostableSilence {
|
||||
silence := *notifier.SilenceToPostableSilence(gen())
|
||||
silence.ID = ""
|
||||
okBody, status, _ := adminApiClient.PostSilence(t, silence)
|
||||
require.Equal(t, http.StatusAccepted, status)
|
||||
require.NotEmpty(t, okBody.SilenceID)
|
||||
silence.ID = okBody.SilenceID
|
||||
return silence
|
||||
}
|
||||
|
||||
tests := map[silenceAction]func(func() ngmodels.Silence, silenceType) (int, string){
|
||||
readSilence: func(gen func() ngmodels.Silence, sType silenceType) (int, string) {
|
||||
silence := persistSilence(gen)
|
||||
_, status, body := apiClient.GetSilence(t, silence.ID)
|
||||
return status, body
|
||||
},
|
||||
createSilence: func(gen func() ngmodels.Silence, sType silenceType) (int, string) {
|
||||
silence := *notifier.SilenceToPostableSilence(gen())
|
||||
silence.ID = ""
|
||||
_, status, body := apiClient.PostSilence(t, silence)
|
||||
return status, body
|
||||
},
|
||||
updateSilence: func(gen func() ngmodels.Silence, sType silenceType) (int, string) {
|
||||
silence := persistSilence(gen)
|
||||
_, status, body := apiClient.PostSilence(t, silence)
|
||||
return status, body
|
||||
},
|
||||
deleteSilence: func(gen func() ngmodels.Silence, sType silenceType) (int, string) {
|
||||
silence := persistSilence(gen)
|
||||
_, status, body := apiClient.DeleteSilence(t, silence.ID)
|
||||
return status, body
|
||||
},
|
||||
}
|
||||
|
||||
for action, test := range tests {
|
||||
t.Run(string(action), func(t *testing.T) {
|
||||
for sType, gen := range silenceGens {
|
||||
expected := expectedStatus(sType, action)
|
||||
t.Run(fmt.Sprintf("Silence: %s, Access: %d", sType, expected), func(t *testing.T) {
|
||||
status, body := test(gen, sType)
|
||||
t.Log(body)
|
||||
require.Equal(t, expected, status)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("List contents", func(t *testing.T) {
|
||||
ids := make(map[silenceType]string)
|
||||
idToStype := make(map[string]silenceType)
|
||||
|
||||
// We Create new silences with a unique label. This is both to test the filter param and to
|
||||
// simplify the test by having a known set of silences to list.
|
||||
filterLabel := util.GenerateShortUID()
|
||||
for sType, gen := range silenceGens {
|
||||
genWithFilterLabels := func() ngmodels.Silence {
|
||||
return ngmodels.CopySilenceWith(gen(), ngmodels.SilenceMuts.WithMatcher(filterLabel, filterLabel, labels.MatchEqual))
|
||||
}
|
||||
silence := persistSilence(genWithFilterLabels)
|
||||
ids[sType] = silence.ID
|
||||
idToStype[silence.ID] = sType
|
||||
}
|
||||
silences, status, body := apiClient.GetSilences(t, fmt.Sprintf("%s=%s", filterLabel, filterLabel))
|
||||
t.Log(body)
|
||||
if tt.listContents == nil {
|
||||
require.Equal(t, http.StatusForbidden, status)
|
||||
return
|
||||
}
|
||||
require.Equal(t, http.StatusOK, status)
|
||||
|
||||
idsInBody := make(map[string]struct{})
|
||||
for _, s := range silences {
|
||||
idsInBody[*s.ID] = struct{}{}
|
||||
}
|
||||
|
||||
for _, sType := range tt.listContents {
|
||||
id, ok := ids[sType]
|
||||
require.True(t, ok)
|
||||
assert.Containsf(t, idsInBody, id, "Silence of type %s not found in list", sType)
|
||||
}
|
||||
|
||||
for _, s := range silences {
|
||||
sType, ok := idToStype[*s.ID]
|
||||
require.True(t, ok, "Unknown listed silence %s", *s.ID)
|
||||
assert.Containsf(t, tt.listContents, sType, "Silence of type %s should not be found in list", sType)
|
||||
}
|
||||
assert.Len(t, silences, len(tt.listContents), "Listed silences count mismatch")
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1996,13 +1996,18 @@ func TestIntegrationAlertmanagerCreateSilence(t *testing.T) {
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
silenceID, err := client.PostSilence(t, tc.silence)
|
||||
silenceOkBody, status, body := client.PostSilence(t, tc.silence)
|
||||
t.Log(body)
|
||||
if tc.expErr != "" {
|
||||
require.EqualError(t, err, tc.expErr)
|
||||
require.Empty(t, silenceID)
|
||||
assert.NotEqual(t, http.StatusAccepted, status)
|
||||
|
||||
var validationError errutil.PublicError
|
||||
assert.NoError(t, json.Unmarshal([]byte(body), &validationError))
|
||||
assert.Contains(t, validationError.Message, tc.expErr)
|
||||
assert.Empty(t, silenceOkBody.SilenceID)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, silenceID)
|
||||
assert.Equal(t, http.StatusAccepted, status)
|
||||
assert.NotEmpty(t, silenceOkBody.SilenceID)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -454,39 +454,50 @@ func (a apiClient) DeleteRulesGroup(t *testing.T, folder string, group string) (
|
||||
return resp.StatusCode, string(b)
|
||||
}
|
||||
|
||||
func (a apiClient) PostSilence(t *testing.T, s apimodels.PostableSilence) (string, error) {
|
||||
func (a apiClient) PostSilence(t *testing.T, s apimodels.PostableSilence) (apimodels.PostSilencesOKBody, int, string) {
|
||||
t.Helper()
|
||||
|
||||
b, err := json.Marshal(s)
|
||||
require.NoError(t, err)
|
||||
|
||||
u := fmt.Sprintf("%s/api/alertmanager/grafana/api/v2/silences", a.url)
|
||||
req, err := http.NewRequest(http.MethodPost, u, bytes.NewReader(b))
|
||||
req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/alertmanager/grafana/api/v2/silences", a.url), bytes.NewReader(b))
|
||||
require.NoError(t, err)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
return sendRequest[apimodels.PostSilencesOKBody](t, req, http.StatusAccepted)
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
func (a apiClient) GetSilence(t *testing.T, id string) (apimodels.GettableSilence, int, string) {
|
||||
t.Helper()
|
||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/alertmanager/grafana/api/v2/silence/%s", a.url, id), nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
return sendRequest[apimodels.GettableSilence](t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
b, err = io.ReadAll(resp.Body)
|
||||
func (a apiClient) GetSilences(t *testing.T, filters ...string) (apimodels.GettableSilences, int, string) {
|
||||
t.Helper()
|
||||
|
||||
u, err := url.Parse(fmt.Sprintf("%s/api/alertmanager/grafana/api/v2/silences", a.url))
|
||||
require.NoError(t, err)
|
||||
|
||||
data := struct {
|
||||
SilenceID string `json:"silenceID"`
|
||||
Message string `json:"message"`
|
||||
}{}
|
||||
require.NoError(t, json.Unmarshal(b, &data))
|
||||
|
||||
if resp.StatusCode == http.StatusAccepted {
|
||||
return data.SilenceID, nil
|
||||
if len(filters) > 0 {
|
||||
u.RawQuery = url.Values{"filter": filters}.Encode()
|
||||
}
|
||||
|
||||
return "", errors.New(data.Message)
|
||||
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
return sendRequest[apimodels.GettableSilences](t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func (a apiClient) DeleteSilence(t *testing.T, id string) (any, int, string) {
|
||||
t.Helper()
|
||||
req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("%s/api/alertmanager/grafana/api/v2/silence/%s", a.url, id), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
type dynamic struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
return sendRequest[dynamic](t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func (a apiClient) GetRulesGroup(t *testing.T, folder string, group string) apimodels.RuleGroupConfigResponse {
|
||||
|
||||
Reference in New Issue
Block a user