From f771d0fb1a2c8fbc24fd5905fbe46da370f58f46 Mon Sep 17 00:00:00 2001 From: Lukasz Mierzwa Date: Mon, 28 Nov 2022 11:32:31 +0000 Subject: [PATCH] Allow snoozing checks --- cmd/pint/tests/0111_snooze.txt | 27 ++ cmd/pint/tests/0112_expired_snooze.txt | 34 ++ docs/changelog.md | 16 + docs/checks/alerts/annotation.md | 11 + docs/checks/alerts/comparison.md | 11 + docs/checks/alerts/count.md | 11 + docs/checks/alerts/for.md | 11 + docs/checks/alerts/template.md | 11 + docs/checks/labels/conflict.md | 11 + docs/checks/promql/aggregate.md | 11 + docs/checks/promql/fragile.md | 11 + docs/checks/promql/range_query.md | 13 +- docs/checks/promql/rate.md | 13 +- docs/checks/promql/regexp.md | 11 + docs/checks/promql/series.md | 11 + docs/checks/promql/syntax.md | 11 + docs/checks/promql/vector_matching.md | 11 + docs/checks/query/cost.md | 11 + docs/checks/rule/duplicate.md | 11 + docs/checks/rule/label.md | 11 + docs/checks/rule/link.md | 11 + docs/checks/rule/reject.md | 11 + docs/ignoring.md | 19 ++ .../config/__snapshots__/config_test.snap | 295 ++++++++++++++++++ internal/config/config_test.go | 39 +++ internal/config/rule.go | 67 +++- 26 files changed, 705 insertions(+), 5 deletions(-) create mode 100644 cmd/pint/tests/0111_snooze.txt create mode 100644 cmd/pint/tests/0112_expired_snooze.txt diff --git a/cmd/pint/tests/0111_snooze.txt b/cmd/pint/tests/0111_snooze.txt new file mode 100644 index 00000000..9afae0a9 --- /dev/null +++ b/cmd/pint/tests/0111_snooze.txt @@ -0,0 +1,27 @@ +pint.ok -l debug --no-color lint rules +! stdout . +cmp stderr stderr.txt + +-- stderr.txt -- +level=info msg="Loading configuration file" path=.pint.hcl +level=debug msg="File parsed" path=rules/0001.yml rules=1 +level=debug msg="Found recording rule" lines=2-3 path=rules/0001.yml record=sum-job +level=debug msg="Check snoozed by comment" check=promql/aggregate(job:true) comment="snooze 2099-11-28T10:24:18Z promql/aggregate" snooze=promql/aggregate until=2099-11-28T10:24:18Z +level=debug msg="Configured checks for rule" enabled=["promql/syntax","alerts/for","alerts/comparison","alerts/template","promql/fragile","promql/regexp"] path=rules/0001.yml rule=sum-job +-- rules/0001.yml -- +# pint snooze 2099-11-28T10:24:18Z promql/aggregate +- record: sum-job + expr: sum(foo) + +-- .pint.hcl -- +parser { + relaxed = [".*"] +} +rule { + match { + kind = "recording" + } + aggregate ".+" { + keep = [ "job" ] + } +} diff --git a/cmd/pint/tests/0112_expired_snooze.txt b/cmd/pint/tests/0112_expired_snooze.txt new file mode 100644 index 00000000..2c2f2b36 --- /dev/null +++ b/cmd/pint/tests/0112_expired_snooze.txt @@ -0,0 +1,34 @@ +pint.error -l debug --no-color lint rules +! stdout . +cmp stderr stderr.txt + +-- stderr.txt -- +level=info msg="Loading configuration file" path=.pint.hcl +level=debug msg="File parsed" path=rules/0001.yml rules=1 +level=debug msg="Found recording rule" lines=2-3 path=rules/0001.yml record=sum-job +level=debug msg="Expired snooze" check=promql/aggregate(job:true) comment="snooze 2000-11-28T10:24:18Z promql/aggregate" snooze=promql/aggregate until=2000-11-28T10:24:18Z +level=debug msg="Expired snooze" check=promql/aggregate(job:true) comment="snooze 2000-11-28T10:24:18Z promql/aggregate" snooze=promql/aggregate until=2000-11-28T10:24:18Z +level=debug msg="Configured checks for rule" enabled=["promql/syntax","alerts/for","alerts/comparison","alerts/template","promql/fragile","promql/regexp","promql/aggregate(job:true)"] path=rules/0001.yml rule=sum-job +rules/0001.yml:3: job label is required and should be preserved when aggregating "^.+$" rules, use by(job, ...) (promql/aggregate) + 3 | expr: sum(foo) + +level=info msg="Problems found" Bug=1 +level=fatal msg="Fatal error" error="problems found" +-- rules/0001.yml -- +# pint snooze 2000-11-28T10:24:18Z promql/aggregate +- record: sum-job + expr: sum(foo) + +-- .pint.hcl -- +parser { + relaxed = [".*"] +} +rule { + match { + kind = "recording" + } + aggregate ".+" { + keep = [ "job" ] + severity = "bug" + } +} diff --git a/docs/changelog.md b/docs/changelog.md index eec48023..7cf238a1 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -7,6 +7,22 @@ - Use [uber-go/automaxprocs](https://github.com/uber-go/automaxprocs) to automatically set GOMAXPROCS to match Linux container CPU quota. - Added [labels/conflict](checks/labels/conflict.md) check. +- If you want to disable invididual checks just for some time then you can now + snooze them instead of disabling forever. + + The difference between `# pint disable ...` and `# pint snooze ...` comments is that + the snooze comment must include a timestamp. Selected check will be disabled *until* + that timestamp. + Timestamp must either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) syntax + or `YYYY-MM-DD` (if you don't care about time and want to snooze until given date). + Examples: + + ```yaml + # pint snooze 2023-01-12T10:00:00Z promql/series + # pint snooze 2023-01-12 promql/rate + - record: ... + expr: ... + ``` ## v0.34.0 diff --git a/docs/checks/alerts/annotation.md b/docs/checks/alerts/annotation.md index d79706ce..c6516662 100644 --- a/docs/checks/alerts/annotation.md +++ b/docs/checks/alerts/annotation.md @@ -143,3 +143,14 @@ annotation "dashboard" { Example comment disabling that rule: `# pint disable alerts/annotation(dashboard:https://grafana\.example\.com/.+:true)` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP alerts/annotation` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `alerts/annotation` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/alerts/comparison.md b/docs/checks/alerts/comparison.md index 204db636..c3a6fac5 100644 --- a/docs/checks/alerts/comparison.md +++ b/docs/checks/alerts/comparison.md @@ -49,3 +49,14 @@ a comment anywhere in that file. Example: Or you can disable it per rule by adding a comment to it. Example: `# pint disable alerts/comparison` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP alerts/comparison` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `alerts/comparison` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/alerts/count.md b/docs/checks/alerts/count.md index 9a38bc38..ae7a3451 100644 --- a/docs/checks/alerts/count.md +++ b/docs/checks/alerts/count.md @@ -84,3 +84,14 @@ Where `$prometheus` is the name of Prometheus server to disable. Example: `# pint disable alerts/count(prod)` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP alerts/count` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `alerts/count` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/alerts/for.md b/docs/checks/alerts/for.md index 8885322d..c16cb04b 100644 --- a/docs/checks/alerts/for.md +++ b/docs/checks/alerts/for.md @@ -35,3 +35,14 @@ a comment anywhere in that file. Example: Or you can disable it per rule by adding a comment to it. Example: `# pint disable alerts/for` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP alerts/for` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `alerts/for` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/alerts/template.md b/docs/checks/alerts/template.md index 0a431c0a..149a4607 100644 --- a/docs/checks/alerts/template.md +++ b/docs/checks/alerts/template.md @@ -52,3 +52,14 @@ a comment anywhere in that file. Example: Or you can disable it per rule by adding a comment to it. Example: `# pint disable alerts/template` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP alerts/template` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `alerts/template` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/labels/conflict.md b/docs/checks/labels/conflict.md index d8f7ee0d..581077c6 100644 --- a/docs/checks/labels/conflict.md +++ b/docs/checks/labels/conflict.md @@ -75,3 +75,14 @@ Where `$prometheus` is the name of Prometheus server to disable. Example: `# pint disable labels/conflict(prod)` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP labels/conflict` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `labels/conflict` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/promql/aggregate.md b/docs/checks/promql/aggregate.md index 37eff3d0..0f48bf8a 100644 --- a/docs/checks/promql/aggregate.md +++ b/docs/checks/promql/aggregate.md @@ -113,3 +113,14 @@ Example: Example: `# pint disable promql/aggregate(instance:true)` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP promql/aggregate` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `promql/aggregate` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/promql/fragile.md b/docs/checks/promql/fragile.md index 9a07078f..36df8970 100644 --- a/docs/checks/promql/fragile.md +++ b/docs/checks/promql/fragile.md @@ -121,3 +121,14 @@ a comment anywhere in that file. Example: Or you can disable it per rule by adding a comment to it. Example: `# pint disable promql/fragile` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP promql/fragile` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `promql/fragile` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/promql/range_query.md b/docs/checks/promql/range_query.md index dba19220..dba1c94a 100644 --- a/docs/checks/promql/range_query.md +++ b/docs/checks/promql/range_query.md @@ -91,4 +91,15 @@ Where `$prometheus` is the name of Prometheus server to disable. Example: -`# pint disable promql/range_query(prod)` \ No newline at end of file +`# pint disable promql/range_query(prod)` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP promql/range_query` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `promql/range_query` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/promql/rate.md b/docs/checks/promql/rate.md index 7c7480e1..b60a9d14 100644 --- a/docs/checks/promql/rate.md +++ b/docs/checks/promql/rate.md @@ -101,4 +101,15 @@ Where `$prometheus` is the name of Prometheus server to disable. Example: -`# pint disable promql/rate(prod)` \ No newline at end of file +`# pint disable promql/rate(prod)` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP promql/rate` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `promql/rate` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/promql/regexp.md b/docs/checks/promql/regexp.md index 0b4c7cea..d363edbb 100644 --- a/docs/checks/promql/regexp.md +++ b/docs/checks/promql/regexp.md @@ -61,3 +61,14 @@ a comment anywhere in that file. Example: Or you can disable it per rule by adding a comment to it. Example: `# pint disable promql/regexp` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP promql/regexp` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `promql/regexp` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/promql/series.md b/docs/checks/promql/series.md index 57b91463..ce59d1f3 100644 --- a/docs/checks/promql/series.md +++ b/docs/checks/promql/series.md @@ -306,3 +306,14 @@ Example: # pint disable promql/series({job="dev"}) expr: my_metric_name{job="dev", instance="a"} / other_metric_name{job="dev", instance="b"} ``` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP promql/series` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `promql/series` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/promql/syntax.md b/docs/checks/promql/syntax.md index 9d1d0329..634dde68 100644 --- a/docs/checks/promql/syntax.md +++ b/docs/checks/promql/syntax.md @@ -35,3 +35,14 @@ a comment anywhere in that file. Example: Or you can disable it per rule by adding a comment to it. Example: `# pint disable promql/syntax` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP promql/syntax` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `promql/syntax` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/promql/vector_matching.md b/docs/checks/promql/vector_matching.md index 19d2a160..024e2972 100644 --- a/docs/checks/promql/vector_matching.md +++ b/docs/checks/promql/vector_matching.md @@ -105,3 +105,14 @@ Where `$prometheus` is the name of Prometheus server to disable. Example: `# pint disable promql/vector_matching(prod)` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP promql/vector_matching` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `promql/vector_matching` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/query/cost.md b/docs/checks/query/cost.md index eb4210ec..9dbacb26 100644 --- a/docs/checks/query/cost.md +++ b/docs/checks/query/cost.md @@ -109,3 +109,14 @@ Where `$prometheus` is the name of Prometheus server to disable. Example: `# pint disable query/cost(dev)` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP query/cost` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `query/cost` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/rule/duplicate.md b/docs/checks/rule/duplicate.md index a4987e86..9dc4c1e8 100644 --- a/docs/checks/rule/duplicate.md +++ b/docs/checks/rule/duplicate.md @@ -79,3 +79,14 @@ Where `$prometheus` is the name of Prometheus server to disable. Example: `# pint disable rule/duplicate(prod)` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP rule/duplicate` + +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. diff --git a/docs/checks/rule/label.md b/docs/checks/rule/label.md index 10e3e550..edde9de9 100644 --- a/docs/checks/rule/label.md +++ b/docs/checks/rule/label.md @@ -121,3 +121,14 @@ label "severity" { Example comment disabling that rule: `# pint disable rule/label(severity:true)` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP rule/label` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `rule/label` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/rule/link.md b/docs/checks/rule/link.md index d5456f8c..f4d80b2d 100644 --- a/docs/checks/rule/link.md +++ b/docs/checks/rule/link.md @@ -115,3 +115,14 @@ you can add a more specific comment. Example: `# pint disable rule/link(^https?://.+$)` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP rule/link` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `rule/link` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/checks/rule/reject.md b/docs/checks/rule/reject.md index ec0c24d0..d71172b1 100644 --- a/docs/checks/rule/reject.md +++ b/docs/checks/rule/reject.md @@ -123,3 +123,14 @@ Example: Example: `# pint disable rule/reject(val=~'^https?://.+$')` + +## How to snooze it + +You can disable this check until given time by adding a comment to it. Example: + +`# pint snooze $TIMESTAMP rule/reject` + +Where `$TIMESTAMP` is either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) +formatted or `YYYY-MM-DD`. +Adding this comment will disable `rule/reject` *until* `$TIMESTAMP`, after that +check will be re-enabled. diff --git a/docs/ignoring.md b/docs/ignoring.md index f30fab06..7b85ea7f 100644 --- a/docs/ignoring.md +++ b/docs/ignoring.md @@ -105,3 +105,22 @@ A single comment can only disable one check, so repeat it for every check you wi to disable. See each individual [check](checks/index.md) documentation for details. + +## Snoozing individual checks for specific rules + +If you want to disable invididual checks just for some time then you can snooze them +instead of disabling forever. + +The difference between `# pint disable ...` and `# pint snooze ...` comments is that +the snooze comment must include a timestamp. Selected check will be disabled *until* +that timestamp. +Timestamp must either use [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) syntax +or `YYYY-MM-DD` (if you don't care about time and want to snooze until given date). +Examples: + +```yaml +# pint snooze 2023-01-12T10:00:00Z promql/series +# pint snooze 2023-01-12 promql/rate +- record: ... + expr: ... +``` diff --git a/internal/config/__snapshots__/config_test.snap b/internal/config/__snapshots__/config_test.snap index 7392c05a..2b6bed3e 100755 --- a/internal/config/__snapshots__/config_test.snap +++ b/internal/config/__snapshots__/config_test.snap @@ -1903,6 +1903,65 @@ } --- +[TestGetChecksForRule/two_prometheus_servers_/_snoozed_checks_via_comment - 1] +{ + "ci": { + "maxCommits": 20, + "baseBranch": "master" + }, + "parser": {}, + "prometheus": [ + { + "name": "prom1", + "uri": "http://localhost/1", + "timeout": "1s", + "concurrency": 16, + "rateLimit": 100, + "cache": 50000, + "uptime": "up", + "required": false + }, + { + "name": "prom2", + "uri": "http://localhost/2", + "timeout": "1s", + "concurrency": 16, + "rateLimit": 100, + "cache": 50000, + "uptime": "up", + "required": false + } + ], + "checks": { + "enabled": [ + "alerts/annotation", + "alerts/count", + "alerts/for", + "alerts/template", + "labels/conflict", + "promql/aggregate", + "alerts/comparison", + "promql/fragile", + "promql/range_query", + "promql/rate", + "promql/regexp", + "promql/syntax", + "promql/vector_matching", + "query/cost", + "promql/series", + "rule/duplicate", + "rule/label", + "rule/link", + "rule/reject" + ], + "disabled": [ + "alerts/template", + "promql/regexp" + ] + } +} +--- + [TestGetChecksForRule/defaults - 2] { "ci": { @@ -3807,6 +3866,65 @@ } --- +[TestGetChecksForRule/two_prometheus_servers_/_snoozed_checks_via_comment - 2] +{ + "ci": { + "maxCommits": 20, + "baseBranch": "master" + }, + "parser": {}, + "prometheus": [ + { + "name": "prom1", + "uri": "http://localhost/1", + "timeout": "1s", + "concurrency": 16, + "rateLimit": 100, + "cache": 50000, + "uptime": "up", + "required": false + }, + { + "name": "prom2", + "uri": "http://localhost/2", + "timeout": "1s", + "concurrency": 16, + "rateLimit": 100, + "cache": 50000, + "uptime": "up", + "required": false + } + ], + "checks": { + "enabled": [ + "alerts/annotation", + "alerts/count", + "alerts/for", + "alerts/template", + "labels/conflict", + "promql/aggregate", + "alerts/comparison", + "promql/fragile", + "promql/range_query", + "promql/rate", + "promql/regexp", + "promql/syntax", + "promql/vector_matching", + "query/cost", + "promql/series", + "rule/duplicate", + "rule/label", + "rule/link", + "rule/reject" + ], + "disabled": [ + "alerts/template", + "promql/regexp" + ] + } +} +--- + [TestGetChecksForRule/defaults - 3] { "ci": { @@ -5711,6 +5829,65 @@ } --- +[TestGetChecksForRule/two_prometheus_servers_/_snoozed_checks_via_comment - 3] +{ + "ci": { + "maxCommits": 20, + "baseBranch": "master" + }, + "parser": {}, + "prometheus": [ + { + "name": "prom1", + "uri": "http://localhost/1", + "timeout": "1s", + "concurrency": 16, + "rateLimit": 100, + "cache": 50000, + "uptime": "up", + "required": false + }, + { + "name": "prom2", + "uri": "http://localhost/2", + "timeout": "1s", + "concurrency": 16, + "rateLimit": 100, + "cache": 50000, + "uptime": "up", + "required": false + } + ], + "checks": { + "enabled": [ + "alerts/annotation", + "alerts/count", + "alerts/for", + "alerts/template", + "labels/conflict", + "promql/aggregate", + "alerts/comparison", + "promql/fragile", + "promql/range_query", + "promql/rate", + "promql/regexp", + "promql/syntax", + "promql/vector_matching", + "query/cost", + "promql/series", + "rule/duplicate", + "rule/label", + "rule/link", + "rule/reject" + ], + "disabled": [ + "alerts/template", + "promql/regexp" + ] + } +} +--- + [TestGetChecksForRule/defaults - 4] { "ci": { @@ -7615,6 +7792,65 @@ } --- +[TestGetChecksForRule/two_prometheus_servers_/_snoozed_checks_via_comment - 4] +{ + "ci": { + "maxCommits": 20, + "baseBranch": "master" + }, + "parser": {}, + "prometheus": [ + { + "name": "prom1", + "uri": "http://localhost/1", + "timeout": "1s", + "concurrency": 16, + "rateLimit": 100, + "cache": 50000, + "uptime": "up", + "required": false + }, + { + "name": "prom2", + "uri": "http://localhost/2", + "timeout": "1s", + "concurrency": 16, + "rateLimit": 100, + "cache": 50000, + "uptime": "up", + "required": false + } + ], + "checks": { + "enabled": [ + "alerts/annotation", + "alerts/count", + "alerts/for", + "alerts/template", + "labels/conflict", + "promql/aggregate", + "alerts/comparison", + "promql/fragile", + "promql/range_query", + "promql/rate", + "promql/regexp", + "promql/syntax", + "promql/vector_matching", + "query/cost", + "promql/series", + "rule/duplicate", + "rule/label", + "rule/link", + "rule/reject" + ], + "disabled": [ + "alerts/template", + "promql/regexp" + ] + } +} +--- + [TestGetChecksForRule/defaults - 5] { "ci": { @@ -9518,3 +9754,62 @@ } } --- + +[TestGetChecksForRule/two_prometheus_servers_/_snoozed_checks_via_comment - 5] +{ + "ci": { + "maxCommits": 20, + "baseBranch": "master" + }, + "parser": {}, + "prometheus": [ + { + "name": "prom1", + "uri": "http://localhost/1", + "timeout": "1s", + "concurrency": 16, + "rateLimit": 100, + "cache": 50000, + "uptime": "up", + "required": false + }, + { + "name": "prom2", + "uri": "http://localhost/2", + "timeout": "1s", + "concurrency": 16, + "rateLimit": 100, + "cache": 50000, + "uptime": "up", + "required": false + } + ], + "checks": { + "enabled": [ + "alerts/annotation", + "alerts/count", + "alerts/for", + "alerts/template", + "labels/conflict", + "promql/aggregate", + "alerts/comparison", + "promql/fragile", + "promql/range_query", + "promql/rate", + "promql/regexp", + "promql/syntax", + "promql/vector_matching", + "query/cost", + "promql/series", + "rule/duplicate", + "rule/label", + "rule/link", + "rule/reject" + ], + "disabled": [ + "alerts/template", + "promql/regexp" + ] + } +} +--- diff --git a/internal/config/config_test.go b/internal/config/config_test.go index c10ff17a..8281e44d 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -1193,6 +1193,45 @@ checks { }, disabledChecks: []string{"promql/rate", "promql/vector_matching", "rule/duplicate", "labels/conflict"}, }, + { + title: "two prometheus servers / snoozed checks via comment", + config: ` +prometheus "prom1" { + uri = "http://localhost/1" + timeout = "1s" +} +prometheus "prom2" { + uri = "http://localhost/2" + timeout = "1s" +} +checks { + disabled = [ "alerts/template", "promql/regexp" ] +} +`, + path: "rules.yml", + rule: newRule(t, ` +# pint snooze 2099-11-AB labels/conflict +# pint snooze 2099-11-28 labels/conflict won't work +# pint snooze 2099-11-28 +# pint snooze 2099-11-28 promql/series(prom1) +# pint snooze 2099-11-28T10:24:18Z promql/range_query +# pint snooze 2099-11-28 rule/duplicate +# pint snooze 2099-11-28T00:00:00+00:00 promql/vector_matching +- record: foo + expr: sum(foo) +# pint file/disable promql/vector_matching +`), + checks: []string{ + checks.SyntaxCheckName, + checks.AlertForCheckName, + checks.ComparisonCheckName, + checks.FragileCheckName, + checks.LabelsConflictCheckName + "(prom1)", + checks.SeriesCheckName + "(prom2)", + checks.LabelsConflictCheckName + "(prom2)", + }, + disabledChecks: []string{"promql/rate"}, + }, } dir := t.TempDir() diff --git a/internal/config/rule.go b/internal/config/rule.go index 944a7dbe..9eb660fb 100644 --- a/internal/config/rule.go +++ b/internal/config/rule.go @@ -4,9 +4,11 @@ import ( "context" "fmt" "regexp" + "strings" "time" "github.com/rs/zerolog/log" + "golang.org/x/exp/slices" "github.com/cloudflare/pint/internal/checks" "github.com/cloudflare/pint/internal/parser" @@ -237,11 +239,11 @@ func (rule Rule) resolveChecks(ctx context.Context, path string, r parser.Rule, func isEnabled(enabledChecks, disabledChecks []string, rule parser.Rule, name string, check checks.RuleChecker) bool { instance := check.String() - comments := []string{ + + for _, comment := range []string{ fmt.Sprintf("disable %s", name), fmt.Sprintf("disable %s", instance), - } - for _, comment := range comments { + } { if rule.HasComment(comment) { log.Debug(). Str("check", instance). @@ -251,6 +253,34 @@ func isEnabled(enabledChecks, disabledChecks []string, rule parser.Rule, name st } } + now := time.Now() + disabled := []string{name, instance} + for _, comment := range rule.GetComments("snooze") { + s := parseSnooze(comment.Value) + if s == nil { + continue + } + if !slices.Contains(disabled, s.text) { + continue + } + if !s.until.After(now) { + log.Debug(). + Str("check", instance). + Str("comment", comment.String()). + Time("until", s.until). + Str("snooze", s.text). + Msg("Expired snooze") + continue + } + log.Debug(). + Str("check", instance). + Str("comment", comment.String()). + Time("until", s.until). + Str("snooze", s.text). + Msg("Check snoozed by comment") + return false + } + for _, c := range disabledChecks { if c == name || c == instance { return false @@ -267,6 +297,37 @@ func isEnabled(enabledChecks, disabledChecks []string, rule parser.Rule, name st return false } +type snoozed struct { + until time.Time + text string +} + +func parseSnooze(comment string) *snoozed { + parts := strings.SplitN(comment, " ", 2) + if len(parts) != 2 { + return nil + } + + s := snoozed{text: parts[1]} + + var ts time.Time + var err error + + ts, err = time.Parse(time.RFC3339, parts[0]) + if err == nil { + s.until = ts + return &s + } + + ts, err = time.Parse("2006-01-02", parts[0]) + if err == nil { + s.until = ts + return &s + } + + return nil +} + func strictRegex(s string) *regexp.Regexp { return regexp.MustCompile("^" + s + "$") }