github.com/macb/etcd@v0.3.1-0.20140227003422-a60481c6b1a0/server/registry.go (about)

     1  package server
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"path"
     7  	"path/filepath"
     8  	"strings"
     9  	"sync"
    10  
    11  	"github.com/coreos/etcd/log"
    12  	"github.com/coreos/etcd/store"
    13  )
    14  
    15  // The location of the peer URL data.
    16  const RegistryKey = "/_etcd/machines"
    17  
    18  // The Registry stores URL information for nodes.
    19  type Registry struct {
    20  	sync.Mutex
    21  	store store.Store
    22  	nodes map[string]*node
    23  }
    24  
    25  // The internal storage format of the registry.
    26  type node struct {
    27  	peerVersion string
    28  	peerURL     string
    29  	url         string
    30  }
    31  
    32  // Creates a new Registry.
    33  func NewRegistry(s store.Store) *Registry {
    34  	return &Registry{
    35  		store: s,
    36  		nodes: make(map[string]*node),
    37  	}
    38  }
    39  
    40  // Adds a node to the registry.
    41  func (r *Registry) Register(name string, peerURL string, machURL string) error {
    42  	r.Lock()
    43  	defer r.Unlock()
    44  
    45  	// Write data to store.
    46  	key := path.Join(RegistryKey, name)
    47  	v := url.Values{}
    48  	v.Set("raft", peerURL)
    49  	v.Set("etcd", machURL)
    50  	_, err := r.store.Create(key, false, v.Encode(), false, store.Permanent)
    51  	log.Debugf("Register: %s", name)
    52  	return err
    53  }
    54  
    55  // Removes a node from the registry.
    56  func (r *Registry) Unregister(name string) error {
    57  	r.Lock()
    58  	defer r.Unlock()
    59  
    60  	// Remove from cache.
    61  	// delete(r.nodes, name)
    62  
    63  	// Remove the key from the store.
    64  	_, err := r.store.Delete(path.Join(RegistryKey, name), false, false)
    65  	log.Debugf("Unregister: %s", name)
    66  	return err
    67  }
    68  
    69  // Returns the number of nodes in the cluster.
    70  func (r *Registry) Count() int {
    71  	e, err := r.store.Get(RegistryKey, false, false)
    72  	if err != nil {
    73  		return 0
    74  	}
    75  	return len(e.Node.Nodes)
    76  }
    77  
    78  // Retrieves the client URL for a given node by name.
    79  func (r *Registry) ClientURL(name string) (string, bool) {
    80  	r.Lock()
    81  	defer r.Unlock()
    82  	return r.clientURL(name)
    83  }
    84  
    85  func (r *Registry) clientURL(name string) (string, bool) {
    86  	if r.nodes[name] == nil {
    87  		r.load(name)
    88  	}
    89  
    90  	if node := r.nodes[name]; node != nil {
    91  		return node.url, true
    92  	}
    93  
    94  	return "", false
    95  }
    96  
    97  // TODO(yichengq): have all of the code use a full URL with scheme
    98  // and remove this method
    99  // PeerHost retrieves the host part of peer URL for a given node by name.
   100  func (r *Registry) PeerHost(name string) (string, bool) {
   101  	rawurl, ok := r.PeerURL(name)
   102  	if ok {
   103  		u, _ := url.Parse(rawurl)
   104  		return u.Host, ok
   105  	}
   106  	return rawurl, ok
   107  }
   108  
   109  // Retrieves the peer URL for a given node by name.
   110  func (r *Registry) PeerURL(name string) (string, bool) {
   111  	r.Lock()
   112  	defer r.Unlock()
   113  	return r.peerURL(name)
   114  }
   115  
   116  func (r *Registry) peerURL(name string) (string, bool) {
   117  	if r.nodes[name] == nil {
   118  		r.load(name)
   119  	}
   120  
   121  	if node := r.nodes[name]; node != nil {
   122  		return node.peerURL, true
   123  	}
   124  
   125  	return "", false
   126  }
   127  
   128  // Retrieves the Client URLs for all nodes.
   129  func (r *Registry) ClientURLs(leaderName, selfName string) []string {
   130  	return r.urls(leaderName, selfName, r.clientURL)
   131  }
   132  
   133  // Retrieves the Peer URLs for all nodes.
   134  func (r *Registry) PeerURLs(leaderName, selfName string) []string {
   135  	return r.urls(leaderName, selfName, r.peerURL)
   136  }
   137  
   138  // Retrieves the URLs for all nodes using url function.
   139  func (r *Registry) urls(leaderName, selfName string, url func(name string) (string, bool)) []string {
   140  	r.Lock()
   141  	defer r.Unlock()
   142  
   143  	// Build list including the leader and self.
   144  	urls := make([]string, 0)
   145  	if url, _ := url(leaderName); len(url) > 0 {
   146  		urls = append(urls, url)
   147  	}
   148  
   149  	// Retrieve a list of all nodes.
   150  	if e, _ := r.store.Get(RegistryKey, false, false); e != nil {
   151  		// Lookup the URL for each one.
   152  		for _, pair := range e.Node.Nodes {
   153  			_, name := filepath.Split(pair.Key)
   154  			if url, _ := url(name); len(url) > 0 && name != leaderName {
   155  				urls = append(urls, url)
   156  			}
   157  		}
   158  	}
   159  
   160  	log.Infof("URLs: %s / %s (%s)", leaderName, selfName, strings.Join(urls, ","))
   161  
   162  	return urls
   163  }
   164  
   165  // Removes a node from the cache.
   166  func (r *Registry) Invalidate(name string) {
   167  	delete(r.nodes, name)
   168  }
   169  
   170  // Loads the given node by name from the store into the cache.
   171  func (r *Registry) load(name string) {
   172  	if name == "" {
   173  		return
   174  	}
   175  
   176  	// Retrieve from store.
   177  	e, err := r.store.Get(path.Join(RegistryKey, name), false, false)
   178  	if err != nil {
   179  		return
   180  	}
   181  
   182  	// Parse as a query string.
   183  	m, err := url.ParseQuery(*e.Node.Value)
   184  	if err != nil {
   185  		panic(fmt.Sprintf("Failed to parse peers entry: %s", name))
   186  	}
   187  
   188  	// Create node.
   189  	r.nodes[name] = &node{
   190  		url:     m["etcd"][0],
   191  		peerURL: m["raft"][0],
   192  	}
   193  }