From 20497f1f8513ff21f5ca5c9b3c5fd11b23b9dc2c Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Wed, 11 Feb 2015 14:03:14 -0800 Subject: [PATCH 1/2] etcdserver: move remote cluster retrive to cluster_util.go --- etcdserver/cluster_util.go | 112 +++++++++++++++++++++++++++++++++++++ etcdserver/server.go | 87 ---------------------------- 2 files changed, 112 insertions(+), 87 deletions(-) create mode 100644 etcdserver/cluster_util.go diff --git a/etcdserver/cluster_util.go b/etcdserver/cluster_util.go new file mode 100644 index 000000000..874e83239 --- /dev/null +++ b/etcdserver/cluster_util.go @@ -0,0 +1,112 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package etcdserver + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "sort" + "time" + + "github.com/coreos/etcd/pkg/types" +) + +// isBootstrapped tries to check if the given member has been bootstrapped +// in the given cluster. +func isBootstrapped(cfg *ServerConfig) bool { + cl := cfg.Cluster + member := cfg.Name + + us := getOtherPeerURLs(cl, member) + rcl, err := getClusterFromPeers(us, false, cfg.Transport) + if err != nil { + return false + } + id := cl.MemberByName(member).ID + m := rcl.Member(id) + if m == nil { + return false + } + if len(m.ClientURLs) > 0 { + return true + } + return false +} + +// GetClusterFromPeers takes a set of URLs representing etcd peers, and +// attempts to construct a Cluster by accessing the members endpoint on one of +// these URLs. The first URL to provide a response is used. If no URLs provide +// a response, or a Cluster cannot be successfully created from a received +// response, an error is returned. +func GetClusterFromPeers(urls []string, tr *http.Transport) (*Cluster, error) { + return getClusterFromPeers(urls, true, tr) +} + +// If logerr is true, it prints out more error messages. +func getClusterFromPeers(urls []string, logerr bool, tr *http.Transport) (*Cluster, error) { + cc := &http.Client{ + Transport: tr, + Timeout: time.Second, + } + for _, u := range urls { + resp, err := cc.Get(u + "/members") + if err != nil { + if logerr { + log.Printf("etcdserver: could not get cluster response from %s: %v", u, err) + } + continue + } + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + if logerr { + log.Printf("etcdserver: could not read the body of cluster response: %v", err) + } + continue + } + var membs []*Member + if err := json.Unmarshal(b, &membs); err != nil { + if logerr { + log.Printf("etcdserver: could not unmarshal cluster response: %v", err) + } + continue + } + id, err := types.IDFromString(resp.Header.Get("X-Etcd-Cluster-ID")) + if err != nil { + if logerr { + log.Printf("etcdserver: could not parse the cluster ID from cluster res: %v", err) + } + continue + } + return NewClusterFromMembers("", id, membs), nil + } + return nil, fmt.Errorf("etcdserver: could not retrieve cluster information from the given urls") +} + +// getOtherPeerURLs returns peer urls of other members in the cluster. The +// returned list is sorted in ascending lexicographical order. +func getOtherPeerURLs(cl ClusterInfo, self string) []string { + us := make([]string, 0) + for _, m := range cl.Members() { + if m.Name == self { + continue + } + us = append(us, m.PeerURLs...) + } + sort.Strings(us) + return us +} diff --git a/etcdserver/server.go b/etcdserver/server.go index df536aec2..723fd1e10 100644 --- a/etcdserver/server.go +++ b/etcdserver/server.go @@ -18,13 +18,11 @@ import ( "encoding/json" "expvar" "fmt" - "io/ioutil" "log" "math/rand" "net/http" "path" "regexp" - "sort" "sync/atomic" "time" @@ -821,88 +819,3 @@ func (s *EtcdServer) snapshot(snapi uint64, confState *raftpb.ConfState) { func (s *EtcdServer) PauseSending() { s.r.pauseSending() } func (s *EtcdServer) ResumeSending() { s.r.resumeSending() } - -// isBootstrapped tries to check if the given member has been bootstrapped -// in the given cluster. -func isBootstrapped(cfg *ServerConfig) bool { - cl := cfg.Cluster - member := cfg.Name - - us := getOtherPeerURLs(cl, member) - rcl, err := getClusterFromPeers(us, false, cfg.Transport) - if err != nil { - return false - } - id := cl.MemberByName(member).ID - m := rcl.Member(id) - if m == nil { - return false - } - if len(m.ClientURLs) > 0 { - return true - } - return false -} - -// GetClusterFromPeers takes a set of URLs representing etcd peers, and -// attempts to construct a Cluster by accessing the members endpoint on one of -// these URLs. The first URL to provide a response is used. If no URLs provide -// a response, or a Cluster cannot be successfully created from a received -// response, an error is returned. -func GetClusterFromPeers(urls []string, tr *http.Transport) (*Cluster, error) { - return getClusterFromPeers(urls, true, tr) -} - -// If logerr is true, it prints out more error messages. -func getClusterFromPeers(urls []string, logerr bool, tr *http.Transport) (*Cluster, error) { - cc := &http.Client{ - Transport: tr, - Timeout: time.Second, - } - for _, u := range urls { - resp, err := cc.Get(u + "/members") - if err != nil { - if logerr { - log.Printf("etcdserver: could not get cluster response from %s: %v", u, err) - } - continue - } - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - if logerr { - log.Printf("etcdserver: could not read the body of cluster response: %v", err) - } - continue - } - var membs []*Member - if err := json.Unmarshal(b, &membs); err != nil { - if logerr { - log.Printf("etcdserver: could not unmarshal cluster response: %v", err) - } - continue - } - id, err := types.IDFromString(resp.Header.Get("X-Etcd-Cluster-ID")) - if err != nil { - if logerr { - log.Printf("etcdserver: could not parse the cluster ID from cluster res: %v", err) - } - continue - } - return NewClusterFromMembers("", id, membs), nil - } - return nil, fmt.Errorf("etcdserver: could not retrieve cluster information from the given urls") -} - -// getOtherPeerURLs returns peer urls of other members in the cluster. The -// returned list is sorted in ascending lexicographical order. -func getOtherPeerURLs(cl ClusterInfo, self string) []string { - us := make([]string, 0) - for _, m := range cl.Members() { - if m.Name == self { - continue - } - us = append(us, m.PeerURLs...) - } - sort.Strings(us) - return us -} From 163f0f09f689df2d0bce787370002649ae8164c4 Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Wed, 11 Feb 2015 14:18:10 -0800 Subject: [PATCH 2/2] etcdserver: cleanup cluster_util --- etcdserver/cluster_util.go | 9 +++------ etcdserver/server.go | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/etcdserver/cluster_util.go b/etcdserver/cluster_util.go index 874e83239..851cf9fbb 100644 --- a/etcdserver/cluster_util.go +++ b/etcdserver/cluster_util.go @@ -26,14 +26,11 @@ import ( "github.com/coreos/etcd/pkg/types" ) -// isBootstrapped tries to check if the given member has been bootstrapped +// isMemberBootstrapped tries to check if the given member has been bootstrapped // in the given cluster. -func isBootstrapped(cfg *ServerConfig) bool { - cl := cfg.Cluster - member := cfg.Name - +func isMemberBootstrapped(cl *Cluster, member string, tr *http.Transport) bool { us := getOtherPeerURLs(cl, member) - rcl, err := getClusterFromPeers(us, false, cfg.Transport) + rcl, err := getClusterFromPeers(us, false, tr) if err != nil { return false } diff --git a/etcdserver/server.go b/etcdserver/server.go index 723fd1e10..555b8c556 100644 --- a/etcdserver/server.go +++ b/etcdserver/server.go @@ -173,7 +173,7 @@ func NewServer(cfg *ServerConfig) (*EtcdServer, error) { return nil, err } m := cfg.Cluster.MemberByName(cfg.Name) - if isBootstrapped(cfg) { + if isMemberBootstrapped(cfg.Cluster, cfg.Name, cfg.Transport) { return nil, fmt.Errorf("member %s has already been bootstrapped", m.ID) } if cfg.ShouldDiscover() {