Skip to content

Commit

Permalink
Add string slice config support
Browse files Browse the repository at this point in the history
When overriding a configuration option via the env which is supposed
to be a collection collection (slice) of options, the override is
instead interpretted as a string.  This patch modifies the config
decode hook to handle this special case and appropriately decode the env
override to a []string instead of a plain string.

There is no JIRA issue associated with this, but is being done to
support the Kafka epic effort, visible here:

https://jira.hyperledger.org/browse/FAB-32

Reclaim commit after a little Gerrit accident

Change-Id: Iae800b5237549232b90c7d7cf91590a3d8caf178
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Oct 5, 2016
1 parent 60e4e45 commit f6caa7b
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 1 deletion.
42 changes: 42 additions & 0 deletions orderer/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ limitations under the License.
package config

import (
"bytes"
"fmt"
"os"
"reflect"
"strings"
"testing"

"github.com/spf13/viper"
Expand Down Expand Up @@ -50,6 +53,45 @@ func TestBadConfig(t *testing.T) {
}
}

type testSlice struct {
Inner struct {
Slice []string
}
}

func TestEnvSlice(t *testing.T) {
envVar := "ORDERER_INNER_SLICE"
envVal := "[a, b, c]"
os.Setenv(envVar, envVal)
defer os.Unsetenv(envVar)
config := viper.New()
config.SetEnvPrefix(Prefix)
config.AutomaticEnv()
replacer := strings.NewReplacer(".", "_")
config.SetEnvKeyReplacer(replacer)
config.SetConfigType("yaml")

data := "---\nInner:\n Slice: [d,e,f]"

err := config.ReadConfig(bytes.NewReader([]byte(data)))

if err != nil {
t.Fatalf("Error reading %s plugin config: %s", Prefix, err)
}

var uconf testSlice

err = ExactWithDateUnmarshal(config, &uconf)
if err != nil {
t.Fatalf("Failed to unmarshal with: %s", err)
}

expected := []string{"a", "b", "c"}
if !reflect.DeepEqual(uconf.Inner.Slice, expected) {
t.Fatalf("Did not get back the right slice, expeced: %v got %v", expected, uconf.Inner.Slice)
}
}

// TestEnvInnerVar verifies that with the Unmarshal function that
// the environmental overrides still work on internal vars. This was
// a bug in the original viper implementation that is worked around in
Expand Down
37 changes: 36 additions & 1 deletion orderer/config/config_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ limitations under the License.
package config

import (
"reflect"
"strings"
"time"

"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
)
Expand Down Expand Up @@ -45,6 +49,37 @@ func getKeysRecursively(base string, v *viper.Viper, nodeKeys map[string]interfa
return result
}

// customDecodeHook adds the additional functions of parsing durations from strings
// as well as parsing strings of the format "[thing1, thing2, thing3]" into string slices
// Note that whitespace around slice elements is removed
func customDecodeHook() mapstructure.DecodeHookFunc {
durationHook := mapstructure.StringToTimeDurationHookFunc()
return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
dur, err := mapstructure.DecodeHookExec(durationHook, f, t, data)
if err == nil {
if _, ok := dur.(time.Duration); ok {
return dur, nil
}
}

if f.Kind() != reflect.String {
return data, nil
}

raw := data.(string)
l := len(raw)
if raw[0] == '[' && raw[l-1] == ']' {
slice := strings.Split(raw[1:l-1], ",")
for i, v := range slice {
slice[i] = strings.TrimSpace(v)
}
return slice, nil
}

return data, nil
}
}

// ExactWithDateUnmarshal is intended to unmarshal a config file into a structure
// producing error when extraneous variables are introduced and supporting
// the time.Duration type
Expand All @@ -58,7 +93,7 @@ func ExactWithDateUnmarshal(v *viper.Viper, output interface{}) error {
Metadata: nil,
Result: output,
WeaklyTypedInput: true,
DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
DecodeHook: customDecodeHook(),
}

decoder, err := mapstructure.NewDecoder(config)
Expand Down

0 comments on commit f6caa7b

Please sign in to comment.