mirror of https://github.com/grafana/grafana
prometheushacktoberfestmetricsmonitoringalertinggrafanagoinfluxdbmysqlpostgresanalyticsdata-visualizationdashboardbusiness-intelligenceelasticsearch
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1544 lines
56 KiB
1544 lines
56 KiB
package receivers
|
|
|
|
import (
|
|
"context"
|
|
"embed"
|
|
"encoding/json"
|
|
"fmt"
|
|
"maps"
|
|
"net/http"
|
|
"path"
|
|
"slices"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/grafana/alerting/notify"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
|
|
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alerting/v0alpha1"
|
|
|
|
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
|
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/routingtree"
|
|
|
|
test_common "github.com/grafana/grafana/pkg/tests/apis/alerting/notifications/common"
|
|
|
|
"github.com/grafana/grafana/pkg/bus"
|
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
|
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
|
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
|
alertingac "github.com/grafana/grafana/pkg/services/ngalert/accesscontrol"
|
|
"github.com/grafana/grafana/pkg/services/ngalert/api"
|
|
"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/channels_config"
|
|
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
|
"github.com/grafana/grafana/pkg/services/org"
|
|
"github.com/grafana/grafana/pkg/tests/api/alerting"
|
|
"github.com/grafana/grafana/pkg/tests/apis"
|
|
"github.com/grafana/grafana/pkg/tests/testinfra"
|
|
"github.com/grafana/grafana/pkg/tests/testsuite"
|
|
"github.com/grafana/grafana/pkg/util"
|
|
)
|
|
|
|
//go:embed test-data/*.*
|
|
var testData embed.FS
|
|
|
|
func TestMain(m *testing.M) {
|
|
testsuite.Run(m)
|
|
}
|
|
|
|
func getTestHelper(t *testing.T) *apis.K8sTestHelper {
|
|
return apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{})
|
|
}
|
|
|
|
func TestIntegrationResourceIdentifier(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
helper := getTestHelper(t)
|
|
client := test_common.NewReceiverClient(t, helper.Org1.Admin)
|
|
newResource := &v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: "Test-Receiver",
|
|
Integrations: []v0alpha1.ReceiverIntegration{},
|
|
},
|
|
}
|
|
|
|
t.Run("create should fail if object name is specified", func(t *testing.T) {
|
|
resource := newResource.Copy().(*v0alpha1.Receiver)
|
|
resource.Name = "new-receiver"
|
|
_, err := client.Create(ctx, resource, v1.CreateOptions{})
|
|
require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest but got %s", err)
|
|
})
|
|
|
|
var resourceID string
|
|
t.Run("create should succeed and provide resource name", func(t *testing.T) {
|
|
actual, err := client.Create(ctx, newResource, v1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
require.NotEmptyf(t, actual.Name, "Resource name should not be empty")
|
|
require.NotEmptyf(t, actual.UID, "Resource UID should not be empty")
|
|
resourceID = actual.Name
|
|
})
|
|
|
|
t.Run("resource should be available by the identifier", func(t *testing.T) {
|
|
actual, err := client.Get(ctx, resourceID, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
require.NotEmptyf(t, actual.Name, "Resource name should not be empty")
|
|
require.Equal(t, newResource.Spec, actual.Spec)
|
|
})
|
|
|
|
t.Run("update should rename receiver if name in the specification changes", func(t *testing.T) {
|
|
existing, err := client.Get(ctx, resourceID, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
|
|
updated := existing.Copy().(*v0alpha1.Receiver)
|
|
updated.Spec.Title = "another-newReceiver"
|
|
|
|
actual, err := client.Update(ctx, updated, v1.UpdateOptions{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, updated.Spec, actual.Spec)
|
|
require.NotEqualf(t, updated.Name, actual.Name, "Update should change the resource name but it didn't")
|
|
require.NotEqualf(t, updated.ResourceVersion, actual.ResourceVersion, "Update should change the resource version but it didn't")
|
|
|
|
resource, err := client.Get(ctx, actual.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, actual.Spec, resource.Spec)
|
|
require.Equal(t, actual.Name, resource.Name)
|
|
require.Equal(t, actual.ResourceVersion, resource.ResourceVersion)
|
|
})
|
|
}
|
|
|
|
// TestIntegrationResourcePermissions focuses on testing resource permissions for the alerting receiver resource. It
|
|
// verifies that access is correctly set when creating resources and assigning permissions to users, teams, and roles.
|
|
func TestIntegrationResourcePermissions(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
helper := getTestHelper(t)
|
|
|
|
org1 := helper.Org1
|
|
|
|
noneUser := helper.CreateUser("none", apis.Org1, org.RoleNone, nil)
|
|
|
|
creator := helper.CreateUser("creator", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{
|
|
createWildcardPermission(
|
|
accesscontrol.ActionAlertingReceiversCreate,
|
|
),
|
|
})
|
|
|
|
admin := org1.Admin
|
|
viewer := org1.Viewer
|
|
editor := org1.Editor
|
|
adminClient := test_common.NewReceiverClient(t, admin)
|
|
|
|
writeACMetadata := []string{"canWrite", "canDelete"}
|
|
allACMetadata := []string{"canWrite", "canDelete", "canReadSecrets", "canAdmin"}
|
|
|
|
mustID := func(user apis.User) int64 {
|
|
id, err := user.Identity.GetInternalID()
|
|
require.NoError(t, err)
|
|
return id
|
|
}
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
creatingUser apis.User
|
|
testUser apis.User
|
|
assignments []accesscontrol.SetResourcePermissionCommand
|
|
expACMetadata []string
|
|
expRead bool
|
|
}{
|
|
// Basic access.
|
|
{
|
|
name: "Admin creates and has all metadata and access",
|
|
creatingUser: admin,
|
|
testUser: admin,
|
|
assignments: nil,
|
|
expACMetadata: allACMetadata,
|
|
expRead: true,
|
|
},
|
|
{
|
|
name: "Creator creates and has all metadata and access",
|
|
creatingUser: creator,
|
|
testUser: creator,
|
|
assignments: nil,
|
|
expACMetadata: allACMetadata,
|
|
expRead: true,
|
|
},
|
|
{
|
|
name: "Admin creates, noneUser has no metadata and no access",
|
|
creatingUser: admin,
|
|
testUser: noneUser,
|
|
assignments: nil,
|
|
expACMetadata: nil,
|
|
expRead: false,
|
|
},
|
|
{
|
|
name: "Admin creates, viewer has no metadata but has access",
|
|
creatingUser: admin,
|
|
testUser: viewer,
|
|
expACMetadata: nil,
|
|
expRead: true,
|
|
},
|
|
{
|
|
name: "Admin creates, editor has write metadata and access",
|
|
creatingUser: admin,
|
|
testUser: editor,
|
|
expACMetadata: writeACMetadata,
|
|
expRead: true,
|
|
},
|
|
// User-based assignments.
|
|
{
|
|
name: "Admin creates, assigns read, noneUser has no metadata but has access",
|
|
creatingUser: admin,
|
|
testUser: noneUser,
|
|
assignments: []accesscontrol.SetResourcePermissionCommand{{UserID: mustID(noneUser), Permission: string(alertingac.ReceiverPermissionView)}},
|
|
expACMetadata: nil,
|
|
expRead: true,
|
|
},
|
|
{
|
|
name: "Admin creates, assigns write, noneUser has write metadata and access",
|
|
creatingUser: admin,
|
|
testUser: noneUser,
|
|
assignments: []accesscontrol.SetResourcePermissionCommand{{UserID: mustID(noneUser), Permission: string(alertingac.ReceiverPermissionEdit)}},
|
|
expACMetadata: writeACMetadata,
|
|
expRead: true,
|
|
},
|
|
{
|
|
name: "Admin creates, assigns admin, noneUser has all metadata and access",
|
|
creatingUser: admin,
|
|
testUser: noneUser,
|
|
assignments: []accesscontrol.SetResourcePermissionCommand{{UserID: mustID(noneUser), Permission: string(alertingac.ReceiverPermissionAdmin)}},
|
|
expACMetadata: allACMetadata,
|
|
expRead: true,
|
|
},
|
|
// Other users don't get assignments.
|
|
{
|
|
name: "Admin creates, assigns read to noneUser, creator has no metadata and no access",
|
|
creatingUser: admin,
|
|
testUser: creator,
|
|
assignments: []accesscontrol.SetResourcePermissionCommand{{UserID: mustID(noneUser), Permission: string(alertingac.ReceiverPermissionView)}},
|
|
expACMetadata: nil,
|
|
expRead: false,
|
|
},
|
|
{
|
|
name: "Admin creates, assigns write to noneUser, creator has no metadata and no access",
|
|
creatingUser: admin,
|
|
testUser: creator,
|
|
assignments: []accesscontrol.SetResourcePermissionCommand{{UserID: mustID(noneUser), Permission: string(alertingac.ReceiverPermissionEdit)}},
|
|
expACMetadata: nil,
|
|
expRead: false,
|
|
},
|
|
{
|
|
name: "Admin creates, assigns admin to noneUser, creator has no metadata and no access",
|
|
creatingUser: admin,
|
|
testUser: creator,
|
|
assignments: []accesscontrol.SetResourcePermissionCommand{{UserID: mustID(noneUser), Permission: string(alertingac.ReceiverPermissionAdmin)}},
|
|
expACMetadata: nil,
|
|
expRead: false,
|
|
},
|
|
// Role-based access.
|
|
{
|
|
name: "Admin creates, assigns editor, viewer has write metadata and access",
|
|
creatingUser: admin,
|
|
testUser: viewer,
|
|
assignments: []accesscontrol.SetResourcePermissionCommand{{UserID: mustID(viewer), Permission: string(alertingac.ReceiverPermissionEdit)}},
|
|
expACMetadata: writeACMetadata,
|
|
expRead: true,
|
|
},
|
|
{
|
|
name: "Admin creates, assigns admin, viewer has all metadata and access",
|
|
creatingUser: admin,
|
|
testUser: viewer,
|
|
assignments: []accesscontrol.SetResourcePermissionCommand{{UserID: mustID(viewer), Permission: string(alertingac.ReceiverPermissionAdmin)}},
|
|
expACMetadata: allACMetadata,
|
|
expRead: true,
|
|
},
|
|
{
|
|
name: "Admin creates, assigns admin, editor has all metadata and access",
|
|
creatingUser: admin,
|
|
testUser: editor,
|
|
assignments: []accesscontrol.SetResourcePermissionCommand{{UserID: mustID(editor), Permission: string(alertingac.ReceiverPermissionAdmin)}},
|
|
expACMetadata: allACMetadata,
|
|
expRead: true,
|
|
},
|
|
// Team-based access. Staff team has editor+admin but not viewer in it.
|
|
{
|
|
name: "Admin creates, assigns admin to staff, viewer has no metadata and access",
|
|
creatingUser: admin,
|
|
testUser: viewer,
|
|
assignments: []accesscontrol.SetResourcePermissionCommand{{TeamID: org1.Staff.ID, Permission: string(alertingac.ReceiverPermissionAdmin)}},
|
|
expACMetadata: nil,
|
|
expRead: true,
|
|
},
|
|
{
|
|
name: "Admin creates, assigns admin to staff, editor has all metadata and access",
|
|
creatingUser: admin,
|
|
testUser: editor,
|
|
assignments: []accesscontrol.SetResourcePermissionCommand{{TeamID: org1.Staff.ID, Permission: string(alertingac.ReceiverPermissionAdmin)}},
|
|
expACMetadata: allACMetadata,
|
|
expRead: true,
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
createClient := test_common.NewReceiverClient(t, tc.creatingUser)
|
|
client := test_common.NewReceiverClient(t, tc.testUser)
|
|
|
|
var created = &v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: "receiver-1",
|
|
Integrations: []v0alpha1.ReceiverIntegration{},
|
|
},
|
|
}
|
|
d, err := json.Marshal(created)
|
|
require.NoError(t, err)
|
|
|
|
// Create receiver with creatingUser
|
|
created, err = createClient.Create(ctx, created, v1.CreateOptions{})
|
|
require.NoErrorf(t, err, "Payload %s", string(d))
|
|
require.NotNil(t, created)
|
|
|
|
defer func() {
|
|
_ = adminClient.Delete(ctx, created.Name, v1.DeleteOptions{})
|
|
}()
|
|
|
|
// Assign resource permissions
|
|
cliCfg := helper.Org1.Admin.NewRestConfig()
|
|
alertingApi := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
|
|
for _, permission := range tc.assignments {
|
|
status, body := alertingApi.AssignReceiverPermission(t, created.Name, permission)
|
|
require.Equalf(t, http.StatusOK, status, "Expected status 200 but got %d: %s", status, body)
|
|
}
|
|
|
|
// Test read
|
|
if tc.expRead {
|
|
// Helper methods.
|
|
extractReceiverFromList := func(list *v0alpha1.ReceiverList, name string) *v0alpha1.Receiver {
|
|
for i := range list.Items {
|
|
if list.Items[i].Name == name {
|
|
return list.Items[i].Copy().(*v0alpha1.Receiver)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Obtain expected responses using admin client as source of truth.
|
|
expectedGetWithMetadata, expectedListWithMetadata := func() (*v0alpha1.Receiver, *v0alpha1.Receiver) {
|
|
expectedGet, err := adminClient.Get(ctx, created.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, expectedGet)
|
|
|
|
// Set expected metadata.
|
|
expectedGetWithMetadata := expectedGet.Copy().(*v0alpha1.Receiver)
|
|
// Clear any existing access control metadata.
|
|
for _, k := range allACMetadata {
|
|
delete(expectedGetWithMetadata.Annotations, v0alpha1.AccessControlAnnotation(k))
|
|
}
|
|
for _, ac := range tc.expACMetadata {
|
|
expectedGetWithMetadata.SetAccessControl(ac)
|
|
}
|
|
|
|
expectedList, err := adminClient.List(ctx, v1.ListOptions{})
|
|
require.NoError(t, err)
|
|
expectedListWithMetadata := extractReceiverFromList(expectedList, created.Name)
|
|
require.NotNil(t, expectedListWithMetadata)
|
|
expectedListWithMetadata = expectedListWithMetadata.Copy().(*v0alpha1.Receiver)
|
|
// Clear any existing access control metadata.
|
|
for _, k := range allACMetadata {
|
|
delete(expectedListWithMetadata.Annotations, v0alpha1.AccessControlAnnotation(k))
|
|
}
|
|
for _, ac := range tc.expACMetadata {
|
|
expectedListWithMetadata.SetAccessControl(ac)
|
|
}
|
|
return expectedGetWithMetadata, expectedListWithMetadata
|
|
}()
|
|
|
|
t.Run("should be able to list receivers", func(t *testing.T) {
|
|
list, err := client.List(ctx, v1.ListOptions{})
|
|
require.NoError(t, err)
|
|
listedReceiver := extractReceiverFromList(list, created.Name)
|
|
assert.Equalf(t, expectedListWithMetadata, listedReceiver, "Expected %v but got %v", expectedListWithMetadata, listedReceiver)
|
|
})
|
|
|
|
t.Run("should be able to read receiver by resource identifier", func(t *testing.T) {
|
|
got, err := client.Get(ctx, expectedGetWithMetadata.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
assert.Equalf(t, expectedGetWithMetadata, got, "Expected %v but got %v", expectedGetWithMetadata, got)
|
|
})
|
|
} else {
|
|
t.Run("list receivers should be empty", func(t *testing.T) {
|
|
list, err := client.List(ctx, v1.ListOptions{})
|
|
require.NoError(t, err)
|
|
require.Emptyf(t, list.Items, "Expected no receivers but got %v", list.Items)
|
|
})
|
|
|
|
t.Run("should be forbidden to read receiver by name", func(t *testing.T) {
|
|
_, err := client.Get(ctx, created.Name, v1.GetOptions{})
|
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIntegrationAccessControl(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
helper := getTestHelper(t)
|
|
|
|
org1 := helper.Org1
|
|
|
|
type testCase struct {
|
|
user apis.User
|
|
canRead bool
|
|
canUpdate bool
|
|
canCreate bool
|
|
canDelete bool
|
|
canReadSecrets bool
|
|
canAdmin bool
|
|
}
|
|
// region users
|
|
unauthorized := helper.CreateUser("unauthorized", "Org1", org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{})
|
|
|
|
reader := helper.CreateUser("reader", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{
|
|
createWildcardPermission(accesscontrol.ActionAlertingReceiversRead),
|
|
})
|
|
secretsReader := helper.CreateUser("secretsReader", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{
|
|
createWildcardPermission(accesscontrol.ActionAlertingReceiversReadSecrets),
|
|
})
|
|
creator := helper.CreateUser("creator", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{
|
|
createWildcardPermission(
|
|
accesscontrol.ActionAlertingReceiversRead,
|
|
accesscontrol.ActionAlertingReceiversCreate,
|
|
),
|
|
})
|
|
updater := helper.CreateUser("updater", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{
|
|
createWildcardPermission(
|
|
accesscontrol.ActionAlertingReceiversRead,
|
|
accesscontrol.ActionAlertingReceiversUpdate,
|
|
),
|
|
})
|
|
deleter := helper.CreateUser("deleter", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{
|
|
createWildcardPermission(
|
|
accesscontrol.ActionAlertingReceiversRead,
|
|
accesscontrol.ActionAlertingReceiversDelete,
|
|
),
|
|
})
|
|
legacyReader := helper.CreateUser("legacyReader", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{
|
|
{
|
|
Actions: []string{
|
|
accesscontrol.ActionAlertingNotificationsRead,
|
|
},
|
|
},
|
|
})
|
|
legacyWriter := helper.CreateUser("legacyWriter", "Org1", org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{
|
|
{
|
|
Actions: []string{
|
|
accesscontrol.ActionAlertingNotificationsRead,
|
|
accesscontrol.ActionAlertingNotificationsWrite,
|
|
},
|
|
},
|
|
})
|
|
adminLikeUser := helper.CreateUser("adminLikeUser", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{
|
|
createWildcardPermission(append(
|
|
[]string{accesscontrol.ActionAlertingReceiversCreate},
|
|
ossaccesscontrol.ReceiversAdminActions...,
|
|
)...),
|
|
})
|
|
|
|
// Test receivers with uids longer than 40 characters. User name is used in receiver name.
|
|
adminLikeUserLongName := helper.CreateUser("adminLikeUserCreatingAReallyLongReceiverName", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{
|
|
createWildcardPermission(append(
|
|
[]string{accesscontrol.ActionAlertingReceiversCreate},
|
|
ossaccesscontrol.ReceiversAdminActions...,
|
|
)...),
|
|
})
|
|
|
|
// endregion
|
|
|
|
testCases := []testCase{
|
|
{
|
|
user: unauthorized,
|
|
canRead: false,
|
|
canUpdate: false,
|
|
canCreate: false,
|
|
canDelete: false,
|
|
},
|
|
{
|
|
user: org1.Admin,
|
|
canRead: true,
|
|
canCreate: true,
|
|
canUpdate: true,
|
|
canDelete: true,
|
|
canAdmin: true,
|
|
canReadSecrets: true,
|
|
},
|
|
{
|
|
user: org1.Editor,
|
|
canRead: true,
|
|
canUpdate: true,
|
|
canCreate: true,
|
|
canDelete: true,
|
|
},
|
|
{
|
|
user: org1.Viewer,
|
|
canRead: true,
|
|
},
|
|
{
|
|
user: reader,
|
|
canRead: true,
|
|
},
|
|
{
|
|
user: secretsReader,
|
|
canRead: true,
|
|
canReadSecrets: true,
|
|
},
|
|
{
|
|
user: creator,
|
|
canRead: true,
|
|
canCreate: true,
|
|
},
|
|
{
|
|
user: updater,
|
|
canRead: true,
|
|
canUpdate: true,
|
|
},
|
|
{
|
|
user: deleter,
|
|
canRead: true,
|
|
canDelete: true,
|
|
},
|
|
{
|
|
user: legacyReader,
|
|
canRead: true,
|
|
},
|
|
{
|
|
user: legacyWriter,
|
|
canRead: true,
|
|
canCreate: true,
|
|
canUpdate: true,
|
|
canDelete: true,
|
|
},
|
|
{
|
|
user: adminLikeUser,
|
|
canRead: true,
|
|
canCreate: true,
|
|
canUpdate: true,
|
|
canDelete: true,
|
|
canAdmin: true,
|
|
canReadSecrets: true,
|
|
},
|
|
{
|
|
user: adminLikeUserLongName,
|
|
canRead: true,
|
|
canCreate: true,
|
|
canUpdate: true,
|
|
canDelete: true,
|
|
canAdmin: true,
|
|
canReadSecrets: true,
|
|
},
|
|
}
|
|
|
|
adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin)
|
|
for _, tc := range testCases {
|
|
t.Run(fmt.Sprintf("user '%s'", tc.user.Identity.GetLogin()), func(t *testing.T) {
|
|
client := test_common.NewReceiverClient(t, tc.user)
|
|
|
|
var expected = &v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: fmt.Sprintf("receiver-1-%s", tc.user.Identity.GetLogin()),
|
|
Integrations: []v0alpha1.ReceiverIntegration{},
|
|
},
|
|
}
|
|
d, err := json.Marshal(expected)
|
|
require.NoError(t, err)
|
|
|
|
newReceiver := expected.Copy().(*v0alpha1.Receiver)
|
|
newReceiver.Spec.Title = fmt.Sprintf("receiver-2-%s", tc.user.Identity.GetLogin())
|
|
if tc.canCreate {
|
|
t.Run("should be able to create receiver", func(t *testing.T) {
|
|
actual, err := client.Create(ctx, newReceiver, v1.CreateOptions{})
|
|
require.NoErrorf(t, err, "Payload %s", string(d))
|
|
|
|
require.Equal(t, newReceiver.Spec, actual.Spec)
|
|
|
|
t.Run("should fail if already exists", func(t *testing.T) {
|
|
_, err := client.Create(ctx, newReceiver, v1.CreateOptions{})
|
|
require.Truef(t, errors.IsConflict(err), "expected bad request but got %s", err)
|
|
})
|
|
|
|
// Cleanup.
|
|
require.NoError(t, adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{}))
|
|
})
|
|
} else {
|
|
t.Run("should be forbidden to create", func(t *testing.T) {
|
|
_, err := client.Create(ctx, newReceiver, v1.CreateOptions{})
|
|
require.Truef(t, errors.IsForbidden(err), "Payload %s", string(d))
|
|
})
|
|
}
|
|
|
|
// create resource to proceed with other tests. We don't use the one created above because the user will always
|
|
// have admin permissions on it.
|
|
expected, err = adminClient.Create(ctx, expected, v1.CreateOptions{})
|
|
require.NoErrorf(t, err, "Payload %s", string(d))
|
|
require.NotNil(t, expected)
|
|
|
|
if tc.canRead {
|
|
// Set expected metadata.
|
|
expectedWithMetadata := expected.Copy().(*v0alpha1.Receiver)
|
|
expectedWithMetadata.SetInUse(0, nil)
|
|
if tc.canUpdate {
|
|
expectedWithMetadata.SetAccessControl("canWrite")
|
|
}
|
|
if tc.canDelete {
|
|
expectedWithMetadata.SetAccessControl("canDelete")
|
|
}
|
|
if tc.canReadSecrets {
|
|
expectedWithMetadata.SetAccessControl("canReadSecrets")
|
|
}
|
|
if tc.canAdmin {
|
|
expectedWithMetadata.SetAccessControl("canAdmin")
|
|
}
|
|
t.Run("should be able to list receivers", func(t *testing.T) {
|
|
list, err := client.List(ctx, v1.ListOptions{})
|
|
require.NoError(t, err)
|
|
require.Len(t, list.Items, 2) // default + created
|
|
})
|
|
|
|
t.Run("should be able to read receiver by resource identifier", func(t *testing.T) {
|
|
got, err := client.Get(ctx, expected.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, expectedWithMetadata, got)
|
|
|
|
t.Run("should get NotFound if resource does not exist", func(t *testing.T) {
|
|
_, err := client.Get(ctx, "Notfound", v1.GetOptions{})
|
|
require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err)
|
|
})
|
|
})
|
|
} else {
|
|
t.Run("list receivers should be empty", func(t *testing.T) {
|
|
list, err := client.List(ctx, v1.ListOptions{})
|
|
require.NoError(t, err)
|
|
require.Emptyf(t, list.Items, "Expected no receivers but got %v", list.Items)
|
|
})
|
|
|
|
t.Run("should be forbidden to read receiver by name", func(t *testing.T) {
|
|
_, err := client.Get(ctx, expected.Name, v1.GetOptions{})
|
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
|
|
|
t.Run("should get forbidden even if name does not exist", func(t *testing.T) {
|
|
_, err := client.Get(ctx, "Notfound", v1.GetOptions{})
|
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
|
})
|
|
})
|
|
}
|
|
|
|
updatedExpected := expected.Copy().(*v0alpha1.Receiver)
|
|
updatedExpected.Spec.Integrations = append(updatedExpected.Spec.Integrations, createIntegration(t, "email"))
|
|
|
|
d, err = json.Marshal(updatedExpected)
|
|
require.NoError(t, err)
|
|
|
|
if tc.canUpdate {
|
|
t.Run("should be able to update receiver", func(t *testing.T) {
|
|
updated, err := client.Update(ctx, updatedExpected, v1.UpdateOptions{})
|
|
require.NoErrorf(t, err, "Payload %s", string(d))
|
|
|
|
expected = updated
|
|
|
|
t.Run("should get NotFound if name does not exist", func(t *testing.T) {
|
|
up := updatedExpected.Copy().(*v0alpha1.Receiver)
|
|
up.Name = "notFound"
|
|
_, err := client.Update(ctx, up, v1.UpdateOptions{})
|
|
require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err)
|
|
})
|
|
})
|
|
} else {
|
|
t.Run("should be forbidden to update receiver", func(t *testing.T) {
|
|
_, err := client.Update(ctx, updatedExpected, v1.UpdateOptions{})
|
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
|
|
|
t.Run("should get forbidden even if resource does not exist", func(t *testing.T) {
|
|
up := updatedExpected.Copy().(*v0alpha1.Receiver)
|
|
up.Name = "notFound"
|
|
_, err := client.Update(ctx, up, v1.UpdateOptions{})
|
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
|
})
|
|
})
|
|
}
|
|
|
|
deleteOptions := v1.DeleteOptions{Preconditions: &v1.Preconditions{ResourceVersion: util.Pointer(expected.ResourceVersion)}}
|
|
|
|
if tc.canDelete {
|
|
t.Run("should be able to delete receiver", func(t *testing.T) {
|
|
err := client.Delete(ctx, expected.Name, deleteOptions)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("should get NotFound if name does not exist", func(t *testing.T) {
|
|
err := client.Delete(ctx, "notfound", v1.DeleteOptions{})
|
|
require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err)
|
|
})
|
|
})
|
|
} else {
|
|
t.Run("should be forbidden to delete receiver", func(t *testing.T) {
|
|
err := client.Delete(ctx, expected.Name, deleteOptions)
|
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
|
|
|
t.Run("should be forbidden even if resource does not exist", func(t *testing.T) {
|
|
err := client.Delete(ctx, "notfound", v1.DeleteOptions{})
|
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
|
})
|
|
})
|
|
require.NoError(t, adminClient.Delete(ctx, expected.Name, v1.DeleteOptions{}))
|
|
}
|
|
|
|
if tc.canRead {
|
|
t.Run("should get empty list if no receivers", func(t *testing.T) {
|
|
list, err := client.List(ctx, v1.ListOptions{})
|
|
require.NoError(t, err)
|
|
require.Len(t, list.Items, 1)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIntegrationInUseMetadata(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
helper := getTestHelper(t)
|
|
|
|
cliCfg := helper.Org1.Admin.NewRestConfig()
|
|
legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
|
|
|
|
adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin)
|
|
// Prepare environment and create notification policy and rule that use receiver
|
|
alertmanagerRaw, err := testData.ReadFile(path.Join("test-data", "notification-settings.json"))
|
|
require.NoError(t, err)
|
|
var amConfig definitions.PostableUserConfig
|
|
require.NoError(t, json.Unmarshal(alertmanagerRaw, &amConfig))
|
|
|
|
// Add more references to the receiver in other routes.
|
|
route1 := *amConfig.AlertmanagerConfig.Route.Routes[0]
|
|
route1.Routes = nil
|
|
route2 := route1
|
|
parentRoute := *amConfig.AlertmanagerConfig.Route.Routes[0]
|
|
parentRoute.Routes = []*definitions.Route{&route1, &route2}
|
|
amConfig.AlertmanagerConfig.Route.Routes = append(amConfig.AlertmanagerConfig.Route.Routes, &parentRoute)
|
|
|
|
persistInitialConfig(t, amConfig)
|
|
|
|
postGroupRaw, err := testData.ReadFile(path.Join("test-data", "rulegroup-1.json"))
|
|
require.NoError(t, err)
|
|
var ruleGroup definitions.PostableRuleGroupConfig
|
|
require.NoError(t, json.Unmarshal(postGroupRaw, &ruleGroup))
|
|
|
|
// Add more references to the receiver by creating adding same rule with a different title.
|
|
ruleGen := func() definitions.PostableGrafanaRule { return *ruleGroup.Rules[0].GrafanaManagedAlert }
|
|
rule2 := ruleGen()
|
|
rule2.Title = "Rule2"
|
|
rule2.NotificationSettings = &definitions.AlertRuleNotificationSettings{Receiver: "grafana-default-email"}
|
|
rule3 := ruleGen()
|
|
rule3.Title = "Rule3"
|
|
ruleGroup.Rules = append(ruleGroup.Rules,
|
|
definitions.PostableExtendedRuleNode{
|
|
ApiRuleNode: ruleGroup.Rules[0].ApiRuleNode,
|
|
GrafanaManagedAlert: &rule2,
|
|
},
|
|
definitions.PostableExtendedRuleNode{
|
|
ApiRuleNode: ruleGroup.Rules[0].ApiRuleNode,
|
|
GrafanaManagedAlert: &rule3,
|
|
},
|
|
)
|
|
|
|
folderUID := "test-folder"
|
|
legacyCli.CreateFolder(t, folderUID, "TEST")
|
|
_, status, data := legacyCli.PostRulesGroupWithStatus(t, folderUID, &ruleGroup, false)
|
|
require.Equalf(t, http.StatusAccepted, status, "Failed to post Rule: %s", data)
|
|
|
|
requestReceivers := func(t *testing.T, title string) (v0alpha1.Receiver, v0alpha1.Receiver) {
|
|
t.Helper()
|
|
receivers, err := adminClient.List(ctx, v1.ListOptions{})
|
|
require.NoError(t, err)
|
|
require.Len(t, receivers.Items, 2)
|
|
idx := slices.IndexFunc(receivers.Items, func(interval v0alpha1.Receiver) bool {
|
|
return interval.Spec.Title == title
|
|
})
|
|
receiverListed := receivers.Items[idx]
|
|
|
|
receiverGet, err := adminClient.Get(ctx, receiverListed.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
|
|
return receiverListed, *receiverGet
|
|
}
|
|
|
|
checkInUse := func(t *testing.T, receiverList, receiverGet v0alpha1.Receiver, routes, rules int) {
|
|
t.Helper()
|
|
assert.Equalf(t, fmt.Sprintf("%d", routes), receiverList.Annotations[v0alpha1.InUseAnnotation("routes")], "LIST: Expected %s used by %d routes", receiverList.Spec.Title, routes)
|
|
assert.Equalf(t, fmt.Sprintf("%d", rules), receiverList.Annotations[v0alpha1.InUseAnnotation("rules")], "LIST: Expected %s used by %d rules", receiverList.Spec.Title, rules)
|
|
assert.Equalf(t, fmt.Sprintf("%d", routes), receiverGet.Annotations[v0alpha1.InUseAnnotation("routes")], "GET: Expected %s used by %d routes", receiverGet.Spec.Title, routes)
|
|
assert.Equalf(t, fmt.Sprintf("%d", rules), receiverGet.Annotations[v0alpha1.InUseAnnotation("rules")], "GET: Expected %s used by %d rules", receiverGet.Spec.Title, rules)
|
|
}
|
|
|
|
receiverListed, receiverGet := requestReceivers(t, "user-defined")
|
|
checkInUse(t, receiverListed, receiverGet, 4, 2)
|
|
|
|
// Verify the default.
|
|
receiverListed, receiverGet = requestReceivers(t, "grafana-default-email")
|
|
checkInUse(t, receiverListed, receiverGet, 1, 1)
|
|
|
|
// Removing the new extra route should leave only 1.
|
|
amConfig.AlertmanagerConfig.Route.Routes = amConfig.AlertmanagerConfig.Route.Routes[:1]
|
|
v1Route, err := routingtree.ConvertToK8sResource(helper.Org1.AdminServiceAccount.OrgId, *amConfig.AlertmanagerConfig.Route, "", func(int64) string { return "default" })
|
|
require.NoError(t, err)
|
|
routeAdminClient := test_common.NewRoutingTreeClient(t, helper.Org1.Admin)
|
|
_, err = routeAdminClient.Update(ctx, v1Route, v1.UpdateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
receiverListed, receiverGet = requestReceivers(t, "user-defined")
|
|
checkInUse(t, receiverListed, receiverGet, 1, 2)
|
|
|
|
// Remove the extra rules.
|
|
ruleGroup.Rules = ruleGroup.Rules[:1]
|
|
_, status, data = legacyCli.PostRulesGroupWithStatus(t, folderUID, &ruleGroup, false)
|
|
require.Equalf(t, http.StatusAccepted, status, "Failed to post Rule: %s", data)
|
|
|
|
receiverListed, receiverGet = requestReceivers(t, "user-defined")
|
|
checkInUse(t, receiverListed, receiverGet, 1, 1)
|
|
|
|
receiverListed, receiverGet = requestReceivers(t, "grafana-default-email")
|
|
checkInUse(t, receiverListed, receiverGet, 1, 0)
|
|
|
|
// Remove the remaining routes.
|
|
amConfig.AlertmanagerConfig.Route.Routes = nil
|
|
v1route, err := routingtree.ConvertToK8sResource(1, *amConfig.AlertmanagerConfig.Route, "", func(int64) string { return "default" })
|
|
require.NoError(t, err)
|
|
_, err = routeAdminClient.Update(ctx, v1route, v1.UpdateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
// Remove the remaining rules.
|
|
ruleGroup.Rules = nil
|
|
_, status, data = legacyCli.PostRulesGroupWithStatus(t, folderUID, &ruleGroup, false)
|
|
require.Equalf(t, http.StatusAccepted, status, "Failed to post Rule: %s", data)
|
|
|
|
receiverListed, receiverGet = requestReceivers(t, "user-defined")
|
|
checkInUse(t, receiverListed, receiverGet, 0, 0)
|
|
|
|
receiverListed, receiverGet = requestReceivers(t, "grafana-default-email")
|
|
checkInUse(t, receiverListed, receiverGet, 1, 0)
|
|
}
|
|
|
|
func TestIntegrationProvisioning(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
helper := getTestHelper(t)
|
|
|
|
org := helper.Org1
|
|
|
|
admin := org.Admin
|
|
adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin)
|
|
env := helper.GetEnv()
|
|
ac := acimpl.ProvideAccessControl(env.FeatureToggles)
|
|
db, err := store.ProvideDBStore(env.Cfg, env.FeatureToggles, env.SQLStore, &foldertest.FakeService{}, &dashboards.FakeDashboardService{}, ac, bus.ProvideBus(tracing.InitializeTracerForTest()))
|
|
require.NoError(t, err)
|
|
|
|
created, err := adminClient.Create(ctx, &v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: "test-receiver-1",
|
|
Integrations: []v0alpha1.ReceiverIntegration{
|
|
createIntegration(t, "email"),
|
|
},
|
|
},
|
|
}, v1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "none", created.GetProvenanceStatus())
|
|
|
|
t.Run("should provide provenance status", func(t *testing.T) {
|
|
require.NoError(t, db.SetProvenance(ctx, &definitions.EmbeddedContactPoint{
|
|
UID: *created.Spec.Integrations[0].Uid,
|
|
}, admin.Identity.GetOrgID(), "API"))
|
|
|
|
got, err := adminClient.Get(ctx, created.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "API", got.GetProvenanceStatus())
|
|
})
|
|
|
|
t.Run("should not let update if provisioned", func(t *testing.T) {
|
|
got, err := adminClient.Get(ctx, created.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
updated := got.Copy().(*v0alpha1.Receiver)
|
|
updated.Spec.Integrations = append(updated.Spec.Integrations, createIntegration(t, "email"))
|
|
|
|
_, err = adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
|
})
|
|
|
|
t.Run("should not let delete if provisioned", func(t *testing.T) {
|
|
err := adminClient.Delete(ctx, created.Name, v1.DeleteOptions{})
|
|
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
|
})
|
|
}
|
|
|
|
func TestIntegrationOptimisticConcurrency(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
helper := getTestHelper(t)
|
|
|
|
adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin)
|
|
receiver := v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: "receiver-1",
|
|
Integrations: []v0alpha1.ReceiverIntegration{},
|
|
},
|
|
}
|
|
|
|
created, err := adminClient.Create(ctx, &receiver, v1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, created)
|
|
require.NotEmpty(t, created.ResourceVersion)
|
|
|
|
t.Run("should forbid if version does not match", func(t *testing.T) {
|
|
updated := created.Copy().(*v0alpha1.Receiver)
|
|
updated.ResourceVersion = "test"
|
|
_, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
|
require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err)
|
|
})
|
|
t.Run("should update if version matches", func(t *testing.T) {
|
|
updated := created.Copy().(*v0alpha1.Receiver)
|
|
updated.Spec.Integrations = append(updated.Spec.Integrations, createIntegration(t, "email"))
|
|
actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
|
require.NoError(t, err)
|
|
for i, integration := range actualUpdated.Spec.Integrations {
|
|
updated.Spec.Integrations[i].Uid = integration.Uid
|
|
}
|
|
require.EqualValues(t, updated.Spec, actualUpdated.Spec)
|
|
require.NotEqual(t, updated.ResourceVersion, actualUpdated.ResourceVersion)
|
|
})
|
|
t.Run("should fail to update if version is empty", func(t *testing.T) {
|
|
updated := created.Copy().(*v0alpha1.Receiver)
|
|
updated.ResourceVersion = ""
|
|
updated.Spec.Integrations = append(updated.Spec.Integrations, createIntegration(t, "webhook"))
|
|
_, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
|
require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err) // TODO Change that? K8s returns 400 instead.
|
|
})
|
|
t.Run("should fail to delete if version does not match", func(t *testing.T) {
|
|
actual, err := adminClient.Get(ctx, created.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
|
|
err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{
|
|
Preconditions: &v1.Preconditions{
|
|
ResourceVersion: util.Pointer("something"),
|
|
},
|
|
})
|
|
require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err)
|
|
})
|
|
t.Run("should succeed if version matches", func(t *testing.T) {
|
|
actual, err := adminClient.Get(ctx, created.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
|
|
err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{
|
|
Preconditions: &v1.Preconditions{
|
|
ResourceVersion: util.Pointer(actual.ResourceVersion),
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
})
|
|
t.Run("should succeed if version is empty", func(t *testing.T) {
|
|
actual, err := adminClient.Create(ctx, &receiver, v1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{
|
|
Preconditions: &v1.Preconditions{
|
|
ResourceVersion: util.Pointer(actual.ResourceVersion),
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestIntegrationPatch(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
helper := getTestHelper(t)
|
|
|
|
adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin)
|
|
receiver := v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: "receiver",
|
|
Integrations: []v0alpha1.ReceiverIntegration{
|
|
createIntegration(t, "email"),
|
|
createIntegration(t, "webhook"),
|
|
createIntegration(t, "sns"),
|
|
},
|
|
},
|
|
}
|
|
|
|
current, err := adminClient.Create(ctx, &receiver, v1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, current)
|
|
|
|
t.Run("should patch with json patch", func(t *testing.T) {
|
|
current, err := adminClient.Get(ctx, current.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
|
|
index := slices.IndexFunc(current.Spec.Integrations, func(t v0alpha1.ReceiverIntegration) bool {
|
|
return t.Type == "webhook"
|
|
})
|
|
|
|
patch := []map[string]any{
|
|
{
|
|
"op": "remove",
|
|
"path": fmt.Sprintf("/spec/integrations/%d/settings/username", index),
|
|
},
|
|
{
|
|
"op": "remove",
|
|
"path": fmt.Sprintf("/spec/integrations/%d/secureFields/password", index),
|
|
},
|
|
{
|
|
"op": "replace",
|
|
"path": fmt.Sprintf("/spec/integrations/%d/settings/authorization_scheme", index),
|
|
"value": "bearer",
|
|
},
|
|
{
|
|
"op": "add",
|
|
"path": fmt.Sprintf("/spec/integrations/%d/settings/authorization_credentials", index),
|
|
"value": "authz-token",
|
|
},
|
|
{
|
|
"op": "remove",
|
|
"path": fmt.Sprintf("/spec/integrations/%d/secureFields/authorization_credentials", index),
|
|
},
|
|
}
|
|
|
|
expected := current.Spec.Integrations[index]
|
|
delete(expected.Settings, "username")
|
|
delete(expected.Settings, "password")
|
|
expected.Settings["authorization_scheme"] = "bearer"
|
|
delete(expected.SecureFields, "password")
|
|
expected.SecureFields["authorization_credentials"] = true
|
|
|
|
patchData, err := json.Marshal(patch)
|
|
require.NoError(t, err)
|
|
|
|
result, err := adminClient.Patch(ctx, current.Name, types.JSONPatchType, patchData, v1.PatchOptions{})
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, expected, result.Spec.Integrations[index])
|
|
|
|
// Use export endpoint because it's the only way to get decrypted secrets fast.
|
|
cliCfg := helper.Org1.Admin.NewRestConfig()
|
|
legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
|
|
|
|
export := legacyCli.ExportReceiverTyped(t, current.Spec.Title, true)
|
|
// we need special unmarshaler to parse settings
|
|
cp, err := api.ContactPointFromContactPointExport(export)
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, cp.Sns, 1)
|
|
assert.Len(t, cp.Email, 1)
|
|
require.Len(t, cp.Webhook, 1)
|
|
|
|
settings := cp.Webhook[0]
|
|
assert.EqualValues(t, "authz-token", *settings.AuthorizationCredentials)
|
|
assert.EqualValues(t, "bearer", *settings.AuthorizationScheme)
|
|
assert.Nil(t, settings.Password)
|
|
assert.Nil(t, settings.User)
|
|
})
|
|
}
|
|
|
|
func TestIntegrationReferentialIntegrity(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
helper := getTestHelper(t)
|
|
env := helper.GetEnv()
|
|
ac := acimpl.ProvideAccessControl(env.FeatureToggles)
|
|
db, err := store.ProvideDBStore(env.Cfg, env.FeatureToggles, env.SQLStore, &foldertest.FakeService{}, &dashboards.FakeDashboardService{}, ac, bus.ProvideBus(tracing.InitializeTracerForTest()))
|
|
require.NoError(t, err)
|
|
orgID := helper.Org1.Admin.Identity.GetOrgID()
|
|
|
|
cliCfg := helper.Org1.Admin.NewRestConfig()
|
|
legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
|
|
|
|
adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin)
|
|
// Prepare environment and create notification policy and rule that use time receiver
|
|
alertmanagerRaw, err := testData.ReadFile(path.Join("test-data", "notification-settings.json"))
|
|
require.NoError(t, err)
|
|
var amConfig definitions.PostableUserConfig
|
|
require.NoError(t, json.Unmarshal(alertmanagerRaw, &amConfig))
|
|
|
|
persistInitialConfig(t, amConfig)
|
|
|
|
postGroupRaw, err := testData.ReadFile(path.Join("test-data", "rulegroup-1.json"))
|
|
require.NoError(t, err)
|
|
var ruleGroup definitions.PostableRuleGroupConfig
|
|
require.NoError(t, json.Unmarshal(postGroupRaw, &ruleGroup))
|
|
|
|
folderUID := "test-folder"
|
|
legacyCli.CreateFolder(t, folderUID, "TEST")
|
|
_, status, data := legacyCli.PostRulesGroupWithStatus(t, folderUID, &ruleGroup, false)
|
|
require.Equalf(t, http.StatusAccepted, status, "Failed to post Rule: %s", data)
|
|
|
|
receivers, err := adminClient.List(ctx, v1.ListOptions{})
|
|
require.NoError(t, err)
|
|
require.Len(t, receivers.Items, 2)
|
|
idx := slices.IndexFunc(receivers.Items, func(interval v0alpha1.Receiver) bool {
|
|
return interval.Spec.Title == "user-defined"
|
|
})
|
|
receiver := receivers.Items[idx]
|
|
|
|
currentRoute := legacyCli.GetRoute(t)
|
|
currentRuleGroup, status := legacyCli.GetRulesGroup(t, folderUID, ruleGroup.Name)
|
|
require.Equal(t, http.StatusAccepted, status)
|
|
|
|
t.Run("Update", func(t *testing.T) {
|
|
t.Run("should rename all references if name changes", func(t *testing.T) {
|
|
renamed := receiver.Copy().(*v0alpha1.Receiver)
|
|
expectedTitle := renamed.Spec.Title + "-new"
|
|
renamed.Spec.Title = expectedTitle
|
|
|
|
actual, err := adminClient.Update(ctx, renamed, v1.UpdateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
updatedRuleGroup, status := legacyCli.GetRulesGroup(t, folderUID, ruleGroup.Name)
|
|
require.Equal(t, http.StatusAccepted, status)
|
|
for idx, rule := range updatedRuleGroup.Rules {
|
|
assert.Equalf(t, expectedTitle, rule.GrafanaManagedAlert.NotificationSettings.Receiver, "receiver in rule %d should have been renamed but it did not", idx)
|
|
}
|
|
|
|
updatedRoute := legacyCli.GetRoute(t)
|
|
for _, route := range updatedRoute.Routes {
|
|
assert.Equalf(t, expectedTitle, route.Receiver, "time receiver in routes should have been renamed but it did not")
|
|
}
|
|
|
|
actual, err = adminClient.Get(ctx, actual.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
|
|
receiver = *actual
|
|
})
|
|
|
|
t.Run("should fail if at least one resource is provisioned", func(t *testing.T) {
|
|
require.NoError(t, err)
|
|
renamed := receiver.Copy().(*v0alpha1.Receiver)
|
|
renamed.Spec.Title += util.GenerateShortUID()
|
|
|
|
t.Run("provisioned route", func(t *testing.T) {
|
|
require.NoError(t, db.SetProvenance(ctx, ¤tRoute, orgID, "API"))
|
|
t.Cleanup(func() {
|
|
require.NoError(t, db.DeleteProvenance(ctx, ¤tRoute, orgID))
|
|
})
|
|
actual, err := adminClient.Update(ctx, renamed, v1.UpdateOptions{})
|
|
require.Errorf(t, err, "Expected error but got successful result: %v", actual)
|
|
require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err)
|
|
})
|
|
|
|
t.Run("provisioned rules", func(t *testing.T) {
|
|
ruleUid := currentRuleGroup.Rules[0].GrafanaManagedAlert.UID
|
|
resource := &ngmodels.AlertRule{UID: ruleUid}
|
|
require.NoError(t, db.SetProvenance(ctx, resource, orgID, "API"))
|
|
t.Cleanup(func() {
|
|
require.NoError(t, db.DeleteProvenance(ctx, resource, orgID))
|
|
})
|
|
|
|
actual, err := adminClient.Update(ctx, renamed, v1.UpdateOptions{})
|
|
require.Errorf(t, err, "Expected error but got successful result: %v", actual)
|
|
require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err)
|
|
})
|
|
})
|
|
})
|
|
|
|
t.Run("Delete", func(t *testing.T) {
|
|
t.Run("should fail to delete if receiver is used in rule and routes", func(t *testing.T) {
|
|
err := adminClient.Delete(ctx, receiver.Name, v1.DeleteOptions{})
|
|
require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err)
|
|
})
|
|
|
|
t.Run("should fail to delete if receiver is used in only rule", func(t *testing.T) {
|
|
route := legacyCli.GetRoute(t)
|
|
route.Routes[0].Receiver = ""
|
|
legacyCli.UpdateRoute(t, route, true)
|
|
|
|
err = adminClient.Delete(ctx, receiver.Name, v1.DeleteOptions{})
|
|
require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestIntegrationCRUD(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
helper := getTestHelper(t)
|
|
|
|
adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin)
|
|
var defaultReceiver *v0alpha1.Receiver
|
|
t.Run("should list the default receiver", func(t *testing.T) {
|
|
items, err := adminClient.List(ctx, v1.ListOptions{})
|
|
require.NoError(t, err)
|
|
assert.Len(t, items.Items, 1)
|
|
defaultReceiver = &items.Items[0]
|
|
assert.Equal(t, "grafana-default-email", defaultReceiver.Spec.Title)
|
|
assert.NotEmpty(t, defaultReceiver.UID)
|
|
assert.NotEmpty(t, defaultReceiver.Name)
|
|
assert.NotEmpty(t, defaultReceiver.ResourceVersion)
|
|
|
|
defaultReceiver, err = adminClient.Get(ctx, defaultReceiver.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, defaultReceiver.UID)
|
|
assert.NotEmpty(t, defaultReceiver.Name)
|
|
assert.NotEmpty(t, defaultReceiver.ResourceVersion)
|
|
assert.Len(t, defaultReceiver.Spec.Integrations, 1)
|
|
})
|
|
|
|
t.Run("should be able to update default receiver", func(t *testing.T) {
|
|
require.NotNil(t, defaultReceiver)
|
|
newDefault := defaultReceiver.Copy().(*v0alpha1.Receiver)
|
|
newDefault.Spec.Integrations = append(newDefault.Spec.Integrations, createIntegration(t, "line"))
|
|
|
|
updatedReceiver, err := adminClient.Update(ctx, newDefault, v1.UpdateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
expected := newDefault.Copy().(*v0alpha1.Receiver)
|
|
expected.Spec.Integrations[0].Uid = updatedReceiver.Spec.Integrations[0].Uid // default integration does not have UID before first update
|
|
lineIntegration := expected.Spec.Integrations[1]
|
|
lineIntegration.SecureFields = map[string]bool{
|
|
"token": true,
|
|
}
|
|
delete(lineIntegration.Settings, "token")
|
|
assert.Equal(t, "LINE", updatedReceiver.Spec.Integrations[1].Type) // this type is in the schema but not in backend
|
|
lineIntegration.Type = "LINE"
|
|
lineIntegration.Uid = updatedReceiver.Spec.Integrations[1].Uid
|
|
expected.Spec.Integrations[1] = lineIntegration
|
|
|
|
assert.Equal(t, expected.Spec, updatedReceiver.Spec)
|
|
})
|
|
|
|
t.Run("should fail to create receiver with the existing name", func(t *testing.T) {
|
|
newReceiver := &v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: defaultReceiver.Spec.Title,
|
|
Integrations: []v0alpha1.ReceiverIntegration{},
|
|
},
|
|
}
|
|
_, err := adminClient.Create(ctx, newReceiver, v1.CreateOptions{})
|
|
require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err)
|
|
})
|
|
|
|
t.Run("should not let delete default receiver", func(t *testing.T) {
|
|
err := adminClient.Delete(ctx, defaultReceiver.Name, v1.DeleteOptions{})
|
|
require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err)
|
|
})
|
|
|
|
var receiver *v0alpha1.Receiver
|
|
t.Run("should correctly persist all known integrations", func(t *testing.T) {
|
|
integrations := make([]v0alpha1.ReceiverIntegration, 0, len(notify.AllKnownConfigsForTesting))
|
|
keysIter := maps.Keys(notify.AllKnownConfigsForTesting)
|
|
keys := slices.Collect(keysIter)
|
|
sort.Strings(keys)
|
|
for _, key := range keys {
|
|
integrations = append(integrations, createIntegration(t, key))
|
|
}
|
|
var err error
|
|
receiver, err = adminClient.Create(ctx, &v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: "all-receivers",
|
|
Integrations: integrations,
|
|
},
|
|
}, v1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
require.Len(t, receiver.Spec.Integrations, len(integrations))
|
|
|
|
// Set expected metadata
|
|
receiver.SetAccessControl("canWrite")
|
|
receiver.SetAccessControl("canDelete")
|
|
receiver.SetAccessControl("canReadSecrets")
|
|
receiver.SetAccessControl("canAdmin")
|
|
receiver.SetInUse(0, nil)
|
|
|
|
// Use export endpoint because it's the only way to get decrypted secrets fast.
|
|
cliCfg := helper.Org1.Admin.NewRestConfig()
|
|
legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
|
|
|
|
export := legacyCli.ExportReceiverTyped(t, receiver.Spec.Title, true)
|
|
for _, integration := range export.Receivers {
|
|
expected := notify.AllKnownConfigsForTesting[strings.ToLower(integration.Type)] // to lower because there is LINE that is in different casing in API
|
|
assert.JSONEqf(t, expected.Config, string(integration.Settings), "integration %s", integration.Type)
|
|
}
|
|
})
|
|
|
|
t.Run("should be able read what it is created", func(t *testing.T) {
|
|
get, err := adminClient.Get(ctx, receiver.Name, v1.GetOptions{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, receiver, get)
|
|
t.Run("should return secrets in secureFields but not settings", func(t *testing.T) {
|
|
for _, integration := range get.Spec.Integrations {
|
|
t.Run(integration.Type, func(t *testing.T) {
|
|
expected := notify.AllKnownConfigsForTesting[strings.ToLower(integration.Type)]
|
|
var fields map[string]any
|
|
require.NoError(t, json.Unmarshal([]byte(expected.Config), &fields))
|
|
secretFields, err := channels_config.GetSecretKeysForContactPointType(integration.Type)
|
|
require.NoError(t, err)
|
|
for _, field := range secretFields {
|
|
if _, ok := fields[field]; !ok { // skip field that is not in the original setting
|
|
continue
|
|
}
|
|
assert.Contains(t, integration.SecureFields, field)
|
|
assert.Truef(t, integration.SecureFields[field], "secure field should be always true")
|
|
|
|
value, ok, err := unstructured.NestedString(integration.Settings, strings.Split(field, ".")...)
|
|
assert.NoErrorf(t, err, "failed to read field %s from settings", field)
|
|
assert.Falsef(t, ok, "secret field %s should not be in settings, value [%s]", field, value)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
})
|
|
|
|
t.Run("should fail to persist receiver with invalid config", func(t *testing.T) {
|
|
keysIter := maps.Keys(notify.AllKnownConfigsForTesting)
|
|
keys := slices.Collect(keysIter)
|
|
sort.Strings(keys)
|
|
for _, key := range keys {
|
|
t.Run(key, func(t *testing.T) {
|
|
integration := createIntegration(t, key)
|
|
// Make the integration invalid, so it fails to create. This is usually done by sending empty settings.
|
|
clear(integration.Settings)
|
|
if key == "webex" {
|
|
// Webex integration is special case and passes validation without any settings so we instead set an invalid URL.
|
|
integration.Settings["api_url"] = "(*^$*^%!@#$*()"
|
|
}
|
|
|
|
receiver, err := adminClient.Create(ctx, &v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: fmt.Sprintf("invalid-%s", key),
|
|
Integrations: []v0alpha1.ReceiverIntegration{integration},
|
|
},
|
|
}, v1.CreateOptions{})
|
|
require.Errorf(t, err, "Expected error but got successful result: %v", receiver)
|
|
require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest, got: %s", err)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestIntegrationReceiverListSelector(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
helper := getTestHelper(t)
|
|
|
|
adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin)
|
|
recv1 := &v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: "test-receiver-1",
|
|
Integrations: []v0alpha1.ReceiverIntegration{
|
|
createIntegration(t, "email"),
|
|
},
|
|
},
|
|
}
|
|
recv1, err := adminClient.Create(ctx, recv1, v1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
recv2 := &v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: "test-receiver-2",
|
|
Integrations: []v0alpha1.ReceiverIntegration{
|
|
createIntegration(t, "email"),
|
|
},
|
|
},
|
|
}
|
|
recv2, err = adminClient.Create(ctx, recv2, v1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
env := helper.GetEnv()
|
|
ac := acimpl.ProvideAccessControl(env.FeatureToggles)
|
|
db, err := store.ProvideDBStore(env.Cfg, env.FeatureToggles, env.SQLStore, &foldertest.FakeService{}, &dashboards.FakeDashboardService{}, ac, bus.ProvideBus(tracing.InitializeTracerForTest()))
|
|
require.NoError(t, err)
|
|
require.NoError(t, db.SetProvenance(ctx, &definitions.EmbeddedContactPoint{
|
|
UID: *recv2.Spec.Integrations[0].Uid,
|
|
}, helper.Org1.Admin.Identity.GetOrgID(), "API"))
|
|
recv2, err = adminClient.Get(ctx, recv2.Name, v1.GetOptions{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
receivers, err := adminClient.List(ctx, v1.ListOptions{})
|
|
require.NoError(t, err)
|
|
require.Len(t, receivers.Items, 3) // Includes default.
|
|
|
|
t.Run("should filter by receiver name", func(t *testing.T) {
|
|
list, err := adminClient.List(ctx, v1.ListOptions{
|
|
FieldSelector: "spec.title=" + recv1.Spec.Title,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, list.Items, 1)
|
|
require.Equal(t, recv1.Name, list.Items[0].Name)
|
|
})
|
|
|
|
t.Run("should filter by metadata name", func(t *testing.T) {
|
|
list, err := adminClient.List(ctx, v1.ListOptions{
|
|
FieldSelector: "metadata.name=" + recv2.Name,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, list.Items, 1)
|
|
require.Equal(t, recv2.Name, list.Items[0].Name)
|
|
})
|
|
|
|
t.Run("should filter by multiple filters", func(t *testing.T) {
|
|
list, err := adminClient.List(ctx, v1.ListOptions{
|
|
FieldSelector: fmt.Sprintf("metadata.name=%s,spec.title=%s", recv2.Name, recv2.Spec.Title),
|
|
})
|
|
require.NoError(t, err)
|
|
require.Len(t, list.Items, 1)
|
|
require.Equal(t, recv2.Name, list.Items[0].Name)
|
|
})
|
|
|
|
t.Run("should be empty when filter does not match", func(t *testing.T) {
|
|
list, err := adminClient.List(ctx, v1.ListOptions{
|
|
FieldSelector: fmt.Sprintf("metadata.name=%s", "unknown"),
|
|
})
|
|
require.NoError(t, err)
|
|
require.Empty(t, list.Items)
|
|
})
|
|
}
|
|
|
|
// persistInitialConfig helps create an initial config with new receivers using legacy json. Config API blocks receiver
|
|
// modifications, so we need to use k8s API to create new receivers before posting the config.
|
|
func persistInitialConfig(t *testing.T, amConfig definitions.PostableUserConfig) {
|
|
ctx := context.Background()
|
|
|
|
helper := getTestHelper(t)
|
|
|
|
receiverClient := test_common.NewReceiverClient(t, helper.Org1.Admin)
|
|
for _, receiver := range amConfig.AlertmanagerConfig.Receivers {
|
|
if receiver.Name == "grafana-default-email" {
|
|
continue
|
|
}
|
|
|
|
toCreate := v0alpha1.Receiver{
|
|
ObjectMeta: v1.ObjectMeta{
|
|
Namespace: "default",
|
|
},
|
|
Spec: v0alpha1.ReceiverSpec{
|
|
Title: receiver.Name,
|
|
Integrations: []v0alpha1.ReceiverIntegration{},
|
|
},
|
|
}
|
|
|
|
for _, integration := range receiver.GrafanaManagedReceivers {
|
|
settings := common.Unstructured{}
|
|
require.NoError(t, settings.UnmarshalJSON(integration.Settings))
|
|
toCreate.Spec.Integrations = append(toCreate.Spec.Integrations, v0alpha1.ReceiverIntegration{
|
|
Settings: settings.Object,
|
|
Type: integration.Type,
|
|
DisableResolveMessage: util.Pointer(false),
|
|
})
|
|
}
|
|
|
|
created, err := receiverClient.Create(ctx, &toCreate, v1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
for i, integration := range created.Spec.Integrations {
|
|
receiver.GrafanaManagedReceivers[i].UID = *integration.Uid
|
|
}
|
|
}
|
|
|
|
nsMapper := func(_ int64) string { return "default" }
|
|
|
|
routeClient := test_common.NewRoutingTreeClient(t, helper.Org1.Admin)
|
|
v1route, err := routingtree.ConvertToK8sResource(helper.Org1.AdminServiceAccount.OrgId, *amConfig.AlertmanagerConfig.Route, "", nsMapper)
|
|
require.NoError(t, err)
|
|
_, err = routeClient.Update(ctx, v1route, v1.UpdateOptions{})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func createIntegration(t *testing.T, integrationType string) v0alpha1.ReceiverIntegration {
|
|
cfg, ok := notify.AllKnownConfigsForTesting[integrationType]
|
|
require.Truef(t, ok, "no known config for integration type %s", integrationType)
|
|
return createIntegrationWithSettings(t, integrationType, cfg.Config)
|
|
}
|
|
func createIntegrationWithSettings(t *testing.T, integrationType string, settingsJson string) v0alpha1.ReceiverIntegration {
|
|
settings := common.Unstructured{}
|
|
require.NoError(t, settings.UnmarshalJSON([]byte(settingsJson)))
|
|
return v0alpha1.ReceiverIntegration{
|
|
Settings: settings.Object,
|
|
Type: integrationType,
|
|
DisableResolveMessage: util.Pointer(false),
|
|
}
|
|
}
|
|
|
|
func createWildcardPermission(actions ...string) resourcepermissions.SetResourcePermissionCommand {
|
|
return resourcepermissions.SetResourcePermissionCommand{
|
|
Actions: actions,
|
|
Resource: "receivers",
|
|
ResourceAttribute: "uid",
|
|
ResourceID: "*",
|
|
}
|
|
}
|
|
|