grafana/pkg/services/ngalert/api/api_provisioning.go
Alexander Weaver 60ec10566f
Extract Route validation from serialization methods so it can be re-used (#47649)
* Extract validation and reject invalid policies

* Validation in dedicated file

* Tests for validation

* Extract root route validation

* Update call and drop TODO

* empty commit to kick actions

* Normalization should be idempotent

* Cleaner representation of validation errors, chain errors properly

* Make internal validate unexported

* Fix missed rename

* Genericize error message

* Improve method names

* Rebase, fix

* Update asserts
2022-04-27 15:15:41 -05:00

98 lines
4.0 KiB
Go

package api
import (
"context"
"errors"
"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"
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"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
)
type ProvisioningSrv struct {
log log.Logger
policies NotificationPolicyService
contactPointService ContactPointService
}
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
DeleteContactPoint(ctx context.Context, orgID int64, uid 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
}
func (srv *ProvisioningSrv) RouteGetPolicyTree(c *models.ReqContext) response.Response {
policies, err := srv.policies.GetPolicyTree(c.Req.Context(), c.OrgId)
if errors.Is(err, store.ErrNoAlertmanagerConfiguration) {
return ErrResp(http.StatusNotFound, err, "")
}
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
return response.JSON(http.StatusOK, policies)
}
func (srv *ProvisioningSrv) RoutePostPolicyTree(c *models.ReqContext, tree apimodels.Route) response.Response {
// TODO: lift validation out of definitions.Rotue.UnmarshalJSON and friends into a dedicated validator.
err := srv.policies.UpdatePolicyTree(c.Req.Context(), c.OrgId, tree, alerting_models.ProvenanceAPI)
if errors.Is(err, store.ErrNoAlertmanagerConfiguration) {
return ErrResp(http.StatusNotFound, err, "")
}
if errors.Is(err, provisioning.ErrValidation) {
return ErrResp(http.StatusBadRequest, err, "")
}
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
return response.JSON(http.StatusAccepted, util.DynMap{"message": "policies updated"})
}
func (srv *ProvisioningSrv) RouteGetContactPoints(c *models.ReqContext) response.Response {
cps, err := srv.contactPointService.GetContactPoints(c.Req.Context(), c.OrgId)
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
return response.JSON(http.StatusOK, cps)
}
func (srv *ProvisioningSrv) RoutePostContactPoint(c *models.ReqContext, cp apimodels.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 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 {
err := srv.contactPointService.UpdateContactPoint(c.Req.Context(), c.OrgId, cp, alerting_models.ProvenanceAPI)
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
return response.JSON(http.StatusAccepted, util.DynMap{"message": "contactpoint updated"})
}
func (srv *ProvisioningSrv) RouteDeleteContactPoint(c *models.ReqContext) response.Response {
cpID := web.Params(c.Req)[":ID"]
err := srv.contactPointService.DeleteContactPoint(c.Req.Context(), c.OrgId, cpID)
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "")
}
return response.JSON(http.StatusAccepted, util.DynMap{"message": "contactpoint deleted"})
}