9c2029a801
Get latest service module from Oslo to prepare for multi-process API service implementation.
Below are the commits included in this pull.
Changes being pulled into in service module are:
* e7bc8c9 2013-11-20 | Merge "os._exit in _start_child may cause unexpected exception"
* 96a2d4e 2013-11-07 | os._exit in _start_child may cause unexpected exception
* 1771a77 2013-11-05 | Adjust import order according to PEP8 imports rule
* 3110c0f 2013-10-17 | Use multiprocessing.Event to ensure services have started
* b5fba9e 2013-09-18 | Move comment in service.py to correct location
* 11cc74f 2013-08-26 | Fixes issue with SUGHUP in services on Windows
* 825ace5 2013-06-17 | Add service restart function in oslo-incubator
* c935d1c 2013-07-16 | Merge "Allow launchers to be stopped multiple times"
* dc8aa79 2013-07-08 | Allow launchers to be stopped multiple times
* 1a2df89 2013-06-25 | Enable H302 hacking check
* 52e857a 2013-06-19 | Ignore any exceptions from rpc.cleanup().
* 5518ad3 2013-05-16 | Add graceful service shutdown support to Launcher
And these dependent modules
- cinder/openstack/common/eventlet_backdoor.py
* 1dcc747 2013-07-15 | Fix stylistic problems with help text
* 1a2df89 2013-06-25 | Enable H302 hacking check
* c7c55b2 2013-06-20 | Improve usability when backdoor_port is nonzero
- cinder/openstack/common/gettextutils.py
* 3970d46 2013-11-02 | Fix typos in oslo
* 88db9c8 2013-10-03 | When translating if no locale is given use default locale
- cinder/openstack/common/jsonutils.py
* 3d7504b 2013-09-23 | Ensure that Message objects will be sent via RPC in unicode format
* 1807d32 2013-08-22 | jsonutils: make types py3 compatible
* bdef862 2013-08-22 | jsonutils: do not require xmlrpclib
* ded9bd6 2013-08-04 | Make dependency on netaddr optional
* 7b7566b 2013-06-25 | Add netaddr.IPAddress support to to_primitive()
- cinder/openstack/common/local.py
* cb2a2b6
2013-06-28 | Modify local.py to not be dependent on Eventlet
* 547ab34 2013-03-11 | Fix Copyright Headers - Rename LLC to Foundation
- cinder/openstack/common/log.py
* a82e889 2013-11-14 | Merge "Do not name variables as builtins"
* 2251cb5 2013-11-13 | Do not name variables as builtins
* 25c5854 2013-11-13 | Adds admin_password as key to be sanitized when logging
* cbfded9 2013-11-11 | Default iso8601 logging to WARN
* 76b0cd1 2013-11-04 | Add mask password impl from other projects
- cinder/openstack/common/loopingcall.py
* 1a2df89 2013-06-25 | Enable H302 hacking check
- cinder/openstack/common/threadgroup.py
* 9d3c34b 2013-10-25 | Add a link method to Thread
* 1a2df89 2013-06-25 | Enable H302 hacking check
- cinder/openstack/common/timeutils.py
* f3b5f17 2013-11-12 | Add helper method total_seconds in timeutils.py
* 53ebd30 2013-10-18 | python3: use six.text_types for unicode()
* 3bc6f79 2013-09-19 | Fix timeutils.set_override_time not defaulting to current wall time
* af76064 2013-08-29 | Optimize timeutils.utcnow_ts()
* df3f2ba 2013-07-26 | BaseException.message is deprecated since Python 2.6
* d28fa69 2013-06-27 | python3: Add python3 compatibility.
Partial bp: multi-process-api-service
Change-Id: Ifd25eae9eb2d6ae53bcf1665c3d5b7db4144433c
147 lines
4.7 KiB
Python
147 lines
4.7 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright (c) 2012 OpenStack Foundation.
|
|
# Administrator of the National Aeronautics and Space Administration.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from __future__ import print_function
|
|
|
|
import errno
|
|
import gc
|
|
import os
|
|
import pprint
|
|
import socket
|
|
import sys
|
|
import traceback
|
|
|
|
import eventlet
|
|
import eventlet.backdoor
|
|
import greenlet
|
|
from oslo.config import cfg
|
|
|
|
from cinder.openstack.common.gettextutils import _ # noqa
|
|
from cinder.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 that port "
|
|
"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.StrOpt('backdoor_port',
|
|
default=None,
|
|
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():
|
|
print("Don't use this, just disconnect instead")
|
|
|
|
|
|
def _find_objects(t):
|
|
return filter(lambda o: isinstance(o, t), gc.get_objects())
|
|
|
|
|
|
def _print_greenthreads():
|
|
for i, gt in enumerate(_find_objects(greenlet.greenlet)):
|
|
print(i, gt)
|
|
traceback.print_stack(gt.gr_frame)
|
|
print()
|
|
|
|
|
|
def _print_nativethreads():
|
|
for threadId, stack in sys._current_frames().items():
|
|
print(threadId)
|
|
traceback.print_stack(stack)
|
|
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
|
|
'quit': _dont_use_this, # So we don't exit the entire process
|
|
'fo': _find_objects,
|
|
'pgt': _print_greenthreads,
|
|
'pnt': _print_nativethreads,
|
|
}
|
|
|
|
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
|
|
# since it won't interact poorly with gettext, and it's easier to
|
|
# read the output too.
|
|
def displayhook(val):
|
|
if val is not None:
|
|
pprint.pprint(val)
|
|
sys.displayhook = displayhook
|
|
|
|
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
|