Alerting: Fix "Not Implemented" responses (#57710)

* fix swagger spec, return 404 instead of 501 when an endpoint does not exist

* update number of paths in authorization_test.go
This commit is contained in:
Santiago 2022-10-26 23:35:52 -03:00 committed by GitHub
parent 0a4121cef8
commit cdb5d4230a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 10 additions and 302 deletions

View File

@ -247,10 +247,6 @@ func (srv AlertmanagerSrv) RoutePostAlertingConfig(c *models.ReqContext, body ap
return ErrResp(http.StatusInternalServerError, err, "") return ErrResp(http.StatusInternalServerError, err, "")
} }
func (srv AlertmanagerSrv) RoutePostAMAlerts(_ *models.ReqContext, _ apimodels.PostableAlerts) response.Response {
return NotImplementedResp
}
func (srv AlertmanagerSrv) RouteGetReceivers(c *models.ReqContext) response.Response { func (srv AlertmanagerSrv) RouteGetReceivers(c *models.ReqContext) response.Response {
am, errResp := srv.AlertmanagerFor(c.OrgID) am, errResp := srv.AlertmanagerFor(c.OrgID)
if errResp != nil { if errResp != nil {

View File

@ -114,8 +114,6 @@ func (api *API) authorize(method, path string) web.Handler {
eval = ac.EvalPermission(ac.ActionAlertingInstanceRead) eval = ac.EvalPermission(ac.ActionAlertingInstanceRead)
case http.MethodGet + "/api/alertmanager/grafana/api/v2/alerts": case http.MethodGet + "/api/alertmanager/grafana/api/v2/alerts":
eval = ac.EvalPermission(ac.ActionAlertingInstanceRead) eval = ac.EvalPermission(ac.ActionAlertingInstanceRead)
case http.MethodPost + "/api/alertmanager/grafana/api/v2/alerts":
eval = ac.EvalAny(ac.EvalPermission(ac.ActionAlertingInstanceCreate), ac.EvalPermission(ac.ActionAlertingInstanceUpdate))
// Grafana Prometheus-compatible Paths // Grafana Prometheus-compatible Paths
case http.MethodGet + "/api/prometheus/grafana/api/v1/alerts": case http.MethodGet + "/api/prometheus/grafana/api/v1/alerts":
@ -171,8 +169,6 @@ func (api *API) authorize(method, path string) web.Handler {
eval = ac.EvalPermission(ac.ActionAlertingNotificationsExternalRead, datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":DatasourceUID"))) eval = ac.EvalPermission(ac.ActionAlertingNotificationsExternalRead, datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":DatasourceUID")))
case http.MethodPost + "/api/alertmanager/{DatasourceUID}/config/api/v1/alerts": case http.MethodPost + "/api/alertmanager/{DatasourceUID}/config/api/v1/alerts":
eval = ac.EvalPermission(ac.ActionAlertingNotificationsExternalWrite, datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":DatasourceUID"))) eval = ac.EvalPermission(ac.ActionAlertingNotificationsExternalWrite, datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":DatasourceUID")))
case http.MethodPost + "/api/alertmanager/{DatasourceUID}/config/api/v1/receivers/test":
eval = ac.EvalPermission(ac.ActionAlertingNotificationsExternalRead, datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":DatasourceUID")))
case http.MethodGet + "/api/v1/ngalert": case http.MethodGet + "/api/v1/ngalert":
// let user with any alerting permission access this API // let user with any alerting permission access this API

View File

@ -49,7 +49,7 @@ func TestAuthorize(t *testing.T) {
} }
paths[p] = methods paths[p] = methods
} }
require.Len(t, paths, 41) require.Len(t, paths, 40)
ac := acmock.New() ac := acmock.New()
api := &API{AccessControl: ac} api := &API{AccessControl: ac}

View File

@ -131,15 +131,6 @@ func (f *AlertmanagerApiHandler) handleRoutePostAMAlerts(ctx *models.ReqContext,
return s.RoutePostAMAlerts(ctx, body) return s.RoutePostAMAlerts(ctx, body)
} }
func (f *AlertmanagerApiHandler) handleRoutePostTestReceivers(ctx *models.ReqContext, body apimodels.TestReceiversConfigBodyParams, dsUID string) response.Response {
s, err := f.getService(ctx)
if err != nil {
return errorToResponse(err)
}
return s.RoutePostTestReceivers(ctx, body)
}
func (f *AlertmanagerApiHandler) handleRouteDeleteGrafanaSilence(ctx *models.ReqContext, id string) response.Response { func (f *AlertmanagerApiHandler) handleRouteDeleteGrafanaSilence(ctx *models.ReqContext, id string) response.Response {
return f.GrafanaSvc.RouteDeleteSilence(ctx, id) return f.GrafanaSvc.RouteDeleteSilence(ctx, id)
} }
@ -176,10 +167,6 @@ func (f *AlertmanagerApiHandler) handleRouteGetGrafanaSilences(ctx *models.ReqCo
return f.GrafanaSvc.RouteGetSilences(ctx) return f.GrafanaSvc.RouteGetSilences(ctx)
} }
func (f *AlertmanagerApiHandler) handleRoutePostGrafanaAMAlerts(ctx *models.ReqContext, conf apimodels.PostableAlerts) response.Response {
return f.GrafanaSvc.RoutePostAMAlerts(ctx, conf)
}
func (f *AlertmanagerApiHandler) handleRoutePostGrafanaAlertingConfig(ctx *models.ReqContext, conf apimodels.PostableUserConfig) response.Response { func (f *AlertmanagerApiHandler) handleRoutePostGrafanaAlertingConfig(ctx *models.ReqContext, conf apimodels.PostableUserConfig) response.Response {
if !conf.AlertmanagerConfig.ReceiverType().Can(apimodels.GrafanaReceiverType) { if !conf.AlertmanagerConfig.ReceiverType().Can(apimodels.GrafanaReceiverType) {
return errorToResponse(backendTypeDoesNotMatchPayloadTypeError(apimodels.GrafanaBackend, conf.AlertmanagerConfig.ReceiverType().String())) return errorToResponse(backendTypeDoesNotMatchPayloadTypeError(apimodels.GrafanaBackend, conf.AlertmanagerConfig.ReceiverType().String()))

View File

@ -40,10 +40,8 @@ type AlertmanagerApi interface {
RouteGetSilences(*models.ReqContext) response.Response RouteGetSilences(*models.ReqContext) response.Response
RoutePostAMAlerts(*models.ReqContext) response.Response RoutePostAMAlerts(*models.ReqContext) response.Response
RoutePostAlertingConfig(*models.ReqContext) response.Response RoutePostAlertingConfig(*models.ReqContext) response.Response
RoutePostGrafanaAMAlerts(*models.ReqContext) response.Response
RoutePostGrafanaAlertingConfig(*models.ReqContext) response.Response RoutePostGrafanaAlertingConfig(*models.ReqContext) response.Response
RoutePostTestGrafanaReceivers(*models.ReqContext) response.Response RoutePostTestGrafanaReceivers(*models.ReqContext) response.Response
RoutePostTestReceivers(*models.ReqContext) response.Response
} }
func (f *AlertmanagerApiHandler) RouteCreateGrafanaSilence(ctx *models.ReqContext) response.Response { func (f *AlertmanagerApiHandler) RouteCreateGrafanaSilence(ctx *models.ReqContext) response.Response {
@ -157,14 +155,6 @@ func (f *AlertmanagerApiHandler) RoutePostAlertingConfig(ctx *models.ReqContext)
} }
return f.handleRoutePostAlertingConfig(ctx, conf, datasourceUIDParam) return f.handleRoutePostAlertingConfig(ctx, conf, datasourceUIDParam)
} }
func (f *AlertmanagerApiHandler) RoutePostGrafanaAMAlerts(ctx *models.ReqContext) response.Response {
// Parse Request Body
conf := apimodels.PostableAlerts{}
if err := web.Bind(ctx.Req, &conf); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
return f.handleRoutePostGrafanaAMAlerts(ctx, conf)
}
func (f *AlertmanagerApiHandler) RoutePostGrafanaAlertingConfig(ctx *models.ReqContext) response.Response { func (f *AlertmanagerApiHandler) RoutePostGrafanaAlertingConfig(ctx *models.ReqContext) response.Response {
// Parse Request Body // Parse Request Body
conf := apimodels.PostableUserConfig{} conf := apimodels.PostableUserConfig{}
@ -181,16 +171,6 @@ func (f *AlertmanagerApiHandler) RoutePostTestGrafanaReceivers(ctx *models.ReqCo
} }
return f.handleRoutePostTestGrafanaReceivers(ctx, conf) return f.handleRoutePostTestGrafanaReceivers(ctx, conf)
} }
func (f *AlertmanagerApiHandler) RoutePostTestReceivers(ctx *models.ReqContext) response.Response {
// Parse Path Parameters
datasourceUIDParam := web.Params(ctx.Req)[":DatasourceUID"]
// Parse Request Body
conf := apimodels.TestReceiversConfigBodyParams{}
if err := web.Bind(ctx.Req, &conf); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
return f.handleRoutePostTestReceivers(ctx, conf, datasourceUIDParam)
}
func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics.API) { func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics.API) {
api.RouteRegister.Group("", func(group routing.RouteRegister) { api.RouteRegister.Group("", func(group routing.RouteRegister) {
@ -404,16 +384,6 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
m, m,
), ),
) )
group.Post(
toMacaronPath("/api/alertmanager/grafana/api/v2/alerts"),
api.authorize(http.MethodPost, "/api/alertmanager/grafana/api/v2/alerts"),
metrics.Instrument(
http.MethodPost,
"/api/alertmanager/grafana/api/v2/alerts",
srv.RoutePostGrafanaAMAlerts,
m,
),
)
group.Post( group.Post(
toMacaronPath("/api/alertmanager/grafana/config/api/v1/alerts"), toMacaronPath("/api/alertmanager/grafana/config/api/v1/alerts"),
api.authorize(http.MethodPost, "/api/alertmanager/grafana/config/api/v1/alerts"), api.authorize(http.MethodPost, "/api/alertmanager/grafana/config/api/v1/alerts"),
@ -434,15 +404,5 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
m, m,
), ),
) )
group.Post(
toMacaronPath("/api/alertmanager/{DatasourceUID}/config/api/v1/receivers/test"),
api.authorize(http.MethodPost, "/api/alertmanager/{DatasourceUID}/config/api/v1/receivers/test"),
metrics.Instrument(
http.MethodPost,
"/api/alertmanager/{DatasourceUID}/config/api/v1/receivers/test",
srv.RoutePostTestReceivers,
m,
),
)
}, middleware.ReqSignedIn) }, middleware.ReqSignedIn)
} }

View File

@ -255,7 +255,3 @@ func (am *LotexAM) RoutePostAMAlerts(ctx *models.ReqContext, alerts apimodels.Po
nil, nil,
) )
} }
func (am *LotexAM) RoutePostTestReceivers(ctx *models.ReqContext, config apimodels.TestReceiversConfigBodyParams) response.Response {
return NotImplementedResp
}

View File

@ -3301,6 +3301,7 @@
"type": "object" "type": "object"
}, },
"alertGroups": { "alertGroups": {
"description": "AlertGroups alert groups",
"items": { "items": {
"$ref": "#/definitions/alertGroup" "$ref": "#/definitions/alertGroup"
}, },
@ -3405,6 +3406,7 @@
"type": "object" "type": "object"
}, },
"gettableAlert": { "gettableAlert": {
"description": "GettableAlert gettable alert",
"properties": { "properties": {
"annotations": { "annotations": {
"$ref": "#/definitions/labelSet" "$ref": "#/definitions/labelSet"
@ -3460,6 +3462,7 @@
"type": "object" "type": "object"
}, },
"gettableAlerts": { "gettableAlerts": {
"description": "GettableAlerts gettable alerts",
"items": { "items": {
"$ref": "#/definitions/gettableAlert" "$ref": "#/definitions/gettableAlert"
}, },
@ -3664,7 +3667,6 @@
"type": "array" "type": "array"
}, },
"postableSilence": { "postableSilence": {
"description": "PostableSilence postable silence",
"properties": { "properties": {
"comment": { "comment": {
"description": "comment", "description": "comment",
@ -3702,6 +3704,7 @@
"type": "object" "type": "object"
}, },
"receiver": { "receiver": {
"description": "Receiver receiver",
"properties": { "properties": {
"active": { "active": {
"description": "active", "description": "active",

View File

@ -108,14 +108,6 @@ import (
// 400: ValidationError // 400: ValidationError
// 404: NotFound // 404: NotFound
// swagger:route POST /api/alertmanager/grafana/api/v2/alerts alertmanager RoutePostGrafanaAMAlerts
//
// create alertmanager alerts
//
// Responses:
// 200: Ack
// 400: ValidationError
// swagger:route POST /api/alertmanager/{DatasourceUID}/api/v2/alerts alertmanager RoutePostAMAlerts // swagger:route POST /api/alertmanager/{DatasourceUID}/api/v2/alerts alertmanager RoutePostAMAlerts
// //
// create alertmanager alerts // create alertmanager alerts
@ -163,20 +155,6 @@ import (
// 408: Failure // 408: Failure
// 409: AlertManagerNotReady // 409: AlertManagerNotReady
// swagger:route POST /api/alertmanager/{DatasourceUID}/config/api/v1/receivers/test alertmanager RoutePostTestReceivers
//
// Test Grafana managed receivers without saving them.
//
// Responses:
//
// 200: Ack
// 207: MultiStatus
// 400: ValidationError
// 403: PermissionDenied
// 404: NotFound
// 408: Failure
// 409: AlertManagerNotReady
// swagger:route GET /api/alertmanager/grafana/api/v2/silences alertmanager RouteGetGrafanaSilences // swagger:route GET /api/alertmanager/grafana/api/v2/silences alertmanager RouteGetGrafanaSilences
// //
// get silences // get silences
@ -254,7 +232,7 @@ type AlertManagerNotReady struct{}
// swagger:model // swagger:model
type MultiStatus struct{} type MultiStatus struct{}
// swagger:parameters RoutePostTestReceivers RoutePostTestGrafanaReceivers // swagger:parameters RoutePostTestGrafanaReceivers
type TestReceiversConfigParams struct { type TestReceiversConfigParams struct {
// in:body // in:body
Body TestReceiversConfigBodyParams Body TestReceiversConfigBodyParams
@ -457,7 +435,7 @@ type AlertsParams struct {
Receivers string `json:"receiver"` Receivers string `json:"receiver"`
} }
// swagger:parameters RoutePostAMAlerts RoutePostGrafanaAMAlerts // swagger:parameters RoutePostAMAlerts
type PostableAlerts struct { type PostableAlerts struct {
// in:body // in:body
PostableAlerts []amv2.PostableAlert `yaml:"" json:""` PostableAlerts []amv2.PostableAlert `yaml:"" json:""`
@ -470,7 +448,7 @@ type BodyAlertingConfig struct {
} }
// alertmanager routes // alertmanager routes
// swagger:parameters RoutePostAlertingConfig RouteGetAlertingConfig RouteDeleteAlertingConfig RouteGetAMStatus RouteGetAMAlerts RoutePostAMAlerts RouteGetAMAlertGroups RouteGetSilences RouteCreateSilence RouteGetSilence RouteDeleteSilence RoutePostAlertingConfig RoutePostTestReceivers // swagger:parameters RoutePostAlertingConfig RouteGetAlertingConfig RouteDeleteAlertingConfig RouteGetAMStatus RouteGetAMAlerts RoutePostAMAlerts RouteGetAMAlertGroups RouteGetSilences RouteCreateSilence RouteGetSilence RouteDeleteSilence RoutePostAlertingConfig
// testing routes // testing routes
// swagger:parameters RouteTestRuleConfig // swagger:parameters RouteTestRuleConfig
// prom routes // prom routes

View File

@ -3302,7 +3302,6 @@
"type": "object" "type": "object"
}, },
"alertGroups": { "alertGroups": {
"description": "AlertGroups alert groups",
"items": { "items": {
"$ref": "#/definitions/alertGroup" "$ref": "#/definitions/alertGroup"
}, },
@ -3463,6 +3462,7 @@
"type": "object" "type": "object"
}, },
"gettableAlerts": { "gettableAlerts": {
"description": "GettableAlerts gettable alerts",
"items": { "items": {
"$ref": "#/definitions/gettableAlert" "$ref": "#/definitions/gettableAlert"
}, },
@ -3668,7 +3668,6 @@
"type": "array" "type": "array"
}, },
"postableSilence": { "postableSilence": {
"description": "PostableSilence postable silence",
"properties": { "properties": {
"comment": { "comment": {
"description": "comment", "description": "comment",
@ -3884,39 +3883,6 @@
"tags": [ "tags": [
"alertmanager" "alertmanager"
] ]
},
"post": {
"description": "create alertmanager alerts",
"operationId": "RoutePostGrafanaAMAlerts",
"parameters": [
{
"in": "body",
"name": "PostableAlerts",
"schema": {
"items": {
"$ref": "#/definitions/postableAlert"
},
"type": "array"
}
}
],
"responses": {
"200": {
"description": "Ack",
"schema": {
"$ref": "#/definitions/Ack"
}
},
"400": {
"description": "ValidationError",
"schema": {
"$ref": "#/definitions/ValidationError"
}
}
},
"tags": [
"alertmanager"
]
} }
}, },
"/api/alertmanager/grafana/api/v2/alerts/groups": { "/api/alertmanager/grafana/api/v2/alerts/groups": {
@ -4800,75 +4766,6 @@
] ]
} }
}, },
"/api/alertmanager/{DatasourceUID}/config/api/v1/receivers/test": {
"post": {
"operationId": "RoutePostTestReceivers",
"parameters": [
{
"in": "body",
"name": "Body",
"schema": {
"$ref": "#/definitions/TestReceiversConfigBodyParams"
}
},
{
"description": "DatasoureUID should be the datasource UID identifier",
"in": "path",
"name": "DatasourceUID",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "Ack",
"schema": {
"$ref": "#/definitions/Ack"
}
},
"207": {
"description": "MultiStatus",
"schema": {
"$ref": "#/definitions/MultiStatus"
}
},
"400": {
"description": "ValidationError",
"schema": {
"$ref": "#/definitions/ValidationError"
}
},
"403": {
"description": "PermissionDenied",
"schema": {
"$ref": "#/definitions/PermissionDenied"
}
},
"404": {
"description": "NotFound",
"schema": {
"$ref": "#/definitions/NotFound"
}
},
"408": {
"description": "Failure",
"schema": {
"$ref": "#/definitions/Failure"
}
},
"409": {
"description": "AlertManagerNotReady",
"schema": {
"$ref": "#/definitions/AlertManagerNotReady"
}
}
},
"summary": "Test Grafana managed receivers without saving them.",
"tags": [
"alertmanager"
]
}
},
"/api/prometheus/grafana/api/v1/alerts": { "/api/prometheus/grafana/api/v1/alerts": {
"get": { "get": {
"description": "gets the current alerts", "description": "gets the current alerts",

View File

@ -76,39 +76,6 @@
} }
} }
} }
},
"post": {
"description": "create alertmanager alerts",
"tags": [
"alertmanager"
],
"operationId": "RoutePostGrafanaAMAlerts",
"parameters": [
{
"name": "PostableAlerts",
"in": "body",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/postableAlert"
}
}
}
],
"responses": {
"200": {
"description": "Ack",
"schema": {
"$ref": "#/definitions/Ack"
}
},
"400": {
"description": "ValidationError",
"schema": {
"$ref": "#/definitions/ValidationError"
}
}
}
} }
}, },
"/api/alertmanager/grafana/api/v2/alerts/groups": { "/api/alertmanager/grafana/api/v2/alerts/groups": {
@ -992,75 +959,6 @@
} }
} }
}, },
"/api/alertmanager/{DatasourceUID}/config/api/v1/receivers/test": {
"post": {
"tags": [
"alertmanager"
],
"summary": "Test Grafana managed receivers without saving them.",
"operationId": "RoutePostTestReceivers",
"parameters": [
{
"name": "Body",
"in": "body",
"schema": {
"$ref": "#/definitions/TestReceiversConfigBodyParams"
}
},
{
"type": "string",
"description": "DatasoureUID should be the datasource UID identifier",
"name": "DatasourceUID",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "Ack",
"schema": {
"$ref": "#/definitions/Ack"
}
},
"207": {
"description": "MultiStatus",
"schema": {
"$ref": "#/definitions/MultiStatus"
}
},
"400": {
"description": "ValidationError",
"schema": {
"$ref": "#/definitions/ValidationError"
}
},
"403": {
"description": "PermissionDenied",
"schema": {
"$ref": "#/definitions/PermissionDenied"
}
},
"404": {
"description": "NotFound",
"schema": {
"$ref": "#/definitions/NotFound"
}
},
"408": {
"description": "Failure",
"schema": {
"$ref": "#/definitions/Failure"
}
},
"409": {
"description": "AlertManagerNotReady",
"schema": {
"$ref": "#/definitions/AlertManagerNotReady"
}
}
}
}
},
"/api/prometheus/grafana/api/v1/alerts": { "/api/prometheus/grafana/api/v1/alerts": {
"get": { "get": {
"description": "gets the current alerts", "description": "gets the current alerts",
@ -5842,7 +5740,6 @@
"$ref": "#/definitions/alertGroup" "$ref": "#/definitions/alertGroup"
}, },
"alertGroups": { "alertGroups": {
"description": "AlertGroups alert groups",
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/alertGroup" "$ref": "#/definitions/alertGroup"
@ -6005,6 +5902,7 @@
"$ref": "#/definitions/gettableAlert" "$ref": "#/definitions/gettableAlert"
}, },
"gettableAlerts": { "gettableAlerts": {
"description": "GettableAlerts gettable alerts",
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/gettableAlert" "$ref": "#/definitions/gettableAlert"
@ -6214,7 +6112,6 @@
} }
}, },
"postableSilence": { "postableSilence": {
"description": "PostableSilence postable silence",
"type": "object", "type": "object",
"required": [ "required": [
"comment", "comment",

View File

@ -27,8 +27,6 @@ import (
var searchRegex = regexp.MustCompile(`\{(\w+)\}`) var searchRegex = regexp.MustCompile(`\{(\w+)\}`)
var NotImplementedResp = ErrResp(http.StatusNotImplemented, errors.New("endpoint not implemented"), "")
func toMacaronPath(path string) string { func toMacaronPath(path string) string {
return string(searchRegex.ReplaceAllFunc([]byte(path), func(s []byte) []byte { return string(searchRegex.ReplaceAllFunc([]byte(path), func(s []byte) []byte {
m := string(s[1 : len(s)-1]) m := string(s[1 : len(s)-1])