Alerting: Fix unmarshalling of GettableStatus to include time intervals (#112602)

* move test files into test-data

* add test for the bug

* populate time-intervals of gettableStatus config
This commit is contained in:
Yuri Tseretyan authored and GitHub committed 2025-10-21 09:28:04 -04:00
1 parent 6851ca2988
commit 5f9a51418c
6 files changed
+383 -8

No files matched your search

@@ -485,10 +485,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
@@ -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
@@ -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": "<secret>",
"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": "<secret>",
"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": "<secret>",
"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"
}
}
@@ -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: <secret>\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: <secret>\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_httLine truncated
},
"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"
}
}