summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Authors1
-rw-r--r--nova/compute/api.py6
-rw-r--r--nova/scheduler/chance.py1
-rw-r--r--nova/scheduler/distributed_scheduler.py1
-rw-r--r--nova/scheduler/simple.py1
-rw-r--r--nova/tests/scheduler/test_chance_scheduler.py53
-rw-r--r--nova/tests/scheduler/test_distributed_scheduler.py54
-rw-r--r--nova/tests/test_compute.py3
8 files changed, 114 insertions, 6 deletions
diff --git a/Authors b/Authors
index ec0e28b06..24595be6c 100644
--- a/Authors
+++ b/Authors
@@ -121,6 +121,7 @@ Matthew Hooker <matt@cloudscaling.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 0aee6dc2f..d900fb77f 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 587c11af9..fbe36e703 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 debd6c0db..0a9436045 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 a02417eaf..40c6607f6 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 8f82ea16f..ed6ffeba4 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 a0deffe7b..a8e2d9317 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 522f57eb1..09e3d8aca 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)