// 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() }
// Daemon starts the volplugin service. func (dc *DaemonConfig) Daemon() error { global, err := dc.Client.GetGlobal() if err != nil { logrus.Errorf("Error fetching global configuration: %v", err) logrus.Infof("No global configuration. Proceeding with defaults...") global = config.NewGlobalConfig() } dc.Global = global errored.AlwaysDebug = dc.Global.Debug errored.AlwaysTrace = dc.Global.Debug if dc.Global.Debug { logrus.SetLevel(logrus.DebugLevel) } go info.HandleDebugSignal() activity := make(chan *watch.Watch) dc.Client.WatchGlobal(activity) go func() { for { dc.Global = (<-activity).Config.(*config.Global) logrus.Debugf("Received global %#v", dc.Global) errored.AlwaysDebug = dc.Global.Debug errored.AlwaysTrace = dc.Global.Debug if dc.Global.Debug { logrus.SetLevel(logrus.DebugLevel) } } }() dc.API = api.NewAPI(docker.NewVolplugin(), dc.Hostname, dc.Client, &dc.Global) if err := dc.updateMounts(); err != nil { return err } go dc.pollRuntime() driverPath := path.Join(basePath, fmt.Sprintf("%s.sock", dc.PluginName)) if err := os.Remove(driverPath); err != nil && !os.IsNotExist(err) { return err } if err := os.MkdirAll(basePath, 0700); err != nil { return err } l, err := net.ListenUnix("unix", &net.UnixAddr{Name: driverPath, Net: "unix"}) if err != nil { return err } srv := http.Server{Handler: dc.API.Router(dc.API)} srv.SetKeepAlivesEnabled(false) if err := srv.Serve(l); err != nil { logrus.Fatalf("Fatal error serving volplugin: %v", err) } l.Close() return os.Remove(driverPath) }
// Daemon initializes the daemon for use. func (d *DaemonConfig) Daemon(listen string) { global, err := d.Config.GetGlobal() if err != nil { logrus.Errorf("Error fetching global configuration: %v", err) logrus.Infof("No global configuration. Proceeding with defaults...") global = config.NewGlobalConfig() } d.Global = global if d.Global.Debug { logrus.SetLevel(logrus.DebugLevel) } errored.AlwaysDebug = d.Global.Debug errored.AlwaysTrace = d.Global.Debug go info.HandleDebugSignal() go info.HandleDumpTarballSignal(d.Config) activity := make(chan *watch.Watch) d.Config.WatchGlobal(activity) go func() { for { d.Global = (<-activity).Config.(*config.Global) errored.AlwaysDebug = d.Global.Debug errored.AlwaysTrace = d.Global.Debug if d.Global.Debug { logrus.SetLevel(logrus.DebugLevel) } } }() r := mux.NewRouter() postRouter := map[string]func(http.ResponseWriter, *http.Request){ "/global": d.handleGlobalUpload, "/volumes/create": d.handleCreate, "/volumes/copy": d.handleCopy, "/volumes/request": d.handleRequest, "/policies/{policy}": d.handlePolicyUpload, "/runtime/{policy}/{volume}": d.handleRuntimeUpload, "/snapshots/take/{policy}/{volume}": d.handleSnapshotTake, } if err := addRoute(r, postRouter, "POST", d.Global.Debug); err != nil { logrus.Fatalf("Error starting apiserver: %v", err) } deleteRouter := map[string]func(http.ResponseWriter, *http.Request){ "/volumes/remove": d.handleRemove, "/volumes/removeforce": d.handleRemoveForce, "/policies/{policy}": d.handlePolicyDelete, } if err := addRoute(r, deleteRouter, "DELETE", d.Global.Debug); err != nil { logrus.Fatalf("Error starting apiserver: %v", err) } getRouter := map[string]func(http.ResponseWriter, *http.Request){ "/global": d.handleGlobal, "/policy-archives/{policy}": d.handlePolicyListRevisions, "/policy-archives/{policy}/{revision}": d.handlePolicyGetRevision, "/policies": d.handlePolicyList, "/policies/{policy}": d.handlePolicy, "/uses/mounts/{policy}/{volume}": d.handleUsesMountsVolume, "/uses/snapshots/{policy}/{volume}": d.handleUsesMountsSnapshots, "/volumes": d.handleListAll, "/volumes/{policy}": d.handleList, "/volumes/{policy}/{volume}": d.handleGet, "/runtime/{policy}/{volume}": d.handleRuntime, "/snapshots/{policy}/{volume}": d.handleSnapshotList, } if err := addRoute(r, getRouter, "GET", d.Global.Debug); err != nil { logrus.Fatalf("Error starting apiserver: %v", err) } if d.Global.Debug { r.HandleFunc("{action:.*}", d.handleDebug) } if err := http.ListenAndServe(listen, r); err != nil { logrus.Fatalf("Error starting apiserver: %v", err) } }