#
#
-# 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
from ganeti import netutils
from ganeti import ssconf
from ganeti import runtime
+from ganeti import compat
class SchedulerBreakout(Exception):
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,
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,
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()
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))