Skip to content

Commit ce8652d

Browse files
Show muted alerts in the Alert Groups API
This commit updates the Alert Groups API (/api/v2/alerts/groups) to show if an alert is suppressed from one or more active or mute time intervals. It does not update the Alerts API (/api/v2/alerts) because that API does not take aggregation or routing into consideration. Signed-off-by: George Robinson <[email protected]>
1 parent 446d53d commit ce8652d

File tree

13 files changed

+993
-379
lines changed

13 files changed

+993
-379
lines changed

api/api.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,19 @@ type API struct {
4545
inFlightSem chan struct{}
4646
}
4747

48-
// Options for the creation of an API object. Alerts, Silences, and StatusFunc
48+
// Options for the creation of an API object. Alerts, Silences, and AlertStatusFunc
4949
// are mandatory to set. The zero value for everything else is a safe default.
5050
type Options struct {
5151
// Alerts to be used by the API. Mandatory.
5252
Alerts provider.Alerts
5353
// Silences to be used by the API. Mandatory.
5454
Silences *silence.Silences
55-
// StatusFunc is used be the API to retrieve the AlertStatus of an
55+
// AlertStatusFunc is used be the API to retrieve the AlertStatus of an
5656
// alert. Mandatory.
57-
StatusFunc func(model.Fingerprint) types.AlertStatus
57+
AlertStatusFunc func(model.Fingerprint) types.AlertStatus
58+
// GroupMutedFunc is used be the API to know if an alert is muted.
59+
// Mandatory.
60+
GroupMutedFunc func(string) ([]string, bool)
5861
// Peer from the gossip cluster. If nil, no clustering will be used.
5962
Peer cluster.ClusterPeer
6063
// Timeout for all HTTP connections. The zero value (and negative
@@ -83,8 +86,11 @@ func (o Options) validate() error {
8386
if o.Silences == nil {
8487
return errors.New("mandatory field Silences not set")
8588
}
86-
if o.StatusFunc == nil {
87-
return errors.New("mandatory field StatusFunc not set")
89+
if o.AlertStatusFunc == nil {
90+
return errors.New("mandatory field AlertStatusFunc not set")
91+
}
92+
if o.GroupMutedFunc == nil {
93+
return errors.New("mandatory field GroupMutedFunc not set")
8894
}
8995
if o.GroupFunc == nil {
9096
return errors.New("mandatory field GroupFunc not set")
@@ -113,7 +119,8 @@ func New(opts Options) (*API, error) {
113119
v2, err := apiv2.NewAPI(
114120
opts.Alerts,
115121
opts.GroupFunc,
116-
opts.StatusFunc,
122+
opts.AlertStatusFunc,
123+
opts.GroupMutedFunc,
117124
opts.Silences,
118125
opts.Peer,
119126
log.With(l, "version", "v2"),

api/v2/api.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ type API struct {
6060
alerts provider.Alerts
6161
alertGroups groupsFn
6262
getAlertStatus getAlertStatusFn
63+
groupMutedFunc groupMutedFunc
6364
uptime time.Time
6465

6566
// mtx protects alertmanagerConfig, setAlertStatus and route.
@@ -78,6 +79,7 @@ type API struct {
7879

7980
type (
8081
groupsFn func(func(*dispatch.Route) bool, func(*types.Alert, time.Time) bool) (dispatch.AlertGroups, map[prometheus_model.Fingerprint][]string)
82+
groupMutedFunc func(groupKey string) ([]string, bool)
8183
getAlertStatusFn func(prometheus_model.Fingerprint) types.AlertStatus
8284
setAlertStatusFn func(prometheus_model.LabelSet)
8385
)
@@ -86,16 +88,18 @@ type (
8688
func NewAPI(
8789
alerts provider.Alerts,
8890
gf groupsFn,
89-
sf getAlertStatusFn,
91+
asf getAlertStatusFn,
92+
gmf groupMutedFunc,
9093
silences *silence.Silences,
9194
peer cluster.ClusterPeer,
9295
l log.Logger,
9396
r prometheus.Registerer,
9497
) (*API, error) {
9598
api := API{
9699
alerts: alerts,
97-
getAlertStatus: sf,
100+
getAlertStatus: asf,
98101
alertGroups: gf,
102+
groupMutedFunc: gmf,
99103
peer: peer,
100104
silences: silences,
101105
logger: l,
@@ -410,14 +414,16 @@ func (api *API) getAlertGroupsHandler(params alertgroup_ops.GetAlertGroupsParams
410414
ag := &open_api_models.AlertGroup{
411415
Receiver: &open_api_models.Receiver{Name: &alertGroup.Receiver},
412416
Labels: ModelLabelSetToAPILabelSet(alertGroup.Labels),
413-
Alerts: make([]*open_api_models.GettableAlert, 0, len(alertGroup.Alerts)),
417+
Alerts: make([]*open_api_models.AlertGroupGettableAlert, 0, len(alertGroup.Alerts)),
414418
}
415419

420+
mutedBy, isMuted := api.groupMutedFunc(alertGroup.GroupKey)
416421
for _, alert := range alertGroup.Alerts {
417422
fp := alert.Fingerprint()
418423
receivers := allReceivers[fp]
419424
status := api.getAlertStatus(fp)
420-
apiAlert := AlertToOpenAPIAlert(alert, status, receivers)
425+
tmp := AlertToOpenAPIAlert(alert, status, receivers)
426+
apiAlert := ToGroupAlert(tmp, isMuted, mutedBy)
421427
ag.Alerts = append(ag.Alerts, apiAlert)
422428
}
423429
res = append(res, ag)

api/v2/api_test.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -412,23 +412,25 @@ func TestAlertToOpenAPIAlert(t *testing.T) {
412412
)
413413
openAPIAlert := AlertToOpenAPIAlert(alert, types.AlertStatus{State: types.AlertStateActive}, receivers)
414414
require.Equal(t, &open_api_models.GettableAlert{
415-
Annotations: open_api_models.LabelSet{},
416-
Alert: open_api_models.Alert{
417-
Labels: open_api_models.LabelSet{"severity": "critical", "alertname": "alert1"},
415+
BaseAlert: open_api_models.BaseAlert{
416+
Annotations: open_api_models.LabelSet{},
417+
Alert: open_api_models.Alert{
418+
Labels: open_api_models.LabelSet{"severity": "critical", "alertname": "alert1"},
419+
},
420+
StartsAt: convertDateTime(start),
421+
EndsAt: convertDateTime(time.Time{}),
422+
UpdatedAt: convertDateTime(updated),
423+
Fingerprint: &fp,
424+
Receivers: []*open_api_models.Receiver{
425+
{Name: &receivers[0]},
426+
{Name: &receivers[1]},
427+
},
418428
},
419429
Status: &open_api_models.AlertStatus{
420430
State: &active,
421431
InhibitedBy: []string{},
422432
SilencedBy: []string{},
423433
},
424-
StartsAt: convertDateTime(start),
425-
EndsAt: convertDateTime(time.Time{}),
426-
UpdatedAt: convertDateTime(updated),
427-
Fingerprint: &fp,
428-
Receivers: []*open_api_models.Receiver{
429-
{Name: &receivers[0]},
430-
{Name: &receivers[1]},
431-
},
432434
}, openAPIAlert)
433435
}
434436

api/v2/compat.go

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,18 @@ func AlertToOpenAPIAlert(alert *types.Alert, status types.AlertStatus, receivers
130130
fp := alert.Fingerprint().String()
131131
state := string(status.State)
132132
aa := &open_api_models.GettableAlert{
133-
Alert: open_api_models.Alert{
134-
GeneratorURL: strfmt.URI(alert.GeneratorURL),
135-
Labels: ModelLabelSetToAPILabelSet(alert.Labels),
133+
BaseAlert: open_api_models.BaseAlert{
134+
Alert: open_api_models.Alert{
135+
GeneratorURL: strfmt.URI(alert.GeneratorURL),
136+
Labels: ModelLabelSetToAPILabelSet(alert.Labels),
137+
},
138+
Annotations: ModelLabelSetToAPILabelSet(alert.Annotations),
139+
StartsAt: &startsAt,
140+
UpdatedAt: &updatedAt,
141+
EndsAt: &endsAt,
142+
Fingerprint: &fp,
143+
Receivers: apiReceivers,
136144
},
137-
Annotations: ModelLabelSetToAPILabelSet(alert.Annotations),
138-
StartsAt: &startsAt,
139-
UpdatedAt: &updatedAt,
140-
EndsAt: &endsAt,
141-
Fingerprint: &fp,
142-
Receivers: apiReceivers,
143145
Status: &open_api_models.AlertStatus{
144146
State: &state,
145147
SilencedBy: status.SilencedBy,
@@ -158,6 +160,32 @@ func AlertToOpenAPIAlert(alert *types.Alert, status types.AlertStatus, receivers
158160
return aa
159161
}
160162

163+
func ToGroupAlert(alert *open_api_models.GettableAlert, isMuted bool, mutedBy []string) *open_api_models.AlertGroupGettableAlert {
164+
status := open_api_models.AlertGroupAlertStatus{}
165+
if alert.Status != nil {
166+
status.AlertStatus = *alert.Status
167+
}
168+
if status.SilencedBy == nil {
169+
status.SilencedBy = []string{}
170+
}
171+
if status.InhibitedBy == nil {
172+
status.InhibitedBy = []string{}
173+
}
174+
if status.MutedBy == nil {
175+
status.MutedBy = []string{}
176+
}
177+
result := open_api_models.AlertGroupGettableAlert{
178+
BaseAlert: alert.BaseAlert,
179+
Status: &status,
180+
}
181+
if isMuted {
182+
state := open_api_models.AlertStatusStateSuppressed
183+
result.Status.MutedBy = mutedBy
184+
result.Status.State = &state
185+
}
186+
return &result
187+
}
188+
161189
// OpenAPIAlertsToAlerts converts open_api_models.PostableAlerts to []*types.Alert.
162190
func OpenAPIAlertsToAlerts(apiAlerts open_api_models.PostableAlerts) []*types.Alert {
163191
alerts := []*types.Alert{}

api/v2/models/alert_group.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v2/models/alert_group_alert_status.go

Lines changed: 146 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)