Alerting: Reject receiver update in config API when FlagAlertingApiServer enabled (#93300)

* Reject receiver update in config API when FlagAlertingApiServer enabled
This commit is contained in:
Matthew Jacobson
2024-09-17 16:49:17 +03:00
committed by GitHub
parent cbf2aa993e
commit 1ea873950b
7 changed files with 149 additions and 32 deletions
@@ -24,6 +24,7 @@ import (
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1"
"github.com/grafana/grafana/pkg/generated/clientset/versioned"
notificationsv0alpha1 "github.com/grafana/grafana/pkg/generated/clientset/versioned/typed/alerting_notifications/v0alpha1"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
@@ -426,6 +427,10 @@ func TestIntegrationInUseMetadata(t *testing.T) {
cliCfg := helper.Org1.Admin.NewRestConfig()
legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
adminK8sClient, err := versioned.NewForConfig(cliCfg)
require.NoError(t, err)
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
// 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)
@@ -440,8 +445,7 @@ func TestIntegrationInUseMetadata(t *testing.T) {
parentRoute.Routes = []*definitions.Route{&route1, &route2}
amConfig.AlertmanagerConfig.Route.Routes = append(amConfig.AlertmanagerConfig.Route.Routes, &parentRoute)
success, err := legacyCli.PostConfiguration(t, amConfig)
require.Truef(t, success, "Failed to post Alertmanager configuration: %s", err)
persistInitialConfig(t, amConfig, adminClient, legacyCli)
postGroupRaw, err := testData.ReadFile(path.Join("test-data", "rulegroup-1.json"))
require.NoError(t, err)
@@ -471,10 +475,6 @@ func TestIntegrationInUseMetadata(t *testing.T) {
_, status, data := legacyCli.PostRulesGroupWithStatus(t, folderUID, &ruleGroup)
require.Equalf(t, http.StatusAccepted, status, "Failed to post Rule: %s", data)
adminK8sClient, err := versioned.NewForConfig(cliCfg)
require.NoError(t, err)
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
requestReceivers := func(t *testing.T, title string) (v0alpha1.Receiver, v0alpha1.Receiver) {
t.Helper()
receivers, err := adminClient.List(ctx, v1.ListOptions{})
@@ -508,7 +508,7 @@ func TestIntegrationInUseMetadata(t *testing.T) {
// Removing the new extra route should leave only 1.
amConfig.AlertmanagerConfig.Route.Routes = amConfig.AlertmanagerConfig.Route.Routes[:1]
success, err = legacyCli.PostConfiguration(t, amConfig)
success, err := legacyCli.PostConfiguration(t, amConfig)
require.Truef(t, success, "Failed to post Alertmanager configuration: %s", err)
receiverListed, receiverGet = requestReceivers(t, "user-defined")
@@ -786,6 +786,26 @@ func TestIntegrationPatch(t *testing.T) {
})
}
func TestIntegrationRejectConfigApiReceiverModification(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
helper := getTestHelper(t)
cliCfg := helper.Org1.Admin.NewRestConfig()
legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
// This config has new and modified receivers.
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))
success, err := legacyCli.PostConfiguration(t, amConfig)
require.Falsef(t, success, "Expected receiver modification to be rejected, but got %s", err)
}
func TestIntegrationReferentialIntegrity(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
@@ -802,14 +822,17 @@ func TestIntegrationReferentialIntegrity(t *testing.T) {
cliCfg := helper.Org1.Admin.NewRestConfig()
legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
adminK8sClient, err := versioned.NewForConfig(cliCfg)
require.NoError(t, err)
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
// 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))
success, err := legacyCli.PostConfiguration(t, amConfig)
require.Truef(t, success, "Failed to post Alertmanager configuration: %s", err)
persistInitialConfig(t, amConfig, adminClient, legacyCli)
postGroupRaw, err := testData.ReadFile(path.Join("test-data", "rulegroup-1.json"))
require.NoError(t, err)
@@ -821,10 +844,6 @@ func TestIntegrationReferentialIntegrity(t *testing.T) {
_, status, data := legacyCli.PostRulesGroupWithStatus(t, folderUID, &ruleGroup)
require.Equalf(t, http.StatusAccepted, status, "Failed to post Rule: %s", data)
adminK8sClient, err := versioned.NewForConfig(cliCfg)
require.NoError(t, err)
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
receivers, err := adminClient.List(ctx, v1.ListOptions{})
require.NoError(t, err)
require.Len(t, receivers.Items, 2)
@@ -1171,14 +1190,72 @@ func TestIntegrationReceiverListSelector(t *testing.T) {
})
}
// 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, adminClient notificationsv0alpha1.ReceiverInterface, legacyCli alerting.LegacyApiClient) {
ctx := context.Background()
var defaultReceiver *definitions.PostableApiReceiver
for _, receiver := range amConfig.AlertmanagerConfig.Receivers {
if receiver.Name == "grafana-default-email" {
defaultReceiver = receiver
continue
}
toCreate := v0alpha1.Receiver{
ObjectMeta: v1.ObjectMeta{
Namespace: "default",
},
Spec: v0alpha1.ReceiverSpec{
Title: receiver.Name,
Integrations: []v0alpha1.Integration{},
},
}
for _, integration := range receiver.GrafanaManagedReceivers {
settings := common.Unstructured{}
require.NoError(t, settings.UnmarshalJSON(integration.Settings))
toCreate.Spec.Integrations = append(toCreate.Spec.Integrations, v0alpha1.Integration{
Settings: settings,
Type: integration.Type,
DisableResolveMessage: util.Pointer(false),
})
}
created, err := adminClient.Create(ctx, &toCreate, v1.CreateOptions{})
require.NoError(t, err)
for i, integration := range created.Spec.Integrations {
receiver.GrafanaManagedReceivers[i].UID = *integration.Uid
}
}
success, err := legacyCli.PostConfiguration(t, amConfig)
require.Truef(t, success, "Failed to post Alertmanager configuration: %s", err)
gettable, status, body := legacyCli.GetAlertmanagerConfigWithStatus(t)
require.Equalf(t, http.StatusOK, status, body)
idx := slices.IndexFunc(gettable.AlertmanagerConfig.Receivers, func(recv *definitions.GettableApiReceiver) bool {
return recv.Name == "grafana-default-email"
})
gettableDefault := gettable.AlertmanagerConfig.Receivers[idx]
// Assign uid of default receiver as well.
defaultReceiver.GrafanaManagedReceivers[0].UID = gettableDefault.GrafanaManagedReceivers[0].UID
}
func createIntegration(t *testing.T, integrationType string) v0alpha1.Integration {
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.Integration {
settings := common.Unstructured{}
require.NoError(t, settings.UnmarshalJSON([]byte(cfg.Config)))
require.NoError(t, settings.UnmarshalJSON([]byte(settingsJson)))
return v0alpha1.Integration{
Settings: settings,
Type: cfg.NotifierType,
Type: integrationType,
DisableResolveMessage: util.Pointer(false),
}
}
@@ -23,8 +23,9 @@
"grafana_managed_receiver_configs": [
{
"type": "email",
"name": "email receiver",
"settings": {
"addresses": "example@email.com"
"addresses": "<example@email.com>"
}
}
]
@@ -34,6 +35,7 @@
"grafana_managed_receiver_configs": [
{
"type": "email",
"name": "user-defined",
"settings": {
"addresses": "example@email.com"
}
@@ -42,4 +44,4 @@
}
]
}
}
}
@@ -45,6 +45,7 @@
"grafana_managed_receiver_configs": [
{
"type": "email",
"name": "email receiver",
"settings": {
"addresses": "<example@email.com>"
}
@@ -53,4 +54,4 @@
}
]
}
}
}