Files
grafana/pkg/services/ngalert/api/tooling/definitions/alertmanager.go
T
Matthew Jacobson 2466685a41 Alerting: Improve template testing by trying non-root scopes (#101471)
Expand template testing to try additional scopes if the root scope fails.
This mitigates errors for definitions like pagerduty.default.instances,
which require the .Alerts scope. Added support for .Alerts and .Alert
scopes.
2025-02-28 20:27:27 +02:00

1015 lines
30 KiB
Go

package definitions
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/go-openapi/strfmt"
"github.com/mohae/deepcopy"
amv2 "github.com/prometheus/alertmanager/api/v2/models"
"github.com/prometheus/alertmanager/config"
"github.com/prometheus/common/model"
"gopkg.in/yaml.v3"
"github.com/grafana/alerting/definition"
alertingmodels "github.com/grafana/alerting/models"
)
// swagger:route POST /alertmanager/grafana/config/api/v1/alerts alertmanager RoutePostGrafanaAlertingConfig
//
// sets an Alerting config
//
// This API is designated to internal use only and can be removed or changed at any time without prior notice.
//
// Deprecated: true
// Responses:
// 201: Ack
// 400: ValidationError
// swagger:route POST /alertmanager/{DatasourceUID}/config/api/v1/alerts alertmanager RoutePostAlertingConfig
//
// sets an Alerting config
//
// Responses:
// 201: Ack
// 400: ValidationError
// 404: NotFound
// swagger:route GET /alertmanager/grafana/config/api/v1/alerts alertmanager RouteGetGrafanaAlertingConfig
//
// gets an Alerting config
//
// This API is designated to internal use only and can be removed or changed at any time without prior notice.
//
// Deprecated: true
//
// Responses:
// 200: GettableUserConfig
// 400: ValidationError
// swagger:route GET /alertmanager/{DatasourceUID}/config/api/v1/alerts alertmanager RouteGetAlertingConfig
//
// gets an Alerting config
//
// Responses:
// 200: GettableUserConfig
// 400: ValidationError
// 404: NotFound
// swagger:route GET /alertmanager/grafana/config/history alertmanager RouteGetGrafanaAlertingConfigHistory
//
// gets Alerting configurations that were successfully applied in the past
//
// This API is designated to internal use only and can be removed or changed at any time without prior notice.
//
// Deprecated: true
// Responses:
// 200: GettableHistoricUserConfigs
// swagger:route POST /alertmanager/grafana/config/history/{id}/_activate alertmanager RoutePostGrafanaAlertingConfigHistoryActivate
//
// revert Alerting configuration to the historical configuration specified by the given id
//
// This API is designated to internal use only and can be removed or changed at any time without prior notice.
//
// Deprecated: true
// Responses:
// 202: Ack
// 400: ValidationError
// 404: NotFound
// swagger:route DELETE /alertmanager/grafana/config/api/v1/alerts alertmanager RouteDeleteGrafanaAlertingConfig
//
// deletes the Alerting config for a tenant
//
// This API is designated to internal use only and can be removed or changed at any time without prior notice.
//
// Deprecated: true
// Responses:
// 200: Ack
// 400: ValidationError
// swagger:route DELETE /alertmanager/{DatasourceUID}/config/api/v1/alerts alertmanager RouteDeleteAlertingConfig
//
// deletes the Alerting config for a tenant
//
// Responses:
// 200: Ack
// 400: ValidationError
// 404: NotFound
// swagger:route GET /alertmanager/grafana/api/v2/status alertmanager RouteGetGrafanaAMStatus
//
// get alertmanager status and configuration
//
// Responses:
// 200: GettableStatus
// 400: ValidationError
// swagger:route GET /alertmanager/{DatasourceUID}/api/v2/status alertmanager RouteGetAMStatus
//
// get alertmanager status and configuration
//
// Responses:
// 200: GettableStatus
// 400: ValidationError
// 404: NotFound
// swagger:route GET /alertmanager/grafana/api/v2/alerts alertmanager RouteGetGrafanaAMAlerts
//
// get alertmanager alerts
//
// Responses:
// 200: gettableAlerts
// 400: ValidationError
// swagger:route GET /alertmanager/{DatasourceUID}/api/v2/alerts alertmanager RouteGetAMAlerts
//
// get alertmanager alerts
//
// Responses:
// 200: gettableAlerts
// 400: ValidationError
// 404: NotFound
// swagger:route POST /alertmanager/{DatasourceUID}/api/v2/alerts alertmanager RoutePostAMAlerts
//
// create alertmanager alerts
//
// Responses:
// 200: Ack
// 400: ValidationError
// 404: NotFound
// swagger:route GET /alertmanager/grafana/api/v2/alerts/groups alertmanager RouteGetGrafanaAMAlertGroups
//
// get alertmanager alerts
//
// Responses:
// 200: alertGroups
// 400: ValidationError
// swagger:route GET /alertmanager/{DatasourceUID}/api/v2/alerts/groups alertmanager RouteGetAMAlertGroups
//
// get alertmanager alerts
//
// Responses:
// 200: alertGroups
// 400: ValidationError
// 404: NotFound
// swagger:route GET /alertmanager/grafana/config/api/v1/receivers alertmanager RouteGetGrafanaReceivers
//
// Get a list of all receivers
//
// Responses:
// 200: receiversResponse
// swagger:route POST /alertmanager/grafana/config/api/v1/receivers/test alertmanager RoutePostTestGrafanaReceivers
//
// Test Grafana managed receivers without saving them.
//
// Responses:
//
// 200: Ack
// 207: MultiStatus
// 400: ValidationError
// 403: PermissionDenied
// 404: NotFound
// 408: Failure
// 409: AlertManagerNotReady
// swagger:route POST /alertmanager/grafana/config/api/v1/templates/test alertmanager RoutePostTestGrafanaTemplates
//
// Test Grafana managed templates without saving them.
// Produces:
// - application/json
//
// Responses:
//
// 200: TestTemplatesResults
// 400: ValidationError
// 403: PermissionDenied
// 409: AlertManagerNotReady
// swagger:route GET /alertmanager/grafana/api/v2/silences alertmanager RouteGetGrafanaSilences
//
// get silences
//
// Responses:
// 200: gettableGrafanaSilences
// 400: ValidationError
// swagger:route GET /alertmanager/{DatasourceUID}/api/v2/silences alertmanager RouteGetSilences
//
// get silences
//
// Responses:
// 200: gettableSilences
// 400: ValidationError
// 404: NotFound
// swagger:route POST /alertmanager/grafana/api/v2/silences alertmanager RouteCreateGrafanaSilence
//
// create silence
//
// Responses:
// 202: postSilencesOKBody
// 400: ValidationError
// swagger:route POST /alertmanager/{DatasourceUID}/api/v2/silences alertmanager RouteCreateSilence
//
// create silence
//
// Responses:
// 201: postSilencesOKBody
// 400: ValidationError
// 404: NotFound
// swagger:route GET /alertmanager/grafana/api/v2/silence/{SilenceId} alertmanager RouteGetGrafanaSilence
//
// get silence
//
// Responses:
// 200: gettableGrafanaSilence
// 400: ValidationError
// swagger:route GET /alertmanager/{DatasourceUID}/api/v2/silence/{SilenceId} alertmanager RouteGetSilence
//
// get silence
//
// Responses:
// 200: gettableSilence
// 400: ValidationError
// 404: NotFound
// swagger:route DELETE /alertmanager/grafana/api/v2/silence/{SilenceId} alertmanager RouteDeleteGrafanaSilence
//
// delete silence
//
// Responses:
// 200: Ack
// 400: ValidationError
// swagger:route DELETE /alertmanager/{DatasourceUID}/api/v2/silence/{SilenceId} alertmanager RouteDeleteSilence
//
// delete silence
//
// Responses:
// 200: Ack
// 400: ValidationError
// 404: NotFound
// Alias all the needed Alertmanager types, functions and constants so that they can be imported directly from grafana/alerting
// without having to modify any of the usage within Grafana.
type (
Config = definition.Config
Route = definition.Route
PostableGrafanaReceiver = definition.PostableGrafanaReceiver
PostableApiAlertingConfig = definition.PostableApiAlertingConfig
RawMessage = definition.RawMessage
Provenance = definition.Provenance
ObjectMatchers = definition.ObjectMatchers
PostableApiReceiver = definition.PostableApiReceiver
PostableGrafanaReceivers = definition.PostableGrafanaReceivers
ReceiverType = definition.ReceiverType
)
const (
GrafanaReceiverType = definition.GrafanaReceiverType
AlertmanagerReceiverType = definition.AlertmanagerReceiverType
)
var (
AsGrafanaRoute = definition.AsGrafanaRoute
AllReceivers = definition.AllReceivers
)
// swagger:model
type PermissionDenied struct{}
// swagger:model
type AlertManagerNotReady struct{}
// swagger:model
type MultiStatus struct{}
// swagger:parameters RouteGetGrafanaAlertingConfigHistory
type RouteGetGrafanaAlertingConfigHistoryParams struct {
// Limit response to n historic configurations.
// in:query
Limit int `json:"limit"`
}
// swagger:parameters RoutePostTestGrafanaReceivers
type TestReceiversConfigParams struct {
// in:body
Body TestReceiversConfigBodyParams
}
type TestReceiversConfigBodyParams struct {
Alert *TestReceiversConfigAlertParams `yaml:"alert,omitempty" json:"alert,omitempty"`
Receivers []*PostableApiReceiver `yaml:"receivers,omitempty" json:"receivers,omitempty"`
}
type TestReceiversConfigAlertParams struct {
Annotations model.LabelSet `yaml:"annotations,omitempty" json:"annotations,omitempty"`
Labels model.LabelSet `yaml:"labels,omitempty" json:"labels,omitempty"`
}
// swagger:model
type TestReceiversResult struct {
Alert TestReceiversConfigAlertParams `json:"alert"`
Receivers []TestReceiverResult `json:"receivers"`
NotifiedAt time.Time `json:"notified_at"`
}
// swagger:model
type TestReceiverResult struct {
Name string `json:"name"`
Configs []TestReceiverConfigResult `json:"grafana_managed_receiver_configs"`
}
// swagger:model
type TestReceiverConfigResult struct {
Name string `json:"name"`
UID string `json:"uid"`
Status string `json:"status"`
Error string `json:"error,omitempty"`
}
// swagger:parameters RoutePostTestGrafanaTemplates
type TestTemplatesConfigParams struct {
// in:body
Body TestTemplatesConfigBodyParams
}
type TestTemplatesConfigBodyParams struct {
// Alerts to use as data when testing the template.
Alerts []*amv2.PostableAlert `json:"alerts"`
// Template string to test.
Template string `json:"template"`
// Name of the template file.
Name string `json:"name"`
}
// swagger:model
type TestTemplatesResults struct {
Results []TestTemplatesResult `json:"results,omitempty"`
Errors []TestTemplatesErrorResult `json:"errors,omitempty"`
}
type TestTemplatesResult struct {
// Name of the associated template definition for this result.
Name string `json:"name"`
// Interpolated value of the template.
Text string `json:"text"`
// Scope that was successfully used to interpolate the template. If the root scope "." fails, more specific
// scopes will be tried, such as ".Alerts', or ".Alert".
Scope TemplateScope `json:"scope"`
}
type TestTemplatesErrorResult struct {
// Name of the associated template for this error. Will be empty if the Kind is "invalid_template".
Name string `json:"name,omitempty"`
// Kind of template error that occurred.
Kind TemplateErrorKind `json:"kind"`
// Error message.
Message string `json:"message"`
}
// swagger:enum TemplateErrorKind
type TemplateErrorKind string
const (
InvalidTemplate TemplateErrorKind = "invalid_template"
ExecutionError TemplateErrorKind = "execution_error"
)
// swagger:enum TemplateScope
type TemplateScope string
const (
RootScope TemplateScope = "."
AlertsScope TemplateScope = ".Alerts"
AlertScope TemplateScope = ".Alert"
)
// swagger:parameters RouteCreateSilence RouteCreateGrafanaSilence
type CreateSilenceParams struct {
// in:body
Silence PostableSilence
}
// swagger:parameters RouteGetSilence RouteDeleteSilence RouteGetGrafanaSilence RouteDeleteGrafanaSilence
type GetDeleteSilenceParams struct {
// in:path
SilenceId string
}
// swagger:parameters RouteGetSilences RouteGetGrafanaSilences
type GetSilencesParams struct {
// in:query
Filter []string `json:"filter"`
// Return rule metadata with silence.
// in:query
// required:false
RuleMetadata bool `json:"ruleMetadata"`
// Return access control metadata with silence.
// in:query
// required:false
AccessControl bool `json:"accesscontrol"`
}
// swagger:model
type GettableStatus struct {
// cluster
// Required: true
Cluster *amv2.ClusterStatus `json:"cluster"`
// config
// Required: true
Config *PostableApiAlertingConfig `json:"config"`
// uptime
// Required: true
// Format: date-time
Uptime *strfmt.DateTime `json:"uptime"`
// version info
// Required: true
VersionInfo *amv2.VersionInfo `json:"versionInfo"`
}
func (s *GettableStatus) UnmarshalJSON(b []byte) error {
amStatus := amv2.AlertmanagerStatus{}
if err := json.Unmarshal(b, &amStatus); err != nil {
return err
}
c := config.Config{}
if err := yaml.Unmarshal([]byte(*amStatus.Config.Original), &c); err != nil {
return err
}
s.Cluster = amStatus.Cluster
s.Config = &PostableApiAlertingConfig{Config: Config{
Global: c.Global,
Route: AsGrafanaRoute(c.Route),
InhibitRules: c.InhibitRules,
Templates: c.Templates,
}}
s.Uptime = amStatus.Uptime
s.VersionInfo = amStatus.VersionInfo
type overrides struct {
Receivers *[]*PostableApiReceiver `yaml:"receivers,omitempty" json:"receivers,omitempty"`
}
if err := yaml.Unmarshal([]byte(*amStatus.Config.Original), &overrides{Receivers: &s.Config.Receivers}); err != nil {
return err
}
return nil
}
func NewGettableStatus(cfg *PostableApiAlertingConfig) *GettableStatus {
// In Grafana, the only field we support is Config.
cs := amv2.ClusterStatusStatusDisabled
na := "N/A"
return &GettableStatus{
Cluster: &amv2.ClusterStatus{
Status: &cs,
Peers: []*amv2.PeerStatus{},
},
VersionInfo: &amv2.VersionInfo{
Branch: &na,
BuildDate: &na,
BuildUser: &na,
GoVersion: &na,
Revision: &na,
Version: &na,
},
Config: cfg,
}
}
type PostableSilence = amv2.PostableSilence
// swagger:model postSilencesOKBody
type PostSilencesOKBody struct { // vendored from "github.com/prometheus/alertmanager/api/v2/restapi/operations/silence/PostSilencesOKBody" because import brings too many other things
// silence ID
SilenceID string `json:"silenceID,omitempty"`
}
// swagger:model gettableSilences
type GettableSilences = amv2.GettableSilences
type GettableSilence = amv2.GettableSilence
// swagger:model gettableGrafanaSilence
type GettableGrafanaSilence struct {
*GettableSilence `json:",inline"`
Metadata *SilenceMetadata `json:"metadata,omitempty"`
// example: {"read": true, "write": false, "create": false}
Permissions map[SilencePermission]bool `json:"accessControl,omitempty"`
}
type SilenceMetadata struct {
RuleUID string `json:"rule_uid,omitempty"`
RuleTitle string `json:"rule_title,omitempty"`
FolderUID string `json:"folder_uid,omitempty"`
}
type SilencePermission string
const (
SilencePermissionRead SilencePermission = "read"
SilencePermissionCreate SilencePermission = "create"
SilencePermissionWrite SilencePermission = "write"
)
// Correctly embed the GettableSilence into the GettableGrafanaSilence struct. This is needed because GettableSilence
// has a custom UnmarshalJSON method.
func (s GettableGrafanaSilence) MarshalJSON() ([]byte, error) {
gettable, err := json.Marshal(s.GettableSilence)
if err != nil {
return nil, err
}
var data map[string]interface{}
if err := json.Unmarshal(gettable, &data); err != nil {
return nil, err
}
if s.Metadata != nil {
data["metadata"] = s.Metadata
}
if s.Permissions != nil {
data["accessControl"] = s.Permissions
}
return json.Marshal(data)
}
// swagger:model gettableGrafanaSilences
type GettableGrafanaSilences []*GettableGrafanaSilence
// swagger:model gettableAlerts
type GettableAlerts = amv2.GettableAlerts
type GettableAlert = amv2.GettableAlert
// swagger:model alertGroups
type AlertGroups = amv2.AlertGroups
type AlertGroup = amv2.AlertGroup
type Receiver = alertingmodels.Receiver
// swagger:response receiversResponse
type ReceiversResponse struct {
// in:body
Body []alertingmodels.Receiver
}
type Integration = alertingmodels.Integration
// swagger:parameters RouteGetAMAlerts RouteGetAMAlertGroups RouteGetGrafanaAMAlerts RouteGetGrafanaAMAlertGroups
type AlertsParams struct {
// Show active alerts
// in: query
// required: false
// default: true
Active bool `json:"active"`
// Show silenced alerts
// in: query
// required: false
// default: true
Silenced bool `json:"silenced"`
// Show inhibited alerts
// in: query
// required: false
// default: true
Inhibited bool `json:"inhibited"`
// A list of matchers to filter alerts by
// in: query
// required: false
Matchers []string `json:"filter"`
// A regex matching receivers to filter alerts by
// in: query
// required: false
Receivers string `json:"receiver"`
}
// swagger:parameters RoutePostAMAlerts
type PostableAlerts struct {
// in:body
PostableAlerts []amv2.PostableAlert `yaml:"" json:""`
}
// swagger:parameters RoutePostAlertingConfig RoutePostGrafanaAlertingConfig
type BodyAlertingConfig struct {
// in:body
Body PostableUserConfig
}
// swagger:parameters RoutePostGrafanaAlertingConfigHistoryActivate
type HistoricalConfigId struct {
// Id should be the id of the GettableHistoricUserConfig
// in:path
Id int64 `json:"id"`
}
// alertmanager routes
// swagger:parameters RoutePostAlertingConfig RouteGetAlertingConfig RouteDeleteAlertingConfig RouteGetAMStatus RouteGetAMAlerts RoutePostAMAlerts RouteGetAMAlertGroups RouteGetSilences RouteCreateSilence RouteGetSilence RouteDeleteSilence RoutePostAlertingConfig
// testing routes
// swagger:parameters RouteTestRuleConfig
// prom routes
// swagger:parameters RouteGetRuleStatuses RouteGetAlertStatuses
// ruler routes
// swagger:parameters RouteGetRulesConfig RoutePostNameRulesConfig RouteGetNamespaceRulesConfig RouteDeleteNamespaceRulesConfig RouteGetRulegGroupConfig RouteDeleteRuleGroupConfig
type DatasourceUIDReference struct {
// DatasoureUID should be the datasource UID identifier
// in:path
DatasourceUID string
}
// swagger:model
type PostableUserConfig struct {
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
AlertmanagerConfig PostableApiAlertingConfig `yaml:"alertmanager_config" json:"alertmanager_config"`
amSimple map[string]interface{} `yaml:"-" json:"-"`
}
func (c *PostableUserConfig) UnmarshalJSON(b []byte) error {
type plain PostableUserConfig
if err := json.Unmarshal(b, (*plain)(c)); err != nil {
return err
}
// validate first
if err := c.validate(); err != nil {
return err
}
type intermediate struct {
AlertmanagerConfig map[string]interface{} `yaml:"alertmanager_config" json:"alertmanager_config"`
}
var tmp intermediate
if err := json.Unmarshal(b, &tmp); err != nil {
return err
}
// store the map[string]interface{} variant for re-encoding later without redaction
c.amSimple = tmp.AlertmanagerConfig
return nil
}
func (c *PostableUserConfig) validate() error {
// Taken from https://github.com/prometheus/alertmanager/blob/master/config/config.go#L170-L191
// Check if we have a root route. We cannot check for it in the
// UnmarshalYAML method because it won't be called if the input is empty
// (e.g. the config file is empty or only contains whitespace).
if c.AlertmanagerConfig.Route == nil {
return fmt.Errorf("no route provided in config")
}
// Check if continue in root route.
if c.AlertmanagerConfig.Route.Continue {
return fmt.Errorf("cannot have continue in root route")
}
return nil
}
// Decrypt returns a copy of the configuration struct with decrypted secure settings in receivers.
func (c *PostableUserConfig) Decrypt(decryptFn func(payload []byte) ([]byte, error)) (PostableUserConfig, error) {
newCfg, ok := deepcopy.Copy(c).(*PostableUserConfig)
if !ok {
return PostableUserConfig{}, fmt.Errorf("failed to copy config")
}
// Iterate through receivers and decrypt secure settings.
for _, rcv := range newCfg.AlertmanagerConfig.Receivers {
for _, gmr := range rcv.PostableGrafanaReceivers.GrafanaManagedReceivers {
decrypted, err := gmr.DecryptSecureSettings(decryptFn)
if err != nil {
return PostableUserConfig{}, err
}
gmr.SecureSettings = decrypted
}
}
return *newCfg, nil
}
// GetGrafanaReceiverMap returns a map that associates UUIDs to grafana receivers
func (c *PostableUserConfig) GetGrafanaReceiverMap() map[string]*PostableGrafanaReceiver {
UIDs := make(map[string]*PostableGrafanaReceiver)
for _, r := range c.AlertmanagerConfig.Receivers {
switch r.Type() {
case GrafanaReceiverType:
for _, gr := range r.PostableGrafanaReceivers.GrafanaManagedReceivers {
UIDs[gr.UID] = gr
}
default:
}
}
return UIDs
}
// MarshalYAML implements yaml.Marshaller.
func (c *PostableUserConfig) MarshalYAML() (interface{}, error) {
yml, err := yaml.Marshal(c.amSimple)
if err != nil {
return nil, err
}
// cortex/loki actually pass the AM config as a string.
cortexPostableUserConfig := struct {
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
AlertmanagerConfig string `yaml:"alertmanager_config" json:"alertmanager_config"`
}{
TemplateFiles: c.TemplateFiles,
AlertmanagerConfig: string(yml),
}
return cortexPostableUserConfig, nil
}
func (c *PostableUserConfig) UnmarshalYAML(value *yaml.Node) error {
// cortex/loki actually pass the AM config as a string.
type cortexPostableUserConfig struct {
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
AlertmanagerConfig string `yaml:"alertmanager_config" json:"alertmanager_config"`
}
var tmp cortexPostableUserConfig
if err := value.Decode(&tmp); err != nil {
return err
}
if err := yaml.Unmarshal([]byte(tmp.AlertmanagerConfig), &c.AlertmanagerConfig); err != nil {
return err
}
c.TemplateFiles = tmp.TemplateFiles
return nil
}
// swagger:model
type GettableUserConfig struct {
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
TemplateFileProvenances map[string]Provenance `yaml:"template_file_provenances,omitempty" json:"template_file_provenances,omitempty"`
AlertmanagerConfig GettableApiAlertingConfig `yaml:"alertmanager_config" json:"alertmanager_config"`
// amSimple stores a map[string]interface of the decoded alertmanager config.
// This enables circumventing the underlying alertmanager secret type
// which redacts itself during encoding.
amSimple map[string]interface{} `yaml:"-" json:"-"`
}
func (c *GettableUserConfig) UnmarshalYAML(value *yaml.Node) error {
// cortex/loki actually pass the AM config as a string.
type cortexGettableUserConfig struct {
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
AlertmanagerConfig string `yaml:"alertmanager_config" json:"alertmanager_config"`
}
var tmp cortexGettableUserConfig
if err := value.Decode(&tmp); err != nil {
return err
}
if err := yaml.Unmarshal([]byte(tmp.AlertmanagerConfig), &c.AlertmanagerConfig); err != nil {
return err
}
if err := yaml.Unmarshal([]byte(tmp.AlertmanagerConfig), &c.amSimple); err != nil {
return err
}
c.TemplateFiles = tmp.TemplateFiles
return nil
}
func (c *GettableUserConfig) MarshalJSON() ([]byte, error) {
type plain struct {
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
AlertmanagerConfig map[string]interface{} `yaml:"alertmanager_config" json:"alertmanager_config"`
}
tmp := plain{
TemplateFiles: c.TemplateFiles,
AlertmanagerConfig: c.amSimple,
}
return json.Marshal(tmp)
}
// GetGrafanaReceiverMap returns a map that associates UUIDs to grafana receivers
func (c *GettableUserConfig) GetGrafanaReceiverMap() map[string]*GettableGrafanaReceiver {
UIDs := make(map[string]*GettableGrafanaReceiver)
for _, r := range c.AlertmanagerConfig.Receivers {
switch r.Type() {
case GrafanaReceiverType:
for _, gr := range r.GettableGrafanaReceivers.GrafanaManagedReceivers {
UIDs[gr.UID] = gr
}
default:
}
}
return UIDs
}
type GettableHistoricUserConfig struct {
ID int64 `yaml:"id" json:"id"`
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
TemplateFileProvenances map[string]Provenance `yaml:"template_file_provenances,omitempty" json:"template_file_provenances,omitempty"`
AlertmanagerConfig GettableApiAlertingConfig `yaml:"alertmanager_config" json:"alertmanager_config"`
LastApplied *strfmt.DateTime `yaml:"last_applied,omitempty" json:"last_applied,omitempty"`
}
// swagger:response GettableHistoricUserConfigs
type GettableHistoricUserConfigs struct {
// in:body
Body []GettableHistoricUserConfig
}
type GettableApiAlertingConfig struct {
Config `yaml:",inline"`
MuteTimeProvenances map[string]Provenance `yaml:"muteTimeProvenances,omitempty" json:"muteTimeProvenances,omitempty"`
// Override with our superset receiver type
Receivers []*GettableApiReceiver `yaml:"receivers,omitempty" json:"receivers,omitempty"`
}
func (c *GettableApiAlertingConfig) GetReceivers() []*GettableApiReceiver {
return c.Receivers
}
func (c *GettableApiAlertingConfig) GetMuteTimeIntervals() []config.MuteTimeInterval {
return c.MuteTimeIntervals
}
func (c *GettableApiAlertingConfig) GetTimeIntervals() []config.TimeInterval { return c.TimeIntervals }
func (c *GettableApiAlertingConfig) GetRoute() *Route {
return c.Route
}
func (c *GettableApiAlertingConfig) UnmarshalJSON(b []byte) error {
type plain GettableApiAlertingConfig
if err := json.Unmarshal(b, (*plain)(c)); err != nil {
return err
}
// Since Config implements json.Unmarshaler, we must handle _all_ other fields independently.
// Otherwise, the json decoder will detect this and only use the embedded type.
// Additionally, we'll use pointers to slices in order to reference the intended target.
type overrides struct {
Receivers *[]*GettableApiReceiver `yaml:"receivers,omitempty" json:"receivers,omitempty"`
}
if err := json.Unmarshal(b, &overrides{Receivers: &c.Receivers}); err != nil {
return err
}
return c.validate()
}
func (c *GettableApiAlertingConfig) UnmarshalYAML(value *yaml.Node) error {
type plain GettableApiAlertingConfig
if err := value.Decode((*plain)(c)); err != nil {
return err
}
// Since Config implements yaml.Unmarshaler, we must handle _all_ other fields independently.
// Otherwise, the yaml decoder will detect this and only use the embedded type.
// Additionally, we'll use pointers to slices in order to reference the intended target.
type overrides struct {
Receivers *[]*GettableApiReceiver `yaml:"receivers,omitempty"`
}
if err := value.Decode(&overrides{Receivers: &c.Receivers}); err != nil {
return err
}
return c.validate()
}
// validate ensures that the two routing trees use the correct receiver types.
func (c *GettableApiAlertingConfig) validate() error {
receivers := make(map[string]struct{}, len(c.Receivers))
var hasGrafReceivers, hasAMReceivers bool
for _, r := range c.Receivers {
receivers[r.Name] = struct{}{}
switch r.Type() {
case GrafanaReceiverType:
hasGrafReceivers = true
case AlertmanagerReceiverType:
hasAMReceivers = true
default:
continue
}
}
if hasGrafReceivers && hasAMReceivers {
return fmt.Errorf("cannot mix Alertmanager & Grafana receiver types")
}
for _, receiver := range AllReceivers(c.Route.AsAMRoute()) {
_, ok := receivers[receiver]
if !ok {
return fmt.Errorf("unexpected receiver (%s) is undefined", receiver)
}
}
return nil
}
type GettableGrafanaReceiver struct {
UID string `json:"uid"`
Name string `json:"name"`
Type string `json:"type"`
DisableResolveMessage bool `json:"disableResolveMessage"`
Settings RawMessage `json:"settings,omitempty"`
SecureFields map[string]bool `json:"secureFields"`
Provenance Provenance `json:"provenance,omitempty"`
}
type GettableApiReceiver struct {
config.Receiver `yaml:",inline"`
GettableGrafanaReceivers `yaml:",inline"`
}
func (r *GettableApiReceiver) UnmarshalJSON(b []byte) error {
type plain GettableApiReceiver
if err := json.Unmarshal(b, (*plain)(r)); err != nil {
return err
}
hasGrafanaReceivers := len(r.GettableGrafanaReceivers.GrafanaManagedReceivers) > 0
if hasGrafanaReceivers {
if len(r.EmailConfigs) > 0 {
return fmt.Errorf("cannot have both Alertmanager EmailConfigs & Grafana receivers together")
}
if len(r.PagerdutyConfigs) > 0 {
return fmt.Errorf("cannot have both Alertmanager PagerdutyConfigs & Grafana receivers together")
}
if len(r.SlackConfigs) > 0 {
return fmt.Errorf("cannot have both Alertmanager SlackConfigs & Grafana receivers together")
}
if len(r.WebhookConfigs) > 0 {
return fmt.Errorf("cannot have both Alertmanager WebhookConfigs & Grafana receivers together")
}
if len(r.OpsGenieConfigs) > 0 {
return fmt.Errorf("cannot have both Alertmanager OpsGenieConfigs & Grafana receivers together")
}
if len(r.WechatConfigs) > 0 {
return fmt.Errorf("cannot have both Alertmanager WechatConfigs & Grafana receivers together")
}
if len(r.PushoverConfigs) > 0 {
return fmt.Errorf("cannot have both Alertmanager PushoverConfigs & Grafana receivers together")
}
if len(r.VictorOpsConfigs) > 0 {
return fmt.Errorf("cannot have both Alertmanager VictorOpsConfigs & Grafana receivers together")
}
}
return nil
}
func (r *GettableApiReceiver) Type() ReceiverType {
if len(r.GettableGrafanaReceivers.GrafanaManagedReceivers) > 0 {
return GrafanaReceiverType
}
return AlertmanagerReceiverType
}
func (r *GettableApiReceiver) GetName() string {
return r.Receiver.Name
}
type GettableGrafanaReceivers struct {
GrafanaManagedReceivers []*GettableGrafanaReceiver `yaml:"grafana_managed_receiver_configs,omitempty" json:"grafana_managed_receiver_configs,omitempty"`
}
type EncryptFn func(ctx context.Context, payload []byte) ([]byte, error)