mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Alertmanager datasource support for upstream Prometheus AM implementation (#39775)
This commit is contained in:
@@ -3,7 +3,9 @@ package api
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
@@ -14,13 +16,26 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var endpoints = map[string]map[string]string{
|
||||
"cortex": {
|
||||
"silences": "/alertmanager/api/v2/silences",
|
||||
"silence": "/alertmanager/api/v2/silence/%s",
|
||||
"status": "/alertmanager/api/v2/status",
|
||||
"groups": "/alertmanager/api/v2/alerts/groups",
|
||||
"alerts": "/alertmanager/api/v2/alerts",
|
||||
"config": "/api/v1/alerts",
|
||||
},
|
||||
"prometheus": {
|
||||
"silences": "/api/v2/silences",
|
||||
"silence": "/api/v2/silence/%s",
|
||||
"status": "/api/v2/status",
|
||||
"groups": "/api/v2/alerts/groups",
|
||||
"alerts": "/api/v2/alerts",
|
||||
},
|
||||
}
|
||||
|
||||
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"
|
||||
defaultImplementation = "cortex"
|
||||
)
|
||||
|
||||
type LotexAM struct {
|
||||
@@ -35,14 +50,57 @@ func NewLotexAM(proxy *AlertingProxy, log log.Logger) *LotexAM {
|
||||
}
|
||||
}
|
||||
|
||||
func (am *LotexAM) RouteGetAMStatus(ctx *models.ReqContext) response.Response {
|
||||
func (am *LotexAM) withAMReq(
|
||||
ctx *models.ReqContext,
|
||||
method string,
|
||||
endpoint string,
|
||||
pathParams []string,
|
||||
body io.Reader,
|
||||
extractor func(*response.NormalResponse) (interface{}, error),
|
||||
headers map[string]string,
|
||||
) response.Response {
|
||||
ds, err := am.DataProxy.DataSourceCache.GetDatasource(ctx.ParamsInt64(":Recipient"), ctx.SignedInUser, ctx.SkipCache)
|
||||
if err != nil {
|
||||
if errors.Is(err, models.ErrDataSourceAccessDenied) {
|
||||
return ErrResp(http.StatusForbidden, err, "Access denied to datasource")
|
||||
}
|
||||
if errors.Is(err, models.ErrDataSourceNotFound) {
|
||||
return ErrResp(http.StatusNotFound, err, "Unable to find datasource")
|
||||
}
|
||||
return ErrResp(http.StatusInternalServerError, err, "Unable to load datasource meta data")
|
||||
}
|
||||
|
||||
impl := ds.JsonData.Get("implementation").MustString(defaultImplementation)
|
||||
implEndpoints, ok := endpoints[impl]
|
||||
if !ok {
|
||||
return ErrResp(http.StatusBadRequest, fmt.Errorf("unsupported Alert Manager implementation \"%s\"", impl), "")
|
||||
}
|
||||
endpointPath, ok := implEndpoints[endpoint]
|
||||
if !ok {
|
||||
return ErrResp(http.StatusBadRequest, fmt.Errorf("unsupported endpoint \"%s\" for Alert Manager implementation \"%s\"", endpoint, impl), "")
|
||||
}
|
||||
|
||||
iPathParams := make([]interface{}, len(pathParams))
|
||||
for idx, value := range pathParams {
|
||||
iPathParams[idx] = value
|
||||
}
|
||||
|
||||
return am.withReq(
|
||||
ctx,
|
||||
method,
|
||||
withPath(*ctx.Req.URL, fmt.Sprintf(endpointPath, iPathParams...)),
|
||||
body,
|
||||
extractor,
|
||||
headers,
|
||||
)
|
||||
}
|
||||
|
||||
func (am *LotexAM) RouteGetAMStatus(ctx *models.ReqContext) response.Response {
|
||||
return am.withAMReq(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
withPath(
|
||||
*ctx.Req.URL,
|
||||
amStatusPath,
|
||||
),
|
||||
"status",
|
||||
nil,
|
||||
nil,
|
||||
jsonExtractor(&apimodels.GettableStatus{}),
|
||||
nil,
|
||||
@@ -54,10 +112,11 @@ func (am *LotexAM) RouteCreateSilence(ctx *models.ReqContext, silenceBody apimod
|
||||
if err != nil {
|
||||
return ErrResp(500, err, "Failed marshal silence")
|
||||
}
|
||||
return am.withReq(
|
||||
return am.withAMReq(
|
||||
ctx,
|
||||
http.MethodPost,
|
||||
withPath(*ctx.Req.URL, amSilencesPath),
|
||||
"silences",
|
||||
nil,
|
||||
bytes.NewBuffer(blob),
|
||||
jsonExtractor(&apimodels.GettableSilence{}),
|
||||
map[string]string{"Content-Type": "application/json"},
|
||||
@@ -65,13 +124,11 @@ func (am *LotexAM) RouteCreateSilence(ctx *models.ReqContext, silenceBody apimod
|
||||
}
|
||||
|
||||
func (am *LotexAM) RouteDeleteAlertingConfig(ctx *models.ReqContext) response.Response {
|
||||
return am.withReq(
|
||||
return am.withAMReq(
|
||||
ctx,
|
||||
http.MethodDelete,
|
||||
withPath(
|
||||
*ctx.Req.URL,
|
||||
amConfigPath,
|
||||
),
|
||||
"config",
|
||||
nil,
|
||||
nil,
|
||||
messageExtractor,
|
||||
nil,
|
||||
@@ -79,13 +136,11 @@ func (am *LotexAM) RouteDeleteAlertingConfig(ctx *models.ReqContext) response.Re
|
||||
}
|
||||
|
||||
func (am *LotexAM) RouteDeleteSilence(ctx *models.ReqContext) response.Response {
|
||||
return am.withReq(
|
||||
return am.withAMReq(
|
||||
ctx,
|
||||
http.MethodDelete,
|
||||
withPath(
|
||||
*ctx.Req.URL,
|
||||
fmt.Sprintf(amSilencePath, macaron.Params(ctx.Req)[":SilenceId"]),
|
||||
),
|
||||
"silence",
|
||||
[]string{macaron.Params(ctx.Req)[":SilenceId"]},
|
||||
nil,
|
||||
messageExtractor,
|
||||
nil,
|
||||
@@ -93,13 +148,11 @@ func (am *LotexAM) RouteDeleteSilence(ctx *models.ReqContext) response.Response
|
||||
}
|
||||
|
||||
func (am *LotexAM) RouteGetAlertingConfig(ctx *models.ReqContext) response.Response {
|
||||
return am.withReq(
|
||||
return am.withAMReq(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
withPath(
|
||||
*ctx.Req.URL,
|
||||
amConfigPath,
|
||||
),
|
||||
"config",
|
||||
nil,
|
||||
nil,
|
||||
yamlExtractor(&apimodels.GettableUserConfig{}),
|
||||
nil,
|
||||
@@ -107,13 +160,11 @@ func (am *LotexAM) RouteGetAlertingConfig(ctx *models.ReqContext) response.Respo
|
||||
}
|
||||
|
||||
func (am *LotexAM) RouteGetAMAlertGroups(ctx *models.ReqContext) response.Response {
|
||||
return am.withReq(
|
||||
return am.withAMReq(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
withPath(
|
||||
*ctx.Req.URL,
|
||||
amAlertGroupsPath,
|
||||
),
|
||||
"groups",
|
||||
nil,
|
||||
nil,
|
||||
jsonExtractor(&apimodels.AlertGroups{}),
|
||||
nil,
|
||||
@@ -121,13 +172,11 @@ func (am *LotexAM) RouteGetAMAlertGroups(ctx *models.ReqContext) response.Respon
|
||||
}
|
||||
|
||||
func (am *LotexAM) RouteGetAMAlerts(ctx *models.ReqContext) response.Response {
|
||||
return am.withReq(
|
||||
return am.withAMReq(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
withPath(
|
||||
*ctx.Req.URL,
|
||||
amAlertsPath,
|
||||
),
|
||||
"alerts",
|
||||
nil,
|
||||
nil,
|
||||
jsonExtractor(&apimodels.GettableAlerts{}),
|
||||
nil,
|
||||
@@ -135,13 +184,11 @@ func (am *LotexAM) RouteGetAMAlerts(ctx *models.ReqContext) response.Response {
|
||||
}
|
||||
|
||||
func (am *LotexAM) RouteGetSilence(ctx *models.ReqContext) response.Response {
|
||||
return am.withReq(
|
||||
return am.withAMReq(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
withPath(
|
||||
*ctx.Req.URL,
|
||||
fmt.Sprintf(amSilencePath, macaron.Params(ctx.Req)[":SilenceId"]),
|
||||
),
|
||||
"silence",
|
||||
[]string{macaron.Params(ctx.Req)[":SilenceId"]},
|
||||
nil,
|
||||
jsonExtractor(&apimodels.GettableSilence{}),
|
||||
nil,
|
||||
@@ -149,13 +196,11 @@ func (am *LotexAM) RouteGetSilence(ctx *models.ReqContext) response.Response {
|
||||
}
|
||||
|
||||
func (am *LotexAM) RouteGetSilences(ctx *models.ReqContext) response.Response {
|
||||
return am.withReq(
|
||||
return am.withAMReq(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
withPath(
|
||||
*ctx.Req.URL,
|
||||
amSilencesPath,
|
||||
),
|
||||
"silences",
|
||||
nil,
|
||||
nil,
|
||||
jsonExtractor(&apimodels.GettableSilences{}),
|
||||
nil,
|
||||
@@ -168,10 +213,11 @@ func (am *LotexAM) RoutePostAlertingConfig(ctx *models.ReqContext, config apimod
|
||||
return ErrResp(500, err, "Failed marshal alert manager configuration ")
|
||||
}
|
||||
|
||||
return am.withReq(
|
||||
return am.withAMReq(
|
||||
ctx,
|
||||
http.MethodPost,
|
||||
withPath(*ctx.Req.URL, amConfigPath),
|
||||
"config",
|
||||
nil,
|
||||
bytes.NewBuffer(yml),
|
||||
messageExtractor,
|
||||
nil,
|
||||
@@ -184,10 +230,11 @@ func (am *LotexAM) RoutePostAMAlerts(ctx *models.ReqContext, alerts apimodels.Po
|
||||
return ErrResp(500, err, "Failed marshal postable alerts")
|
||||
}
|
||||
|
||||
return am.withReq(
|
||||
return am.withAMReq(
|
||||
ctx,
|
||||
http.MethodPost,
|
||||
withPath(*ctx.Req.URL, amAlertsPath),
|
||||
"alerts",
|
||||
nil,
|
||||
bytes.NewBuffer(yml),
|
||||
messageExtractor,
|
||||
nil,
|
||||
|
||||
Reference in New Issue
Block a user