Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for jsonnet config file format #97

Merged
merged 2 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
- name: Golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: "v1.62.2"
args: --timeout 5m0s

- name: Build
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [3.6.0] - 2024-11-29
- Added: Configuration file can now be in Jsonnet format if the config file name ends with `.jsonnet` and it will get automatically evaluated.

## [3.5.0] - 2024-10-31
- Added: New validation `expressionDoesNotUseClassicHistogramBucketOperations` to avoid queries fragile because of the classic histogram bucket operations.
See the docs for more info [expressionDoesNotUseClassicHistogramBucketOperations](docs/validations.md#expressiondoesnotuseclassichistogrambucketoperations)
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ build:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o $(PROMRUVAL_BIN)

E2E_TESTS_VALIDATIONS_FILE := examples/validation.yaml
E2E_TESTS_ADDITIONAL_VALIDATIONS_FILE := examples/additional-validation.yaml
E2E_TESTS_ADDITIONAL_VALIDATIONS_FILE := examples/additional-validation.jsonnet
E2E_TESTS_RULES_FILES := examples/rules/*
E2E_TESTS_DOCS_FILE_MD := examples/human_readable.md
E2E_TESTS_DOCS_FILE_HTML := examples/human_readable.html
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ validation-docs [<flags>]
Promruval supports the default YAML format (`.yaml` or `.yml`) of rule files but also supports rules written in [Jsonnet](https://jsonnet.org/) (`.jsonnet`).
If will be rendered using the [go-jsonnet](https://github.com/google/go-jsonnet) library and then validated as usual, so you don't have to evaluate those by yourself before running the validation.

Additionaly it supports also the configuration file in the Jsonnet format.

#### Configuration composition

The `--config-file` flag can be passed multiple times. Promruval will append the additional validation rules from the
Expand Down Expand Up @@ -134,7 +136,7 @@ promruval validate --config-file ./rules/validation.yaml --config-file ./rules/p

### Configuration

Promruval uses a yaml configuration file to define the validation rules.
Promruval uses a yaml or jsonnet (if config file ends with `.jsonnet`) configuration file to define the validation rules.

Basic structure is:

Expand Down
10 changes: 10 additions & 0 deletions examples/additional-validation.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
validationRules:
[
{
name: "another-checks",
scope: "All rules",
validations: [{ type: "nonEmptyLabels" }],
},
],
}
5 changes: 0 additions & 5 deletions examples/additional-validation.yaml

This file was deleted.

15 changes: 15 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ package config

import (
"fmt"
"io"
"os"
"path"
"strings"
"sync"
"time"

"gopkg.in/yaml.v3"

"github.com/creasty/defaults"
"github.com/google/go-jsonnet"
)

const (
Expand Down Expand Up @@ -48,6 +51,7 @@ type Loader struct {
}

func (l *Loader) Load() (*Config, error) {
var configFile io.ReadCloser
configFile, err := os.Open(l.ConfigPath)
if err != nil {
return nil, fmt.Errorf("open config file: %w", err)
Expand All @@ -59,6 +63,17 @@ func (l *Loader) Load() (*Config, error) {
configDirMtx.Unlock()
}()
validationConfig := Config{}

// If the config file is a jsonnet file, evaluate it first
if strings.HasSuffix(l.ConfigPath, ".jsonnet") {
jsonnetVM := jsonnet.MakeVM()
jsonStr, err := jsonnetVM.EvaluateFile(l.ConfigPath)
if err != nil {
return nil, fmt.Errorf("evaluating jsonnet in config file %s: %w", l.ConfigPath, err)
}
configFile = io.NopCloser(strings.NewReader(jsonStr))
}

decoder := yaml.NewDecoder(configFile)
decoder.KnownFields(true)
if err := decoder.Decode(&validationConfig); err != nil {
Expand Down
6 changes: 5 additions & 1 deletion pkg/validator/promql_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,11 @@ func (h validFunctionsOnCounters) Validate(_ unmarshaler.RuleGroup, rule rulefmt
}
for _, ch := range parser.Children(n) {
if m, ok := ch.(*parser.MatrixSelector); ok {
if !match.MatchString(m.VectorSelector.(*parser.VectorSelector).Name) {
vs, ok := m.VectorSelector.(*parser.VectorSelector)
if !ok {
continue
}
if !match.MatchString(vs.Name) {
errs = append(errs, fmt.Errorf("`%s` function should be used only on counters and those should end with the `_total` suffix, which is not this case `%s`", v.Func.Name, n.String()))
}
}
Expand Down