Merge pull request #2582 from xiang90/cluster-check

etcdserver: loose member validation for joining existing cluster
release-2.1
Xiang Li 2015-03-25 14:37:13 -07:00
commit 635e4db6d9
2 changed files with 39 additions and 8 deletions

View File

@ -49,7 +49,7 @@ type ServerConfig struct {
// VerifyBootstrapConfig sanity-checks the initial config for bootstrap case // VerifyBootstrapConfig sanity-checks the initial config for bootstrap case
// and returns an error for things that should never happen. // and returns an error for things that should never happen.
func (c *ServerConfig) VerifyBootstrap() error { func (c *ServerConfig) VerifyBootstrap() error {
if err := c.verifyLocalMember(); err != nil { if err := c.verifyLocalMember(true); err != nil {
return err return err
} }
if err := c.Cluster.Validate(); err != nil { if err := c.Cluster.Validate(); err != nil {
@ -64,7 +64,10 @@ func (c *ServerConfig) VerifyBootstrap() error {
// VerifyJoinExisting sanity-checks the initial config for join existing cluster // VerifyJoinExisting sanity-checks the initial config for join existing cluster
// case and returns an error for things that should never happen. // case and returns an error for things that should never happen.
func (c *ServerConfig) VerifyJoinExisting() error { func (c *ServerConfig) VerifyJoinExisting() error {
if err := c.verifyLocalMember(); err != nil { // no need for strict checking since the member have announced its
// peer urls to the cluster before starting and do not have to set
// it in the configuration again.
if err := c.verifyLocalMember(false); err != nil {
return err return err
} }
if err := c.Cluster.Validate(); err != nil { if err := c.Cluster.Validate(); err != nil {
@ -76,9 +79,10 @@ func (c *ServerConfig) VerifyJoinExisting() error {
return nil return nil
} }
// verifyLocalMember verifies that the local member is valid and is listed // verifyLocalMember verifies the configured member is in configured
// in the cluster correctly. // cluster. If strict is set, it also verifies the configured member
func (c *ServerConfig) verifyLocalMember() error { // has the same peer urls as configured advertised peer urls.
func (c *ServerConfig) verifyLocalMember(strict bool) error {
m := c.Cluster.MemberByName(c.Name) m := c.Cluster.MemberByName(c.Name)
// Make sure the cluster at least contains the local server. // Make sure the cluster at least contains the local server.
if m == nil { if m == nil {
@ -92,8 +96,10 @@ func (c *ServerConfig) verifyLocalMember() error {
// TODO: Remove URLStringsEqual after improvement of using hostnames #2150 #2123 // TODO: Remove URLStringsEqual after improvement of using hostnames #2150 #2123
apurls := c.PeerURLs.StringSlice() apurls := c.PeerURLs.StringSlice()
sort.Strings(apurls) sort.Strings(apurls)
if !netutil.URLStringsEqual(apurls, m.PeerURLs) { if strict {
return fmt.Errorf("%s has different advertised URLs in the cluster and advertised peer URLs list", c.Name) if !netutil.URLStringsEqual(apurls, m.PeerURLs) {
return fmt.Errorf("%s has different advertised URLs in the cluster and advertised peer URLs list", c.Name)
}
} }
return nil return nil
} }

View File

@ -22,6 +22,9 @@ import (
) )
func mustNewURLs(t *testing.T, urls []string) []url.URL { func mustNewURLs(t *testing.T, urls []string) []url.URL {
if len(urls) == 0 {
return nil
}
u, err := types.NewURLs(urls) u, err := types.NewURLs(urls)
if err != nil { if err != nil {
t.Fatalf("error creating new URLs from %q: %v", urls, err) t.Fatalf("error creating new URLs from %q: %v", urls, err)
@ -65,12 +68,14 @@ func TestConfigVerifyLocalMember(t *testing.T) {
tests := []struct { tests := []struct {
clusterSetting string clusterSetting string
apurls []string apurls []string
strict bool
shouldError bool shouldError bool
}{ }{
{ {
// Node must exist in cluster // Node must exist in cluster
"", "",
nil, nil,
true,
true, true,
}, },
@ -78,6 +83,7 @@ func TestConfigVerifyLocalMember(t *testing.T) {
// Initial cluster set // Initial cluster set
"node1=http://localhost:7001,node2=http://localhost:7002", "node1=http://localhost:7001,node2=http://localhost:7002",
[]string{"http://localhost:7001"}, []string{"http://localhost:7001"},
true,
false, false,
}, },
@ -85,6 +91,7 @@ func TestConfigVerifyLocalMember(t *testing.T) {
// Default initial cluster // Default initial cluster
"node1=http://localhost:2380,node1=http://localhost:7001", "node1=http://localhost:2380,node1=http://localhost:7001",
[]string{"http://localhost:2380", "http://localhost:7001"}, []string{"http://localhost:2380", "http://localhost:7001"},
true,
false, false,
}, },
@ -92,6 +99,7 @@ func TestConfigVerifyLocalMember(t *testing.T) {
// Advertised peer URLs must match those in cluster-state // Advertised peer URLs must match those in cluster-state
"node1=http://localhost:7001", "node1=http://localhost:7001",
[]string{"http://localhost:12345"}, []string{"http://localhost:12345"},
true,
true, true,
}, },
@ -99,9 +107,26 @@ func TestConfigVerifyLocalMember(t *testing.T) {
// Advertised peer URLs must match those in cluster-state // Advertised peer URLs must match those in cluster-state
"node1=http://localhost:7001,node1=http://localhost:12345", "node1=http://localhost:7001,node1=http://localhost:12345",
[]string{"http://localhost:12345"}, []string{"http://localhost:12345"},
true,
true, true,
}, },
{
// Advertised peer URLs must match those in cluster-state
"node1=http://localhost:7001",
[]string{},
true,
true,
},
{
// do not care about the urls if strict is not set
"node1=http://localhost:7001",
[]string{},
false,
false,
},
} }
for i, tt := range tests { for i, tt := range tests {
@ -116,7 +141,7 @@ func TestConfigVerifyLocalMember(t *testing.T) {
if tt.apurls != nil { if tt.apurls != nil {
cfg.PeerURLs = mustNewURLs(t, tt.apurls) cfg.PeerURLs = mustNewURLs(t, tt.apurls)
} }
err = cfg.verifyLocalMember() err = cfg.verifyLocalMember(tt.strict)
if (err == nil) && tt.shouldError { if (err == nil) && tt.shouldError {
t.Errorf("%#v", *cluster) t.Errorf("%#v", *cluster)
t.Errorf("#%d: Got no error where one was expected", i) t.Errorf("#%d: Got no error where one was expected", i)