diff --git a/nova/api/openstack/compute/console_auth_tokens.py b/nova/api/openstack/compute/console_auth_tokens.py index 12c0b61c268a..d7ce020f241e 100644 --- a/nova/api/openstack/compute/console_auth_tokens.py +++ b/nova/api/openstack/compute/console_auth_tokens.py @@ -16,10 +16,15 @@ import webob from nova.api.openstack import wsgi +import nova.conf from nova.consoleauth import rpcapi as consoleauth_rpcapi +from nova import context as nova_context from nova.i18n import _ +from nova import objects from nova.policies import console_auth_tokens as cat_policies +CONF = nova.conf.CONF + class ConsoleAuthTokensController(wsgi.Controller): def __init__(self, *args, **kwargs): @@ -36,7 +41,24 @@ class ConsoleAuthTokensController(wsgi.Controller): msg = _("token not provided") raise webob.exc.HTTPBadRequest(explanation=msg) - connect_info = self._consoleauth_rpcapi.check_token(context, token) + connect_info = None + if CONF.workarounds.enable_consoleauth: + connect_info = self._consoleauth_rpcapi.check_token(context, token) + else: + results = nova_context.scatter_gather_skip_cell0( + context, objects.ConsoleAuthToken.validate, token) + # NOTE(melwitt): Console token auths are stored in cell databases, + # but with only the token as a request param, we can't know which + # cell database contains the token's corresponding connection info. + # So, we must query all cells for the info and we can break the + # loop as soon as we find a result because the token is associated + # with one instance, which can only be in one cell. + for result in results.values(): + if result not in (nova_context.did_not_respond_sentinel, + nova_context.raised_exception_sentinel): + connect_info = result.to_dict() + break + if not connect_info: raise webob.exc.HTTPNotFound(explanation=_("Token not found")) diff --git a/nova/compute/api.py b/nova/compute/api.py index 22b0837c0b81..f23f45a67b5d 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1911,12 +1911,11 @@ class API(base.Base): # NOTE(dtp): cells.enable = False means "use cells v2". # Run everywhere except v1 compute cells. - if not CONF.cells.enable or self.cell_type == 'api': - # TODO(melwitt): In Rocky, we store console authorizations - # in both the consoleauth service and the database while - # we convert to using the database. Remove the consoleauth - # line below when authorizations are no longer being - # stored in consoleauth, in Stein. + if (not CONF.cells.enable and CONF.workarounds.enable_consoleauth + ) or self.cell_type == 'api': + # TODO(melwitt): Remove the conditions for running this line + # with cells v2, when consoleauth is no longer being used by + # cells v2, in Stein. self.consoleauth_rpcapi.delete_tokens_for_instance( context, instance.uuid) @@ -3706,11 +3705,12 @@ class API(base.Base): # console authorization in the database in the above method. # The following will be removed when everything has been # converted to use the database, in Stein. - self.consoleauth_rpcapi.authorize_console(context, - connect_info['token'], console_type, - connect_info['host'], connect_info['port'], - connect_info['internal_access_path'], instance.uuid, - access_url=connect_info['access_url']) + if CONF.workarounds.enable_consoleauth: + self.consoleauth_rpcapi.authorize_console(context, + connect_info['token'], console_type, + connect_info['host'], connect_info['port'], + connect_info['internal_access_path'], instance.uuid, + access_url=connect_info['access_url']) return {'url': connect_info['access_url']} @@ -3732,11 +3732,12 @@ class API(base.Base): # console authorization in the database in the above method. # The following will be removed when everything has been # converted to use the database, in Stein. - self.consoleauth_rpcapi.authorize_console(context, - connect_info['token'], console_type, - connect_info['host'], connect_info['port'], - connect_info['internal_access_path'], instance.uuid, - access_url=connect_info['access_url']) + if CONF.workarounds.enable_consoleauth: + self.consoleauth_rpcapi.authorize_console(context, + connect_info['token'], console_type, + connect_info['host'], connect_info['port'], + connect_info['internal_access_path'], instance.uuid, + access_url=connect_info['access_url']) return {'url': connect_info['access_url']} @@ -3758,11 +3759,12 @@ class API(base.Base): # console authorization in the database in the above method. # The following will be removed when everything has been # converted to use the database, in Stein. - self.consoleauth_rpcapi.authorize_console(context, - connect_info['token'], console_type, - connect_info['host'], connect_info['port'], - connect_info['internal_access_path'], instance.uuid, - access_url=connect_info['access_url']) + if CONF.workarounds.enable_consoleauth: + self.consoleauth_rpcapi.authorize_console(context, + connect_info['token'], console_type, + connect_info['host'], connect_info['port'], + connect_info['internal_access_path'], instance.uuid, + access_url=connect_info['access_url']) return {'url': connect_info['access_url']} @@ -3785,11 +3787,12 @@ class API(base.Base): # console authorization in the database in the above method. # The following will be removed when everything has been # converted to use the database, in Stein. - self.consoleauth_rpcapi.authorize_console(context, - connect_info['token'], console_type, - connect_info['host'], connect_info['port'], - connect_info['internal_access_path'], instance.uuid, - access_url=connect_info['access_url']) + if CONF.workarounds.enable_consoleauth: + self.consoleauth_rpcapi.authorize_console(context, + connect_info['token'], console_type, + connect_info['host'], connect_info['port'], + connect_info['internal_access_path'], instance.uuid, + access_url=connect_info['access_url']) return {'url': connect_info['access_url']} @check_instance_host @@ -3810,11 +3813,12 @@ class API(base.Base): # console authorization in the database in the above method. # The following will be removed when everything has been # converted to use the database, in Stein. - self.consoleauth_rpcapi.authorize_console(context, - connect_info['token'], console_type, - connect_info['host'], connect_info['port'], - connect_info['internal_access_path'], instance.uuid, - access_url=connect_info['access_url']) + if CONF.workarounds.enable_consoleauth: + self.consoleauth_rpcapi.authorize_console(context, + connect_info['token'], console_type, + connect_info['host'], connect_info['port'], + connect_info['internal_access_path'], instance.uuid, + access_url=connect_info['access_url']) return {'url': connect_info['access_url']} @check_instance_host @@ -4339,13 +4343,14 @@ class API(base.Base): self._record_action_start(context, instance, instance_actions.LIVE_MIGRATION) - # TODO(melwitt): In Rocky, we store console authorizations + # TODO(melwitt): In Rocky, we optionally store console authorizations # in both the consoleauth service and the database while - # we convert to using the database. Remove the consoleauth - # line below when authorizations are no longer being - # stored in consoleauth, in Stein. - self.consoleauth_rpcapi.delete_tokens_for_instance( - context, instance.uuid) + # we convert to using the database. Remove the condition for running + # this line with cells v2, when consoleauth is no longer being used by + # cells v2, in Stein. + if CONF.cells.enable or CONF.workarounds.enable_consoleauth: + self.consoleauth_rpcapi.delete_tokens_for_instance( + context, instance.uuid) try: request_spec = objects.RequestSpec.get_by_instance_uuid( diff --git a/nova/console/websocketproxy.py b/nova/console/websocketproxy.py index 105765ebedbc..0463b7463886 100644 --- a/nova/console/websocketproxy.py +++ b/nova/console/websocketproxy.py @@ -113,25 +113,6 @@ class NovaProxyRequestHandlerBase(object): return origin_proto in expected_protos - @staticmethod - def _console_auth_token_obj_to_dict(obj): - """Convert to a dict representation.""" - # NOTE(PaulMurray) For compatibility while there is code that - # expects the dict representation returned by consoleauth. - # TODO(PaulMurray) Remove this function when the code no - # longer expects the consoleauth dict representation - connect_info = {} - connect_info['token'] = obj.token, - connect_info['instance_uuid'] = obj.instance_uuid - connect_info['console_type'] = obj.console_type - connect_info['host'] = obj.host - connect_info['port'] = obj.port - if 'internal_access_path' in obj: - connect_info['internal_access_path'] = obj.internal_access_path - if 'access_url_base' in obj: - connect_info['access_url'] = obj.access_url - return connect_info - def _check_console_port(self, ctxt, instance_uuid, port, console_type): try: @@ -155,8 +136,7 @@ class NovaProxyRequestHandlerBase(object): # NOTE(PaulMurray) ConsoleAuthToken.validate validates the token. # We call the compute manager directly to check the console port # is correct. - connect_info = self._console_auth_token_obj_to_dict( - objects.ConsoleAuthToken.validate(ctxt, token)) + connect_info = objects.ConsoleAuthToken.validate(ctxt, token).to_dict() valid_port = self._check_console_port( ctxt, connect_info['instance_uuid'], connect_info['port'], diff --git a/nova/objects/console_auth_token.py b/nova/objects/console_auth_token.py index d5d01ab039c2..e6e5a2e58c8d 100644 --- a/nova/objects/console_auth_token.py +++ b/nova/objects/console_auth_token.py @@ -74,6 +74,24 @@ class ConsoleAuthToken(base.NovaTimestampObject, base.NovaObject): obj.obj_reset_changes() return obj + def to_dict(self): + """Convert to a dict representation.""" + # NOTE(PaulMurray) For compatibility while there is code that + # expects the dict representation returned by consoleauth. + # TODO(PaulMurray) Remove this function when the code no + # longer expects the consoleauth dict representation + connect_info = {} + connect_info['token'] = self.token, + connect_info['instance_uuid'] = self.instance_uuid + connect_info['console_type'] = self.console_type + connect_info['host'] = self.host + connect_info['port'] = self.port + if 'internal_access_path' in self: + connect_info['internal_access_path'] = self.internal_access_path + if 'access_url_base' in self: + connect_info['access_url'] = self.access_url + return connect_info + @base.remotable def authorize(self, ttl): """Authorise the console token and store in the database. diff --git a/nova/tests/unit/api/openstack/compute/test_console_auth_tokens.py b/nova/tests/unit/api/openstack/compute/test_console_auth_tokens.py index 3057cddb0aa7..f68f588c71cd 100644 --- a/nova/tests/unit/api/openstack/compute/test_console_auth_tokens.py +++ b/nova/tests/unit/api/openstack/compute/test_console_auth_tokens.py @@ -13,6 +13,9 @@ # License for the specific language governing permissions and limitations # under the License. +import copy + +import ddt import mock import webob @@ -20,58 +23,115 @@ from nova.api.openstack import api_version_request from nova.api.openstack.compute import console_auth_tokens \ as console_auth_tokens_v21 from nova.consoleauth import rpcapi as consoleauth_rpcapi +from nova import exception +from nova import objects from nova import test from nova.tests.unit.api.openstack import fakes +@ddt.ddt class ConsoleAuthTokensExtensionTestV21(test.NoDBTestCase): controller_class = console_auth_tokens_v21 _EXPECTED_OUTPUT = {'console': {'instance_uuid': fakes.FAKE_UUID, 'host': 'fake_host', - 'port': 'fake_port', + 'port': '1234', 'internal_access_path': 'fake_access_path'}} + # The database backend returns a ConsoleAuthToken.to_dict() and o.vo + # StringField are unicode. And the port is an IntegerField. + _EXPECTED_OUTPUT_DB = copy.deepcopy(_EXPECTED_OUTPUT) + _EXPECTED_OUTPUT_DB['console'].update( + {'host': u'fake_host', 'port': 1234, + 'internal_access_path': u'fake_access_path'}) + def setUp(self): super(ConsoleAuthTokensExtensionTestV21, self).setUp() self.controller = self.controller_class.ConsoleAuthTokensController() self.req = fakes.HTTPRequest.blank('', use_admin_context=True) self.context = self.req.environ['nova.context'] + @ddt.data(True, False) + @mock.patch('nova.objects.ConsoleAuthToken.validate', + return_value=objects.ConsoleAuthToken( + instance_uuid=fakes.FAKE_UUID, host='fake_host', + port='1234', internal_access_path='fake_access_path', + console_type='rdp-html5', token=fakes.FAKE_UUID)) @mock.patch.object(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token', return_value={ 'instance_uuid': fakes.FAKE_UUID, 'host': 'fake_host', - 'port': 'fake_port', + 'port': '1234', 'internal_access_path': 'fake_access_path', 'console_type': 'rdp-html5'}) - def test_get_console_connect_info(self, mock_check_token): + def test_get_console_connect_info(self, enable_consoleauth, + mock_check_token, mock_validate): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') output = self.controller.show(self.req, fakes.FAKE_UUID) - self.assertEqual(self._EXPECTED_OUTPUT, output) - mock_check_token.assert_called_once_with(self.context, fakes.FAKE_UUID) + if enable_consoleauth: + self.assertEqual(self._EXPECTED_OUTPUT, output) + mock_check_token.assert_called_once_with(self.context, + fakes.FAKE_UUID) + mock_validate.assert_not_called() + else: + self.assertEqual(self._EXPECTED_OUTPUT_DB, output) + mock_validate.assert_called_once_with(self.context, + fakes.FAKE_UUID) + mock_check_token.assert_not_called() + @ddt.data(True, False) + @mock.patch('nova.objects.ConsoleAuthToken.validate', + side_effect=exception.InvalidToken(token='***')) @mock.patch.object(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token', return_value=None) - def test_get_console_connect_info_token_not_found(self, mock_check_token): + def test_get_console_connect_info_token_not_found(self, enable_consoleauth, + mock_check_token, + mock_validate): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, self.req, fakes.FAKE_UUID) - mock_check_token.assert_called_once_with(self.context, fakes.FAKE_UUID) + if enable_consoleauth: + mock_check_token.assert_called_once_with(self.context, + fakes.FAKE_UUID) + mock_validate.assert_not_called() + else: + mock_validate.assert_called_once_with(self.context, + fakes.FAKE_UUID) + mock_check_token.assert_not_called() + @ddt.data(True, False) + @mock.patch('nova.objects.ConsoleAuthToken.validate', + return_value=objects.ConsoleAuthToken( + instance_uuid=fakes.FAKE_UUID, host='fake_host', + port='1234', internal_access_path='fake_access_path', + console_type='unauthorized_console_type', + token=fakes.FAKE_UUID)) @mock.patch.object(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token', return_value={ 'instance_uuid': fakes.FAKE_UUID, 'host': 'fake_host', - 'port': 'fake_port', + 'port': '1234', 'internal_access_path': 'fake_access_path', 'console_type': 'unauthorized_console_type'}) def test_get_console_connect_info_nonrdp_console_type(self, - mock_check_token): + enable_consoleauth, + mock_check_token, + mock_validate): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') self.assertRaises(webob.exc.HTTPUnauthorized, self.controller.show, self.req, fakes.FAKE_UUID) - mock_check_token.assert_called_once_with(self.context, fakes.FAKE_UUID) + if enable_consoleauth: + mock_check_token.assert_called_once_with(self.context, + fakes.FAKE_UUID) + mock_validate.assert_not_called() + else: + mock_validate.assert_called_once_with(self.context, + fakes.FAKE_UUID) + mock_check_token.assert_not_called() +@ddt.ddt class ConsoleAuthTokensExtensionTestV231(ConsoleAuthTokensExtensionTestV21): def setUp(self): @@ -79,13 +139,30 @@ class ConsoleAuthTokensExtensionTestV231(ConsoleAuthTokensExtensionTestV21): self.req.api_version_request = api_version_request.APIVersionRequest( '2.31') + @ddt.data(True, False) + @mock.patch('nova.objects.ConsoleAuthToken.validate') @mock.patch.object(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token') - def test_get_console_connect_info_nonrdp_console_type(self, mock_check): + def test_get_console_connect_info_nonrdp_console_type(self, + enable_consoleauth, + mock_check, + mock_validate): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') + mock_validate.return_value = objects.ConsoleAuthToken( + instance_uuid=fakes.FAKE_UUID, host='fake_host', port='1234', + internal_access_path='fake_access_path', console_type='webmks', + token=fakes.FAKE_UUID) mock_check.return_value = {'instance_uuid': fakes.FAKE_UUID, 'host': 'fake_host', - 'port': 'fake_port', + 'port': '1234', 'internal_access_path': 'fake_access_path', 'console_type': 'webmks'} output = self.controller.show(self.req, fakes.FAKE_UUID) - self.assertEqual(self._EXPECTED_OUTPUT, output) - mock_check.assert_called_once_with(self.context, fakes.FAKE_UUID) + if enable_consoleauth: + self.assertEqual(self._EXPECTED_OUTPUT, output) + mock_check.assert_called_once_with(self.context, fakes.FAKE_UUID) + mock_validate.assert_not_called() + else: + self.assertEqual(self._EXPECTED_OUTPUT_DB, output) + mock_validate.assert_called_once_with(self.context, + fakes.FAKE_UUID) + mock_check.assert_not_called() diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py index 4f98d6515c16..dfebffff9b08 100644 --- a/nova/tests/unit/compute/test_compute.py +++ b/nova/tests/unit/compute/test_compute.py @@ -9925,10 +9925,12 @@ class ComputeAPITestCase(BaseTestCase): self.assertRaises(exception.InvalidVolume, self.compute_api.rescue, self.context, instance) + @ddt.data(True, False) @mock.patch.object(compute_rpcapi.ComputeAPI, 'get_vnc_console') @mock.patch.object(compute_api.consoleauth_rpcapi.ConsoleAuthAPI, 'authorize_console') - def test_vnc_console(self, mock_auth, mock_get): + def test_vnc_console(self, enable_consoleauth, mock_auth, mock_get): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') # Make sure we can a vnc console for an instance. fake_instance = self._fake_instance( @@ -9951,11 +9953,14 @@ class ComputeAPITestCase(BaseTestCase): mock_get.assert_called_once_with( self.context, instance=fake_instance, console_type=fake_console_type) - mock_auth.assert_called_once_with( - self.context, 'fake_token', fake_console_type, 'fake_console_host', - 'fake_console_port', 'fake_access_path', - 'f3000000-0000-0000-0000-000000000000', - access_url='fake_console_url') + if enable_consoleauth or CONF.cells.enable: + mock_auth.assert_called_once_with( + self.context, 'fake_token', fake_console_type, + 'fake_console_host', 'fake_console_port', 'fake_access_path', + 'f3000000-0000-0000-0000-000000000000', + access_url='fake_console_url') + else: + mock_auth.assert_not_called() def test_get_vnc_console_no_host(self): instance = self._create_fake_instance_obj(params={'host': ''}) @@ -9964,10 +9969,12 @@ class ComputeAPITestCase(BaseTestCase): self.compute_api.get_vnc_console, self.context, instance, 'novnc') + @ddt.data(True, False) @mock.patch.object(compute_api.consoleauth_rpcapi.ConsoleAuthAPI, 'authorize_console') @mock.patch.object(compute_rpcapi.ComputeAPI, 'get_spice_console') - def test_spice_console(self, mock_spice, mock_auth): + def test_spice_console(self, enable_consoleauth, mock_spice, mock_auth): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') # Make sure we can a spice console for an instance. fake_instance = self._fake_instance( @@ -9990,11 +9997,14 @@ class ComputeAPITestCase(BaseTestCase): mock_spice.assert_called_once_with(self.context, instance=fake_instance, console_type=fake_console_type) - mock_auth.assert_called_once_with( - self.context, 'fake_token', fake_console_type, 'fake_console_host', - 'fake_console_port', 'fake_access_path', - 'f3000000-0000-0000-0000-000000000000', - access_url='fake_console_url') + if enable_consoleauth or CONF.cells.enable: + mock_auth.assert_called_once_with( + self.context, 'fake_token', fake_console_type, + 'fake_console_host', 'fake_console_port', 'fake_access_path', + 'f3000000-0000-0000-0000-000000000000', + access_url='fake_console_url') + else: + mock_auth.assert_not_called() def test_get_spice_console_no_host(self): instance = self._create_fake_instance_obj(params={'host': ''}) @@ -10022,10 +10032,12 @@ class ComputeAPITestCase(BaseTestCase): getattr(self.compute_api, 'get_%s_console' % console_type), self.context, instance, console_type) + @ddt.data(True, False) @mock.patch.object(compute_api.consoleauth_rpcapi.ConsoleAuthAPI, 'authorize_console') @mock.patch.object(compute_rpcapi.ComputeAPI, 'get_rdp_console') - def test_rdp_console(self, mock_rdp, mock_auth): + def test_rdp_console(self, enable_consoleauth, mock_rdp, mock_auth): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') # Make sure we can a rdp console for an instance. fake_instance = self._fake_instance({ 'uuid': 'f3000000-0000-0000-0000-000000000000', @@ -10046,11 +10058,14 @@ class ComputeAPITestCase(BaseTestCase): self.assertEqual(console, {'url': 'fake_console_url'}) mock_rdp.assert_called_once_with(self.context, instance=fake_instance, console_type=fake_console_type) - mock_auth.assert_called_once_with( - self.context, 'fake_token', fake_console_type, 'fake_console_host', - 'fake_console_port', 'fake_access_path', - 'f3000000-0000-0000-0000-000000000000', - access_url='fake_console_url') + if enable_consoleauth or CONF.cells.enable: + mock_auth.assert_called_once_with( + self.context, 'fake_token', fake_console_type, + 'fake_console_host', 'fake_console_port', 'fake_access_path', + 'f3000000-0000-0000-0000-000000000000', + access_url='fake_console_url') + else: + mock_auth.assert_not_called() def test_get_rdp_console_no_host(self): instance = self._create_fake_instance_obj(params={'host': ''}) @@ -11164,8 +11179,11 @@ class ComputeAPITestCase(BaseTestCase): disk_over_commit=True, request_spec=fake_spec, async_=False) - delete_tokens_for_instance.assert_called_once_with( - self.context, instance.uuid) + if CONF.workarounds.enable_consoleauth or CONF.cells.enable: + delete_tokens_for_instance.assert_called_once_with( + self.context, instance.uuid) + else: + delete_tokens_for_instance.assert_not_called() do_test() instance.refresh() @@ -11177,13 +11195,19 @@ class ComputeAPITestCase(BaseTestCase): self.assertEqual('fake_dest_host', req_dest.host) self.assertEqual('fake_dest_node', req_dest.node) - def test_live_migrate(self): + @ddt.data(True, False) + def test_live_migrate(self, enable_consoleauth): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') self._test_live_migrate() - def test_live_migrate_with_not_forced_host(self): + @ddt.data(True, False) + def test_live_migrate_with_not_forced_host(self, enable_consoleauth): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') self._test_live_migrate(force=False) - def test_live_migrate_with_forced_host(self): + @ddt.data(True, False) + def test_live_migrate_with_forced_host(self, enable_consoleauth): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') self._test_live_migrate(force=True) def test_fail_live_migrate_with_non_existing_destination(self): diff --git a/nova/tests/unit/compute/test_compute_api.py b/nova/tests/unit/compute/test_compute_api.py index 217534174e6a..9e503f1934f4 100644 --- a/nova/tests/unit/compute/test_compute_api.py +++ b/nova/tests/unit/compute/test_compute_api.py @@ -1200,8 +1200,11 @@ class _ComputeAPIUnitTestMixIn(object): mock_terminate.assert_called_once_with( self.context, inst, [], delete_type=delete_type) - if self.cell_type is None or self.cell_type == 'api': + if ((self.cell_type is None and CONF.workarounds.enable_consoleauth) + or self.cell_type == 'api'): mock_del_token.assert_called_once_with(self.context, instance_uuid) + else: + mock_del_token.assert_not_called() if is_shelved: mock_image_delete.assert_called_once_with(self.context, @@ -1227,7 +1230,9 @@ class _ComputeAPIUnitTestMixIn(object): task_state=task_states.RESIZE_FINISH, old_flavor=old_flavor) - def test_delete_in_resized(self): + @ddt.data(True, False) + def test_delete_in_resized(self, enable_consoleauth): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') self._test_delete('delete', vm_state=vm_states.RESIZED) def test_delete_shelved(self): @@ -1236,7 +1241,9 @@ class _ComputeAPIUnitTestMixIn(object): vm_state=vm_states.SHELVED, system_metadata=fake_sys_meta) - def test_delete_shelved_offloaded(self): + @ddt.data(True, False) + def test_delete_shelved_offloaded(self, enable_consoleauth): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') fake_sys_meta = {'shelved_image_id': SHELVED_IMAGE} self._test_delete('delete', vm_state=vm_states.SHELVED_OFFLOADED, @@ -1254,7 +1261,9 @@ class _ComputeAPIUnitTestMixIn(object): vm_state=vm_states.SHELVED_OFFLOADED, system_metadata=fake_sys_meta) - def test_delete_shelved_exception(self): + @ddt.data(True, False) + def test_delete_shelved_exception(self, enable_consoleauth): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') fake_sys_meta = {'shelved_image_id': SHELVED_IMAGE_EXCEPTION} self._test_delete('delete', vm_state=vm_states.SHELVED, @@ -1269,7 +1278,9 @@ class _ComputeAPIUnitTestMixIn(object): def test_delete_soft_in_resized(self): self._test_delete('soft_delete', vm_state=vm_states.RESIZED) - def test_delete_soft(self): + @ddt.data(True, False) + def test_delete_soft(self, enable_consoleauth): + self.flags(enable_consoleauth=enable_consoleauth, group='workarounds') self._test_delete('soft_delete') def test_delete_forced(self):