Skip to content

Commit 67fb855

Browse files
authored
Merge pull request #66 from NETWAYS/no-alerts-logic
Rework logic when there are no alerts defined
2 parents 271f051 + c4706c1 commit 67fb855

File tree

4 files changed

+94
-16
lines changed

4 files changed

+94
-16
lines changed

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,12 @@ Examples:
150150
| total=2 firing=1 pending=0 inactive=1
151151
152152
Flags:
153-
-h, --help help for alert
154-
-n, --name strings The name of one or more specific alerts to check.
155-
This parameter can be repeated e.G.: '--name alert1 --name alert2'
156-
If no name is given, all alerts will be evaluated
157-
-P, --problems Display only alerts which status is not inactive/OK
153+
-h, --help help for alert
154+
-n, --name strings The name of one or more specific alerts to check.
155+
This parameter can be repeated e.G.: '--name alert1 --name alert2'
156+
If no name is given, all alerts will be evaluated
157+
-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")
158+
-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
158159
```
159160
160161
#### Checking all defined alerts

cmd/alert.go

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package cmd
22

33
import (
4+
"errors"
45
"fmt"
6+
"strings"
57

68
"github.com/NETWAYS/check_prometheus/internal/alert"
79
"github.com/NETWAYS/go-check"
@@ -10,6 +12,15 @@ import (
1012
"github.com/spf13/cobra"
1113
)
1214

15+
type AlertConfig struct {
16+
AlertName []string
17+
Group []string
18+
ProblemsOnly bool
19+
NoAlertsState string
20+
}
21+
22+
var cliAlertConfig AlertConfig
23+
1324
func contains(s string, list []string) bool {
1425
// Tiny helper to see if a string is in a list of strings
1526
for _, elem := range list {
@@ -40,14 +51,21 @@ inactive = 0`,
4051
\_[CRITICAL] [PrometheusAlertmanagerJobMissing] - Job: [alertmanager] is firing - value: 1.00
4152
| total=2 firing=1 pending=0 inactive=1`,
4253
Run: func(_ *cobra.Command, _ []string) {
54+
// Convert --no-alerts-state to integer and validate input
55+
noAlertsState, err := convertStateToInt(cliAlertConfig.NoAlertsState)
56+
if err != nil {
57+
check.ExitError(fmt.Errorf("invalid value for --no-alerts-state: %s", cliAlertConfig.NoAlertsState))
58+
}
59+
4360
var (
4461
counterFiring int
4562
counterPending int
4663
counterInactive int
4764
)
4865

4966
c := cliConfig.NewClient()
50-
err := c.Connect()
67+
err = c.Connect()
68+
5169
if err != nil {
5270
check.ExitError(err)
5371
}
@@ -65,6 +83,16 @@ inactive = 0`,
6583
// Get all rules from all groups into a single list
6684
rules := alert.FlattenRules(alerts.Groups)
6785

86+
// If there are no rules we can exit early
87+
if len(rules) == 0 {
88+
// Since the user is expecting the state of a certain alert and
89+
// it that is not present it might be noteworthy.
90+
if cliAlertConfig.AlertName != nil {
91+
check.ExitRaw(check.Unknown, "No such alert defined")
92+
}
93+
check.ExitRaw(noAlertsState, "No alerts defined")
94+
}
95+
6896
// Set initial capacity to reduce memory allocations
6997
var l int
7098
for _, rl := range rules {
@@ -164,11 +192,33 @@ inactive = 0`,
164192

165193
func init() {
166194
rootCmd.AddCommand(alertCmd)
195+
167196
fs := alertCmd.Flags()
197+
198+
fs.StringVarP(&cliAlertConfig.NoAlertsState, "no-alerts-state", "T", "OK", "State to assign when no alerts are found (0, 1, 2, 3, OK, WARNING, CRITICAL, UNKNOWN). If not set this defaults to OK")
199+
168200
fs.StringSliceVarP(&cliAlertConfig.AlertName, "name", "n", nil,
169201
"The name of one or more specific alerts to check."+
170202
"\nThis parameter can be repeated e.G.: '--name alert1 --name alert2'"+
171203
"\nIf no name is given, all alerts will be evaluated")
204+
172205
fs.BoolVarP(&cliAlertConfig.ProblemsOnly, "problems", "P", false,
173206
"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")
174207
}
208+
209+
// Function to convert state to integer.
210+
func convertStateToInt(state string) (int, error) {
211+
state = strings.ToUpper(state)
212+
switch state {
213+
case "OK", "0":
214+
return check.OK, nil
215+
case "WARNING", "1":
216+
return check.Warning, nil
217+
case "CRITICAL", "2":
218+
return check.Critical, nil
219+
case "UNKNOWN", "3":
220+
return check.Unknown, nil
221+
default:
222+
return check.Unknown, errors.New("invalid state")
223+
}
224+
}

cmd/alert_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,42 @@ type AlertTest struct {
3131

3232
func TestAlertCmd(t *testing.T) {
3333
tests := []AlertTest{
34+
{
35+
name: "alert-none",
36+
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
37+
w.WriteHeader(http.StatusOK)
38+
w.Write([]byte(`{"status":"success","data":{"groups":[]}}`))
39+
})),
40+
args: []string{"run", "../main.go", "alert"},
41+
expected: "[OK] - No alerts defined\n",
42+
},
43+
{
44+
name: "alert-none-with-problems",
45+
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
46+
w.WriteHeader(http.StatusOK)
47+
w.Write([]byte(`{"status":"success","data":{"groups":[]}}`))
48+
})),
49+
args: []string{"run", "../main.go", "alert", "--problems"},
50+
expected: "[OK] - No alerts defined\n",
51+
},
52+
{
53+
name: "alert-none-with-no-state",
54+
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
55+
w.WriteHeader(http.StatusOK)
56+
w.Write([]byte(`{"status":"success","data":{"groups":[]}}`))
57+
})),
58+
args: []string{"run", "../main.go", "alert", "--no-alerts-state", "3"},
59+
expected: "[UNKNOWN] - No alerts defined\nexit status 3\n",
60+
},
61+
{
62+
name: "alert-none-with-name",
63+
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
64+
w.WriteHeader(http.StatusOK)
65+
w.Write([]byte(`{"status":"success","data":{"groups":[]}}`))
66+
})),
67+
args: []string{"run", "../main.go", "alert", "--name", "MyPreciousAlert"},
68+
expected: "[UNKNOWN] - No such alert defined\nexit status 3\n",
69+
},
3470
{
3571
name: "alert-default",
3672
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

cmd/config.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,6 @@ import (
1515
"github.com/prometheus/common/config"
1616
)
1717

18-
type AlertConfig struct {
19-
AlertName []string
20-
Group []string
21-
ProblemsOnly bool
22-
}
23-
2418
type Config struct {
2519
BasicAuth string `env:"CHECK_PROMETHEUS_BASICAUTH"`
2620
Bearer string `env:"CHECK_PROMETHEUS_BEARER"`
@@ -57,10 +51,7 @@ You should have received a copy of the GNU General Public License
5751
along with this program. If not, see https://www.gnu.org/licenses/.
5852
`
5953

60-
var (
61-
cliConfig Config
62-
cliAlertConfig AlertConfig
63-
)
54+
var cliConfig Config
6455

6556
func (c *Config) NewClient() *client.Client {
6657
u := url.URL{

0 commit comments

Comments
 (0)