Alerting: Support saving extra Mimir configurations (#106721)
This commit is contained in:
@@ -1123,6 +1123,26 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ExtraConfiguration": {
|
||||
"properties": {
|
||||
"alertmanager_config": {
|
||||
"type": "string"
|
||||
},
|
||||
"identifier": {
|
||||
"type": "string"
|
||||
},
|
||||
"merge_matchers": {
|
||||
"$ref": "#/definitions/Matchers"
|
||||
},
|
||||
"template_files": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"Failure": {
|
||||
"$ref": "#/definitions/ResponseDetails"
|
||||
},
|
||||
@@ -1854,6 +1874,12 @@
|
||||
"alertmanager_config": {
|
||||
"$ref": "#/definitions/GettableApiAlertingConfig"
|
||||
},
|
||||
"extra_config": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ExtraConfiguration"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"template_file_provenances": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/Provenance"
|
||||
@@ -3057,6 +3083,12 @@
|
||||
"alertmanager_config": {
|
||||
"$ref": "#/definitions/PostableApiAlertingConfig"
|
||||
},
|
||||
"extra_config": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ExtraConfiguration"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"template_files": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
@@ -3687,7 +3719,6 @@
|
||||
"type": "object"
|
||||
},
|
||||
"Route": {
|
||||
"description": "A Route is a node that contains definitions of how to handle alerts. This is modified\nfrom the upstream alertmanager in that it adds the ObjectMatchers property.",
|
||||
"properties": {
|
||||
"active_time_intervals": {
|
||||
"items": {
|
||||
@@ -3729,12 +3760,6 @@
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"object_matchers": {
|
||||
"$ref": "#/definitions/ObjectMatchers"
|
||||
},
|
||||
"provenance": {
|
||||
"$ref": "#/definitions/Provenance"
|
||||
},
|
||||
"receiver": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3748,6 +3773,7 @@
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"title": "A Route is a node that contains definitions of how to handle alerts.",
|
||||
"type": "object"
|
||||
},
|
||||
"RouteExport": {
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
"github.com/prometheus/alertmanager/pkg/labels"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/grafana/alerting/definition"
|
||||
@@ -649,31 +648,69 @@ type DatasourceUIDReference struct {
|
||||
}
|
||||
|
||||
type ExtraConfiguration struct {
|
||||
Identifier string `yaml:"identifier" json:"identifier"`
|
||||
MergeMatchers config.Matchers `yaml:"merge_matchers" json:"merge_matchers"`
|
||||
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
|
||||
AlertmanagerConfig PostableApiAlertingConfig `yaml:"alertmanager_config" json:"alertmanager_config"`
|
||||
Identifier string `yaml:"identifier" json:"identifier"`
|
||||
MergeMatchers config.Matchers `yaml:"merge_matchers" json:"merge_matchers"`
|
||||
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
|
||||
AlertmanagerConfig string `yaml:"alertmanager_config" json:"alertmanager_config"`
|
||||
}
|
||||
|
||||
func (c *ExtraConfiguration) GetAlertmanagerConfig() (PostableApiAlertingConfig, error) {
|
||||
if c.AlertmanagerConfig == "" {
|
||||
return PostableApiAlertingConfig{}, fmt.Errorf("no alertmanager configuration available")
|
||||
}
|
||||
|
||||
var prometheusConfig config.Config
|
||||
if err := yaml.Unmarshal([]byte(c.AlertmanagerConfig), &prometheusConfig); err != nil {
|
||||
return PostableApiAlertingConfig{}, fmt.Errorf("failed to parse alertmanager config: %w", err)
|
||||
}
|
||||
|
||||
return fromPrometheusConfig(prometheusConfig), nil
|
||||
}
|
||||
|
||||
func (c ExtraConfiguration) Validate() error {
|
||||
if c.Identifier == "" {
|
||||
return errors.New("identifier is required")
|
||||
}
|
||||
|
||||
if len(c.MergeMatchers) == 0 {
|
||||
return errors.New("at least one matcher is required")
|
||||
}
|
||||
|
||||
for _, m := range c.MergeMatchers {
|
||||
if m.Type != labels.MatchEqual {
|
||||
return errors.New("only matchers with type equal are supported")
|
||||
}
|
||||
}
|
||||
err := c.AlertmanagerConfig.Validate()
|
||||
|
||||
// Alertmanager configuration is validated during YAML unmarshalling.
|
||||
am := config.Config{}
|
||||
err := yaml.Unmarshal([]byte(c.AlertmanagerConfig), &am)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid alertmanager configuration: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fromPrometheusConfig(prometheusConfig config.Config) PostableApiAlertingConfig {
|
||||
config := PostableApiAlertingConfig{
|
||||
Config: Config{
|
||||
Global: prometheusConfig.Global,
|
||||
Route: AsGrafanaRoute(prometheusConfig.Route),
|
||||
InhibitRules: prometheusConfig.InhibitRules,
|
||||
Templates: prometheusConfig.Templates,
|
||||
},
|
||||
}
|
||||
|
||||
for _, receiver := range prometheusConfig.Receivers {
|
||||
config.Receivers = append(config.Receivers, &PostableApiReceiver{
|
||||
Receiver: receiver,
|
||||
})
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// swagger:model
|
||||
type PostableUserConfig struct {
|
||||
TemplateFiles map[string]string `yaml:"template_files" json:"template_files"`
|
||||
@@ -697,7 +734,13 @@ func (c *PostableUserConfig) GetMergedAlertmanagerConfig() (MergeResult, error)
|
||||
if err := opts.Validate(); err != nil {
|
||||
return MergeResult{}, fmt.Errorf("invalid merge options: %w", err)
|
||||
}
|
||||
return definition.Merge(c.AlertmanagerConfig, mimirCfg.AlertmanagerConfig, opts) // for now support only the first extra config
|
||||
|
||||
mcfg, err := mimirCfg.GetAlertmanagerConfig()
|
||||
if err != nil {
|
||||
return MergeResult{}, fmt.Errorf("failed to get mimir alertmanager config: %w", err)
|
||||
}
|
||||
|
||||
return definition.Merge(c.AlertmanagerConfig, mcfg, opts)
|
||||
}
|
||||
|
||||
// GetMergedTemplateDefinitions converts the given PostableUserConfig's TemplateFiles to a slice of TemplateDefinitions.
|
||||
@@ -738,11 +781,6 @@ func (c *PostableUserConfig) UnmarshalJSON(b []byte) error {
|
||||
if len(c.ExtraConfigs) > 1 {
|
||||
return errors.New("only one extra config is supported")
|
||||
}
|
||||
for _, extraConfig := range c.ExtraConfigs {
|
||||
if err := extraConfig.Validate(); err != nil {
|
||||
return fmt.Errorf("extra configuration is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
type intermediate struct {
|
||||
AlertmanagerConfig map[string]interface{} `yaml:"alertmanager_config" json:"alertmanager_config"`
|
||||
@@ -833,6 +871,7 @@ 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"`
|
||||
ExtraConfigs []ExtraConfiguration `yaml:"extra_config,omitempty" json:"extra_config,omitempty"`
|
||||
|
||||
// amSimple stores a map[string]interface of the decoded alertmanager config.
|
||||
// This enables circumventing the underlying alertmanager secret type
|
||||
|
||||
@@ -259,20 +259,10 @@ func TestPostableUserConfig_GetMergedAlertmanagerConfig(t *testing.T) {
|
||||
Value: "prod",
|
||||
},
|
||||
},
|
||||
AlertmanagerConfig: PostableApiAlertingConfig{
|
||||
Config: Config{
|
||||
Route: &Route{
|
||||
Receiver: "mimir-receiver",
|
||||
},
|
||||
},
|
||||
Receivers: []*PostableApiReceiver{
|
||||
{
|
||||
Receiver: config.Receiver{
|
||||
Name: "mimir-receiver",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AlertmanagerConfig: `route:
|
||||
receiver: mimir-receiver
|
||||
receivers:
|
||||
- name: mimir-receiver`,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -285,13 +275,11 @@ func TestPostableUserConfig_GetMergedAlertmanagerConfig(t *testing.T) {
|
||||
{
|
||||
Identifier: "",
|
||||
MergeMatchers: config.Matchers{},
|
||||
AlertmanagerConfig: PostableApiAlertingConfig{
|
||||
Config: Config{
|
||||
Route: &Route{
|
||||
Receiver: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
AlertmanagerConfig: `{
|
||||
"route": {
|
||||
"receiver": "test"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1123,6 +1123,26 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ExtraConfiguration": {
|
||||
"properties": {
|
||||
"alertmanager_config": {
|
||||
"type": "string"
|
||||
},
|
||||
"identifier": {
|
||||
"type": "string"
|
||||
},
|
||||
"merge_matchers": {
|
||||
"$ref": "#/definitions/Matchers"
|
||||
},
|
||||
"template_files": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"Failure": {
|
||||
"$ref": "#/definitions/ResponseDetails"
|
||||
},
|
||||
@@ -1854,6 +1874,12 @@
|
||||
"alertmanager_config": {
|
||||
"$ref": "#/definitions/GettableApiAlertingConfig"
|
||||
},
|
||||
"extra_config": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ExtraConfiguration"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"template_file_provenances": {
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/Provenance"
|
||||
@@ -3057,6 +3083,12 @@
|
||||
"alertmanager_config": {
|
||||
"$ref": "#/definitions/PostableApiAlertingConfig"
|
||||
},
|
||||
"extra_config": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ExtraConfiguration"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"template_files": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
|
||||
@@ -5412,6 +5412,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"ExtraConfiguration": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"alertmanager_config": {
|
||||
"type": "string"
|
||||
},
|
||||
"identifier": {
|
||||
"type": "string"
|
||||
},
|
||||
"merge_matchers": {
|
||||
"$ref": "#/definitions/Matchers"
|
||||
},
|
||||
"template_files": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Failure": {
|
||||
"$ref": "#/definitions/ResponseDetails"
|
||||
},
|
||||
@@ -6144,6 +6164,12 @@
|
||||
"alertmanager_config": {
|
||||
"$ref": "#/definitions/GettableApiAlertingConfig"
|
||||
},
|
||||
"extra_config": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ExtraConfiguration"
|
||||
}
|
||||
},
|
||||
"template_file_provenances": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
@@ -7348,6 +7374,12 @@
|
||||
"alertmanager_config": {
|
||||
"$ref": "#/definitions/PostableApiAlertingConfig"
|
||||
},
|
||||
"extra_config": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ExtraConfiguration"
|
||||
}
|
||||
},
|
||||
"template_files": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
|
||||
Reference in New Issue
Block a user