github.com/rohankumardubey/proxyfs@v0.0.0-20210108201508-653efa9ab00e/proxyfsd/daemon.go (about) 1 package proxyfsd 2 3 import ( 4 "fmt" 5 _ "net/http/pprof" 6 "os" 7 "os/signal" 8 "strings" 9 "sync" 10 11 "golang.org/x/sys/unix" 12 13 "github.com/swiftstack/ProxyFS/conf" 14 "github.com/swiftstack/ProxyFS/logger" 15 "github.com/swiftstack/ProxyFS/transitions" 16 "github.com/swiftstack/ProxyFS/version" 17 18 // Force importing of the following "top-most" package 19 _ "github.com/swiftstack/ProxyFS/httpserver" 20 ) 21 22 // Daemon is launched as a GoRoutine that launches ProxyFS. During startup, the parent should read errChan 23 // to await Daemon getting to the point where it is ready to handle the specified signal set. Any errors 24 // encountered before or after this point will be sent to errChan (and be non-nil of course). 25 func Daemon(confFile string, confStrings []string, errChan chan error, wg *sync.WaitGroup, execArgs []string, signals ...os.Signal) { 26 var ( 27 confMap conf.ConfMap 28 err error 29 signalReceived os.Signal 30 ) 31 32 // Compute confMap 33 34 confMap, err = conf.MakeConfMapFromFile(confFile) 35 if nil != err { 36 errChan <- err 37 38 return 39 } 40 41 err = confMap.UpdateFromStrings(confStrings) 42 if nil != err { 43 errChan <- err 44 45 return 46 } 47 48 // Start up dæmon packages 49 50 err = transitions.Up(confMap) 51 if nil != err { 52 errChan <- err 53 return 54 } 55 wg.Add(1) 56 logger.Infof("proxyfsd is starting up (version %s) (PID %d); invoked as '%s'", 57 version.ProxyFSVersion, os.Getpid(), strings.Join(execArgs, "' '")) 58 defer func() { 59 logger.Infof("proxyfsd logger is shutting down (PID %d)", os.Getpid()) 60 err = transitions.Down(confMap) 61 if nil != err { 62 logger.Errorf("transitions.Down() failed: %v", err) // Oddly, if logger.Down() fails, will this work? 63 } 64 errChan <- err 65 wg.Done() 66 }() 67 68 // Arm signal handler used to indicate termination and wait on it 69 // 70 // Note: signalled chan must be buffered to avoid race with window between 71 // arming handler and blocking on the chan read 72 73 signalChan := make(chan os.Signal, 8) 74 75 // if signals is empty it means "catch all signals" its possible to catch 76 signal.Notify(signalChan, signals...) 77 78 // indicate signal handlers have been armed successfully 79 errChan <- nil 80 81 // Await a signal - reloading confFile each SIGHUP - exiting otherwise 82 for { 83 signalReceived = <-signalChan 84 logger.Infof("Received signal: '%v'", signalReceived) 85 86 // these signals are normally ignored, but if "signals..." above is empty 87 // they are delivered via the channel. we should simply ignore them. 88 if signalReceived == unix.SIGCHLD || signalReceived == unix.SIGURG || 89 signalReceived == unix.SIGWINCH || signalReceived == unix.SIGCONT { 90 logger.Infof("Ignored signal: '%v'", signalReceived) 91 continue 92 } 93 94 // we can get SIGPIPE whenever an HTTP or other client closes a 95 // socket on us, so ignore it 96 if signalReceived == unix.SIGPIPE { 97 logger.Infof("Ignored signal: '%v'", signalReceived) 98 continue 99 } 100 101 // SIGHUP means reconfig but any other signal means time to exit 102 if unix.SIGHUP != signalReceived { 103 logger.Infof("signal catcher is shutting down proxyfsd (PID %d)", os.Getpid()) 104 105 if signalReceived != unix.SIGTERM && signalReceived != unix.SIGINT { 106 logger.Errorf("proxyfsd received unexpected signal: %v", signalReceived) 107 } 108 109 return 110 } 111 112 // caught SIGHUP -- recompute confMap and re-apply 113 confMap, err = conf.MakeConfMapFromFile(confFile) 114 if nil != err { 115 err = fmt.Errorf("failed to load updated config: %v", err) 116 errChan <- err 117 return 118 } 119 120 err = confMap.UpdateFromStrings(confStrings) 121 if nil != err { 122 err = fmt.Errorf("failed to reapply config overrides: %v", err) 123 errChan <- err 124 return 125 } 126 127 err = transitions.Signaled(confMap) 128 if nil != err { 129 err = fmt.Errorf("transitions.Signaled() failed: %v", err) 130 errChan <- err 131 return 132 } 133 } 134 }