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  }