package daemon import ( "fmt" "strconv" "time" log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/discovery" // Register the libkv backends for discovery. _ "github.com/docker/docker/pkg/discovery/kv" ) const ( // defaultDiscoveryHeartbeat is the default value for discovery heartbeat interval. defaultDiscoveryHeartbeat = 20 * time.Second // defaultDiscoveryTTLFactor is the default TTL factor for discovery defaultDiscoveryTTLFactor = 3 ) func discoveryOpts(clusterOpts map[string]string) (time.Duration, time.Duration, error) { var ( heartbeat = defaultDiscoveryHeartbeat ttl = defaultDiscoveryTTLFactor * defaultDiscoveryHeartbeat ) if hb, ok := clusterOpts["discovery.heartbeat"]; ok { h, err := strconv.Atoi(hb) if err != nil { return time.Duration(0), time.Duration(0), err } heartbeat = time.Duration(h) * time.Second ttl = defaultDiscoveryTTLFactor * heartbeat } if tstr, ok := clusterOpts["discovery.ttl"]; ok { t, err := strconv.Atoi(tstr) if err != nil { return time.Duration(0), time.Duration(0), err } ttl = time.Duration(t) * time.Second if _, ok := clusterOpts["discovery.heartbeat"]; !ok { h := int(t / defaultDiscoveryTTLFactor) heartbeat = time.Duration(h) * time.Second } if ttl <= heartbeat { return time.Duration(0), time.Duration(0), fmt.Errorf("discovery.ttl timer must be greater than discovery.heartbeat") } } return heartbeat, ttl, nil } // initDiscovery initialized the nodes discovery subsystem by connecting to the specified backend // and start a registration loop to advertise the current node under the specified address. func initDiscovery(backend, address string, clusterOpts map[string]string) (discovery.Backend, error) { heartbeat, ttl, err := discoveryOpts(clusterOpts) if err != nil { return nil, err } discoveryBackend, err := discovery.New(backend, heartbeat, ttl, clusterOpts) if err != nil { return nil, err } // We call Register() on the discovery backend in a loop for the whole lifetime of the daemon, // but we never actually Watch() for nodes appearing and disappearing for the moment. go registrationLoop(discoveryBackend, address, heartbeat) return discoveryBackend, nil } func registerAddr(backend discovery.Backend, addr string) { if err := backend.Register(addr); err != nil { log.Warnf("Registering as %q in discovery failed: %v", addr, err) } } // registrationLoop registers the current node against the discovery backend using the specified // address. The function never returns, as registration against the backend comes with a TTL and // requires regular heartbeats. func registrationLoop(discoveryBackend discovery.Backend, address string, heartbeat time.Duration) { registerAddr(discoveryBackend, address) for range time.Tick(heartbeat) { registerAddr(discoveryBackend, address) } }