Alerting: Remove the POST endpoint for the internal Grafana Alertmanager config (#103819)
* Remove POST config for Grafana Alertmanager * Delete auth + test for removed path * Alerting: Remove check for `alertingApiServer` toggle in UI (#103805) * Remove check for alertingApiServer in UI * Update tests to no longer care about alertingApiServer * Add contact points handlers now that we use alertingApiServer all the time * Fix test broken from removing camelCase for UIDs --------- Co-authored-by: Tom Ratcliffe <tom.ratcliffe@grafana.com>
This commit is contained in:
co-authored by
Tom Ratcliffe
parent
c47ab101d1
commit
a5288db624
@@ -429,20 +429,14 @@ func (s *ServiceImpl) buildAlertNavLinks(c *contextmodel.ReqContext) *navtree.Na
|
||||
contactPointsPerms := []ac.Evaluator{
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsRead),
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsExternalRead),
|
||||
}
|
||||
|
||||
// With the new alerting API, we have other permissions to consider. We don't want to consider these with the old
|
||||
// alerting API to maintain backwards compatibility.
|
||||
if s.features.IsEnabled(c.Req.Context(), featuremgmt.FlagAlertingApiServer) {
|
||||
contactPointsPerms = append(contactPointsPerms,
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversRead),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversReadSecrets),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversCreate),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversRead),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversReadSecrets),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversCreate),
|
||||
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsTemplatesRead),
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsTemplatesWrite),
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsTemplatesDelete),
|
||||
)
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsTemplatesRead),
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsTemplatesWrite),
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsTemplatesDelete),
|
||||
}
|
||||
|
||||
if hasAccess(ac.EvalAny(contactPointsPerms...)) {
|
||||
|
||||
@@ -381,10 +381,9 @@ func DeclareFixedRoles(service accesscontrol.Service, features featuremgmt.Featu
|
||||
instancesReaderRole, instancesWriterRole,
|
||||
notificationsReaderRole, notificationsWriterRole,
|
||||
alertingReaderRole, alertingWriterRole, alertingAdminRole, alertingProvisionerRole, alertingProvisioningReaderWithSecretsRole, alertingProvisioningStatus,
|
||||
}
|
||||
|
||||
if features.IsEnabledGlobally(featuremgmt.FlagAlertingApiServer) {
|
||||
fixedRoles = append(fixedRoles, receiversReaderRole, receiversCreatorRole, receiversWriterRole, templatesReaderRole, templatesWriterRole, timeIntervalsReaderRole, timeIntervalsWriterRole, routesReaderRole, routesWriterRole)
|
||||
// k8s roles
|
||||
receiversReaderRole, receiversCreatorRole, receiversWriterRole, templatesReaderRole, templatesWriterRole,
|
||||
timeIntervalsReaderRole, timeIntervalsWriterRole, routesReaderRole, routesWriterRole,
|
||||
}
|
||||
|
||||
return service.DeclareFixedRoles(fixedRoles...)
|
||||
|
||||
@@ -188,52 +188,6 @@ func (srv AlertmanagerSrv) RoutePostGrafanaAlertingConfigHistoryActivate(c *cont
|
||||
return response.JSON(http.StatusAccepted, util.DynMap{"message": "configuration activated"})
|
||||
}
|
||||
|
||||
func (srv AlertmanagerSrv) RoutePostAlertingConfig(c *contextmodel.ReqContext, body apimodels.PostableUserConfig) response.Response {
|
||||
// Remove autogenerated config from the user config before checking provenance guard and eventually saving it.
|
||||
// TODO: This and provenance guard should be moved to the notifier package.
|
||||
notifier.RemoveAutogenConfigIfExists(body.AlertmanagerConfig.Route)
|
||||
currentConfig, err := srv.mam.GetAlertmanagerConfiguration(c.Req.Context(), c.GetOrgID(), false)
|
||||
// If a config is present and valid we proceed with the guard, otherwise we
|
||||
// just bypass the guard which is okay as we are anyway in an invalid state.
|
||||
if err == nil {
|
||||
if err := srv.provenanceGuard(currentConfig, body); err != nil {
|
||||
return ErrResp(http.StatusBadRequest, err, "")
|
||||
}
|
||||
}
|
||||
if srv.featureManager.IsEnabled(c.Req.Context(), featuremgmt.FlagAlertingApiServer) {
|
||||
if err != nil {
|
||||
// Unclear if returning an error here is the right thing to do, preventing the user from posting a new config
|
||||
// when the current one is legitimately invalid is not optimal, but we need to ensure receiver
|
||||
// permissions are maintained and prevent potential access control bypasses. The workaround is to use the
|
||||
// various new k8s API endpoints to fix the configuration.
|
||||
return ErrResp(http.StatusInternalServerError, err, "")
|
||||
}
|
||||
if err := srv.k8sApiServiceGuard(currentConfig, body); err != nil {
|
||||
return ErrResp(http.StatusBadRequest, err, "")
|
||||
}
|
||||
}
|
||||
err = srv.mam.SaveAndApplyAlertmanagerConfiguration(c.Req.Context(), c.GetOrgID(), body)
|
||||
if err == nil {
|
||||
return response.JSON(http.StatusAccepted, util.DynMap{"message": "configuration created"})
|
||||
}
|
||||
var unknownReceiverError notifier.UnknownReceiverError
|
||||
if errors.As(err, &unknownReceiverError) {
|
||||
return ErrResp(http.StatusBadRequest, unknownReceiverError, "")
|
||||
}
|
||||
var configRejectedError notifier.AlertmanagerConfigRejectedError
|
||||
if errors.As(err, &configRejectedError) {
|
||||
return ErrResp(http.StatusBadRequest, configRejectedError, "")
|
||||
}
|
||||
if errors.Is(err, notifier.ErrNoAlertmanagerForOrg) {
|
||||
return response.Error(http.StatusNotFound, err.Error(), err)
|
||||
}
|
||||
if errors.Is(err, notifier.ErrAlertmanagerNotReady) {
|
||||
return response.Error(http.StatusConflict, err.Error(), err)
|
||||
}
|
||||
|
||||
return response.ErrOrFallback(http.StatusInternalServerError, err.Error(), err)
|
||||
}
|
||||
|
||||
func (srv AlertmanagerSrv) RouteGetReceivers(c *contextmodel.ReqContext) response.Response {
|
||||
am, errResp := srv.AlertmanagerFor(c.GetOrgID())
|
||||
if errResp != nil {
|
||||
|
||||
@@ -16,46 +16,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/util/cmputil"
|
||||
)
|
||||
|
||||
func (srv AlertmanagerSrv) provenanceGuard(currentConfig apimodels.GettableUserConfig, newConfig apimodels.PostableUserConfig) error {
|
||||
if err := checkRoutes(currentConfig, newConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkTemplates(currentConfig, newConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkContactPoints(currentConfig.AlertmanagerConfig.Receivers, newConfig.AlertmanagerConfig.Receivers); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkMuteTimes(currentConfig, newConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (srv AlertmanagerSrv) k8sApiServiceGuard(currentConfig apimodels.GettableUserConfig, newConfig apimodels.PostableUserConfig) error {
|
||||
// Modifications to receivers via this API is tricky with new per-receiver RBAC. Assuming we restrict the API to only
|
||||
// those users with global edit permissions, we would still need to consider the following:
|
||||
// - Since the UIDs stored in the database for the purposes of per-receiver RBAC are generated based on the receiver
|
||||
// name, we would need to ensure continuity of permissions when a receiver is renamed. This would, preferably,
|
||||
// require detecting renames and updating the permissions UID in the database.
|
||||
// - Editors don't have permission to manage all receiver permissions by default, only admin users do. This means that
|
||||
// certain combined operations (e.g. swapping the name of receivers) would require careful handling to ensure
|
||||
// that the correct permissions are maintained, and considering receivers don't have a unique identifier outside
|
||||
// their name, this is non-trivial.
|
||||
|
||||
// Neither of these are insurmountable, but considering this endpoint will be removed once FlagAlertingApiServer
|
||||
// becomes GA, the complexity may not be worthwhile. To that end, for now we reject any request that attempts to
|
||||
// update receivers, while allowing operations that add or remove receivers.
|
||||
delta, err := calculateReceiversDelta(currentConfig.AlertmanagerConfig.Receivers, newConfig.AlertmanagerConfig.Receivers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(delta.Updated) > 0 {
|
||||
return fmt.Errorf("cannot update receivers using this API while per-receiver RBAC is enabled; either disable the `alertingApiServer` feature flag or use an API that supports per-receiver RBAC (e.g. provisioning or receivers API)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkRoutes(currentConfig apimodels.GettableUserConfig, newConfig apimodels.PostableUserConfig) error {
|
||||
reporter := cmputil.DiffReporter{}
|
||||
options := []cmp.Option{cmp.Reporter(&reporter), cmpopts.EquateEmpty(), cmpopts.IgnoreUnexported(labels.Matcher{}), cmp.Transformer("", func(regexp amConfig.Regexp) any {
|
||||
|
||||
@@ -2,7 +2,6 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
@@ -101,90 +100,6 @@ func TestContextWithTimeoutFromRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAlertmanagerConfig(t *testing.T) {
|
||||
sut := createSut(t)
|
||||
|
||||
t.Run("assert 404 Not Found when applying config to nonexistent org", func(t *testing.T) {
|
||||
rc := contextmodel.ReqContext{
|
||||
Context: &web.Context{
|
||||
Req: &http.Request{},
|
||||
},
|
||||
SignedInUser: &user.SignedInUser{
|
||||
OrgID: 12,
|
||||
},
|
||||
}
|
||||
request := createAmConfigRequest(t, validConfig)
|
||||
|
||||
response := sut.RoutePostAlertingConfig(&rc, request)
|
||||
|
||||
require.Equal(t, 404, response.Status())
|
||||
require.Contains(t, string(response.Body()), "Alertmanager does not exist for this organization")
|
||||
})
|
||||
|
||||
t.Run("assert 202 when config successfully applied", func(t *testing.T) {
|
||||
rc := contextmodel.ReqContext{
|
||||
Context: &web.Context{
|
||||
Req: &http.Request{},
|
||||
},
|
||||
SignedInUser: &user.SignedInUser{
|
||||
OrgID: 1,
|
||||
},
|
||||
}
|
||||
request := createAmConfigRequest(t, validConfig)
|
||||
|
||||
response := sut.RoutePostAlertingConfig(&rc, request)
|
||||
|
||||
require.Equal(t, 202, response.Status())
|
||||
})
|
||||
|
||||
t.Run("assert 202 when alertmanager to configure is not ready", func(t *testing.T) {
|
||||
sut := createSut(t)
|
||||
rc := contextmodel.ReqContext{
|
||||
Context: &web.Context{
|
||||
Req: &http.Request{},
|
||||
},
|
||||
SignedInUser: &user.SignedInUser{
|
||||
OrgID: 3, // Org 3 was initialized with broken config.
|
||||
},
|
||||
}
|
||||
request := createAmConfigRequest(t, validConfig)
|
||||
|
||||
response := sut.RoutePostAlertingConfig(&rc, request)
|
||||
|
||||
require.Equal(t, 202, response.Status())
|
||||
})
|
||||
|
||||
t.Run("assert config hash doesn't change when sending RouteGetAlertingConfig back to RoutePostAlertingConfig", func(t *testing.T) {
|
||||
rc := contextmodel.ReqContext{
|
||||
Context: &web.Context{
|
||||
Req: &http.Request{},
|
||||
},
|
||||
SignedInUser: &user.SignedInUser{
|
||||
OrgID: 1,
|
||||
},
|
||||
}
|
||||
request := createAmConfigRequest(t, validConfigWithSecureSetting)
|
||||
|
||||
r := sut.RoutePostAlertingConfig(&rc, request)
|
||||
require.Equal(t, 202, r.Status())
|
||||
|
||||
getResponse := sut.RouteGetAlertingConfig(&rc)
|
||||
require.Equal(t, 200, getResponse.Status())
|
||||
|
||||
body := getResponse.Body()
|
||||
hash := md5.Sum(body)
|
||||
postable, err := notifier.Load(body)
|
||||
require.NoError(t, err)
|
||||
|
||||
r = sut.RoutePostAlertingConfig(&rc, *postable)
|
||||
require.Equal(t, 202, r.Status())
|
||||
|
||||
getResponse = sut.RouteGetAlertingConfig(&rc)
|
||||
require.Equal(t, 200, getResponse.Status())
|
||||
|
||||
newHash := md5.Sum(getResponse.Body())
|
||||
require.Equal(t, hash, newHash)
|
||||
})
|
||||
|
||||
t.Run("when objects are not provisioned", func(t *testing.T) {
|
||||
t.Run("route from GET config has no provenance", func(t *testing.T) {
|
||||
sut := createSut(t)
|
||||
@@ -229,9 +144,8 @@ func TestAlertmanagerConfig(t *testing.T) {
|
||||
t.Run("contact point from GET config has expected provenance", func(t *testing.T) {
|
||||
sut := createSut(t)
|
||||
rc := createRequestCtxInOrg(1)
|
||||
request := createAmConfigRequest(t, validConfig)
|
||||
|
||||
_ = sut.RoutePostAlertingConfig(rc, request)
|
||||
RoutePostAlertingConfig(t, sut.mam, rc, validConfig)
|
||||
|
||||
response := sut.RouteGetAlertingConfig(rc)
|
||||
body := asGettableUserConfig(t, response)
|
||||
@@ -347,11 +261,8 @@ func TestGetAlertmanagerConfiguration_NewSecretField(t *testing.T) {
|
||||
}
|
||||
}
|
||||
`
|
||||
postable := createAmConfigRequest(t, postWithoutChanges)
|
||||
|
||||
res = sut.RoutePostAlertingConfig(rc, postable)
|
||||
require.Equal(t, 202, res.Status())
|
||||
|
||||
RoutePostAlertingConfig(t, sut.mam, rc, postWithoutChanges)
|
||||
// Check that the secret field "integrationKey" is now encrypted in SecureSettings.
|
||||
savedConfig := &apimodels.PostableUserConfig{}
|
||||
err = json.Unmarshal([]byte(configs[orgId].AlertmanagerConfiguration), savedConfig)
|
||||
@@ -400,31 +311,6 @@ func TestAlertmanagerAutogenConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("route POST config", func(t *testing.T) {
|
||||
t.Run("does not save autogen routes", func(t *testing.T) {
|
||||
sut, configs := createSutForAutogen(t)
|
||||
rc := createRequestCtxInOrg(1)
|
||||
request := createAmConfigRequest(t, validConfigWithAutogen)
|
||||
response := sut.RoutePostAlertingConfig(rc, request)
|
||||
require.Equal(t, 202, response.Status())
|
||||
|
||||
compare(t, validConfigWithoutAutogen, configs[1].AlertmanagerConfiguration)
|
||||
})
|
||||
|
||||
t.Run("provenance guard ignores autogen routes", func(t *testing.T) {
|
||||
sut := createSut(t)
|
||||
rc := createRequestCtxInOrg(1)
|
||||
request := createAmConfigRequest(t, validConfigWithoutAutogen)
|
||||
_ = sut.RoutePostAlertingConfig(rc, request)
|
||||
|
||||
setRouteProvenance(t, 1, sut.mam.ProvStore)
|
||||
request = createAmConfigRequest(t, validConfigWithAutogen)
|
||||
request.AlertmanagerConfig.Route.Provenance = apimodels.Provenance(ngmodels.ProvenanceAPI)
|
||||
response := sut.RoutePostAlertingConfig(rc, request)
|
||||
require.Equal(t, 202, response.Status())
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("route GET config", func(t *testing.T) {
|
||||
t.Run("when admin return autogen routes", func(t *testing.T) {
|
||||
sut, _ := createSutForAutogen(t)
|
||||
@@ -691,16 +577,6 @@ func createSut(t *testing.T) AlertmanagerSrv {
|
||||
}
|
||||
}
|
||||
|
||||
func createAmConfigRequest(t *testing.T, config string) apimodels.PostableUserConfig {
|
||||
t.Helper()
|
||||
|
||||
request := apimodels.PostableUserConfig{}
|
||||
err := request.UnmarshalJSON([]byte(config))
|
||||
require.NoError(t, err)
|
||||
|
||||
return request
|
||||
}
|
||||
|
||||
func createMultiOrgAlertmanager(t *testing.T, configs map[int64]*ngmodels.AlertConfiguration) *notifier.MultiOrgAlertmanager {
|
||||
t.Helper()
|
||||
|
||||
@@ -849,40 +725,6 @@ var validConfigWithAutogen = `{
|
||||
}
|
||||
`
|
||||
|
||||
var validConfigWithSecureSetting = `{
|
||||
"template_files": {
|
||||
"a": "template"
|
||||
},
|
||||
"alertmanager_config": {
|
||||
"route": {
|
||||
"receiver": "grafana-default-email"
|
||||
},
|
||||
"receivers": [{
|
||||
"name": "grafana-default-email",
|
||||
"grafana_managed_receiver_configs": [{
|
||||
"uid": "",
|
||||
"name": "email receiver",
|
||||
"type": "email",
|
||||
"settings": {
|
||||
"addresses": "<example@email.com>"
|
||||
}
|
||||
}]},
|
||||
{
|
||||
"name": "slack",
|
||||
"grafana_managed_receiver_configs": [{
|
||||
"uid": "",
|
||||
"name": "slack1",
|
||||
"type": "slack",
|
||||
"settings": {"text": "slack text"},
|
||||
"secureSettings": {
|
||||
"url": "secure url"
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
var brokenConfig = `
|
||||
"alertmanager_config": {
|
||||
"route": {
|
||||
@@ -947,3 +789,13 @@ func asGettableHistoricUserConfigs(t *testing.T, r response.Response) []apimodel
|
||||
require.NoError(t, err)
|
||||
return body
|
||||
}
|
||||
|
||||
// RoutePostAlertingConfig drop-in replacement for removed POST endpoint to make test transition easier.
|
||||
func RoutePostAlertingConfig(t *testing.T, mam *notifier.MultiOrgAlertmanager, rc *contextmodel.ReqContext, amConfig string) {
|
||||
t.Helper()
|
||||
cfg := apimodels.PostableUserConfig{}
|
||||
err := json.Unmarshal([]byte(amConfig), &cfg)
|
||||
require.NoError(t, err)
|
||||
err = mam.SaveAndApplyAlertmanagerConfiguration(rc.Req.Context(), 1, cfg)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
@@ -229,9 +228,6 @@ func (api *API) authorize(method, path string) web.Handler {
|
||||
eval = ac.EvalPermission(ac.ActionAlertingNotificationsRead)
|
||||
case http.MethodGet + "/api/alertmanager/grafana/api/v2/status":
|
||||
eval = ac.EvalPermission(ac.ActionAlertingNotificationsRead)
|
||||
case http.MethodPost + "/api/alertmanager/grafana/config/api/v1/alerts":
|
||||
// additional authorization is done in the request handler
|
||||
eval = ac.EvalAny(ac.EvalPermission(ac.ActionAlertingNotificationsWrite))
|
||||
case http.MethodPost + "/api/alertmanager/grafana/config/history/{id}/_activate":
|
||||
eval = ac.EvalAny(ac.EvalPermission(ac.ActionAlertingNotificationsWrite))
|
||||
case http.MethodGet + "/api/alertmanager/grafana/config/api/v1/receivers":
|
||||
@@ -296,12 +292,9 @@ func (api *API) authorize(method, path string) web.Handler {
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningRead), // organization scope
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsProvisioningRead), // organization scope
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets), // organization scope
|
||||
}
|
||||
if api.FeatureManager.IsEnabledGlobally(featuremgmt.FlagAlertingApiServer) {
|
||||
perms = append(perms,
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversRead),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversReadSecrets),
|
||||
)
|
||||
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversRead), // organization scope
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversReadSecrets), // organization scope
|
||||
}
|
||||
eval = ac.EvalAny(perms...)
|
||||
|
||||
|
||||
@@ -175,13 +175,6 @@ func (f *AlertmanagerApiHandler) handleRouteGetGrafanaSilences(ctx *contextmodel
|
||||
return f.GrafanaSvc.RouteGetSilences(ctx)
|
||||
}
|
||||
|
||||
func (f *AlertmanagerApiHandler) handleRoutePostGrafanaAlertingConfig(ctx *contextmodel.ReqContext, conf apimodels.PostableUserConfig) response.Response {
|
||||
if !conf.AlertmanagerConfig.ReceiverType().Can(apimodels.GrafanaReceiverType) {
|
||||
return errorToResponse(backendTypeDoesNotMatchPayloadTypeError(apimodels.GrafanaBackend, conf.AlertmanagerConfig.ReceiverType().String()))
|
||||
}
|
||||
return f.GrafanaSvc.RoutePostAlertingConfig(ctx, conf)
|
||||
}
|
||||
|
||||
func (f *AlertmanagerApiHandler) handleRouteGetGrafanaReceivers(ctx *contextmodel.ReqContext) response.Response {
|
||||
return f.GrafanaSvc.RouteGetReceivers(ctx)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ type AlertmanagerApi interface {
|
||||
RouteGetSilences(*contextmodel.ReqContext) response.Response
|
||||
RoutePostAMAlerts(*contextmodel.ReqContext) response.Response
|
||||
RoutePostAlertingConfig(*contextmodel.ReqContext) response.Response
|
||||
RoutePostGrafanaAlertingConfig(*contextmodel.ReqContext) response.Response
|
||||
RoutePostGrafanaAlertingConfigHistoryActivate(*contextmodel.ReqContext) response.Response
|
||||
RoutePostTestGrafanaReceivers(*contextmodel.ReqContext) response.Response
|
||||
RoutePostTestGrafanaTemplates(*contextmodel.ReqContext) response.Response
|
||||
@@ -162,14 +161,6 @@ func (f *AlertmanagerApiHandler) RoutePostAlertingConfig(ctx *contextmodel.ReqCo
|
||||
}
|
||||
return f.handleRoutePostAlertingConfig(ctx, conf, datasourceUIDParam)
|
||||
}
|
||||
func (f *AlertmanagerApiHandler) RoutePostGrafanaAlertingConfig(ctx *contextmodel.ReqContext) response.Response {
|
||||
// Parse Request Body
|
||||
conf := apimodels.PostableUserConfig{}
|
||||
if err := web.Bind(ctx.Req, &conf); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
}
|
||||
return f.handleRoutePostGrafanaAlertingConfig(ctx, conf)
|
||||
}
|
||||
func (f *AlertmanagerApiHandler) RoutePostGrafanaAlertingConfigHistoryActivate(ctx *contextmodel.ReqContext) response.Response {
|
||||
// Parse Path Parameters
|
||||
idParam := web.Params(ctx.Req)[":id"]
|
||||
@@ -458,18 +449,6 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
|
||||
m,
|
||||
),
|
||||
)
|
||||
group.Post(
|
||||
toMacaronPath("/api/alertmanager/grafana/config/api/v1/alerts"),
|
||||
requestmeta.SetOwner(requestmeta.TeamAlerting),
|
||||
requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow),
|
||||
api.authorize(http.MethodPost, "/api/alertmanager/grafana/config/api/v1/alerts"),
|
||||
metrics.Instrument(
|
||||
http.MethodPost,
|
||||
"/api/alertmanager/grafana/config/api/v1/alerts",
|
||||
api.Hooks.Wrap(srv.RoutePostGrafanaAlertingConfig),
|
||||
m,
|
||||
),
|
||||
)
|
||||
group.Post(
|
||||
toMacaronPath("/api/alertmanager/grafana/config/history/{id}/_activate"),
|
||||
requestmeta.SetOwner(requestmeta.TeamAlerting),
|
||||
|
||||
@@ -16,17 +16,6 @@ import (
|
||||
alertingmodels "github.com/grafana/alerting/models"
|
||||
)
|
||||
|
||||
// swagger:route POST /alertmanager/grafana/config/api/v1/alerts alertmanager RoutePostGrafanaAlertingConfig
|
||||
//
|
||||
// sets an Alerting config
|
||||
//
|
||||
// This API is designated to internal use only and can be removed or changed at any time without prior notice.
|
||||
//
|
||||
// Deprecated: true
|
||||
// Responses:
|
||||
// 201: Ack
|
||||
// 400: ValidationError
|
||||
|
||||
// swagger:route POST /alertmanager/{DatasourceUID}/config/api/v1/alerts alertmanager RoutePostAlertingConfig
|
||||
//
|
||||
// sets an Alerting config
|
||||
|
||||
@@ -5696,38 +5696,6 @@
|
||||
"tags": [
|
||||
"alertmanager"
|
||||
]
|
||||
},
|
||||
"post": {
|
||||
"deprecated": true,
|
||||
"description": "This API is designated to internal use only and can be removed or changed at any time without prior notice.",
|
||||
"operationId": "RoutePostGrafanaAlertingConfig",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "Body",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/PostableUserConfig"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Ack",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Ack"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "ValidationError",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ValidationError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "sets an Alerting config",
|
||||
"tags": [
|
||||
"alertmanager"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/alertmanager/grafana/config/api/v1/receivers": {
|
||||
|
||||
@@ -321,38 +321,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"description": "This API is designated to internal use only and can be removed or changed at any time without prior notice.",
|
||||
"tags": [
|
||||
"alertmanager"
|
||||
],
|
||||
"summary": "sets an Alerting config",
|
||||
"operationId": "RoutePostGrafanaAlertingConfig",
|
||||
"deprecated": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Body",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/PostableUserConfig"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Ack",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Ack"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "ValidationError",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"description": "This API is designated to internal use only and can be removed or changed at any time without prior notice.",
|
||||
"tags": [
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// 🌟 This was machine generated. Do not edit. 🌟
|
||||
//
|
||||
//
|
||||
// Frame[0] {
|
||||
// "type": "directory-listing",
|
||||
// "typeVersion": [
|
||||
@@ -10,7 +10,7 @@
|
||||
// "HasMore": false
|
||||
// }
|
||||
// }
|
||||
// Name:
|
||||
// Name:
|
||||
// Dimensions: 3 Fields by 3 Rows
|
||||
// +----------------------------+----------------------+---------------+
|
||||
// | Name: name | Name: mediaType | Name: size |
|
||||
@@ -87,4 +87,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user