*: detect duplicate name for discovery bootstrap

This commit is contained in:
Xiang Li 2015-07-02 18:16:49 -07:00 committed by Yicheng Qin
parent b8279b3591
commit dc3f7f5d90
3 changed files with 63 additions and 14 deletions

View File

@ -42,6 +42,7 @@ var (
ErrSizeNotFound = errors.New("discovery: size key not found") ErrSizeNotFound = errors.New("discovery: size key not found")
ErrTokenNotFound = errors.New("discovery: token not found") ErrTokenNotFound = errors.New("discovery: token not found")
ErrDuplicateID = errors.New("discovery: found duplicate id") ErrDuplicateID = errors.New("discovery: found duplicate id")
ErrDuplicateName = errors.New("discovery: found duplicate name")
ErrFullCluster = errors.New("discovery: cluster is full") ErrFullCluster = errors.New("discovery: cluster is full")
ErrTooManyRetries = errors.New("discovery: too many retries") ErrTooManyRetries = errors.New("discovery: too many retries")
) )
@ -170,14 +171,14 @@ func (d *discovery) joinCluster(config string) (string, error) {
return "", err return "", err
} }
return nodesToCluster(all), nil return nodesToCluster(all, size)
} }
func (d *discovery) getCluster() (string, error) { func (d *discovery) getCluster() (string, error) {
nodes, size, index, err := d.checkCluster() nodes, size, index, err := d.checkCluster()
if err != nil { if err != nil {
if err == ErrFullCluster { if err == ErrFullCluster {
return nodesToCluster(nodes), nil return nodesToCluster(nodes, size)
} }
return "", err return "", err
} }
@ -186,7 +187,7 @@ func (d *discovery) getCluster() (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return nodesToCluster(all), nil return nodesToCluster(all, size)
} }
func (d *discovery) createSelf(contents string) error { func (d *discovery) createSelf(contents string) error {
@ -322,12 +323,20 @@ func (d *discovery) selfKey() string {
return path.Join("/", d.cluster, d.id.String()) return path.Join("/", d.cluster, d.id.String())
} }
func nodesToCluster(ns []*client.Node) string { func nodesToCluster(ns []*client.Node, size int) (string, error) {
s := make([]string, len(ns)) s := make([]string, len(ns))
for i, n := range ns { for i, n := range ns {
s[i] = n.Value s[i] = n.Value
} }
return strings.Join(s, ",") us := strings.Join(s, ",")
m, err := types.NewURLsMap(us)
if err != nil {
return us, ErrInvalidURL
}
if m.Len() != size {
return us, ErrDuplicateName
}
return us, nil
} }
type sortableNodes struct{ Nodes []*client.Node } type sortableNodes struct{ Nodes []*client.Node }

View File

@ -344,16 +344,52 @@ func TestCreateSelf(t *testing.T) {
} }
func TestNodesToCluster(t *testing.T) { func TestNodesToCluster(t *testing.T) {
nodes := []*client.Node{ tests := []struct {
0: {Key: "/1000/1", Value: "1=1.1.1.1", CreatedIndex: 1}, nodes []*client.Node
1: {Key: "/1000/2", Value: "2=2.2.2.2", CreatedIndex: 2}, size int
2: {Key: "/1000/3", Value: "3=3.3.3.3", CreatedIndex: 3}, wcluster string
werr error
}{
{
[]*client.Node{
0: {Key: "/1000/1", Value: "1=http://1.1.1.1:2380", CreatedIndex: 1},
1: {Key: "/1000/2", Value: "2=http://2.2.2.2:2380", CreatedIndex: 2},
2: {Key: "/1000/3", Value: "3=http://3.3.3.3:2380", CreatedIndex: 3},
},
3,
"1=http://1.1.1.1:2380,2=http://2.2.2.2:2380,3=http://3.3.3.3:2380",
nil,
},
{
[]*client.Node{
0: {Key: "/1000/1", Value: "1=http://1.1.1.1:2380", CreatedIndex: 1},
1: {Key: "/1000/2", Value: "2=http://2.2.2.2:2380", CreatedIndex: 2},
2: {Key: "/1000/3", Value: "2=http://3.3.3.3:2380", CreatedIndex: 3},
},
3,
"1=http://1.1.1.1:2380,2=http://2.2.2.2:2380,2=http://3.3.3.3:2380",
ErrDuplicateName,
},
{
[]*client.Node{
0: {Key: "/1000/1", Value: "1=1.1.1.1:2380", CreatedIndex: 1},
1: {Key: "/1000/2", Value: "2=http://2.2.2.2:2380", CreatedIndex: 2},
2: {Key: "/1000/3", Value: "2=http://3.3.3.3:2380", CreatedIndex: 3},
},
3,
"1=1.1.1.1:2380,2=http://2.2.2.2:2380,2=http://3.3.3.3:2380",
ErrInvalidURL,
},
} }
w := "1=1.1.1.1,2=2.2.2.2,3=3.3.3.3"
cluster := nodesToCluster(nodes) for i, tt := range tests {
if !reflect.DeepEqual(cluster, w) { cluster, err := nodesToCluster(tt.nodes, tt.size)
t.Errorf("cluster = %v, want %v", cluster, w) if err != tt.werr {
t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
}
if !reflect.DeepEqual(cluster, tt.wcluster) {
t.Errorf("#%d: cluster = %v, want %v", i, cluster, tt.wcluster)
}
} }
} }

View File

@ -110,10 +110,14 @@ func Main() {
switch err { switch err {
case discovery.ErrDuplicateID: case discovery.ErrDuplicateID:
plog.Errorf("member %q has previously registered with discovery service token (%s).", cfg.name, cfg.durl) plog.Errorf("member %q has previously registered with discovery service token (%s).", cfg.name, cfg.durl)
plog.Errorf("But etcd could not find vaild cluster configuration in the given data dir (%s).", cfg.dir) plog.Errorf("But etcd could not find valid cluster configuration in the given data dir (%s).", cfg.dir)
plog.Infof("Please check the given data dir path if the previous bootstrap succeeded") plog.Infof("Please check the given data dir path if the previous bootstrap succeeded")
plog.Infof("or use a new discovery token if the previous bootstrap failed.") plog.Infof("or use a new discovery token if the previous bootstrap failed.")
os.Exit(1) os.Exit(1)
case discovery.ErrDuplicateName:
plog.Errorf("member with duplicated name has registered with discovery service token(%s).", cfg.durl)
plog.Errorf("please check (cURL) the discovery token for more information.")
plog.Errorf("please do not reuse the discovery token and generate a new one to bootstrap the cluster.")
default: default:
plog.Fatalf("%v", err) plog.Fatalf("%v", err)
} }