2 minute read

Originally posted on https://developer.ibm.com/opentech/2015/04/27/debugging-keystone-tests-and-live-deployments/

Debugging an application is sometimes necessary, and keystone (OpenStack’s Identity service) is like any other, though it does have it’s quirks. For the most part, developers will just add in import pdb; pdb.set_trace() and run the application, resulting in an interactive prompt.

Debugging keystone tests

The wrong way

Say a developer wants to debug a keystone federation test, test_create_idp in test_v3_federation.py. Most will use python’s debugger, pdb.

def test_create_idp(self):
"""Creates the IdentityProvider entity associated to remote_ids."""

import pdb; pdb.set_trace()
keys_to_check = list(self.idp_keys)
body = self.default_body.copy()
body['description'] = uuid.uuid4().hex

However, if a developer runs tox -e py27 test_v3_federation to run the unit tests, with the above changes, they’ll see the following output:

steve$ tox -e py27 test_v3_federation
Captured traceback:
    Traceback (most recent call last):
      File "keystone/tests/unit/test_v3_federation.py", line 2001, in setUp
        super(FederatedTokenTests, self).setUp()
      File "keystone/tests/unit/test_v3.py", line 158, in setUp
        super(RestfulTestCase, self).setUp(app_conf=app_conf)
      File "keystone/tests/unit/rest.py", line 66, in setUp
      File "keystone/tests/unit/test_v3_federation.py", line 2032, in load_fixtures
      File "keystone/tests/unit/test_v3_federation.py", line 669, in load_federation_sample_data
        self._inject_assertion(context, variant)
      File "keystone/tests/unit/test_v3_federation.py", line 184, in _inject_assertion
        import pdb; pdb.set_trace()
      File "/usr/lib/python2.7/bdb.py", line 53, in trace_dispatch
        return self.dispatch_return(frame, arg)
      File "/usr/lib/python2.7/bdb.py", line 91, in dispatch_return
        if self.quitting: raise BdbQuit

This is caused by an issue with testr and testtools, it is further discussed on the OpenStack Wiki

The right way

What a developer should do is use Oslo Test’s debug helper, oslo_debug_helper. Simply run tox with the debug option instead of py27. Voilà! Your own debugging prompt.

steve$ tox -e debug test_v3_federation
debug develop-inst-nodeps: /opt/stack/keystone
debug runtests: commands[0] | oslo_debug_helper test_v3_federation
Tests running...
import pdb; pdb.set_trace()

There is additional documentation on how to add the debug environment to any OpenStack project by viewing the Oslo Test documentation.

Debugging live keystone deployments

Now let’s say a deployer want to debug a live server where keystone is running under Apache (the recommended way to deploy keystone).

The wrong way

Like the above example, most folks will use pdb; let’s try using pdb and to try debugging an issue with listing users.

@controller.filterprotected('domain_id', 'enabled', 'name')
def list_users(self, context, filters):
    import pdb; pdb.set_trace()

Restart Apache so the changes take effect.

steve:devstack$ sudo service apache2 restart
 * Restarting web server apache2 - [ OK ]

Attempting to list users will result in an error and upon checking the logs, a similar exception to the one seen above will be logged.

steve$ openstack user list
WARNING: openstackclient.shell The volume version  is not in supported versions
ERROR: openstack An unexpected error prevented the server from fulfilling your request:  (Disable debug mode to suppress these details.) (HTTP 500) (Request-ID: req-7795e720-0196-4201-8a0a-44a136f4449e)

The right way

Use rpdb instead of pdb to remotely debug an application running under Apache. (Note, to install rpdb, simply run: pip install rpdb.) Simply drop in import rpdb; rpdb.set_trace() instead of the usual import pdb; pdb.set_trace(). Attempting to run $ openstack user list again will cause the terminal to hang, this is expected. The keystone log will show a message similar to: 2015-04-27 02:02:44.041686 pdb is running on Attempt to connect to this service using the nc command in another terminal.

steve$ nc 4444
hints = UserV3.build_driver_hints(context, filters)

Now you may debug your application. Happy debugging!