Merge "Reject live migration and suspend on SEV guests"

This commit is contained in:
Zuul 2019-09-11 08:34:08 +00:00 committed by Gerrit Code Review
commit 5ad53470ff
6 changed files with 58 additions and 1 deletions

View File

@ -171,6 +171,8 @@ class MigrateServerController(wsgi.Controller):
"'%(ex)s'", {'ex': ex})
else:
raise exc.HTTPBadRequest(explanation=ex.format_message())
except exception.OperationNotSupportedForSEV as e:
raise exc.HTTPConflict(explanation=e.format_message())
except exception.InstanceIsLocked as e:
raise exc.HTTPConflict(explanation=e.format_message())
except exception.ComputeHostNotFound as e:

View File

@ -38,7 +38,8 @@ class SuspendServerController(wsgi.Controller):
target={'user_id': server.user_id,
'project_id': server.project_id})
self.compute_api.suspend(context, server)
except exception.InstanceIsLocked as e:
except (exception.OperationNotSupportedForSEV,
exception.InstanceIsLocked) as e:
raise exc.HTTPConflict(explanation=e.format_message())
except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error,

View File

@ -205,6 +205,24 @@ def check_instance_lock(function):
return inner
def reject_sev_instances(operation):
"""Decorator. Raise OperationNotSupportedForSEV if instance has SEV
enabled.
"""
def outer(f):
@six.wraps(f)
def inner(self, context, instance, *args, **kw):
if hardware.get_mem_encryption_constraint(instance.flavor,
instance.image_meta):
raise exception.OperationNotSupportedForSEV(
instance_uuid=instance.uuid,
operation=operation)
return f(self, context, instance, *args, **kw)
return inner
return outer
def _diff_dict(orig, new):
"""Return a dict describing how to change orig to new. The keys
correspond to values that have changed; the value will be a list
@ -3785,6 +3803,7 @@ class API(base.Base):
return self.compute_rpcapi.get_instance_diagnostics(context,
instance=instance)
@reject_sev_instances(instance_actions.SUSPEND)
@check_instance_lock
@check_instance_state(vm_state=[vm_states.ACTIVE])
def suspend(self, context, instance):
@ -4448,6 +4467,7 @@ class API(base.Base):
diff=diff)
return _metadata
@reject_sev_instances(instance_actions.LIVE_MIGRATION)
@check_instance_lock
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.PAUSED])
def live_migrate(self, context, instance, block_migration,

View File

@ -533,6 +533,12 @@ class UnableToMigrateToSelf(Invalid):
"to current host (%(host)s).")
class OperationNotSupportedForSEV(NovaException):
msg_fmt = _("Operation '%(operation)s' not supported for SEV-enabled "
"instance (%(instance_uuid)s).")
code = 409
class InvalidHypervisorType(Invalid):
msg_fmt = _("The supplied hypervisor type of is invalid.")

View File

@ -609,6 +609,20 @@ class MigrateServerTestsV268(MigrateServerTestsV256):
method_translations=method_translations,
args_map=args_map)
@mock.patch('nova.virt.hardware.get_mem_encryption_constraint',
new=mock.Mock(return_value=True))
@mock.patch.object(objects.instance.Instance, 'image_meta')
def test_live_migrate_sev_rejected(self, mock_image):
instance = self._stub_instance_get()
body = {'os-migrateLive': {'host': 'hostname',
'block_migration': 'auto'}}
ex = self.assertRaises(webob.exc.HTTPConflict,
self.controller._migrate_live,
self.req, fakes.FAKE_UUID, body=body)
self.assertIn("Operation 'live-migration' not supported for "
"SEV-enabled instance (%s)" % instance.uuid,
six.text_type(ex))
def test_live_migrate_with_forced_host(self):
body = {'os-migrateLive': {'host': 'hostname',
'block_migration': 'auto',

View File

@ -13,10 +13,13 @@
# under the License.
import mock
import six
import webob
from nova.api.openstack.compute import suspend_server as \
suspend_server_v21
from nova import exception
from nova import objects
from nova import test
from nova.tests.unit.api.openstack.compute import admin_only_action_common
from nova.tests.unit.api.openstack import fakes
@ -39,6 +42,17 @@ class SuspendServerTestsV21(admin_only_action_common.CommonTests):
def test_suspend_resume(self):
self._test_actions(['_suspend', '_resume'])
@mock.patch('nova.virt.hardware.get_mem_encryption_constraint',
new=mock.Mock(return_value=True))
@mock.patch.object(objects.instance.Instance, 'image_meta')
def test_suspend_sev_rejected(self, mock_image):
instance = self._stub_instance_get()
ex = self.assertRaises(webob.exc.HTTPConflict,
self.controller._suspend,
self.req, fakes.FAKE_UUID, body={})
self.assertIn("Operation 'suspend' not supported for SEV-enabled "
"instance (%s)" % instance.uuid, six.text_type(ex))
def test_suspend_resume_with_non_existed_instance(self):
self._test_actions_with_non_existed_instance(['_suspend', '_resume'])