import sched
import time
import socket
+import select
import sys
from ganeti import utils
constants.MAX_UDP_DATA_SIZE))
self._out_queue.append((ip, port, payload))
+ def process_next_packet(self, timeout=0):
+ """Process the next datagram, waiting for it if necessary.
+
+ @type timeout: float
+ @param timeout: how long to wait for data
+ @rtype: boolean
+ @return: True if some data has been handled, False otherwise
+
+ """
+ result = utils.WaitForFdCondition(self, select.POLLIN, timeout)
+ if result is not None and result & select.POLLIN:
+ self.do_read()
+ return True
+ else:
+ return False
+
class Mainloop(object):
"""Generic mainloop for daemons
self._signal_wait.append(owner)
-def GenericMain(daemon_name, optionparser, dirs, check_fn, exec_fn):
+def GenericMain(daemon_name, optionparser, dirs, check_fn, exec_fn,
+ multithreaded=False,
+ default_ssl_cert=None, default_ssl_key=None):
"""Shared main function for daemons.
@type daemon_name: string
@type exec_fn: function which accepts (options, args)
@param exec_fn: function that's executed with the daemon's pid file held, and
runs the daemon itself.
+ @type multithreaded: bool
+ @param multithreaded: Whether the daemon uses threads
+ @type default_ssl_cert: string
+ @param default_ssl_cert: Default SSL certificate path
+ @type default_ssl_key: string
+ @param default_ssl_key: Default SSL key path
"""
optionparser.add_option("-f", "--foreground", dest="fork",
constants.SYSLOG_USAGE,
default=constants.SYSLOG_USAGE,
choices=["no", "yes", "only"])
+
if daemon_name in constants.DAEMONS_PORTS:
- # for networked daemons we also allow choosing the bind port and address.
- # by default we use the port provided by utils.GetDaemonPort, and bind to
- # 0.0.0.0 (which is represented by and empty bind address.
- port = utils.GetDaemonPort(daemon_name)
+ default_bind_address = "0.0.0.0"
+ default_port = utils.GetDaemonPort(daemon_name)
+
+ # For networked daemons we allow choosing the port and bind address
optionparser.add_option("-p", "--port", dest="port",
- help="Network port (%s default)." % port,
- default=port, type="int")
+ help="Network port (default: %s)" % default_port,
+ default=default_port, type="int")
optionparser.add_option("-b", "--bind", dest="bind_address",
- help="Bind address",
- default="", metavar="ADDRESS")
+ help=("Bind address (default: %s)" %
+ default_bind_address),
+ default=default_bind_address, metavar="ADDRESS")
- if daemon_name in constants.DAEMONS_SSL:
- default_cert, default_key = constants.DAEMONS_SSL[daemon_name]
+ if default_ssl_key is not None and default_ssl_cert is not None:
optionparser.add_option("--no-ssl", dest="ssl",
help="Do not secure HTTP protocol with SSL",
default=True, action="store_false")
optionparser.add_option("-K", "--ssl-key", dest="ssl_key",
- help="SSL key",
- default=default_key, type="string")
+ help=("SSL key path (default: %s)" %
+ default_ssl_key),
+ default=default_ssl_key, type="string",
+ metavar="SSL_KEY_PATH")
optionparser.add_option("-C", "--ssl-cert", dest="ssl_cert",
- help="SSL certificate",
- default=default_cert, type="string")
+ help=("SSL certificate path (default: %s)" %
+ default_ssl_cert),
+ default=default_ssl_cert, type="string",
+ metavar="SSL_CERT_PATH")
- multithread = utils.no_fork = daemon_name in constants.MULTITHREADED_DAEMONS
+ # Disable the use of fork(2) if the daemon uses threads
+ utils.no_fork = multithreaded
options, args = optionparser.parse_args()
- if hasattr(options, 'ssl') and options.ssl:
- if not (options.ssl_cert and options.ssl_key):
- print >> sys.stderr, "Need key and certificate to use ssl"
- sys.exit(constants.EXIT_FAILURE)
- for fname in (options.ssl_cert, options.ssl_key):
- if not os.path.isfile(fname):
- print >> sys.stderr, "Need ssl file %s to run" % fname
+ if getattr(options, "ssl", False):
+ ssl_paths = {
+ "certificate": options.ssl_cert,
+ "key": options.ssl_key,
+ }
+
+ for name, path in ssl_paths.iteritems():
+ if not os.path.isfile(path):
+ print >> sys.stderr, "SSL %s file '%s' was not found" % (name, path)
sys.exit(constants.EXIT_FAILURE)
+ # TODO: By initiating http.HttpSslParams here we would only read the files
+ # once and have a proper validation (isfile returns False on directories)
+ # at the same time.
+
if check_fn is not None:
check_fn(options, args)
utils.SetupLogging(logfile=constants.DAEMONS_LOGFILES[daemon_name],
debug=options.debug,
stderr_logging=not options.fork,
- multithreaded=multithread,
+ multithreaded=multithreaded,
program=daemon_name,
syslog=options.syslog)
logging.info("%s daemon startup", daemon_name)