| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2022-01-15 00:55:57 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/api/response" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/models" | 
					
						
							| 
									
										
										
										
											2021-04-20 02:26:04 +08:00
										 |  |  | 	apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/web" | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	"gopkg.in/yaml.v3" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 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", | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	defaultImplementation = "cortex" | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type LotexAM struct { | 
					
						
							|  |  |  | 	log log.Logger | 
					
						
							|  |  |  | 	*AlertingProxy | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewLotexAM(proxy *AlertingProxy, log log.Logger) *LotexAM { | 
					
						
							|  |  |  | 	return &LotexAM{ | 
					
						
							|  |  |  | 		log:           log, | 
					
						
							|  |  |  | 		AlertingProxy: proxy, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 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 { | 
					
						
							| 
									
										
										
										
											2022-01-15 00:55:57 +08:00
										 |  |  | 	recipient, err := strconv.ParseInt(web.Params(ctx.Req)[":Recipient"], 10, 64) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return response.Error(http.StatusBadRequest, "Recipient is invalid", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ds, err := am.DataProxy.DataSourceCache.GetDatasource(ctx.Req.Context(), recipient, ctx.SignedInUser, ctx.SkipCache) | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	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 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-16 00:14:02 +08:00
										 |  |  | 	return am.withReq( | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		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( | 
					
						
							| 
									
										
										
										
											2021-06-16 00:14:02 +08:00
										 |  |  | 		ctx, | 
					
						
							|  |  |  | 		http.MethodGet, | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		"status", | 
					
						
							|  |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-06-16 00:14:02 +08:00
										 |  |  | 		nil, | 
					
						
							|  |  |  | 		jsonExtractor(&apimodels.GettableStatus{}), | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 04:00:56 +08:00
										 |  |  | func (am *LotexAM) RouteCreateSilence(ctx *models.ReqContext, silenceBody apimodels.PostableSilence) response.Response { | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	blob, err := json.Marshal(silenceBody) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(500, err, "Failed marshal silence") | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	return am.withAMReq( | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		ctx, | 
					
						
							|  |  |  | 		http.MethodPost, | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		"silences", | 
					
						
							|  |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		bytes.NewBuffer(blob), | 
					
						
							|  |  |  | 		jsonExtractor(&apimodels.GettableSilence{}), | 
					
						
							|  |  |  | 		map[string]string{"Content-Type": "application/json"}, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (am *LotexAM) RouteDeleteAlertingConfig(ctx *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	return am.withAMReq( | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		ctx, | 
					
						
							|  |  |  | 		http.MethodDelete, | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		"config", | 
					
						
							|  |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 		messageExtractor, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (am *LotexAM) RouteDeleteSilence(ctx *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	return am.withAMReq( | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		ctx, | 
					
						
							|  |  |  | 		http.MethodDelete, | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		"silence", | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 		[]string{web.Params(ctx.Req)[":SilenceId"]}, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 		messageExtractor, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (am *LotexAM) RouteGetAlertingConfig(ctx *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	return am.withAMReq( | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		ctx, | 
					
						
							|  |  |  | 		http.MethodGet, | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		"config", | 
					
						
							|  |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-04-07 13:42:43 +08:00
										 |  |  | 		yamlExtractor(&apimodels.GettableUserConfig{}), | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (am *LotexAM) RouteGetAMAlertGroups(ctx *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	return am.withAMReq( | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		ctx, | 
					
						
							|  |  |  | 		http.MethodGet, | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		"groups", | 
					
						
							|  |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 		jsonExtractor(&apimodels.AlertGroups{}), | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (am *LotexAM) RouteGetAMAlerts(ctx *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	return am.withAMReq( | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		ctx, | 
					
						
							|  |  |  | 		http.MethodGet, | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		"alerts", | 
					
						
							|  |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 		jsonExtractor(&apimodels.GettableAlerts{}), | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (am *LotexAM) RouteGetSilence(ctx *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	return am.withAMReq( | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		ctx, | 
					
						
							|  |  |  | 		http.MethodGet, | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		"silence", | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 		[]string{web.Params(ctx.Req)[":SilenceId"]}, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 		jsonExtractor(&apimodels.GettableSilence{}), | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (am *LotexAM) RouteGetSilences(ctx *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	return am.withAMReq( | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		ctx, | 
					
						
							|  |  |  | 		http.MethodGet, | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		"silences", | 
					
						
							|  |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 		jsonExtractor(&apimodels.GettableSilences{}), | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (am *LotexAM) RoutePostAlertingConfig(ctx *models.ReqContext, config apimodels.PostableUserConfig) response.Response { | 
					
						
							| 
									
										
										
										
											2021-04-12 17:04:37 +08:00
										 |  |  | 	yml, err := yaml.Marshal(&config) | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(500, err, "Failed marshal alert manager configuration ") | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	return am.withAMReq( | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		ctx, | 
					
						
							|  |  |  | 		http.MethodPost, | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		"config", | 
					
						
							|  |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		bytes.NewBuffer(yml), | 
					
						
							|  |  |  | 		messageExtractor, | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (am *LotexAM) RoutePostAMAlerts(ctx *models.ReqContext, alerts apimodels.PostableAlerts) response.Response { | 
					
						
							|  |  |  | 	yml, err := yaml.Marshal(alerts) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(500, err, "Failed marshal postable alerts") | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 	return am.withAMReq( | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		ctx, | 
					
						
							|  |  |  | 		http.MethodPost, | 
					
						
							| 
									
										
										
										
											2021-10-01 21:24:56 +08:00
										 |  |  | 		"alerts", | 
					
						
							|  |  |  | 		nil, | 
					
						
							| 
									
										
										
										
											2021-04-08 03:36:50 +08:00
										 |  |  | 		bytes.NewBuffer(yml), | 
					
						
							|  |  |  | 		messageExtractor, | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-03-29 23:18:25 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-08-17 20:49:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-01 03:55:54 +08:00
										 |  |  | func (am *LotexAM) RoutePostTestReceivers(ctx *models.ReqContext, config apimodels.TestReceiversConfigBodyParams) response.Response { | 
					
						
							| 
									
										
										
										
											2021-08-17 20:49:05 +08:00
										 |  |  | 	return NotImplementedResp | 
					
						
							|  |  |  | } |