Alerting: API to create extra Alertmanager configurations (#106904)

What is this feature?

Implements the POST endpoint for deleting imported Mimir Alertmanager configurations:

    POST /api/convert/api/v1/alerts

The API endpoint creates the extra Alertmanager configuration with the provided identifier and matchers.
This commit is contained in:
Alexander Akhmetov
2025-06-18 15:05:06 +02:00
committed by GitHub
parent 3ab54a5562
commit 426c334973
6 changed files with 625 additions and 4 deletions
@@ -128,6 +128,7 @@ type ConvertPrometheusSrv struct {
type Alertmanager interface {
DeleteExtraConfiguration(ctx context.Context, org int64, identifier string) error
SaveAndApplyExtraConfiguration(ctx context.Context, org int64, extraConfig apimodels.ExtraConfiguration) error
GetAlertmanagerConfiguration(ctx context.Context, org int64, withAutogen bool) (apimodels.GettableUserConfig, error)
}
@@ -532,7 +533,44 @@ func (srv *ConvertPrometheusSrv) convertToGrafanaRuleGroup(
}
func (srv *ConvertPrometheusSrv) RouteConvertPrometheusPostAlertmanagerConfig(c *contextmodel.ReqContext, amCfg apimodels.AlertmanagerUserConfig) response.Response {
return response.Error(http.StatusNotImplemented, "Not Implemented", nil)
if !srv.featureToggles.IsEnabledGlobally(featuremgmt.FlagAlertingImportAlertmanagerAPI) {
return response.Error(http.StatusNotImplemented, "Not Implemented", nil)
}
logger := srv.logger.FromContext(c.Req.Context())
identifier, err := parseConfigIdentifierHeader(c)
if err != nil {
logger.Error("Failed to parse config identifier header", "error", err, "identifier", identifier)
return errorToResponse(err)
}
mergeMatchers, err := parseMergeMatchersHeader(c)
if err != nil {
logger.Error("Failed to parse merge matchers header", "error", err, "identifier", identifier)
return errorToResponse(err)
}
ec := apimodels.ExtraConfiguration{
Identifier: identifier,
MergeMatchers: mergeMatchers,
TemplateFiles: amCfg.TemplateFiles,
AlertmanagerConfig: amCfg.AlertmanagerConfig,
}
err = ec.Validate()
if err != nil {
logger.Error("Invalid alertmanager configuration", "error", err, "identifier", identifier)
return errorToResponse(err)
}
err = srv.am.SaveAndApplyExtraConfiguration(c.Req.Context(), c.GetOrgID(), ec)
if err != nil {
logger.Error("Failed to save alertmanager configuration", "error", err, "identifier", identifier)
return errorToResponse(fmt.Errorf("failed to save alertmanager configuration: %w", err))
}
logger.Info("Successfully updated alertmanager configuration with imported Prometheus config", "identifier", identifier)
return successfulResponse()
}
func (srv *ConvertPrometheusSrv) RouteConvertPrometheusGetAlertmanagerConfig(c *contextmodel.ReqContext) response.Response {
@@ -1515,6 +1515,70 @@ func (m *mockAlertmanager) DeleteExtraConfiguration(ctx context.Context, org int
return args.Error(0)
}
func TestRouteConvertPrometheusPostAlertmanagerConfig(t *testing.T) {
const identifier = "test-config"
mockAM := &mockAlertmanager{}
ft := featuremgmt.WithFeatures(featuremgmt.FlagAlertingImportAlertmanagerAPI)
srv, _, _ := createConvertPrometheusSrv(t, withAlertmanager(mockAM), withFeatureToggles(ft))
t.Run("should parse headers and call SaveAndApplyExtraConfiguration", func(t *testing.T) {
mockAM.On("SaveAndApplyExtraConfiguration", mock.Anything, int64(1), mock.MatchedBy(func(extraConfig apimodels.ExtraConfiguration) bool {
return extraConfig.Identifier == identifier &&
len(extraConfig.MergeMatchers) == 2 &&
len(extraConfig.TemplateFiles) == 1 &&
extraConfig.TemplateFiles["test.tmpl"] == "{{ define \"test\" }}Hello{{ end }}"
})).Return(nil).Once()
rc := createRequestCtx()
rc.Req.Header.Set(configIdentifierHeader, identifier)
rc.Req.Header.Set(mergeMatchersHeader, "environment=production,team=backend")
amCfg := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: `{
"route": {
"receiver": "default"
},
"receivers": [
{
"name": "default"
}
]
}`,
TemplateFiles: map[string]string{
"test.tmpl": "{{ define \"test\" }}Hello{{ end }}",
},
}
response := srv.RouteConvertPrometheusPostAlertmanagerConfig(rc, amCfg)
require.Equal(t, http.StatusAccepted, response.Status())
mockAM.AssertExpectations(t)
})
t.Run("should return error when identifier header is missing", func(t *testing.T) {
rc := createRequestCtx()
amCfg := apimodels.AlertmanagerUserConfig{}
response := srv.RouteConvertPrometheusPostAlertmanagerConfig(rc, amCfg)
require.Equal(t, http.StatusBadRequest, response.Status())
require.Contains(t, string(response.Body()), "identifier cannot be empty")
})
t.Run("should return error when merge matchers header has invalid format", func(t *testing.T) {
rc := createRequestCtx()
rc.Req.Header.Set(configIdentifierHeader, identifier)
rc.Req.Header.Set(mergeMatchersHeader, "invalid-format")
amCfg := apimodels.AlertmanagerUserConfig{}
response := srv.RouteConvertPrometheusPostAlertmanagerConfig(rc, amCfg)
require.Equal(t, http.StatusBadRequest, response.Status())
require.Contains(t, string(response.Body()), "format should be 'key=value,key2=value2'")
})
}
func TestRouteConvertPrometheusGetAlertmanagerConfig(t *testing.T) {
const identifier = "test-config"
const orgID = int64(1)
@@ -17,6 +17,7 @@ import (
"github.com/grafana/alerting/definition"
alertingmodels "github.com/grafana/alerting/models"
"github.com/grafana/grafana/pkg/apimachinery/errutil"
)
// swagger:route POST /alertmanager/{DatasourceUID}/config/api/v1/alerts alertmanager RoutePostAlertingConfig
@@ -272,8 +273,18 @@ type (
const (
GrafanaReceiverType = definition.GrafanaReceiverType
AlertmanagerReceiverType = definition.AlertmanagerReceiverType
errInvalidExtraConfigurationMsg = "Invalid Alertmanager configuration: {{.Public.Error}}"
)
var (
errInvalidExtraConfigurationBase = errutil.ValidationFailed("alerting.invalidExtraConfiguration").MustTemplate(errInvalidExtraConfigurationMsg, errutil.WithPublic(errInvalidExtraConfigurationMsg))
)
func errInvalidExtraConfiguration(err error) error {
return errInvalidExtraConfigurationBase.Build(errutil.TemplateData{Public: map[string]any{"Error": err}})
}
var (
AsGrafanaRoute = definition.AsGrafanaRoute
AllReceivers = definition.AllReceivers
@@ -673,12 +684,12 @@ func (c ExtraConfiguration) Validate() error {
}
if len(c.MergeMatchers) == 0 {
return errors.New("at least one matcher is required")
return errInvalidExtraConfiguration(errors.New("at least one matcher is required"))
}
for _, m := range c.MergeMatchers {
if m.Type != labels.MatchEqual {
return errors.New("only matchers with type equal are supported")
return errInvalidExtraConfiguration(errors.New("only matchers with type equal are supported"))
}
}
@@ -686,7 +697,7 @@ func (c ExtraConfiguration) Validate() error {
am := config.Config{}
err := yaml.Unmarshal([]byte(c.AlertmanagerConfig), &am)
if err != nil {
return fmt.Errorf("invalid alertmanager configuration: %w", err)
return errInvalidExtraConfiguration(fmt.Errorf("failed to parse alertmanager config: %w", err))
}
return nil
@@ -2,6 +2,7 @@ package notifier
import (
"context"
"encoding/json"
"testing"
"time"
@@ -67,6 +68,75 @@ func TestAlertmanager_newAlertmanager(t *testing.T) {
require.False(t, am.Ready())
}
func TestAlertmanager_SaveAndApplyConfig_WithExternalSecrets(t *testing.T) {
am := setupAMTest(t)
cfg := &definitions.PostableUserConfig{
AlertmanagerConfig: definitions.PostableApiAlertingConfig{
Config: definitions.Config{
Route: &definitions.Route{
Receiver: "default-receiver",
},
},
Receivers: []*definitions.PostableApiReceiver{
{
Receiver: config.Receiver{Name: "default-receiver"},
},
},
},
ExtraConfigs: []definitions.ExtraConfiguration{
{
Identifier: "external-prometheus",
MergeMatchers: []*labels.Matcher{{Type: labels.MatchEqual, Name: "cluster", Value: "prod"}},
AlertmanagerConfig: `
route:
receiver: webhook-receiver
receivers:
- name: webhook-receiver
webhook_configs:
- url: 'https://webhook.example.com/alerts'
http_config:
basic_auth:
username: 'admin'
password: 'super-secret-password'
- url: 'https://slack.com/webhook/ABC123'
send_resolved: true
- name: email-receiver
email_configs:
- to: 'alerts@example.com'
from: 'grafana@example.com'
smarthost: 'smtp.gmail.com:587'
auth_username: 'grafana@example.com'
auth_password: 'another-secret-password'`,
},
},
}
err := am.SaveAndApplyConfig(context.Background(), cfg)
require.NoError(t, err)
savedConfig, err := am.Store.GetLatestAlertmanagerConfiguration(context.Background(), am.Base.TenantID())
require.NoError(t, err)
// Verify secrets are encrypted in stored config
var savedUserConfig definitions.PostableUserConfig
err = json.Unmarshal([]byte(savedConfig.AlertmanagerConfiguration), &savedUserConfig)
require.NoError(t, err)
require.Len(t, savedUserConfig.ExtraConfigs, 1)
extraConfig := savedUserConfig.ExtraConfigs[0]
require.Equal(t, "external-prometheus", extraConfig.Identifier)
require.NotContains(t, extraConfig.AlertmanagerConfig, "super-secret-password")
require.NotContains(t, extraConfig.AlertmanagerConfig, "another-secret-password")
require.NotContains(t, extraConfig.AlertmanagerConfig, "ABC123")
// Apply the saved configuration again and check that it is applied without errors
err = am.ApplyConfig(context.Background(), savedConfig)
require.NoError(t, err)
require.True(t, am.Ready())
}
func TestAlertmanager_ApplyConfig(t *testing.T) {
basicConfig := func() definitions.PostableApiAlertingConfig {
return definitions.PostableApiAlertingConfig{
@@ -0,0 +1,352 @@
package alerting
import (
"net/http"
"testing"
"github.com/stretchr/testify/require"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/tests/testinfra"
)
const testAlertmanagerConfigYAML = `
global:
smtp_smarthost: localhost:587
smtp_from: alertmanager@example.org
route:
group_by: ['alertname']
group_wait: 10s
group_interval: 10s
repeat_interval: 1h
receiver: web.hook
receivers:
- name: web.hook
webhook_configs:
- url: 'http://127.0.0.1:5001/'
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'dev', 'instance']
`
func TestIntegrationConvertPrometheusAlertmanagerEndpoints(t *testing.T) {
testinfra.SQLiteIntegrationTest(t)
// Setup Grafana with alerting import feature flag enabled
dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
DisableLegacyAlerting: true,
EnableUnifiedAlerting: true,
DisableAnonymous: true,
AppModeProduction: true,
EnableFeatureToggles: []string{
"alertingImportAlertmanagerAPI",
},
})
grafanaListedAddr, _ := testinfra.StartGrafanaEnv(t, dir, gpath)
apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "admin")
t.Run("create and get alertmanager configuration", func(t *testing.T) {
identifier := "test-create-get-config"
mergeMatchers := "environment=production,team=backend"
headers := map[string]string{
"Content-Type": "application/yaml",
"X-Grafana-Alerting-Config-Identifier": identifier,
"X-Grafana-Alerting-Merge-Matchers": mergeMatchers,
}
amConfig := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: testAlertmanagerConfigYAML,
TemplateFiles: map[string]string{
"test.tmpl": `{{ define "test.template" }}Test template{{ end }}`,
},
}
response := apiClient.ConvertPrometheusPostAlertmanagerConfig(t, amConfig, headers)
require.Equal(t, "success", response.Status)
getHeaders := map[string]string{
"X-Grafana-Alerting-Config-Identifier": identifier,
}
retrievedConfig := apiClient.ConvertPrometheusGetAlertmanagerConfig(t, getHeaders)
require.NotEmpty(t, retrievedConfig.AlertmanagerConfig)
require.Contains(t, retrievedConfig.TemplateFiles, "test.tmpl")
require.Equal(t, `{{ define "test.template" }}Test template{{ end }}`, retrievedConfig.TemplateFiles["test.tmpl"])
// Verify the configuration contains expected content
require.Contains(t, retrievedConfig.AlertmanagerConfig, "smtp_smarthost: localhost:587")
require.Contains(t, retrievedConfig.AlertmanagerConfig, "web.hook")
// Cleanup
deleteHeaders := map[string]string{
"X-Grafana-Alerting-Config-Identifier": identifier,
}
apiClient.ConvertPrometheusDeleteAlertmanagerConfig(t, deleteHeaders)
})
t.Run("delete alertmanager configuration", func(t *testing.T) {
identifier := "test-delete-config"
mergeMatchers := "environment=production,team=backend"
headers := map[string]string{
"Content-Type": "application/yaml",
"X-Grafana-Alerting-Config-Identifier": identifier,
"X-Grafana-Alerting-Merge-Matchers": mergeMatchers,
}
amConfig := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: testAlertmanagerConfigYAML,
TemplateFiles: map[string]string{
"test.tmpl": `{{ define "test.template" }}Test template{{ end }}`,
},
}
response := apiClient.ConvertPrometheusPostAlertmanagerConfig(t, amConfig, headers)
require.Equal(t, "success", response.Status)
deleteHeaders := map[string]string{
"X-Grafana-Alerting-Config-Identifier": identifier,
}
apiClient.ConvertPrometheusDeleteAlertmanagerConfig(t, deleteHeaders)
// Verify configuration is deleted by trying to get it again
getHeaders := map[string]string{
"X-Grafana-Alerting-Config-Identifier": identifier,
}
_, status, _ := apiClient.RawConvertPrometheusGetAlertmanagerConfig(t, getHeaders)
requireStatusCode(t, http.StatusNotFound, status, "")
})
t.Run("error cases", func(t *testing.T) {
t.Run("POST without config identifier header should fail", func(t *testing.T) {
headers := map[string]string{
"Content-Type": "application/yaml",
"X-Grafana-Alerting-Merge-Matchers": "environment=test",
}
amConfig := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: testAlertmanagerConfigYAML,
}
_, status, _ := apiClient.RawConvertPrometheusPostAlertmanagerConfig(t, amConfig, headers)
requireStatusCode(t, http.StatusBadRequest, status, "")
})
t.Run("POST without merge matchers header should fail", func(t *testing.T) {
headers := map[string]string{
"Content-Type": "application/yaml",
"X-Grafana-Alerting-Config-Identifier": "test-config",
}
amConfig := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: testAlertmanagerConfigYAML,
}
_, status, _ := apiClient.RawConvertPrometheusPostAlertmanagerConfig(t, amConfig, headers)
requireStatusCode(t, http.StatusBadRequest, status, "")
})
t.Run("POST with invalid merge matchers format should fail", func(t *testing.T) {
headers := map[string]string{
"Content-Type": "application/yaml",
"X-Grafana-Alerting-Config-Identifier": "test-invalid-matchers",
"X-Grafana-Alerting-Merge-Matchers": "invalid-no-equals-sign",
}
amConfig := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: testAlertmanagerConfigYAML,
}
_, status, _ := apiClient.RawConvertPrometheusPostAlertmanagerConfig(t, amConfig, headers)
requireStatusCode(t, http.StatusBadRequest, status, "")
})
t.Run("POST with invalid alertmanager configuration should fail", func(t *testing.T) {
headers := map[string]string{
"Content-Type": "application/yaml",
"X-Grafana-Alerting-Config-Identifier": "test-invalid-yaml",
"X-Grafana-Alerting-Merge-Matchers": "environment=test",
}
amConfig := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: `invalid yaml: [[[`,
}
_, status, _ := apiClient.RawConvertPrometheusPostAlertmanagerConfig(t, amConfig, headers)
requireStatusCode(t, http.StatusBadRequest, status, "")
})
t.Run("DELETE without config identifier header should fail", func(t *testing.T) {
headers := map[string]string{}
_, status, _ := apiClient.RawConvertPrometheusDeleteAlertmanagerConfig(t, headers)
requireStatusCode(t, http.StatusBadRequest, status, "")
})
})
t.Run("update existing configuration", func(t *testing.T) {
identifier := "test-update-config"
headers := map[string]string{
"Content-Type": "application/yaml",
"X-Grafana-Alerting-Config-Identifier": identifier,
"X-Grafana-Alerting-Merge-Matchers": "environment=production",
}
amConfig1 := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: testAlertmanagerConfigYAML,
TemplateFiles: map[string]string{
"config1.tmpl": `{{ define "config1.template" }}Config 1{{ end }}`,
},
}
response1 := apiClient.ConvertPrometheusPostAlertmanagerConfig(t, amConfig1, headers)
require.Equal(t, "success", response1.Status)
// Update the same configuration with new content
updatedConfigYAML := `
global:
smtp_smarthost: localhost:25
smtp_from: updated@example.org
route:
group_by: ['service']
group_wait: 5s
group_interval: 5s
repeat_interval: 30m
receiver: updated.hook
receivers:
- name: updated.hook
webhook_configs:
- url: 'http://127.0.0.1:8080/updated'
`
amConfig2 := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: updatedConfigYAML,
TemplateFiles: map[string]string{
"updated.tmpl": `{{ define "updated.template" }}Updated Config{{ end }}`,
},
}
response2 := apiClient.ConvertPrometheusPostAlertmanagerConfig(t, amConfig2, headers)
require.Equal(t, "success", response2.Status)
// Verify the updated configuration is retrieved
getHeaders := map[string]string{
"X-Grafana-Alerting-Config-Identifier": identifier,
}
retrievedConfig := apiClient.ConvertPrometheusGetAlertmanagerConfig(t, getHeaders)
require.NotEmpty(t, retrievedConfig.AlertmanagerConfig)
require.Contains(t, retrievedConfig.AlertmanagerConfig, "updated@example.org")
require.Contains(t, retrievedConfig.AlertmanagerConfig, "updated.hook")
require.Contains(t, retrievedConfig.TemplateFiles, "updated.tmpl")
require.Equal(t, `{{ define "updated.template" }}Updated Config{{ end }}`, retrievedConfig.TemplateFiles["updated.tmpl"])
deleteHeaders := map[string]string{
"X-Grafana-Alerting-Config-Identifier": identifier,
}
apiClient.ConvertPrometheusDeleteAlertmanagerConfig(t, deleteHeaders)
})
t.Run("multiple extra configurations conflict", func(t *testing.T) {
firstIdentifier := "first-config"
secondIdentifier := "second-config"
// Create first configuration
firstHeaders := map[string]string{
"Content-Type": "application/yaml",
"X-Grafana-Alerting-Config-Identifier": firstIdentifier,
"X-Grafana-Alerting-Merge-Matchers": "environment=first",
}
amConfig1 := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: testAlertmanagerConfigYAML,
TemplateFiles: map[string]string{
"first.tmpl": `{{ define "first.template" }}First Config{{ end }}`,
},
}
response1 := apiClient.ConvertPrometheusPostAlertmanagerConfig(t, amConfig1, firstHeaders)
require.Equal(t, "success", response1.Status)
// Try to create second configuration with different identifier,
// it should fail because we don't support this yet.
secondHeaders := map[string]string{
"Content-Type": "application/yaml",
"X-Grafana-Alerting-Config-Identifier": secondIdentifier,
"X-Grafana-Alerting-Merge-Matchers": "environment=second",
}
amConfig2 := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: `
global:
smtp_smarthost: localhost:25
route:
group_by: ['service']
receiver: second.hook
receivers:
- name: second.hook
webhook_configs:
- url: 'http://127.0.0.1:8080/second'
`,
TemplateFiles: map[string]string{
"second.tmpl": `{{ define "second.template" }}Second Config{{ end }}`,
},
}
_, status, body := apiClient.RawConvertPrometheusPostAlertmanagerConfig(t, amConfig2, secondHeaders)
requireStatusCode(t, http.StatusConflict, status, "")
require.Contains(t, body, "multiple extra configurations are not supported")
require.Contains(t, body, firstIdentifier)
})
}
func TestIntegrationConvertPrometheusAlertmanagerEndpoints_FeatureFlagDisabled(t *testing.T) {
testinfra.SQLiteIntegrationTest(t)
dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
DisableLegacyAlerting: true,
EnableUnifiedAlerting: true,
DisableAnonymous: true,
AppModeProduction: true,
})
grafanaListedAddr, _ := testinfra.StartGrafanaEnv(t, dir, gpath)
apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "admin")
headers := map[string]string{
"Content-Type": "application/yaml",
"X-Grafana-Alerting-Config-Identifier": "test-config",
"X-Grafana-Alerting-Merge-Matchers": "environment=test",
}
t.Run("POST should return not implemented when feature flag disabled", func(t *testing.T) {
amConfig := apimodels.AlertmanagerUserConfig{
AlertmanagerConfig: testAlertmanagerConfigYAML,
}
_, status, _ := apiClient.RawConvertPrometheusPostAlertmanagerConfig(t, amConfig, headers)
requireStatusCode(t, http.StatusNotImplemented, status, "")
})
t.Run("GET should return not implemented when feature flag disabled", func(t *testing.T) {
_, status, _ := apiClient.RawConvertPrometheusGetAlertmanagerConfig(t, headers)
requireStatusCode(t, http.StatusNotImplemented, status, "")
})
t.Run("DELETE should return not implemented when feature flag disabled", func(t *testing.T) {
_, status, _ := apiClient.RawConvertPrometheusDeleteAlertmanagerConfig(t, headers)
requireStatusCode(t, http.StatusNotImplemented, status, "")
})
}
+86
View File
@@ -1262,6 +1262,92 @@ func (a apiClient) ConvertPrometheusDeleteNamespace(t *testing.T, namespaceTitle
requireStatusCode(t, http.StatusAccepted, status, raw)
}
func (a apiClient) ConvertPrometheusPostAlertmanagerConfig(t *testing.T, amCfg apimodels.AlertmanagerUserConfig, headers map[string]string) apimodels.ConvertPrometheusResponse {
t.Helper()
resp, status, body := a.RawConvertPrometheusPostAlertmanagerConfig(t, amCfg, headers)
requireStatusCode(t, http.StatusAccepted, status, body)
return resp
}
func (a apiClient) RawConvertPrometheusPostAlertmanagerConfig(t *testing.T, amCfg apimodels.AlertmanagerUserConfig, headers map[string]string) (apimodels.ConvertPrometheusResponse, int, string) {
t.Helper()
path := "%s/api/convert/api/v1/alerts"
// Based on the content-type header, marshal the data to JSON or YAML
contentType := headers["Content-Type"]
var data []byte
var err error
if contentType == "application/json" {
data, err = json.Marshal(amCfg)
require.NoError(t, err)
} else {
data, err = yaml.Marshal(amCfg)
require.NoError(t, err)
}
buf := bytes.NewReader(data)
req, err := http.NewRequest(http.MethodPost, fmt.Sprintf(path, a.url), buf)
require.NoError(t, err)
for key, value := range headers {
req.Header.Set(key, value)
}
return sendRequestJSON[apimodels.ConvertPrometheusResponse](t, req, http.StatusAccepted)
}
func (a apiClient) ConvertPrometheusGetAlertmanagerConfig(t *testing.T, headers map[string]string) apimodels.AlertmanagerUserConfig {
t.Helper()
config, status, raw := a.RawConvertPrometheusGetAlertmanagerConfig(t, headers)
requireStatusCode(t, http.StatusOK, status, raw)
return config
}
func (a apiClient) RawConvertPrometheusGetAlertmanagerConfig(t *testing.T, headers map[string]string) (apimodels.AlertmanagerUserConfig, int, string) {
t.Helper()
path := "%s/api/convert/api/v1/alerts"
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf(path, a.url), nil)
require.NoError(t, err)
for key, value := range headers {
req.Header.Set(key, value)
}
config, status, raw := sendRequestYAML[apimodels.AlertmanagerUserConfig](t, req, http.StatusOK)
return config, status, raw
}
func (a apiClient) ConvertPrometheusDeleteAlertmanagerConfig(t *testing.T, headers map[string]string) {
t.Helper()
_, status, raw := a.RawConvertPrometheusDeleteAlertmanagerConfig(t, headers)
requireStatusCode(t, http.StatusAccepted, status, raw)
}
func (a apiClient) RawConvertPrometheusDeleteAlertmanagerConfig(t *testing.T, headers map[string]string) (apimodels.ConvertPrometheusResponse, int, string) {
t.Helper()
path := "%s/api/convert/api/v1/alerts"
req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf(path, a.url), nil)
require.NoError(t, err)
for key, value := range headers {
req.Header.Set(key, value)
}
return sendRequestJSON[apimodels.ConvertPrometheusResponse](t, req, http.StatusAccepted)
}
func (a apiClient) RawConvertPrometheusDeleteNamespace(t *testing.T, namespaceTitle string, headers map[string]string) (apimodels.ConvertPrometheusResponse, int, string) {
t.Helper()