package api import ( "bytes" "encoding/json" "fmt" "net/http" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" "gopkg.in/yaml.v3" ) const ( amSilencesPath = "/alertmanager/api/v2/silences" amSilencePath = "/alertmanager/api/v2/silence/%s" amAlertGroupsPath = "/alertmanager/api/v2/alerts/groups" amAlertsPath = "/alertmanager/api/v2/alerts" amConfigPath = "/api/v1/alerts" ) type LotexAM struct { log log.Logger *AlertingProxy } func NewLotexAM(proxy *AlertingProxy, log log.Logger) *LotexAM { return &LotexAM{ log: log, AlertingProxy: proxy, } } func (am *LotexAM) RouteCreateSilence(ctx *models.ReqContext, silenceBody apimodels.PostableSilence) response.Response { blob, err := json.Marshal(silenceBody) if err != nil { return response.Error(500, "Failed marshal silence", err) } return am.withReq( ctx, http.MethodPost, withPath(*ctx.Req.URL, amSilencesPath), bytes.NewBuffer(blob), jsonExtractor(&apimodels.GettableSilence{}), map[string]string{"Content-Type": "application/json"}, ) } func (am *LotexAM) RouteDeleteAlertingConfig(ctx *models.ReqContext) response.Response { return am.withReq( ctx, http.MethodDelete, withPath( *ctx.Req.URL, amConfigPath, ), nil, messageExtractor, nil, ) } func (am *LotexAM) RouteDeleteSilence(ctx *models.ReqContext) response.Response { return am.withReq( ctx, http.MethodDelete, withPath( *ctx.Req.URL, fmt.Sprintf(amSilencePath, ctx.Params(":SilenceId")), ), nil, messageExtractor, nil, ) } func (am *LotexAM) RouteGetAlertingConfig(ctx *models.ReqContext) response.Response { return am.withReq( ctx, http.MethodGet, withPath( *ctx.Req.URL, amConfigPath, ), nil, yamlExtractor(&apimodels.GettableUserConfig{}), nil, ) } func (am *LotexAM) RouteGetAMAlertGroups(ctx *models.ReqContext) response.Response { return am.withReq( ctx, http.MethodGet, withPath( *ctx.Req.URL, amAlertGroupsPath, ), nil, jsonExtractor(&apimodels.AlertGroups{}), nil, ) } func (am *LotexAM) RouteGetAMAlerts(ctx *models.ReqContext) response.Response { return am.withReq( ctx, http.MethodGet, withPath( *ctx.Req.URL, amAlertsPath, ), nil, jsonExtractor(&apimodels.GettableAlerts{}), nil, ) } func (am *LotexAM) RouteGetSilence(ctx *models.ReqContext) response.Response { return am.withReq( ctx, http.MethodGet, withPath( *ctx.Req.URL, fmt.Sprintf(amSilencePath, ctx.Params(":SilenceId")), ), nil, jsonExtractor(&apimodels.GettableSilence{}), nil, ) } func (am *LotexAM) RouteGetSilences(ctx *models.ReqContext) response.Response { return am.withReq( ctx, http.MethodGet, withPath( *ctx.Req.URL, amSilencesPath, ), nil, jsonExtractor(&apimodels.GettableSilences{}), nil, ) } func (am *LotexAM) RoutePostAlertingConfig(ctx *models.ReqContext, config apimodels.PostableUserConfig) response.Response { yml, err := yaml.Marshal(&config) if err != nil { return response.Error(500, "Failed marshal alert manager configuration ", err) } return am.withReq( ctx, http.MethodPost, withPath(*ctx.Req.URL, amConfigPath), bytes.NewBuffer(yml), messageExtractor, nil, ) } func (am *LotexAM) RoutePostAMAlerts(ctx *models.ReqContext, alerts apimodels.PostableAlerts) response.Response { yml, err := yaml.Marshal(alerts) if err != nil { return response.Error(500, "Failed marshal postable alerts", err) } return am.withReq( ctx, http.MethodPost, withPath(*ctx.Req.URL, amAlertsPath), bytes.NewBuffer(yml), messageExtractor, nil, ) }