[Alerting]: Require login for alerting API routes (#32688)

* [Alerting]: Require login for alerting API routes

* Fix example requests

* [Alerting]: Add /api prefix to all routes (#32716)
This commit is contained in:
Sofia Papagiannaki 2021-04-06 17:22:05 +03:00 committed by GitHub
parent 5c1d4777b2
commit 9d7d33ebb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 809 additions and 64 deletions

View File

@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
)
@ -36,17 +37,17 @@ type AlertmanagerApiBase struct {
func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApiService) {
api.RouteRegister.Group("", func(group routing.RouteRegister) {
group.Post(toMacaronPath("/alertmanager/{Recipient}/api/v2/silences"), binding.Bind(apimodels.PostableSilence{}), routing.Wrap(srv.RouteCreateSilence))
group.Delete(toMacaronPath("/alertmanager/{Recipient}/config/api/v1/alerts"), routing.Wrap(srv.RouteDeleteAlertingConfig))
group.Delete(toMacaronPath("/alertmanager/{Recipient}/api/v2/silence/{SilenceId}"), routing.Wrap(srv.RouteDeleteSilence))
group.Get(toMacaronPath("/alertmanager/{Recipient}/api/v2/alerts/groups"), routing.Wrap(srv.RouteGetAMAlertGroups))
group.Get(toMacaronPath("/alertmanager/{Recipient}/api/v2/alerts"), routing.Wrap(srv.RouteGetAMAlerts))
group.Get(toMacaronPath("/alertmanager/{Recipient}/config/api/v1/alerts"), routing.Wrap(srv.RouteGetAlertingConfig))
group.Get(toMacaronPath("/alertmanager/{Recipient}/api/v2/silence/{SilenceId}"), routing.Wrap(srv.RouteGetSilence))
group.Get(toMacaronPath("/alertmanager/{Recipient}/api/v2/silences"), routing.Wrap(srv.RouteGetSilences))
group.Post(toMacaronPath("/alertmanager/{Recipient}/api/v2/alerts"), binding.Bind(apimodels.PostableAlerts{}), routing.Wrap(srv.RoutePostAMAlerts))
group.Post(toMacaronPath("/alertmanager/{Recipient}/config/api/v1/alerts"), binding.Bind(apimodels.PostableUserConfig{}), routing.Wrap(srv.RoutePostAlertingConfig))
})
group.Post(toMacaronPath("/api/alertmanager/{Recipient}/api/v2/silences"), binding.Bind(apimodels.PostableSilence{}), routing.Wrap(srv.RouteCreateSilence))
group.Delete(toMacaronPath("/api/alertmanager/{Recipient}/config/api/v1/alerts"), routing.Wrap(srv.RouteDeleteAlertingConfig))
group.Delete(toMacaronPath("/api/alertmanager/{Recipient}/api/v2/silence/{SilenceId}"), routing.Wrap(srv.RouteDeleteSilence))
group.Get(toMacaronPath("/api/alertmanager/{Recipient}/api/v2/alerts/groups"), routing.Wrap(srv.RouteGetAMAlertGroups))
group.Get(toMacaronPath("/api/alertmanager/{Recipient}/api/v2/alerts"), routing.Wrap(srv.RouteGetAMAlerts))
group.Get(toMacaronPath("/api/alertmanager/{Recipient}/config/api/v1/alerts"), routing.Wrap(srv.RouteGetAlertingConfig))
group.Get(toMacaronPath("/api/alertmanager/{Recipient}/api/v2/silence/{SilenceId}"), routing.Wrap(srv.RouteGetSilence))
group.Get(toMacaronPath("/api/alertmanager/{Recipient}/api/v2/silences"), routing.Wrap(srv.RouteGetSilences))
group.Post(toMacaronPath("/api/alertmanager/{Recipient}/api/v2/alerts"), binding.Bind(apimodels.PostableAlerts{}), routing.Wrap(srv.RoutePostAMAlerts))
group.Post(toMacaronPath("/api/alertmanager/{Recipient}/config/api/v1/alerts"), binding.Bind(apimodels.PostableUserConfig{}), routing.Wrap(srv.RoutePostAlertingConfig))
}, middleware.ReqSignedIn)
}
func (base AlertmanagerApiBase) RouteCreateSilence(c *models.ReqContext, body apimodels.PostableSilence) response.Response {

View File

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
)
@ -26,9 +27,9 @@ type PrometheusApiBase struct {
func (api *API) RegisterPrometheusApiEndpoints(srv PrometheusApiService) {
api.RouteRegister.Group("", func(group routing.RouteRegister) {
group.Get(toMacaronPath("/prometheus/{Recipient}/api/v1/alerts"), routing.Wrap(srv.RouteGetAlertStatuses))
group.Get(toMacaronPath("/prometheus/{Recipient}/api/v1/rules"), routing.Wrap(srv.RouteGetRuleStatuses))
})
group.Get(toMacaronPath("/api/prometheus/{Recipient}/api/v1/alerts"), routing.Wrap(srv.RouteGetAlertStatuses))
group.Get(toMacaronPath("/api/prometheus/{Recipient}/api/v1/rules"), routing.Wrap(srv.RouteGetRuleStatuses))
}, middleware.ReqSignedIn)
}
func (base PrometheusApiBase) RouteGetAlertStatuses(c *models.ReqContext) response.Response {

View File

@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
)
@ -32,13 +33,13 @@ type RulerApiBase struct {
func (api *API) RegisterRulerApiEndpoints(srv RulerApiService) {
api.RouteRegister.Group("", func(group routing.RouteRegister) {
group.Delete(toMacaronPath("/ruler/{Recipient}/api/v1/rules/{Namespace}"), routing.Wrap(srv.RouteDeleteNamespaceRulesConfig))
group.Delete(toMacaronPath("/ruler/{Recipient}/api/v1/rules/{Namespace}/{Groupname}"), routing.Wrap(srv.RouteDeleteRuleGroupConfig))
group.Get(toMacaronPath("/ruler/{Recipient}/api/v1/rules/{Namespace}"), routing.Wrap(srv.RouteGetNamespaceRulesConfig))
group.Get(toMacaronPath("/ruler/{Recipient}/api/v1/rules/{Namespace}/{Groupname}"), routing.Wrap(srv.RouteGetRulegGroupConfig))
group.Get(toMacaronPath("/ruler/{Recipient}/api/v1/rules"), routing.Wrap(srv.RouteGetRulesConfig))
group.Post(toMacaronPath("/ruler/{Recipient}/api/v1/rules/{Namespace}"), binding.Bind(apimodels.PostableRuleGroupConfig{}), routing.Wrap(srv.RoutePostNameRulesConfig))
})
group.Delete(toMacaronPath("/api/ruler/{Recipient}/api/v1/rules/{Namespace}"), routing.Wrap(srv.RouteDeleteNamespaceRulesConfig))
group.Delete(toMacaronPath("/api/ruler/{Recipient}/api/v1/rules/{Namespace}/{Groupname}"), routing.Wrap(srv.RouteDeleteRuleGroupConfig))
group.Get(toMacaronPath("/api/ruler/{Recipient}/api/v1/rules/{Namespace}"), routing.Wrap(srv.RouteGetNamespaceRulesConfig))
group.Get(toMacaronPath("/api/ruler/{Recipient}/api/v1/rules/{Namespace}/{Groupname}"), routing.Wrap(srv.RouteGetRulegGroupConfig))
group.Get(toMacaronPath("/api/ruler/{Recipient}/api/v1/rules"), routing.Wrap(srv.RouteGetRulesConfig))
group.Post(toMacaronPath("/api/ruler/{Recipient}/api/v1/rules/{Namespace}"), binding.Bind(apimodels.PostableRuleGroupConfig{}), routing.Wrap(srv.RoutePostNameRulesConfig))
}, middleware.ReqSignedIn)
}
func (base RulerApiBase) RouteDeleteNamespaceRulesConfig(c *models.ReqContext) response.Response {

View File

@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
)
@ -30,7 +31,7 @@ func (api *API) RegisterTestingApiEndpoints(srv TestingApiService) {
api.RouteRegister.Group("", func(group routing.RouteRegister) {
group.Post(toMacaronPath("/api/v1/receiver/test"), binding.Bind(apimodels.ExtendedReceiver{}), routing.Wrap(srv.RouteTestReceiverConfig))
group.Post(toMacaronPath("/api/v1/rule/test"), binding.Bind(apimodels.TestRulePayload{}), routing.Wrap(srv.RouteTestRuleConfig))
})
}, middleware.ReqSignedIn)
}
func (base TestingApiBase) RouteTestReceiverConfig(c *models.ReqContext, body apimodels.ExtendedReceiver) response.Response {

View File

@ -11,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/infra/log"
apimodels "github.com/grafana/alerting-api/pkg/api"
"github.com/grafana/grafana/pkg/middleware"
)
type {{classname}}Service interface { {{#operation}}
@ -24,7 +25,7 @@ type {{classname}}Base struct {
func (api *API) Register{{classname}}Endpoints(srv {{classname}}Service) {
api.RouteRegister.Group("", func(group routing.RouteRegister){ {{#operations}}{{#operation}}
group.{{httpMethod}}(toMacaronPath("{{{path}}}"){{#bodyParams}}, binding.Bind(apimodels.{{dataType}}{}){{/bodyParams}}, routing.Wrap(srv.{{nickname}})){{/operation}}{{/operations}}
})
}, middleware.ReqSignedIn)
}{{#operation}}

View File

@ -0,0 +1,101 @@
@alertManagerDatasourceID = 36
###
# create AM configuration
POST http://localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/config/api/v1/alerts
content-type: application/json
{
"template_files": {},
"alertmanager_config": {
"global": {
"smtp_smarthost": "localhost:25",
"smtp_from": "youraddress@example.org",
},
"receivers": [
{
"name": "example-email",
"email_configs": {
"to": "youraddress@example.org"
}
}
],
"route": {
"receiver": "example-email",
"routes": [],
"group_wait": "1s",
"group_interval": "1s",
"repeat_interval": "1s"
},
"template": []
}
}
###
# get latest AM configuration
GET http://localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/config/api/v1/alerts
content-type: application/json
###
# delete AM configuration
DELETE http://localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/config/api/v1/alerts
###
# create AM alerts
POST http://localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/api/v2/alerts
content-type: application/json
###
# get silences - no silences
GET http://localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/api/v2/silences?Filter=foo="bar"&Filter=bar="foo"
###
# create silence
POST http://localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/api/v2/silences
content-type: application/json
{
"comment": "string",
"createdBy": "string",
"endsAt": "2023-03-31T14:17:04.419Z",
"matchers": [
{
"isRegex": true,
"name": "string",
"value": "string"
}
],
"startsAt": "2021-03-31T13:17:04.419Z"
}
###
# update silence - does not exist
POST http://localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/api/v2/silences
content-type: application/json
{
"id": "something",
"comment": "string",
"createdBy": "string",
"endsAt": "2023-03-31T14:17:04.419Z",
"matchers": [
{
"isRegex": true,
"name": "string",
"value": "string"
}
],
"startsAt": "2021-03-31T13:17:04.419Z"
}
###
# get silences
GET http://localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/api/v2/silences
###
# get silence
GET http://localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/api/v2/silence/unknown
###
# delete silence
DELETE http://localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/api/v2/silence/unknown

View File

@ -0,0 +1,96 @@
@grafana = grafana
###
# create AM configuration
POST http://localhost:3000/api/alertmanager/{{grafana}}/config/api/v1/alerts
content-type: application/json
< ./post-user-config.json
###
# get latest AM configuration
GET http://localhost:3000/api/alertmanager/{{grafana}}/config/api/v1/alerts
content-type: application/json
###
# delete AM configuration
DELETE http://localhost:3000/api/alertmanager/{{grafana}}/config/api/v1/alerts
###
# create AM alerts
POST http://localhost:3000/api/alertmanager/{{grafana}}/api/v2/alerts
content-type: application/json
###
# get silences - no silences
GET http://localhost:3000/api/alertmanager/{{grafana}}/api/v2/silences?Filter=foo="bar"&Filter=bar="foo"
###
# create silence
POST http://localhost:3000/api/alertmanager/{{grafana}}/api/v2/silences
content-type: application/json
{
"comment": "string",
"createdBy": "string",
"endsAt": "2023-03-31T14:17:04.419Z",
"matchers": [
{
"isRegex": true,
"name": "string",
"value": "string"
}
],
"startsAt": "2021-03-31T13:17:04.419Z"
}
###
# update silence - does not exist
POST http://localhost:3000/api/alertmanager/{{grafana}}/api/v2/silences
content-type: application/json
{
"id": "something",
"comment": "string",
"createdBy": "string",
"endsAt": "2023-03-31T14:17:04.419Z",
"matchers": [
{
"isRegex": true,
"name": "string",
"value": "string"
}
],
"startsAt": "2021-03-31T13:17:04.419Z"
}
###
# create silence - bad paylaad - start time must be before end time
POST http://localhost:3000/api/alertmanager/{{grafana}}/api/v2/silences
content-type: application/json
{
"comment": "string",
"createdBy": "string",
"endsAt": "2019-03-31T14:17:04.419Z",
"matchers": [
{
"isRegex": true,
"name": "string",
"value": "string"
}
],
"startsAt": "2021-03-31T13:17:04.419Z"
}
###
# get silences
GET http://localhost:3000/api/alertmanager/{{grafana}}/api/v2/silences
###
# get silence - unknown
GET http://localhost:3000/api/alertmanager/{{grafana}}/api/v2/silence/unknown
###
# delete silence - unknown
DELETE http://localhost:3000/api/alertmanager/{{grafana}}/api/v2/silence/unknown

View File

@ -1,42 +1,33 @@
@lokiDatasourceID = 32
@prometheusDatasourceID = 875
@grafana = grafana
# unsupported loki backend
GET http://admin:admin@localhost:3000/alertmanager/{{lokiDatasourceID}}/config/api/v1/alerts
###
# unsupported cortex backend
GET http://admin:admin@localhost:3000/alertmanager/{{prometheusDatasourceID}}/config/api/v1/alerts
###
# create AM configuration
POST http://admin:admin@localhost:3000/alertmanager/{{grafana}}/config/api/v1/alerts
POST http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/config/api/v1/alerts
content-type: application/json
< ./post-user-config.json
###
# get latest AM configuration
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/config/api/v1/alerts
GET http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/config/api/v1/alerts
content-type: application/json
###
# delete AM configuration
DELETE http://admin:admin@localhost:3000/alertmanager/{{grafana}}/config/api/v1/alerts
DELETE http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/config/api/v1/alerts
###
# create AM alerts
POST http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/alerts
POST http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/alerts
content-type: application/json
###
# get silences - no silences
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silences?Filter=foo="bar"&Filter=bar="foo"
GET http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/silences?Filter=foo="bar"&Filter=bar="foo"
###
# create silence
POST http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silences
POST http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/silences
content-type: application/json
{
@ -55,7 +46,7 @@ content-type: application/json
###
# update silence - does not exist
POST http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silences
POST http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/silences
content-type: application/json
{
@ -75,7 +66,7 @@ content-type: application/json
###
# create silence - bad paylaad - start time must be before end time
POST http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silences
POST http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/silences
content-type: application/json
{
@ -95,24 +86,23 @@ content-type: application/json
###
# get silences
# @name getSilences
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silences
GET http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/silences
###
@silenceID = {{getSilences.response.body.$.[0].id}}
###
# get silence
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silence/{{silenceID}}
GET http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/silence/{{silenceID}}
###
# get silence - unknown
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silence/unknown
GET http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/silence/unknown
###
# delete silence
DELETE http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silence/{{silenceID}}
DELETE http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/silence/{{silenceID}}
###
# delete silence - unknown
DELETE http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silence/unknown
DELETE http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/silence/unknown

View File

@ -0,0 +1,13 @@
@lokiDatasourceID = 32
@prometheusDatasourceID = 35
# unsupported loki backend
GET http://admin:admin@localhost:3000/api/alertmanager/{{lokiDatasourceID}}/config/api/v1/alerts
###
# unsupported cortex backend
GET http://admin:admin@localhost:3000/api/alertmanager/{{prometheusDatasourceID}}/config/api/v1/alerts
###
# unknown datasource
GET http://admin:admin@localhost:3000/api/alertmanager/unknown/config/api/v1/alerts

View File

@ -0,0 +1,75 @@
@prometheusDatasourceID = 35
// should point to an existing folder named alerting
@namespace1 = test
// create/update test namespace group42 rulegroup
POST http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
"name": "group42",
"rules": [
{
"alert": "logs_exist",
"expr": "rate({cluster=\"us-central1\", job=\"loki-prod/loki-canary\"}[1m]) > 0",
"for": "1m"
}
]
}
###
// create group101
POST http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
"name": "group101",
"rules": [
{
"alert": "logs_exist",
"expr": "rate({cluster=\"us-central1\", job=\"loki-prod/loki-canary\"}[1m]) > 0",
"for": "2m"
}
]
}
###
// get group42 rules
GET http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get group101 rules
GET http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}/group101
###
// get namespace rules
GET http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get org rules
GET http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules
###
// delete group42 rules
DELETE http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules - only group101 should be listed
GET http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
###
// delete namespace rules
DELETE http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get namespace rules - no rules
GET http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get group42 rules
GET http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules
GET http://admin:admin@localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}

View File

@ -0,0 +1,242 @@
@grafanaRecipient = grafana
// should point to an existing folder named alerting
@namespace1 = alerting
// create group42 under unknown namespace - it should fail
POST http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/unknown
content-type: application/json
< ./post-rulegroup-42.json
###
// create group42
POST http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
content-type: application/json
< ./post-rulegroup-42.json
###
// create group101
POST http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
content-type: application/json
< ./post-rulegroup-101.json
###
// get group42 rules
GET http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
###
// get group101 rules
GET http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group101
###
// get namespace rules
GET http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
###
// get org rules
GET http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules
###
// delete group42 rules
DELETE http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules - only group101 should be listed
GET http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
###
// delete namespace rules
DELETE http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
###
// get namespace rules - no rules
GET http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
###
// recreate group42
POST http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
"name": "group42",
"interval": "10s",
"rules": [
{
"grafana_alert": {
"title": "prom query with SSE",
"condition": "condition",
"data": [
{
"refId": "query",
"queryType": "",
"relativeTimeRange": {
"from": 18000,
"to": 10800
},
"model": {
"datasource": "gdev-prometheus",
"datasourceUid": "000000002",
"expr": "http_request_duration_microseconds_count",
"hide": false,
"interval": "",
"intervalMs": 1000,
"legendFormat": "",
"maxDataPoints": 100,
"refId": "query"
}
},
{
"refId": "reduced",
"queryType": "",
"relativeTimeRange": {
"from": 18000,
"to": 10800
},
"model": {
"datasource": "__expr__",
"datasourceUid": "-100",
"expression": "query",
"hide": false,
"intervalMs": 1000,
"maxDataPoints": 100,
"reducer": "mean",
"refId": "reduced",
"type": "reduce"
}
},
{
"refId": "condition",
"queryType": "",
"relativeTimeRange": {
"from": 18000,
"to": 10800
},
"model": {
"datasource": "__expr__",
"datasourceUid": "-100",
"expression": "$reduced > 10",
"hide": false,
"intervalMs": 1000,
"maxDataPoints": 100,
"refId": "condition",
"type": "math"
}
}
],
"no_data_state": "NoData",
"exec_err_state": "Alerting"
}
}
]
}
###
// get group42 rules
# @name getRule
GET http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
###
// update group42 interval and condition threshold
POST http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
"name": "group42",
"interval": "20s",
"rules": [
{
"grafana_alert": {
"title": "prom query with SSE",
"condition": "condition",
"uid": "UID",
"data": [
{
"refId": "query",
"queryType": "",
"relativeTimeRange": {
"from": 18000,
"to": 10800
},
"model": {
"datasource": "gdev-prometheus",
"datasourceUid": "000000002",
"expr": "http_request_duration_microseconds_count",
"hide": false,
"interval": "",
"intervalMs": 1000,
"legendFormat": "",
"maxDataPoints": 100,
"refId": "query"
}
},
{
"refId": "reduced",
"queryType": "",
"relativeTimeRange": {
"from": 18000,
"to": 10800
},
"model": {
"datasource": "__expr__",
"datasourceUid": "-100",
"expression": "query",
"hide": false,
"intervalMs": 1000,
"maxDataPoints": 100,
"reducer": "mean",
"refId": "reduced",
"type": "reduce"
}
},
{
"refId": "condition",
"queryType": "",
"relativeTimeRange": {
"from": 18000,
"to": 10800
},
"model": {
"datasource": "__expr__",
"datasourceUid": "-100",
"expression": "$reduced > 42",
"hide": false,
"intervalMs": 1000,
"maxDataPoints": 100,
"refId": "condition",
"type": "math"
}
}
],
"no_data_state": "NoData",
"exec_err_state": "Alerting"
}
}
]
}
###
// get group42 rules
GET http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
###
// update group42 - delete all rules
POST http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
"name": "group42",
"interval": "20s",
"rules": []
}
###
// get group42 rules
GET http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules
GET http://localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}

View File

@ -4,60 +4,60 @@
@namespace1 = alerting
// create group42 under unknown namespace - it should fail
POST http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/unknown
POST http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/unknown
content-type: application/json
< ./post-rulegroup-42.json
###
// create group42
POST http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
POST http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
content-type: application/json
< ./post-rulegroup-42.json
###
// create group101
POST http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
POST http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
content-type: application/json
< ./post-rulegroup-101.json
###
// get group42 rules
GET http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
GET http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
###
// get group101 rules
GET http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group101
GET http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group101
###
// get namespace rules
GET http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
GET http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
###
// get org rules
GET http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules
GET http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules
###
// delete group42 rules
DELETE http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
DELETE http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules - only group101 should be listed
GET http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
GET http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
###
// delete namespace rules
DELETE http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
DELETE http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
###
// get namespace rules - no rules
GET http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
GET http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
###
// recreate group42
POST http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
POST http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
@ -137,7 +137,7 @@ content-type: application/json
###
// get group42 rules
# @name getRule
GET http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
GET http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
###
@ruleUID = {{getRule.response.body.$.rules[0].grafana_alert.uid}}
@ -145,7 +145,7 @@ GET http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{
###
// update group42 interval and condition threshold
POST http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
POST http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
@ -224,11 +224,11 @@ content-type: application/json
###
// get group42 rules
GET http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
GET http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
###
// update group42 - delete all rules
POST http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
POST http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
@ -239,8 +239,8 @@ content-type: application/json
###
// get group42 rules
GET http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
GET http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules
GET http://admin:admin@localhost:3000/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}
GET http://admin:admin@localhost:3000/api/ruler/{{grafanaRecipient}}/api/v1/rules/{{namespace1}}

View File

@ -0,0 +1,75 @@
@lokiDatasourceID = 32
// should point to an existing folder named alerting
@namespace1 = test
// create/update test namespace group42 rulegroup
POST http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
"name": "group42",
"rules": [
{
"alert": "logs_exist",
"expr": "rate({cluster=\"us-central1\", job=\"loki-prod/loki-canary\"}[1m]) > 0",
"for": "1m"
}
]
}
###
// create group101
POST http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
"name": "group101",
"rules": [
{
"alert": "logs_exist",
"expr": "rate({cluster=\"us-central1\", job=\"loki-prod/loki-canary\"}[1m]) > 0",
"for": "2m"
}
]
}
###
// get group42 rules
GET http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get group101 rules
GET http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}/group101
###
// get namespace rules
GET http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get org rules
GET http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules
###
// delete group42 rules
DELETE http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules - only group101 should be listed
GET http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
###
// delete namespace rules
DELETE http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get namespace rules - no rules
GET http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get group42 rules
GET http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules
GET http://admin:admin@localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}

View File

@ -0,0 +1,148 @@
@lokiDatasourceID = 32
@prometheusDatasourceID = 35
// should point to an existing folder named alerting
@namespace1 = test
// create/update test namespace group42 rulegroup
POST http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
"name": "group42",
"rules": [
{
"alert": "logs_exist",
"expr": "rate({cluster=\"us-central1\", job=\"loki-prod/loki-canary\"}[1m]) > 0",
"for": "1m"
}
]
}
###
// create group101
POST http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
"name": "group101",
"rules": [
{
"alert": "logs_exist",
"expr": "rate({cluster=\"us-central1\", job=\"loki-prod/loki-canary\"}[1m]) > 0",
"for": "2m"
}
]
}
###
// get group42 rules
GET http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get group101 rules
GET http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}/group101
###
// get namespace rules
GET http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get org rules
GET http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules
###
// delete group42 rules
DELETE http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules - only group101 should be listed
GET http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
###
// delete namespace rules
DELETE http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get namespace rules - no rules
GET http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get group42 rules
GET http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules
GET http://localhost:3000/api/ruler/{{lokiDatasourceID}}/api/v1/rules/{{namespace1}}
###
// create/update test namespace group42 rulegroup
POST http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
"name": "group42",
"rules": [
{
"alert": "logs_exist",
"expr": "rate({cluster=\"us-central1\", job=\"loki-prod/loki-canary\"}[1m]) > 0",
"for": "1m"
}
]
}
###
// create group101
POST http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
content-type: application/json
{
"name": "group101",
"rules": [
{
"alert": "logs_exist",
"expr": "rate({cluster=\"us-central1\", job=\"loki-prod/loki-canary\"}[1m]) > 0",
"for": "2m"
}
]
}
###
// get group42 rules
GET http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get group101 rules
GET http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}/group101
###
// get namespace rules
GET http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get org rules
GET http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules
###
// delete group42 rules
DELETE http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules - only group101 should be listed
GET http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
###
// delete namespace rules
DELETE http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get namespace rules - no rules
GET http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}
###
// get group42 rules
GET http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}/group42
###
// get namespace rules
GET http://localhost:3000/api/ruler/{{prometheusDatasourceID}}/api/v1/rules/{{namespace1}}