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 }