// Entries are Docker Engines func (c *Cluster) monitorDiscovery(ch <-chan discovery.Entries, errCh <-chan error) { // Watch changes on the discovery channel. currentEntries := discovery.Entries{} for { select { case entries := <-ch: added, removed := currentEntries.Diff(entries) currentEntries = entries // Remove engines first. `addEngine` will refuse to add an engine // if there's already an engine with the same ID. If an engine // changes address, we have to first remove it then add it back. for _, entry := range removed { c.removeEngine(entry.String()) } // Since `addEngine` can be very slow (it has to connect to the // engine), we are going to do the adds in parallel. for _, entry := range added { go c.addEngine(entry.String()) } case err := <-errCh: log.Errorf("Discovery error: %v", err) } } }
func TestWatch(t *testing.T) { d := &Discovery{} d.Initialize("1.1.1.1:1111,2.2.2.2:2222", 0, 0) expected := discovery.Entries{ &discovery.Entry{Host: "1.1.1.1", Port: "1111"}, &discovery.Entry{Host: "2.2.2.2", Port: "2222"}, } ch, _ := d.Watch(nil) assert.True(t, expected.Equals(<-ch)) }
// Create a new endpoint func newDiscoveryEndpoint(url, localAddr string, discPort string, weaveCli *WeaveClient, heartbeat time.Duration, ttl time.Duration) (*discoveryEndpoint, error) { d, err := discovery.New(url, heartbeat, ttl) if err != nil { return nil, err } stopChan := make(chan struct{}) ep := discoveryEndpoint{ Discovery: d, url: url, stopChan: stopChan, } register := func() {} var localAddrHost, localAddrPort string if len(localAddr) > 0 { localAddrHost, localAddrPort, err = net.SplitHostPort(localAddr) if err != nil { Log.Warningf("[manager] Invalid local address '%s': %s", localAddr, err) return nil, err } register = func() { Log.Debugf("[manager] Registering on '%s' we are at '%s' (%s period)...", url, localAddr, heartbeat) if err := d.Register(localAddr); err != nil { Log.Warningf("[manager] Registration failed: %s", err) } else { ep.lastRegister = time.Now() } } } hostAndPort := func(e *discovery.Entry) (string, string, bool) { host := e.Host port := e.Port if len(discPort) > 0 { port = discPort } return host, port, (host == localAddrHost && port == localAddrPort) } entriesChan, errorsChan := d.Watch(stopChan) ticker := time.NewTicker(heartbeat) go func() { register() currentEntries := discovery.Entries{} for { select { case reportedEntries := <-entriesChan: added, removed := currentEntries.Diff(reportedEntries) ep.added += uint64(len(added)) ep.removed += uint64(len(removed)) currentEntries = reportedEntries Log.Printf("[manager] Updates from '%s': %d added, %d removed...", url, len(added), len(removed)) for _, e := range added { if host, port, isLocal := hostAndPort(e); !isLocal { weaveCli.Join(host, port) } } for _, e := range removed { if host, port, isLocal := hostAndPort(e); !isLocal { weaveCli.Forget(host, port) } } case reportedError := <-errorsChan: Log.Warningf("[manager] Error from endpoint %s: %s...", url, reportedError) case <-ticker.C: register() case <-stopChan: ticker.Stop() return } } }() return &ep, nil }