Alerting: Support saving extra Mimir configurations (#106721)

This commit is contained in:
Alexander Akhmetov
2025-06-17 23:33:16 +02:00
committed by GitHub
parent 74e800e427
commit 5a78ce8a4b
13 changed files with 583 additions and 99 deletions
+33 -7
View File
@@ -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": {