Alerting: Improve validation of query and expressions on rule submit (#53258)
* Improve error messages of server-side expression * move validation of alert queries and a condition to eval package
This commit is contained in:
+20
-19
@@ -2,6 +2,7 @@ package expr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -43,16 +44,16 @@ func NewMathCommand(refID, expr string) (*MathCommand, error) {
|
||||
func UnmarshalMathCommand(rn *rawNode) (*MathCommand, error) {
|
||||
rawExpr, ok := rn.Query["expression"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("math command for refId %v is missing an expression", rn.RefID)
|
||||
return nil, errors.New("command is missing an expression")
|
||||
}
|
||||
exprString, ok := rawExpr.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected math command for refId %v expression to be a string, got %T", rn.RefID, rawExpr)
|
||||
return nil, fmt.Errorf("math expression is expected to be a string, got %T", rawExpr)
|
||||
}
|
||||
|
||||
gm, err := NewMathCommand(rn.RefID, exprString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid math command type in '%v': %v", rn.RefID, err)
|
||||
return nil, fmt.Errorf("invalid math command type: %w", err)
|
||||
}
|
||||
return gm, nil
|
||||
}
|
||||
@@ -96,21 +97,21 @@ func NewReduceCommand(refID, reducer, varToReduce string, mapper mathexp.ReduceM
|
||||
func UnmarshalReduceCommand(rn *rawNode) (*ReduceCommand, error) {
|
||||
rawVar, ok := rn.Query["expression"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no variable specified to reduce for refId %v", rn.RefID)
|
||||
return nil, errors.New("no expression ID is specified to reduce. Must be a reference to an existing query or expression")
|
||||
}
|
||||
varToReduce, ok := rawVar.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected reduce variable to be a string, got %T for refId %v", rawVar, rn.RefID)
|
||||
return nil, fmt.Errorf("expression ID is expected to be a string, got %T", rawVar)
|
||||
}
|
||||
varToReduce = strings.TrimPrefix(varToReduce, "$")
|
||||
|
||||
rawReducer, ok := rn.Query["reducer"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no reducer specified for refId %v", rn.RefID)
|
||||
return nil, errors.New("no reducer specified")
|
||||
}
|
||||
redFunc, ok := rawReducer.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected reducer to be a string, got %T for refId %v", rawReducer, rn.RefID)
|
||||
return nil, fmt.Errorf("expected reducer to be a string, got %T", rawReducer)
|
||||
}
|
||||
|
||||
var mapper mathexp.ReduceMapper = nil
|
||||
@@ -126,20 +127,20 @@ func UnmarshalReduceCommand(rn *rawNode) (*ReduceCommand, error) {
|
||||
case "replaceNN":
|
||||
valueStr, ok := s["replaceWithValue"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected settings.replaceWithValue to be specified when mode is 'replaceNN' for refId %v", rn.RefID)
|
||||
return nil, errors.New("setting replaceWithValue must be specified when mode is 'replaceNN'")
|
||||
}
|
||||
switch value := valueStr.(type) {
|
||||
case float64:
|
||||
mapper = mathexp.ReplaceNonNumberWithValue{Value: value}
|
||||
default:
|
||||
return nil, fmt.Errorf("expected settings.replaceWithValue to be a number, got %T for refId %v", value, rn.RefID)
|
||||
return nil, fmt.Errorf("setting replaceWithValue must be a number, got %T", value)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("reducer mode %s is not supported for refId %v. Supported only: [dropNN,replaceNN]", mode, rn.RefID)
|
||||
return nil, fmt.Errorf("reducer mode '%s' is not supported. Supported only: [dropNN,replaceNN]", mode)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("expected settings to be an object, got %T for refId %v", s, rn.RefID)
|
||||
return nil, fmt.Errorf("field settings must be an object, got %T for refId %v", s, rn.RefID)
|
||||
}
|
||||
}
|
||||
return NewReduceCommand(rn.RefID, redFunc, varToReduce, mapper)
|
||||
@@ -211,40 +212,40 @@ func NewResampleCommand(refID, rawWindow, varToResample string, downsampler stri
|
||||
func UnmarshalResampleCommand(rn *rawNode) (*ResampleCommand, error) {
|
||||
rawVar, ok := rn.Query["expression"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no variable to resample for refId %v", rn.RefID)
|
||||
return nil, errors.New("no expression ID to resample. must be a reference to an existing query or expression")
|
||||
}
|
||||
varToReduce, ok := rawVar.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected resample input variable to be type string, but got type %T for refId %v", rawVar, rn.RefID)
|
||||
return nil, fmt.Errorf("expected resample input variable to be type string, but got type %T", rawVar)
|
||||
}
|
||||
varToReduce = strings.TrimPrefix(varToReduce, "$")
|
||||
varToResample := varToReduce
|
||||
|
||||
rawWindow, ok := rn.Query["window"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no time duration specified for the window in resample command for refId %v", rn.RefID)
|
||||
return nil, errors.New("no time duration specified for the window in resample command")
|
||||
}
|
||||
window, ok := rawWindow.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected resample window to be a string, got %T for refId %v", rawWindow, rn.RefID)
|
||||
return nil, fmt.Errorf("resample window is expected to be a string, got %T", rawWindow)
|
||||
}
|
||||
|
||||
rawDownsampler, ok := rn.Query["downsampler"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no downsampler function specified in resample command for refId %v", rn.RefID)
|
||||
return nil, errors.New("no downsampler function specified in resample command")
|
||||
}
|
||||
downsampler, ok := rawDownsampler.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected resample downsampler to be a string, got type %T for refId %v", downsampler, rn.RefID)
|
||||
return nil, fmt.Errorf("expected resample downsampler to be a string, got type %T", downsampler)
|
||||
}
|
||||
|
||||
rawUpsampler, ok := rn.Query["upsampler"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no downsampler specified in resample command for refId %v", rn.RefID)
|
||||
return nil, errors.New("no upsampler specified in resample command")
|
||||
}
|
||||
upsampler, ok := rawUpsampler.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected resample downsampler to be a string, got type %T for refId %v", upsampler, rn.RefID)
|
||||
return nil, fmt.Errorf("expected resample downsampler to be a string, got type %T", upsampler)
|
||||
}
|
||||
|
||||
return NewResampleCommand(rn.RefID, window, varToResample, downsampler, upsampler, rn.TimeRange)
|
||||
|
||||
Reference in New Issue
Block a user