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 }