diff options
author | Mike Milner <mike.milner@canonical.com> | 2012-02-23 15:13:51 -0400 |
---|---|---|
committer | Vishvananda Ishaya <vishvananda@gmail.com> | 2012-02-29 11:55:23 -0800 |
commit | 09e664c0f00326d3dea8c04ac661ca0a05bbf0f5 (patch) | |
tree | 67d5cba184c6482fa31cc6796bb322fef3df1ade | |
parent | 10c58c6e81ed8623091231fb1ef65c8529b43fe1 (diff) | |
download | nova-09e664c0f00326d3dea8c04ac661ca0a05bbf0f5.tar.gz |
Include launch_index when creating instances.
Fixes bug 934534.
The launch_index column in the database is used as the ami-launch-index value
provided by the metadata service.
If launch_index is not specified it defaults to 1. This is incorrect for the
single instance case (should be 0) and doesn't correctly handle multi-instance
starts.
This branch changes the default launch_index to 0 (to handle the single
instance case) and adds the launch_index in the schedulers for multi-instance
starts.
Change-Id: Ifc45abf4cd9f50f732ba4a4b68c0a6242a6c9710
-rw-r--r-- | Authors | 1 | ||||
-rw-r--r-- | nova/compute/api.py | 6 | ||||
-rw-r--r-- | nova/scheduler/chance.py | 1 | ||||
-rw-r--r-- | nova/scheduler/distributed_scheduler.py | 1 | ||||
-rw-r--r-- | nova/scheduler/simple.py | 1 | ||||
-rw-r--r-- | nova/tests/scheduler/test_chance_scheduler.py | 53 | ||||
-rw-r--r-- | nova/tests/scheduler/test_distributed_scheduler.py | 54 | ||||
-rw-r--r-- | nova/tests/test_compute.py | 3 |
8 files changed, 114 insertions, 6 deletions
@@ -123,6 +123,7 @@ Michael Basnight <mbasnigh@rackspace.com> Michael Gundlach <michael.gundlach@rackspace.com> Michael Still <mikal@stillhq.com> Mike Lundy <mike@pistoncloud.com> +Mike Milner <mike.milner@canonical.com> Mike Pittaro <mikeyp@lahondaresearch.org> Mike Scherbakov <mihgen@gmail.com> Mikyung Kang <mkkang@isi.edu> diff --git a/nova/compute/api.py b/nova/compute/api.py index 0aee6dc2fe..d900fb77f5 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -462,7 +462,7 @@ class API(base.Base): #NOTE(bcwaldon): No policy check since this is only used by scheduler and # the compute api. That should probably be cleaned up, though. def create_db_entry_for_new_instance(self, context, instance_type, image, - base_options, security_group, block_device_mapping, num=1): + base_options, security_group, block_device_mapping): """Create an entry in the DB for this new instance, including any related table updates (such as security group, etc). @@ -483,8 +483,8 @@ class API(base.Base): security_group_name) security_groups.append(group['id']) - instance = dict(launch_index=num, **base_options) - instance = self.db.instance_create(context, instance) + base_options.setdefault('launch_index', 0) + instance = self.db.instance_create(context, base_options) instance_id = instance['id'] instance_uuid = instance['uuid'] diff --git a/nova/scheduler/chance.py b/nova/scheduler/chance.py index 587c11af9b..fbe36e7037 100644 --- a/nova/scheduler/chance.py +++ b/nova/scheduler/chance.py @@ -66,6 +66,7 @@ class ChanceScheduler(driver.Scheduler): instances = [] for num in xrange(num_instances): host = self._schedule(context, 'compute', request_spec, **kwargs) + request_spec['instance_properties']['launch_index'] = num instance = self.create_instance_db_entry(context, request_spec) driver.cast_to_compute_host(context, host, 'run_instance', instance_uuid=instance['uuid'], **kwargs) diff --git a/nova/scheduler/distributed_scheduler.py b/nova/scheduler/distributed_scheduler.py index debd6c0db4..0a94360459 100644 --- a/nova/scheduler/distributed_scheduler.py +++ b/nova/scheduler/distributed_scheduler.py @@ -84,6 +84,7 @@ class DistributedScheduler(driver.Scheduler): break weighted_host = weighted_hosts.pop(0) + request_spec['instance_properties']['launch_index'] = num instance = self._provision_resource(elevated, weighted_host, request_spec, kwargs) diff --git a/nova/scheduler/simple.py b/nova/scheduler/simple.py index a02417eaf7..40c6607f69 100644 --- a/nova/scheduler/simple.py +++ b/nova/scheduler/simple.py @@ -97,6 +97,7 @@ class SimpleScheduler(chance.ChanceScheduler): for num in xrange(num_instances): host = self._schedule_instance(context, request_spec['instance_properties'], *_args, **_kwargs) + request_spec['instance_properties']['launch_index'] = num instance_ref = self.create_instance_db_entry(context, request_spec) driver.cast_to_compute_host(context, host, 'run_instance', diff --git a/nova/tests/scheduler/test_chance_scheduler.py b/nova/tests/scheduler/test_chance_scheduler.py index 8f82ea16f3..ed6ffeba4a 100644 --- a/nova/tests/scheduler/test_chance_scheduler.py +++ b/nova/tests/scheduler/test_chance_scheduler.py @@ -20,6 +20,8 @@ Tests For Chance Scheduler. import random +import mox + from nova import context from nova import exception from nova.scheduler import driver @@ -114,6 +116,57 @@ class ChanceSchedulerTestCase(test_scheduler.SchedulerTestCase): expected = [instance1_encoded, instance2_encoded] self.assertEqual(result, expected) + def test_scheduler_includes_launch_index(self): + ctxt = "fake-context" + instance_opts = {'fake_opt1': 'meow'} + request_spec = {'num_instances': 2, + 'instance_properties': instance_opts} + instance1 = {'uuid': 'fake-uuid1'} + instance2 = {'uuid': 'fake-uuid2'} + + # create_instance_db_entry() usually does this, but we're + # stubbing it. + def _add_uuid(num): + """Return a function that adds the provided uuid number.""" + def _add_uuid_num(_, spec): + spec['instance_properties']['uuid'] = 'fake-uuid%d' % num + return _add_uuid_num + + def _has_launch_index(expected_index): + """Return a function that verifies the expected index.""" + def _check_launch_index(value): + if 'instance_properties' in value: + if 'launch_index' in value['instance_properties']: + index = value['instance_properties']['launch_index'] + if index == expected_index: + return True + return False + return _check_launch_index + + self.mox.StubOutWithMock(self.driver, '_schedule') + self.mox.StubOutWithMock(self.driver, 'create_instance_db_entry') + self.mox.StubOutWithMock(driver, 'cast_to_compute_host') + self.mox.StubOutWithMock(driver, 'encode_instance') + # instance 1 + self.driver._schedule(ctxt, 'compute', request_spec).AndReturn('host') + self.driver.create_instance_db_entry( + ctxt, mox.Func(_has_launch_index(0)) + ).WithSideEffects(_add_uuid(1)).AndReturn(instance1) + driver.cast_to_compute_host(ctxt, 'host', 'run_instance', + instance_uuid=instance1['uuid']) + driver.encode_instance(instance1).AndReturn(instance1) + # instance 2 + self.driver._schedule(ctxt, 'compute', request_spec).AndReturn('host') + self.driver.create_instance_db_entry( + ctxt, mox.Func(_has_launch_index(1)) + ).WithSideEffects(_add_uuid(2)).AndReturn(instance2) + driver.cast_to_compute_host(ctxt, 'host', 'run_instance', + instance_uuid=instance2['uuid']) + driver.encode_instance(instance2).AndReturn(instance2) + self.mox.ReplayAll() + + self.driver.schedule_run_instance(ctxt, request_spec) + def test_basic_schedule_run_instance_no_hosts(self): ctxt = context.RequestContext('fake', 'fake', False) ctxt_elevated = 'fake-context-elevated' diff --git a/nova/tests/scheduler/test_distributed_scheduler.py b/nova/tests/scheduler/test_distributed_scheduler.py index a0deffe7bf..a8e2d9317b 100644 --- a/nova/tests/scheduler/test_distributed_scheduler.py +++ b/nova/tests/scheduler/test_distributed_scheduler.py @@ -16,21 +16,26 @@ Tests For Distributed Scheduler. """ +import mox + from nova import context from nova import exception from nova.scheduler import least_cost from nova.scheduler import host_manager +from nova.scheduler import distributed_scheduler from nova import test -from nova.tests.scheduler import fakes +from nova.tests.scheduler import fakes, test_scheduler def fake_filter_hosts(hosts, filter_properties): return list(hosts) -class DistributedSchedulerTestCase(test.TestCase): +class DistributedSchedulerTestCase(test_scheduler.SchedulerTestCase): """Test case for Distributed Scheduler.""" + driver_cls = distributed_scheduler.DistributedScheduler + def test_run_instance_no_hosts(self): """ Ensure empty hosts & child_zones result in NoValidHosts exception. @@ -76,6 +81,51 @@ class DistributedSchedulerTestCase(test.TestCase): self.assertRaises(NotImplementedError, sched._schedule, fake_context, "foo", {}) + def test_scheduler_includes_launch_index(self): + ctxt = "fake-context" + fake_kwargs = {'fake_kwarg1': 'fake_value1', + 'fake_kwarg2': 'fake_value2'} + instance_opts = {'fake_opt1': 'meow'} + request_spec = {'num_instances': 2, + 'instance_properties': instance_opts} + instance1 = {'uuid': 'fake-uuid1'} + instance2 = {'uuid': 'fake-uuid2'} + + def _has_launch_index(expected_index): + """Return a function that verifies the expected index.""" + def _check_launch_index(value): + if 'instance_properties' in value: + if 'launch_index' in value['instance_properties']: + index = value['instance_properties']['launch_index'] + if index == expected_index: + return True + return False + return _check_launch_index + + class ContextFake(object): + def elevated(self): + return ctxt + context_fake = ContextFake() + + self.mox.StubOutWithMock(self.driver, '_schedule') + self.mox.StubOutWithMock(self.driver, '_provision_resource') + + self.driver._schedule(context_fake, 'compute', + request_spec, **fake_kwargs + ).AndReturn(['host1', 'host2']) + # instance 1 + self.driver._provision_resource( + ctxt, 'host1', + mox.Func(_has_launch_index(0)), fake_kwargs).AndReturn(instance1) + # instance 2 + self.driver._provision_resource( + ctxt, 'host2', + mox.Func(_has_launch_index(1)), fake_kwargs).AndReturn(instance2) + self.mox.ReplayAll() + + self.driver.schedule_run_instance(context_fake, request_spec, + **fake_kwargs) + def test_schedule_happy_day(self): """Make sure there's nothing glaringly wrong with _schedule() by doing a happy day pass through.""" diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 522f57eb13..09e3d8aca2 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -80,7 +80,8 @@ def rpc_call_wrapper(context, topic, msg, do_cast=True): scheduler = scheduler_driver.Scheduler num_instances = request_spec.get('num_instances', 1) instances = [] - for x in xrange(num_instances): + for num in xrange(num_instances): + request_spec['instance_properties']['launch_index'] = num instance = scheduler().create_instance_db_entry( context, request_spec) encoded = scheduler_driver.encode_instance(instance) |