Promruval

repository·master·Indexed 41 days ago

https://github.com/fusakla/promruval

A validation tool for Prometheus rules that ensures metadata and PromQL expressions adhere to cluster constraints. It can be integrated into CI pipelines to prevent misconfigured rules from being deployed, supporting YAML and Jsonnet formats as well as Loki, Mimir, and Thanos rule formats.

Tokens
6.7K
Snippets
17
Records
32
Agent score
50%

What's inside Promruval

  1. How to use the 'test-onlyif' conditional validation

    master

    The test-onlyif rule allows you to apply specific validations only when certain conditions are met. This is useful for enforcing stricter rules on critical alerts or specific groups.

    Example Logic: In the provided example, the escalate label is only required if:

    1. The rule label severity matches the regexp ^critical$.
    2. The group contains at most 1 rule.
  2. Compose multiple configuration files

    master

    You can pass the --config-file flag multiple times to compose configurations. Promruval will append validation rules from additional configs and override existing configurations. The last configuration provided takes precedence (the "late wins" pattern). This is useful for applying generic validations globally while having specific overrides for different environments (e.g., Prometheus vs Thanos).

    # Example of composing a generic config with a specific Prometheus config
    promruval validate --config-file ./rules/validation.yaml --config-file ./rules/prometheus/validation.yaml ./rules/prometheus/*.yaml
  3. Understand validation scopes in promruval

    master

    Promruval organizes its validations into different scopes. Depending on the type of rule you are validating (e.g., a Rule Group, an Alert, or a Recording Rule), only specific validators are available.

    • Groups: Validations that apply specifically to the Group scope (e.g., maxRulesPerGroup, hasAllowedEvaluationInterval).
    • Universal rule validators: Validations that can be applied to any rule, including Labels and PromQL expression validators.
    • Alert validators: Validations specific to Alert rules, covering Labels, Annotations, and other alert-specific properties.
    • Recording rules validators: Validations specific to Recording rules.

    For a sane starting point, you can refer to default_validation.yaml to see recommended default validations.

    Note on Regular Expressions: Unless explicitly stated otherwise, all regular expressions used in configuration are fully anchored (^...$) and default to matching everything (.*).

  4. Disable validation rules

    master

    There are four ways to disable specific validation rules:

    1. Command Line Flag: Use --disable-rule=<RULE_NAME> to temporarily disable a rule for all files in the current execution.
    2. YAML Comments: Add # ignore_validations: rule1, rule2 at the file, group, or rule level. The prefix ignore_validations can be customized via customDisableComment in the config.
    3. PromQL Expression Comments: Add # ignore_validations: rule1 anywhere within a PromQL expression.
    4. Alert Annotations: For alerts only, add the annotation disabled_validation_rules: rule1, rule2. The annotation name can be customized via customExcludeAnnotation in the config.
    # Using YAML comments to disable a rule for a specific group
    groups:
      - name: group1
        # ignore_validations: expressionDoesNotUseIrate
        rules:
          - record: recorded_metrics
            expr: 1
  5. Install Promruval

    master

    You can install Promruval using prebuilt binaries, Docker images, or by building from source.

    Using Go:

    go install github.com/fusakla/promruval/v3@latest

    Using Make:

    make build

    Using Docker: Pull the image from Docker Hub: fusakla/promruval.

  6. Configure Promruval validation rules

    master

    Promruval uses a YAML or Jsonnet configuration file to define how rules are validated.

    Configuration Structure:

    • customExcludeAnnotation: (Optional) Overrides the annotation used for disabling rules.
    • prometheus: Configuration for connecting to a Prometheus instance:
      • url: The URL of the running Prometheus instance.
      • insecureSkipTlsVerify: (Optional) Skip TLS verification.
      • bearerTokenFile: (Optional) Path to a file containing a bearer token. Alternatively, use the PROMETHEUS_BEARER_TOKEN environment variable.
      • timeout: (Optional) Request timeout.
      • cacheFile: (Optional) File to save Prometheus call cache.
      • maxCacheAge: (Optional) Maximum age of the cache.
      • queryOffset: (Optional) Offset for query evaluation time.
      • queryLookback: (Optional) How far back to look in queries.
      • httpHeaders: (Optional) Custom HTTP headers.
    • validationRules: A list of rule sets to apply:
      • name: Unique name for the validation rule set.
      • scope: The target of the validation (Group, Alert, Recording rule, or All rules).
      • validations: A list of specific validation types to perform.
        • type: The validation type (see docs/validations.md).
        • additionalDetails: (Optional) Custom text appended to error messages.
        • params: Parameters for the validation.
        • paramsFromFile: (Optional) Path to a file containing parameters (mutually exclusive with params).
      • onlyIf: (Optional) Conditions that must be met for the rule to apply.
    customExcludeAnnotation: my_disable_annotation
    
    prometheus:
      url: https://foo.bar/
      insecureSkipTlsVerify: false
      bearerTokenFile: bearer_token.txt
      timeout: 30s
      cacheFile: .promruval_cache.json
      maxCacheAge: 1h
      queryOffset: 1m
      queryLookback: 20m
      httpHeaders:
        foo: bar
    
    validationRules:
      - name: example-validation
        scope: All rules
        validations:
          - type: hasLabels
            additionalDetails: "We do this because ..."
            params:
              labels: [ "severity" ]
  7. Use Live Prometheus Validators

    master

    Some validators require a connection to a running Prometheus instance (configured in the prometheus section of your config) to perform real-time checks.

    • expressionCanBeEvaluated: Runs the expression against the live instance to check for errors. You can set timeSeriesLimit and evaluationDurationLimit to prevent long-running queries.
    • expressionUsesExistingLabels: Fails if the expression uses labels that do not exist in the live Prometheus instance.
    • expressionSelectorsMatchesAnything: Verifies that selectors (e.g., up{foo="bar"}) actually match data in the live instance. Use maximumMatchingSeries to limit the check scope.
    # Example: expressionCanBeEvaluated
    params:
      timeSeriesLimit: 100
      evaluationDurationLimit: 1m
    
    # Example: expressionSelectorsMatchesAnything
    params:
      maximumMatchingSeries: 1000
  8. Validate Alert Timing and Naming

    master

    Use these validators to enforce constraints on the for duration, keep_firing_for duration, and the alert name itself within the Alert scope.

    • forIsNotLongerThan: Fails if the for duration exceeds the specified limit (e.g., 1h).
    • keepFiringForIsNotLongerThan: Fails if the keep_firing_for duration exceeds the specified limit.
    • alertNameMatchesRegexp: Fails if the alert name does not match the provided regexp. Use negative: true to fail if the name does match.
    # Example: Limit 'for' duration to 1 hour
    params:
      limit: "1h"
  9. Restrict Metrics and Labels in PromQL Expressions

    master

    You can restrict which metrics or labels are used within PromQL expressions to prevent unauthorized data access or ensure compatibility with specific environments (like Thanos or KSM).

    • expressionDoesNotUseMetrics: Fails if the expression uses metrics matching any provided regexps. Regexps are fully anchored (^...$).
    • expressionDoesNotUseLabels: Fails if the expression uses specific labels in matchers, aggregations, or joins.
    • expressionUsesOnlyAllowedLabelsForMetricRegexp: Restricts labels used when a specific metric (matched by metricNameRegexp) is present.
    • expressionDoesNotUseLabelsForMetricRegexp: Fails if specific labels are used in combination with a metric matching metricNameRegexp.
    • expressionUsesOnlyAllowedLabelValuesForMetricRegexp: Ensures that if a metric (matching metricNameRegexp) is used, its label selectors match at least one value in the allowedLabelValues map.
    # Example: expressionDoesNotUseMetrics
    params:
      metricNameRegexps: [ "foo_bar.*", "foo_baz" ]
    
    # Example: expressionUsesOnlyAllowedLabelsForMetricRegexp
    params:
      metricNameRegexp: "kube_pod_labels"
      allowedLabels: [ "pod", "cluster", "app", "team" ]
    
    # Example: expressionUsesOnlyAllowedLabelValuesForMetricRegexp
    params:
      metricNameRegexp: "kube_pod_labels"
      allowedLabelValues:
        cluster: ['kube1', 'kube2', 'kube3']
        team: ['sre', 'backend']
  10. Use Universal Label Validators

    master

    Universal rule validators can be applied to All rules, Recording rule, and Alert scopes. These validators check for the presence, absence, or specific patterns of labels on Prometheus rules.

    Key validators include:

    • hasLabels: Ensures all specified labels are present. If searchInExpr is true, it also checks the rule's expr.
    • doesNotHaveLabels: Fails if any of the specified labels are present.
    • hasAnyOfLabels: Fails if none of the specified labels are present.
    • labelMatchesRegexp: Validates a label against a regex. Use negative: true to fail if it matches.
    • labelHasAllowedValue: Ensures a label value is within a whitelist. Supports commaSeparatedValue splitting and ignoreTemplatedValues to skip templated labels.
    • nonEmptyLabels: Fails if any label has an empty value.
    • exclusiveLabels: Prevents the coexistence of two specific labels (optionally checking their values).
    # Example: hasLabels
    params:
      labels: [ "foo", "bar" ]
      searchInExpr: true
    
    # Example: labelHasAllowedValue
    params:
      label: "foo"
      allowedValues: [ "foo", "bar" ]
      commaSeparatedValue: true
      ignoreTemplatedValues: false
    
    # Example: exclusiveLabels
    params:
      firstLabel: "severity"
      firstLabelValue: "critical"
      secondLabel: "page"
      secondLabelValue: "true"
  11. Use LogQL and Other Specialized Validators

    master

    Promruval supports validation for LogQL (Loki) and specialized checks for multi-tenant environments.

    LogQL

    • expressionIsValidLogQL: Validates LogQL syntax.
    • logQlExpressionUsesRangeAggregation: Ensures LogQL expressions used in rules utilize range aggregation functions.

    Multi-tenancy (Mimir/Mimir-like)

    • hasSourceTenantsForMetrics: Ensures that if a rule uses a metric matching a specific regexp, that metric's tenant is explicitly listed in the rule group's source_tenants configuration. This is useful for ensuring metrics from specific tenants (like KSM or Kafka) are correctly scoped.

    Typo Detection

    • doesNotContainTypos: Uses Levenshtein distance to identify typos in well-known labels, annotations, or values. You can configure maxLevenshteinDistance or maxDifferenceRatio to define the threshold for what constitutes a typo.
    # Example: hasSourceTenantsForMetrics
    params:
      defaultTenant: "my-tenant"
      sourceTenants:
        k8s:
          - regexp: "kube_.*|container_.*"
            description: "Metrics from KSM"
    
    # Example: doesNotContainTypos
    params:
      maxLevenshteinDistance: 2
      wellKnownAnnotations: ['playbook', 'dashboard', 'title', 'description']
      wellKnownRuleLabels: ['do_not_inhibit']
      wellKnownSeriesLabels: ['pod', 'locality', 'cluster']
  12. Validate Alert Labels and Annotations

    master

    Use these validators to ensure Alert rules follow specific formatting and metadata requirements.

    Label Validation

    • validateLabelTemplates: Ensures label values contain valid Go templates.

    Annotation Presence

    • hasAnnotations: Fails if the rule is missing any of the specified annotations.
    • doesNotHaveAnnotations: Fails if the rule contains any of the specified annotations.
    • hasAnyOfAnnotations: Fails if the rule does not contain at least one of the specified annotations.

    Annotation Content Validation

    • annotationMatchesRegexp: Fails if an annotation value does not match a regex. Use negative: true to fail if it does match.
    • annotationHasAllowedValue: Fails if an annotation value is not in the allowedValues list. If the annotation is missing entirely, validation succeeds.
    • annotationIsValidURL: Validates that an annotation is a valid URL.
      • If resolveUrl: true, it attempts an HTTP request to the URL and fails on non-200 status or connection failure.
      • If asTemplate: true, it parses the annotation as a Go text template before validation. If both are enabled, the template is executed first, then the resulting URL is resolved.
    • annotationIsValidPromQL: Validates that the content of a specific annotation is a valid PromQL expression.
    • validateAnnotationTemplates: Ensures annotation values contain valid Go templates.
    # Example: Ensure 'playbook' annotation is a valid, resolvable URL
    params:
      annotation: "playbook"
      resolveUrl: true
      asTemplate: false