X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/b42ea9ed7231b1ed42741c745ad153defe7d0f99..14970c323143a79d33a0e49edfcf002aa713dcdb:/lib/daemon.py diff --git a/lib/daemon.py b/lib/daemon.py index eceeac4..6d6bd74 100644 --- a/lib/daemon.py +++ b/lib/daemon.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2006, 2007, 2008, 2010 Google Inc. +# Copyright (C) 2006, 2007, 2008, 2010, 2011 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -40,6 +40,7 @@ from ganeti import errors from ganeti import netutils from ganeti import ssconf from ganeti import runtime +from ganeti import compat class SchedulerBreakout(Exception): @@ -491,8 +492,8 @@ class Mainloop(object): def _VerifyDaemonUser(daemon_name): """Verifies the process uid matches the configured uid. - This method verifies that a daemon is started as the user it is intended to be - run + This method verifies that a daemon is started as the user it is + intended to be run @param daemon_name: The name of daemon to be started @return: A tuple with the first item indicating success or not, @@ -512,6 +513,44 @@ def _VerifyDaemonUser(daemon_name): daemon_uids[daemon_name]) +def _BeautifyError(err): + """Try to format an error better. + + Since we're dealing with daemon startup errors, in many cases this + will be due to socket error and such, so we try to format these cases better. + + @param err: an exception object + @rtype: string + @return: the formatted error description + + """ + try: + if isinstance(err, socket.error): + return "Socket-related error: %s (errno=%s)" % (err.args[1], err.args[0]) + elif isinstance(err, EnvironmentError): + if err.filename is None: + return "%s (errno=%s)" % (err.strerror, err.errno) + else: + return "%s (file %s) (errno=%s)" % (err.strerror, err.filename, + err.errno) + else: + return str(err) + except Exception: # pylint: disable-msg=W0703 + logging.exception("Error while handling existing error %s", err) + return "%s" % str(err) + + +def _HandleSigHup(reopen_cb, signum, frame): # pylint: disable-msg=W0613 + """Handler for SIGHUP. + + @param reopen_cb: Callback function for reopening log files + + """ + assert callable(reopen_cb) + logging.info("Reopening log files after receiving SIGHUP") + reopen_cb() + + def GenericMain(daemon_name, optionparser, check_fn, prepare_fn, exec_fn, multithreaded=False, console_logging=False, @@ -593,7 +632,8 @@ def GenericMain(daemon_name, optionparser, metavar="SSL_CERT_PATH") # Disable the use of fork(2) if the daemon uses threads - utils.no_fork = multithreaded + if multithreaded: + utils.DisableFork() options, args = optionparser.parse_args() @@ -624,23 +664,38 @@ def GenericMain(daemon_name, optionparser, if options.fork: utils.CloseFDs() - utils.Daemonize(logfile=constants.DAEMONS_LOGFILES[daemon_name]) + wpipe = utils.Daemonize(logfile=constants.DAEMONS_LOGFILES[daemon_name]) + else: + wpipe = None - utils.WritePidFile(utils.DaemonPidFileName(daemon_name)) - try: - utils.SetupLogging(logfile=constants.DAEMONS_LOGFILES[daemon_name], + log_reopen_fn = \ + utils.SetupLogging(constants.DAEMONS_LOGFILES[daemon_name], daemon_name, debug=options.debug, stderr_logging=not options.fork, multithreaded=multithreaded, - program=daemon_name, syslog=options.syslog, console_logging=console_logging) - logging.info("%s daemon startup", daemon_name) - if callable(prepare_fn): - prep_results = prepare_fn(options, args) - else: - prep_results = None + + # Reopen log file(s) on SIGHUP + signal.signal(signal.SIGHUP, compat.partial(_HandleSigHup, log_reopen_fn)) + + utils.WritePidFile(utils.DaemonPidFileName(daemon_name)) + try: + try: + logging.info("%s daemon startup", daemon_name) + if callable(prepare_fn): + prep_results = prepare_fn(options, args) + else: + prep_results = None + except Exception, err: + utils.WriteErrorToFD(wpipe, _BeautifyError(err)) + raise + + if wpipe is not None: + # we're done with the preparation phase, we close the pipe to + # let the parent know it's safe to exit + os.close(wpipe) exec_fn(options, args, prep_results) finally: - utils.RemovePidFile(daemon_name) + utils.RemoveFile(utils.DaemonPidFileName(daemon_name))