The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/ngalert/api/api_alertmanager_silences.go

112 lines
5.1 KiB

package api
import (
"context"
"net/http"
"github.com/go-openapi/strfmt"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/apimachinery/identity"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/util"
)
// SilenceService is the service for managing and authenticating silences access in Grafana AM.
type SilenceService interface {
GetSilence(ctx context.Context, user identity.Requester, silenceID string) (*models.Silence, error)
ListSilences(ctx context.Context, user identity.Requester, filter []string) ([]*models.Silence, error)
CreateSilence(ctx context.Context, user identity.Requester, ps models.Silence) (string, error)
UpdateSilence(ctx context.Context, user identity.Requester, ps models.Silence) (string, error)
DeleteSilence(ctx context.Context, user identity.Requester, silenceID string) error
WithAccessControlMetadata(ctx context.Context, user identity.Requester, silencesWithMetadata ...*models.SilenceWithMetadata) error
WithRuleMetadata(ctx context.Context, user identity.Requester, silences ...*models.SilenceWithMetadata) error
}
// RouteGetSilence is the single silence GET endpoint for Grafana AM.
func (srv AlertmanagerSrv) RouteGetSilence(c *contextmodel.ReqContext, silenceID string) response.Response {
silence, err := srv.silenceSvc.GetSilence(c.Req.Context(), c.SignedInUser, silenceID)
if err != nil {
return response.ErrOrFallback(http.StatusInternalServerError, "failed to get silence", err)
}
silenceWithMetadata := &models.SilenceWithMetadata{
Silence: silence,
}
if c.QueryBool("accesscontrol") {
if err := srv.silenceSvc.WithAccessControlMetadata(c.Req.Context(), c.SignedInUser, silenceWithMetadata); err != nil {
srv.log.Error("failed to get silence access control metadata", "silenceID", silenceID, "error", err)
}
}
if c.QueryBool("ruleMetadata") {
if err := srv.silenceSvc.WithRuleMetadata(c.Req.Context(), c.SignedInUser, silenceWithMetadata); err != nil {
srv.log.Error("failed to get silence rule metadata", "silenceID", silenceID, "error", err)
}
}
return response.JSON(http.StatusOK, SilenceToGettableGrafanaSilence(silenceWithMetadata))
}
// RouteGetSilences is the silence list GET endpoint for Grafana AM.
func (srv AlertmanagerSrv) RouteGetSilences(c *contextmodel.ReqContext) response.Response {
silences, err := srv.silenceSvc.ListSilences(c.Req.Context(), c.SignedInUser, c.QueryStrings("filter"))
if err != nil {
return response.ErrOrFallback(http.StatusInternalServerError, "failed to list silence", err)
}
silencesWithMetadata := withEmptyMetadata(silences...)
if c.QueryBool("accesscontrol") {
if err := srv.silenceSvc.WithAccessControlMetadata(c.Req.Context(), c.SignedInUser, silencesWithMetadata...); err != nil {
srv.log.Error("failed to get silence access control metadata", "error", err)
}
}
if c.QueryBool("ruleMetadata") {
if err := srv.silenceSvc.WithRuleMetadata(c.Req.Context(), c.SignedInUser, silencesWithMetadata...); err != nil {
srv.log.Error("failed to get silence rule metadata", "error", err)
}
}
return response.JSON(http.StatusOK, SilencesToGettableGrafanaSilences(silencesWithMetadata))
}
// RouteCreateSilence is the silence POST (create + update) endpoint for Grafana AM.
func (srv AlertmanagerSrv) RouteCreateSilence(c *contextmodel.ReqContext, postableSilence apimodels.PostableSilence) response.Response {
err := postableSilence.Validate(strfmt.Default)
if err != nil {
srv.log.Error("Silence failed validation", "error", err)
return ErrResp(http.StatusBadRequest, err, "silence failed validation")
}
action := srv.silenceSvc.UpdateSilence
if postableSilence.ID == "" {
action = srv.silenceSvc.CreateSilence
}
silenceID, err := action(c.Req.Context(), c.SignedInUser, PostableSilenceToSilence(postableSilence))
if err != nil {
return response.ErrOrFallback(http.StatusInternalServerError, "failed to create/update silence", err)
}
return response.JSON(http.StatusAccepted, apimodels.PostSilencesOKBody{
SilenceID: silenceID,
})
}
// RouteDeleteSilence is the silence DELETE endpoint for Grafana AM.
func (srv AlertmanagerSrv) RouteDeleteSilence(c *contextmodel.ReqContext, silenceID string) response.Response {
if err := srv.silenceSvc.DeleteSilence(c.Req.Context(), c.SignedInUser, silenceID); err != nil {
return response.ErrOrFallback(http.StatusInternalServerError, "failed to delete silence", err)
}
return response.JSON(http.StatusOK, util.DynMap{"message": "silence deleted"})
}
// withEmptyMetadata creates a slice of SilenceWithMetadata from a slice of Silence where the metadata for each silence
// is empty.
func withEmptyMetadata(silences ...*models.Silence) []*models.SilenceWithMetadata {
silencesWithMetadata := make([]*models.SilenceWithMetadata, 0, len(silences))
for _, silence := range silences {
silencesWithMetadata = append(silencesWithMetadata, &models.SilenceWithMetadata{
Silence: silence,
})
}
return silencesWithMetadata
}