From 6250ee4b5222d0e4dd362cb062f9a3102a4d972b Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 13:49:58 +0100 Subject: [PATCH 01/16] replaced viper with koanf, feature parity --- cmd/root.go | 35 +- core/config.go | 488 +++++------------------ core/config_test.go | 569 +++------------------------ core/engine.go | 7 +- crypto/api/v1/generated.go | 1 - crypto/crypto_test.go | 5 - crypto/engine/engine.go | 12 +- crypto/engine/engine_test.go | 10 +- docs/config-options-docs.go | 4 +- docs/pages/configuration/options.rst | 5 +- go.mod | 2 +- go.sum | 182 +++------ network/api/v1/generated.go | 1 - network/config.go | 16 +- network/dag/test.go | 2 - network/engine/engine.go | 33 +- network/engine/engine_test.go | 8 +- network/network_integration_test.go | 2 +- vdr/api/v1/generated.go | 1 - vdr/config.go | 8 +- vdr/engine/engine.go | 13 +- vdr/engine/engine_test.go | 28 +- 22 files changed, 301 insertions(+), 1131 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 1220c94002..60e4132725 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -52,11 +52,24 @@ func createRootCommand() *cobra.Command { } } +func createPrintConfigCommand(system *core.System) *cobra.Command { + return &cobra.Command{ + Use: "config", + Short: "Prints the current config", + Run: func(cmd *cobra.Command, args []string) { + cmd.Println(system.Config.PrintConfig()) + }, + } +} + func createServerCommand(system *core.System) *cobra.Command { return &cobra.Command{ Use: "server", Short: "Starts the Nuts server", Run: func(cmd *cobra.Command, args []string) { + logrus.Info("Starting server with config:") + logrus.Println(system.Config.PrintConfig()) + // check config on all engines if err := system.Configure(); err != nil { logrus.Fatal(err) @@ -67,7 +80,6 @@ func createServerCommand(system *core.System) *cobra.Command { logrus.Fatal(err) } - cfg := core.NutsConfig() // start interfaces echoServer := echoCreator() system.VisitEngines(func(engine *core.Engine) { @@ -81,7 +93,7 @@ func createServerCommand(system *core.System) *cobra.Command { logrus.Fatal(err) } }() - if err := echoServer.Start(cfg.ServerAddress()); err != nil { + if err := echoServer.Start(system.Config.Address); err != nil { logrus.Fatal(err) } }, @@ -93,7 +105,7 @@ func CreateCommand(system *core.System) *cobra.Command { command := createRootCommand() command.SetOut(stdOutWriter) addSubCommands(system, command) - addFlagSets(system, command, core.NutsConfig()) + addFlagSets(system, command) return command } @@ -117,17 +129,13 @@ func Execute() { command := CreateCommand(system) command.SetOut(stdOutWriter) - // Load global Nuts config - cfg := core.NutsConfig() - // Load all config and add generic options - if err := cfg.Load(command); err != nil { + if err := system.Config.Load(command); err != nil { panic(err) } // Load config into engines - injectConfig(system, cfg) - cfg.PrintConfig(system, logrus.StandardLogger()) + injectConfig(system) // blocking main call command.Execute() @@ -140,18 +148,19 @@ func addSubCommands(system *core.System, root *cobra.Command) { } }) root.AddCommand(createServerCommand(system)) + root.AddCommand(createPrintConfigCommand(system)) } -func injectConfig(system *core.System, cfg *core.NutsGlobalConfig) { +func injectConfig(system *core.System) { if err := system.VisitEnginesE(func(engine *core.Engine) error { - return cfg.InjectIntoEngine(engine) + return system.Config.InjectIntoEngine(engine) }); err != nil { logrus.Fatal(err) } } -func addFlagSets(system *core.System, cmd *cobra.Command, cfg *core.NutsGlobalConfig) { +func addFlagSets(system *core.System, cmd *cobra.Command) { system.VisitEngines(func(engine *core.Engine) { - cfg.RegisterFlags(cmd, engine) + system.Config.RegisterFlags(cmd, engine) }) } diff --git a/core/config.go b/core/config.go index fc83791533..942d4e9459 100644 --- a/core/config.go +++ b/core/config.go @@ -21,21 +21,23 @@ package core import ( "errors" - "fmt" - "math" "os" - "reflect" "strings" "sync" + "github.com/knadh/koanf" + "github.com/knadh/koanf/parsers/yaml" + "github.com/knadh/koanf/providers/env" + "github.com/knadh/koanf/providers/file" + "github.com/knadh/koanf/providers/posflag" + errors2 "github.com/pkg/errors" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/pflag" - "github.com/spf13/viper" ) -const defaultPrefix = "NUTS" -const defaultSeparator = "." +const defaultPrefix = "NUTS_" +const defaultDelimiter = "." const defaultConfigFile = "nuts.yaml" const configFileFlag = "configfile" const loggerLevelFlag = "verbosity" @@ -43,433 +45,133 @@ const addressFlag = "address" const defaultLogLevel = "info" const defaultAddress = "localhost:1323" const strictModeFlag = "strictmode" -const identityFlag = "identity" +const defaultStrictmode = "false" -var defaultIgnoredPrefixes = []string{"root"} - -// Make sure NutsGlobalConfig implements NutConfigValues interface -var _ NutsConfigValues = (*NutsGlobalConfig)(nil) - -// NutsGlobalConfig has the settings which influence all other settings. +// NutsGlobalConfig has global settings. type NutsGlobalConfig struct { - // The default config file the configuration looks for (Default nuts.yaml) - DefaultConfigFile string - - // Prefix sets the global config environment variable prefix (Default: NUTS) - Prefix string - - // Delimiter sets the nested config separator string (Default: '.') - Delimiter string - - // IgnoredPrefixes is a slice of prefixes which will not be used to prepend config variables, eg: --logging.verbosity will just be --verbosity - IgnoredPrefixes []string - - v *viper.Viper -} - -// NutsConfigValues exposes global configuration values -type NutsConfigValues interface { - ServerAddress() string - InStrictMode() bool + Address string `koanf:"address"` + Verbosity string `koanf:"verbosity"` + Strictmode bool `koanf:"strictmode"` + configMap *koanf.Koanf + once sync.Once } -// NewNutsGlobalConfig creates a NutsGlobalConfig with the following defaults -// * Prefix: NUTS -// * Delimiter: '.' -// * IgnoredPrefixes: ["root","logging"] -func NewNutsGlobalConfig() *NutsGlobalConfig { +func NewNutsConfig() *NutsGlobalConfig { return &NutsGlobalConfig{ - DefaultConfigFile: defaultConfigFile, - Prefix: defaultPrefix, - Delimiter: defaultSeparator, - IgnoredPrefixes: defaultIgnoredPrefixes, - v: viper.New(), + configMap: koanf.New(defaultDelimiter), + once: sync.Once{}, + Address: defaultAddress, + Verbosity: defaultLogLevel, + Strictmode: false, } } -var configOnce sync.Once -var configInstance *NutsGlobalConfig - -// NutsGlobalConfig returns a singleton global config -func NutsConfig() *NutsGlobalConfig { - configOnce.Do(func() { - configInstance = NewNutsGlobalConfig() - }) - return configInstance -} - -// ServerAddress is the address which is used to either listen on (in server mode) or connect to (in client mode). -func (ngc NutsGlobalConfig) ServerAddress() string { - return ngc.v.GetString(addressFlag) -} - -// InStrictMode helps to safeguard settings which are handy and default in development but not safe for production. -func (ngc NutsGlobalConfig) InStrictMode() bool { - return ngc.v.GetBool(strictModeFlag) -} - -// Load sets some initial config in order to be able for commands to load the right parameters and to add the configFile Flag. -// This is mainly spf13/viper related stuff -func (ngc *NutsGlobalConfig) Load(cmd *cobra.Command) error { - ngc.v.SetEnvPrefix(ngc.Prefix) - ngc.v.AutomaticEnv() - ngc.v.SetEnvKeyReplacer(strings.NewReplacer(ngc.Delimiter, "_")) - flagSet := pflag.NewFlagSet("config", pflag.ContinueOnError) - flagSet.String(configFileFlag, ngc.DefaultConfigFile, "Nuts config file") - flagSet.String(loggerLevelFlag, defaultLogLevel, "Log level (trace, debug, info, warn, error)") - flagSet.String(addressFlag, defaultAddress, "Address and port the server will be listening to") - flagSet.Bool(strictModeFlag, false, "When set, insecure settings are forbidden.") - flagSet.String(identityFlag, "", "Vendor identity for the node, mandatory when running in server mode. Must be in the format: urn:oid:"+NutsVendorOID+":") - cmd.PersistentFlags().AddFlagSet(flagSet) +// load follows the load order of configfile, env vars and then commandline param +// it only loads once +func (ngc *NutsGlobalConfig) Load(cmd *cobra.Command) (err error) { + ngc.once.Do(func() { + cmd.PersistentFlags().AddFlagSet(ngc.flagSet()) - // Bind config flag - // Bind log level flag - ngc.bindFlag(flagSet, configFileFlag) - ngc.bindFlag(flagSet, loggerLevelFlag) - ngc.bindFlag(flagSet, addressFlag) - ngc.bindFlag(flagSet, strictModeFlag) - ngc.bindFlag(flagSet, identityFlag) + ngc.configMap = koanf.New(defaultDelimiter) + var f string - // load flags into viper - pfs := cmd.PersistentFlags() - pfs.ParseErrorsWhitelist.UnknownFlags = true - if err := pfs.Parse(os.Args[1:]); err != nil { - if err != pflag.ErrHelp { - return err + f, err = ngc.getConfigfile(cmd) + if err != nil { + return } - } - // load configFile into viper - if err := ngc.loadConfigFile(); err != nil { - return err - } - - // initialize logger, verbosity flag needs to be available - level, err := log.ParseLevel(ngc.v.GetString(loggerLevelFlag)) - if err != nil { - return err - } - log.SetLevel(level) - - return nil -} - -func (ngc *NutsGlobalConfig) bindFlag(fs *pflag.FlagSet, name string) error { - s := fs.Lookup(name) - if err := ngc.v.BindPFlag(s.Name, s); err != nil { - return err - } - if err := ngc.v.BindEnv(s.Name); err != nil { - return err - } - return nil -} - -// PrintConfig outputs the current config to the logger on info level -func (ngc *NutsGlobalConfig) PrintConfig(system *System, logger log.FieldLogger) { - title := "Config" - var longestKey = 10 - var longestValue int - system.VisitEngines(func(engine *Engine) { - if engine.FlagSet != nil { - engine.FlagSet.VisitAll(func(flag *pflag.Flag) { - s := fmt.Sprintf("%v", ngc.v.Get(strings.ToLower(flag.Name))) - if len(s) > longestValue { - longestValue = len(s) - } - if len(flag.Name) > longestKey { - longestKey = len(flag.Name) - } - }) + // load file + p := file.Provider(f) + if err = ngc.configMap.Load(p, yaml.Parser()); err != nil { + if !errors.Is(err, os.ErrNotExist) { + return + } } - }) - - totalLength := 7 + longestKey + longestValue - stars := strings.Repeat("*", totalLength) - sideStarsLeft := int(math.Floor((float64(totalLength)-float64(len(title)))/2.0)) - 1 - sideStarsRight := int(math.Ceil((float64(totalLength)-float64(len(title)))/2.0)) - 1 - - logger.Infoln(stars) - logger.Infof("%s %s %s", strings.Repeat("*", sideStarsLeft), title, strings.Repeat("*", sideStarsRight)) - f := fmt.Sprintf("%%-%ds%%v", 7+longestKey) - - logger.Infof(f, addressFlag, ngc.ServerAddress()) - logger.Infof(f, configFileFlag, ngc.v.Get(configFileFlag)) - logger.Infof(f, loggerLevelFlag, ngc.v.Get(loggerLevelFlag)) - logger.Infof(f, strictModeFlag, ngc.InStrictMode()) - system.VisitEngines(func(engine *Engine) { - if engine.FlagSet != nil { - engine.FlagSet.VisitAll(func(flag *pflag.Flag) { - logger.Infof(f, flag.Name, ngc.v.Get(strings.ToLower(flag.Name))) - }) + // load env + e := env.Provider(defaultPrefix, defaultDelimiter, func(s string) string { + return strings.Replace(strings.ToLower( + strings.TrimPrefix(s, defaultPrefix)), "_", defaultDelimiter, -1) + }) + if err = ngc.configMap.Load(e, nil); err != nil { + return } - }) - logger.Infoln(stars) -} -// LoadConfigFile load the config from the given config file or from the default config file. If the file does not exist it'll continue with default values. -func (ngc *NutsGlobalConfig) loadConfigFile() error { - configFile := ngc.v.GetString(configFileFlag) - - // default path, relative paths and absolute paths should work - ngc.v.AddConfigPath(".") - ngc.v.SetConfigFile(configFile) - - // if file can not be found, print to stderr and continue - err := ngc.v.ReadInConfig() - if err != nil { - var pathError *os.PathError - // error on opening file - if errors.As(err, &pathError) && pathError.Op == "open" { - fmt.Fprintf(os.Stderr, "Config file %s not found, using defaults!\n", configFile) - return nil + // load cmd params + cmd.PersistentFlags().Parse(os.Args[1:]) + if err = ngc.configMap.Load(posflag.Provider(cmd.PersistentFlags(), defaultDelimiter, ngc.configMap), nil); err != nil { + return } - } - return err -} - -// InjectIntoEngine loop over all flags from an engine and injects any value into the given Config struct for the Engine. -// If the Engine does not have a config struct, it does nothing. -// Any config not registered as global flag will be ignored. -// It expects all config var names to be prepended or nested with the Engine ConfigKey, -// this will be ignored if the ConfigKey is "" or if the key is in the set of ignored prefixes. -func (ngc *NutsGlobalConfig) InjectIntoEngine(e *Engine) error { - var err error - - // ignore if no target for injection - if e.Config != nil { - // ignore if no registered flags - if e.FlagSet != nil { - fs := e.FlagSet - log.Tracef("Injecting values for engine %s\n", e.Name) - - fs.VisitAll(func(f *pflag.Flag) { - // config name as used by viper - configName := ngc.configName(e, f) - // field in struct - var field *reflect.Value - field, err = ngc.findField(e, ngc.fieldName(e, f.Name)) - - if err != nil { - err = fmt.Errorf("problem injecting [%v] for %s: %w", configName, e.Name, err) - return - } - - // test if is set, this can not be done with IsSet, because it doesn't take ENV variables into account. - var val interface{} - val = ngc.v.Get(configName) - if val == nil { - err = fmt.Errorf("nil value for %v, forgot to add flag binding", configName) - return - } - - isStringSlice := false - - // get real value with correct type - switch field.Kind() { - case reflect.Int: - val = ngc.v.GetInt(configName) - case reflect.Int32: - val = ngc.v.GetInt32(configName) - case reflect.Int64: - val = ngc.v.GetInt64(configName) - case reflect.String: - val = ngc.v.GetString(configName) - case reflect.Bool: - val = ngc.v.GetBool(configName) - case reflect.Slice: - val = ngc.v.Get(configName) - valI := val.([]interface{}) - if _, ok := valI[0].(string); ok { - isStringSlice = true - } - default: - val = ngc.v.Get(configName) - } - - if val == nil { - err = fmt.Errorf("nil value for %v, forgot to add flag binding", configName) - return - } - - // inject value - if isStringSlice { - valI := val.([]interface{}) - va := make([]string, len(valI)) - for i, v := range valI { - va[i] = v.(string) - } - field.Set(reflect.ValueOf(va)) - } else { - field.Set(reflect.ValueOf(val)) - } - log.Tracef("[%s] %s=%v\n", e.Name, f.Name, val) - }) + // load into struct + if err = ngc.configMap.Unmarshal("", ngc); err != nil { + return } - } - return err -} - -func (ngc *NutsGlobalConfig) injectIntoStruct(s interface{}) error { - var err error - - for _, configName := range ngc.v.AllKeys() { - // ignore global flags - if configName == configFileFlag || configName == loggerLevelFlag || configName == addressFlag || configName == strictModeFlag { - continue - } - - sv := reflect.ValueOf(s) - var field *reflect.Value - field, err = ngc.findFieldInStruct(&sv, configName) - - if err != nil { - return fmt.Errorf("problem injecting [%v]: %w", configName, err) + // initialize logger, verbosity flag needs to be available + if _, err = log.ParseLevel(ngc.Verbosity); err != nil { + return } - // inject value - field.Set(reflect.ValueOf(ngc.v.Get(configName))) - } - return err + }) + return } -// RegisterFlags adds the flagSet of an engine to the commandline, flag names are prefixed if needed -// The passed command must be the root command not the engine.Cmd (unless they are the same) -func (ngc *NutsGlobalConfig) RegisterFlags(cmd *cobra.Command, e *Engine) { - if e.FlagSet != nil { - fs := e.FlagSet - - fs.VisitAll(func(f *pflag.Flag) { - // prepend with engine.configKey - if e.ConfigKey != "" && !ngc.isIgnoredPrefix(e.ConfigKey) { - f.Name = fmt.Sprintf("%s%s%s", e.ConfigKey, ngc.Delimiter, f.Name) - } +// getConfigfile returns the configfile path in the following order: commandline param, env variable, default path +func (ngc *NutsGlobalConfig) getConfigfile(cmd *cobra.Command) (string, error) { + k := koanf.New(defaultDelimiter) - // add commandline flag - pf := cmd.PersistentFlags().Lookup(f.Name) - if pf == nil { - cmd.PersistentFlags().AddFlag(f) - pf = f - } - - // some magic for stuff to get combined - ngc.v.BindPFlag(f.Name, pf) - - // bind environment variable - ngc.v.BindEnv(f.Name) - }) - } -} - -func (ngc *NutsGlobalConfig) isIgnoredPrefix(prefix string) bool { - for _, ip := range ngc.IgnoredPrefixes { - if ip == prefix { - return true - } + // load cmd flags + if err := k.Load(posflag.Provider(cmd.Flags(), defaultDelimiter, k), nil); err != nil { + return "", errors2.Wrap(err, "error loading cmd flags") } - return false -} - -// Unmarshal loads config from Env, commandLine and configFile into given struct. -// This call is intended to be used outside of the engine structure of Nuts-go. -// It can be used by the individual repo's, for testing the repo as standalone command. -func (ngc *NutsGlobalConfig) LoadAndUnmarshal(cmd *cobra.Command, targetCfg interface{}) error { - if err := ngc.Load(cmd); err != nil { - return err + if f := k.String(configFileFlag); f != "" { + return f, nil } - return ngc.injectIntoStruct(targetCfg) -} - -// configName returns the fully qualified config name including prefixes and delimiter -func (ngc *NutsGlobalConfig) configName(e *Engine, f *pflag.Flag) string { - if e.ConfigKey == "" { - return f.Name - } - for _, i := range ngc.IgnoredPrefixes { - if i == e.ConfigKey { - return f.Name - } + // load env flags + e := env.Provider(defaultPrefix, defaultDelimiter, func(s string) string { + return strings.Replace(strings.ToLower( + strings.TrimPrefix(s, defaultPrefix)), "_", defaultDelimiter, -1) + }) + if err := k.Load(e, nil); err != nil { + return "", errors2.Wrap(err, "error loading env flags") } - - // check if flag name already starts with prefix - if strings.Index(f.Name, e.ConfigKey) == 0 { - return f.Name + if f := k.String(configFileFlag); f != "" { + return f, nil } - // add prefix - return fmt.Sprintf("%s%s%s", e.ConfigKey, ngc.Delimiter, f.Name) + return defaultConfigFile, nil } -func (ngc *NutsGlobalConfig) fieldName(e *Engine, s string) string { - if e.ConfigKey != "" && !ngc.isIgnoredPrefix(e.ConfigKey) { - if strings.Index(s, e.ConfigKey) == 0 { - return s[len(e.ConfigKey)+1:] - } - } - - return s +func (ngc *NutsGlobalConfig) flagSet() *pflag.FlagSet { + flagSet := pflag.NewFlagSet("config", pflag.ContinueOnError) + flagSet.String(configFileFlag, "", "Nuts config file") + flagSet.String(loggerLevelFlag, defaultLogLevel, "Log level (trace, debug, info, warn, error)") + flagSet.String(addressFlag, defaultAddress, "Address and port the server will be listening to") + flagSet.Bool(strictModeFlag, false, "When set, insecure settings are forbidden.") + return flagSet } -// findField returns the Value of the field to inject value into -// it also checks if the Field can be set -// it uses findFieldRecursive to find deeper nested struct fields -func (ngc *NutsGlobalConfig) findField(e *Engine, fieldName string) (*reflect.Value, error) { - cfgP := reflect.ValueOf(e.Config) - - return ngc.findFieldInStruct(&cfgP, fieldName) +// PrintConfig return the current config in string form +func (ngc *NutsGlobalConfig) PrintConfig() string { + return ngc.configMap.Sprint() } -// ErrInvalidConfigTarget is an error used for invalid config target pointers -var ErrInvalidConfigTarget = errors.New("only struct pointers are supported to be a config target") - -// ErrUnMutableConfigTarget is an error used when a struct member is accessible -var ErrUnMutableConfigTarget = errors.New("given Engine.Config can not be altered") - -func (ngc *NutsGlobalConfig) findFieldInStruct(cfgP *reflect.Value, configName string) (*reflect.Value, error) { - if cfgP.Kind() != reflect.Ptr { - return nil, ErrInvalidConfigTarget - } - - s := cfgP.Elem() - if !s.CanSet() { - return nil, ErrUnMutableConfigTarget +// InjectIntoEngine +func (ngc *NutsGlobalConfig) InjectIntoEngine(e *Engine) error { + // ignore if no target for injection + if e.Config != nil { + return ngc.configMap.Unmarshal(e.ConfigKey, e.Config) } - spl := strings.Split(configName, ngc.Delimiter) - - return ngc.findFieldRecursive(&s, spl) + return nil } -func (ngc *NutsGlobalConfig) findFieldRecursive(s *reflect.Value, names []string) (*reflect.Value, error) { - head := names[0] - tail := names[1:] - - t := strings.Title(head) - field := s.FieldByName(t) - switch field.Kind() { - case reflect.Invalid: - return nil, fmt.Errorf("inaccessible or invalid field [%v] in %v", t, s.Type()) - case reflect.Struct: - if len(tail) == 0 { - return nil, fmt.Errorf("incompatible source/target, trying to set value to struct target: %v to %v", strings.Title(head), field.Type()) - } - return ngc.findFieldRecursive(&field, tail) - case reflect.Map: - return nil, fmt.Errorf("map values not supported in %v", field.Type()) - default: - if len(tail) > 0 { - n := fmt.Sprintf("%s.%s", head, strings.Join(tail, ".")) - return nil, fmt.Errorf("incompatible source/target, deeper nested key than target %s", n) - } - } - - if !field.CanSet() { - return nil, fmt.Errorf("field %v can not be Set", t) +// RegisterFlags adds the flagSet of an engine to the commandline, flag names are prefixed if needed +// The passed command must be the root command not the engine.Cmd (unless they are the same) +func (ngc *NutsGlobalConfig) RegisterFlags(cmd *cobra.Command, e *Engine) { + if e.FlagSet != nil { + cmd.PersistentFlags().AddFlagSet(e.FlagSet) } - - return &field, nil } diff --git a/core/config_test.go b/core/config_test.go index e331bec705..4a56d3dfd8 100644 --- a/core/config_test.go +++ b/core/config_test.go @@ -20,72 +20,51 @@ package core import ( - "bytes" "os" - "reflect" "strings" "testing" - "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/pflag" - "github.com/spf13/viper" "github.com/stretchr/testify/assert" ) -func TestNewNutsGlobalConfig(t *testing.T) { - t.Run("returns a NutsGlobalConfig with defaults", func(t *testing.T) { - c := NewNutsGlobalConfig() - - if c.DefaultConfigFile != defaultConfigFile { - t.Errorf("Expected DefaultConfigFile to be [%s], got [%s]", defaultConfigFile, c.DefaultConfigFile) - } - - if c.Prefix != defaultPrefix { - t.Errorf("Expected Prefix to be [%s], got [%s]", defaultPrefix, c.Prefix) - } +func TestNutsGlobalConfig_Load(t *testing.T) { + t.Run("sets defaults", func(t *testing.T) { + cfg := NewNutsConfig() - if c.Delimiter != defaultSeparator { - t.Errorf("Expected Prefix to be [%s], got [%s]", defaultSeparator, c.Delimiter) + err := cfg.Load(&cobra.Command{}) + if !assert.NoError(t, err) { + return } - if !reflect.DeepEqual(c.IgnoredPrefixes, defaultIgnoredPrefixes) { - t.Errorf("Expected Prefix to be [%s], got [%s]", defaultIgnoredPrefixes, c.IgnoredPrefixes) - } + assert.Equal(t, defaultAddress, cfg.Address) + assert.Equal(t, defaultLogLevel, cfg.Verbosity) + assert.Equal(t, false, cfg.Strictmode) }) -} - -func TestNutsConfig(t *testing.T) { - t.Run("returns same instance every time", func(t *testing.T) { - if NutsConfig() != NutsConfig() { - t.Error("Expected instance to be the same") - } - }) -} - -func TestNutsGlobalConfig_Load(t *testing.T) { - cfg := NewNutsGlobalConfig() - if err := cfg.Load(&cobra.Command{}); err != nil { - t.Errorf("Expected no error, got %v", err) - } t.Run("Sets global Env prefix", func(t *testing.T) { + cfg := NewNutsConfig() os.Setenv("NUTS_KEY", "value") - if value := cfg.v.Get("key"); value != "value" { + + err := cfg.Load(&cobra.Command{}) + if !assert.NoError(t, err) { + return + } + + if value := cfg.configMap.Get("key"); value != "value" { t.Errorf("Expected key to have [value], got [%v]", value) } }) t.Run("Sets correct key replacer", func(t *testing.T) { + cfg := NewNutsConfig() os.Setenv("NUTS_SUB_KEY", "value") - if value := cfg.v.Get("sub.key"); value != "value" { - t.Errorf("Expected sub.key to have [value], got [%v]", value) - } - }) - t.Run("Adds configFile flag", func(t *testing.T) { - if value := cfg.v.Get(configFileFlag); value != defaultConfigFile { - t.Errorf("Expected configFile to be [%s], got [%v]", defaultConfigFile, value) + cfg.Load(&cobra.Command{}) + + if value := cfg.configMap.Get("sub.key"); value != "value" { + t.Errorf("Expected sub.key to have [value], got [%v]", value) } }) } @@ -97,27 +76,16 @@ func TestNutsGlobalConfig_Load2(t *testing.T) { t.Run("Ignores unknown flags when parsing", func(t *testing.T) { os.Args = []string{"executable", "command", "--unknown", "value"} - cfg := NewNutsGlobalConfig() - if err := cfg.Load(&cobra.Command{}); err != nil { - t.Errorf("Expected no error, got %v", err) - } - }) - - t.Run("Incorrect arguments returns error", func(t *testing.T) { - os.Args = []string{"command", "---"} - cfg := NewNutsGlobalConfig() + cfg := NewNutsConfig() err := cfg.Load(&cobra.Command{}) - if err == nil { - t.Error("Expected error, got nothing") - return - } + assert.NoError(t, err) }) t.Run("Ignores --help as incorrect argument", func(t *testing.T) { os.Args = []string{"command", "--help"} - cfg := NewNutsGlobalConfig() + cfg := NewNutsConfig() if err := cfg.Load(&cobra.Command{}); err != nil { t.Errorf("Expected no error, got %v", err) @@ -126,510 +94,89 @@ func TestNutsGlobalConfig_Load2(t *testing.T) { t.Run("Returns error for incorrect verbosity", func(t *testing.T) { os.Args = []string{"command", "--verbosity", "hell"} - cfg := NewNutsGlobalConfig() + cfg := NewNutsConfig() err := cfg.Load(&cobra.Command{}) - if err == nil { - t.Error("Expected error, got nothing") - return - } - - expected := "not a valid logrus Level: \"hell\"" - if err.Error() != expected { - t.Errorf("Expected error [%s], got [%v]", expected, err) - } + assert.Error(t, err) }) t.Run("Strict-mode is off by default", func(t *testing.T) { os.Args = []string{"command"} - cfg := NewNutsGlobalConfig() + cfg := NewNutsConfig() err := cfg.Load(&cobra.Command{}) assert.NoError(t, err) - assert.False(t, cfg.InStrictMode()) + assert.False(t, cfg.Strictmode) }) t.Run("Strict-mode can be turned on", func(t *testing.T) { os.Args = []string{"command", "--strictmode"} - cfg := NewNutsGlobalConfig() + cfg := NewNutsConfig() + err := cfg.Load(&cobra.Command{}) + assert.NoError(t, err) - assert.True(t, cfg.InStrictMode()) + assert.True(t, cfg.Strictmode) }) } func TestNutsGlobalConfig_PrintConfig(t *testing.T) { - cfg := NewNutsGlobalConfig() + cfg := NewNutsConfig() fs := pflag.FlagSet{} fs.String("camelCaseKey", "value", "description") - system := NewSystem() - system.RegisterEngine(&Engine{FlagSet: &fs}) - logger := logrus.New() - buf := new(bytes.Buffer) - logger.Out = buf - cfg.PrintConfig(system, logger) - bs := buf.String() + cmd := &cobra.Command{} + cmd.PersistentFlags().AddFlagSet(&fs) + cfg.Load(cmd) + + bs := cfg.PrintConfig() t.Run("output contains key", func(t *testing.T) { if strings.Index(bs, "camelCaseKey") == -1 { t.Error("Expected key to be in output") } }) - - t.Run("output contains some stars", func(t *testing.T) { - if strings.Index(bs, "***************") == -1 { - t.Error("Expected stars to be in output") - } - }) - - t.Run("output contains header", func(t *testing.T) { - if strings.Index(bs, "*** Config ****") == -1 { - t.Error("Expected header to be in output") - } - }) } func TestNutsGlobalConfig_RegisterFlags(t *testing.T) { - t.Run("adds prefix to flag", func(t *testing.T) { + t.Run("adds flags", func(t *testing.T) { e := &Engine{ - Cmd: &cobra.Command{}, - ConfigKey: "pre", - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), + Cmd: &cobra.Command{}, + FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), } e.FlagSet.String("key", "", "") - cfg := NewNutsGlobalConfig() - cfg.RegisterFlags(e.Cmd, e) + assert.False(t, e.Cmd.PersistentFlags().HasAvailableFlags()) - var found bool - for _, key := range cfg.v.AllKeys() { - if key == "pre.key" { - found = true - } - } - - if !found { - t.Errorf("Expected [pre.key] to be available as config") - } - }) - - t.Run("does not add a prefix to flag when prefix is added to ignoredPrefixes", func(t *testing.T) { - e := &Engine{ - Cmd: &cobra.Command{}, - ConfigKey: "pre", - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.String("key", "", "") - - cfg := NewNutsGlobalConfig() - cfg.IgnoredPrefixes = append(cfg.IgnoredPrefixes, "pre") + cfg := NewNutsConfig() cfg.RegisterFlags(e.Cmd, e) - var found bool - for _, key := range cfg.v.AllKeys() { - if key == "key" { - found = true - } - } - - if !found { - t.Errorf("Expected [key] to be available as config") - } - }) -} - -func TestNutsGlobalConfig_LoadConfigFile(t *testing.T) { - t.Run("Does not return error on missing file", func(t *testing.T) { - cfg := NutsGlobalConfig{ - DefaultConfigFile: "non_existing.yaml", - v: viper.New(), - } - cfg.Load(&cobra.Command{}) - - if err := cfg.loadConfigFile(); err != nil { - t.Errorf("Expected no error, got %v", err) - } - }) - - t.Run("Returns error on incorrect file", func(t *testing.T) { - cfg := NutsGlobalConfig{ - DefaultConfigFile: "test/config/corrupt.yaml", - v: viper.New(), - } - cfg.Load(&cobra.Command{}) - - err := cfg.loadConfigFile() - if err == nil { - t.Errorf("Expected error, got nothing") - return - } - - expected := "While parsing config: yaml: line 1: did not find expected ',' or '}'" - if err.Error() != expected { - t.Errorf("Expected error: [%s], got [%v]", expected, err.Error()) - } - }) - - t.Run("Loads settings into viper", func(t *testing.T) { - cfg := NutsGlobalConfig{ - DefaultConfigFile: "test/config/dummy.yaml", - v: viper.New(), - } - cfg.Load(&cobra.Command{}) - - err := cfg.loadConfigFile() - if err != nil { - t.Errorf("Expected no error, got [%v]", err.Error()) - return - } - - val := cfg.v.Get("key") - if val != "value" { - t.Errorf("Expected value to equals [value], got [%v]", val) - } - }) -} - -func TestNutsGlobalConfig_LoadAndUnmarshal(t *testing.T) { - cfg := NewNutsGlobalConfig() - cfg.Load(&cobra.Command{}) - - type mandatory struct { - Identity string - } - - t.Run("Adds configFile flag to Cmd", func(t *testing.T) { - err := cfg.LoadAndUnmarshal(&cobra.Command{}, &struct{ mandatory }{}) - if assert.NoError(t, err) { - assert.NotEmpty(t, cfg.v.GetString(configFileFlag)) - } - }) - - t.Run("Injects custom config into struct", func(t *testing.T) { - s := struct { - mandatory - Key string - }{ - Key: "", - } - cfg.v.Set("key", "value") - err := cfg.LoadAndUnmarshal(&cobra.Command{}, &s) - if err != nil { - t.Errorf("Expected no error, got [%v]", err.Error()) - } - - if s.Key != "value" { - t.Errorf("Expected value for key in struct to equal [value], got %s", s.Key) - } - }) - - t.Run("returns error on incorrect struct argument", func(t *testing.T) { - cfg := NewNutsGlobalConfig() - s := struct{ mandatory }{} - err := cfg.LoadAndUnmarshal(&cobra.Command{}, s) - if err == nil { - t.Errorf("Expected error, got nothing") - return - } - - assert.Contains(t, err.Error(), "only struct pointers are supported to be a config target") - }) - - t.Run("returns error on map argument", func(t *testing.T) { - cfg := NewNutsGlobalConfig() - s := struct { - mandatory - Key map[string]string - }{ - Key: make(map[string]string), - } - cfg.v.Set("key", "value") - err := cfg.LoadAndUnmarshal(&cobra.Command{}, &s) - if err == nil { - t.Errorf("Expected error, got nothing") - return - } - - expected := "problem injecting [key]: map values not supported in map[string]string" - if err.Error() != expected { - t.Errorf("Expected error [%s], got [%v]", expected, err.Error()) - } - }) - - t.Run("returns error on unknown value", func(t *testing.T) { - s := struct{ mandatory }{} - cfg.v.Set("key", "value") - err := cfg.LoadAndUnmarshal(&cobra.Command{}, &s) - - if err == nil { - t.Errorf("Expected error, got nothing") - return - } - - assert.Contains(t, err.Error(), "problem injecting [key]: inaccessible or invalid field [Key] in struct") - }) - - t.Run("returns error on inaccessible value", func(t *testing.T) { - s := struct { - mandatory - key string - }{ - key: "", - } - cfg.v.Set("key", "value") - err := cfg.LoadAndUnmarshal(&cobra.Command{}, &s) - - if err == nil { - t.Errorf("Expected error, got nothing") - return - } - - assert.Contains(t, err.Error(), "problem injecting [key]: inaccessible or invalid field [Key] in struct") - }) - - t.Run("returns error on incorrect argument", func(t *testing.T) { - os.Args = []string{"command", "---"} - cfg := NewNutsGlobalConfig() - s := struct{}{} - - err := cfg.LoadAndUnmarshal(&cobra.Command{}, &s) - - if err == nil { - t.Error("Expected error, got nothing") - return - } + assert.True(t, e.Cmd.PersistentFlags().HasAvailableFlags()) }) } func TestNutsGlobalConfig_InjectIntoEngine(t *testing.T) { - cfg := NewNutsGlobalConfig() - cfg.Load(&cobra.Command{}) - - t.Run("param is injected into engine without ConfigKey", func(t *testing.T) { - c := struct { - Key string - }{} - - e := &Engine{ - Config: &c, - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.String("key", "", "") - - cfg.v.Set("key", "value") - - if err := cfg.InjectIntoEngine(e); err != nil { - t.Errorf("Expected no error, got [%v]", err.Error()) - } - - if c.Key != "value" { - t.Errorf("Expected value to be injected into struct") - } - }) - - t.Run("slice param is injected into engine without ConfigKey", func(t *testing.T) { - c := struct { - Key []string - }{} - - e := &Engine{ - Config: &c, - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.StringArray("key", []string{""}, "") - - // slices a read as []interface{} - cfg.v.Set("key", []interface{}{"value"}) - - if err := cfg.InjectIntoEngine(e); err != nil { - t.Errorf("Expected no error, got [%v]", err.Error()) - } - - if c.Key[0] != "value" { - t.Errorf("Expected value to be injected into struct") - } - }) - - t.Run("int param is injected into engine from env variable", func(t *testing.T) { - c := struct { - EnvKey int - }{} - - e := &Engine{ - Config: &c, - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.Int("envKey", 0, "") - - os.Setenv("NUTS_ENVKEY", "1") - - if err := cfg.InjectIntoEngine(e); err != nil { - t.Errorf("Expected no error, got [%v]", err.Error()) - } - - if c.EnvKey != 1 { - t.Errorf("Expected value to be injected into struct") - } - }) - - t.Run("bool param is injected into engine from env variable", func(t *testing.T) { - c := struct { - EnvKey bool - }{} - - e := &Engine{ - Config: &c, - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.Bool("envKey", false, "") - - os.Setenv("NUTS_ENVKEY", "true") - - if err := cfg.InjectIntoEngine(e); err != nil { - t.Errorf("Expected no error, got [%v]", err.Error()) - } - - if c.EnvKey != true { - t.Errorf("Expected value to be injected into struct") - } - }) - - t.Run("param is injected into engine with ConfigKey", func(t *testing.T) { - c := struct { - Key string - }{} - - e := &Engine{ - Config: &c, - ConfigKey: "pre", - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.String("key", "", "") - - cfg.v.Set("pre.key", "value") - - if err := cfg.InjectIntoEngine(e); err != nil { - t.Errorf("Expected no error, got [%v]", err.Error()) - } - - if c.Key != "value" { - t.Errorf("Expected value to be injected into struct") - } - }) - - t.Run("nested param is injected into engine without ConfigKey", func(t *testing.T) { - c := struct { - Nested struct{ Key string } - }{} - - e := &Engine{ - Config: &c, - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.String("nested.key", "", "") - - cfg.v.Set("nested.key", "value") - - if err := cfg.InjectIntoEngine(e); err != nil { - t.Errorf("Expected no error, got [%v]", err.Error()) - } - - if c.Nested.Key != "value" { - t.Errorf("Expected value to be injected into struct") - } - }) - - t.Run("nested param is injected into engine with ConfigKey", func(t *testing.T) { - c := struct { - Nested struct{ Key string } - }{} - - e := &Engine{ - Config: &c, - ConfigKey: "pre", - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.String("nested.key", "", "") - - cfg.v.Set("pre.nested.key", "value") - - if err := cfg.InjectIntoEngine(e); err != nil { - t.Errorf("Expected no error, got [%v]", err.Error()) - } - - if c.Nested.Key != "value" { - t.Errorf("Expected value to be injected into struct") - } - }) - - t.Run("returns error for inaccessible key in struct", func(t *testing.T) { - c := struct { - key string - }{} - - e := &Engine{ - Name: "test", - Config: &c, - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.String("key", "", "") - - err := cfg.InjectIntoEngine(e) - if err == nil { - t.Errorf("Expected error, got nothing") - } - - expected := "problem injecting [key] for test: inaccessible or invalid field [Key] in struct { key string }" - if err.Error() != expected { - t.Errorf("Expected error [%s], got [%v]", expected, err.Error()) - } - }) - - t.Run("returns error on missing default", func(t *testing.T) { - c := struct { - Nested struct{ Key string } - }{} - - e := &Engine{ - Config: &c, - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.String("nested.key", "", "") - - cfg.v.Set("nested", "value") - - err := cfg.InjectIntoEngine(e) - if err == nil { - t.Errorf("Expected error, got nothing") - } + defer func() { + os.Args = []string{"command"} + }() - expected := "nil value for nested.key, forgot to add flag binding" - if err.Error() != expected { - t.Errorf("Expected error [%s], got [%v]", expected, err.Error()) - } - }) + os.Args = []string{"command", "--key", "value"} + cfg := NewNutsConfig() - t.Run("returns error on wrong nesting", func(t *testing.T) { + t.Run("param is injected", func(t *testing.T) { c := struct { - Nested string + Key string `koanf:"key"` }{} - e := &Engine{ Config: &c, + Cmd: &cobra.Command{}, FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), } - e.FlagSet.String("nested.key", "", "") + e.FlagSet.String("key", "", "test") - cfg.v.Set("nested.key", "value") - - err := cfg.InjectIntoEngine(e) - if err == nil { - t.Errorf("Expected error, got nothing") - } + cfg.RegisterFlags(e.Cmd, e) + cfg.Load(e.Cmd) + cfg.InjectIntoEngine(e) - expected := "problem injecting [nested.key] for : incompatible source/target, deeper nested key than target nested.key" - if err.Error() != expected { - t.Errorf("Expected error [%s], got [%v]", expected, err.Error()) - } + assert.Equal(t, "value", c.Key) }) } diff --git a/core/engine.go b/core/engine.go index b184180851..26ccb715ce 100644 --- a/core/engine.go +++ b/core/engine.go @@ -29,13 +29,18 @@ import ( // NewSystem creates a new, empty System. func NewSystem() *System { - return &System{engines: []*Engine{}} + return &System{ + engines: []*Engine{}, + Config: NewNutsConfig(), + } } // System is the control structure where engines are registered. type System struct { // engines is the slice of all registered engines engines []*Engine + // Config holds the global and raw config + Config *NutsGlobalConfig } // Diagnostics returns the compound diagnostics for all engines. diff --git a/crypto/api/v1/generated.go b/crypto/api/v1/generated.go index 7309b9c63c..873d6da43b 100644 --- a/crypto/api/v1/generated.go +++ b/crypto/api/v1/generated.go @@ -499,4 +499,3 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.POST(baseURL+"/internal/crypto/v1/sign_jwt", wrapper.SignJwt) } - diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 317635785d..b7a6945657 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -29,8 +29,6 @@ import ( "github.com/nuts-foundation/nuts-node/test/io" "github.com/nuts-foundation/nuts-node/core" - "github.com/spf13/cobra" - "github.com/nuts-foundation/nuts-node/crypto/storage" "github.com/stretchr/testify/assert" ) @@ -172,9 +170,6 @@ func TestCryptoConfig_getFsPath(t *testing.T) { } func createCrypto(t *testing.T) *Crypto { - if err := core.NutsConfig().Load(&cobra.Command{}); err != nil { - panic(err) - } dir := io.TestDirectory(t) backend, _ := storage.NewFileSystemBackend(dir) crypto := Crypto{ diff --git a/crypto/engine/engine.go b/crypto/engine/engine.go index 3eb9990e84..c2ded6371d 100644 --- a/crypto/engine/engine.go +++ b/crypto/engine/engine.go @@ -32,11 +32,11 @@ import ( "github.com/spf13/pflag" ) -// ConfigStorage is used as --storage config flag -const ConfigStorage string = "storage" +// ConfigStorage is used as --crypto.storage config flag +const ConfigStorage string = "crypto.storage" -// ConfigFSPath is used as --fspath config flagclient.getStoragePath() -const ConfigFSPath string = "fspath" +// ConfigFSPath is used as --crypto.fspath config flagclient.getStoragePath() +const ConfigFSPath string = "crypto.fspath" // NewCryptoEngine the engine configuration for nuts-go. func NewCryptoEngine() (*core.Engine, crypto2.KeyStore) { @@ -134,11 +134,11 @@ func cmd() *cobra.Command { // newCryptoClient creates a remote client func newCryptoClient(cmd *cobra.Command) api.HTTPClient { - cfg := core.NutsConfig() + cfg := core.NewNutsConfig() cfg.Load(cmd) return api.HTTPClient{ - ServerAddress: cfg.ServerAddress(), + ServerAddress: cfg.Address, Timeout: 10 * time.Second, } } diff --git a/crypto/engine/engine_test.go b/crypto/engine/engine_test.go index ccd4f22880..55634ae52e 100644 --- a/crypto/engine/engine_test.go +++ b/crypto/engine/engine_test.go @@ -83,8 +83,6 @@ var jwkAsString = ` var jwkAsBytes = []byte(jwkAsString) func TestNewCryptoEngine_Cmd(t *testing.T) { - core.NutsConfig().Load(&cobra.Command{}) - createCmd := func(t *testing.T) (*cobra.Command, *crypto.Crypto) { testDirectory := io.TestDirectory(t) instance := crypto.NewTestCryptoInstance(testDirectory) @@ -119,7 +117,7 @@ func TestNewCryptoEngine_Cmd(t *testing.T) { cmd, _ := createCmd(t) s := httptest.NewServer(handler{statusCode: http.StatusOK, responseData: jwkAsBytes}) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() buf := new(bytes.Buffer) @@ -138,7 +136,7 @@ func TestNewCryptoEngine_Cmd(t *testing.T) { cmd, _ := createCmd(t) s := httptest.NewServer(handler{statusCode: http.StatusOK, responseData: jwkAsBytes}) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() buf := new(bytes.Buffer) @@ -169,11 +167,11 @@ func TestNewCryptoEngine_FlagSet(t *testing.T) { result := buf.String() - if !strings.Contains(result, "--storage") { + if !strings.Contains(result, "--crypto.storage") { t.Errorf("Expected --storage to be command line flag") } - if !strings.Contains(result, "--fspath") { + if !strings.Contains(result, "--crypto.fspath") { t.Errorf("Expected --fspath to be command line flag") } diff --git a/docs/config-options-docs.go b/docs/config-options-docs.go index 05665ee09c..49a7d3a3fd 100644 --- a/docs/config-options-docs.go +++ b/docs/config-options-docs.go @@ -13,7 +13,7 @@ func main() { flags := make(map[string]*pflag.FlagSet) system := cmd.CreateSystem() command := cmd.CreateCommand(system) - core.NutsConfig().Load(command) + core.NewNutsConfig().Load(command) globalFlags := command.PersistentFlags() flags[""] = globalFlags // Make sure engines are registered @@ -33,7 +33,7 @@ func main() { func extractFlagsForEngine(configKey string, flagSet *pflag.FlagSet) *pflag.FlagSet { result := pflag.FlagSet{} flagSet.VisitAll(func(current *pflag.Flag) { - if strings.HasPrefix(current.Name, configKey + ".") { + if strings.HasPrefix(current.Name, configKey+".") { // This flag belongs to this engine, so copy it and hide it in the input flag set flagCopy := *current current.Hidden = true diff --git a/docs/pages/configuration/options.rst b/docs/pages/configuration/options.rst index 6a8a0161e7..681f712f76 100755 --- a/docs/pages/configuration/options.rst +++ b/docs/pages/configuration/options.rst @@ -3,8 +3,7 @@ Key Default Description ============================ ============== ================================================================================================================================================================================= **** address localhost:1323 Address and port the server will be listening to -configfile nuts.yaml Nuts config file -identity Vendor identity for the node, mandatory when running in server mode. Must be in the format: urn:oid:1.3.6.1.4.1.54851.4: +configfile Nuts config file strictmode false When set, insecure settings are forbidden. verbosity info Log level (trace, debug, info, warn, error) **Crypto** @@ -14,7 +13,7 @@ crypto.storage fs Storage to use, 'fs' for file syst network.advertHashesInterval 2000 Interval (in milliseconds) that specifies how often the node should broadcast its last hashes to other nodes. network.bootstrapNodes Space-separated list of bootstrap nodes (`:`) which the node initially connect to. network.certFile PEM file containing the server certificate for the gRPC server. Required when `enableTLS` is `true`. -network.certKeyFile PEM file containing the private key of the server certificate. Required when `enableTLS` is `true`. +network.certKeyFile PEM file containing the private key of the server certificate. Required when `network.enableTLS` is `true`. network.databaseFile network.db File path to the network database. network.enableTLS true Whether to enable TLS for inbound gRPC connections. If set to `true` (which is default) `certFile` and `certKeyFile` MUST be configured. network.grpcAddr \:5555 Local address for gRPC to listen on. If empty the gRPC server won't be started and other nodes will not be able to connect to this node (outbound connections can still be made). diff --git a/go.mod b/go.mod index 86fec21c79..2b9e45d56f 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/golang/mock v1.4.4 github.com/golang/protobuf v1.4.3 github.com/google/uuid v1.1.2 + github.com/knadh/koanf v0.15.0 github.com/labstack/echo/v4 v4.1.17 github.com/lestrrat-go/jwx v1.0.7 github.com/magiconair/properties v1.8.4 @@ -17,7 +18,6 @@ require ( github.com/sirupsen/logrus v1.7.0 github.com/spf13/cobra v1.0.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.7.1 github.com/stretchr/testify v1.6.1 go.etcd.io/bbolt v1.3.5 google.golang.org/grpc v1.33.1 diff --git a/go.sum b/go.sum index 0b16dec979..2e993b4150 100644 --- a/go.sum +++ b/go.sum @@ -1,25 +1,11 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -29,7 +15,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -39,9 +24,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -59,26 +42,27 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.26.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -97,8 +81,8 @@ github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -108,55 +92,48 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= +github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q= +github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/knadh/koanf v0.15.0 h1:HMm8cJZZIokMn5ETu9Exut1jQhfu1dm3b0TZedvhSVo= +github.com/knadh/koanf v0.15.0/go.mod h1:Ut3d4JaTRZYfO5a0wdYIGE+oyGaGFo4vXQ3ZvaSWxNc= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -185,8 +162,6 @@ github.com/lestrrat-go/pdebug v0.0.0-20200204225717-4d6bd78da58d/go.mod h1:B06CS github.com/lestrrat-go/pdebug/v3 v3.0.0-20210111091911-ec4f5c88c087 h1:T5Wh8C/p5nWoGuEUBQj+daEXkj1CScB9GshvvsBJhpg= github.com/lestrrat-go/pdebug/v3 v3.0.0-20210111091911-ec4f5c88c087/go.mod h1:za+m+Ve24yCxTEhR59N7UlnJomWwCiIqbJRmKeiADU4= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= @@ -203,16 +178,17 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= +github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -222,10 +198,14 @@ github.com/nuts-foundation/go-did v0.0.0-20210125091337-21da6ad69a82 h1:AUj8bNaF github.com/nuts-foundation/go-did v0.0.0-20210125091337-21da6ad69a82/go.mod h1:wpgiNMle93QRhzm2Oh4J+yGgbSpw1LoBAcsoUqNr2Bo= github.com/ockam-network/did v0.1.3 h1:qJGdccOV4bLfsS/eFM+Aj+CdCRJKNMxbmJevQclw44k= github.com/ockam-network/did v0.1.3/go.mod h1:ZsbTIuVGt8OrQEbqWrSztUISN4joeMabdsinbLubbzw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -258,11 +238,11 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/shengdoushi/base58 v1.0.0 h1:tGe4o6TmdXFJWoI31VoSWvuaKxf0Px3gqa3sUWhAxBs= github.com/shengdoushi/base58 v1.0.0/go.mod h1:m5uIILfzcKMw6238iWAhP4l3s5+uXyF3+bJKUNhAL9I= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -270,10 +250,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= @@ -288,8 +264,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= -github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -298,8 +272,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -314,16 +286,11 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -333,38 +300,18 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 h1:3wPMTskHO3+O6jqTEXyFcsnuxMQOqYSaHsDxcbUXpqA= golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -372,8 +319,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -383,19 +328,16 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -404,35 +346,24 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200417140056-c07e33ef3290/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -440,32 +371,17 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= @@ -484,27 +400,23 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/network/api/v1/generated.go b/network/api/v1/generated.go index 1d386ab251..c4f81ec65a 100644 --- a/network/api/v1/generated.go +++ b/network/api/v1/generated.go @@ -525,4 +525,3 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.GET(baseURL+"/api/document/:ref/payload", wrapper.GetDocumentPayload) } - diff --git a/network/config.go b/network/config.go index 631991a301..5c30b51783 100644 --- a/network/config.go +++ b/network/config.go @@ -10,16 +10,16 @@ import ( // Config holds the config for Network type Config struct { // Socket address for gRPC to listen on - GrpcAddr string - DatabaseFile string + GrpcAddr string `koanf:"grpcAddr"` + DatabaseFile string `koanf:"databaseFile"` // EnableTLS specifies whether to enable TLS for incoming connections. - EnableTLS bool + EnableTLS bool `koanf:"enableTLS"` // Public address of this nodes other nodes can use to connect to this node. - PublicAddr string - BootstrapNodes string - CertFile string - CertKeyFile string - TrustStoreFile string + PublicAddr string `koanf:"publicAddr"` + BootstrapNodes string `koanf:"bootstrapNodes"` + CertFile string `koanf:"certFile"` + CertKeyFile string `koanf:"certKeyFile"` + TrustStoreFile string `koanf:"trustStoreFile"` // AdvertHashesInterval specifies how often (in milliseconds) the node should broadcasts its last hashes so // other nodes can compare and synchronize. diff --git a/network/dag/test.go b/network/dag/test.go index a0f5363cdc..8b4cae6fb7 100644 --- a/network/dag/test.go +++ b/network/dag/test.go @@ -27,7 +27,6 @@ import ( "time" ) - // CreateTestDocumentWithJWK creates a document with the given num as payload hash and signs it with a random EC key. // The JWK is attached, rather than referred to using the kid. func CreateTestDocumentWithJWK(num uint32, prevs ...hash.SHA256Hash) Document { @@ -55,4 +54,3 @@ func CreateTestDocument(num uint32, prevs ...hash.SHA256Hash) (Document, string, } return signedDocument, kid, signer.Key.Public() } - diff --git a/network/engine/engine.go b/network/engine/engine.go index fe26c54b07..e89b4b8547 100644 --- a/network/engine/engine.go +++ b/network/engine/engine.go @@ -31,9 +31,12 @@ import ( "time" ) -var clientCreator = func() *v1.HTTPClient { +var clientCreator = func(cmd *cobra.Command) *v1.HTTPClient { + cfg := core.NewNutsConfig() + cfg.Load(cmd) + return &v1.HTTPClient{ - ServerAddress: core.NutsConfig().ServerAddress(), + ServerAddress: cfg.Address, Timeout: 30 * time.Second, } } @@ -60,20 +63,20 @@ func NewNetworkEngine(keyStore crypto.KeyStore) (*core.Engine, network.Network) func flagSet() *pflag.FlagSet { defs := network.DefaultConfig() flagSet := pflag.NewFlagSet("network", pflag.ContinueOnError) - flagSet.String("grpcAddr", defs.GrpcAddr, "Local address for gRPC to listen on. "+ + flagSet.String("network.grpcAddr", defs.GrpcAddr, "Local address for gRPC to listen on. "+ "If empty the gRPC server won't be started and other nodes will not be able to connect to this node "+ "(outbound connections can still be made).") - flagSet.String("publicAddr", defs.PublicAddr, "Public address (of this node) other nodes can use to connect to it. If set, it is registered on the nodelist.") - flagSet.String("bootstrapNodes", defs.BootstrapNodes, "Space-separated list of bootstrap nodes (`:`) which the node initially connect to.") - flagSet.Bool("enableTLS", defs.EnableTLS, "Whether to enable TLS for inbound gRPC connections. "+ + flagSet.String("network.publicAddr", defs.PublicAddr, "Public address (of this node) other nodes can use to connect to it. If set, it is registered on the nodelist.") + flagSet.String("network.bootstrapNodes", defs.BootstrapNodes, "Space-separated list of bootstrap nodes (`:`) which the node initially connect to.") + flagSet.Bool("network.enableTLS", defs.EnableTLS, "Whether to enable TLS for inbound gRPC connections. "+ "If set to `true` (which is default) `certFile` and `certKeyFile` MUST be configured.") - flagSet.String("certFile", defs.CertFile, "PEM file containing the server certificate for the gRPC server. "+ - "Required when `enableTLS` is `true`.") - flagSet.String("certKeyFile", defs.CertKeyFile, "PEM file containing the private key of the server certificate. "+ + flagSet.String("network.certFile", defs.CertFile, "PEM file containing the server certificate for the gRPC server. "+ "Required when `enableTLS` is `true`.") - flagSet.String("databaseFile", defs.DatabaseFile, "File path to the network database.") - flagSet.String("trustStoreFile", defs.TrustStoreFile, "PEM file containing the trusted CA certificates for authenticating remote gRPC servers.") - flagSet.Int("advertHashesInterval", defs.AdvertHashesInterval, "Interval (in milliseconds) that specifies how often the node should broadcast its last hashes to other nodes.") + flagSet.String("network.certKeyFile", defs.CertKeyFile, "PEM file containing the private key of the server certificate. "+ + "Required when `network.enableTLS` is `true`.") + flagSet.String("network.databaseFile", defs.DatabaseFile, "File path to the network database.") + flagSet.String("network.trustStoreFile", defs.TrustStoreFile, "PEM file containing the trusted CA certificates for authenticating remote gRPC servers.") + flagSet.Int("network.advertHashesInterval", defs.AdvertHashesInterval, "Interval (in milliseconds) that specifies how often the node should broadcast its last hashes to other nodes.") return flagSet } @@ -98,7 +101,7 @@ func payloadCommand() *cobra.Command { if err != nil { return err } - data, err := clientCreator().GetDocumentPayload(hash) + data, err := clientCreator(cmd).GetDocumentPayload(hash) if err != nil { return err } @@ -122,7 +125,7 @@ func getCommand() *cobra.Command { if err != nil { return err } - document, err := clientCreator().GetDocument(hash) + document, err := clientCreator(cmd).GetDocument(hash) if err != nil { return err } @@ -141,7 +144,7 @@ func listCommand() *cobra.Command { Use: "list", Short: "Lists the documents on the network", RunE: func(cmd *cobra.Command, args []string) error { - documents, err := clientCreator().ListDocuments() + documents, err := clientCreator(cmd).ListDocuments() if err != nil { return err } diff --git a/network/engine/engine_test.go b/network/engine/engine_test.go index 5e7488b26a..0ef2204235 100644 --- a/network/engine/engine_test.go +++ b/network/engine/engine_test.go @@ -49,7 +49,7 @@ func TestCmd_List(t *testing.T) { response := []interface{}{string(dag.CreateTestDocumentWithJWK(1).Data()), string(dag.CreateTestDocumentWithJWK(2).Data())} s := httptest.NewServer(http2.Handler{StatusCode: http.StatusOK, ResponseData: response}) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() cmd.SetArgs([]string{"list"}) @@ -63,7 +63,7 @@ func TestCmd_Get(t *testing.T) { handler := http2.Handler{StatusCode: http.StatusOK, ResponseData: string(response.Data())} s := httptest.NewServer(handler) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() t.Run("ok", func(t *testing.T) { @@ -85,7 +85,7 @@ func TestCmd_Payload(t *testing.T) { handler := http2.Handler{StatusCode: http.StatusOK, ResponseData: []byte("Hello, World!")} s := httptest.NewServer(handler) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() t.Run("ok", func(t *testing.T) { @@ -103,7 +103,7 @@ func TestCmd_Payload(t *testing.T) { } func createCmd(t *testing.T) *cobra.Command { - core.NutsConfig().Load(&cobra.Command{}) + core.NewNutsConfig().Load(&cobra.Command{}) testDirectory := io.TestDirectory(t) cryptoInstance := crypto.NewTestCryptoInstance(testDirectory) engine, _ := NewNetworkEngine(cryptoInstance) diff --git a/network/network_integration_test.go b/network/network_integration_test.go index 5123168346..451db66d92 100644 --- a/network/network_integration_test.go +++ b/network/network_integration_test.go @@ -195,7 +195,7 @@ func startNode(name string, directory string) (*NetworkEngine, error) { log.Logger().Infof("Starting node: %s", name) os.MkdirAll(directory, os.ModePerm) logrus.SetLevel(logrus.DebugLevel) - core.NutsConfig().Load(&cobra.Command{}) + core.NewNutsConfig().Load(&cobra.Command{}) mutex.Lock() mutex.Unlock() // Create NetworkEngine instance diff --git a/vdr/api/v1/generated.go b/vdr/api/v1/generated.go index bbabab0a2b..f63fc02d24 100644 --- a/vdr/api/v1/generated.go +++ b/vdr/api/v1/generated.go @@ -584,4 +584,3 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.PUT(baseURL+"/internal/vdr/v1/did/:did", wrapper.UpdateDID) } - diff --git a/vdr/config.go b/vdr/config.go index 6297985d46..123d3bc9d3 100644 --- a/vdr/config.go +++ b/vdr/config.go @@ -1,18 +1,18 @@ package vdr // ConfDataDir is the config name for specifiying the data location of the requiredFiles -const ConfDataDir = "datadir" +const ConfDataDir = "vdr.datadir" // ConfClientTimeout is the time-out for the client in seconds (e.g. when using the CLI). -const ConfClientTimeout = "clientTimeout" +const ConfClientTimeout = "vdr.clientTimeout" // ModuleName contains the name of this module const ModuleName = "Verifiable Data Registry" // Config holds the config for the VDR engine type Config struct { - Datadir string - ClientTimeout int + Datadir string `koanf:"datadir"` + ClientTimeout int `koanf:"clientTimeout"` } // DefaultConfig returns a fresh Config filled with default values diff --git a/vdr/engine/engine.go b/vdr/engine/engine.go index da723f7bc5..5040b1b11a 100644 --- a/vdr/engine/engine.go +++ b/vdr/engine/engine.go @@ -88,7 +88,7 @@ func createCmd() *cobra.Command { Short: "Registers a new DID", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - client := httpClient() + client := httpClient(cmd) doc, err := client.Create() if err != nil { @@ -110,7 +110,7 @@ func updateCmd() *cobra.Command { "If no file is given, a pipe is assumed. The hash is needed to prevent concurrent updates.", Args: cobra.RangeArgs(2, 3), RunE: func(cmd *cobra.Command, args []string) error { - client := httpClient() + client := httpClient(cmd) id := args[0] hash := args[1] @@ -153,7 +153,7 @@ func resolveCmd() *cobra.Command { Short: "Resolve a DID document based on its DID", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - client := httpClient() + client := httpClient(cmd) doc, meta, err := client.Get(args[0]) if err != nil { @@ -181,9 +181,12 @@ func readFromStdin() ([]byte, error) { return ioutil.ReadAll(bufio.NewReader(os.Stdin)) } -func httpClient() api.HTTPClient { +func httpClient(cmd *cobra.Command) api.HTTPClient { + cfg := core.NewNutsConfig() + cfg.Load(cmd) + // TODO: allow for https - addr := core.NutsConfig().ServerAddress() + addr := cfg.Address if !strings.HasPrefix(addr, "http") { addr = "http://" + addr } diff --git a/vdr/engine/engine_test.go b/vdr/engine/engine_test.go index c87abecf4e..101e5859b4 100644 --- a/vdr/engine/engine_test.go +++ b/vdr/engine/engine_test.go @@ -52,14 +52,14 @@ func TestNewRegistryEngine(t *testing.T) { t.Run("configuration", func(t *testing.T) { e := NewVDREngine(cryptoInstance, networkInstance) - cfg := core.NutsConfig() + cfg := core.NewNutsConfig() cfg.RegisterFlags(e.Cmd, e) assert.NoError(t, cfg.InjectIntoEngine(e)) }) } func TestEngine_Command(t *testing.T) { - core.NutsConfig().Load(&cobra.Command{}) + core.NewNutsConfig().Load(&cobra.Command{}) testDirectory := io.TestDirectory(t) cryptoInstance := crypto.NewTestCryptoInstance(testDirectory) networkInstance := network.NewTestNetworkInstance(testDirectory) @@ -83,7 +83,7 @@ func TestEngine_Command(t *testing.T) { cmd := createCmd(t) s := httptest.NewServer(http2.Handler{StatusCode: http.StatusOK, ResponseData: exampleDIDDocument}) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() buf := new(bytes.Buffer) @@ -102,7 +102,7 @@ func TestEngine_Command(t *testing.T) { cmd := createCmd(t) s := httptest.NewServer(http2.Handler{StatusCode: http.StatusInternalServerError, ResponseData: "b00m!"}) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() buf := new(bytes.Buffer) @@ -123,7 +123,7 @@ func TestEngine_Command(t *testing.T) { cmd := createCmd(t) s := httptest.NewServer(http2.Handler{StatusCode: http.StatusOK, ResponseData: exampleDIDRsolution}) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() buf := new(bytes.Buffer) @@ -142,7 +142,7 @@ func TestEngine_Command(t *testing.T) { cmd := createCmd(t) s := httptest.NewServer(http2.Handler{StatusCode: http.StatusNotFound, ResponseData: "not found"}) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() buf := new(bytes.Buffer) @@ -163,7 +163,7 @@ func TestEngine_Command(t *testing.T) { cmd := createCmd(t) s := httptest.NewServer(http2.Handler{StatusCode: http.StatusOK, ResponseData: exampleDIDDocument}) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() buf := new(bytes.Buffer) @@ -181,7 +181,7 @@ func TestEngine_Command(t *testing.T) { cmd := createCmd(t) s := httptest.NewServer(http2.Handler{StatusCode: http.StatusOK, ResponseData: exampleDIDDocument}) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() buf := new(bytes.Buffer) @@ -199,7 +199,7 @@ func TestEngine_Command(t *testing.T) { cmd := createCmd(t) s := httptest.NewServer(http2.Handler{StatusCode: http.StatusBadRequest, ResponseData: "invalid"}) os.Setenv("NUTS_ADDRESS", s.URL) - core.NutsConfig().Load(cmd) + core.NewNutsConfig().Load(cmd) defer s.Close() buf := new(bytes.Buffer) @@ -219,14 +219,16 @@ func TestEngine_Command(t *testing.T) { func Test_httpClient(t *testing.T) { t.Run("address has http prefix", func(t *testing.T) { os.Setenv("NUTS_ADDRESS", "https://localhost") - core.NutsConfig().Load(&cobra.Command{}) - client := httpClient() + cmd := &cobra.Command{} + core.NewNutsConfig().Load(cmd) + client := httpClient(cmd) assert.Equal(t, "https://localhost", client.ServerAddress) }) t.Run("address has no http prefix", func(t *testing.T) { os.Setenv("NUTS_ADDRESS", "localhost") - core.NutsConfig().Load(&cobra.Command{}) - client := httpClient() + cmd := &cobra.Command{} + core.NewNutsConfig().Load(cmd) + client := httpClient(cmd) assert.Equal(t, "http://localhost", client.ServerAddress) }) } From dd58b4c1c75673e4ddf8dbbac49f56e583dff514 Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 14:45:26 +0100 Subject: [PATCH 02/16] added coverage to core/config --- core/config.go | 91 ++++++++++++++++--------------------- core/config_test.go | 81 +++++++++++++++++++++++---------- core/test/config/dummy.yaml | 3 -- 3 files changed, 98 insertions(+), 77 deletions(-) delete mode 100644 core/test/config/dummy.yaml diff --git a/core/config.go b/core/config.go index 942d4e9459..a4ad5bb1d6 100644 --- a/core/config.go +++ b/core/config.go @@ -23,14 +23,12 @@ import ( "errors" "os" "strings" - "sync" "github.com/knadh/koanf" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/env" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/providers/posflag" - errors2 "github.com/pkg/errors" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -45,7 +43,6 @@ const addressFlag = "address" const defaultLogLevel = "info" const defaultAddress = "localhost:1323" const strictModeFlag = "strictmode" -const defaultStrictmode = "false" // NutsGlobalConfig has global settings. type NutsGlobalConfig struct { @@ -53,13 +50,11 @@ type NutsGlobalConfig struct { Verbosity string `koanf:"verbosity"` Strictmode bool `koanf:"strictmode"` configMap *koanf.Koanf - once sync.Once } func NewNutsConfig() *NutsGlobalConfig { return &NutsGlobalConfig{ configMap: koanf.New(defaultDelimiter), - once: sync.Once{}, Address: defaultAddress, Verbosity: defaultLogLevel, Strictmode: false, @@ -67,66 +62,61 @@ func NewNutsConfig() *NutsGlobalConfig { } // load follows the load order of configfile, env vars and then commandline param -// it only loads once func (ngc *NutsGlobalConfig) Load(cmd *cobra.Command) (err error) { - ngc.once.Do(func() { - cmd.PersistentFlags().AddFlagSet(ngc.flagSet()) + cmd.PersistentFlags().AddFlagSet(ngc.flagSet()) - ngc.configMap = koanf.New(defaultDelimiter) - var f string + ngc.configMap = koanf.New(defaultDelimiter) + f := ngc.getConfigfile(cmd) - f, err = ngc.getConfigfile(cmd) - if err != nil { + // load file + p := file.Provider(f) + if err = ngc.configMap.Load(p, yaml.Parser()); err != nil { + if !errors.Is(err, os.ErrNotExist) { return } + } - // load file - p := file.Provider(f) - if err = ngc.configMap.Load(p, yaml.Parser()); err != nil { - if !errors.Is(err, os.ErrNotExist) { - return - } - } + // load env + e := env.Provider(defaultPrefix, defaultDelimiter, func(s string) string { + return strings.Replace(strings.ToLower( + strings.TrimPrefix(s, defaultPrefix)), "_", defaultDelimiter, -1) + }) + // errors can't occur for this provider + _ = ngc.configMap.Load(e, nil) - // load env - e := env.Provider(defaultPrefix, defaultDelimiter, func(s string) string { - return strings.Replace(strings.ToLower( - strings.TrimPrefix(s, defaultPrefix)), "_", defaultDelimiter, -1) - }) - if err = ngc.configMap.Load(e, nil); err != nil { - return - } + // load cmd params + if len(os.Args) > 1 { + _ = cmd.PersistentFlags().Parse(os.Args[1:]) + } + // errors can't occur for this provider + _ = ngc.configMap.Load(posflag.Provider(cmd.PersistentFlags(), defaultDelimiter, ngc.configMap), nil) - // load cmd params - cmd.PersistentFlags().Parse(os.Args[1:]) - if err = ngc.configMap.Load(posflag.Provider(cmd.PersistentFlags(), defaultDelimiter, ngc.configMap), nil); err != nil { - return - } - // load into struct - if err = ngc.configMap.Unmarshal("", ngc); err != nil { - return - } + // load into struct + if err = ngc.configMap.Unmarshal("", ngc); err != nil { + return + } - // initialize logger, verbosity flag needs to be available - if _, err = log.ParseLevel(ngc.Verbosity); err != nil { - return - } + // initialize logger, verbosity flag needs to be available + if _, err = log.ParseLevel(ngc.Verbosity); err != nil { + return + } - }) return } // getConfigfile returns the configfile path in the following order: commandline param, env variable, default path -func (ngc *NutsGlobalConfig) getConfigfile(cmd *cobra.Command) (string, error) { +func (ngc *NutsGlobalConfig) getConfigfile(cmd *cobra.Command) string { k := koanf.New(defaultDelimiter) - // load cmd flags - if err := k.Load(posflag.Provider(cmd.Flags(), defaultDelimiter, k), nil); err != nil { - return "", errors2.Wrap(err, "error loading cmd flags") + if len(os.Args) > 1 { + _ = cmd.PersistentFlags().Parse(os.Args[1:]) } + + // load cmd flags, without a parser, no error can be returned + _ = k.Load(posflag.Provider(cmd.PersistentFlags(), defaultDelimiter, k), nil) if f := k.String(configFileFlag); f != "" { - return f, nil + return f } // load env flags @@ -134,14 +124,13 @@ func (ngc *NutsGlobalConfig) getConfigfile(cmd *cobra.Command) (string, error) { return strings.Replace(strings.ToLower( strings.TrimPrefix(s, defaultPrefix)), "_", defaultDelimiter, -1) }) - if err := k.Load(e, nil); err != nil { - return "", errors2.Wrap(err, "error loading env flags") - } + // can't return error + _ = k.Load(e, nil) if f := k.String(configFileFlag); f != "" { - return f, nil + return f } - return defaultConfigFile, nil + return defaultConfigFile } func (ngc *NutsGlobalConfig) flagSet() *pflag.FlagSet { diff --git a/core/config_test.go b/core/config_test.go index 4a56d3dfd8..4c3c8076cc 100644 --- a/core/config_test.go +++ b/core/config_test.go @@ -29,7 +29,12 @@ import ( "github.com/stretchr/testify/assert" ) -func TestNutsGlobalConfig_Load(t *testing.T) { +var reset = func() { + os.Args = []string{"command"} + os.Args = []string{} +} + +func TestNewNutsConfig_Load(t *testing.T) { t.Run("sets defaults", func(t *testing.T) { cfg := NewNutsConfig() @@ -46,6 +51,7 @@ func TestNutsGlobalConfig_Load(t *testing.T) { t.Run("Sets global Env prefix", func(t *testing.T) { cfg := NewNutsConfig() os.Setenv("NUTS_KEY", "value") + defer os.Unsetenv("NUTS_KEY") err := cfg.Load(&cobra.Command{}) if !assert.NoError(t, err) { @@ -60,6 +66,7 @@ func TestNutsGlobalConfig_Load(t *testing.T) { t.Run("Sets correct key replacer", func(t *testing.T) { cfg := NewNutsConfig() os.Setenv("NUTS_SUB_KEY", "value") + defer os.Unsetenv("NUTS_SUB_KEY") cfg.Load(&cobra.Command{}) @@ -67,14 +74,9 @@ func TestNutsGlobalConfig_Load(t *testing.T) { t.Errorf("Expected sub.key to have [value], got [%v]", value) } }) -} - -func TestNutsGlobalConfig_Load2(t *testing.T) { - defer func() { - os.Args = []string{"command"} - }() t.Run("Ignores unknown flags when parsing", func(t *testing.T) { + defer reset() os.Args = []string{"executable", "command", "--unknown", "value"} cfg := NewNutsConfig() @@ -83,16 +85,8 @@ func TestNutsGlobalConfig_Load2(t *testing.T) { assert.NoError(t, err) }) - t.Run("Ignores --help as incorrect argument", func(t *testing.T) { - os.Args = []string{"command", "--help"} - cfg := NewNutsConfig() - - if err := cfg.Load(&cobra.Command{}); err != nil { - t.Errorf("Expected no error, got %v", err) - } - }) - t.Run("Returns error for incorrect verbosity", func(t *testing.T) { + defer reset() os.Args = []string{"command", "--verbosity", "hell"} cfg := NewNutsConfig() @@ -102,6 +96,7 @@ func TestNutsGlobalConfig_Load2(t *testing.T) { }) t.Run("Strict-mode is off by default", func(t *testing.T) { + defer reset() os.Args = []string{"command"} cfg := NewNutsConfig() err := cfg.Load(&cobra.Command{}) @@ -110,6 +105,7 @@ func TestNutsGlobalConfig_Load2(t *testing.T) { }) t.Run("Strict-mode can be turned on", func(t *testing.T) { + defer reset() os.Args = []string{"command", "--strictmode"} cfg := NewNutsConfig() @@ -118,9 +114,21 @@ func TestNutsGlobalConfig_Load2(t *testing.T) { assert.NoError(t, err) assert.True(t, cfg.Strictmode) }) + + t.Run("error - incorrect yaml", func(t *testing.T) { + defer reset() + os.Args = []string{"command", "--configfile", "test/config/corrupt.yaml"} + cfg := NewNutsConfig() + + err := cfg.Load(&cobra.Command{}) + + if !assert.Error(t, err) { + return + } + }) } -func TestNutsGlobalConfig_PrintConfig(t *testing.T) { +func TestNewNutsConfig_PrintConfig(t *testing.T) { cfg := NewNutsConfig() fs := pflag.FlagSet{} fs.String("camelCaseKey", "value", "description") @@ -132,12 +140,12 @@ func TestNutsGlobalConfig_PrintConfig(t *testing.T) { t.Run("output contains key", func(t *testing.T) { if strings.Index(bs, "camelCaseKey") == -1 { - t.Error("Expected key to be in output") + t.Error("Expected camelCaseKey to be in output") } }) } -func TestNutsGlobalConfig_RegisterFlags(t *testing.T) { +func TestNewNutsConfig_RegisterFlags(t *testing.T) { t.Run("adds flags", func(t *testing.T) { e := &Engine{ Cmd: &cobra.Command{}, @@ -154,10 +162,8 @@ func TestNutsGlobalConfig_RegisterFlags(t *testing.T) { }) } -func TestNutsGlobalConfig_InjectIntoEngine(t *testing.T) { - defer func() { - os.Args = []string{"command"} - }() +func TestNewNutsConfig_InjectIntoEngine(t *testing.T) { + defer reset() os.Args = []string{"command", "--key", "value"} cfg := NewNutsConfig() @@ -180,3 +186,32 @@ func TestNutsGlobalConfig_InjectIntoEngine(t *testing.T) { assert.Equal(t, "value", c.Key) }) } + +func TestNewNutsConfig_getConfigFile(t *testing.T) { + t.Run("uses configfile from cmd line param", func(t *testing.T) { + defer reset() + + os.Args = []string{"executable", "command", "--configfile", "from_file.yaml"} + cmd := &cobra.Command{} + cfg := NewNutsConfig() + cfg.Load(cmd) + + file := cfg.getConfigfile(cmd) + + assert.Equal(t, "from_file.yaml", file) + }) + + t.Run("uses configfile from env variable", func(t *testing.T) { + defer reset() + + os.Setenv("NUTS_CONFIGFILE", "from_env.yaml") + defer os.Unsetenv("NUTS_CONFIGFILE") + cmd := &cobra.Command{} + cfg := NewNutsConfig() + cfg.Load(cmd) + + file := cfg.getConfigfile(cmd) + + assert.Equal(t, "from_env.yaml", file) + }) +} \ No newline at end of file diff --git a/core/test/config/dummy.yaml b/core/test/config/dummy.yaml deleted file mode 100644 index f3333036f3..0000000000 --- a/core/test/config/dummy.yaml +++ /dev/null @@ -1,3 +0,0 @@ -key: value -keys: - - value \ No newline at end of file From 10ada8ed09d5cf1b63ac3a10f68ea75c09815636 Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 14:53:26 +0100 Subject: [PATCH 03/16] fix status cmd test by removing status engine Cmd --- core/status.go | 8 -------- core/status_test.go | 29 +++-------------------------- 2 files changed, 3 insertions(+), 34 deletions(-) diff --git a/core/status.go b/core/status.go index 92008e2754..ca8b627c3c 100644 --- a/core/status.go +++ b/core/status.go @@ -25,7 +25,6 @@ import ( "strings" "github.com/labstack/echo/v4" - "github.com/spf13/cobra" ) type status struct { @@ -39,13 +38,6 @@ func NewStatusEngine(system *System) *Engine { } return &Engine{ Name: "Status", - Cmd: &cobra.Command{ - Use: "diagnostics", - Short: "show engine diagnostics", - Run: func(cmd *cobra.Command, args []string) { - instance.diagnosticsSummaryAsText() - }, - }, Diagnosable: instance, Routes: func(router EchoRouter) { router.GET("/status/diagnostics", instance.diagnosticsOverview) diff --git a/core/status_test.go b/core/status_test.go index cae8bc5544..5aee32767b 100644 --- a/core/status_test.go +++ b/core/status_test.go @@ -1,13 +1,12 @@ package core import ( + "net/http" + "testing" + "github.com/golang/mock/gomock" "github.com/nuts-foundation/nuts-node/mock" "github.com/stretchr/testify/assert" - "io/ioutil" - "net/http" - "os" - "testing" ) func TestNewStatusEngine_Routes(t *testing.T) { @@ -23,28 +22,6 @@ func TestNewStatusEngine_Routes(t *testing.T) { }) } -func TestNewStatusEngine_Cmd(t *testing.T) { - system := NewSystem() - t.Run("Cmd returns a cobra command", func(t *testing.T) { - e := NewStatusEngine(system).Cmd - assert.Equal(t, "diagnostics", e.Name()) - }) - - t.Run("Executed Cmd writes diagnostics to prompt", func(t *testing.T) { - rescueStdout := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w - - NewStatusEngine(system).Cmd.Execute() - - w.Close() - out, _ := ioutil.ReadAll(r) - os.Stdout = rescueStdout - - assert.Equal(t, "", string(out)) - }) -} - func TestNewStatusEngine_Diagnostics(t *testing.T) { system := NewSystem() system.RegisterEngine(NewStatusEngine(system)) From 1cfc0c499352976415d57d00343e972f369223ab Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 14:57:35 +0100 Subject: [PATCH 04/16] test for new config command --- cmd/root.go | 3 ++- cmd/root_test.go | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/cmd/root.go b/cmd/root.go index 60e4132725..b41b6d3fb4 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -57,6 +57,7 @@ func createPrintConfigCommand(system *core.System) *cobra.Command { Use: "config", Short: "Prints the current config", Run: func(cmd *cobra.Command, args []string) { + cmd.Println("Current system config") cmd.Println(system.Config.PrintConfig()) }, } @@ -68,7 +69,7 @@ func createServerCommand(system *core.System) *cobra.Command { Short: "Starts the Nuts server", Run: func(cmd *cobra.Command, args []string) { logrus.Info("Starting server with config:") - logrus.Println(system.Config.PrintConfig()) + logrus.Info(system.Config.PrintConfig()) // check config on all engines if err := system.Configure(); err != nil { diff --git a/cmd/root_test.go b/cmd/root_test.go index 15b5cf424c..d120554bff 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -24,6 +24,21 @@ func Test_rootCmd(t *testing.T) { actual := buf.String() assert.Contains(t, actual, "Available Commands") }) + + t.Run("config cmd prints config", func(t *testing.T) { + oldStdout := stdOutWriter + buf := new(bytes.Buffer) + stdOutWriter = buf + defer func() { + stdOutWriter = oldStdout + }() + os.Args = []string{"nuts", "config"} + Execute() + actual := buf.String() + assert.Contains(t, actual, "Current system config") + assert.Contains(t, actual, "address") + }) + t.Run("start in server mode", func(t *testing.T) { ctrl := gomock.NewController(t) echoServer := core.NewMockEchoServer(ctrl) From f8ad6aafaf4e314cd1d2ca714400659eee9078d3 Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 14:58:40 +0100 Subject: [PATCH 05/16] gofmt --- core/config.go | 1 - core/config_test.go | 2 +- core/status.go | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/config.go b/core/config.go index a4ad5bb1d6..aefbb5b16c 100644 --- a/core/config.go +++ b/core/config.go @@ -91,7 +91,6 @@ func (ngc *NutsGlobalConfig) Load(cmd *cobra.Command) (err error) { // errors can't occur for this provider _ = ngc.configMap.Load(posflag.Provider(cmd.PersistentFlags(), defaultDelimiter, ngc.configMap), nil) - // load into struct if err = ngc.configMap.Unmarshal("", ngc); err != nil { return diff --git a/core/config_test.go b/core/config_test.go index 4c3c8076cc..099ad55c3a 100644 --- a/core/config_test.go +++ b/core/config_test.go @@ -214,4 +214,4 @@ func TestNewNutsConfig_getConfigFile(t *testing.T) { assert.Equal(t, "from_env.yaml", file) }) -} \ No newline at end of file +} diff --git a/core/status.go b/core/status.go index ca8b627c3c..caf1706686 100644 --- a/core/status.go +++ b/core/status.go @@ -37,7 +37,7 @@ func NewStatusEngine(system *System) *Engine { system: system, } return &Engine{ - Name: "Status", + Name: "Status", Diagnosable: instance, Routes: func(router EchoRouter) { router.GET("/status/diagnostics", instance.diagnosticsOverview) From 6e84f773959bda5ce253a567fd7eb09fcd9b696a Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 15:00:13 +0100 Subject: [PATCH 06/16] add godoc --- core/config.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/config.go b/core/config.go index aefbb5b16c..f44770e7bd 100644 --- a/core/config.go +++ b/core/config.go @@ -52,6 +52,7 @@ type NutsGlobalConfig struct { configMap *koanf.Koanf } +// NewNutsConfig creates a new config with some defaults func NewNutsConfig() *NutsGlobalConfig { return &NutsGlobalConfig{ configMap: koanf.New(defaultDelimiter), @@ -61,7 +62,7 @@ func NewNutsConfig() *NutsGlobalConfig { } } -// load follows the load order of configfile, env vars and then commandline param +// Load follows the load order of configfile, env vars and then commandline param func (ngc *NutsGlobalConfig) Load(cmd *cobra.Command) (err error) { cmd.PersistentFlags().AddFlagSet(ngc.flagSet()) @@ -146,7 +147,7 @@ func (ngc *NutsGlobalConfig) PrintConfig() string { return ngc.configMap.Sprint() } -// InjectIntoEngine +// InjectIntoEngine takes the loaded config and sets the engine's config struct func (ngc *NutsGlobalConfig) InjectIntoEngine(e *Engine) error { // ignore if no target for injection if e.Config != nil { From b358236a2ac3af0fdbaf994125a85b4fd262daa5 Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 15:03:07 +0100 Subject: [PATCH 07/16] up coverage --- cmd/root_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/root_test.go b/cmd/root_test.go index d120554bff..974ad61281 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -60,3 +60,9 @@ func Test_rootCmd(t *testing.T) { Execute() }) } + +func Test_echoCreator(t *testing.T) { + t.Run("creates an echo server", func(t *testing.T) { + assert.NotNil(t, echoCreator()) + }) +} From 89b583b539f7cf86e302acaf542d83c88e0ce7c3 Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 15:09:38 +0100 Subject: [PATCH 08/16] move loading of config into engines to system --- cmd/root.go | 11 ----------- core/engine.go | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index b41b6d3fb4..4b5acb114b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -135,9 +135,6 @@ func Execute() { panic(err) } - // Load config into engines - injectConfig(system) - // blocking main call command.Execute() } @@ -152,14 +149,6 @@ func addSubCommands(system *core.System, root *cobra.Command) { root.AddCommand(createPrintConfigCommand(system)) } -func injectConfig(system *core.System) { - if err := system.VisitEnginesE(func(engine *core.Engine) error { - return system.Config.InjectIntoEngine(engine) - }); err != nil { - logrus.Fatal(err) - } -} - func addFlagSets(system *core.System, cmd *cobra.Command) { system.VisitEngines(func(engine *core.Engine) { system.Config.RegisterFlags(cmd, engine) diff --git a/core/engine.go b/core/engine.go index 26ccb715ce..efd93ff138 100644 --- a/core/engine.go +++ b/core/engine.go @@ -43,6 +43,24 @@ type System struct { Config *NutsGlobalConfig } +// Load loads the config and injects config values into engines +func (system *System) Load(cmd *cobra.Command) error { + if err := system.Config.Load(cmd); err != nil { + return err + } + + return system.injectConfig() +} + +func (system *System) injectConfig() error { + if err := system.VisitEnginesE(func(engine *Engine) error { + return system.Config.InjectIntoEngine(engine) + }); err != nil { + return err + } + return nil +} + // Diagnostics returns the compound diagnostics for all engines. func (system *System) Diagnostics() []DiagnosticResult { result := make([]DiagnosticResult, 0) From c793e732f7fe4552db24e2937730d9d128bed417 Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 15:22:38 +0100 Subject: [PATCH 09/16] added doc on param load ordering --- docs/pages/configuration/configuration.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/pages/configuration/configuration.rst b/docs/pages/configuration/configuration.rst index 1bedba6dbe..c95381e286 100644 --- a/docs/pages/configuration/configuration.rst +++ b/docs/pages/configuration/configuration.rst @@ -5,9 +5,7 @@ Nuts node config .. marker-for-readme -The Nuts-go library contains some configuration logic which allows for usage of configFiles, Environment variables and commandLine params transparently. -If a Nuts engine is added as Engine it'll automatically work for the given engine. It is also possible for an engine to add the capabilities on a standalone basis. -This allows for testing from within a repo. +The Nuts library contains some configuration logic which allows for usage of configFiles, Environment variables and commandLine params transparently. The parameters follow the following convention: ``$ nuts --parameter X`` is equal to ``$ NUTS_PARAMETER=X nuts`` is equal to ``parameter: X`` in a yaml file. @@ -32,6 +30,12 @@ Config parameters for engines are prepended by the ``engine.ConfigKey`` by defau is equal to ``$ nuts --engine.nested.parameter X`` is equal to ``$ NUTS_ENGINE_NESTED_PARAMETER=X nuts`` +Ordering +******** + +Command line parameters have the highest priority, then environment variables, then parameters from the configfile and lastly defaults. +The location of the configfile is determined by the environment variable ``NUTS_CONFIGFILE`` or the commandline parameter ``--configfile``. If both are missing the default location ``./nuts.yaml`` is used. + Options ******* From 22784a1c57b474634c73eb32f5cd17571bacb55d Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 15:24:45 +0100 Subject: [PATCH 10/16] updated README --- README.rst | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 4e773ce016..3fe7064f80 100644 --- a/README.rst +++ b/README.rst @@ -90,9 +90,7 @@ Requirements for running sphinx Configuration ************* -The Nuts-go library contains some configuration logic which allows for usage of configFiles, Environment variables and commandLine params transparently. -If a Nuts engine is added as Engine it'll automatically work for the given engine. It is also possible for an engine to add the capabilities on a standalone basis. -This allows for testing from within a repo. +The Nuts library contains some configuration logic which allows for usage of configFiles, Environment variables and commandLine params transparently. The parameters follow the following convention: ``$ nuts --parameter X`` is equal to ``$ NUTS_PARAMETER=X nuts`` is equal to ``parameter: X`` in a yaml file. @@ -117,6 +115,12 @@ Config parameters for engines are prepended by the ``engine.ConfigKey`` by defau is equal to ``$ nuts --engine.nested.parameter X`` is equal to ``$ NUTS_ENGINE_NESTED_PARAMETER=X nuts`` +Ordering +******** + +Command line parameters have the highest priority, then environment variables, then parameters from the configfile and lastly defaults. +The location of the configfile is determined by the environment variable ``NUTS_CONFIGFILE`` or the commandline parameter ``--configfile``. If both are missing the default location ``./nuts.yaml`` is used. + Options ******* @@ -129,8 +133,7 @@ Key Default Description ============================ ============== ================================================================================================================================================================================= **** address localhost:1323 Address and port the server will be listening to -configfile nuts.yaml Nuts config file -identity Vendor identity for the node, mandatory when running in server mode. Must be in the format: urn:oid:1.3.6.1.4.1.54851.4: +configfile Nuts config file strictmode false When set, insecure settings are forbidden. verbosity info Log level (trace, debug, info, warn, error) **Crypto** @@ -140,7 +143,7 @@ crypto.storage fs Storage to use, 'fs' for file syst network.advertHashesInterval 2000 Interval (in milliseconds) that specifies how often the node should broadcast its last hashes to other nodes. network.bootstrapNodes Space-separated list of bootstrap nodes (`:`) which the node initially connect to. network.certFile PEM file containing the server certificate for the gRPC server. Required when `enableTLS` is `true`. -network.certKeyFile PEM file containing the private key of the server certificate. Required when `enableTLS` is `true`. +network.certKeyFile PEM file containing the private key of the server certificate. Required when `network.enableTLS` is `true`. network.databaseFile network.db File path to the network database. network.enableTLS true Whether to enable TLS for inbound gRPC connections. If set to `true` (which is default) `certFile` and `certKeyFile` MUST be configured. network.grpcAddr \:5555 Local address for gRPC to listen on. If empty the gRPC server won't be started and other nodes will not be able to connect to this node (outbound connections can still be made). From f3b20364e8d194afae095df54eb31ad0a43d0b11 Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 15:38:41 +0100 Subject: [PATCH 11/16] extra test for engine --- core/engine.go | 7 ++----- core/engine_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/core/engine.go b/core/engine.go index efd93ff138..3b1b2468de 100644 --- a/core/engine.go +++ b/core/engine.go @@ -53,12 +53,9 @@ func (system *System) Load(cmd *cobra.Command) error { } func (system *System) injectConfig() error { - if err := system.VisitEnginesE(func(engine *Engine) error { + return system.VisitEnginesE(func(engine *Engine) error { return system.Config.InjectIntoEngine(engine) - }); err != nil { - return err - } - return nil + }) } // Diagnostics returns the compound diagnostics for all engines. diff --git a/core/engine_test.go b/core/engine_test.go index b7a9959d83..444489a13b 100644 --- a/core/engine_test.go +++ b/core/engine_test.go @@ -23,10 +23,13 @@ import ( "fmt" "github.com/golang/mock/gomock" "github.com/labstack/echo/v4" + "github.com/spf13/cobra" + "github.com/spf13/pflag" "github.com/stretchr/testify/assert" "io/ioutil" "net/http" "net/http/httptest" + "os" "testing" ) @@ -101,6 +104,33 @@ func TestSystem_RegisterEngine(t *testing.T) { }) } +func TestSystem_Load(t *testing.T) { + c := struct { + Key string `koanf:"key"` + }{} + e := &Engine{ + Cmd: &cobra.Command{}, + Config: &c, + FlagSet: &pflag.FlagSet{}, + } + ctl := System{ + engines: []*Engine{e}, + Config: NewNutsConfig(), + } + e.FlagSet.String("key", "", "") + os.Args = []string{"command", "--key", "value"} + ctl.Config.RegisterFlags(e.Cmd, e) + + t.Run("loads config without error", func(t *testing.T) { + assert.NoError(t, ctl.Load(e.Cmd)) + }) + + t.Run("calls inject into engine", func(t *testing.T) { + ctl.Load(e.Cmd) + assert.Equal(t, "value", c.Key) + }) +} + func TestDecodeURIPath(t *testing.T) { rawParam := "urn:oid:2.16.840.1.113883.2.4.6.1:87654321" encodedParam := "urn%3Aoid%3A2.16.840.1.113883.2.4.6.1%3A87654321" From 62af176c2cdf0961df33c6a97440b4f8f7f177e0 Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 15:39:28 +0100 Subject: [PATCH 12/16] gofmt --- core/engine_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/engine_test.go b/core/engine_test.go index 444489a13b..98eafd4623 100644 --- a/core/engine_test.go +++ b/core/engine_test.go @@ -115,7 +115,7 @@ func TestSystem_Load(t *testing.T) { } ctl := System{ engines: []*Engine{e}, - Config: NewNutsConfig(), + Config: NewNutsConfig(), } e.FlagSet.String("key", "", "") os.Args = []string{"command", "--key", "value"} From e7ab28f563349fa8f65489bf1e03c5df0b554750 Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Tue, 2 Feb 2021 16:16:16 +0100 Subject: [PATCH 13/16] PR review --- core/config.go | 7 ++++--- core/config_test.go | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/core/config.go b/core/config.go index f44770e7bd..3caa78eb8e 100644 --- a/core/config.go +++ b/core/config.go @@ -43,6 +43,7 @@ const addressFlag = "address" const defaultLogLevel = "info" const defaultAddress = "localhost:1323" const strictModeFlag = "strictmode" +const defaultStrictMode = false // NutsGlobalConfig has global settings. type NutsGlobalConfig struct { @@ -58,7 +59,7 @@ func NewNutsConfig() *NutsGlobalConfig { configMap: koanf.New(defaultDelimiter), Address: defaultAddress, Verbosity: defaultLogLevel, - Strictmode: false, + Strictmode: defaultStrictMode, } } @@ -135,10 +136,10 @@ func (ngc *NutsGlobalConfig) getConfigfile(cmd *cobra.Command) string { func (ngc *NutsGlobalConfig) flagSet() *pflag.FlagSet { flagSet := pflag.NewFlagSet("config", pflag.ContinueOnError) - flagSet.String(configFileFlag, "", "Nuts config file") + flagSet.String(configFileFlag, defaultConfigFile, "Nuts config file") flagSet.String(loggerLevelFlag, defaultLogLevel, "Log level (trace, debug, info, warn, error)") flagSet.String(addressFlag, defaultAddress, "Address and port the server will be listening to") - flagSet.Bool(strictModeFlag, false, "When set, insecure settings are forbidden.") + flagSet.Bool(strictModeFlag, defaultStrictMode, "When set, insecure settings are forbidden.") return flagSet } diff --git a/core/config_test.go b/core/config_test.go index 099ad55c3a..5a67ae60cc 100644 --- a/core/config_test.go +++ b/core/config_test.go @@ -45,7 +45,7 @@ func TestNewNutsConfig_Load(t *testing.T) { assert.Equal(t, defaultAddress, cfg.Address) assert.Equal(t, defaultLogLevel, cfg.Verbosity) - assert.Equal(t, false, cfg.Strictmode) + assert.Equal(t, defaultStrictMode, cfg.Strictmode) }) t.Run("Sets global Env prefix", func(t *testing.T) { From c9024b896eb784401032e04af872708feb98b40c Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Wed, 3 Feb 2021 13:36:23 +0100 Subject: [PATCH 14/16] fix test --- core/config.go | 21 ++++++++------------- core/config_test.go | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/core/config.go b/core/config.go index 3caa78eb8e..bf8dc02b95 100644 --- a/core/config.go +++ b/core/config.go @@ -110,16 +110,6 @@ func (ngc *NutsGlobalConfig) Load(cmd *cobra.Command) (err error) { func (ngc *NutsGlobalConfig) getConfigfile(cmd *cobra.Command) string { k := koanf.New(defaultDelimiter) - if len(os.Args) > 1 { - _ = cmd.PersistentFlags().Parse(os.Args[1:]) - } - - // load cmd flags, without a parser, no error can be returned - _ = k.Load(posflag.Provider(cmd.PersistentFlags(), defaultDelimiter, k), nil) - if f := k.String(configFileFlag); f != "" { - return f - } - // load env flags e := env.Provider(defaultPrefix, defaultDelimiter, func(s string) string { return strings.Replace(strings.ToLower( @@ -127,11 +117,16 @@ func (ngc *NutsGlobalConfig) getConfigfile(cmd *cobra.Command) string { }) // can't return error _ = k.Load(e, nil) - if f := k.String(configFileFlag); f != "" { - return f + + if len(os.Args) > 1 { + _ = cmd.PersistentFlags().Parse(os.Args[1:]) } - return defaultConfigFile + // load cmd flags, without a parser, no error can be returned + // this also loads the default flag value of nuts.yaml. So we need a way to know if it's overiden. + _ = k.Load(posflag.Provider(cmd.PersistentFlags(), defaultDelimiter, k), nil) + + return k.String(configFileFlag) } func (ngc *NutsGlobalConfig) flagSet() *pflag.FlagSet { diff --git a/core/config_test.go b/core/config_test.go index 5a67ae60cc..0b2953a17a 100644 --- a/core/config_test.go +++ b/core/config_test.go @@ -126,6 +126,22 @@ func TestNewNutsConfig_Load(t *testing.T) { return } }) + + t.Run("ok - env overrides default flag", func(t *testing.T) { + defer reset() + os.Args = []string{"command", "some", "args"} + os.Setenv("NUTS_VERBOSITY", "warn") + defer os.Unsetenv("NUTS_VERBOSITY") + cfg := NewNutsConfig() + + err := cfg.Load(&cobra.Command{}) + + if !assert.NoError(t, err) { + return + } + + assert.Equal(t, "warn", cfg.Verbosity) + }) } func TestNewNutsConfig_PrintConfig(t *testing.T) { From 935033ecd6009baa8e218912ccca5b65a32cfe6d Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Thu, 4 Feb 2021 13:10:58 +0100 Subject: [PATCH 15/16] set log lvl --- core/config.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/config.go b/core/config.go index bf8dc02b95..8d9acb01f3 100644 --- a/core/config.go +++ b/core/config.go @@ -98,11 +98,14 @@ func (ngc *NutsGlobalConfig) Load(cmd *cobra.Command) (err error) { return } + var lvl log.Level // initialize logger, verbosity flag needs to be available - if _, err = log.ParseLevel(ngc.Verbosity); err != nil { + if lvl, err = log.ParseLevel(ngc.Verbosity); err != nil { return } + log.SetLevel(lvl) + return } From 2e7478da5f60cc5744a3228f1cffbde15cc51c21 Mon Sep 17 00:00:00 2001 From: Wout Slakhorst Date: Thu, 4 Feb 2021 13:12:03 +0100 Subject: [PATCH 16/16] add log todo --- core/config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/config.go b/core/config.go index 8d9acb01f3..f6c408ee09 100644 --- a/core/config.go +++ b/core/config.go @@ -104,6 +104,7 @@ func (ngc *NutsGlobalConfig) Load(cmd *cobra.Command) (err error) { return } + // todo, see #40 log.SetLevel(lvl) return