Skip to content

Commit

Permalink
Add rule/for check
Browse files Browse the repository at this point in the history
  • Loading branch information
prymitive committed Mar 1, 2023
1 parent 17a8330 commit b83b6d6
Show file tree
Hide file tree
Showing 11 changed files with 471 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmd/pint/tests/0025_config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ level=info msg="Loading configuration file" path=.pint.hcl
"query/cost",
"promql/series",
"rule/duplicate",
"rule/for",
"rule/label",
"rule/link",
"rule/reject"
Expand Down
1 change: 1 addition & 0 deletions cmd/pint/tests/0113_config_env_expand.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ level=info msg="Loading configuration file" path=.pint.hcl
"query/cost",
"promql/series",
"rule/duplicate",
"rule/for",
"rule/label",
"rule/link",
"rule/reject"
Expand Down
36 changes: 36 additions & 0 deletions cmd/pint/tests/0121_rule_for.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
pint.error --no-color lint rules
! stdout .
cmp stderr stderr.txt

-- stderr.txt --
level=info msg="Loading configuration file" path=.pint.hcl
rules/0001.yml:6 Bug: this alert rule must have a 'for' field with a minimum duration of 5m (rule/for)
6 | for: 3m

rules/0001.yml:9 Bug: this alert rule must have a 'for' field with a maximum duration of 10m (rule/for)
9 | for: 13m

level=info msg="Problems found" Bug=2
level=fatal msg="Fatal error" error="problems found"
-- rules/0001.yml --
- alert: ok
expr: up == 0
for: 5m
- alert: 3m
expr: up == 0
for: 3m
- alert: 13m
expr: up == 0
for: 13m

-- .pint.hcl --
parser {
relaxed = [".*"]
}
rule {
for {
severity = "bug"
min = "5m"
max = "10m"
}
}
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- alert: my alert
expr: rate(my:sum[5m])
```
- Added [rule/for](checks/rule/for.md) check.
### Changed
Expand Down
64 changes: 64 additions & 0 deletions docs/checks/rule/for.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
layout: default
parent: Checks
grand_parent: Documentation
---

# rule/for

This check allows to enforce the presence of `for` field on alerting
rules.
You can configure it to enforce some minimal and/or maximum duration
set on alerts via `for` field.

## Configuration

This check doesn't have any configuration options.

## How to enable it

Syntax:

```js
for {
severity = "bug|warning|info"
min = "5m"
max = "10m"
}
```

- `severity` - set custom severity for reported issues, defaults to a bug.
- `min` - minimum required `for` value for matching alerting rules.
If not set minimum `for` duration won't be enforced.
- `max` - maximum allowed `for` value for matching alerting rules.
- If not set maximum `for` duration won't be enforced.

## How to disable it

You can disable this check globally by adding this config block:

```js
checks {
disabled = ["rule/for"]
}
```

You can also disable it for all rules inside given file by adding
a comment anywhere in that file. Example:

`# pint file/disable rule/for`

Or you can disable it per rule by adding a comment to it. Example:

`# pint disable rule/for`

## How to snooze it

You can disable this check until given time by adding a comment to it. Example:

`# pint snooze $TIMESTAMP rule/for`

Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339)
formatted or `YYYY-MM-DD`.
Adding this comment will disable `rule/duplicate` *until* `$TIMESTAMP`, after that
check will be re-enabled.
1 change: 1 addition & 0 deletions internal/checks/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var (
CostCheckName,
SeriesCheckName,
RuleDuplicateCheckName,
RuleForCheckName,
LabelCheckName,
RuleLinkCheckName,
RejectCheckName,
Expand Down
82 changes: 82 additions & 0 deletions internal/checks/rule_for.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package checks

import (
"context"
"fmt"
"time"

"github.com/cloudflare/pint/internal/discovery"
"github.com/cloudflare/pint/internal/output"
"github.com/cloudflare/pint/internal/parser"
)

const (
RuleForCheckName = "rule/for"
)

func NewRuleForCheck(minFor, maxFor time.Duration, severity Severity) RuleForCheck {
return RuleForCheck{
minFor: minFor,
maxFor: maxFor,
severity: severity,
}
}

type RuleForCheck struct {
severity Severity
minFor time.Duration
maxFor time.Duration
}

func (c RuleForCheck) Meta() CheckMeta {
return CheckMeta{IsOnline: true}
}

func (c RuleForCheck) String() string {
return fmt.Sprintf("%s(%s:%s)", RuleForCheckName, output.HumanizeDuration(c.minFor), output.HumanizeDuration(c.maxFor))
}

func (c RuleForCheck) Reporter() string {
return RuleForCheckName
}

func (c RuleForCheck) Check(ctx context.Context, path string, rule parser.Rule, entries []discovery.Entry) (problems []Problem) {
if rule.AlertingRule == nil {
return nil
}

var forDur time.Duration
var fragment string
var lines []int
if rule.AlertingRule.For != nil {
forDur, _ = time.ParseDuration(rule.AlertingRule.For.Value.Value)
fragment = rule.AlertingRule.For.Value.Value
lines = rule.AlertingRule.For.Lines()
}
if fragment == "" {
fragment = rule.AlertingRule.Alert.Value.Value
lines = rule.AlertingRule.Alert.Lines()
}

if forDur < c.minFor {
problems = append(problems, Problem{
Fragment: fragment,
Lines: lines,
Reporter: c.Reporter(),
Text: fmt.Sprintf("this alert rule must have a 'for' field with a minimum duration of %s", output.HumanizeDuration(c.minFor)),
Severity: c.severity,
})
}

if c.maxFor > 0 && forDur > c.maxFor {
problems = append(problems, Problem{
Fragment: fragment,
Lines: lines,
Reporter: c.Reporter(),
Text: fmt.Sprintf("this alert rule must have a 'for' field with a maximum duration of %s", output.HumanizeDuration(c.maxFor)),
Severity: c.severity,
})
}

return problems
}
Loading

0 comments on commit b83b6d6

Please sign in to comment.