Skip to content

Commit

Permalink
feat: make the sourceTenant of the validator a list of regexps instea…
Browse files Browse the repository at this point in the history
…d of single regexp

Signed-off-by: Martin Chodur <[email protected]>
  • Loading branch information
FUSAKLA committed Mar 7, 2024
1 parent d968328 commit d274c08
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 33 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.11.0] - 2024-03-07
- :warning: CHANGED: Params of the `hasSourceTenantsForMetrics` validator (again FACEPALM). Now the tenant can have multiple regexp matchers.
See its [docs](docs/validations.md#hassourcetenantsformetrics).

## [2.10.0] - 2024-03-05
- Fixed error messages for the `hasSourceTenantsForMetrics` and `expressionDoesNotUseIrate` validators.

Expand Down
16 changes: 10 additions & 6 deletions docs/validations.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,16 @@ Fails, if the rule uses metric, that matches the specified regular expression fo
params:
sourceTenants:
<tenant_name>:
regexp: <metric_name_regexp> # The regexp will be fully anchored (surrounded by ^...$)
description: <description> # Optional, will be shown in the validator output human-readable description
# Example:
# k8s:
# regexp: "kube_.*|container_.*"
# description: "Kubernetes metrics from KSM and cAdvisor provided by the k8s infrastructure team"
- regexp: <metric_name_regexp> # The regexp will be fully anchored (surrounded by ^...$)
description: <description> # Optional, will be shown in the validator output human-readable description
# Example:
# k8s:
# - regexp: "kube_.*|container_.*"
# description: "Metrics from KSM"
# - regexp: "container_.*"
# description: "Metrics from cAdvisor "
# - regexp: "node_.*"
# description: "Node exporter metrics provided by the k8s infrastructure team"
```

## Alert validators
Expand Down
5 changes: 3 additions & 2 deletions examples/human_readable.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ <h2><a href="#check-prometheus-limitations">check-prometheus-limitations</a></h2
<h2><a href="#check-source-tenants">check-source-tenants</a></h2>
<ul>
<li>All rules rule group, the rule belongs to, has the required <code>source_tenants</code> configured, according to the mapping of metric names to tenants:
<br/> <code>mysql</code>: <code>^mysql_.*$</code> (MySQL metrics from the MySQL team)
<br/> <code>k8s</code>: <code>^container_.*|kube_.*$</code> (Kubernetes metrics from KSM and cAdvisor provided by the k8s infrastructure team)</li>
<br/> <code>k8s</code>: <code>^container_.*$</code> (Metrics from cAdvisor)
<br/> <code>k8s</code>: <code>^kube_.*$</code> (Metrics from KSM)
<br/> <code>mysql</code>: <code>^mysql_.*$</code> (MySQL metrics from the MySQL team)</li>
</ul>

<h2><a href="#check-metric-name">check-metric-name</a></h2>
Expand Down
3 changes: 2 additions & 1 deletion examples/human_readable.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ Validation rules:

check-source-tenants
- All rules rule group, the rule belongs to, has the required `source_tenants` configured, according to the mapping of metric names to tenants:
`k8s`: `^container_.*$` (Metrics from cAdvisor)
`k8s`: `^kube_.*$` (Metrics from KSM)
`mysql`: `^mysql_.*$` (MySQL metrics from the MySQL team)
`k8s`: `^container_.*|kube_.*$` (Kubernetes metrics from KSM and cAdvisor provided by the k8s infrastructure team)

check-metric-name
- Alert expression uses metric name in selectors
Expand Down
10 changes: 6 additions & 4 deletions examples/validation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,13 @@ validationRules:
params:
sourceTenants:
"k8s":
regexp: "container_.*|kube_.*"
description: "Kubernetes metrics from KSM and cAdvisor provided by the k8s infrastructure team"
- regexp: "container_.*"
description: "Metrics from cAdvisor"
- regexp: "kube_.*"
description: "Metrics from KSM"
"mysql":
regexp: "mysql_.*"
description: "MySQL metrics from the MySQL team"
- regexp: "mysql_.*"
description: "MySQL metrics from the MySQL team"

- name: check-metric-name
scope: Alert
Expand Down
38 changes: 23 additions & 15 deletions pkg/validator/others.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,28 @@ type SourceTenantMetrics struct {

func newHasSourceTenantsForMetrics(paramsConfig yaml.Node) (Validator, error) {
params := struct {
SourceTenants map[string]SourceTenantMetrics `yaml:"sourceTenants"`
SourceTenants map[string][]SourceTenantMetrics `yaml:"sourceTenants"`
}{}
if err := paramsConfig.Decode(&params); err != nil {
return nil, err
}
if params.SourceTenants == nil || len(params.SourceTenants) == 0 {
return nil, fmt.Errorf("sourceTenants metrics mapping needs to be set")
}
validator := hasSourceTenantsForMetrics{sourceTenants: map[string]tenantMetrics{}}
validator := hasSourceTenantsForMetrics{sourceTenants: map[string][]tenantMetrics{}}
for tenant, metrics := range params.SourceTenants {
compiledRegexp, err := regexp.Compile("^" + metrics.Regexp + "$")
if err != nil {
return nil, fmt.Errorf("invalid metric name regexp: %s", metrics.Regexp)
}
validator.sourceTenants[tenant] = tenantMetrics{
regexp: compiledRegexp,
description: metrics.Description,
m := make([]tenantMetrics, len(metrics))
for i, metric := range metrics {
compiledRegexp, err := regexp.Compile("^" + metric.Regexp + "$")
if err != nil {
return nil, fmt.Errorf("invalid metric name regexp: %s", metric.Regexp)
}
m[i] = tenantMetrics{
regexp: compiledRegexp,
description: metric.Description,
}
}
validator.sourceTenants[tenant] = m
}
return &validator, nil
}
Expand All @@ -47,13 +51,15 @@ type tenantMetrics struct {
}

type hasSourceTenantsForMetrics struct {
sourceTenants map[string]tenantMetrics
sourceTenants map[string][]tenantMetrics
}

func (h hasSourceTenantsForMetrics) String() string {
tenantStrings := []string{}
for tenant, metricsRegexp := range h.sourceTenants {
tenantStrings = append(tenantStrings, fmt.Sprintf("`%s`: `%s` (%s)", tenant, metricsRegexp.regexp.String(), metricsRegexp.description))
for tenant, metrics := range h.sourceTenants {
for _, m := range metrics {
tenantStrings = append(tenantStrings, fmt.Sprintf("`%s`: `%s` (%s)", tenant, m.regexp.String(), m.description))
}
}
return fmt.Sprintf("rule group, the rule belongs to, has the required `source_tenants` configured, according to the mapping of metric names to tenants: \n %s", strings.Join(tenantStrings, "\n "))
}
Expand All @@ -66,9 +72,11 @@ func (h hasSourceTenantsForMetrics) Validate(group unmarshaler.RuleGroup, rule r
return errs
}
for _, usedMetric := range usedMetrics {
for tenant, metricsRegexp := range h.sourceTenants {
if metricsRegexp.regexp.MatchString(usedMetric.Name) && !slices.Contains(group.SourceTenants, tenant) {
errs = append(errs, fmt.Errorf("rule uses metric `%s` of the tenant `%s` tenant, you should set the tenant in the groups source_tenants settings", tenant, usedMetric.Name))
for tenant, metrics := range h.sourceTenants {
for _, metric := range metrics {
if metric.regexp.MatchString(usedMetric.Name) && !slices.Contains(group.SourceTenants, tenant) {
errs = append(errs, fmt.Errorf("rule uses metric `%s` of the tenant `%s` tenant, you should set the tenant in the groups source_tenants settings", tenant, usedMetric.Name))
}
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions pkg/validator/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,11 @@ var testCases = []struct {
{name: "regexpIsFullyAnchored", validator: expressionDoesNotUseMetrics{metricNameRegexps: []*regexp.Regexp{regexp.MustCompile(`^foo_bar$`)}}, rule: rulefmt.Rule{Expr: `foo_baz_baz{foo="bar"} and foo_bar`}, expectedErrors: 1},

// hasSourceTenantsForMetrics
{name: "emptyMapping", validator: hasSourceTenantsForMetrics{sourceTenants: map[string]tenantMetrics{}}, rule: rulefmt.Rule{Expr: `up{foo="bar"}`}, expectedErrors: 0},
{name: "usesMetricWithSourceTenantAndGroupHasSourceTenant", validator: hasSourceTenantsForMetrics{sourceTenants: map[string]tenantMetrics{"tenant1": {regexp: regexp.MustCompile(`^teanant1_metric$`)}}}, group: unmarshaler.RuleGroup{SourceTenants: []string{"tenant1"}}, rule: rulefmt.Rule{Expr: `teanant1_metric{foo="bar"}`}, expectedErrors: 0},
{name: "usesMetricWithSourceTenantAndGroupDoesNotHaveSourceTenant", validator: hasSourceTenantsForMetrics{sourceTenants: map[string]tenantMetrics{"tenant1": {regexp: regexp.MustCompile(`^teanant1_metric$`)}}}, group: unmarshaler.RuleGroup{SourceTenants: []string{"tenant2"}}, rule: rulefmt.Rule{Expr: `teanant1_metric{foo="bar"}`}, expectedErrors: 1},
{name: "usesMetricWithSourceTenantAndGroupHasMultipleSourceTenants", validator: hasSourceTenantsForMetrics{sourceTenants: map[string]tenantMetrics{"tenant1": {regexp: regexp.MustCompile(`^teanant1_metric$`)}}}, group: unmarshaler.RuleGroup{SourceTenants: []string{"tenant2", "tenant1"}}, rule: rulefmt.Rule{Expr: `teanant1_metric{foo="bar"}`}, expectedErrors: 0},
{name: "usesMetricWithSourceTenantAndGroupHasMultipleSourceTenantsAndOneIsMissing", validator: hasSourceTenantsForMetrics{sourceTenants: map[string]tenantMetrics{"tenant1": {regexp: regexp.MustCompile(`^teanant1_metric$`)}}}, group: unmarshaler.RuleGroup{SourceTenants: []string{"tenant2", "tenant3"}}, rule: rulefmt.Rule{Expr: `teanant1_metric{foo="bar"}`}, expectedErrors: 1},
{name: "emptyMapping", validator: hasSourceTenantsForMetrics{sourceTenants: map[string][]tenantMetrics{}}, rule: rulefmt.Rule{Expr: `up{foo="bar"}`}, expectedErrors: 0},
{name: "usesMetricWithSourceTenantAndGroupHasSourceTenant", validator: hasSourceTenantsForMetrics{sourceTenants: map[string][]tenantMetrics{"tenant1": {{regexp: regexp.MustCompile(`^teanant1_metric$`)}}}}, group: unmarshaler.RuleGroup{SourceTenants: []string{"tenant1"}}, rule: rulefmt.Rule{Expr: `teanant1_metric{foo="bar"}`}, expectedErrors: 0},
{name: "usesMetricWithSourceTenantAndGroupDoesNotHaveSourceTenant", validator: hasSourceTenantsForMetrics{sourceTenants: map[string][]tenantMetrics{"tenant1": {{regexp: regexp.MustCompile(`^teanant1_metric$`)}}}}, group: unmarshaler.RuleGroup{SourceTenants: []string{"tenant2"}}, rule: rulefmt.Rule{Expr: `teanant1_metric{foo="bar"}`}, expectedErrors: 1},
{name: "usesMetricWithSourceTenantAndGroupHasMultipleSourceTenants", validator: hasSourceTenantsForMetrics{sourceTenants: map[string][]tenantMetrics{"tenant1": {{regexp: regexp.MustCompile(`^teanant1_metric$`)}}}}, group: unmarshaler.RuleGroup{SourceTenants: []string{"tenant2", "tenant1"}}, rule: rulefmt.Rule{Expr: `teanant1_metric{foo="bar"}`}, expectedErrors: 0},
{name: "usesMetricWithSourceTenantAndGroupHasMultipleSourceTenantsAndOneIsMissing", validator: hasSourceTenantsForMetrics{sourceTenants: map[string][]tenantMetrics{"tenant1": {{regexp: regexp.MustCompile(`^teanant1_metric$`)}}}}, group: unmarshaler.RuleGroup{SourceTenants: []string{"tenant2", "tenant3"}}, rule: rulefmt.Rule{Expr: `teanant1_metric{foo="bar"}`}, expectedErrors: 1},

// hasAllowedSourceTenants
{name: "emptyAllowedSourceTenantsAndGroupSourceTenants", validator: hasAllowedSourceTenants{allowedSourceTenants: []string{}}, group: unmarshaler.RuleGroup{SourceTenants: []string{}}, rule: rulefmt.Rule{Expr: `up{foo="bar"}`}, expectedErrors: 0},
Expand Down

0 comments on commit d274c08

Please sign in to comment.