Merge pull request #3746 from hashicorp/node-meta-merge

Changes maps to merge vs. overwrite when processing configs.
This commit is contained in:
James Phillips 2017-12-13 20:55:03 -08:00 committed by GitHub
commit 3dc3ba8d37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 23 additions and 12 deletions

View File

@ -40,7 +40,8 @@ import (
// //
// The config sources are merged sequentially and later values // The config sources are merged sequentially and later values
// overwrite previously set values. Slice values are merged by // overwrite previously set values. Slice values are merged by
// concatenating the two slices. // concatenating the two slices. Map values are merged by over-
// laying the later maps on top of earlier ones.
// //
// Then call Validate() to perform the semantic validation to ensure // Then call Validate() to perform the semantic validation to ensure
// that the configuration is ready to be used. // that the configuration is ready to be used.

View File

@ -11,7 +11,7 @@ import (
// * only values of type struct, slice, map and pointer to simple types are allowed. Other types panic. // * only values of type struct, slice, map and pointer to simple types are allowed. Other types panic.
// * when merging two structs the result is the recursive merge of all fields according to the rules below // * when merging two structs the result is the recursive merge of all fields according to the rules below
// * when merging two slices the result is the second slice appended to the first // * when merging two slices the result is the second slice appended to the first
// * when merging two maps the result is the second map if it is not empty, otherwise the first // * when merging two maps the result is the second map overlaid on the first
// * when merging two pointer values the result is the second value if it is not nil, otherwise the first // * when merging two pointer values the result is the second value if it is not nil, otherwise the first
func Merge(files ...Config) Config { func Merge(files ...Config) Config {
var a Config var a Config
@ -28,10 +28,16 @@ func merge(a, b interface{}) interface{} {
func mergeValue(a, b reflect.Value) reflect.Value { func mergeValue(a, b reflect.Value) reflect.Value {
switch a.Kind() { switch a.Kind() {
case reflect.Map: case reflect.Map:
if b.Len() > 0 { r := reflect.MakeMap(a.Type())
return b for _, k := range a.MapKeys() {
v := a.MapIndex(k)
r.SetMapIndex(k, v)
} }
return a for _, k := range b.MapKeys() {
v := b.MapIndex(k)
r.SetMapIndex(k, v)
}
return r
case reflect.Ptr: case reflect.Ptr:
if !b.IsNil() { if !b.IsNil() {

View File

@ -26,6 +26,7 @@ func TestMerge(t *testing.T) {
{StartJoinAddrsLAN: []string{"b"}}, {StartJoinAddrsLAN: []string{"b"}},
{NodeMeta: map[string]string{"a": "b"}}, {NodeMeta: map[string]string{"a": "b"}},
{NodeMeta: map[string]string{"c": "d"}}, {NodeMeta: map[string]string{"c": "d"}},
{NodeMeta: map[string]string{"c": "e"}},
{Ports: Ports{DNS: pInt(1)}}, {Ports: Ports{DNS: pInt(1)}},
{Ports: Ports{DNS: pInt(2), HTTP: pInt(3)}}, {Ports: Ports{DNS: pInt(2), HTTP: pInt(3)}},
}, },
@ -34,8 +35,11 @@ func TestMerge(t *testing.T) {
RaftProtocol: pInt(2), RaftProtocol: pInt(2),
ServerMode: pBool(true), ServerMode: pBool(true),
StartJoinAddrsLAN: []string{"a", "b"}, StartJoinAddrsLAN: []string{"a", "b"},
NodeMeta: map[string]string{"c": "d"}, NodeMeta: map[string]string{
Ports: Ports{DNS: pInt(2), HTTP: pInt(3)}, "a": "b",
"c": "e",
},
Ports: Ports{DNS: pInt(2), HTTP: pInt(3)},
}, },
}, },
} }

View File

@ -1115,7 +1115,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
"bootstrap_expect": 0, "bootstrap_expect": 0,
"datacenter":"b", "datacenter":"b",
"start_join": ["c", "d"], "start_join": ["c", "d"],
"node_meta": {"c":"d"} "node_meta": {"a":"c"}
}`, }`,
}, },
hcl: []string{ hcl: []string{
@ -1131,7 +1131,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
bootstrap_expect = 0 bootstrap_expect = 0
datacenter = "b" datacenter = "b"
start_join = ["c", "d"] start_join = ["c", "d"]
node_meta = { "c" = "d" } node_meta = { "a" = "c" }
`, `,
}, },
patch: func(rt *RuntimeConfig) { patch: func(rt *RuntimeConfig) {
@ -1139,7 +1139,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
rt.BootstrapExpect = 0 rt.BootstrapExpect = 0
rt.Datacenter = "b" rt.Datacenter = "b"
rt.StartJoinAddrsLAN = []string{"a", "b", "c", "d"} rt.StartJoinAddrsLAN = []string{"a", "b", "c", "d"}
rt.NodeMeta = map[string]string{"c": "d"} rt.NodeMeta = map[string]string{"a": "c"}
rt.DataDir = dataDir rt.DataDir = dataDir
}, },
}, },
@ -1181,7 +1181,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
`-datacenter=b`, `-datacenter=b`,
`-data-dir=` + dataDir, `-data-dir=` + dataDir,
`-join`, `c`, `-join=d`, `-join`, `c`, `-join=d`,
`-node-meta=c:d`, `-node-meta=a:c`,
`-recursor`, `1.2.3.6`, `-recursor=5.6.7.10`, `-recursor`, `1.2.3.6`, `-recursor=5.6.7.10`,
`-serf-lan-bind=3.3.3.3`, `-serf-lan-bind=3.3.3.3`,
`-serf-wan-bind=4.4.4.4`, `-serf-wan-bind=4.4.4.4`,
@ -1194,7 +1194,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
rt.SerfAdvertiseAddrWAN = tcpAddr("2.2.2.2:8302") rt.SerfAdvertiseAddrWAN = tcpAddr("2.2.2.2:8302")
rt.Datacenter = "b" rt.Datacenter = "b"
rt.DNSRecursors = []string{"1.2.3.6", "5.6.7.10", "1.2.3.5", "5.6.7.9"} rt.DNSRecursors = []string{"1.2.3.6", "5.6.7.10", "1.2.3.5", "5.6.7.9"}
rt.NodeMeta = map[string]string{"c": "d"} rt.NodeMeta = map[string]string{"a": "c"}
rt.SerfBindAddrLAN = tcpAddr("3.3.3.3:8301") rt.SerfBindAddrLAN = tcpAddr("3.3.3.3:8301")
rt.SerfBindAddrWAN = tcpAddr("4.4.4.4:8302") rt.SerfBindAddrWAN = tcpAddr("4.4.4.4:8302")
rt.StartJoinAddrsLAN = []string{"c", "d", "a", "b"} rt.StartJoinAddrsLAN = []string{"c", "d", "a", "b"}