Skip to content

Commit 3c8fb4f

Browse files
committed
Add --use-state-labels to override the exit state for firing alerts with labels
If this flag is set the plugin looks for warning/critical/ok in the label 'icingaState'
1 parent 87497ba commit 3c8fb4f

5 files changed

Lines changed: 101 additions & 18 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ Flags:
168168
If no name is given, all alerts will be evaluated
169169
-T, --no-alerts-state string State to assign when no alerts are found (0, 1, 2, 3, OK, WARNING, CRITICAL, UNKNOWN). If not set this defaults to OK (default "OK")
170170
-P, --problems Display only alerts which status is not inactive/OK. Note that in combination with the --name flag this might result in no alerts being displayed
171+
-K, --state-labels-key string Label key for the --use-state-labels. Can be used to override the default label key 'icingaState' (default "icingaState")
172+
-S, --use-state-labels Use the AlertRule label 'icingaState' to override the exit state for firing alerts.
173+
If this flag is set the plugin looks for warning/critical/ok in the label 'icingaState'
171174
```
172175
173176
#### Checking all defined alerts

cmd/alert.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ import (
1616
)
1717

1818
type AlertConfig struct {
19-
AlertName []string
20-
Group []string
21-
ExcludeAlerts []string
22-
ExcludeLabels []string
23-
IncludeLabels []string
24-
ProblemsOnly bool
25-
NoAlertsState string
19+
AlertName []string
20+
Group []string
21+
ExcludeAlerts []string
22+
ExcludeLabels []string
23+
IncludeLabels []string
24+
ProblemsOnly bool
25+
HandleStateLabels bool
26+
HandleStateLabelKey string
27+
NoAlertsState string
2628
}
2729

2830
var cliAlertConfig AlertConfig
@@ -144,8 +146,9 @@ inactive = 0`,
144146

145147
// Handle Inactive Alerts
146148
if len(rl.AlertingRule.Alerts) == 0 {
147-
// Counting states for perfdata
148-
switch rl.GetStatus() {
149+
// Counting states for perfdata. We don't use the state-label override here
150+
// to have the acutal count from Prometheus
151+
switch rl.GetStatus(false, "") {
149152
case 0:
150153
counterInactive++
151154
case 1:
@@ -156,7 +159,7 @@ inactive = 0`,
156159

157160
sc := result.NewPartialResult()
158161

159-
_ = sc.SetState(rl.GetStatus())
162+
_ = sc.SetState(rl.GetStatus(cliAlertConfig.HandleStateLabels, cliAlertConfig.HandleStateLabelKey))
160163
sc.Output = rl.GetOutput()
161164
overall.AddSubcheck(sc)
162165
}
@@ -165,8 +168,9 @@ inactive = 0`,
165168
if len(rl.AlertingRule.Alerts) > 0 {
166169
// Handle Pending or Firing Alerts
167170
for _, alert := range rl.AlertingRule.Alerts {
168-
// Counting states for perfdata
169-
switch rl.GetStatus() {
171+
// Counting states for perfdata. We don't use the state-label override here
172+
// to have the acutal count from Prometheus
173+
switch rl.GetStatus(false, "") {
170174
case 0:
171175
counterInactive++
172176
case 1:
@@ -177,7 +181,7 @@ inactive = 0`,
177181

178182
sc := result.NewPartialResult()
179183

180-
_ = sc.SetState(rl.GetStatus())
184+
_ = sc.SetState(rl.GetStatus(cliAlertConfig.HandleStateLabels, cliAlertConfig.HandleStateLabelKey))
181185
// Set the alert in the internal Type to generate the output
182186
rl.Alert = alert
183187
sc.Output = rl.GetOutput()
@@ -248,6 +252,13 @@ func init() {
248252

249253
fs.BoolVarP(&cliAlertConfig.ProblemsOnly, "problems", "P", false,
250254
"Display only alerts which status is not inactive/OK. Note that in combination with the --name flag this might result in no alerts being displayed")
255+
256+
fs.BoolVarP(&cliAlertConfig.HandleStateLabels, "use-state-labels", "S", false,
257+
"Use the AlertRule label 'icingaState' to override the exit state for firing alerts."+
258+
"\nIf this flag is set the plugin looks for warning/critical/ok in the label 'icingaState'")
259+
260+
fs.StringVarP(&cliAlertConfig.HandleStateLabelKey, "state-labels-key", "K", "icingaState",
261+
"Label key for the --use-state-labels. Can be used to override the default label key 'icingaState'")
251262
}
252263

253264
// Function to convert state to integer.

internal/alert/alert.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ func FlattenRules(groups []v1.RuleGroup, wantedGroups []string) []Rule {
5858
return rules
5959
}
6060

61-
func (a *Rule) GetStatus() (status int) {
62-
switch a.AlertingRule.State {
61+
func (a *Rule) GetStatus(handleStateLabels bool, labelKey string) (status int) {
62+
state := a.AlertingRule.State
63+
64+
switch state {
6365
case string(v1.AlertStateFiring):
6466
status = check.Critical
6567
case string(v1.AlertStatePending):
@@ -70,6 +72,24 @@ func (a *Rule) GetStatus() (status int) {
7072
status = check.Unknown
7173
}
7274

75+
if state == string(v1.AlertStateFiring) && handleStateLabels {
76+
stateLabel, ok := a.AlertingRule.Labels[model.LabelName(labelKey)]
77+
78+
if !ok {
79+
return status
80+
}
81+
82+
lb := strings.ToLower(string(stateLabel))
83+
switch lb {
84+
case "warning":
85+
status = check.Warning
86+
case "critical":
87+
status = check.Critical
88+
case "ok":
89+
status = check.OK
90+
}
91+
}
92+
7393
return status
7494
}
7595

internal/alert/alert_test.go

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
)
1111

1212
func TestGetStatus(t *testing.T) {
13-
1413
testTime := time.Now()
1514

1615
ar := v1.AlertingRule{
@@ -49,19 +48,67 @@ func TestGetStatus(t *testing.T) {
4948
Alert: ar.Alerts[0],
5049
}
5150

52-
actual := r.GetStatus()
51+
actual := r.GetStatus(false, "")
5352
if actual != check.Critical {
5453
t.Error("\nActual: ", actual, "\nExpected: ", check.Critical)
5554
}
5655

5756
r.AlertingRule.State = "pending"
58-
actual = r.GetStatus()
57+
actual = r.GetStatus(false, "")
5958
if actual != check.Warning {
6059
t.Error("\nActual: ", actual, "\nExpected: ", check.Warning)
6160
}
6261

6362
}
6463

64+
func TestGetStatus_WithLabel(t *testing.T) {
65+
ar := v1.AlertingRule{
66+
Alerts: []*v1.Alert{
67+
{
68+
Annotations: model.LabelSet{
69+
"summary": "High request latency",
70+
},
71+
Labels: model.LabelSet{
72+
"alertname": "HighRequestLatency",
73+
"severity": "page",
74+
},
75+
State: v1.AlertStateFiring,
76+
Value: "1e+00",
77+
},
78+
},
79+
Annotations: model.LabelSet{
80+
"summary": "High request latency",
81+
},
82+
Labels: model.LabelSet{
83+
"severity": "page",
84+
"icingaState": "OK",
85+
},
86+
Duration: 600,
87+
Health: v1.RuleHealthGood,
88+
Name: "HighRequestLatency",
89+
Query: "job:request_latency_seconds:mean5m{job=\"myjob\"} > 0.5",
90+
LastError: "",
91+
EvaluationTime: 0.5,
92+
State: "firing",
93+
}
94+
95+
r := Rule{
96+
AlertingRule: ar,
97+
Alert: ar.Alerts[0],
98+
}
99+
100+
actual := r.GetStatus(true, "icingaState")
101+
if actual != check.OK {
102+
t.Error("\nActual: ", actual, "\nExpected: ", check.Critical)
103+
}
104+
105+
r.AlertingRule.State = "pending"
106+
actual = r.GetStatus(true, "icingaState")
107+
if actual != check.Warning {
108+
t.Error("\nActual: ", actual, "\nExpected: ", check.Warning)
109+
}
110+
}
111+
65112
func TestGetOutput(t *testing.T) {
66113

67114
testTime := time.Now()

testdata/alertmanager/alert.rules

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ groups:
77
for: 0m
88
labels:
99
severity: critical
10+
icingaState: warning
1011
annotations:
1112
summary: Prometheus target missing (instance {{ $labels.instance }})
1213
description: "A Prometheus target has disappeared. An exporter might be crashed.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
@@ -16,6 +17,7 @@ groups:
1617
for: 0m
1718
labels:
1819
severity: low
20+
icingaState: warning
1921
annotations:
2022
summary: Prometheus AlertManager job missing (instance {{ $labels.instance }})
2123
description: "A Prometheus AlertManager job has disappeared\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"

0 commit comments

Comments
 (0)