summaryrefslogtreecommitdiffstats
path: root/openstack
diff options
context:
space:
mode:
Diffstat (limited to 'openstack')
-rw-r--r--openstack/common/eventlet_backdoor.py63
-rw-r--r--openstack/common/rootwrap/filters.py3
-rw-r--r--openstack/common/rootwrap/wrapper.py4
-rw-r--r--openstack/common/timeutils.py5
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)