Alerting: Fix provisioning validation status codes and panics (#50464)

* Updates to all except alert rules

* Return 400 when rules fail to validate, add testinfra

* More sane package aliases

* More package alias renames

* One more bug in contact point validation

* remove unused function

Co-authored-by: Jean-Philippe Quémémer <jeanphilippe.quemener@grafana.com>
Co-authored-by: Jean-Philippe Quéméner <JohnnyQQQQ@users.noreply.github.com>
This commit is contained in:
Alexander Weaver
2022-06-09 10:38:46 +02:00
committed by GitHub
co-authored by Jean-Philippe Quémémer Jean-Philippe Quéméner
parent 52deb821d6
commit 7dd78fee2c
9 changed files with 533 additions and 197 deletions
+39 -24
View File
@@ -8,7 +8,7 @@ import (
"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"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
alerting_models "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/provisioning"
"github.com/grafana/grafana/pkg/services/ngalert/store"
@@ -33,27 +33,27 @@ type ProvisioningSrv struct {
}
type ContactPointService interface {
GetContactPoints(ctx context.Context, orgID int64) ([]apimodels.EmbeddedContactPoint, error)
CreateContactPoint(ctx context.Context, orgID int64, contactPoint apimodels.EmbeddedContactPoint, p alerting_models.Provenance) (apimodels.EmbeddedContactPoint, error)
UpdateContactPoint(ctx context.Context, orgID int64, contactPoint apimodels.EmbeddedContactPoint, p alerting_models.Provenance) error
GetContactPoints(ctx context.Context, orgID int64) ([]definitions.EmbeddedContactPoint, error)
CreateContactPoint(ctx context.Context, orgID int64, contactPoint definitions.EmbeddedContactPoint, p alerting_models.Provenance) (definitions.EmbeddedContactPoint, error)
UpdateContactPoint(ctx context.Context, orgID int64, contactPoint definitions.EmbeddedContactPoint, p alerting_models.Provenance) error
DeleteContactPoint(ctx context.Context, orgID int64, uid string) error
}
type TemplateService interface {
GetTemplates(ctx context.Context, orgID int64) (map[string]string, error)
SetTemplate(ctx context.Context, orgID int64, tmpl apimodels.MessageTemplate) (apimodels.MessageTemplate, error)
SetTemplate(ctx context.Context, orgID int64, tmpl definitions.MessageTemplate) (definitions.MessageTemplate, error)
DeleteTemplate(ctx context.Context, orgID int64, name string) error
}
type NotificationPolicyService interface {
GetPolicyTree(ctx context.Context, orgID int64) (apimodels.Route, error)
UpdatePolicyTree(ctx context.Context, orgID int64, tree apimodels.Route, p alerting_models.Provenance) error
GetPolicyTree(ctx context.Context, orgID int64) (definitions.Route, error)
UpdatePolicyTree(ctx context.Context, orgID int64, tree definitions.Route, p alerting_models.Provenance) error
}
type MuteTimingService interface {
GetMuteTimings(ctx context.Context, orgID int64) ([]apimodels.MuteTimeInterval, error)
CreateMuteTiming(ctx context.Context, mt apimodels.MuteTimeInterval, orgID int64) (*apimodels.MuteTimeInterval, error)
UpdateMuteTiming(ctx context.Context, mt apimodels.MuteTimeInterval, orgID int64) (*apimodels.MuteTimeInterval, error)
GetMuteTimings(ctx context.Context, orgID int64) ([]definitions.MuteTimeInterval, error)
CreateMuteTiming(ctx context.Context, mt definitions.MuteTimeInterval, orgID int64) (*definitions.MuteTimeInterval, error)
UpdateMuteTiming(ctx context.Context, mt definitions.MuteTimeInterval, orgID int64) (*definitions.MuteTimeInterval, error)
DeleteMuteTiming(ctx context.Context, name string, orgID int64) error
}
@@ -77,7 +77,7 @@ func (srv *ProvisioningSrv) RouteGetPolicyTree(c *models.ReqContext) response.Re
return response.JSON(http.StatusOK, policies)
}
func (srv *ProvisioningSrv) RoutePutPolicyTree(c *models.ReqContext, tree apimodels.Route) response.Response {
func (srv *ProvisioningSrv) RoutePutPolicyTree(c *models.ReqContext, tree definitions.Route) response.Response {
err := srv.policies.UpdatePolicyTree(c.Req.Context(), c.OrgId, tree, alerting_models.ProvenanceAPI)
if errors.Is(err, store.ErrNoAlertmanagerConfiguration) {
return ErrResp(http.StatusNotFound, err, "")
@@ -100,18 +100,24 @@ func (srv *ProvisioningSrv) RouteGetContactPoints(c *models.ReqContext) response
return response.JSON(http.StatusOK, cps)
}
func (srv *ProvisioningSrv) RoutePostContactPoint(c *models.ReqContext, cp apimodels.EmbeddedContactPoint) response.Response {
func (srv *ProvisioningSrv) RoutePostContactPoint(c *models.ReqContext, cp definitions.EmbeddedContactPoint) response.Response {
// TODO: provenance is hardcoded for now, change it later to make it more flexible
contactPoint, err := srv.contactPointService.CreateContactPoint(c.Req.Context(), c.OrgId, cp, alerting_models.ProvenanceAPI)
if errors.Is(err, provisioning.ErrValidation) {
return ErrResp(http.StatusBadRequest, err, "")
}
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
return response.JSON(http.StatusAccepted, contactPoint)
}
func (srv *ProvisioningSrv) RoutePutContactPoint(c *models.ReqContext, cp apimodels.EmbeddedContactPoint) response.Response {
func (srv *ProvisioningSrv) RoutePutContactPoint(c *models.ReqContext, cp definitions.EmbeddedContactPoint) response.Response {
cp.UID = pathParam(c, uidPathParam)
err := srv.contactPointService.UpdateContactPoint(c.Req.Context(), c.OrgId, cp, alerting_models.ProvenanceAPI)
if errors.Is(err, provisioning.ErrValidation) {
return ErrResp(http.StatusBadRequest, err, "")
}
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
@@ -132,9 +138,9 @@ func (srv *ProvisioningSrv) RouteGetTemplates(c *models.ReqContext) response.Res
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
result := make([]apimodels.MessageTemplate, 0, len(templates))
result := make([]definitions.MessageTemplate, 0, len(templates))
for k, v := range templates {
result = append(result, apimodels.MessageTemplate{Name: k, Template: v})
result = append(result, definitions.MessageTemplate{Name: k, Template: v})
}
return response.JSON(http.StatusOK, result)
}
@@ -146,14 +152,14 @@ func (srv *ProvisioningSrv) RouteGetTemplate(c *models.ReqContext) response.Resp
return ErrResp(http.StatusInternalServerError, err, "")
}
if tmpl, ok := templates[name]; ok {
return response.JSON(http.StatusOK, apimodels.MessageTemplate{Name: name, Template: tmpl})
return response.JSON(http.StatusOK, definitions.MessageTemplate{Name: name, Template: tmpl})
}
return response.Empty(http.StatusNotFound)
}
func (srv *ProvisioningSrv) RoutePutTemplate(c *models.ReqContext, body apimodels.MessageTemplateContent) response.Response {
func (srv *ProvisioningSrv) RoutePutTemplate(c *models.ReqContext, body definitions.MessageTemplateContent) response.Response {
name := pathParam(c, namePathParam)
tmpl := apimodels.MessageTemplate{
tmpl := definitions.MessageTemplate{
Name: name,
Template: body.Template,
Provenance: alerting_models.ProvenanceAPI,
@@ -199,7 +205,7 @@ func (srv *ProvisioningSrv) RouteGetMuteTimings(c *models.ReqContext) response.R
return response.JSON(http.StatusOK, timings)
}
func (srv *ProvisioningSrv) RoutePostMuteTiming(c *models.ReqContext, mt apimodels.MuteTimeInterval) response.Response {
func (srv *ProvisioningSrv) RoutePostMuteTiming(c *models.ReqContext, mt definitions.MuteTimeInterval) response.Response {
created, err := srv.muteTimings.CreateMuteTiming(c.Req.Context(), mt, c.OrgId)
if err != nil {
if errors.Is(err, provisioning.ErrValidation) {
@@ -210,7 +216,7 @@ func (srv *ProvisioningSrv) RoutePostMuteTiming(c *models.ReqContext, mt apimode
return response.JSON(http.StatusCreated, created)
}
func (srv *ProvisioningSrv) RoutePutMuteTiming(c *models.ReqContext, mt apimodels.MuteTimeInterval) response.Response {
func (srv *ProvisioningSrv) RoutePutMuteTiming(c *models.ReqContext, mt definitions.MuteTimeInterval) response.Response {
name := pathParam(c, namePathParam)
mt.Name = name
updated, err := srv.muteTimings.UpdateMuteTiming(c.Req.Context(), mt, c.OrgId)
@@ -241,11 +247,14 @@ func (srv *ProvisioningSrv) RouteRouteGetAlertRule(c *models.ReqContext) respons
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
return response.JSON(http.StatusOK, apimodels.NewAlertRule(rule, provenace))
return response.JSON(http.StatusOK, definitions.NewAlertRule(rule, provenace))
}
func (srv *ProvisioningSrv) RoutePostAlertRule(c *models.ReqContext, ar apimodels.AlertRule) response.Response {
func (srv *ProvisioningSrv) RoutePostAlertRule(c *models.ReqContext, ar definitions.AlertRule) response.Response {
createdAlertRule, err := srv.alertRules.CreateAlertRule(c.Req.Context(), ar.UpstreamModel(), alerting_models.ProvenanceAPI)
if errors.Is(err, alerting_models.ErrAlertRuleFailedValidation) {
return ErrResp(http.StatusBadRequest, err, "")
}
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
@@ -255,8 +264,14 @@ func (srv *ProvisioningSrv) RoutePostAlertRule(c *models.ReqContext, ar apimodel
return response.JSON(http.StatusCreated, ar)
}
func (srv *ProvisioningSrv) RoutePutAlertRule(c *models.ReqContext, ar apimodels.AlertRule) response.Response {
func (srv *ProvisioningSrv) RoutePutAlertRule(c *models.ReqContext, ar definitions.AlertRule) response.Response {
updatedAlertRule, err := srv.alertRules.UpdateAlertRule(c.Req.Context(), ar.UpstreamModel(), alerting_models.ProvenanceAPI)
if errors.Is(err, alerting_models.ErrAlertRuleNotFound) {
return response.Empty(http.StatusNotFound)
}
if errors.Is(err, alerting_models.ErrAlertRuleFailedValidation) {
return ErrResp(http.StatusBadRequest, err, "")
}
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
@@ -273,7 +288,7 @@ func (srv *ProvisioningSrv) RouteDeleteAlertRule(c *models.ReqContext) response.
return response.JSON(http.StatusNoContent, "")
}
func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *models.ReqContext, ag apimodels.AlertRuleGroup) response.Response {
func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *models.ReqContext, ag definitions.AlertRuleGroup) response.Response {
rulegroup := pathParam(c, groupPathParam)
folderUID := pathParam(c, folderUIDPathParam)
err := srv.alertRules.UpdateRuleGroup(c.Req.Context(), c.OrgId, folderUID, rulegroup, ag.Interval)