forked from cloudflare/pint
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
1,065 additions
and
597 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
--- | ||
layout: default | ||
parent: Checks | ||
grand_parent: Documentation | ||
--- | ||
|
||
# labels/conflict | ||
|
||
This check will look for any conflicting labels used in rules. | ||
Below is the list of conflicts it looks for. | ||
|
||
## External labels | ||
|
||
If recording rules are manually setting some lables that are | ||
already present in `external_labels` Prometheus configuration option | ||
then both labels might conflict when metrics are federated or when sending | ||
alerts. | ||
|
||
## Configuration | ||
|
||
This check doesn't have any configuration options. | ||
|
||
## How to enable it | ||
|
||
This check is enabled by default for all configured Prometheus servers. | ||
|
||
Example: | ||
|
||
```js | ||
prometheus "prod" { | ||
uri = "https://prometheus-prod.example.com" | ||
timeout = "60s" | ||
include = [ | ||
"rules/prod/.*", | ||
"rules/common/.*", | ||
] | ||
} | ||
|
||
prometheus "dev" { | ||
uri = "https://prometheus-dev.example.com" | ||
timeout = "30s" | ||
include = [ | ||
"rules/dev/.*", | ||
"rules/common/.*", | ||
] | ||
} | ||
``` | ||
|
||
## How to disable it | ||
|
||
You can disable this check globally by adding this config block: | ||
|
||
```js | ||
checks { | ||
disabled = ["labels/conflict"] | ||
} | ||
``` | ||
|
||
You can also disable it for all rules inside given file by adding | ||
a comment anywhere in that file. Example: | ||
|
||
`# pint file/disable labels/conflict` | ||
|
||
Or you can disable it per rule by adding a comment to it. Example: | ||
|
||
`# pint disable labels/conflict` | ||
|
||
If you want to disable only individual instances of this check | ||
you can add a more specific comment. | ||
|
||
`# pint disable labels/conflict($prometheus)` | ||
|
||
Where `$prometheus` is the name of Prometheus server to disable. | ||
|
||
Example: | ||
|
||
`# pint disable labels/conflict(prod)` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package checks | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/cloudflare/pint/internal/discovery" | ||
"github.com/cloudflare/pint/internal/parser" | ||
"github.com/cloudflare/pint/internal/promapi" | ||
) | ||
|
||
const ( | ||
LabelsConflictCheckName = "labels/conflict" | ||
) | ||
|
||
func NewLabelsConflictCheck(prom *promapi.FailoverGroup) LabelsConflictCheck { | ||
return LabelsConflictCheck{prom: prom} | ||
} | ||
|
||
type LabelsConflictCheck struct { | ||
prom *promapi.FailoverGroup | ||
} | ||
|
||
func (c LabelsConflictCheck) Meta() CheckMeta { | ||
return CheckMeta{IsOnline: true} | ||
} | ||
|
||
func (c LabelsConflictCheck) String() string { | ||
return fmt.Sprintf("%s(%s)", LabelsConflictCheckName, c.prom.Name()) | ||
} | ||
|
||
func (c LabelsConflictCheck) Reporter() string { | ||
return LabelsConflictCheckName | ||
} | ||
|
||
func (c LabelsConflictCheck) Check(ctx context.Context, path string, rule parser.Rule, entries []discovery.Entry) (problems []Problem) { | ||
if rule.RecordingRule == nil || rule.RecordingRule.Expr.SyntaxError != nil { | ||
return nil | ||
} | ||
|
||
if rule.RecordingRule.Labels == nil { | ||
return nil | ||
} | ||
|
||
cfg, err := c.prom.Config(ctx) | ||
if err != nil { | ||
text, severity := textAndSeverityFromError(err, c.Reporter(), c.prom.Name(), Warning) | ||
problems = append(problems, Problem{ | ||
Fragment: rule.RecordingRule.Labels.Key.Value, | ||
Lines: rule.RecordingRule.Labels.Lines(), | ||
Reporter: c.Reporter(), | ||
Text: text, | ||
Severity: severity, | ||
}) | ||
return | ||
} | ||
|
||
for _, label := range rule.RecordingRule.Labels.Items { | ||
for k, v := range cfg.Config.Global.ExternalLabels { | ||
if label.Key.Value == k { | ||
problems = append(problems, Problem{ | ||
Fragment: fmt.Sprintf("%s: %s", label.Key.Value, label.Value.Value), | ||
Lines: label.Lines(), | ||
Reporter: c.Reporter(), | ||
Text: fmt.Sprintf("%s external_labels already has %s=%q label set, please choose a different name for this label to avoid any conflicts", promText(c.prom.Name(), cfg.URI), k, v), | ||
Severity: Warning, | ||
}) | ||
} | ||
} | ||
} | ||
|
||
return problems | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package checks_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
"time" | ||
|
||
"github.com/cloudflare/pint/internal/checks" | ||
"github.com/cloudflare/pint/internal/promapi" | ||
) | ||
|
||
func textExternalLabels(name, uri, k, v string) string { | ||
return fmt.Sprintf("prometheus %q at %s external_labels already has %s=%q label set, please choose a different name for this label to avoid any conflicts", name, uri, k, v) | ||
} | ||
|
||
func newLabelsConflict(prom *promapi.FailoverGroup) checks.RuleChecker { | ||
return checks.NewLabelsConflictCheck(prom) | ||
} | ||
|
||
func TestLabelsConflictCheck(t *testing.T) { | ||
testCases := []checkTest{ | ||
{ | ||
description: "ignores rules with syntax errors", | ||
content: "- record: foo\n expr: sum(foo) without(\n", | ||
checker: newLabelsConflict, | ||
prometheus: newSimpleProm, | ||
problems: noProblems, | ||
}, | ||
{ | ||
description: "ignores alerting rules", | ||
content: "- alert: foo\n expr: up == 0\n", | ||
checker: newLabelsConflict, | ||
prometheus: newSimpleProm, | ||
problems: noProblems, | ||
}, | ||
{ | ||
description: "no labels", | ||
content: "- record: foo\n expr: up == 0\n", | ||
checker: newLabelsConflict, | ||
prometheus: newSimpleProm, | ||
problems: noProblems, | ||
}, | ||
{ | ||
description: "connection refused", | ||
content: "- record: foo\n expr: up == 0\n labels:\n foo: bar\n", | ||
checker: newLabelsConflict, | ||
prometheus: func(_ string) *promapi.FailoverGroup { | ||
return simpleProm("prom", "http://127.0.0.1:1111", time.Second, false) | ||
}, | ||
problems: func(uri string) []checks.Problem { | ||
return []checks.Problem{ | ||
{ | ||
Fragment: "labels", | ||
Lines: []int{3, 4}, | ||
Reporter: checks.LabelsConflictCheckName, | ||
Text: checkErrorUnableToRun(checks.LabelsConflictCheckName, "prom", "http://127.0.0.1:1111", "connection refused"), | ||
Severity: checks.Warning, | ||
}, | ||
} | ||
}, | ||
}, | ||
{ | ||
description: "conflict", | ||
content: "- record: foo\n expr: up == 0\n labels:\n foo: bar\n", | ||
checker: newLabelsConflict, | ||
prometheus: newSimpleProm, | ||
problems: func(uri string) []checks.Problem { | ||
return []checks.Problem{ | ||
{ | ||
Fragment: "foo: bar", | ||
Lines: []int{4}, | ||
Reporter: checks.LabelsConflictCheckName, | ||
Text: textExternalLabels("prom", uri, "foo", "bob"), | ||
Severity: checks.Warning, | ||
}, | ||
} | ||
}, | ||
mocks: []*prometheusMock{ | ||
{ | ||
conds: []requestCondition{requireConfigPath}, | ||
resp: configResponse{yaml: "global:\n external_labels:\n foo: bob\n"}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
description: "no conflict", | ||
content: "- record: foo\n expr: up == 0\n labels:\n foo: bar\n", | ||
checker: newLabelsConflict, | ||
prometheus: newSimpleProm, | ||
problems: noProblems, | ||
mocks: []*prometheusMock{ | ||
{ | ||
conds: []requestCondition{requireConfigPath}, | ||
resp: configResponse{yaml: "global:\n external_labels:\n bob: bob\n"}, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
runTests(t, testCases) | ||
} |
Oops, something went wrong.