diff --git a/cmd/neofs-node/config/calls.go b/cmd/neofs-node/config/calls.go index 4f15351d..d8720d5f 100644 --- a/cmd/neofs-node/config/calls.go +++ b/cmd/neofs-node/config/calls.go @@ -15,9 +15,19 @@ func (x *Config) Sub(name string) *Config { copy(path, x.path) + var defaultPath []string + if x.defaultPath != nil { + ln := len(x.defaultPath) + defaultPath = make([]string, ln, ln+1) + copy(defaultPath, x.defaultPath) + } + + copy(path, x.path) + return &Config{ - v: x.v, - path: append(path, name), + v: x.v, + path: append(path, name), + defaultPath: append(defaultPath, name), } } @@ -30,5 +40,18 @@ func (x *Config) Sub(name string) *Config { // // Returns nil if config is nil. func (x *Config) Value(name string) interface{} { - return x.v.Get(strings.Join(append(x.path, name), separator)) + value := x.v.Get(strings.Join(append(x.path, name), separator)) + if value != nil || x.defaultPath == nil { + return value + } + return x.v.Get(strings.Join(append(x.defaultPath, name), separator)) +} + +// SetDefault sets fallback config for missing values. +// +// It supports only one level of nesting and is intended to be used +// to provide default values. +func (x *Config) SetDefault(from *Config) { + x.defaultPath = make([]string, len(from.path)) + copy(x.defaultPath, from.path) } diff --git a/cmd/neofs-node/config/calls_test.go b/cmd/neofs-node/config/calls_test.go index 52425ab7..20dd8007 100644 --- a/cmd/neofs-node/config/calls_test.go +++ b/cmd/neofs-node/config/calls_test.go @@ -60,3 +60,20 @@ func TestConfig_SubValue(t *testing.T) { require.Equal(t, "val1", sub.Value("key")) }) } + +func TestConfig_SetDefault(t *testing.T) { + configtest.ForEachFileType("test/config", func(c *config.Config) { + c = c.Sub("with_default") + s := c.Sub("custom") + s.SetDefault(c.Sub("default")) + + require.Equal(t, int64(42), config.Int(s, "missing")) + require.Equal(t, "b", config.String(s, "overridden")) + require.Equal(t, false, config.Bool(s, "overridden_with_default")) + + // Default can be set only once. + s = s.Sub("sub") + require.Equal(t, int64(123), config.Int(s, "missing")) + require.Equal(t, "y", config.String(s, "overridden")) + }) +} diff --git a/cmd/neofs-node/config/config.go b/cmd/neofs-node/config/config.go index dd5e0359..609cef11 100644 --- a/cmd/neofs-node/config/config.go +++ b/cmd/neofs-node/config/config.go @@ -17,7 +17,8 @@ import ( type Config struct { v *viper.Viper - path []string + defaultPath []string + path []string } const separator = "." diff --git a/cmd/neofs-node/config/test/config.json b/cmd/neofs-node/config/test/config.json index 4c1c0caf..e1f1da78 100644 --- a/cmd/neofs-node/config/test/config.json +++ b/cmd/neofs-node/config/test/config.json @@ -56,5 +56,24 @@ "size_tb": "5 TB", "size_bytes": "2048b", "size_bytes_no_suffix": 123456 + }, + + "with_default": { + "default": { + "sub": { + "missing": 123, + "overridden": "x" + }, + "missing": 42, + "overridden": "a", + "overridden_with_default": true + }, + "custom": { + "sub": { + "overridden": "y" + }, + "overridden": "b", + "overridden_with_default": false + } } } diff --git a/cmd/neofs-node/config/test/config.yaml b/cmd/neofs-node/config/test/config.yaml index 062bed4d..e2e6d3aa 100644 --- a/cmd/neofs-node/config/test/config.yaml +++ b/cmd/neofs-node/config/test/config.yaml @@ -49,3 +49,17 @@ sizes: size_tb: 5 TB size_bytes: 2048b size_bytes_no_suffix: 123456 + +with_default: + default: + sub: + missing: 123 + overridden: "x" + missing: 42 + overridden: "a" + overridden_with_default: true + custom: + sub: + overridden: "y" + overridden: "b" + overridden_with_default: false