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). diff --git a/cmd/root.go b/cmd/root.go index 1220c94002..4b5acb114b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -52,11 +52,25 @@ 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("Current system config") + 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.Info(system.Config.PrintConfig()) + // check config on all engines if err := system.Configure(); err != nil { logrus.Fatal(err) @@ -67,7 +81,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 +94,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 +106,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,18 +130,11 @@ 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()) - // blocking main call command.Execute() } @@ -140,18 +146,11 @@ func addSubCommands(system *core.System, root *cobra.Command) { } }) root.AddCommand(createServerCommand(system)) + root.AddCommand(createPrintConfigCommand(system)) } -func injectConfig(system *core.System, cfg *core.NutsGlobalConfig) { - if err := system.VisitEnginesE(func(engine *core.Engine) error { - return cfg.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/cmd/root_test.go b/cmd/root_test.go index 15b5cf424c..974ad61281 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) @@ -45,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()) + }) +} diff --git a/core/config.go b/core/config.go index fc83791533..f6c408ee09 100644 --- a/core/config.go +++ b/core/config.go @@ -21,21 +21,21 @@ 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" 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 +43,124 @@ 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 } -// NewNutsGlobalConfig creates a NutsGlobalConfig with the following defaults -// * Prefix: NUTS -// * Delimiter: '.' -// * IgnoredPrefixes: ["root","logging"] -func NewNutsGlobalConfig() *NutsGlobalConfig { +// NewNutsConfig creates a new config with some defaults +func NewNutsConfig() *NutsGlobalConfig { return &NutsGlobalConfig{ - DefaultConfigFile: defaultConfigFile, - Prefix: defaultPrefix, - Delimiter: defaultSeparator, - IgnoredPrefixes: defaultIgnoredPrefixes, - v: viper.New(), + configMap: koanf.New(defaultDelimiter), + Address: defaultAddress, + Verbosity: defaultLogLevel, + Strictmode: defaultStrictMode, } } -var configOnce sync.Once -var configInstance *NutsGlobalConfig - -// NutsGlobalConfig returns a singleton global config -func NutsConfig() *NutsGlobalConfig { - configOnce.Do(func() { - configInstance = NewNutsGlobalConfig() - }) - return configInstance -} +// 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()) -// 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) -} + ngc.configMap = koanf.New(defaultDelimiter) + f := ngc.getConfigfile(cmd) -// 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 file + p := file.Provider(f) + if err = ngc.configMap.Load(p, yaml.Parser()); err != nil { + if !errors.Is(err, os.ErrNotExist) { + return + } + } - // 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) + // 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 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 - } + // 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 configFile into viper - if err := ngc.loadConfigFile(); err != nil { - return err + // load into struct + if err = ngc.configMap.Unmarshal("", ngc); err != nil { + return } + var lvl log.Level // initialize logger, verbosity flag needs to be available - level, err := log.ParseLevel(ngc.v.GetString(loggerLevelFlag)) - if err != nil { - return err + if lvl, err = log.ParseLevel(ngc.Verbosity); err != nil { + return } - log.SetLevel(level) - return nil -} + // todo, see #40 + log.SetLevel(lvl) -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 + return } -// 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) - } - }) - } - }) +// getConfigfile returns the configfile path in the following order: commandline param, env variable, default path +func (ngc *NutsGlobalConfig) getConfigfile(cmd *cobra.Command) string { + k := koanf.New(defaultDelimiter) - 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 + // load env flags + e := env.Provider(defaultPrefix, defaultDelimiter, func(s string) string { + return strings.Replace(strings.ToLower( + strings.TrimPrefix(s, defaultPrefix)), "_", defaultDelimiter, -1) + }) + // can't return error + _ = k.Load(e, nil) - logger.Infoln(stars) - logger.Infof("%s %s %s", strings.Repeat("*", sideStarsLeft), title, strings.Repeat("*", sideStarsRight)) + if len(os.Args) > 1 { + _ = cmd.PersistentFlags().Parse(os.Args[1:]) + } - f := fmt.Sprintf("%%-%ds%%v", 7+longestKey) + // 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) - 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))) - }) - } - }) - logger.Infoln(stars) + return k.String(configFileFlag) } -// 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) +func (ngc *NutsGlobalConfig) flagSet() *pflag.FlagSet { + flagSet := pflag.NewFlagSet("config", pflag.ContinueOnError) + 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, defaultStrictMode, "When set, insecure settings are forbidden.") + return flagSet +} - // 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 - } - } - return err +// PrintConfig return the current config in string form +func (ngc *NutsGlobalConfig) PrintConfig() string { + return ngc.configMap.Sprint() } -// 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. +// InjectIntoEngine takes the loaded config and sets the engine's config struct 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) - }) - } + return ngc.configMap.Unmarshal(e.ConfigKey, e.Config) } - 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) - } - - // inject value - field.Set(reflect.ValueOf(ngc.v.Get(configName))) - } - return err + return nil } // 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) - } - - // 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 - } - } - 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 - } - - 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 - } - } - - // check if flag name already starts with prefix - if strings.Index(f.Name, e.ConfigKey) == 0 { - return f.Name - } - - // add prefix - return fmt.Sprintf("%s%s%s", e.ConfigKey, ngc.Delimiter, f.Name) -} - -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 -} - -// 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) -} - -// 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 + cmd.PersistentFlags().AddFlagSet(e.FlagSet) } - - s := cfgP.Elem() - if !s.CanSet() { - return nil, ErrUnMutableConfigTarget - } - - spl := strings.Split(configName, ngc.Delimiter) - - return ngc.findFieldRecursive(&s, spl) -} - -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) - } - - return &field, nil } diff --git a/core/config_test.go b/core/config_test.go index e331bec705..0b2953a17a 100644 --- a/core/config_test.go +++ b/core/config_test.go @@ -20,616 +20,214 @@ 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) - } +var reset = func() { + os.Args = []string{"command"} + os.Args = []string{} +} - if c.Delimiter != defaultSeparator { - t.Errorf("Expected Prefix to be [%s], got [%s]", defaultSeparator, c.Delimiter) - } +func TestNewNutsConfig_Load(t *testing.T) { + t.Run("sets defaults", func(t *testing.T) { + cfg := NewNutsConfig() - if !reflect.DeepEqual(c.IgnoredPrefixes, defaultIgnoredPrefixes) { - t.Errorf("Expected Prefix to be [%s], got [%s]", defaultIgnoredPrefixes, c.IgnoredPrefixes) + err := cfg.Load(&cobra.Command{}) + if !assert.NoError(t, err) { + return } - }) -} -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") - } + assert.Equal(t, defaultAddress, cfg.Address) + assert.Equal(t, defaultLogLevel, cfg.Verbosity) + assert.Equal(t, defaultStrictMode, cfg.Strictmode) }) -} - -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" { + defer os.Unsetenv("NUTS_KEY") + + 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) - } - }) + defer os.Unsetenv("NUTS_SUB_KEY") + + cfg.Load(&cobra.Command{}) - 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) + if value := cfg.configMap.Get("sub.key"); value != "value" { + 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 := 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 - } - }) - - t.Run("Ignores --help as incorrect argument", func(t *testing.T) { - os.Args = []string{"command", "--help"} - cfg := NewNutsGlobalConfig() - - if err := cfg.Load(&cobra.Command{}); err != nil { - t.Errorf("Expected no error, got %v", err) - } + assert.NoError(t, err) }) t.Run("Returns error for incorrect verbosity", func(t *testing.T) { + defer reset() 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) { + defer reset() 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) { + defer reset() os.Args = []string{"command", "--strictmode"} - cfg := NewNutsGlobalConfig() - err := cfg.Load(&cobra.Command{}) - assert.NoError(t, err) - assert.True(t, cfg.InStrictMode()) - }) -} - -func TestNutsGlobalConfig_PrintConfig(t *testing.T) { - cfg := NewNutsGlobalConfig() - 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() + cfg := NewNutsConfig() - 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) { - e := &Engine{ - Cmd: &cobra.Command{}, - ConfigKey: "pre", - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.String("key", "", "") - - cfg := NewNutsGlobalConfig() - cfg.RegisterFlags(e.Cmd, e) - - 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.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()) - } + err := cfg.Load(&cobra.Command{}) - if s.Key != "value" { - t.Errorf("Expected value for key in struct to equal [value], got %s", s.Key) - } + assert.NoError(t, err) + assert.True(t, cfg.Strictmode) }) - 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 - } + t.Run("error - incorrect yaml", func(t *testing.T) { + defer reset() + os.Args = []string{"command", "--configfile", "test/config/corrupt.yaml"} + cfg := NewNutsConfig() - assert.Contains(t, err.Error(), "only struct pointers are supported to be a config target") - }) + err := cfg.Load(&cobra.Command{}) - 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") + if !assert.Error(t, err) { 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) + 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() - 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) + err := cfg.Load(&cobra.Command{}) - if err == nil { - t.Errorf("Expected error, got nothing") + if !assert.NoError(t, err) { return } - assert.Contains(t, err.Error(), "problem injecting [key]: inaccessible or invalid field [Key] in struct") + assert.Equal(t, "warn", cfg.Verbosity) }) +} - t.Run("returns error on incorrect argument", func(t *testing.T) { - os.Args = []string{"command", "---"} - cfg := NewNutsGlobalConfig() - s := struct{}{} +func TestNewNutsConfig_PrintConfig(t *testing.T) { + cfg := NewNutsConfig() + fs := pflag.FlagSet{} + fs.String("camelCaseKey", "value", "description") + cmd := &cobra.Command{} + cmd.PersistentFlags().AddFlagSet(&fs) + cfg.Load(cmd) - err := cfg.LoadAndUnmarshal(&cobra.Command{}, &s) + bs := cfg.PrintConfig() - if err == nil { - t.Error("Expected error, got nothing") - return + t.Run("output contains key", func(t *testing.T) { + if strings.Index(bs, "camelCaseKey") == -1 { + t.Error("Expected camelCaseKey to be in output") } }) } -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 - }{} - +func TestNewNutsConfig_RegisterFlags(t *testing.T) { + t.Run("adds flags", func(t *testing.T) { e := &Engine{ - Config: &c, + Cmd: &cobra.Command{}, 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"}) + assert.False(t, e.Cmd.PersistentFlags().HasAvailableFlags()) - 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()) - } + cfg := NewNutsConfig() + cfg.RegisterFlags(e.Cmd, e) - if c.Nested.Key != "value" { - t.Errorf("Expected value to be injected into struct") - } + assert.True(t, e.Cmd.PersistentFlags().HasAvailableFlags()) }) +} - 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()) - } +func TestNewNutsConfig_InjectIntoEngine(t *testing.T) { + defer reset() - if c.Nested.Key != "value" { - t.Errorf("Expected value to be injected into struct") - } - }) + os.Args = []string{"command", "--key", "value"} + cfg := NewNutsConfig() - t.Run("returns error for inaccessible key in struct", func(t *testing.T) { + t.Run("param is injected", func(t *testing.T) { c := struct { - key string + Key string `koanf:"key"` }{} - e := &Engine{ - Name: "test", Config: &c, + Cmd: &cobra.Command{}, FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), } - e.FlagSet.String("key", "", "") + e.FlagSet.String("key", "", "test") - 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 [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()) - } + assert.Equal(t, "value", c.Key) }) +} - t.Run("returns error on missing default", func(t *testing.T) { - c := struct { - Nested struct{ Key string } - }{} +func TestNewNutsConfig_getConfigFile(t *testing.T) { + t.Run("uses configfile from cmd line param", func(t *testing.T) { + defer reset() - e := &Engine{ - Config: &c, - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.String("nested.key", "", "") - - cfg.v.Set("nested", "value") + os.Args = []string{"executable", "command", "--configfile", "from_file.yaml"} + cmd := &cobra.Command{} + cfg := NewNutsConfig() + cfg.Load(cmd) - err := cfg.InjectIntoEngine(e) - if err == nil { - t.Errorf("Expected error, got nothing") - } + file := cfg.getConfigfile(cmd) - 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()) - } + assert.Equal(t, "from_file.yaml", file) }) - t.Run("returns error on wrong nesting", func(t *testing.T) { - c := struct { - Nested string - }{} + t.Run("uses configfile from env variable", func(t *testing.T) { + defer reset() - e := &Engine{ - Config: &c, - FlagSet: pflag.NewFlagSet("dummy", pflag.ContinueOnError), - } - e.FlagSet.String("nested.key", "", "") + os.Setenv("NUTS_CONFIGFILE", "from_env.yaml") + defer os.Unsetenv("NUTS_CONFIGFILE") + cmd := &cobra.Command{} + cfg := NewNutsConfig() + cfg.Load(cmd) - cfg.v.Set("nested.key", "value") + file := cfg.getConfigfile(cmd) - err := cfg.InjectIntoEngine(e) - if err == nil { - t.Errorf("Expected error, got nothing") - } - - 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, "from_env.yaml", file) }) } diff --git a/core/engine.go b/core/engine.go index b184180851..3b1b2468de 100644 --- a/core/engine.go +++ b/core/engine.go @@ -29,13 +29,33 @@ 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 +} + +// 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 { + return system.VisitEnginesE(func(engine *Engine) error { + return system.Config.InjectIntoEngine(engine) + }) } // Diagnostics returns the compound diagnostics for all engines. diff --git a/core/engine_test.go b/core/engine_test.go index b7a9959d83..98eafd4623 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" diff --git a/core/status.go b/core/status.go index 92008e2754..caf1706686 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 { @@ -38,14 +37,7 @@ func NewStatusEngine(system *System) *Engine { system: system, } return &Engine{ - Name: "Status", - Cmd: &cobra.Command{ - Use: "diagnostics", - Short: "show engine diagnostics", - Run: func(cmd *cobra.Command, args []string) { - instance.diagnosticsSummaryAsText() - }, - }, + Name: "Status", 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)) 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 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/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 ******* 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) }) }