a97d20cf63
Many places in consul already treated node names case insensitively. The state store indexes already do it, but there are a few places that did a direct byte comparison which have now been corrected. One place of particular consideration is ensureCheckIfNodeMatches which is executed during snapshot restore (among other places). If a node check used a slightly different casing than the casing of the node during register then the snapshot restore here would deterministically fail. This has been fixed. Primary approach: git grep -i "node.*[!=]=.*node" -- ':!*_test.go' ':!docs' git grep -i '\[[^]]*member[^]]*\] git grep -i '\[[^]]*\(member\|name\|node\)[^]]*\]' -- ':!*_test.go' ':!website' ':!ui' ':!agent/proxycfg/testing.go:' ':!*.md'
289 lines
5.9 KiB
Go
289 lines
5.9 KiB
Go
package consul
|
|
|
|
import (
|
|
"testing"
|
|
|
|
uuid "github.com/hashicorp/go-uuid"
|
|
"github.com/hashicorp/serf/serf"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/hashicorp/consul/sdk/testutil"
|
|
"github.com/hashicorp/consul/types"
|
|
)
|
|
|
|
func TestMerge_LAN(t *testing.T) {
|
|
type testcase struct {
|
|
members []*serf.Member
|
|
expect string
|
|
}
|
|
|
|
const thisNodeID = "ee954a2f-80de-4b34-8780-97b942a50a99"
|
|
|
|
run := func(t *testing.T, tc testcase) {
|
|
delegate := &lanMergeDelegate{
|
|
dc: "dc1",
|
|
nodeID: types.NodeID(thisNodeID),
|
|
nodeName: "node0",
|
|
}
|
|
|
|
err := delegate.NotifyMerge(tc.members)
|
|
|
|
if tc.expect == "" {
|
|
require.NoError(t, err)
|
|
} else {
|
|
testutil.RequireErrorContains(t, err, tc.expect)
|
|
}
|
|
}
|
|
|
|
cases := map[string]testcase{
|
|
"client in the wrong datacenter": {
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc2",
|
|
name: "node1",
|
|
server: false,
|
|
build: "0.7.5",
|
|
}),
|
|
},
|
|
expect: "wrong datacenter",
|
|
},
|
|
"server in the wrong datacenter": {
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc2",
|
|
name: "node1",
|
|
server: true,
|
|
build: "0.7.5",
|
|
}),
|
|
},
|
|
expect: "wrong datacenter",
|
|
},
|
|
"node ID conflict with delegate's ID but same node name with same casing": {
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc1",
|
|
name: "node0",
|
|
id: thisNodeID,
|
|
server: true,
|
|
build: "0.7.5",
|
|
}),
|
|
},
|
|
expect: "",
|
|
},
|
|
"node ID conflict with delegate's ID but same node name with different casing": {
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc1",
|
|
name: "NoDe0",
|
|
id: thisNodeID,
|
|
server: true,
|
|
build: "0.7.5",
|
|
}),
|
|
},
|
|
expect: "",
|
|
},
|
|
"node ID conflict with delegate's ID": {
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc1",
|
|
name: "node1",
|
|
id: thisNodeID,
|
|
server: true,
|
|
build: "0.7.5",
|
|
}),
|
|
},
|
|
expect: "with this agent's ID",
|
|
},
|
|
"cluster with existing conflicting node IDs": {
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc1",
|
|
name: "node1",
|
|
id: "6185913b-98d7-4441-bd8f-f7f7d854a4af",
|
|
server: true,
|
|
build: "0.8.5",
|
|
}),
|
|
makeTestNode(t, testMember{
|
|
dc: "dc1",
|
|
name: "node2",
|
|
id: "6185913b-98d7-4441-bd8f-f7f7d854a4af",
|
|
server: true,
|
|
build: "0.9.0",
|
|
}),
|
|
},
|
|
expect: "with member",
|
|
},
|
|
"cluster with existing conflicting node IDs, but version is old enough to skip the check": {
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc1",
|
|
name: "node1",
|
|
id: "6185913b-98d7-4441-bd8f-f7f7d854a4af",
|
|
server: true,
|
|
build: "0.8.5",
|
|
}),
|
|
makeTestNode(t, testMember{
|
|
dc: "dc1",
|
|
name: "node2",
|
|
id: "6185913b-98d7-4441-bd8f-f7f7d854a4af",
|
|
server: true,
|
|
build: "0.8.4",
|
|
}),
|
|
},
|
|
expect: "with member",
|
|
},
|
|
"good cluster": {
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc1",
|
|
name: "node1",
|
|
server: true,
|
|
build: "0.8.5",
|
|
}),
|
|
makeTestNode(t, testMember{
|
|
dc: "dc1",
|
|
name: "node2",
|
|
server: true,
|
|
build: "0.8.5",
|
|
}),
|
|
},
|
|
expect: "",
|
|
},
|
|
}
|
|
|
|
for name, tc := range cases {
|
|
t.Run(name, func(t *testing.T) {
|
|
run(t, tc)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMerge_WAN(t *testing.T) {
|
|
type testcase struct {
|
|
members []*serf.Member
|
|
expect string
|
|
setupFn func(t *testing.T, delegate *wanMergeDelegate)
|
|
}
|
|
|
|
run := func(t *testing.T, tc testcase) {
|
|
delegate := &wanMergeDelegate{
|
|
localDatacenter: "dc1",
|
|
}
|
|
if tc.setupFn != nil {
|
|
tc.setupFn(t, delegate)
|
|
}
|
|
err := delegate.NotifyMerge(tc.members)
|
|
if tc.expect == "" {
|
|
require.NoError(t, err)
|
|
} else {
|
|
testutil.RequireErrorContains(t, err, tc.expect)
|
|
}
|
|
}
|
|
|
|
cases := map[string]testcase{
|
|
"not a server": {
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc2",
|
|
name: "node1",
|
|
server: false,
|
|
build: "0.7.5",
|
|
}),
|
|
},
|
|
expect: "not a server",
|
|
},
|
|
"good cluster": {
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc2",
|
|
name: "node1",
|
|
server: true,
|
|
build: "0.7.5",
|
|
}),
|
|
makeTestNode(t, testMember{
|
|
dc: "dc3",
|
|
name: "node2",
|
|
server: true,
|
|
build: "0.7.5",
|
|
}),
|
|
},
|
|
},
|
|
"federation disabled and local join allowed": {
|
|
setupFn: func(t *testing.T, delegate *wanMergeDelegate) {
|
|
delegate.SetWANFederationDisabled(true)
|
|
},
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc1",
|
|
name: "node1",
|
|
server: true,
|
|
build: "0.7.5",
|
|
}),
|
|
},
|
|
},
|
|
"federation disabled and remote join blocked": {
|
|
setupFn: func(t *testing.T, delegate *wanMergeDelegate) {
|
|
delegate.SetWANFederationDisabled(true)
|
|
},
|
|
members: []*serf.Member{
|
|
makeTestNode(t, testMember{
|
|
dc: "dc2",
|
|
name: "node1",
|
|
server: true,
|
|
build: "0.7.5",
|
|
}),
|
|
},
|
|
expect: `WAN federation is disabled`,
|
|
},
|
|
}
|
|
|
|
for name, tc := range cases {
|
|
t.Run(name, func(t *testing.T) {
|
|
run(t, tc)
|
|
})
|
|
}
|
|
}
|
|
|
|
type testMember struct {
|
|
dc string
|
|
name string
|
|
id string
|
|
server bool
|
|
build string
|
|
segment string
|
|
partition string
|
|
}
|
|
|
|
func (tm testMember) role() string {
|
|
if tm.server {
|
|
return "consul"
|
|
}
|
|
return "node"
|
|
}
|
|
|
|
func makeTestNode(t *testing.T, tm testMember) *serf.Member {
|
|
if tm.id == "" {
|
|
uuid, err := uuid.GenerateUUID()
|
|
require.NoError(t, err)
|
|
tm.id = uuid
|
|
}
|
|
m := &serf.Member{
|
|
Name: tm.name,
|
|
Tags: map[string]string{
|
|
"role": tm.role(),
|
|
"dc": tm.dc,
|
|
"id": tm.id,
|
|
"port": "8300",
|
|
"segment": tm.segment,
|
|
"build": tm.build,
|
|
"vsn": "2",
|
|
"vsn_max": "3",
|
|
"vsn_min": "2",
|
|
},
|
|
}
|
|
if tm.partition != "" {
|
|
m.Tags["ap"] = tm.partition
|
|
}
|
|
return m
|
|
}
|