Unshelve using the RequestSpec object

Now that we have done this for live-migrate and evacuate, we can modify
the unshelve conductor method to get the RequestSpec.

Partially-Implements: blueprint check-destination-on-migrations

Change-Id: I8d17c7eb908c6aa614744058ed7e483ce6afe27d
This commit is contained in:
Sylvain Bauza 2016-02-16 12:03:25 +01:00
parent 111a852e79
commit b951e04655
6 changed files with 98 additions and 15 deletions

View File

@ -2687,7 +2687,15 @@ class API(base.Base):
self._record_action_start(context, instance, instance_actions.UNSHELVE)
self.compute_task_api.unshelve_instance(context, instance)
try:
request_spec = objects.RequestSpec.get_by_instance_uuid(
context, instance.uuid)
except exception.RequestSpecNotFound:
# Some old instances can still have no RequestSpec object attached
# to them, we need to support the old way
request_spec = None
self.compute_task_api.unshelve_instance(context, instance,
request_spec)
@wrap_check_policy
@check_instance_lock

View File

@ -95,9 +95,9 @@ class LocalComputeTaskAPI(object):
block_device_mapping=block_device_mapping,
legacy_bdm=legacy_bdm)
def unshelve_instance(self, context, instance):
def unshelve_instance(self, context, instance, request_spec=None):
utils.spawn_n(self._manager.unshelve_instance, context,
instance=instance)
instance=instance, request_spec=request_spec)
def rebuild_instance(self, context, instance, orig_image_ref, image_ref,
injected_files, new_pass, orig_sys_metadata,
@ -205,9 +205,9 @@ class ComputeTaskAPI(object):
block_device_mapping=block_device_mapping,
legacy_bdm=legacy_bdm)
def unshelve_instance(self, context, instance):
def unshelve_instance(self, context, instance, request_spec=None):
self.conductor_compute_rpcapi.unshelve_instance(context,
instance=instance)
instance=instance, request_spec=None)
def rebuild_instance(self, context, instance, orig_image_ref, image_ref,
injected_files, new_pass, orig_sys_metadata,

View File

@ -144,7 +144,7 @@ class ComputeTaskManager(base.Base):
may involve coordinating activities on multiple compute nodes.
"""
target = messaging.Target(namespace='compute_task', version='1.13')
target = messaging.Target(namespace='compute_task', version='1.14')
def __init__(self):
super(ComputeTaskManager, self).__init__()
@ -433,7 +433,7 @@ class ComputeTaskManager(base.Base):
hosts = self.scheduler_client.select_destinations(context, spec_obj)
return hosts
def unshelve_instance(self, context, instance):
def unshelve_instance(self, context, instance, request_spec=None):
sys_meta = instance.system_metadata
def safe_image_show(ctx, image_id):
@ -471,11 +471,24 @@ class ComputeTaskManager(base.Base):
try:
with compute_utils.EventReporter(context, 'schedule_instances',
instance.uuid):
filter_properties = {}
if not request_spec:
# NOTE(sbauza): We were unable to find an original
# RequestSpec object - probably because the instance is
# old. We need to mock that the old way
filter_properties = {}
request_spec = scheduler_utils.build_request_spec(
context, image, [instance])
else:
# TODO(sbauza): Provide directly the RequestSpec object
# when _schedule_instances(),
# populate_filter_properties and populate_retry()
# accept it
filter_properties = request_spec.\
to_legacy_filter_properties_dict()
request_spec = request_spec.\
to_legacy_request_spec_dict()
scheduler_utils.populate_retry(filter_properties,
instance.uuid)
request_spec = scheduler_utils.build_request_spec(
context, image, [instance])
hosts = self._schedule_instances(
context, request_spec, filter_properties)
host_state = hosts[0]

View File

@ -269,6 +269,7 @@ class ComputeTaskAPI(object):
1.11 - Added clean_shutdown to migrate_server()
1.12 - Added request_spec to rebuild_instance()
1.13 - Added request_spec to migrate_server()
1.14 - Added request_spec to unshelve_instance()
"""
def __init__(self):
@ -337,9 +338,16 @@ class ComputeTaskAPI(object):
cctxt = self.client.prepare(version=version)
cctxt.cast(context, 'build_instances', **kw)
def unshelve_instance(self, context, instance):
cctxt = self.client.prepare(version='1.3')
cctxt.cast(context, 'unshelve_instance', instance=instance)
def unshelve_instance(self, context, instance, request_spec=None):
version = '1.14'
kw = {'instance': instance,
'request_spec': request_spec
}
if not self.client.can_send_version(version):
version = '1.3'
del kw['request_spec']
cctxt = self.client.prepare(version=version)
cctxt.cast(context, 'unshelve_instance', **kw)
def rebuild_instance(self, ctxt, instance, new_pass, injected_files,
image_ref, orig_image_ref, orig_sys_metadata, bdms,

View File

@ -476,7 +476,8 @@ class ShelveComputeAPITestCase(test_compute.BaseTestCase):
db.instance_destroy(self.context, instance['uuid'])
def test_unshelve(self):
@mock.patch.object(objects.RequestSpec, 'get_by_instance_uuid')
def test_unshelve(self, get_by_instance_uuid):
# Ensure instance can be unshelved.
instance = self._create_fake_instance_obj()
@ -488,7 +489,14 @@ class ShelveComputeAPITestCase(test_compute.BaseTestCase):
instance.vm_state = vm_states.SHELVED
instance.save()
self.compute_api.unshelve(self.context, instance)
fake_spec = objects.RequestSpec()
get_by_instance_uuid.return_value = fake_spec
with mock.patch.object(self.compute_api.compute_task_api,
'unshelve_instance') as unshelve:
self.compute_api.unshelve(self.context, instance)
get_by_instance_uuid.assert_called_once_with(self.context,
instance.uuid)
unshelve.assert_called_once_with(self.context, instance, fake_spec)
self.assertEqual(instance.task_state, task_states.UNSHELVING)

View File

@ -50,6 +50,7 @@ from nova.tests.unit import cast_as_call
from nova.tests.unit.compute import test_compute
from nova.tests.unit import fake_instance
from nova.tests.unit import fake_notifier
from nova.tests.unit import fake_request_spec
from nova.tests.unit import fake_server_actions
from nova.tests.unit import fake_utils
from nova import utils
@ -643,6 +644,51 @@ class _BaseTaskTestCase(object):
system_metadata['shelved_host'] = 'fake-mini'
self.conductor_manager.unshelve_instance(self.context, instance)
def test_unshelve_offload_instance_on_host_with_request_spec(self):
instance = self._create_fake_instance_obj()
instance.vm_state = vm_states.SHELVED_OFFLOADED
instance.task_state = task_states.UNSHELVING
instance.save()
system_metadata = instance.system_metadata
system_metadata['shelved_at'] = timeutils.utcnow()
system_metadata['shelved_image_id'] = 'fake_image_id'
system_metadata['shelved_host'] = 'fake-mini'
fake_spec = fake_request_spec.fake_spec_obj()
# FIXME(sbauza): Modify the fake RequestSpec object to either add a
# non-empty SchedulerRetries object or nullify the field
fake_spec.retry = None
# FIXME(sbauza): Modify the fake RequestSpec object to either add a
# non-empty SchedulerLimits object or nullify the field
fake_spec.limits = None
# FIXME(sbauza): Modify the fake RequestSpec object to either add a
# non-empty InstanceGroup object or nullify the field
fake_spec.instance_group = None
filter_properties = fake_spec.to_legacy_filter_properties_dict()
request_spec = fake_spec.to_legacy_request_spec_dict()
host = {'host': 'host1', 'nodename': 'node1', 'limits': []}
@mock.patch.object(self.conductor_manager.compute_rpcapi,
'unshelve_instance')
@mock.patch.object(self.conductor_manager, '_schedule_instances')
def do_test(sched_instances, unshelve_instance):
sched_instances.return_value = [host]
self.conductor_manager.unshelve_instance(self.context, instance,
fake_spec)
scheduler_utils.populate_retry(filter_properties, instance.uuid)
scheduler_utils.populate_filter_properties(filter_properties, host)
sched_instances.assert_called_once_with(self.context, request_spec,
filter_properties)
unshelve_instance.assert_called_once_with(
self.context, instance, host['host'], image=mock.ANY,
filter_properties=filter_properties, node=host['nodename']
)
do_test()
def test_unshelve_offloaded_instance_glance_image_not_found(self):
shelved_image_id = "image_not_found"