github.com/ghodss/etcd@v0.3.1-0.20140417172404-cc329bfa55cb/server/registry.go (about)

     1  package server
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"path"
     7  	"path/filepath"
     8  	"sort"
     9  	"strings"
    10  	"sync"
    11  
    12  	"github.com/coreos/etcd/log"
    13  	"github.com/coreos/etcd/store"
    14  )
    15  
    16  // The location of the peer URL data.
    17  const RegistryPeerKey = "/_etcd/machines"
    18  
    19  // The location of the standby URL data.
    20  const RegistryStandbyKey = "/_etcd/standbys"
    21  
    22  // The Registry stores URL information for nodes.
    23  type Registry struct {
    24  	sync.Mutex
    25  	store    store.Store
    26  	peers    map[string]*node
    27  	standbys map[string]*node
    28  }
    29  
    30  // The internal storage format of the registry.
    31  type node struct {
    32  	peerVersion string
    33  	peerURL     string
    34  	url         string
    35  }
    36  
    37  // Creates a new Registry.
    38  func NewRegistry(s store.Store) *Registry {
    39  	return &Registry{
    40  		store:    s,
    41  		peers:    make(map[string]*node),
    42  		standbys: make(map[string]*node),
    43  	}
    44  }
    45  
    46  // Peers returns a list of cached peer names.
    47  func (r *Registry) Peers() []string {
    48  	r.Lock()
    49  	defer r.Unlock()
    50  
    51  	names := make([]string, 0, len(r.peers))
    52  	for name := range r.peers {
    53  		names = append(names, name)
    54  	}
    55  	sort.Sort(sort.StringSlice(names))
    56  	return names
    57  }
    58  
    59  // Standbys returns a list of cached standby names.
    60  func (r *Registry) Standbys() []string {
    61  	r.Lock()
    62  	defer r.Unlock()
    63  
    64  	names := make([]string, 0, len(r.standbys))
    65  	for name := range r.standbys {
    66  		names = append(names, name)
    67  	}
    68  	sort.Sort(sort.StringSlice(names))
    69  	return names
    70  }
    71  
    72  // RegisterPeer adds a peer to the registry.
    73  func (r *Registry) RegisterPeer(name string, peerURL string, machURL string) error {
    74  	if err := r.register(RegistryPeerKey, name, peerURL, machURL); err != nil {
    75  		return err
    76  	}
    77  
    78  	r.Lock()
    79  	defer r.Unlock()
    80  	r.peers[name] = r.load(RegistryPeerKey, name)
    81  	return nil
    82  }
    83  
    84  // RegisterStandby adds a standby to the registry.
    85  func (r *Registry) RegisterStandby(name string, peerURL string, machURL string) error {
    86  	if err := r.register(RegistryStandbyKey, name, peerURL, machURL); err != nil {
    87  		return err
    88  	}
    89  
    90  	r.Lock()
    91  	defer r.Unlock()
    92  	r.standbys[name] = r.load(RegistryStandbyKey, name)
    93  	return nil
    94  }
    95  
    96  func (r *Registry) register(key, name string, peerURL string, machURL string) error {
    97  	// Write data to store.
    98  	v := url.Values{}
    99  	v.Set("raft", peerURL)
   100  	v.Set("etcd", machURL)
   101  	_, err := r.store.Create(path.Join(key, name), false, v.Encode(), false, store.Permanent)
   102  	log.Debugf("Register: %s", name)
   103  	return err
   104  }
   105  
   106  // UpdatePeerURL updates peer URL in registry
   107  func (r *Registry) UpdatePeerURL(name string, peerURL string) error {
   108  	r.Lock()
   109  	defer r.Unlock()
   110  
   111  	machURL, _ := r.clientURL(RegistryPeerKey, name)
   112  	// Write data to store.
   113  	key := path.Join(RegistryPeerKey, name)
   114  	v := url.Values{}
   115  	v.Set("raft", peerURL)
   116  	v.Set("etcd", machURL)
   117  	_, err := r.store.Update(key, v.Encode(), store.Permanent)
   118  
   119  	// Invalidate outdated cache.
   120  	r.invalidate(name)
   121  	log.Debugf("Update PeerURL: %s", name)
   122  	return err
   123  }
   124  
   125  // UnregisterPeer removes a peer from the registry.
   126  func (r *Registry) UnregisterPeer(name string) error {
   127  	return r.unregister(RegistryPeerKey, name)
   128  }
   129  
   130  // UnregisterStandby removes a standby from the registry.
   131  func (r *Registry) UnregisterStandby(name string) error {
   132  	return r.unregister(RegistryStandbyKey, name)
   133  }
   134  
   135  func (r *Registry) unregister(key, name string) error {
   136  	// Remove the key from the store.
   137  	_, err := r.store.Delete(path.Join(key, name), false, false)
   138  	log.Debugf("Unregister: %s", name)
   139  	return err
   140  }
   141  
   142  // PeerCount returns the number of peers in the cluster.
   143  func (r *Registry) PeerCount() int {
   144  	return r.count(RegistryPeerKey)
   145  }
   146  
   147  // StandbyCount returns the number of standbys in the cluster.
   148  func (r *Registry) StandbyCount() int {
   149  	return r.count(RegistryStandbyKey)
   150  }
   151  
   152  // Returns the number of nodes in the cluster.
   153  func (r *Registry) count(key string) int {
   154  	e, err := r.store.Get(key, false, false)
   155  	if err != nil {
   156  		return 0
   157  	}
   158  	return len(e.Node.Nodes)
   159  }
   160  
   161  // PeerExists checks if a peer with the given name exists.
   162  func (r *Registry) PeerExists(name string) bool {
   163  	return r.exists(RegistryPeerKey, name)
   164  }
   165  
   166  // StandbyExists checks if a standby with the given name exists.
   167  func (r *Registry) StandbyExists(name string) bool {
   168  	return r.exists(RegistryStandbyKey, name)
   169  }
   170  
   171  func (r *Registry) exists(key, name string) bool {
   172  	e, err := r.store.Get(path.Join(key, name), false, false)
   173  	if err != nil {
   174  		return false
   175  	}
   176  	return (e.Node != nil)
   177  }
   178  
   179  // Retrieves the client URL for a given node by name.
   180  func (r *Registry) ClientURL(name string) (string, bool) {
   181  	r.Lock()
   182  	defer r.Unlock()
   183  	return r.clientURL(RegistryPeerKey, name)
   184  }
   185  
   186  func (r *Registry) clientURL(key, name string) (string, bool) {
   187  	if r.peers[name] == nil {
   188  		if node := r.load(key, name); node != nil {
   189  			r.peers[name] = node
   190  		}
   191  	}
   192  
   193  	if node := r.peers[name]; node != nil {
   194  		return node.url, true
   195  	}
   196  
   197  	return "", false
   198  }
   199  
   200  // TODO(yichengq): have all of the code use a full URL with scheme
   201  // and remove this method
   202  // PeerHost retrieves the host part of peer URL for a given node by name.
   203  func (r *Registry) PeerHost(name string) (string, bool) {
   204  	rawurl, ok := r.PeerURL(name)
   205  	if ok {
   206  		u, _ := url.Parse(rawurl)
   207  		return u.Host, ok
   208  	}
   209  	return rawurl, ok
   210  }
   211  
   212  // Retrieves the peer URL for a given node by name.
   213  func (r *Registry) PeerURL(name string) (string, bool) {
   214  	r.Lock()
   215  	defer r.Unlock()
   216  	return r.peerURL(RegistryPeerKey, name)
   217  }
   218  
   219  func (r *Registry) peerURL(key, name string) (string, bool) {
   220  	if r.peers[name] == nil {
   221  		if node := r.load(key, name); node != nil {
   222  			r.peers[name] = node
   223  		}
   224  	}
   225  
   226  	if node := r.peers[name]; node != nil {
   227  		return node.peerURL, true
   228  	}
   229  
   230  	return "", false
   231  }
   232  
   233  // Retrieves the client URL for a given standby by name.
   234  func (r *Registry) StandbyClientURL(name string) (string, bool) {
   235  	r.Lock()
   236  	defer r.Unlock()
   237  	return r.standbyClientURL(RegistryStandbyKey, name)
   238  }
   239  
   240  func (r *Registry) standbyClientURL(key, name string) (string, bool) {
   241  	if r.standbys[name] == nil {
   242  		if node := r.load(key, name); node != nil {
   243  			r.standbys[name] = node
   244  		}
   245  	}
   246  	if node := r.standbys[name]; node != nil {
   247  		return node.url, true
   248  	}
   249  	return "", false
   250  }
   251  
   252  // Retrieves the peer URL for a given standby by name.
   253  func (r *Registry) StandbyPeerURL(name string) (string, bool) {
   254  	r.Lock()
   255  	defer r.Unlock()
   256  	return r.standbyPeerURL(RegistryStandbyKey, name)
   257  }
   258  
   259  func (r *Registry) standbyPeerURL(key, name string) (string, bool) {
   260  	if r.standbys[name] == nil {
   261  		if node := r.load(key, name); node != nil {
   262  			r.standbys[name] = node
   263  		}
   264  	}
   265  	if node := r.standbys[name]; node != nil {
   266  		return node.peerURL, true
   267  	}
   268  	return "", false
   269  }
   270  
   271  // Retrieves the Client URLs for all nodes.
   272  func (r *Registry) ClientURLs(leaderName, selfName string) []string {
   273  	return r.urls(RegistryPeerKey, leaderName, selfName, r.clientURL)
   274  }
   275  
   276  // Retrieves the Peer URLs for all nodes.
   277  func (r *Registry) PeerURLs(leaderName, selfName string) []string {
   278  	return r.urls(RegistryPeerKey, leaderName, selfName, r.peerURL)
   279  }
   280  
   281  // Retrieves the URLs for all nodes using url function.
   282  func (r *Registry) urls(key, leaderName, selfName string, url func(key, name string) (string, bool)) []string {
   283  	r.Lock()
   284  	defer r.Unlock()
   285  
   286  	// Build list including the leader and self.
   287  	urls := make([]string, 0)
   288  	if url, _ := url(key, leaderName); len(url) > 0 {
   289  		urls = append(urls, url)
   290  	}
   291  
   292  	// Retrieve a list of all nodes.
   293  	if e, _ := r.store.Get(key, false, false); e != nil {
   294  		// Lookup the URL for each one.
   295  		for _, pair := range e.Node.Nodes {
   296  			_, name := filepath.Split(pair.Key)
   297  			if url, _ := url(key, name); len(url) > 0 && name != leaderName {
   298  				urls = append(urls, url)
   299  			}
   300  		}
   301  	}
   302  
   303  	log.Infof("URLs: %s: %s / %s (%s)", key, leaderName, selfName, strings.Join(urls, ","))
   304  
   305  	return urls
   306  }
   307  
   308  // Removes a node from the cache.
   309  func (r *Registry) Invalidate(name string) {
   310  	r.Lock()
   311  	defer r.Unlock()
   312  	r.invalidate(name)
   313  }
   314  
   315  func (r *Registry) invalidate(name string) {
   316  	delete(r.peers, name)
   317  	delete(r.standbys, name)
   318  }
   319  
   320  // Loads the given node by name from the store into the cache.
   321  func (r *Registry) load(key, name string) *node {
   322  	if name == "" {
   323  		return nil
   324  	}
   325  
   326  	// Retrieve from store.
   327  	e, err := r.store.Get(path.Join(key, name), false, false)
   328  	if err != nil {
   329  		return nil
   330  	}
   331  
   332  	// Parse as a query string.
   333  	m, err := url.ParseQuery(*e.Node.Value)
   334  	if err != nil {
   335  		panic(fmt.Sprintf("Failed to parse peers entry: %s", name))
   336  	}
   337  
   338  	// Create node.
   339  	return &node{
   340  		url:     m["etcd"][0],
   341  		peerURL: m["raft"][0],
   342  	}
   343  }