mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00

Cluster and transport may recover to old states when new node joins the cluster. Record cluster last modified index to avoid this.
124 lines
3.5 KiB
Go
124 lines
3.5 KiB
Go
// 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"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/coreos/etcd/pkg/types"
|
|
)
|
|
|
|
// isMemberBootstrapped tries to check if the given member has been bootstrapped
|
|
// in the given cluster.
|
|
func isMemberBootstrapped(cl *Cluster, member string, tr *http.Transport) bool {
|
|
rcl, err := getClusterFromRemotePeers(getRemotePeerURLs(cl, member), false, tr)
|
|
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
|
|
}
|
|
|
|
// GetClusterFromRemotePeers 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 GetClusterFromRemotePeers(urls []string, tr *http.Transport) (*Cluster, error) {
|
|
return getClusterFromRemotePeers(urls, true, tr)
|
|
}
|
|
|
|
// If logerr is true, it prints out more error messages.
|
|
func getClusterFromRemotePeers(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
|
|
}
|
|
var index uint64
|
|
// The header at or before v2.0.3 doesn't have this field. For backward
|
|
// compatibility, it checks whether the field exists.
|
|
if indexStr := resp.Header.Get("X-Raft-Index"); indexStr != "" {
|
|
index, err = strconv.ParseUint(indexStr, 10, 64)
|
|
if err != nil {
|
|
if logerr {
|
|
log.Printf("etcdserver: could not parse raft index: %v", err)
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
cl := NewClusterFromMembers("", id, membs)
|
|
cl.UpdateIndex(index)
|
|
return cl, nil
|
|
}
|
|
return nil, fmt.Errorf("etcdserver: could not retrieve cluster information from the given urls")
|
|
}
|
|
|
|
// getRemotePeerURLs returns peer urls of remote members in the cluster. The
|
|
// returned list is sorted in ascending lexicographical order.
|
|
func getRemotePeerURLs(cl ClusterInfo, local string) []string {
|
|
us := make([]string, 0)
|
|
for _, m := range cl.Members() {
|
|
if m.Name == local {
|
|
continue
|
|
}
|
|
us = append(us, m.PeerURLs...)
|
|
}
|
|
sort.Strings(us)
|
|
return us
|
|
}
|