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
This commit is contained in:
melanie witt 2018-10-01 23:47:28 +00:00
parent 1792e2f5e9
commit b49209cc29
7 changed files with 238 additions and 101 deletions

View File

@ -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"))

View File

@ -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(

View File

@ -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'],

View File

@ -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.

View File

@ -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()

View File

@ -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):

View File

@ -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):