diff options
-rw-r--r-- | nova/scheduler/chance.py | 6 | ||||
-rw-r--r-- | nova/scheduler/driver.py | 5 | ||||
-rw-r--r-- | nova/scheduler/filter_scheduler.py | 5 | ||||
-rw-r--r-- | nova/scheduler/manager.py | 9 | ||||
-rw-r--r-- | nova/scheduler/rpcapi.py | 7 | ||||
-rw-r--r-- | nova/tests/scheduler/test_chance_scheduler.py | 30 | ||||
-rw-r--r-- | nova/tests/scheduler/test_filter_scheduler.py | 40 | ||||
-rw-r--r-- | nova/tests/scheduler/test_rpcapi.py | 6 |
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') |