Skip to content

Rework logic when there are no alerts defined #66

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,12 @@ Examples:
| total=2 firing=1 pending=0 inactive=1

Flags:
-h, --help help for alert
-n, --name strings The name of one or more specific alerts to check.
This parameter can be repeated e.G.: '--name alert1 --name alert2'
If no name is given, all alerts will be evaluated
-P, --problems Display only alerts which status is not inactive/OK
-h, --help help for alert
-n, --name strings The name of one or more specific alerts to check.
This parameter can be repeated e.G.: '--name alert1 --name alert2'
If no name is given, all alerts will be evaluated
-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")
-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
```

#### Checking all defined alerts
Expand Down
52 changes: 51 additions & 1 deletion cmd/alert.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package cmd

import (
"errors"
"fmt"
"strings"

"github.com/NETWAYS/check_prometheus/internal/alert"
"github.com/NETWAYS/go-check"
Expand All @@ -10,6 +12,15 @@ import (
"github.com/spf13/cobra"
)

type AlertConfig struct {
AlertName []string
Group []string
ProblemsOnly bool
NoAlertsState string
}

var cliAlertConfig AlertConfig

func contains(s string, list []string) bool {
// Tiny helper to see if a string is in a list of strings
for _, elem := range list {
Expand Down Expand Up @@ -40,14 +51,21 @@ inactive = 0`,
\_[CRITICAL] [PrometheusAlertmanagerJobMissing] - Job: [alertmanager] is firing - value: 1.00
| total=2 firing=1 pending=0 inactive=1`,
Run: func(_ *cobra.Command, _ []string) {
// Convert --no-alerts-state to integer and validate input
noAlertsState, err := convertStateToInt(cliAlertConfig.NoAlertsState)
if err != nil {
check.ExitError(fmt.Errorf("invalid value for --no-alerts-state: %s", cliAlertConfig.NoAlertsState))
}

var (
counterFiring int
counterPending int
counterInactive int
)

c := cliConfig.NewClient()
err := c.Connect()
err = c.Connect()

if err != nil {
check.ExitError(err)
}
Expand All @@ -65,6 +83,16 @@ inactive = 0`,
// Get all rules from all groups into a single list
rules := alert.FlattenRules(alerts.Groups)

// If there are no rules we can exit early
if len(rules) == 0 {
// Since the user is expecting the state of a certain alert and
// it that is not present it might be noteworthy.
if cliAlertConfig.AlertName != nil {
check.ExitRaw(check.Unknown, "No such alert defined")
}
check.ExitRaw(noAlertsState, "No alerts defined")
}

// Set initial capacity to reduce memory allocations
var l int
for _, rl := range rules {
Expand Down Expand Up @@ -164,11 +192,33 @@ inactive = 0`,

func init() {
rootCmd.AddCommand(alertCmd)

fs := alertCmd.Flags()

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")

fs.StringSliceVarP(&cliAlertConfig.AlertName, "name", "n", nil,
"The name of one or more specific alerts to check."+
"\nThis parameter can be repeated e.G.: '--name alert1 --name alert2'"+
"\nIf no name is given, all alerts will be evaluated")

fs.BoolVarP(&cliAlertConfig.ProblemsOnly, "problems", "P", false,
"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")
}

// Function to convert state to integer.
func convertStateToInt(state string) (int, error) {
state = strings.ToUpper(state)
switch state {
case "OK", "0":
return check.OK, nil
case "WARNING", "1":
return check.Warning, nil
case "CRITICAL", "2":
return check.Critical, nil
case "UNKNOWN", "3":
return check.Unknown, nil
default:
return check.Unknown, errors.New("invalid state")
}
}
36 changes: 36 additions & 0 deletions cmd/alert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,42 @@ type AlertTest struct {

func TestAlertCmd(t *testing.T) {
tests := []AlertTest{
{
name: "alert-none",
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"success","data":{"groups":[]}}`))
})),
args: []string{"run", "../main.go", "alert"},
expected: "[OK] - No alerts defined\n",
},
{
name: "alert-none-with-problems",
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"success","data":{"groups":[]}}`))
})),
args: []string{"run", "../main.go", "alert", "--problems"},
expected: "[OK] - No alerts defined\n",
},
{
name: "alert-none-with-no-state",
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"success","data":{"groups":[]}}`))
})),
args: []string{"run", "../main.go", "alert", "--no-alerts-state", "3"},
expected: "[UNKNOWN] - No alerts defined\nexit status 3\n",
},
{
name: "alert-none-with-name",
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"success","data":{"groups":[]}}`))
})),
args: []string{"run", "../main.go", "alert", "--name", "MyPreciousAlert"},
expected: "[UNKNOWN] - No such alert defined\nexit status 3\n",
},
{
name: "alert-default",
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand Down
11 changes: 1 addition & 10 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ import (
"github.com/prometheus/common/config"
)

type AlertConfig struct {
AlertName []string
Group []string
ProblemsOnly bool
}

type Config struct {
BasicAuth string `env:"CHECK_PROMETHEUS_BASICAUTH"`
Bearer string `env:"CHECK_PROMETHEUS_BEARER"`
Expand Down Expand Up @@ -57,10 +51,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see https://www.gnu.org/licenses/.
`

var (
cliConfig Config
cliAlertConfig AlertConfig
)
var cliConfig Config

func (c *Config) NewClient() *client.Client {
u := url.URL{
Expand Down
Loading