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: Integrate validation into the executable #706

Merged
merged 4 commits into from
Jun 9, 2023
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
6 changes: 5 additions & 1 deletion cmd/refinery/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,13 @@ func main() {
}
})
if err != nil {
fmt.Printf("unable to load config: %+v\n", err)
fmt.Printf("%+v\n", err)
os.Exit(1)
}
if opts.Validate {
fmt.Println("Config and Rules validated successfully.")
os.Exit(0)
}

// get desired implementation for each dependency to inject
lgr := logger.GetLoggerImplementation(c)
Expand Down
4 changes: 2 additions & 2 deletions collect/stressRelief.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ func (s *StressRelief) UpdateFromConfig(cfg config.StressReliefConfig) error {
// before we start processing it in earnest. This is to help address the
// problem of trying to bring a new node into an already-overloaded
// cluster. If the time is 0 we won't do this at all.
if s.mode != Monitor && cfg.StartStressedDuration != 0 {
if s.mode != Monitor && cfg.MinimumStartupDuration != 0 {
s.stressed = true
s.stayOnUntil = time.Now().Add(time.Duration(cfg.StartStressedDuration))
s.stayOnUntil = time.Now().Add(time.Duration(cfg.MinimumStartupDuration))
}
s.mode = Monitor
case "always":
Expand Down
3 changes: 2 additions & 1 deletion config/cmdenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ type CmdEnv struct {
Debug bool `short:"d" long:"debug" description:"Runs debug service (on the first open port between localhost:6060 and :6069 by default)"`
Version bool `short:"v" long:"version" description:"Print version number and exit"`
InterfaceNames bool `long:"interface-names" description:"Print system's network interface names and exit."`
Validate bool `short:"V" long:"validate" description:"Validate the configuration files and exit"`
Validate bool `short:"V" long:"validate" description:"Validate the configuration files, writing results to stdout, and exit with 0 if valid, 1 if invalid."`
NoValidate bool `long:"no-validate" description:"Do not attempt to validate the configuration files. Makes --validate meaningless."`
}

func NewCmdEnvOptions(args []string) (*CmdEnv, error) {
Expand Down
55 changes: 37 additions & 18 deletions config/configLoadHelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ import (
"os"
"path/filepath"
"reflect"
"time"

"github.com/creasty/defaults"
"github.com/go-playground/validator/v10"
"github.com/pelletier/go-toml/v2"
"gopkg.in/yaml.v3"
)
Expand Down Expand Up @@ -108,18 +106,46 @@ func load(r io.Reader, format Format, into any) error {
}
}

// dminValidator is a validator for the validator library that checks if a
// value is at least a minimum value, specified as a Duration string.
func dminValidator(fl validator.FieldLevel) bool {
min, err := time.ParseDuration(fl.Param())
func validateConfig(location string) ([]string, error) {
r, format, err := getReaderFor(location)
if err != nil {
return false
return nil, err
}
defer r.Close()

var userData map[string]any
if err := load(r, format, &userData); err != nil {
return nil, fmt.Errorf("readConfigInto unable to load config %s: %w", location, err)
}
field, ok := fl.Field().Interface().(Duration)
if !ok {
return false

metadata, err := LoadConfigMetadata()
if err != nil {
return nil, err
}
return field >= Duration(min)

failures := metadata.Validate(userData)
return failures, nil
}

func validateRules(location string) ([]string, error) {
r, format, err := getReaderFor(location)
if err != nil {
return nil, err
}
defer r.Close()

var userData map[string]any
if err := load(r, format, &userData); err != nil {
return nil, fmt.Errorf("readConfigInto unable to load config %s: %w", location, err)
}

metadata, err := LoadRulesMetadata()
if err != nil {
return nil, err
}

failures := metadata.ValidateRules(userData)
return failures, nil
}

// readConfigInto reads the config from the given location and applies it to the given struct.
Expand Down Expand Up @@ -155,12 +181,5 @@ func readConfigInto(dest any, location string, opts *CmdEnv) (string, error) {
return hash, fmt.Errorf("readConfigInto unable to apply command line options: %w", err)
}

// validate the config
v := validator.New()
v.RegisterValidation("dmin", dminValidator)
if err := v.Struct(dest); err != nil {
return hash, fmt.Errorf("readConfigInto config validation failed: %w", err)
}

return hash, nil
}
Loading