func join(c *cli.Context) { dflag := getDiscovery(c) if dflag == "" { log.Fatalf("discovery required to join a cluster. See '%s join --help'.", c.App.Name) } addr := c.String("advertise") if addr == "" { log.Fatal("missing mandatory --advertise flag") } if !checkAddrFormat(addr) { log.Fatal("--advertise should be of the form ip:port or hostname:port") } joinDelay, err := time.ParseDuration(c.String("delay")) if err != nil { log.Fatalf("invalid --delay: %v", err) } if joinDelay < time.Duration(0)*time.Second { log.Fatalf("--delay should not be a negative number") } hb, err := time.ParseDuration(c.String("heartbeat")) if err != nil { log.Fatalf("invalid --heartbeat: %v", err) } if hb < 1*time.Second { log.Fatal("--heartbeat should be at least one second") } ttl, err := time.ParseDuration(c.String("ttl")) if err != nil { log.Fatalf("invalid --ttl: %v", err) } if ttl <= hb { log.Fatal("--ttl must be strictly superior to the heartbeat value") } d, err := discovery.New(dflag, hb, ttl, getDiscoveryOpt(c)) if err != nil { log.Fatal(err) } // if joinDelay is 0, no delay will be executed // if joinDelay is larger than 0, // add a random delay between 0s and joinDelay at start to avoid synchronized registration if joinDelay > 0 { r := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) delay := time.Duration(r.Int63n(int64(joinDelay))) log.Infof("Add a random delay %s to avoid synchronized registration", delay) time.Sleep(delay) } for { log.WithFields(log.Fields{"addr": addr, "discovery": dflag}).Infof("Registering on the discovery service every %s...", hb) if err := d.Register(addr); err != nil { log.Error(err) } time.Sleep(hb) } }
func list(c *cli.Context) { dflag := getDiscovery(c) if dflag == "" { log.Fatalf("discovery required to list a cluster. See '%s list --help'.", c.App.Name) } timeout, err := time.ParseDuration(c.String("timeout")) if err != nil { log.Fatalf("invalid --timeout: %v", err) } d, err := discovery.New(dflag, timeout, 0, getDiscoveryOpt(c)) if err != nil { log.Fatal(err) } ch, errCh := d.Watch(nil) select { case entries := <-ch: for _, entry := range entries { fmt.Println(entry) } case err := <-errCh: log.Fatal(err) case <-time.After(timeout): log.Fatal("Timed out") } }
// 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) { discoveryBackend, err := discovery.New(backend, defaultDiscoveryHeartbeat, defaultDiscoveryTTL, 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) return discoveryBackend, nil }
func parseDiscoveryOptions(backendAddress string, clusterOpts map[string]string) (time.Duration, discovery.Backend, error) { heartbeat, ttl, err := discoveryOpts(clusterOpts) if err != nil { return 0, nil, err } backend, err := discovery.New(backendAddress, heartbeat, ttl, clusterOpts) if err != nil { return 0, nil, err } return heartbeat, backend, nil }
func startDiscovery(cfg *config.ClusterCfg) ([]config.Option, error) { if cfg == nil { return nil, fmt.Errorf("discovery requires a valid configuration") } hb := time.Duration(cfg.Heartbeat) * time.Second if hb == 0 { hb = defaultHeartbeat } logrus.Infof("discovery : %s $s", cfg.Discovery, hb.String()) d, err := discovery.New(cfg.Discovery, hb, ttlFactor*hb) if err != nil { return nil, err } if cfg.Address == "" { iface, err := net.InterfaceByName("eth0") if err != nil { return nil, err } addrs, err := iface.Addrs() if err != nil || len(addrs) == 0 { return nil, err } ip, _, _ := net.ParseCIDR(addrs[0].String()) cfg.Address = ip.String() } if ip := net.ParseIP(cfg.Address); ip == nil { return nil, errors.New("address config should be either ipv4 or ipv6 address") } if err := d.Register(cfg.Address + ":0"); err != nil { return nil, err } options := []config.Option{config.OptionDiscoveryWatcher(d), config.OptionDiscoveryAddress(cfg.Address)} go func() { for { select { case <-time.After(hb): if err := d.Register(cfg.Address + ":0"); err != nil { logrus.Warn(err) } } } }() return options, nil }
// Initialize the discovery service. func createDiscovery(uri string, c *cli.Context, discoveryOpt []string) discovery.Backend { hb, err := time.ParseDuration(c.String("heartbeat")) if err != nil { log.Fatalf("invalid --heartbeat: %v", err) } if hb < 1*time.Second { log.Fatal("--heartbeat should be at least one second") } // Set up discovery. discovery, err := discovery.New(uri, hb, 0, getDiscoveryOpt(c)) if err != nil { log.Fatal(err) } return discovery }
func TestNew(t *testing.T) { d, err := discovery.New("file:///path/to/file", 0, 0) assert.NoError(t, err) assert.Equal(t, d.(*Discovery).path, "/path/to/file") }
func (s *DiscoverySuite) TestNew(c *check.C) { d, err := discovery.New("file:///path/to/file", 0, 0, nil) c.Assert(err, check.IsNil) c.Assert(d.(*Discovery).path, check.Equals, "/path/to/file") }