diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go index dfd39e73f56..17db4cab530 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go @@ -465,10 +465,12 @@ func (s *GettableStatus) UnmarshalJSON(b []byte) error { s.Cluster = amStatus.Cluster s.Config = &PostableApiAlertingConfig{Config: Config{ - Global: c.Global, - Route: AsGrafanaRoute(c.Route), - InhibitRules: c.InhibitRules, - Templates: c.Templates, + Global: c.Global, + Route: AsGrafanaRoute(c.Route), + InhibitRules: c.InhibitRules, + Templates: c.Templates, + MuteTimeIntervals: c.MuteTimeIntervals, + TimeIntervals: c.TimeIntervals, }} s.Uptime = amStatus.Uptime s.VersionInfo = amStatus.VersionInfo diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager_test.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager_test.go index 5f6fb5c2390..906a5c1974e 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager_test.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager_test.go @@ -1,8 +1,10 @@ package definitions import ( + "embed" "encoding/json" - "os" + "path" + "reflect" "strings" "testing" @@ -15,6 +17,32 @@ import ( "gopkg.in/yaml.v3" ) +//go:embed test-data/*.* +var testData embed.FS + +func Test_GettableStatusUnmarshalJSON(t *testing.T) { + incoming, err := testData.ReadFile(path.Join("test-data", "gettable-status.json")) + require.Nil(t, err) + + var actual GettableStatus + require.NoError(t, json.Unmarshal(incoming, &actual)) + + actualJson, err := json.Marshal(actual) + require.NoError(t, err) + + expected, err := testData.ReadFile(path.Join("test-data", "gettable-status-expected.json")) + require.NoError(t, err) + assert.JSONEq(t, string(expected), string(actualJson)) + + v := reflect.ValueOf(actual.Config.Config) + ty := v.Type() + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + fieldName := ty.Field(i).Name + assert.False(t, field.IsZero(), "Field %s should not be zero value", fieldName) + } +} + func Test_GettableUserConfigUnmarshaling(t *testing.T) { for _, tc := range []struct { desc, input string @@ -140,10 +168,10 @@ alertmanager_config: | func Test_GettableUserConfigRoundtrip(t *testing.T) { // raw contains secret fields. We'll unmarshal, re-marshal, and ensure // the fields are not redacted. - yamlEncoded, err := os.ReadFile("alertmanager_test_artifact.yaml") + yamlEncoded, err := testData.ReadFile(path.Join("test-data", "alertmanager_test_artifact.yaml")) require.Nil(t, err) - jsonEncoded, err := os.ReadFile("alertmanager_test_artifact.json") + jsonEncoded, err := testData.ReadFile(path.Join("test-data", "alertmanager_test_artifact.json")) require.Nil(t, err) // test GettableUserConfig (yamlDecode -> jsonEncode) @@ -162,7 +190,7 @@ func Test_GettableUserConfigRoundtrip(t *testing.T) { } func Test_Marshaling_Validation(t *testing.T) { - jsonEncoded, err := os.ReadFile("alertmanager_test_artifact.json") + jsonEncoded, err := testData.ReadFile(path.Join("test-data", "alertmanager_test_artifact.json")) require.Nil(t, err) var tmp GettableUserConfig diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager_test_artifact.json b/pkg/services/ngalert/api/tooling/definitions/test-data/alertmanager_test_artifact.json similarity index 100% rename from pkg/services/ngalert/api/tooling/definitions/alertmanager_test_artifact.json rename to pkg/services/ngalert/api/tooling/definitions/test-data/alertmanager_test_artifact.json diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager_test_artifact.yaml b/pkg/services/ngalert/api/tooling/definitions/test-data/alertmanager_test_artifact.yaml similarity index 100% rename from pkg/services/ngalert/api/tooling/definitions/alertmanager_test_artifact.yaml rename to pkg/services/ngalert/api/tooling/definitions/test-data/alertmanager_test_artifact.yaml diff --git a/pkg/services/ngalert/api/tooling/definitions/test-data/gettable-status-expected.json b/pkg/services/ngalert/api/tooling/definitions/test-data/gettable-status-expected.json new file mode 100644 index 00000000000..b4be8591a85 --- /dev/null +++ b/pkg/services/ngalert/api/tooling/definitions/test-data/gettable-status-expected.json @@ -0,0 +1,321 @@ +{ + "cluster": { + "name": "01K7SGS3KSRG8FT5RZQPFN72NB", + "peers": [ + { + "address": "172.18.0.5:9094", + "name": "01K7SGS3KSRG8FT5RZQPFN72NB" + } + ], + "status": "ready" + }, + "config": { + "global": { + "resolve_timeout": "5m", + "http_config": { + "tls_config": { + "insecure_skip_verify": false + }, + "follow_redirects": true, + "enable_http2": true, + "proxy_url": null + }, + "smtp_from": "alertmanager@example.org", + "smtp_hello": "localhost", + "smtp_smarthost": "localhost:25", + "smtp_require_tls": true, + "pagerduty_url": "https://events.pagerduty.com/v2/enqueue", + "opsgenie_api_url": "https://api.opsgenie.com/", + "wechat_api_url": "https://qyapi.weixin.qq.com/cgi-bin/", + "victorops_api_url": "https://alert.victorops.com/integrations/generic/20131114/alert/", + "telegram_api_url": "https://api.telegram.org", + "webex_api_url": "https://webexapis.com/v1/messages", + "smtp_tls_config": { + "insecure_skip_verify": false + } + }, + "route": { + "receiver": "team-X-mails", + "group_by": [ + "alertname", + "cluster" + ], + "routes": [ + { + "receiver": "team-X-mails", + "matchers": [ + "service=~\"^(foo1|foo2|baz)$\"" + ], + "routes": [ + { + "receiver": "team-X-pager", + "matchers": [ + "severity=\"critical\"" + ] + } + ] + }, + { + "receiver": "team-Y-mails", + "matchers": [ + "service=\"files\"" + ], + "routes": [ + { + "receiver": "team-Y-pager", + "matchers": [ + "severity=\"critical\"" + ], + "mute_time_intervals": [ + "nightly-quiet-time-deprecated" + ] + } + ] + }, + { + "receiver": "team-DB-pager", + "group_by": [ + "alertname", + "cluster", + "database" + ], + "matchers": [ + "service=\"database\"" + ], + "routes": [ + { + "receiver": "team-X-pager", + "matchers": [ + "owner=\"team-X\"" + ], + "mute_time_intervals": [ + "nightly-quiet-time" + ] + }, + { + "receiver": "team-Y-pager", + "matchers": [ + "owner=\"team-Y\"" + ] + } + ] + } + ], + "group_wait": "30s", + "group_interval": "5m", + "repeat_interval": "3h" + }, + "inhibit_rules": [ + { + "source_matchers": [ + "severity=\"critical\"" + ], + "target_matchers": [ + "severity=\"warning\"" + ], + "equal": [ + "alertname" + ] + } + ], + "mute_time_intervals": [ + { + "name": "nightly-quiet-time-deprecated", + "time_intervals": [ + { + "times": [ + { + "start_time": "18:00", + "end_time": "23:59" + }, + { + "start_time": "00:00", + "end_time": "07:00" + } + ] + } + ] + } + ], + "time_intervals": [ + { + "name": "nightly-quiet-time", + "time_intervals": [ + { + "times": [ + { + "start_time": "18:00", + "end_time": "23:59" + }, + { + "start_time": "00:00", + "end_time": "07:00" + } + ] + } + ] + } + ], + "templates": [ + "/etc/alertmanager/templates/*.tmpl" + ], + "receivers": [ + { + "name": "team-X-mails", + "email_configs": [ + { + "send_resolved": false, + "to": "team-X+alerts@example.org, team-Y+alerts@example.org", + "from": "alertmanager@example.org", + "hello": "localhost", + "smarthost": "localhost:25", + "headers": { + "From": "alertmanager@example.org", + "Subject": "{{ template \"email.default.subject\" . }}", + "To": "team-X+alerts@example.org, team-Y+alerts@example.org" + }, + "html": "{{ template \"email.default.html\" . }}", + "require_tls": true, + "tls_config": { + "insecure_skip_verify": false + } + } + ] + }, + { + "name": "team-X-pager", + "email_configs": [ + { + "send_resolved": false, + "to": "team-X+alerts-critical@example.org", + "from": "alertmanager@example.org", + "hello": "localhost", + "smarthost": "localhost:25", + "headers": { + "From": "alertmanager@example.org", + "Subject": "{{ template \"email.default.subject\" . }}", + "To": "team-X+alerts-critical@example.org" + }, + "html": "{{ template \"email.default.html\" . }}", + "require_tls": true, + "tls_config": { + "insecure_skip_verify": false + } + } + ], + "pagerduty_configs": [ + { + "send_resolved": true, + "http_config": { + "tls_config": { + "insecure_skip_verify": false + }, + "follow_redirects": true, + "enable_http2": true, + "proxy_url": null + }, + "routing_key": "", + "url": "https://events.pagerduty.com/v2/enqueue", + "client": "{{ template \"pagerduty.default.client\" . }}", + "client_url": "{{ template \"pagerduty.default.clientURL\" . }}", + "description": "{{ template \"pagerduty.default.description\" .}}", + "details": { + "firing": "{{ template \"pagerduty.default.instances\" .Alerts.Firing }}", + "num_firing": "{{ .Alerts.Firing | len }}", + "num_resolved": "{{ .Alerts.Resolved | len }}", + "resolved": "{{ template \"pagerduty.default.instances\" .Alerts.Resolved }}" + }, + "source": "{{ template \"pagerduty.default.client\" . }}" + } + ] + }, + { + "name": "team-Y-mails", + "email_configs": [ + { + "send_resolved": false, + "to": "team-Y+alerts@example.org", + "from": "alertmanager@example.org", + "hello": "localhost", + "smarthost": "localhost:25", + "headers": { + "From": "alertmanager@example.org", + "Subject": "{{ template \"email.default.subject\" . }}", + "To": "team-Y+alerts@example.org" + }, + "html": "{{ template \"email.default.html\" . }}", + "require_tls": true, + "tls_config": { + "insecure_skip_verify": false + } + } + ] + }, + { + "name": "team-Y-pager", + "pagerduty_configs": [ + { + "send_resolved": true, + "http_config": { + "tls_config": { + "insecure_skip_verify": false + }, + "follow_redirects": true, + "enable_http2": true, + "proxy_url": null + }, + "routing_key": "", + "url": "https://events.pagerduty.com/v2/enqueue", + "client": "{{ template \"pagerduty.default.client\" . }}", + "client_url": "{{ template \"pagerduty.default.clientURL\" . }}", + "description": "{{ template \"pagerduty.default.description\" .}}", + "details": { + "firing": "{{ template \"pagerduty.default.instances\" .Alerts.Firing }}", + "num_firing": "{{ .Alerts.Firing | len }}", + "num_resolved": "{{ .Alerts.Resolved | len }}", + "resolved": "{{ template \"pagerduty.default.instances\" .Alerts.Resolved }}" + }, + "source": "{{ template \"pagerduty.default.client\" . }}" + } + ] + }, + { + "name": "team-DB-pager", + "pagerduty_configs": [ + { + "send_resolved": true, + "http_config": { + "tls_config": { + "insecure_skip_verify": false + }, + "follow_redirects": true, + "enable_http2": true, + "proxy_url": null + }, + "routing_key": "", + "url": "https://events.pagerduty.com/v2/enqueue", + "client": "{{ template \"pagerduty.default.client\" . }}", + "client_url": "{{ template \"pagerduty.default.clientURL\" . }}", + "description": "{{ template \"pagerduty.default.description\" .}}", + "details": { + "firing": "{{ template \"pagerduty.default.instances\" .Alerts.Firing }}", + "num_firing": "{{ .Alerts.Firing | len }}", + "num_resolved": "{{ .Alerts.Resolved | len }}", + "resolved": "{{ template \"pagerduty.default.instances\" .Alerts.Resolved }}" + }, + "source": "{{ template \"pagerduty.default.client\" . }}" + } + ] + } + ] + }, + "uptime": "2025-10-17T16:41:50.500Z", + "versionInfo": { + "branch": "HEAD", + "buildDate": "20250115-14:22:34", + "buildUser": "root@40be7f318ba7", + "goVersion": "go1.23.4", + "revision": "4ce04fb010bd626fca35928dcfe82f6f2da52ced", + "version": "0.28.0" + } +} \ No newline at end of file diff --git a/pkg/services/ngalert/api/tooling/definitions/test-data/gettable-status.json b/pkg/services/ngalert/api/tooling/definitions/test-data/gettable-status.json new file mode 100644 index 00000000000..b64c9947dad --- /dev/null +++ b/pkg/services/ngalert/api/tooling/definitions/test-data/gettable-status.json @@ -0,0 +1,24 @@ +{ + "cluster": { + "name": "01K7SGS3KSRG8FT5RZQPFN72NB", + "peers": [ + { + "address": "172.18.0.5:9094", + "name": "01K7SGS3KSRG8FT5RZQPFN72NB" + } + ], + "status": "ready" + }, + "config": { + "original": "global:\n resolve_timeout: 5m\n http_config:\n follow_redirects: true\n enable_http2: true\n smtp_from: alertmanager@example.org\n smtp_hello: localhost\n smtp_smarthost: localhost:25\n smtp_require_tls: true\n smtp_tls_config:\n insecure_skip_verify: false\n pagerduty_url: https://events.pagerduty.com/v2/enqueue\n opsgenie_api_url: https://api.opsgenie.com/\n wechat_api_url: https://qyapi.weixin.qq.com/cgi-bin/\n victorops_api_url: https://alert.victorops.com/integrations/generic/20131114/alert/\n telegram_api_url: https://api.telegram.org\n webex_api_url: https://webexapis.com/v1/messages\n rocketchat_api_url: https://open.rocket.chat/\nroute:\n receiver: team-X-mails\n group_by:\n - alertname\n - cluster\n continue: false\n routes:\n - receiver: team-X-mails\n matchers:\n - service=~\"^(foo1|foo2|baz)$\"\n continue: false\n routes:\n - receiver: team-X-pager\n matchers:\n - severity=\"critical\"\n continue: false\n - receiver: team-Y-mails\n matchers:\n - service=\"files\"\n continue: false\n routes:\n - receiver: team-Y-pager\n matchers:\n - severity=\"critical\"\n mute_time_intervals:\n - nightly-quiet-time-deprecated\n continue: false\n - receiver: team-DB-pager\n group_by:\n - alertname\n - cluster\n - database\n matchers:\n - service=\"database\"\n continue: false\n routes:\n - receiver: team-X-pager\n matchers:\n - owner=\"team-X\"\n mute_time_intervals:\n - nightly-quiet-time\n continue: false\n - receiver: team-Y-pager\n matchers:\n - owner=\"team-Y\"\n continue: false\n group_wait: 30s\n group_interval: 5m\n repeat_interval: 3h\ninhibit_rules:\n- source_matchers:\n - severity=\"critical\"\n target_matchers:\n - severity=\"warning\"\n equal:\n - alertname\nreceivers:\n- name: team-X-mails\n email_configs:\n - send_resolved: false\n to: team-X+alerts@example.org, team-Y+alerts@example.org\n from: alertmanager@example.org\n hello: localhost\n smarthost: localhost:25\n headers:\n From: alertmanager@example.org\n Subject: '{{ template \"email.default.subject\" . }}'\n To: team-X+alerts@example.org, team-Y+alerts@example.org\n html: '{{ template \"email.default.html\" . }}'\n require_tls: true\n tls_config:\n insecure_skip_verify: false\n- name: team-X-pager\n email_configs:\n - send_resolved: false\n to: team-X+alerts-critical@example.org\n from: alertmanager@example.org\n hello: localhost\n smarthost: localhost:25\n headers:\n From: alertmanager@example.org\n Subject: '{{ template \"email.default.subject\" . }}'\n To: team-X+alerts-critical@example.org\n html: '{{ template \"email.default.html\" . }}'\n require_tls: true\n tls_config:\n insecure_skip_verify: false\n pagerduty_configs:\n - send_resolved: true\n http_config:\n follow_redirects: true\n enable_http2: true\n routing_key: \n url: https://events.pagerduty.com/v2/enqueue\n client: '{{ template \"pagerduty.default.client\" . }}'\n client_url: '{{ template \"pagerduty.default.clientURL\" . }}'\n description: '{{ template \"pagerduty.default.description\" .}}'\n details:\n firing: '{{ template \"pagerduty.default.instances\" .Alerts.Firing }}'\n num_firing: '{{ .Alerts.Firing | len }}'\n num_resolved: '{{ .Alerts.Resolved | len }}'\n resolved: '{{ template \"pagerduty.default.instances\" .Alerts.Resolved }}'\n source: '{{ template \"pagerduty.default.client\" . }}'\n- name: team-Y-mails\n email_configs:\n - send_resolved: false\n to: team-Y+alerts@example.org\n from: alertmanager@example.org\n hello: localhost\n smarthost: localhost:25\n headers:\n From: alertmanager@example.org\n Subject: '{{ template \"email.default.subject\" . }}'\n To: team-Y+alerts@example.org\n html: '{{ template \"email.default.html\" . }}'\n require_tls: true\n tls_config:\n insecure_skip_verify: false\n- name: team-Y-pager\n pagerduty_configs:\n - send_resolved: true\n http_config:\n follow_redirects: true\n enable_http2: true\n routing_key: \n url: https://events.pagerduty.com/v2/enqueue\n client: '{{ template \"pagerduty.default.client\" . }}'\n client_url: '{{ template \"pagerduty.default.clientURL\" . }}'\n description: '{{ template \"pagerduty.default.description\" .}}'\n details:\n firing: '{{ template \"pagerduty.default.instances\" .Alerts.Firing }}'\n num_firing: '{{ .Alerts.Firing | len }}'\n num_resolved: '{{ .Alerts.Resolved | len }}'\n resolved: '{{ template \"pagerduty.default.instances\" .Alerts.Resolved }}'\n source: '{{ template \"pagerduty.default.client\" . }}'\n- name: team-DB-pager\n pagerduty_configs:\n - send_resolved: true\n http_config:\n follow_redirects: true\n enable_http2: true\n routing_key: \n url: https://events.pagerduty.com/v2/enqueue\n client: '{{ template \"pagerduty.default.client\" . }}'\n client_url: '{{ template \"pagerduty.default.clientURL\" . }}'\n description: '{{ template \"pagerduty.default.description\" .}}'\n details:\n firing: '{{ template \"pagerduty.default.instances\" .Alerts.Firing }}'\n num_firing: '{{ .Alerts.Firing | len }}'\n num_resolved: '{{ .Alerts.Resolved | len }}'\n resolved: '{{ template \"pagerduty.default.instances\" .Alerts.Resolved }}'\n source: '{{ template \"pagerduty.default.client\" . }}'\ntemplates:\n- /etc/alertmanager/templates/*.tmpl\nmute_time_intervals:\n- name: nightly-quiet-time-deprecated\n time_intervals:\n - times:\n - start_time: \"18:00\"\n end_time: \"23:59\"\n - start_time: \"00:00\"\n end_time: \"07:00\"\ntime_intervals:\n- name: nightly-quiet-time\n time_intervals:\n - times:\n - start_time: \"18:00\"\n end_time: \"23:59\"\n - start_time: \"00:00\"\n end_time: \"07:00\"\n" + }, + "uptime": "2025-10-17T16:41:50.500Z", + "versionInfo": { + "branch": "HEAD", + "buildDate": "20250115-14:22:34", + "buildUser": "root@40be7f318ba7", + "goVersion": "go1.23.4", + "revision": "4ce04fb010bd626fca35928dcfe82f6f2da52ced", + "version": "0.28.0" + } +} \ No newline at end of file