prometheus/model/rulefmt/rulefmt.go

376 lines
10 KiB
Go
Raw Normal View History

// Copyright 2017 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2017-06-07 07:58:15 -07:00
package rulefmt
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"strings"
"time"
2017-06-07 07:58:15 -07:00
"github.com/prometheus/common/model"
"gopkg.in/yaml.v3"
"github.com/prometheus/prometheus/model/timestamp"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/promql/parser"
"github.com/prometheus/prometheus/template"
2017-06-07 07:58:15 -07:00
)
Spelling (#6517) * spelling: alertmanager Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: attributes Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: autocomplete Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: bootstrap Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: caught Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: chunkenc Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: compaction Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: corrupted Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: deletable Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: expected Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: fine-grained Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: initialized Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: iteration Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: javascript Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: multiple Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: number Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: overlapping Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: possible Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: postings Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: procedure Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: programmatic Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: queuing Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: querier Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: repairing Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: received Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: reproducible Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: retention Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: sample Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: segements Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: semantic Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: software [LICENSE] Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: staging Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: timestamp Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: unfortunately Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: uvarint Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: subsequently Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: ressamples Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-01-02 06:54:09 -08:00
// Error represents semantic errors on parsing rule groups.
2017-06-07 07:58:15 -07:00
type Error struct {
Group string
Rule int
RuleName string
Err WrappedError
}
// Error prints the error message in a formatted string.
func (err *Error) Error() string {
if err.Err.err == nil {
return ""
}
if err.Err.nodeAlt != nil {
return fmt.Sprintf("%d:%d: %d:%d: group %q, rule %d, %q: %v", err.Err.node.Line, err.Err.node.Column, err.Err.nodeAlt.Line, err.Err.nodeAlt.Column, err.Group, err.Rule, err.RuleName, err.Err.err)
}
if err.Err.node != nil {
return fmt.Sprintf("%d:%d: group %q, rule %d, %q: %v", err.Err.node.Line, err.Err.node.Column, err.Group, err.Rule, err.RuleName, err.Err.err)
}
return fmt.Sprintf("group %q, rule %d, %q: %v", err.Group, err.Rule, err.RuleName, err.Err.err)
}
// Unwrap unpacks wrapped error for use in errors.Is & errors.As.
func (err *Error) Unwrap() error {
return &err.Err
}
// WrappedError wraps error with the yaml node which can be used to represent
// the line and column numbers of the error.
type WrappedError struct {
err error
node *yaml.Node
nodeAlt *yaml.Node
2017-06-07 07:58:15 -07:00
}
// Error prints the error message in a formatted string.
func (we *WrappedError) Error() string {
if we.err == nil {
return ""
}
if we.nodeAlt != nil {
return fmt.Sprintf("%d:%d: %d:%d: %v", we.node.Line, we.node.Column, we.nodeAlt.Line, we.nodeAlt.Column, we.err)
}
if we.node != nil {
return fmt.Sprintf("%d:%d: %v", we.node.Line, we.node.Column, we.err)
}
return we.err.Error()
2017-06-07 07:58:15 -07:00
}
// Unwrap unpacks wrapped error for use in errors.Is & errors.As.
func (we *WrappedError) Unwrap() error {
return we.err
}
2017-06-07 07:58:15 -07:00
// RuleGroups is a set of rule groups that are typically exposed in a file.
type RuleGroups struct {
Groups []RuleGroup `yaml:"groups"`
2017-06-07 07:58:15 -07:00
}
type ruleGroups struct {
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
Groups []ruleGroupNode `yaml:"groups"`
}
2017-06-07 07:58:15 -07:00
// Validate validates all rules in the rule groups.
func (g *RuleGroups) Validate(node ruleGroups) (errs []error) {
set := map[string]struct{}{}
for j, g := range g.Groups {
if g.Name == "" {
errs = append(errs, fmt.Errorf("%d:%d: Groupname must not be empty", node.Groups[j].Line, node.Groups[j].Column))
}
if _, ok := set[g.Name]; ok {
errs = append(
errs,
fmt.Errorf("%d:%d: groupname: \"%s\" is repeated in the same file", node.Groups[j].Line, node.Groups[j].Column, g.Name),
)
}
for k, v := range g.Labels {
if !model.LabelName(k).IsValid() || k == model.MetricNameLabel {
errs = append(
errs, fmt.Errorf("invalid label name: %s", k),
)
}
if !model.LabelValue(v).IsValid() {
errs = append(
errs, fmt.Errorf("invalid label value: %s", v),
)
}
}
set[g.Name] = struct{}{}
2017-06-07 07:58:15 -07:00
for i, r := range g.Rules {
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
for _, node := range r.Validate(node.Groups[j].Rules[i]) {
var ruleName string
if r.Alert != "" {
ruleName = r.Alert
} else {
ruleName = r.Record
}
2017-06-07 07:58:15 -07:00
errs = append(errs, &Error{
Group: g.Name,
Rule: i + 1,
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
RuleName: ruleName,
Err: node,
2017-06-07 07:58:15 -07:00
})
}
}
}
2017-06-07 07:58:15 -07:00
return errs
}
// RuleGroup is a list of sequentially evaluated recording and alerting rules.
type RuleGroup struct {
Name string `yaml:"name"`
Interval model.Duration `yaml:"interval,omitempty"`
QueryOffset *model.Duration `yaml:"query_offset,omitempty"`
Limit int `yaml:"limit,omitempty"`
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
Rules []Rule `yaml:"rules"`
Labels map[string]string `yaml:"labels,omitempty"`
}
// ruleGroupNode adds yaml.v3 layer to support line and columns outputs for invalid rule groups.
type ruleGroupNode struct {
yaml.Node
Name string `yaml:"name"`
Interval model.Duration `yaml:"interval,omitempty"`
QueryOffset *model.Duration `yaml:"query_offset,omitempty"`
Limit int `yaml:"limit,omitempty"`
Rules []ruleNode `yaml:"rules"`
Labels map[string]string `yaml:"labels,omitempty"`
2017-06-07 07:58:15 -07:00
}
// Rule describes an alerting or recording rule.
type Rule struct {
Record string `yaml:"record,omitempty"`
Alert string `yaml:"alert,omitempty"`
Expr string `yaml:"expr"`
For model.Duration `yaml:"for,omitempty"`
KeepFiringFor model.Duration `yaml:"keep_firing_for,omitempty"`
Labels map[string]string `yaml:"labels,omitempty"`
Annotations map[string]string `yaml:"annotations,omitempty"`
2017-06-07 07:58:15 -07:00
}
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
// ruleNode adds yaml.v3 layer to support line and column outputs for invalid rules.
type ruleNode struct {
Record yaml.Node `yaml:"record,omitempty"`
Alert yaml.Node `yaml:"alert,omitempty"`
Expr yaml.Node `yaml:"expr"`
For model.Duration `yaml:"for,omitempty"`
KeepFiringFor model.Duration `yaml:"keep_firing_for,omitempty"`
Labels map[string]string `yaml:"labels,omitempty"`
Annotations map[string]string `yaml:"annotations,omitempty"`
}
2017-06-07 07:58:15 -07:00
// Validate the rule and return a list of encountered errors.
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
func (r *Rule) Validate(node ruleNode) (nodes []WrappedError) {
if r.Record != "" && r.Alert != "" {
nodes = append(nodes, WrappedError{
err: errors.New("only one of 'record' and 'alert' must be set"),
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
node: &node.Record,
nodeAlt: &node.Alert,
})
2017-06-07 07:58:15 -07:00
}
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
if r.Record == "" && r.Alert == "" {
nodes = append(nodes, WrappedError{
err: errors.New("one of 'record' or 'alert' must be set"),
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
node: &node.Record,
nodeAlt: &node.Alert,
})
2017-06-07 07:58:15 -07:00
}
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
if r.Expr == "" {
nodes = append(nodes, WrappedError{
err: errors.New("field 'expr' must be set in rule"),
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
node: &node.Expr,
})
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
} else if _, err := parser.ParseExpr(r.Expr); err != nil {
nodes = append(nodes, WrappedError{
err: fmt.Errorf("could not parse expression: %w", err),
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
node: &node.Expr,
})
2017-06-07 07:58:15 -07:00
}
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
if r.Record != "" {
2017-06-07 07:58:15 -07:00
if len(r.Annotations) > 0 {
nodes = append(nodes, WrappedError{
err: errors.New("invalid field 'annotations' in recording rule"),
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
node: &node.Record,
})
2017-06-07 07:58:15 -07:00
}
if r.For != 0 {
nodes = append(nodes, WrappedError{
err: errors.New("invalid field 'for' in recording rule"),
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
node: &node.Record,
})
2017-06-07 07:58:15 -07:00
}
if r.KeepFiringFor != 0 {
nodes = append(nodes, WrappedError{
err: errors.New("invalid field 'keep_firing_for' in recording rule"),
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
node: &node.Record,
})
}
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
if !model.IsValidMetricName(model.LabelValue(r.Record)) {
nodes = append(nodes, WrappedError{
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
err: fmt.Errorf("invalid recording rule name: %s", r.Record),
node: &node.Record,
})
}
// While record is a valid UTF-8 it's common mistake to put PromQL expression in the record name.
// Disallow "{}" chars.
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
if strings.Contains(r.Record, "{") || strings.Contains(r.Record, "}") {
nodes = append(nodes, WrappedError{
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
err: fmt.Errorf("braces present in the recording rule name; should it be in expr?: %s", r.Record),
node: &node.Record,
})
}
2017-06-07 07:58:15 -07:00
}
for k, v := range r.Labels {
if !model.LabelName(k).IsValid() || k == model.MetricNameLabel {
nodes = append(nodes, WrappedError{
err: fmt.Errorf("invalid label name: %s", k),
})
}
if !model.LabelValue(v).IsValid() {
nodes = append(nodes, WrappedError{
err: fmt.Errorf("invalid label value: %s", v),
})
}
}
for k := range r.Annotations {
if !model.LabelName(k).IsValid() {
nodes = append(nodes, WrappedError{
err: fmt.Errorf("invalid annotation name: %s", k),
})
}
}
for _, err := range testTemplateParsing(r) {
nodes = append(nodes, WrappedError{err: err})
}
return
}
// testTemplateParsing checks if the templates used in labels and annotations
// of the alerting rules are parsed correctly.
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
func testTemplateParsing(rl *Rule) (errs []error) {
if rl.Alert == "" {
// Not an alerting rule.
return errs
}
// Trying to parse templates.
tmplData := template.AlertTemplateData(map[string]string{}, map[string]string{}, "", promql.Sample{})
defs := []string{
"{{$labels := .Labels}}",
"{{$externalLabels := .ExternalLabels}}",
"{{$externalURL := .ExternalURL}}",
"{{$value := .Value}}",
}
parseTest := func(text string) error {
tmpl := template.NewTemplateExpander(
context.TODO(),
strings.Join(append(defs, text), ""),
rulefmt: support YAML aliases for Alert/Record/Expr (#14957) * rulefmt: add tests with YAML aliases for Alert/Record/Expr Altough somewhat discouraged in favour of using proper configuration management tools to generate full YAML, it can still be useful in some situations to use YAML anchors/aliases in rules. The current implementation is however confusing: aliases will work everywhere except on the alert/record name and expr This first commit adds (failing) tests to illustrate the issue, the next one fixes it. The YAML test file is intentionally filled with anchors and aliases. Although this is probably not representative of a real-world use case (which would have less of them), it errs on the safer side. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: support YAML aliases for Alert/Record/Expr This fixes the use of YAML aliases in alert/recording rule names and expressions. A side effect of this change is that the RuleNode YAML type is no longer propagated deeper in the codebase, instead the generic Rule type can now be used. Signed-off-by: François HORTA <fhorta@scaleway.com> * rulefmt: Add test for YAML merge combined with aliases Currently this does work, but adding a test for the related functionally here makes sense. Signed-off-by: David Leadbeater <dgl@dgl.cx> * rulefmt: Rebase to latest changes Signed-off-by: David Leadbeater <dgl@dgl.cx> --------- Signed-off-by: François HORTA <fhorta@scaleway.com> Signed-off-by: David Leadbeater <dgl@dgl.cx> Co-authored-by: David Leadbeater <dgl@dgl.cx>
2025-02-13 01:48:33 -08:00
"__alert_"+rl.Alert,
tmplData,
model.Time(timestamp.FromTime(time.Now())),
nil,
nil,
nil,
)
return tmpl.ParseTest()
}
// Parsing Labels.
for k, val := range rl.Labels {
err := parseTest(val)
if err != nil {
errs = append(errs, fmt.Errorf("label %q: %w", k, err))
}
}
// Parsing Annotations.
for k, val := range rl.Annotations {
err := parseTest(val)
if err != nil {
errs = append(errs, fmt.Errorf("annotation %q: %w", k, err))
}
}
2017-06-07 07:58:15 -07:00
return errs
}
// Parse parses and validates a set of rules.
func Parse(content []byte, ignoreUnknownFields bool) (*RuleGroups, []error) {
var (
groups RuleGroups
node ruleGroups
errs []error
)
decoder := yaml.NewDecoder(bytes.NewReader(content))
if !ignoreUnknownFields {
decoder.KnownFields(true)
}
err := decoder.Decode(&groups)
// Ignore io.EOF which happens with empty input.
if err != nil && !errors.Is(err, io.EOF) {
errs = append(errs, err)
}
err = yaml.Unmarshal(content, &node)
if err != nil {
errs = append(errs, err)
}
if len(errs) > 0 {
return nil, errs
}
return &groups, groups.Validate(node)
}
// ParseFile reads and parses rules from a file.
func ParseFile(file string, ignoreUnknownFields bool) (*RuleGroups, []error) {
b, err := os.ReadFile(file)
2017-06-07 07:58:15 -07:00
if err != nil {
return nil, []error{fmt.Errorf("%s: %w", file, err)}
}
rgs, errs := Parse(b, ignoreUnknownFields)
for i := range errs {
errs[i] = fmt.Errorf("%s: %w", file, errs[i])
2017-06-07 07:58:15 -07:00
}
return rgs, errs
2017-06-07 07:58:15 -07:00
}