summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/scheduler/chance.py6
-rw-r--r--nova/scheduler/driver.py5
-rw-r--r--nova/scheduler/filter_scheduler.py5
-rw-r--r--nova/scheduler/manager.py9
-rw-r--r--nova/scheduler/rpcapi.py7
-rw-r--r--nova/tests/scheduler/test_chance_scheduler.py30
-rw-r--r--nova/tests/scheduler/test_filter_scheduler.py40
-rw-r--r--nova/tests/scheduler/test_rpcapi.py6
8 files changed, 107 insertions, 1 deletions
diff --git a/nova/scheduler/chance.py b/nova/scheduler/chance.py
index e161166fd..806758e42 100644
--- a/nova/scheduler/chance.py
+++ b/nova/scheduler/chance.py
@@ -57,6 +57,12 @@ class ChanceScheduler(driver.Scheduler):
return hosts[int(random.random() * len(hosts))]
+ def select_hosts(self, context, request_spec, filter_properties):
+ """Selects a set of random hosts."""
+ return [self._schedule(context, CONF.compute_topic,
+ request_spec, filter_properties)
+ for instance_uuid in request_spec.get('instance_uuids', [])]
+
def schedule_run_instance(self, context, request_spec,
admin_password, injected_files,
requested_networks, is_first_time,
diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py
index 2565e4e40..1a2e8254a 100644
--- a/nova/scheduler/driver.py
+++ b/nova/scheduler/driver.py
@@ -160,6 +160,11 @@ class Scheduler(object):
msg = _("Driver must implement schedule_run_instance")
raise NotImplementedError(msg)
+ def select_hosts(self, context, request_spec, filter_properties):
+ """Must override select_hosts method for scheduler to work."""
+ msg = _("Driver must implement select_hosts")
+ raise NotImplementedError(msg)
+
def schedule_live_migration(self, context, instance, dest,
block_migration, disk_over_commit):
"""Live migration scheduling method.
diff --git a/nova/scheduler/filter_scheduler.py b/nova/scheduler/filter_scheduler.py
index c9118cb22..ecf909c9b 100644
--- a/nova/scheduler/filter_scheduler.py
+++ b/nova/scheduler/filter_scheduler.py
@@ -137,6 +137,11 @@ class FilterScheduler(driver.Scheduler):
request_spec=request_spec, filter_properties=filter_properties,
node=weighed_host.obj.nodename)
+ def select_hosts(self, context, request_spec, filter_properties):
+ """Selects a filtered set of hosts."""
+ return [host.obj.host for host in self._schedule(context, request_spec,
+ filter_properties)]
+
def _provision_resource(self, context, weighed_host, request_spec,
filter_properties, requested_networks, injected_files,
admin_password, is_first_time, instance_uuid=None):
diff --git a/nova/scheduler/manager.py b/nova/scheduler/manager.py
index 64a388f60..176d1f014 100644
--- a/nova/scheduler/manager.py
+++ b/nova/scheduler/manager.py
@@ -56,7 +56,7 @@ QUOTAS = quota.QUOTAS
class SchedulerManager(manager.Manager):
"""Chooses a host to run instances on."""
- RPC_API_VERSION = '2.5'
+ RPC_API_VERSION = '2.6'
def __init__(self, scheduler_driver=None, *args, **kwargs):
if not scheduler_driver:
@@ -285,3 +285,10 @@ class SchedulerManager(manager.Manager):
def get_backdoor_port(self, context):
return self.backdoor_port
+
+ def select_hosts(self, context, request_spec, filter_properties):
+ """Returns host(s) best suited for this request_spec and
+ filter_properties"""
+ hosts = self.driver.select_hosts(context, request_spec,
+ filter_properties)
+ return hosts
diff --git a/nova/scheduler/rpcapi.py b/nova/scheduler/rpcapi.py
index c3a37d6ad..5ce8abd7f 100644
--- a/nova/scheduler/rpcapi.py
+++ b/nova/scheduler/rpcapi.py
@@ -56,6 +56,7 @@ class SchedulerAPI(nova.openstack.common.rpc.proxy.RpcProxy):
2.4 - Change update_service_capabilities()
- accepts a list of capabilities
2.5 - Add get_backdoor_port()
+ 2.6 - Add select_hosts()
'''
#
@@ -117,3 +118,9 @@ class SchedulerAPI(nova.openstack.common.rpc.proxy.RpcProxy):
def get_backdoor_port(self, context, host):
return self.call(context, self.make_msg('get_backdoor_port'),
version='2.5')
+
+ def select_hosts(self, ctxt, request_spec, filter_properties):
+ return self.call(ctxt, self.make_msg('select_hosts',
+ request_spec=request_spec,
+ filter_properties=filter_properties),
+ version='2.6')
diff --git a/nova/tests/scheduler/test_chance_scheduler.py b/nova/tests/scheduler/test_chance_scheduler.py
index dcbe86f75..0ee617044 100644
--- a/nova/tests/scheduler/test_chance_scheduler.py
+++ b/nova/tests/scheduler/test_chance_scheduler.py
@@ -165,3 +165,33 @@ class ChanceSchedulerTestCase(test_scheduler.SchedulerTestCase):
self.driver.schedule_prep_resize(fake_context, {}, {}, {},
instance, {}, None)
self.assertEqual(info['called'], 0)
+
+ def test_select_hosts(self):
+ ctxt = context.RequestContext('fake', 'fake', False)
+ ctxt_elevated = 'fake-context-elevated'
+ fake_args = (1, 2, 3)
+ instance_opts = {'fake_opt1': 'meow', 'launch_index': -1}
+ instance1 = {'uuid': 'fake-uuid1'}
+ instance2 = {'uuid': 'fake-uuid2'}
+ request_spec = {'instance_uuids': ['fake-uuid1', 'fake-uuid2'],
+ 'instance_properties': instance_opts}
+
+ self.mox.StubOutWithMock(ctxt, 'elevated')
+ self.mox.StubOutWithMock(self.driver, 'hosts_up')
+ self.mox.StubOutWithMock(random, 'random')
+
+ ctxt.elevated().AndReturn(ctxt_elevated)
+ # instance 1
+ self.driver.hosts_up(ctxt_elevated, 'compute').AndReturn(
+ ['host1', 'host2', 'host3', 'host4'])
+ random.random().AndReturn(.5)
+
+ # instance 2
+ ctxt.elevated().AndReturn(ctxt_elevated)
+ self.driver.hosts_up(ctxt_elevated, 'compute').AndReturn(
+ ['host1', 'host2', 'host3', 'host4'])
+ random.random().AndReturn(.2)
+
+ self.mox.ReplayAll()
+ hosts = self.driver.select_hosts(ctxt, request_spec, {})
+ self.assertEquals(['host3', 'host1'], hosts)
diff --git a/nova/tests/scheduler/test_filter_scheduler.py b/nova/tests/scheduler/test_filter_scheduler.py
index 4b07581fb..849f63f5d 100644
--- a/nova/tests/scheduler/test_filter_scheduler.py
+++ b/nova/tests/scheduler/test_filter_scheduler.py
@@ -656,3 +656,43 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
self.assertEquals(1, len(hosts))
self.assertEquals(50, hosts[0].weight)
+
+ def test_select_hosts_happy_day(self):
+ """select_hosts is basically a wrapper around the _select() method.
+ Similar to the _select tests, this just does a happy path test to
+ ensure there is nothing glaringly wrong."""
+
+ self.next_weight = 1.0
+
+ selected_hosts = []
+
+ def _fake_weigh_objects(_self, functions, hosts, options):
+ self.next_weight += 2.0
+ host_state = hosts[0]
+ selected_hosts.append(host_state.host)
+ return [weights.WeighedHost(host_state, self.next_weight)]
+
+ sched = fakes.FakeFilterScheduler()
+ fake_context = context.RequestContext('user', 'project',
+ is_admin=True)
+
+ self.stubs.Set(sched.host_manager, 'get_filtered_hosts',
+ fake_get_filtered_hosts)
+ self.stubs.Set(weights.HostWeightHandler,
+ 'get_weighed_objects', _fake_weigh_objects)
+ fakes.mox_host_manager_db_calls(self.mox, fake_context)
+
+ request_spec = {'num_instances': 10,
+ 'instance_type': {'memory_mb': 512, 'root_gb': 512,
+ 'ephemeral_gb': 0,
+ 'vcpus': 1},
+ 'instance_properties': {'project_id': 1,
+ 'root_gb': 512,
+ 'memory_mb': 512,
+ 'ephemeral_gb': 0,
+ 'vcpus': 1,
+ 'os_type': 'Linux'}}
+ self.mox.ReplayAll()
+ hosts = sched.select_hosts(fake_context, request_spec, {})
+ self.assertEquals(len(hosts), 10)
+ self.assertEquals(hosts, selected_hosts)
diff --git a/nova/tests/scheduler/test_rpcapi.py b/nova/tests/scheduler/test_rpcapi.py
index e9a1680a8..af6a57ba6 100644
--- a/nova/tests/scheduler/test_rpcapi.py
+++ b/nova/tests/scheduler/test_rpcapi.py
@@ -90,3 +90,9 @@ class SchedulerRpcAPITestCase(test.TestCase):
def test_get_backdoor_port(self):
self._test_scheduler_api('get_backdoor_port', rpc_method='call',
host='fake_host', version='2.5')
+
+ def test_select_hosts(self):
+ self._test_scheduler_api('select_hosts', rpc_method='call',
+ request_spec='fake_request_spec',
+ filter_properties='fake_prop',
+ version='2.6')