From b49209cc29f5ccd529b8074b68be074c5a2f742f Mon Sep 17 00:00:00 2001 From: melanie witt Date: Mon, 1 Oct 2018 23:47:28 +0000 Subject: [PATCH] Use nova-consoleauth only if workaround enabled In Rocky, we deprecated the nova-consoleauth service but there were unconditional calls to nova-consoleauth in the compute/api, which made it impossible to avoid running the nova-consoleauth service. This adds conditional checks to call nova-consoleauth only if the [workarounds]enable_consoleauth configuration option is True. The option defaults to False because the default console token auth TTL is 10 minutes and only operators who have configured much longer TTL or otherwise wish to avoid resetting all consoles at upgrade time need to use the option. This also updates the /os-console-auth-tokens/{console_token} API to use nova-consoleauth only if the [workarounds] option is enabled. This had to be done in the same change because the conditional checks in the compute/api code caused the /os-console-auth-tokens API functional tests to fail to find token authorizations in nova-consoleauth. Closes-Bug: #1788470 Closes-Bug: #1795982 Change-Id: Iff6020f1a10afc476864f979faf251ef5a1a6184 --- .../openstack/compute/console_auth_tokens.py | 24 +++- nova/compute/api.py | 79 +++++++------ nova/console/websocketproxy.py | 22 +--- nova/objects/console_auth_token.py | 18 +++ .../compute/test_console_auth_tokens.py | 105 +++++++++++++++--- nova/tests/unit/compute/test_compute.py | 70 ++++++++---- nova/tests/unit/compute/test_compute_api.py | 21 +++- 7 files changed, 238 insertions(+), 101 deletions(-) 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):