Re-work how debugger CLI opts are registered

CLI options must be registered before the command line is parsed or a
cfg.ArgsAlreadyParsedError is raised.

Since commit 2cbea24 we are registering two 'remote_debug' arguments
in nova.service. In commit b506529, we see a hack being added to
ensure that nova.service is imported and the CLI opts registered
before config.parse_args() is called.

To clean this up somewhat, refactor all the elements of this remote
debugger support into nova.debugger. Avoid importing modules at
module import time since we need to import this before monkey
patching. Add a function for registering the CLI options just before
config.parse_args() is called. And fail gracefully if the CLI options
aren't registered when we called debugger.init().

Note that because the options aren't registered at module import time
any more, the config generator doesn't pick them up. However, that's
actually a good thing since this support doesn't work if you enable it
via config files since debugger.enabled() only looks at the command
line.

DocImpact: remote_debug options are not available via the config file,
only via the command line.

Change-Id: I97f747a2fb9222137203657df1d86ba89f3219e2
This commit is contained in:
Mark McLoughlin 2014-02-18 07:48:07 +00:00
parent f5eb59b897
commit 0861fc2d22
5 changed files with 87 additions and 38 deletions

View File

@ -30,8 +30,9 @@ if ('eventlet' in sys.modules and
os.environ['EVENTLET_NO_GREENDNS'] = 'yes'
import eventlet
from nova import debugger
if '--remote_debug-host' in sys.argv and '--remote_debug-port' in sys.argv:
if debugger.enabled():
# turn off thread patching to enable the remote debugger
eventlet.monkey_patch(os=False, thread=False)
else:

View File

@ -17,6 +17,7 @@
from oslo.config import cfg
from nova import debugger
from nova.openstack.common.db import options
from nova import paths
from nova import rpc
@ -29,6 +30,7 @@ def parse_args(argv, default_config_files=None):
options.set_defaults(sql_connection=_DEFAULT_SQL_CONNECTION,
sqlite_db='nova.sqlite')
rpc.set_defaults(control_exchange='nova')
debugger.register_cli_opts()
cfg.CONF(argv[1:],
project='nova',
version=version.version_string(),

80
nova/debugger.py Normal file
View File

@ -0,0 +1,80 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# Copyright 2011 Justin Santa Barbara
# 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.
# NOTE(markmc): this is imported before monkey patching in nova.cmd
# so we avoid extra imports here
import sys
def enabled():
return ('--remote_debug-host' in sys.argv and
'--remote_debug-port' in sys.argv)
def register_cli_opts():
from oslo.config import cfg
cli_opts = [
cfg.StrOpt('host',
help='Debug host (IP or name) to connect. Note '
'that using the remote debug option changes how '
'Nova uses the eventlet library to support async IO. '
'This could result in failures that do not occur '
'under normal operation. Use at your own risk.'),
cfg.IntOpt('port',
help='Debug port to connect. Note '
'that using the remote debug option changes how '
'Nova uses the eventlet library to support async IO. '
'This could result in failures that do not occur '
'under normal operation. Use at your own risk.')
]
cfg.CONF.register_cli_opts(cli_opts, 'remote_debug')
def init():
from oslo.config import cfg
CONF = cfg.CONF
# NOTE(markmc): gracefully handle the CLI options not being registered
if 'remote_debug' not in CONF:
return
if not (CONF.remote_debug.host and CONF.remote_debug.port):
return
from nova.openstack.common.gettextutils import _
from nova.openstack.common import log as logging
LOG = logging.getLogger(__name__)
LOG.debug(_('Listening on %(host)s:%(port)s for debug connection'),
{'host': CONF.remote_debug.host,
'port': CONF.remote_debug.port})
from pydev import pydevd
pydevd.settrace(host=CONF.remote_debug.host,
port=CONF.remote_debug.port,
stdoutToServer=False,
stderrToServer=False)
LOG.warn(_('WARNING: Using the remote debug option changes how '
'Nova uses the eventlet library to support async IO. This '
'could result in failures that do not occur under normal '
'operation. Use at your own risk.'))

View File

@ -27,6 +27,7 @@ from oslo import messaging
from nova import baserpc
from nova import conductor
from nova import context
from nova import debugger
from nova import exception
from nova.objects import base as objects_base
from nova.openstack.common.gettextutils import _
@ -112,27 +113,9 @@ service_opts = [
help='Maximum time since last check-in for up service'),
]
cli_opts = [
cfg.StrOpt('host',
help='Debug host (IP or name) to connect. Note '
'that using the remote debug option changes how '
'Nova uses the eventlet library to support async IO. '
'This could result in failures that do not occur '
'under normal operation. Use at your own risk.'),
cfg.IntOpt('port',
help='Debug port to connect. Note '
'that using the remote debug option changes how '
'Nova uses the eventlet library to support async IO. '
'This could result in failures that do not occur '
'under normal operation. Use at your own risk.')
]
CONF = cfg.CONF
CONF.register_opts(service_opts)
CONF.import_opt('host', 'nova.netconf')
CONF.register_cli_opts(cli_opts, 'remote_debug')
class Service(service.Service):
@ -279,20 +262,8 @@ class Service(service.Service):
periodic_enable = CONF.periodic_enable
if periodic_fuzzy_delay is None:
periodic_fuzzy_delay = CONF.periodic_fuzzy_delay
if CONF.remote_debug.host and CONF.remote_debug.port:
from pydev import pydevd
LOG = logging.getLogger('nova')
LOG.debug(_('Listening on %(host)s:%(port)s for debug connection'),
{'host': CONF.remote_debug.host,
'port': CONF.remote_debug.port})
pydevd.settrace(host=CONF.remote_debug.host,
port=CONF.remote_debug.port,
stdoutToServer=False,
stderrToServer=False)
LOG.warn(_('WARNING: Using the remote debug option changes how '
'Nova uses the eventlet library to support async IO. This '
'could result in failures that do not occur under normal '
'operation. Use at your own risk.'))
debugger.init()
service_obj = cls(host, binary, topic, manager,
report_interval=report_interval,

View File

@ -31,11 +31,6 @@ from nova import config
from nova import context
from nova import db
from nova import exception
# NOTE(philip-schwartz) Added service import to fix issue where importing
# xenapi service would cause an ArgsAlreadyParsedError exception
from nova import service
from nova.openstack.common import timeutils
from nova.virt import virtapi
from nova.virt.xenapi import driver as xenapi_driver