diff --git a/go.mod b/go.mod index da803faad66a..fcda3007803f 100644 --- a/go.mod +++ b/go.mod @@ -77,7 +77,7 @@ require ( github.com/prometheus/alertmanager v0.21.1-0.20210511232218-7301451eb94d github.com/prometheus/client_golang v1.10.0 github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.24.0 + github.com/prometheus/common v0.27.0 github.com/prometheus/prometheus v1.8.2-0.20210430082741-2a4b8e12bbf2 github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 github.com/robfig/cron/v3 v3.0.1 @@ -96,8 +96,8 @@ require ( go.opentelemetry.io/collector v0.27.0 golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a golang.org/x/exp v0.0.0-20210220032938-85be41e4509f // indirect - golang.org/x/net v0.0.0-20210521195947-fe42d452be8f - golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78 + golang.org/x/net v0.0.0-20210525063256-abc453219eb5 + golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20210521203332-0cec03c779c1 // indirect golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba diff --git a/go.sum b/go.sum index a95365292128..121a6d536e4c 100644 --- a/go.sum +++ b/go.sum @@ -551,6 +551,7 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -1546,8 +1547,9 @@ github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.20.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.21.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.23.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= -github.com/prometheus/common v0.24.0 h1:aIycr3wRFxPUq8XlLQlGQ9aNXV3dFi5y62pe/SB262k= github.com/prometheus/common v0.24.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= +github.com/prometheus/common v0.27.0 h1:kJb5BtkTmonXrV2nfyRRlChGpgqhPCdj2ooGivZ8txo= +github.com/prometheus/common v0.27.0/go.mod h1:LdLj/WiR+LL0ThCPrtSZbijrsxInIhizDTiPlJhPPq4= github.com/prometheus/exporter-toolkit v0.5.0/go.mod h1:OCkM4805mmisBhLmVFw858QYi3v0wKdY6/UxrT0pZVg= github.com/prometheus/exporter-toolkit v0.5.1/go.mod h1:OCkM4805mmisBhLmVFw858QYi3v0wKdY6/UxrT0pZVg= github.com/prometheus/node_exporter v1.0.0-rc.0.0.20200428091818-01054558c289 h1:dTUS1vaLWq+Y6XKOTnrFpoVsQKLCbCp1OLj24TDi7oM= @@ -2094,8 +2096,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210324051636-2c4c8ecb7826/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210427231257-85d9c07bbe3a/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210521195947-fe42d452be8f h1:Si4U+UcgJzya9kpiEUJKQvjr512OLli+gL4poHrz93U= -golang.org/x/net v0.0.0-20210521195947-fe42d452be8f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2111,8 +2113,9 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78 h1:rPRtHfUb0UKZeZ6GH4K4Nt4YRbE9V1u+QZX5upZXqJQ= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/pkg/services/ngalert/api/api.go b/pkg/services/ngalert/api/api.go index 9e24ef7aa931..fa614b82c1d1 100644 --- a/pkg/services/ngalert/api/api.go +++ b/pkg/services/ngalert/api/api.go @@ -25,6 +25,7 @@ var timeNow = time.Now type Alertmanager interface { // Configuration SaveAndApplyConfig(config *apimodels.PostableUserConfig) error + GetStatus() apimodels.GettableStatus // Silences CreateSilence(ps *apimodels.PostableSilence) (string, error) diff --git a/pkg/services/ngalert/api/api_alertmanager.go b/pkg/services/ngalert/api/api_alertmanager.go index a0972987b3be..53fb1ca8ac87 100644 --- a/pkg/services/ngalert/api/api_alertmanager.go +++ b/pkg/services/ngalert/api/api_alertmanager.go @@ -21,6 +21,10 @@ type AlertmanagerSrv struct { log log.Logger } +func (srv AlertmanagerSrv) RouteGetAMStatus(c *models.ReqContext) response.Response { + return response.JSON(http.StatusOK, srv.am.GetStatus()) +} + func (srv AlertmanagerSrv) RouteCreateSilence(c *models.ReqContext, postableSilence apimodels.PostableSilence) response.Response { if !c.HasUserRole(models.ROLE_EDITOR) { return ErrResp(http.StatusForbidden, errors.New("permission denied"), "") diff --git a/pkg/services/ngalert/api/forked_am.go b/pkg/services/ngalert/api/forked_am.go index bb56a1dfcc6f..427125317a3a 100644 --- a/pkg/services/ngalert/api/forked_am.go +++ b/pkg/services/ngalert/api/forked_am.go @@ -39,6 +39,15 @@ func (am *ForkedAMSvc) getService(ctx *models.ReqContext) (AlertmanagerApiServic } } +func (am *ForkedAMSvc) RouteGetAMStatus(ctx *models.ReqContext) response.Response { + s, err := am.getService(ctx) + if err != nil { + return response.Error(400, err.Error(), nil) + } + + return s.RouteGetAMStatus(ctx) +} + func (am *ForkedAMSvc) RouteCreateSilence(ctx *models.ReqContext, body apimodels.PostableSilence) response.Response { s, err := am.getService(ctx) if err != nil { diff --git a/pkg/services/ngalert/api/generated_base_api_alertmanager.go b/pkg/services/ngalert/api/generated_base_api_alertmanager.go index e53e668faaa3..f20eb3d57597 100644 --- a/pkg/services/ngalert/api/generated_base_api_alertmanager.go +++ b/pkg/services/ngalert/api/generated_base_api_alertmanager.go @@ -26,6 +26,7 @@ type AlertmanagerApiService interface { RouteDeleteSilence(*models.ReqContext) response.Response RouteGetAMAlertGroups(*models.ReqContext) response.Response RouteGetAMAlerts(*models.ReqContext) response.Response + RouteGetAMStatus(*models.ReqContext) response.Response RouteGetAlertingConfig(*models.ReqContext) response.Response RouteGetSilence(*models.ReqContext) response.Response RouteGetSilences(*models.ReqContext) response.Response @@ -81,6 +82,15 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApiService, m * m, ), ) + group.Get( + toMacaronPath("/api/alertmanager/{Recipient}/api/v2/status"), + metrics.Instrument( + http.MethodGet, + "/api/alertmanager/{Recipient}/api/v2/status", + srv.RouteGetAMStatus, + m, + ), + ) group.Get( toMacaronPath("/api/alertmanager/{Recipient}/config/api/v1/alerts"), metrics.Instrument( diff --git a/pkg/services/ngalert/api/lotex_am.go b/pkg/services/ngalert/api/lotex_am.go index d77ba5095296..e8e5fac185f2 100644 --- a/pkg/services/ngalert/api/lotex_am.go +++ b/pkg/services/ngalert/api/lotex_am.go @@ -16,6 +16,7 @@ import ( const ( amSilencesPath = "/alertmanager/api/v2/silences" amSilencePath = "/alertmanager/api/v2/silence/%s" + amStatusPath = "/alertmanager/api/v2/status" amAlertGroupsPath = "/alertmanager/api/v2/alerts/groups" amAlertsPath = "/alertmanager/api/v2/alerts" amConfigPath = "/api/v1/alerts" @@ -33,6 +34,20 @@ func NewLotexAM(proxy *AlertingProxy, log log.Logger) *LotexAM { } } +func (am *LotexAM) RouteGetAMStatus(ctx *models.ReqContext) response.Response { + return am.withReq( + ctx, + http.MethodGet, + withPath( + *ctx.Req.URL, + amStatusPath, + ), + nil, + jsonExtractor(&apimodels.GettableStatus{}), + nil, + ) +} + func (am *LotexAM) RouteCreateSilence(ctx *models.ReqContext, silenceBody apimodels.PostableSilence) response.Response { blob, err := json.Marshal(silenceBody) if err != nil { diff --git a/pkg/services/ngalert/api/test-data/am-alertmanager-recipient.http b/pkg/services/ngalert/api/test-data/am-alertmanager-recipient.http index ecd0d91b6889..6fc614fa31d6 100644 --- a/pkg/services/ngalert/api/test-data/am-alertmanager-recipient.http +++ b/pkg/services/ngalert/api/test-data/am-alertmanager-recipient.http @@ -96,6 +96,10 @@ content-type: application/json # get AM alerts GET http://admin:admin@localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/api/v2/alerts +### +# get status +GET http://admin:admin@localhost:3000/api/alertmanager/{{alertManagerDatasourceID}}/api/v2/status + ### # get AM alert groups GET http://admin:admin@localhost:3000/alertmanager/{{alertManagerDatasourceID}}/api/v2/alerts/groups diff --git a/pkg/services/ngalert/api/test-data/am-grafana-recipient.http b/pkg/services/ngalert/api/test-data/am-grafana-recipient.http index 3fff2ca569e9..00358e07660b 100644 --- a/pkg/services/ngalert/api/test-data/am-grafana-recipient.http +++ b/pkg/services/ngalert/api/test-data/am-grafana-recipient.http @@ -21,6 +21,14 @@ DELETE http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/config/api POST http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/alerts content-type: application/json +### +# get AM alerts +GET http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/alerts + +### +# get AM status +GET http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/status + ### # get silences - no silences GET http://admin:admin@localhost:3000/api/alertmanager/{{grafana}}/api/v2/silences?Filter=foo="bar"&Filter=bar="foo" diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go index 75da775e78ae..28b4913f38b1 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go @@ -6,6 +6,7 @@ import ( "fmt" "reflect" + "github.com/go-openapi/strfmt" "github.com/pkg/errors" amv2 "github.com/prometheus/alertmanager/api/v2/models" "github.com/prometheus/alertmanager/config" @@ -40,6 +41,14 @@ import ( // 200: Ack // 400: ValidationError +// swagger:route GET /api/alertmanager/{Recipient}/api/v2/status alertmanager RouteGetAMStatus +// +// get alertmanager status and configuration +// +// Responses: +// 200: GettableStatus +// 400: ValidationError + // swagger:route GET /api/alertmanager/{Recipient}/api/v2/alerts alertmanager RouteGetAMAlerts // // get alertmanager alerts @@ -114,6 +123,79 @@ type GetSilencesParams struct { Filter []string `json:"filter"` } +// swagger:model +type GettableStatus struct { + // cluster + // Required: true + Cluster *amv2.ClusterStatus `json:"cluster"` + + // config + // Required: true + Config *PostableApiAlertingConfig `json:"config"` + + // uptime + // Required: true + // Format: date-time + Uptime *strfmt.DateTime `json:"uptime"` + + // version info + // Required: true + VersionInfo *amv2.VersionInfo `json:"versionInfo"` +} + +func (s *GettableStatus) UnmarshalJSON(b []byte) error { + amStatus := amv2.AlertmanagerStatus{} + if err := json.Unmarshal(b, &amStatus); err != nil { + return err + } + + c := config.Config{} + if err := yaml.Unmarshal([]byte(*amStatus.Config.Original), &c); err != nil { + return err + } + + s.Cluster = amStatus.Cluster + s.Config = &PostableApiAlertingConfig{Config: Config{ + Global: c.Global, + Route: c.Route, + InhibitRules: c.InhibitRules, + Templates: c.Templates, + }} + s.Uptime = amStatus.Uptime + s.VersionInfo = amStatus.VersionInfo + + type overrides struct { + Receivers *[]*PostableApiReceiver `yaml:"receivers,omitempty" json:"receivers,omitempty"` + } + + if err := yaml.Unmarshal([]byte(*amStatus.Config.Original), &overrides{Receivers: &s.Config.Receivers}); err != nil { + return err + } + + return nil +} + +func NewGettableStatus(cfg *PostableApiAlertingConfig) *GettableStatus { + // In Grafana, the only field we support is Config. + cs := amv2.ClusterStatusStatusDisabled + na := "N/A" + return &GettableStatus{ + Cluster: &amv2.ClusterStatus{ + Status: &cs, + Peers: []*amv2.PeerStatus{}, + }, + VersionInfo: &amv2.VersionInfo{ + Branch: &na, + BuildDate: &na, + BuildUser: &na, + GoVersion: &na, + Revision: &na, + Version: &na, + }, + Config: cfg, + } +} + // swagger:model type PostableSilence = amv2.PostableSilence @@ -183,7 +265,7 @@ type BodyAlertingConfig struct { } // alertmanager routes -// swagger:parameters RoutePostAlertingConfig RouteGetAlertingConfig RouteDeleteAlertingConfig RouteGetAMAlerts RoutePostAMAlerts RouteGetAMAlertGroups RouteGetSilences RouteCreateSilence RouteGetSilence RouteDeleteSilence RoutePostAlertingConfig +// swagger:parameters RoutePostAlertingConfig RouteGetAlertingConfig RouteDeleteAlertingConfig RouteGetAMStatus RouteGetAMAlerts RoutePostAMAlerts RouteGetAMAlertGroups RouteGetSilences RouteCreateSilence RouteGetSilence RouteDeleteSilence RoutePostAlertingConfig // ruler routes // swagger:parameters RouteGetRulesConfig RoutePostNameRulesConfig RouteGetNamespaceRulesConfig RouteDeleteNamespaceRulesConfig RouteGetRulegGroupConfig RouteDeleteRuleGroupConfig // prom routes diff --git a/pkg/services/ngalert/api/tooling/post.json b/pkg/services/ngalert/api/tooling/post.json index ec43435dbea9..91f147af0e69 100644 --- a/pkg/services/ngalert/api/tooling/post.json +++ b/pkg/services/ngalert/api/tooling/post.json @@ -57,10 +57,10 @@ "type": "object", "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, - "AlertGroup": { - "$ref": "#/definitions/alertGroup" + "AlertGroup": {}, + "AlertGroups": { + "$ref": "#/definitions/alertGroups" }, - "AlertGroups": {}, "AlertInstancesResponse": { "properties": { "instances": { @@ -79,65 +79,6 @@ "type": "object", "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, - "AlertNotification": { - "properties": { - "created": { - "format": "date-time", - "type": "string", - "x-go-name": "Created" - }, - "disableResolveMessage": { - "type": "boolean", - "x-go-name": "DisableResolveMessage" - }, - "frequency": { - "$ref": "#/definitions/Duration", - "type": "string" - }, - "id": { - "format": "int64", - "type": "integer", - "x-go-name": "Id" - }, - "isDefault": { - "type": "boolean", - "x-go-name": "IsDefault" - }, - "name": { - "type": "string", - "x-go-name": "Name" - }, - "secureFields": { - "additionalProperties": { - "type": "boolean" - }, - "type": "object", - "x-go-name": "SecureFields" - }, - "sendReminder": { - "type": "boolean", - "x-go-name": "SendReminder" - }, - "settings": { - "$ref": "#/definitions/Json" - }, - "type": { - "type": "string", - "x-go-name": "Type" - }, - "uid": { - "type": "string", - "x-go-name": "Uid" - }, - "updated": { - "format": "date-time", - "type": "string", - "x-go-name": "Updated" - } - }, - "type": "object", - "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" - }, "AlertQuery": { "properties": { "datasourceUid": { @@ -296,14 +237,16 @@ }, "Authorization": { "properties": { - "Credentials": { + "credentials": { "$ref": "#/definitions/Secret" }, - "CredentialsFile": { - "type": "string" + "credentials_file": { + "type": "string", + "x-go-name": "CredentialsFile" }, - "Type": { - "type": "string" + "type": { + "type": "string", + "x-go-name": "Type" } }, "title": "Authorization contains HTTP authorization credentials.", @@ -312,14 +255,16 @@ }, "BasicAuth": { "properties": { - "Password": { + "password": { "$ref": "#/definitions/Secret" }, - "PasswordFile": { - "type": "string" + "password_file": { + "type": "string", + "x-go-name": "PasswordFile" }, - "Username": { - "type": "string" + "username": { + "type": "string", + "x-go-name": "Username" } }, "title": "BasicAuth contains basic HTTP authentication credentials.", @@ -338,13 +283,6 @@ "type": "array", "x-go-name": "InhibitRules" }, - "receivers": { - "items": { - "$ref": "#/definitions/Receiver" - }, - "type": "array", - "x-go-name": "Receivers" - }, "route": { "$ref": "#/definitions/Route" }, @@ -360,53 +298,6 @@ "type": "object", "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, - "CreateAlertNotificationCommand": { - "properties": { - "Result": { - "$ref": "#/definitions/AlertNotification" - }, - "disableResolveMessage": { - "type": "boolean", - "x-go-name": "DisableResolveMessage" - }, - "frequency": { - "type": "string", - "x-go-name": "Frequency" - }, - "isDefault": { - "type": "boolean", - "x-go-name": "IsDefault" - }, - "name": { - "type": "string", - "x-go-name": "Name" - }, - "secureSettings": { - "additionalProperties": { - "type": "string" - }, - "type": "object", - "x-go-name": "SecureSettings" - }, - "sendReminder": { - "type": "boolean", - "x-go-name": "SendReminder" - }, - "settings": { - "$ref": "#/definitions/Json" - }, - "type": { - "type": "string", - "x-go-name": "Type" - }, - "uid": { - "type": "string", - "x-go-name": "Uid" - } - }, - "type": "object", - "x-go-package": "github.com/grafana/grafana/pkg/models" - }, "DateTime": { "description": "DateTime is a time but it serializes to ISO8601 format with millis\nIt knows how to read 3 different variations of a RFC3339 date time.\nMost APIs we encounter want either millisecond or second precision times.\nThis just tries to make it worry-free.", "format": "date-time", @@ -584,8 +475,12 @@ "Failure": { "$ref": "#/definitions/ResponseDetails" }, - "GettableAlert": {}, - "GettableAlerts": {}, + "GettableAlert": { + "$ref": "#/definitions/gettableAlert" + }, + "GettableAlerts": { + "$ref": "#/definitions/gettableAlerts" + }, "GettableApiAlertingConfig": { "properties": { "global": { @@ -733,7 +628,36 @@ "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, "GettableGrafanaReceiver": { - "$ref": "#/definitions/AlertNotification" + "properties": { + "disableResolveMessage": { + "type": "boolean", + "x-go-name": "DisableResolveMessage" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "secureFields": { + "additionalProperties": { + "type": "boolean" + }, + "type": "object", + "x-go-name": "SecureFields" + }, + "settings": { + "$ref": "#/definitions/Json" + }, + "type": { + "type": "string", + "x-go-name": "Type" + }, + "uid": { + "type": "string", + "x-go-name": "UID" + } + }, + "type": "object", + "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, "GettableGrafanaReceivers": { "properties": { @@ -763,8 +687,7 @@ }, "exec_err_state": { "enum": [ - "Alerting", - "KeepLastState" + "Alerting" ], "type": "string", "x-go-name": "ExecErrState" @@ -792,7 +715,6 @@ "enum": [ "Alerting", "NoData", - "KeepLastState", "OK" ], "type": "string", @@ -852,7 +774,36 @@ "GettableSilence": { "$ref": "#/definitions/gettableSilence" }, - "GettableSilences": {}, + "GettableSilences": { + "$ref": "#/definitions/gettableSilences" + }, + "GettableStatus": { + "properties": { + "cluster": { + "$ref": "#/definitions/clusterStatus" + }, + "config": { + "$ref": "#/definitions/PostableApiAlertingConfig" + }, + "uptime": { + "description": "uptime", + "format": "date-time", + "type": "string", + "x-go-name": "Uptime" + }, + "versionInfo": { + "$ref": "#/definitions/versionInfo" + } + }, + "required": [ + "cluster", + "config", + "uptime", + "versionInfo" + ], + "type": "object", + "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" + }, "GettableUserConfig": { "properties": { "alertmanager_config": { @@ -945,30 +896,32 @@ }, "HTTPClientConfig": { "properties": { - "Authorization": { + "authorization": { "$ref": "#/definitions/Authorization" }, - "BasicAuth": { + "basic_auth": { "$ref": "#/definitions/BasicAuth" }, - "BearerToken": { + "bearer_token": { "$ref": "#/definitions/Secret" }, - "BearerTokenFile": { + "bearer_token_file": { "description": "The bearer token file for the targets. Deprecated in favour of\nAuthorization.CredentialsFile.", - "type": "string" + "type": "string", + "x-go-name": "BearerTokenFile" }, - "FollowRedirects": { + "follow_redirects": { "description": "FollowRedirects specifies whether the client should follow HTTP 3xx redirects.\nThe omitempty flag is not set, because it would be hidden from the\nmarshalled configuration when set to false.", - "type": "boolean" + "type": "boolean", + "x-go-name": "FollowRedirects" }, - "OAuth2": { + "oauth2": { "$ref": "#/definitions/OAuth2" }, - "ProxyURL": { + "proxy_url": { "$ref": "#/definitions/URL" }, - "TLSConfig": { + "tls_config": { "$ref": "#/definitions/TLSConfig" } }, @@ -1123,29 +1076,34 @@ }, "OAuth2": { "properties": { - "ClientID": { - "type": "string" + "client_id": { + "type": "string", + "x-go-name": "ClientID" }, - "ClientSecret": { + "client_secret": { "$ref": "#/definitions/Secret" }, - "ClientSecretFile": { - "type": "string" + "client_secret_file": { + "type": "string", + "x-go-name": "ClientSecretFile" }, - "EndpointParams": { + "endpoint_params": { "additionalProperties": { "type": "string" }, - "type": "object" + "type": "object", + "x-go-name": "EndpointParams" }, - "Scopes": { + "scopes": { "items": { "type": "string" }, - "type": "array" + "type": "array", + "x-go-name": "Scopes" }, - "TokenURL": { - "type": "string" + "token_url": { + "type": "string", + "x-go-name": "TokenURL" } }, "title": "OAuth2 is the oauth2 client configuration.", @@ -1502,7 +1460,36 @@ "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, "PostableGrafanaReceiver": { - "$ref": "#/definitions/CreateAlertNotificationCommand" + "properties": { + "disableResolveMessage": { + "type": "boolean", + "x-go-name": "DisableResolveMessage" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "secureSettings": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "x-go-name": "SecureSettings" + }, + "settings": { + "$ref": "#/definitions/Json" + }, + "type": { + "type": "string", + "x-go-name": "Type" + }, + "uid": { + "type": "string", + "x-go-name": "UID" + } + }, + "type": "object", + "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, "PostableGrafanaReceivers": { "properties": { @@ -1532,8 +1519,7 @@ }, "exec_err_state": { "enum": [ - "Alerting", - "KeepLastState" + "Alerting" ], "type": "string", "x-go-name": "ExecErrState" @@ -1542,7 +1528,6 @@ "enum": [ "Alerting", "NoData", - "KeepLastState", "OK" ], "type": "string", @@ -1651,7 +1636,6 @@ "x-go-package": "github.com/prometheus/alertmanager/config" }, "Receiver": { - "$ref": "#/definitions/receiver", "properties": { "email_configs": { "items": { @@ -1985,18 +1969,6 @@ "$ref": "#/definitions/URL", "title": "SecretURL is a URL that must not be revealed on marshaling." }, - "SecureJsonData": { - "additionalProperties": { - "items": { - "format": "uint8", - "type": "integer" - }, - "type": "array" - }, - "description": "SecureJsonData is used to store encrypted data (for example in data_source table). Only values are separately\nencrypted.", - "type": "object", - "x-go-package": "github.com/grafana/grafana/pkg/components/securejsondata" - }, "SlackAction": { "description": "See https://api.slack.com/docs/message-attachments#action_fields and https://api.slack.com/docs/message-buttons\nfor more information.", "properties": { @@ -2190,25 +2162,30 @@ }, "TLSConfig": { "properties": { - "CAFile": { + "ca_file": { "description": "The CA cert to use for the targets.", - "type": "string" + "type": "string", + "x-go-name": "CAFile" }, - "CertFile": { + "cert_file": { "description": "The client cert file for the targets.", - "type": "string" + "type": "string", + "x-go-name": "CertFile" }, - "InsecureSkipVerify": { + "insecure_skip_verify": { "description": "Disable target certificate validation.", - "type": "boolean" + "type": "boolean", + "x-go-name": "InsecureSkipVerify" }, - "KeyFile": { + "key_file": { "description": "The client key file for the targets.", - "type": "string" + "type": "string", + "x-go-name": "KeyFile" }, - "ServerName": { + "server_name": { "description": "Used to verify the hostname for the targets.", - "type": "string" + "type": "string", + "x-go-name": "ServerName" } }, "title": "TLSConfig configures the options for TLS connections.", @@ -2624,7 +2601,7 @@ "receivers": { "description": "receivers", "items": { - "$ref": "#/definitions/Receiver" + "$ref": "#/definitions/receiver" }, "type": "array", "x-go-name": "Receivers" @@ -2662,7 +2639,7 @@ "gettableAlerts": { "description": "GettableAlerts gettable alerts", "items": { - "$ref": "#/definitions/gettableAlert" + "$ref": "#/definitions/GettableAlert" }, "type": "array", "x-go-name": "GettableAlerts", @@ -3341,7 +3318,7 @@ "in": "body", "name": "Silence", "schema": { - "$ref": "#/definitions/PostableSilence" + "$ref": "#/definitions/postableSilence" } }, { @@ -3371,6 +3348,38 @@ ] } }, + "/api/alertmanager/{Recipient}/api/v2/status": { + "get": { + "description": "get alertmanager status and configuration", + "operationId": "RouteGetAMStatus", + "parameters": [ + { + "description": "Recipient should be \"grafana\" for requests to be handled by grafana\nand the numeric datasource id for requests to be forwarded to a datasource", + "in": "path", + "name": "Recipient", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "GettableStatus", + "schema": { + "$ref": "#/definitions/GettableStatus" + } + }, + "400": { + "description": "ValidationError", + "schema": { + "$ref": "#/definitions/ValidationError" + } + } + }, + "tags": [ + "alertmanager" + ] + } + }, "/api/alertmanager/{Recipient}/config/api/v1/alerts": { "delete": { "description": "deletes the Alerting config for a tenant", diff --git a/pkg/services/ngalert/api/tooling/spec.json b/pkg/services/ngalert/api/tooling/spec.json index d2e511461cd3..e7ce3bba95bd 100644 --- a/pkg/services/ngalert/api/tooling/spec.json +++ b/pkg/services/ngalert/api/tooling/spec.json @@ -327,7 +327,7 @@ "name": "Silence", "in": "body", "schema": { - "$ref": "#/definitions/PostableSilence" + "$ref": "#/definitions/postableSilence" } }, { @@ -354,6 +354,38 @@ } } }, + "/api/alertmanager/{Recipient}/api/v2/status": { + "get": { + "description": "get alertmanager status and configuration", + "tags": [ + "alertmanager" + ], + "operationId": "RouteGetAMStatus", + "parameters": [ + { + "type": "string", + "description": "Recipient should be \"grafana\" for requests to be handled by grafana\nand the numeric datasource id for requests to be forwarded to a datasource", + "name": "Recipient", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "GettableStatus", + "schema": { + "$ref": "#/definitions/GettableStatus" + } + }, + "400": { + "description": "ValidationError", + "schema": { + "$ref": "#/definitions/ValidationError" + } + } + } + } + }, "/api/alertmanager/{Recipient}/config/api/v1/alerts": { "get": { "description": "gets an Alerting config", @@ -895,10 +927,10 @@ "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, "AlertGroup": { - "$ref": "#/definitions/alertGroup" + "$ref": "#/definitions/AlertGroup" }, "AlertGroups": { - "$ref": "#/definitions/AlertGroups" + "$ref": "#/definitions/alertGroups" }, "AlertInstancesResponse": { "type": "object", @@ -918,65 +950,6 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, - "AlertNotification": { - "type": "object", - "properties": { - "created": { - "type": "string", - "format": "date-time", - "x-go-name": "Created" - }, - "disableResolveMessage": { - "type": "boolean", - "x-go-name": "DisableResolveMessage" - }, - "frequency": { - "type": "string", - "$ref": "#/definitions/Duration" - }, - "id": { - "type": "integer", - "format": "int64", - "x-go-name": "Id" - }, - "isDefault": { - "type": "boolean", - "x-go-name": "IsDefault" - }, - "name": { - "type": "string", - "x-go-name": "Name" - }, - "secureFields": { - "type": "object", - "additionalProperties": { - "type": "boolean" - }, - "x-go-name": "SecureFields" - }, - "sendReminder": { - "type": "boolean", - "x-go-name": "SendReminder" - }, - "settings": { - "$ref": "#/definitions/Json" - }, - "type": { - "type": "string", - "x-go-name": "Type" - }, - "uid": { - "type": "string", - "x-go-name": "Uid" - }, - "updated": { - "type": "string", - "format": "date-time", - "x-go-name": "Updated" - } - }, - "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" - }, "AlertQuery": { "type": "object", "title": "AlertQuery represents a single query associated with an alert definition.", @@ -1137,14 +1110,16 @@ "type": "object", "title": "Authorization contains HTTP authorization credentials.", "properties": { - "Credentials": { + "credentials": { "$ref": "#/definitions/Secret" }, - "CredentialsFile": { - "type": "string" + "credentials_file": { + "type": "string", + "x-go-name": "CredentialsFile" }, - "Type": { - "type": "string" + "type": { + "type": "string", + "x-go-name": "Type" } }, "x-go-package": "github.com/prometheus/common/config" @@ -1153,14 +1128,16 @@ "type": "object", "title": "BasicAuth contains basic HTTP authentication credentials.", "properties": { - "Password": { + "password": { "$ref": "#/definitions/Secret" }, - "PasswordFile": { - "type": "string" + "password_file": { + "type": "string", + "x-go-name": "PasswordFile" }, - "Username": { - "type": "string" + "username": { + "type": "string", + "x-go-name": "Username" } }, "x-go-package": "github.com/prometheus/common/config" @@ -1179,13 +1156,6 @@ }, "x-go-name": "InhibitRules" }, - "receivers": { - "type": "array", - "items": { - "$ref": "#/definitions/Receiver" - }, - "x-go-name": "Receivers" - }, "route": { "$ref": "#/definitions/Route" }, @@ -1199,53 +1169,6 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, - "CreateAlertNotificationCommand": { - "type": "object", - "properties": { - "Result": { - "$ref": "#/definitions/AlertNotification" - }, - "disableResolveMessage": { - "type": "boolean", - "x-go-name": "DisableResolveMessage" - }, - "frequency": { - "type": "string", - "x-go-name": "Frequency" - }, - "isDefault": { - "type": "boolean", - "x-go-name": "IsDefault" - }, - "name": { - "type": "string", - "x-go-name": "Name" - }, - "secureSettings": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "x-go-name": "SecureSettings" - }, - "sendReminder": { - "type": "boolean", - "x-go-name": "SendReminder" - }, - "settings": { - "$ref": "#/definitions/Json" - }, - "type": { - "type": "string", - "x-go-name": "Type" - }, - "uid": { - "type": "string", - "x-go-name": "Uid" - } - }, - "x-go-package": "github.com/grafana/grafana/pkg/models" - }, "DateTime": { "description": "DateTime is a time but it serializes to ISO8601 format with millis\nIt knows how to read 3 different variations of a RFC3339 date time.\nMost APIs we encounter want either millisecond or second precision times.\nThis just tries to make it worry-free.", "type": "string", @@ -1427,10 +1350,10 @@ "$ref": "#/definitions/ResponseDetails" }, "GettableAlert": { - "$ref": "#/definitions/GettableAlert" + "$ref": "#/definitions/gettableAlert" }, "GettableAlerts": { - "$ref": "#/definitions/GettableAlerts" + "$ref": "#/definitions/gettableAlerts" }, "GettableApiAlertingConfig": { "type": "object", @@ -1579,7 +1502,36 @@ "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, "GettableGrafanaReceiver": { - "$ref": "#/definitions/AlertNotification" + "type": "object", + "properties": { + "disableResolveMessage": { + "type": "boolean", + "x-go-name": "DisableResolveMessage" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "secureFields": { + "type": "object", + "additionalProperties": { + "type": "boolean" + }, + "x-go-name": "SecureFields" + }, + "settings": { + "$ref": "#/definitions/Json" + }, + "type": { + "type": "string", + "x-go-name": "Type" + }, + "uid": { + "type": "string", + "x-go-name": "UID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, "GettableGrafanaReceivers": { "type": "object", @@ -1611,8 +1563,7 @@ "exec_err_state": { "type": "string", "enum": [ - "Alerting", - "KeepLastState" + "Alerting" ], "x-go-name": "ExecErrState" }, @@ -1640,7 +1591,6 @@ "enum": [ "Alerting", "NoData", - "KeepLastState", "OK" ], "x-go-name": "NoDataState" @@ -1699,7 +1649,34 @@ "$ref": "#/definitions/gettableSilence" }, "GettableSilences": { - "$ref": "#/definitions/GettableSilences" + "$ref": "#/definitions/gettableSilences" + }, + "GettableStatus": { + "type": "object", + "required": [ + "cluster", + "config", + "uptime", + "versionInfo" + ], + "properties": { + "cluster": { + "$ref": "#/definitions/clusterStatus" + }, + "config": { + "$ref": "#/definitions/PostableApiAlertingConfig" + }, + "uptime": { + "description": "uptime", + "type": "string", + "format": "date-time", + "x-go-name": "Uptime" + }, + "versionInfo": { + "$ref": "#/definitions/versionInfo" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, "GettableUserConfig": { "type": "object", @@ -1795,30 +1772,32 @@ "type": "object", "title": "HTTPClientConfig configures an HTTP client.", "properties": { - "Authorization": { + "authorization": { "$ref": "#/definitions/Authorization" }, - "BasicAuth": { + "basic_auth": { "$ref": "#/definitions/BasicAuth" }, - "BearerToken": { + "bearer_token": { "$ref": "#/definitions/Secret" }, - "BearerTokenFile": { + "bearer_token_file": { "description": "The bearer token file for the targets. Deprecated in favour of\nAuthorization.CredentialsFile.", - "type": "string" + "type": "string", + "x-go-name": "BearerTokenFile" }, - "FollowRedirects": { + "follow_redirects": { "description": "FollowRedirects specifies whether the client should follow HTTP 3xx redirects.\nThe omitempty flag is not set, because it would be hidden from the\nmarshalled configuration when set to false.", - "type": "boolean" + "type": "boolean", + "x-go-name": "FollowRedirects" }, - "OAuth2": { + "oauth2": { "$ref": "#/definitions/OAuth2" }, - "ProxyURL": { + "proxy_url": { "$ref": "#/definitions/URL" }, - "TLSConfig": { + "tls_config": { "$ref": "#/definitions/TLSConfig" } }, @@ -1974,29 +1953,34 @@ "type": "object", "title": "OAuth2 is the oauth2 client configuration.", "properties": { - "ClientID": { - "type": "string" + "client_id": { + "type": "string", + "x-go-name": "ClientID" }, - "ClientSecret": { + "client_secret": { "$ref": "#/definitions/Secret" }, - "ClientSecretFile": { - "type": "string" + "client_secret_file": { + "type": "string", + "x-go-name": "ClientSecretFile" }, - "EndpointParams": { + "endpoint_params": { "type": "object", "additionalProperties": { "type": "string" - } + }, + "x-go-name": "EndpointParams" }, - "Scopes": { + "scopes": { "type": "array", "items": { "type": "string" - } + }, + "x-go-name": "Scopes" }, - "TokenURL": { - "type": "string" + "token_url": { + "type": "string", + "x-go-name": "TokenURL" } }, "x-go-package": "github.com/prometheus/common/config" @@ -2351,7 +2335,36 @@ "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, "PostableGrafanaReceiver": { - "$ref": "#/definitions/CreateAlertNotificationCommand" + "type": "object", + "properties": { + "disableResolveMessage": { + "type": "boolean", + "x-go-name": "DisableResolveMessage" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "secureSettings": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-go-name": "SecureSettings" + }, + "settings": { + "$ref": "#/definitions/Json" + }, + "type": { + "type": "string", + "x-go-name": "Type" + }, + "uid": { + "type": "string", + "x-go-name": "UID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, "PostableGrafanaReceivers": { "type": "object", @@ -2383,8 +2396,7 @@ "exec_err_state": { "type": "string", "enum": [ - "Alerting", - "KeepLastState" + "Alerting" ], "x-go-name": "ExecErrState" }, @@ -2393,7 +2405,6 @@ "enum": [ "Alerting", "NoData", - "KeepLastState", "OK" ], "x-go-name": "NoDataState" @@ -2567,7 +2578,7 @@ "x-go-name": "WechatConfigs" } }, - "$ref": "#/definitions/receiver" + "$ref": "#/definitions/Receiver" }, "Regexp": { "description": "A Regexp is safe for concurrent use by multiple goroutines,\nexcept for configuration methods, such as Longest.", @@ -2836,18 +2847,6 @@ "title": "SecretURL is a URL that must not be revealed on marshaling.", "$ref": "#/definitions/URL" }, - "SecureJsonData": { - "description": "SecureJsonData is used to store encrypted data (for example in data_source table). Only values are separately\nencrypted.", - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8" - } - }, - "x-go-package": "github.com/grafana/grafana/pkg/components/securejsondata" - }, "SlackAction": { "description": "See https://api.slack.com/docs/message-attachments#action_fields and https://api.slack.com/docs/message-buttons\nfor more information.", "type": "object", @@ -3043,25 +3042,30 @@ "type": "object", "title": "TLSConfig configures the options for TLS connections.", "properties": { - "CAFile": { + "ca_file": { "description": "The CA cert to use for the targets.", - "type": "string" + "type": "string", + "x-go-name": "CAFile" }, - "CertFile": { + "cert_file": { "description": "The client cert file for the targets.", - "type": "string" + "type": "string", + "x-go-name": "CertFile" }, - "InsecureSkipVerify": { + "insecure_skip_verify": { "description": "Disable target certificate validation.", - "type": "boolean" + "type": "boolean", + "x-go-name": "InsecureSkipVerify" }, - "KeyFile": { + "key_file": { "description": "The client key file for the targets.", - "type": "string" + "type": "string", + "x-go-name": "KeyFile" }, - "ServerName": { + "server_name": { "description": "Used to verify the hostname for the targets.", - "type": "string" + "type": "string", + "x-go-name": "ServerName" } }, "x-go-package": "github.com/prometheus/common/config" @@ -3487,7 +3491,7 @@ "description": "receivers", "type": "array", "items": { - "$ref": "#/definitions/Receiver" + "$ref": "#/definitions/receiver" }, "x-go-name": "Receivers" }, @@ -3514,7 +3518,7 @@ "description": "GettableAlerts gettable alerts", "type": "array", "items": { - "$ref": "#/definitions/gettableAlert" + "$ref": "#/definitions/GettableAlert" }, "x-go-name": "GettableAlerts", "x-go-package": "github.com/prometheus/alertmanager/api/v2/models" diff --git a/pkg/services/ngalert/notifier/status.go b/pkg/services/ngalert/notifier/status.go new file mode 100644 index 000000000000..8726166dcbe7 --- /dev/null +++ b/pkg/services/ngalert/notifier/status.go @@ -0,0 +1,22 @@ +package notifier + +import ( + "encoding/json" + + apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" +) + +func (am *Alertmanager) GetStatus() apimodels.GettableStatus { + am.reloadConfigMtx.RLock() + defer am.reloadConfigMtx.RUnlock() + + var amConfig apimodels.PostableApiAlertingConfig + if am.config != nil { + err := json.Unmarshal(am.config, &amConfig) + if err != nil { + // this should never error here, if the configuration is running it should be valid. + am.logger.Error("unable to marshal alertmanager configuration", "err", err) + } + } + return *apimodels.NewGettableStatus(&amConfig) +} diff --git a/pkg/tests/api/alerting/api_alertmanager_test.go b/pkg/tests/api/alerting/api_alertmanager_test.go index a66c8559dd03..23b355957b12 100644 --- a/pkg/tests/api/alerting/api_alertmanager_test.go +++ b/pkg/tests/api/alerting/api_alertmanager_test.go @@ -1434,6 +1434,66 @@ func TestAlertRuleCRUD(t *testing.T) { } } +func TestAlertmanagerStatus(t *testing.T) { + // Setup Grafana and its Database + dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ + EnableFeatureToggles: []string{"ngalert"}, + }) + store := testinfra.SetUpDatabase(t, dir) + grafanaListedAddr := testinfra.StartGrafana(t, dir, path, store) + + // Get the Alertmanager current status. + { + alertsURL := fmt.Sprintf("http://%s/api/alertmanager/grafana/api/v2/status", grafanaListedAddr) + // nolint:gosec + resp, err := http.Get(alertsURL) + require.NoError(t, err) + t.Cleanup(func() { + err := resp.Body.Close() + require.NoError(t, err) + }) + b, err := ioutil.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, 200, resp.StatusCode) + require.JSONEq(t, ` +{ + "cluster": { + "peers": [], + "status": "disabled" + }, + "config": { + "route": { + "receiver": "grafana-default-email" + }, + "templates": null, + "receivers": [{ + "name": "grafana-default-email", + "grafana_managed_receiver_configs": [{ + "uid": "", + "name": "email receiver", + "type": "email", + "disableResolveMessage": false, + "settings": { + "addresses": "\u003cexample@email.com\u003e" + }, + "secureSettings": null + }] + }] + }, + "uptime": null, + "versionInfo": { + "branch": "N/A", + "buildDate": "N/A", + "buildUser": "N/A", + "goVersion": "N/A", + "revision": "N/A", + "version": "N/A" + } +} +`, string(b)) + } +} + func TestQuota(t *testing.T) { // Setup Grafana and its Database dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ @@ -1528,7 +1588,6 @@ func TestQuota(t *testing.T) { }) b, err := ioutil.ReadAll(resp.Body) require.NoError(t, err) - assert.Equal(t, http.StatusForbidden, resp.StatusCode) require.JSONEq(t, `{"message":"quota reached"}`, string(b)) })