diff --git a/doc/source/contributor/guides/remote-debugger.rst b/doc/source/contributor/guides/remote-debugger.rst index 8de56b8623..4db07e0f64 100644 --- a/doc/source/contributor/guides/remote-debugger.rst +++ b/doc/source/contributor/guides/remote-debugger.rst @@ -16,7 +16,7 @@ Debugging Octavia code ====================== This document describes how to setup and debug Octavia code using your favorite -IDE (e.g. PyCharm). +IDE (e.g. PyCharm, Visual Studio Code). Prerequisites ============= @@ -27,8 +27,10 @@ Prerequisites Setup ===== -Ensure your OpenStack and IDE environments have the PyDev library installed. If -you're using PyCharm, you can find it in +Ensure your OpenStack and IDE environments have the PyDev or ptvsd library +installed. + +If you're using PyCharm, you can find it in */path/to/pycharm/debug-eggs/pycharm-debug.egg* (Python 2) and */path/to/pycharm/debug-eggs/pycharm-debug-py3k.egg* (Python 3). Copy that file into your OpenStack host and install the library in your Python path: @@ -37,6 +39,11 @@ into your OpenStack host and install the library in your Python path: $ sudo easy_install pycharm-debug.egg +If using Visual Studio Code, simply install ptvsd in both environments: + +:: + + $ pip install ptvsd Create a remote debugging configuration in your IDE. In PyCharm, go to *Run -> Edit Configurations -> Python Remote Debug*. The local host name refers to the @@ -48,23 +55,25 @@ a path mapping in the remote debug configuration. Invoke the debug configuration (*Run -> Debug... -> (config name)*). PyCharm will begin listening on the specified host and port. -Export *PYDEV_DEBUG_HOST* and *PYDEV_DEBUG_PORT* (host and port of the system -running the IDE, respectively), and start the Octavia service you want to -debug. It is recommended to run only one uWSGI process/controller worker. -For example, to debug the Octavia Worker service: +Export *DEBUGGER_TYPE*, *DEBUGGER_HOST* and *DEBUGGER_PORT* (host and port of +the system running the IDE, respectively), and start the Octavia service you +want to debug. It is recommended to run only one uWSGI process/controller +worker. For example, to debug the Octavia Worker service: :: - $ export PYDEV_DEBUG_HOST=192.168.121.1 - $ export PYDEV_DEBUG_PORT=5678 + $ export DEBUGGER_TYPE=pydev + $ export DEBUGGER_HOST=192.168.121.1 + $ export DEBUGGER_PORT=5678 $ /usr/bin/octavia-worker --config-file /etc/octavia/octavia.conf -Another example is the Octavia API service: +Another example is debugging the Octavia API service with the ptvsd debugger: :: - $ export PYDEV_DEBUG_HOST=192.168.121.1 - $ export PYDEV_DEBUG_PORT=5678 + $ export DEBUGGER_TYPE=ptvsd + $ export DEBUGGER_HOST=192.168.121.1 + $ export DEBUGGER_PORT=5678 $ /usr/bin/uwsgi --ini /etc/octavia/octavia-uwsgi.ini -p 1 The service will connect to your IDE, at which point remote debugging is diff --git a/octavia/common/config.py b/octavia/common/config.py index 5d7d2f90d6..a0efa3223e 100644 --- a/octavia/common/config.py +++ b/octavia/common/config.py @@ -676,7 +676,7 @@ def init(args, **kwargs): version='%%prog %s' % version.version_info.release_string(), **kwargs) handle_deprecation_compatibility() - setup_remote_pydev_debug() + setup_remote_debugger() def setup_logging(conf): @@ -708,32 +708,54 @@ def handle_deprecation_compatibility(): group='health_manager') -def setup_remote_pydev_debug(): +def _enable_pydev(debugger_host, debugger_port): + try: + from pydev import pydevd + except ImportError: + import pydevd + + pydevd.settrace(debugger_host, + port=int(debugger_port), + stdoutToServer=True, + stderrToServer=True) + + +def _enable_ptvsd(debuggger_host, debugger_port): + import ptvsd + + # Allow other computers to attach to ptvsd at this IP address and port. + ptvsd.enable_attach(address=(debuggger_host, debugger_port), + redirect_output=True) + + # Pause the program until a remote debugger is attached + ptvsd.wait_for_attach() + + +def setup_remote_debugger(): """Required setup for remote debugging.""" - pydev_debug_host = os.environ.get('PYDEV_DEBUG_HOST') - pydev_debug_port = os.environ.get('PYDEV_DEBUG_PORT') + debugger_type = os.environ.get('DEBUGGER_TYPE', 'pydev') + debugger_host = os.environ.get('DEBUGGER_HOST') + debugger_port = os.environ.get('DEBUGGER_PORT') - if not pydev_debug_host or not pydev_debug_port: + if not debugger_type or not debugger_host or not debugger_port: return try: - try: - from pydev import pydevd - except ImportError: - import pydevd - LOG.warning("Connecting to remote debugger. Once connected, resume " "the program on the debugger to continue with the " "initialization of the service.") - pydevd.settrace(pydev_debug_host, - port=int(pydev_debug_port), - stdoutToServer=True, - stderrToServer=True) + if debugger_type == 'pydev': + _enable_pydev(debugger_host, debugger_port) + elif debugger_type == 'ptvsd': + _enable_ptvsd(debugger_host, debugger_port) + else: + LOG.exception('Debugger %(debugger)s is not supported', + debugger_type) except Exception: LOG.exception('Unable to join debugger, please make sure that the ' 'debugger processes is listening on debug-host ' '\'%(debug-host)s\' debug-port \'%(debug-port)s\'.', - {'debug-host': pydev_debug_host, - 'debug-port': pydev_debug_port}) + {'debug-host': debugger_host, + 'debug-port': debugger_port}) raise diff --git a/releasenotes/notes/add-ptvsd-debugger-33bb632bccf494bb.yaml b/releasenotes/notes/add-ptvsd-debugger-33bb632bccf494bb.yaml new file mode 100644 index 0000000000..32bed00750 --- /dev/null +++ b/releasenotes/notes/add-ptvsd-debugger-33bb632bccf494bb.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Added support to debug with the Python Visual Studio Debugger engine + (ptvsd).