diff options
Diffstat (limited to 'openstack')
-rw-r--r-- | openstack/common/eventlet_backdoor.py | 63 | ||||
-rw-r--r-- | openstack/common/rootwrap/filters.py | 3 | ||||
-rw-r--r-- | openstack/common/rootwrap/wrapper.py | 4 | ||||
-rw-r--r-- | openstack/common/timeutils.py | 5 |
4 files changed, 68 insertions, 7 deletions
diff --git a/openstack/common/eventlet_backdoor.py b/openstack/common/eventlet_backdoor.py index 57b89ae..f2102d6 100644 --- a/openstack/common/eventlet_backdoor.py +++ b/openstack/common/eventlet_backdoor.py @@ -18,8 +18,11 @@ from __future__ import print_function +import errno import gc +import os import pprint +import socket import sys import traceback @@ -28,14 +31,34 @@ import eventlet.backdoor import greenlet from oslo.config import cfg +from openstack.common.gettextutils import _ +from openstack.common import log as logging + +help_for_backdoor_port = 'Acceptable ' + \ + 'values are 0, <port> and <start>:<end>, where 0 results in ' + \ + 'listening on a random tcp port number, <port> results in ' + \ + 'listening on the specified port number and not enabling backdoor' + \ + 'if it is in use and <start>:<end> results in listening on the ' + \ + 'smallest unused port number within the specified range of port ' + \ + 'numbers. The chosen port is displayed in the service\'s log file.' eventlet_backdoor_opts = [ - cfg.IntOpt('backdoor_port', + cfg.StrOpt('backdoor_port', default=None, - help='port for eventlet backdoor to listen') + help='Enable eventlet backdoor. %s' % help_for_backdoor_port) ] CONF = cfg.CONF CONF.register_opts(eventlet_backdoor_opts) +LOG = logging.getLogger(__name__) + + +class EventletBackdoorConfigValueError(Exception): + def __init__(self, port_range, help_msg, ex): + msg = ('Invalid backdoor_port configuration %(range)s: %(ex)s. ' + '%(help)s' % + {'range': port_range, 'ex': ex, 'help': help_msg}) + super(EventletBackdoorConfigValueError, self).__init__(msg) + self.port_range = port_range def _dont_use_this(): @@ -60,6 +83,33 @@ def _print_nativethreads(): print() +def _parse_port_range(port_range): + if ':' not in port_range: + start, end = port_range, port_range + else: + start, end = port_range.split(':', 1) + try: + start, end = int(start), int(end) + if end < start: + raise ValueError + return start, end + except ValueError as ex: + raise EventletBackdoorConfigValueError(port_range, ex, + help_for_backdoor_port) + + +def _listen(host, start_port, end_port, listen_func): + try_port = start_port + while True: + try: + return listen_func((host, try_port)) + except socket.error as exc: + if (exc.errno != errno.EADDRINUSE or + try_port >= end_port): + raise + try_port += 1 + + def initialize_if_enabled(): backdoor_locals = { 'exit': _dont_use_this, # So we don't exit the entire process @@ -72,6 +122,8 @@ def initialize_if_enabled(): if CONF.backdoor_port is None: return None + start_port, end_port = _parse_port_range(str(CONF.backdoor_port)) + # NOTE(johannes): The standard sys.displayhook will print the value of # the last expression and set it to __builtin__._, which overwrites # the __builtin__._ that gettext sets. Let's switch to using pprint @@ -82,8 +134,13 @@ def initialize_if_enabled(): pprint.pprint(val) sys.displayhook = displayhook - sock = eventlet.listen(('localhost', CONF.backdoor_port)) + sock = _listen('localhost', start_port, end_port, eventlet.listen) + + # In the case of backdoor port being zero, a port number is assigned by + # listen(). In any case, pull the port number out here. port = sock.getsockname()[1] + LOG.info(_('Eventlet backdoor listening on %(port)s for process %(pid)d') % + {'port': port, 'pid': os.getpid()}) eventlet.spawn_n(eventlet.backdoor.backdoor_server, sock, locals=backdoor_locals) return port diff --git a/openstack/common/rootwrap/filters.py b/openstack/common/rootwrap/filters.py index dfec412..b40fdfd 100644 --- a/openstack/common/rootwrap/filters.py +++ b/openstack/common/rootwrap/filters.py @@ -217,7 +217,8 @@ class KillFilter(CommandFilter): return (os.path.isabs(command) and kill_command == os.path.basename(command) and - os.path.dirname(command) in os.environ['PATH'].split(':')) + os.path.dirname(command) in os.environ.get('PATH', '' + ).split(':')) class ReadFileFilter(CommandFilter): diff --git a/openstack/common/rootwrap/wrapper.py b/openstack/common/rootwrap/wrapper.py index df1a9f4..6bd829e 100644 --- a/openstack/common/rootwrap/wrapper.py +++ b/openstack/common/rootwrap/wrapper.py @@ -46,8 +46,10 @@ class RootwrapConfig(object): if config.has_option("DEFAULT", "exec_dirs"): self.exec_dirs = config.get("DEFAULT", "exec_dirs").split(",") else: + self.exec_dirs = [] # Use system PATH if exec_dirs is not specified - self.exec_dirs = os.environ["PATH"].split(':') + if "PATH" in os.environ: + self.exec_dirs = os.environ['PATH'].split(':') # syslog_log_facility if config.has_option("DEFAULT", "syslog_log_facility"): diff --git a/openstack/common/timeutils.py b/openstack/common/timeutils.py index ac2441b..bd60489 100644 --- a/openstack/common/timeutils.py +++ b/openstack/common/timeutils.py @@ -23,6 +23,7 @@ import calendar import datetime import iso8601 +import six # ISO 8601 extended time format with microseconds @@ -75,14 +76,14 @@ def normalize_time(timestamp): def is_older_than(before, seconds): """Return True if before is older than seconds.""" - if isinstance(before, basestring): + if isinstance(before, six.string_types): before = parse_strtime(before).replace(tzinfo=None) return utcnow() - before > datetime.timedelta(seconds=seconds) def is_newer_than(after, seconds): """Return True if after is newer than seconds.""" - if isinstance(after, basestring): + if isinstance(after, six.string_types): after = parse_strtime(after).replace(tzinfo=None) return after - utcnow() > datetime.timedelta(seconds=seconds) |