// Daemon is the top-level entrypoint for the volsupervisor from the CLI. func Daemon(ctx *cli.Context) { cfg, err := config.NewClient(ctx.String("prefix"), ctx.StringSlice("etcd")) if err != nil { logrus.Fatal(err) } retry: global, err := cfg.GetGlobal() if err != nil { logrus.Errorf("Could not retrieve global configuration: %v. Retrying in 1 second", err) time.Sleep(time.Second) goto retry } dc := &DaemonConfig{Config: cfg, Global: global, Hostname: ctx.String("host-label")} dc.setDebug() globalChan := make(chan *watch.Watch) dc.Config.WatchGlobal(globalChan) go dc.watchAndSetGlobal(globalChan) go info.HandleDebugSignal() stopChan, err := lock.NewDriver(dc.Config).AcquireWithTTLRefresh(&config.UseVolsupervisor{Hostname: dc.Hostname}, dc.Global.TTL, dc.Global.Timeout) if err != nil { logrus.Fatal("Could not start volsupervisor: already in use") } sigChan := make(chan os.Signal, 1) go func() { <-sigChan logrus.Infof("Removing volsupervisor global lock; waiting %v for lock to clear", dc.Global.TTL) stopChan <- struct{}{} time.Sleep(wait.Jitter(dc.Global.TTL+time.Second, 0)) // give us enough time to try to clear the lock os.Exit(0) }() signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT) dc.signalSnapshot() dc.updateVolumes() // doing it here ensures the goroutine is created when the first poll completes. go func() { for { time.Sleep(wait.Jitter(time.Second, 0)) dc.updateVolumes() } }() dc.loop() }
// AcquireAndRefresh starts a goroutine to refresh the key every 1/4 // (jittered) of the TTL. A stop channel is returned which, when sent a // struct, will terminate the refresh. Error is returned for anything that // might occur while setting up the goroutine. // // Do not use Free to free these locks, it will not work! Use the stop // channel. func (c *Client) AcquireAndRefresh(lock db.Lock, ttl time.Duration) (chan struct{}, error) { logrus.Debugf("In refresh, performing preliminary permanent lock on %v", lock) if err := c.Acquire(lock); err != nil { return nil, err } stopChan := make(chan struct{}) go func() { for { select { case <-stopChan: if err := c.Free(lock, false); err != nil { logrus.Errorf("Error freeing lock %q: %v", lock, err) } return default: time.Sleep(wait.Jitter(ttl/4, 0)) if err := c.AcquireWithTTL(lock, ttl); err != nil { logrus.Errorf("Could not acquire lock %v: %v", lock, err) } } } }() return stopChan, nil }