Change RPC to use new BDM format for instance boot

This patch makes rpc calls that are the result of booting an instance
propagate the new block device mapping format.

The way this is done is by adding a 'legacy_bdm' flag to the conductor
(task) API. Since both the scheduler and the compute service propagate
the block device mapping as part of the request_spec field, a flag named
legacy_bdm_in_spec to indicate that was introduced in their respective
APIs.

Currently block_device_mapping is not used by any of the in-tree filters
in the scheduler, so it is assumed that scheduler's boot functionality
has now transitioned to the new format.

This patch also bumps RPC versions of the task, scheduler and compute
manager classes.

Finally this patch propagates the legacy_bdm_in_spec through the
run_instance callback of the compute manager so that, in case of error -
the instance is re-scheduled with the proper flag set.

blueprint: improve-block-device-handling

Change-Id: I5f25ddd4d586dda91061f065c1796be726b0ede3
This commit is contained in:
Nikola Dipanov
2013-07-15 10:40:50 +02:00
parent e0fb7f69c8
commit 7ea4a01a9d
9 changed files with 43 additions and 29 deletions

View File

@@ -92,7 +92,7 @@ class ChanceScheduler(driver.Scheduler):
def schedule_run_instance(self, context, request_spec,
admin_password, injected_files,
requested_networks, is_first_time,
filter_properties):
filter_properties, legacy_bdm_in_spec):
"""Create and run an instance or instances."""
instance_uuids = request_spec.get('instance_uuids')
for num, instance_uuid in enumerate(instance_uuids):
@@ -109,7 +109,8 @@ class ChanceScheduler(driver.Scheduler):
admin_password=admin_password,
is_first_time=is_first_time,
request_spec=request_spec,
filter_properties=filter_properties)
filter_properties=filter_properties,
legacy_bdm_in_spec=legacy_bdm_in_spec)
except Exception as ex:
# NOTE(vish): we don't reraise the exception here to make sure
# that all instances in the request get set to

View File

@@ -147,7 +147,7 @@ class Scheduler(object):
def schedule_run_instance(self, context, request_spec,
admin_password, injected_files,
requested_networks, is_first_time,
filter_properties):
filter_properties, legacy_bdm_in_spec):
"""Must override schedule_run_instance method for scheduler to work."""
msg = _("Driver must implement schedule_run_instance")
raise NotImplementedError(msg)

View File

@@ -64,7 +64,7 @@ class FilterScheduler(driver.Scheduler):
def schedule_run_instance(self, context, request_spec,
admin_password, injected_files,
requested_networks, is_first_time,
filter_properties):
filter_properties, legacy_bdm_in_spec):
"""This method is called from nova.compute.api to provision
an instance. We first create a build plan (a list of WeightedHosts)
and then provision.
@@ -113,7 +113,8 @@ class FilterScheduler(driver.Scheduler):
requested_networks,
injected_files, admin_password,
is_first_time,
instance_uuid=instance_uuid)
instance_uuid=instance_uuid,
legacy_bdm_in_spec=legacy_bdm_in_spec)
except Exception as ex:
# NOTE(vish): we don't reraise the exception here to make sure
# that all instances in the request get set to
@@ -154,7 +155,8 @@ class FilterScheduler(driver.Scheduler):
def _provision_resource(self, context, weighed_host, request_spec,
filter_properties, requested_networks, injected_files,
admin_password, is_first_time, instance_uuid=None):
admin_password, is_first_time, instance_uuid=None,
legacy_bdm_in_spec=True):
"""Create the requested resource in this Zone."""
# NOTE(vish): add our current instance back into the request spec
request_spec['instance_uuids'] = [instance_uuid]
@@ -194,7 +196,8 @@ class FilterScheduler(driver.Scheduler):
requested_networks=requested_networks,
injected_files=injected_files,
admin_password=admin_password, is_first_time=is_first_time,
node=weighed_host.obj.nodename)
node=weighed_host.obj.nodename,
legacy_bdm_in_spec=legacy_bdm_in_spec)
def _get_configuration_options(self):
"""Fetch options dictionary. Broken out for testing."""

View File

@@ -57,7 +57,7 @@ QUOTAS = quota.QUOTAS
class SchedulerManager(manager.Manager):
"""Chooses a host to run instances on."""
RPC_API_VERSION = '2.8'
RPC_API_VERSION = '2.9'
def __init__(self, scheduler_driver=None, *args, **kwargs):
if not scheduler_driver:
@@ -138,7 +138,7 @@ class SchedulerManager(manager.Manager):
def run_instance(self, context, request_spec, admin_password,
injected_files, requested_networks, is_first_time,
filter_properties):
filter_properties, legacy_bdm_in_spec=True):
"""Tries to call schedule_run_instance on the driver.
Sets instance vm_state to ERROR on exceptions
"""
@@ -148,7 +148,8 @@ class SchedulerManager(manager.Manager):
try:
return self.driver.schedule_run_instance(context,
request_spec, admin_password, injected_files,
requested_networks, is_first_time, filter_properties)
requested_networks, is_first_time, filter_properties,
legacy_bdm_in_spec)
except exception.NoValidHost as ex:
# don't re-raise

View File

@@ -69,6 +69,7 @@ class SchedulerAPI(nova.openstack.common.rpc.proxy.RpcProxy):
2.7 - Add select_destinations()
2.8 - Deprecate prep_resize()
2.9 - Added the leagacy_bdm_in_spec parameter to run_instances
'''
#
@@ -99,13 +100,14 @@ class SchedulerAPI(nova.openstack.common.rpc.proxy.RpcProxy):
def run_instance(self, ctxt, request_spec, admin_password,
injected_files, requested_networks, is_first_time,
filter_properties):
filter_properties, legacy_bdm_in_spec=True):
return self.cast(ctxt, self.make_msg('run_instance',
request_spec=request_spec, admin_password=admin_password,
injected_files=injected_files,
requested_networks=requested_networks,
is_first_time=is_first_time,
filter_properties=filter_properties))
filter_properties=filter_properties,
legacy_bdm_in_spec=legacy_bdm_in_spec), version='2.9')
# NOTE(timello): This method is deprecated and it's functionality has
# been moved to conductor. This should be removed in RPC_API_VERSION 3.0.

View File

@@ -94,7 +94,8 @@ class ChanceSchedulerTestCase(test_scheduler.SchedulerTestCase):
compute_rpcapi.ComputeAPI.run_instance(ctxt, host='host3',
instance=instance1, requested_networks=None,
injected_files=None, admin_password=None, is_first_time=None,
request_spec=request_spec, filter_properties={})
request_spec=request_spec, filter_properties={},
legacy_bdm_in_spec=False)
# instance 2
ctxt.elevated().AndReturn(ctxt_elevated)
@@ -105,11 +106,12 @@ class ChanceSchedulerTestCase(test_scheduler.SchedulerTestCase):
compute_rpcapi.ComputeAPI.run_instance(ctxt, host='host1',
instance=instance2, requested_networks=None,
injected_files=None, admin_password=None, is_first_time=None,
request_spec=request_spec, filter_properties={})
request_spec=request_spec, filter_properties={},
legacy_bdm_in_spec=False)
self.mox.ReplayAll()
self.driver.schedule_run_instance(ctxt, request_spec,
None, None, None, None, {})
None, None, None, None, {}, False)
def test_basic_schedule_run_instance_no_hosts(self):
ctxt = context.RequestContext('fake', 'fake', False)
@@ -136,7 +138,7 @@ class ChanceSchedulerTestCase(test_scheduler.SchedulerTestCase):
self.mox.ReplayAll()
self.driver.schedule_run_instance(
ctxt, request_spec, None, None, None, None, {})
ctxt, request_spec, None, None, None, None, {}, False)
def test_select_hosts(self):
ctxt = context.RequestContext('fake', 'fake', False)

View File

@@ -82,7 +82,8 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
self.mox.ReplayAll()
sched.schedule_run_instance(
fake_context, request_spec, None, None, None, None, {})
fake_context, request_spec, None, None,
None, None, {}, False)
def test_run_instance_non_admin(self):
self.was_admin = False
@@ -113,7 +114,7 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
mox.IsA(exception.NoValidHost), mox.IgnoreArg())
self.mox.ReplayAll()
sched.schedule_run_instance(
fake_context, request_spec, None, None, None, None, {})
fake_context, request_spec, None, None, None, None, {}, False)
self.assertTrue(self.was_admin)
def test_scheduler_includes_launch_index(self):
@@ -145,17 +146,19 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
fake_context, 'host1',
mox.Func(_has_launch_index(0)), {},
None, None, None, None,
instance_uuid='fake-uuid1').AndReturn(instance1)
instance_uuid='fake-uuid1',
legacy_bdm_in_spec=False).AndReturn(instance1)
# instance 2
self.driver._provision_resource(
fake_context, 'host2',
mox.Func(_has_launch_index(1)), {},
None, None, None, None,
instance_uuid='fake-uuid2').AndReturn(instance2)
instance_uuid='fake-uuid2',
legacy_bdm_in_spec=False).AndReturn(instance2)
self.mox.ReplayAll()
self.driver.schedule_run_instance(fake_context, request_spec,
None, None, None, None, {})
None, None, None, None, {}, False)
def test_schedule_happy_day(self):
"""Make sure there's nothing glaringly wrong with _schedule()
@@ -285,7 +288,8 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
self.context, request_spec, admin_password=None,
injected_files=None, requested_networks=None,
is_first_time=False,
filter_properties=filter_properties)
filter_properties=filter_properties,
legacy_bdm_in_spec=False)
uuids = request_spec.get('instance_uuids')
self.assertEqual(uuids, instance_uuids)
@@ -368,7 +372,7 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
instance=instance1_1, requested_networks=None,
injected_files=None, admin_password=None, is_first_time=None,
request_spec=request_spec1, filter_properties=mox.IgnoreArg(),
node='node3')
node='node3', legacy_bdm_in_spec=False)
driver.instance_update_db(fake_context, instance1_2['uuid'],
extra_values=expected_metadata).WithSideEffects(
@@ -377,10 +381,10 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
instance=instance1_2, requested_networks=None,
injected_files=None, admin_password=None, is_first_time=None,
request_spec=request_spec1, filter_properties=mox.IgnoreArg(),
node='node4')
node='node4', legacy_bdm_in_spec=False)
self.mox.ReplayAll()
sched.schedule_run_instance(fake_context, request_spec1,
None, None, None, None, filter_properties)
None, None, None, None, filter_properties, False)
def test_schedule_host_pool(self):
"""Make sure the scheduler_host_subset_size property works properly."""

View File

@@ -60,7 +60,8 @@ class SchedulerRpcAPITestCase(test.NoDBTestCase):
request_spec='fake_request_spec',
admin_password='pw', injected_files='fake_injected_files',
requested_networks='fake_requested_networks',
is_first_time=True, filter_properties='fake_filter_properties')
is_first_time=True, filter_properties='fake_filter_properties',
legacy_bdm_in_spec=False, version='2.9')
def test_prep_resize(self):
self._test_scheduler_api('prep_resize', rpc_method='cast',

View File

@@ -192,7 +192,7 @@ class SchedulerManagerTestCase(test.NoDBTestCase):
'instance_uuids': [fake_instance_uuid]}
self.manager.driver.schedule_run_instance(self.context,
request_spec, None, None, None, None, {}).AndRaise(
request_spec, None, None, None, None, {}, False).AndRaise(
exception.NoValidHost(reason=""))
old, new_ref = db.instance_update_and_get_original(self.context,
fake_instance_uuid,
@@ -204,7 +204,7 @@ class SchedulerManagerTestCase(test.NoDBTestCase):
self.mox.ReplayAll()
self.manager.run_instance(self.context, request_spec,
None, None, None, None, {})
None, None, None, None, {}, False)
def test_live_migration_schedule_novalidhost(self):
inst = {"uuid": "fake-instance-id",
@@ -586,7 +586,7 @@ class SchedulerDriverBaseTestCase(SchedulerTestCase):
self.assertRaises(NotImplementedError,
self.driver.schedule_run_instance,
self.context, fake_request_spec, None, None, None,
None, None)
None, None, False)
def test_unimplemented_select_hosts(self):
self.assertRaises(NotImplementedError,