From 6d04d6e17f753e0573d37992576dedccccf9db93 Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Fri, 13 May 2011 10:43:43 -0700 Subject: started on integrating HostFilter --- nova/scheduler/host_filter.py | 18 ++++++++++++++++++ nova/scheduler/zone_aware_scheduler.py | 16 ++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/nova/scheduler/host_filter.py b/nova/scheduler/host_filter.py index 483f3225c..17f63d4a0 100644 --- a/nova/scheduler/host_filter.py +++ b/nova/scheduler/host_filter.py @@ -286,3 +286,21 @@ def choose_driver(driver_name=None): if "%s.%s" % (driver.__module__, driver.__name__) == driver_name: return driver() raise exception.SchedulerHostFilterDriverNotFound(driver_name=driver_name) + + +class HostFilterScheduler(ZoneAwareScheduler): + """The HostFilterScheduler uses the HostFilter drivers to filter + hosts for weighing. The particular driver used may be passed in + as an argument or the default will be used.""" + + def filter_hosts(self, num, specs): + """Filter the full host list (from the ZoneManager)""" + driver_name = specs.get("filter_driver", None) + driver = host_filter.choose_driver(driver_name) + + # TODO(sandy): We're only using InstanceType-based specs + # currently. Later we'll need to snoop for more detailed + # host filter requests. + instance_type = specs['instance_type'] + query = driver.instance_type_to_filter(query) + return driver.filter_hosts(self.zone_manager, query) diff --git a/nova/scheduler/zone_aware_scheduler.py b/nova/scheduler/zone_aware_scheduler.py index b3d230bd2..fde8b6792 100644 --- a/nova/scheduler/zone_aware_scheduler.py +++ b/nova/scheduler/zone_aware_scheduler.py @@ -25,6 +25,7 @@ import operator from nova import log as logging from nova.scheduler import api from nova.scheduler import driver +from nova.scheduler import host_filter LOG = logging.getLogger('nova.scheduler.zone_aware_scheduler') @@ -36,7 +37,7 @@ class ZoneAwareScheduler(driver.Scheduler): """Call novaclient zone method. Broken out for testing.""" return api.call_zone_method(context, method, specs=specs) - def schedule_run_instance(self, context, topic='compute', specs={}, + def schedule_run_instance(self, context, instance_id, instance_type, *args, **kwargs): """This method is called from nova.compute.api to provision an instance. However we need to look at the parameters being @@ -46,6 +47,9 @@ class ZoneAwareScheduler(driver.Scheduler): to simply create the instance (either in this zone or a child zone).""" + # TODO(sandy): We'll have to look for richer specs at some point. + specs = instance_type + if 'blob' in specs: return self.provision_instance(context, topic, specs) @@ -58,7 +62,7 @@ class ZoneAwareScheduler(driver.Scheduler): """Create the requested instance in this Zone or a child zone.""" pass - def select(self, context, *args, **kwargs): + def select(self, context, specs, *args, **kwargs): """Select returns a list of weights and zone/host information corresponding to the best hosts to service the request. Any child zone information has been encrypted so as not to reveal @@ -80,9 +84,13 @@ class ZoneAwareScheduler(driver.Scheduler): ordered by their fitness. """ - #TODO(sandy): extract these from args. + if topic != "compute": + raise NotImplemented(_("Zone Aware Scheduler only understands " + "Compute nodes (for now)")) + + specs = args['instance_type'] + #TODO(sandy): how to infer this from OS API params? num_instances = 1 - specs = {} # Filter local hosts based on requirements ... host_list = self.filter_hosts(num_instances, specs) -- cgit From 02bba6a8f49b924e9b5b0e69124afd953e8cc3ae Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Mon, 16 May 2011 15:37:25 -0700 Subject: basic call going through --- nova/compute/api.py | 7 ++++++- nova/scheduler/host_filter.py | 19 ++++++++++--------- nova/scheduler/zone_aware_scheduler.py | 32 +++++++++++++++----------------- nova/virt/fake.py | 24 ++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 8a7c713a2..f57d5cd90 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -259,7 +259,12 @@ class API(base.Base): {"method": "run_instance", "args": {"topic": FLAGS.compute_topic, "instance_id": instance_id, - "instance_type": instance_type, + "request_spec": { + 'instance_type': instance_type, + 'filter_driver': + 'nova.scheduler.host_filter.' + 'InstanceTypeFilter' + }, "availability_zone": availability_zone, "injected_files": injected_files}}) diff --git a/nova/scheduler/host_filter.py b/nova/scheduler/host_filter.py index 17f63d4a0..a47e41da4 100644 --- a/nova/scheduler/host_filter.py +++ b/nova/scheduler/host_filter.py @@ -42,6 +42,7 @@ from nova import exception from nova import flags from nova import log as logging from nova import utils +from nova.scheduler import zone_aware_scheduler LOG = logging.getLogger('nova.scheduler.host_filter') @@ -83,8 +84,8 @@ class AllHostsFilter(HostFilter): for host, services in zone_manager.service_states.iteritems()] -class FlavorFilter(HostFilter): - """HostFilter driver hard-coded to work with flavors.""" +class InstanceTypeFilter(HostFilter): + """HostFilter driver hard-coded to work with InstanceType records.""" def instance_type_to_filter(self, instance_type): """Use instance_type to filter hosts.""" @@ -271,7 +272,7 @@ class JsonFilter(HostFilter): return hosts -DRIVERS = [AllHostsFilter, FlavorFilter, JsonFilter] +DRIVERS = [AllHostsFilter, InstanceTypeFilter, JsonFilter] def choose_driver(driver_name=None): @@ -288,19 +289,19 @@ def choose_driver(driver_name=None): raise exception.SchedulerHostFilterDriverNotFound(driver_name=driver_name) -class HostFilterScheduler(ZoneAwareScheduler): +class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler): """The HostFilterScheduler uses the HostFilter drivers to filter hosts for weighing. The particular driver used may be passed in as an argument or the default will be used.""" - def filter_hosts(self, num, specs): + def filter_hosts(self, num, request_spec): """Filter the full host list (from the ZoneManager)""" - driver_name = specs.get("filter_driver", None) - driver = host_filter.choose_driver(driver_name) + driver_name = request_spec.get("filter_driver", None) + driver = choose_driver(driver_name) # TODO(sandy): We're only using InstanceType-based specs # currently. Later we'll need to snoop for more detailed # host filter requests. - instance_type = specs['instance_type'] - query = driver.instance_type_to_filter(query) + instance_type = request_spec['instance_type'] + query = driver.instance_type_to_filter(instance_type) return driver.filter_hosts(self.zone_manager, query) diff --git a/nova/scheduler/zone_aware_scheduler.py b/nova/scheduler/zone_aware_scheduler.py index fde8b6792..f9c5f65f3 100644 --- a/nova/scheduler/zone_aware_scheduler.py +++ b/nova/scheduler/zone_aware_scheduler.py @@ -25,7 +25,6 @@ import operator from nova import log as logging from nova.scheduler import api from nova.scheduler import driver -from nova.scheduler import host_filter LOG = logging.getLogger('nova.scheduler.zone_aware_scheduler') @@ -37,7 +36,7 @@ class ZoneAwareScheduler(driver.Scheduler): """Call novaclient zone method. Broken out for testing.""" return api.call_zone_method(context, method, specs=specs) - def schedule_run_instance(self, context, instance_id, instance_type, + def schedule_run_instance(self, context, instance_id, request_spec, *args, **kwargs): """This method is called from nova.compute.api to provision an instance. However we need to look at the parameters being @@ -48,13 +47,12 @@ class ZoneAwareScheduler(driver.Scheduler): a child zone).""" # TODO(sandy): We'll have to look for richer specs at some point. - specs = instance_type - if 'blob' in specs: - return self.provision_instance(context, topic, specs) + if 'blob' in request_spec: + return self.provision_instance(context, topic, request_spec) # Create build plan and provision ... - build_plan = self.select(context, specs) + build_plan = self.select(context, request_spec) for item in build_plan: self.provision_instance(context, topic, item) @@ -62,24 +60,24 @@ class ZoneAwareScheduler(driver.Scheduler): """Create the requested instance in this Zone or a child zone.""" pass - def select(self, context, specs, *args, **kwargs): + def select(self, context, request_spec, *args, **kwargs): """Select returns a list of weights and zone/host information corresponding to the best hosts to service the request. Any child zone information has been encrypted so as not to reveal anything about the children.""" - return self._schedule(context, "compute", *args, **kwargs) + return self._schedule(context, "compute", request_spec, *args, **kwargs) - def schedule(self, context, topic, *args, **kwargs): + def schedule(self, context, topic, request_spec, *args, **kwargs): """The schedule() contract requires we return the one best-suited host for this request. """ - res = self._schedule(context, topic, *args, **kwargs) + res = self._schedule(context, topic, request_spec, *args, **kwargs) # TODO(sirp): should this be a host object rather than a weight-dict? if not res: raise driver.NoValidHost(_('No hosts were available')) return res[0] - def _schedule(self, context, topic, *args, **kwargs): + def _schedule(self, context, topic, request_spec, *args, **kwargs): """Returns a list of hosts that meet the required specs, ordered by their fitness. """ @@ -88,20 +86,20 @@ class ZoneAwareScheduler(driver.Scheduler): raise NotImplemented(_("Zone Aware Scheduler only understands " "Compute nodes (for now)")) - specs = args['instance_type'] + LOG.debug("specs = %s, ARGS = %s" % (request_spec, args, )) #TODO(sandy): how to infer this from OS API params? num_instances = 1 # Filter local hosts based on requirements ... - host_list = self.filter_hosts(num_instances, specs) + host_list = self.filter_hosts(num_instances, request_spec) # then weigh the selected hosts. # weighted = [{weight=weight, name=hostname}, ...] - weighted = self.weigh_hosts(num_instances, specs, host_list) + weighted = self.weigh_hosts(num_instances, request_spec, host_list) # Next, tack on the best weights from the child zones ... child_results = self._call_zone_method(context, "select", - specs=specs) + specs=request_spec) for child_zone, result in child_results: for weighting in result: # Remember the child_zone so we can get back to @@ -116,12 +114,12 @@ class ZoneAwareScheduler(driver.Scheduler): weighted.sort(key=operator.itemgetter('weight')) return weighted - def filter_hosts(self, num, specs): + def filter_hosts(self, num, request_spec): """Derived classes must override this method and return a list of hosts in [(hostname, capability_dict)] format.""" raise NotImplemented() - def weigh_hosts(self, num, specs, hosts): + def weigh_hosts(self, num, request_spec, hosts): """Derived classes must override this method and return a lists of hosts in [{weight, hostname}] format.""" raise NotImplemented() diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 5ac376e46..bf87e5ced 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -82,6 +82,20 @@ class FakeConnection(driver.ComputeDriver): def __init__(self): self.instances = {} + self.host_status = {'host_name-description': 'Fake Host', + 'host_hostname': 'fake-mini', + 'host_memory_total': 8000000000, + 'host_memory_overhead': 10000000, + 'host_memory_free': 7900000000, + 'host_memory_free_computed': 7900000000, + 'host_other-config': {}, + 'host_ip_address': '192.168.1.109', + 'host_cpu_info': {}, + 'disk_available': 500000000000, + 'disk_total': 600000000000, + 'disk_used': 100000000000, + 'host_uuid': 'cedb9b39-9388-41df-8891-c5c9a0c0fe5f', + 'host_name-label': 'fake-mini'} @classmethod def instance(cls): @@ -456,3 +470,13 @@ class FakeConnection(driver.ComputeDriver): def test_remove_vm(self, instance_name): """ Removes the named VM, as if it crashed. For testing""" self.instances.pop(instance_name) + + def update_host_status(self): + """Return fake Host Status of ram, disk, network.""" + return self.host_status + + def get_host_stats(self, refresh=False): + """Return fake Host Status of ram, disk, network.""" + return self.host_status + + -- cgit From 7ed85c9ee57190589efcb22819783d6faf973cc3 Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Tue, 17 May 2011 05:27:50 -0700 Subject: tests fixed and pep8'ed --- nova/scheduler/host_filter.py | 10 +++++++--- nova/scheduler/manager.py | 3 ++- nova/scheduler/zone_aware_scheduler.py | 11 ++++++++--- nova/tests/test_host_filter.py | 11 ++++++----- nova/virt/fake.py | 2 -- 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/nova/scheduler/host_filter.py b/nova/scheduler/host_filter.py index 8519b8b51..2b0d9af77 100644 --- a/nova/scheduler/host_filter.py +++ b/nova/scheduler/host_filter.py @@ -292,11 +292,15 @@ def choose_driver(driver_name=None): class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler): """The HostFilterScheduler uses the HostFilter drivers to filter hosts for weighing. The particular driver used may be passed in - as an argument or the default will be used.""" + as an argument or the default will be used. + + request_spec = {'filter_driver': , + 'instance_type': } + """ def filter_hosts(self, num, request_spec): """Filter the full host list (from the ZoneManager)""" - driver_name = request_spec.get("filter_driver", None) + driver_name = request_spec.get('filter_driver', None) driver = choose_driver(driver_name) # TODO(sandy): We're only using InstanceType-based specs @@ -309,4 +313,4 @@ class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler): def weigh_hosts(self, num, request_spec, hosts): """Derived classes must override this method and return a lists of hosts in [{weight, hostname}] format.""" - return [] + return [dict(weight=1, hostname=hostname) for host, caps in hosts] diff --git a/nova/scheduler/manager.py b/nova/scheduler/manager.py index 60f98b082..bd40e73c0 100644 --- a/nova/scheduler/manager.py +++ b/nova/scheduler/manager.py @@ -84,7 +84,8 @@ class SchedulerManager(manager.Manager): host = self.driver.schedule(elevated, topic, *args, **kwargs) if not host: - LOG.debug(_("%(topic)s %(method)s handled in Scheduler") % locals()) + LOG.debug(_("%(topic)s %(method)s handled in Scheduler") + % locals()) return rpc.cast(context, diff --git a/nova/scheduler/zone_aware_scheduler.py b/nova/scheduler/zone_aware_scheduler.py index 2fc5f1f87..614b1bb89 100644 --- a/nova/scheduler/zone_aware_scheduler.py +++ b/nova/scheduler/zone_aware_scheduler.py @@ -59,20 +59,25 @@ class ZoneAwareScheduler(driver.Scheduler): for item in build_plan: self.provision_instance(context, topic, item) + # Returning None short-circuits the routing to Compute (since + # we've already done it here) + return None + def provision_instance(context, topic, item): """Create the requested instance in this Zone or a child zone.""" - pass + return None def select(self, context, request_spec, *args, **kwargs): """Select returns a list of weights and zone/host information corresponding to the best hosts to service the request. Any child zone information has been encrypted so as not to reveal anything about the children.""" - return self._schedule(context, "compute", request_spec, *args, **kwargs) + return self._schedule(context, "compute", request_spec, + *args, **kwargs) # TODO(sandy): We're only focused on compute instances right now, # so we don't implement the default "schedule()" method required - # of Schedulers. + # of Schedulers. def schedule(self, context, topic, request_spec, *args, **kwargs): """The schedule() contract requires we return the one best-suited host for this request. diff --git a/nova/tests/test_host_filter.py b/nova/tests/test_host_filter.py index c029d41e6..dd2325cc6 100644 --- a/nova/tests/test_host_filter.py +++ b/nova/tests/test_host_filter.py @@ -85,9 +85,9 @@ class HostFilterTestCase(test.TestCase): 'nova.scheduler.host_filter.AllHostsFilter') # Test valid driver ... driver = host_filter.choose_driver( - 'nova.scheduler.host_filter.FlavorFilter') + 'nova.scheduler.host_filter.InstanceTypeFilter') self.assertEquals(driver._full_name(), - 'nova.scheduler.host_filter.FlavorFilter') + 'nova.scheduler.host_filter.InstanceTypeFilter') # Test invalid driver ... try: host_filter.choose_driver('does not exist') @@ -103,11 +103,12 @@ class HostFilterTestCase(test.TestCase): for host, capabilities in hosts: self.assertTrue(host.startswith('host')) - def test_flavor_driver(self): - driver = host_filter.FlavorFilter() + def test_instance_type_driver(self): + driver = host_filter.InstanceTypeFilter() # filter all hosts that can support 50 ram and 500 disk name, cooked = driver.instance_type_to_filter(self.instance_type) - self.assertEquals('nova.scheduler.host_filter.FlavorFilter', name) + self.assertEquals('nova.scheduler.host_filter.InstanceTypeFilter', + name) hosts = driver.filter_hosts(self.zone_manager, cooked) self.assertEquals(6, len(hosts)) just_hosts = [host for host, caps in hosts] diff --git a/nova/virt/fake.py b/nova/virt/fake.py index bf87e5ced..3bd9fbc93 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -478,5 +478,3 @@ class FakeConnection(driver.ComputeDriver): def get_host_stats(self, refresh=False): """Return fake Host Status of ram, disk, network.""" return self.host_status - - -- cgit From effa4b37fae0e6fef993ffd2892bb77c0e7245f1 Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Tue, 17 May 2011 05:43:06 -0700 Subject: ugh, fixed again --- nova/tests/test_zone_aware_scheduler.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nova/tests/test_zone_aware_scheduler.py b/nova/tests/test_zone_aware_scheduler.py index fdcde34c9..37169fb97 100644 --- a/nova/tests/test_zone_aware_scheduler.py +++ b/nova/tests/test_zone_aware_scheduler.py @@ -116,4 +116,6 @@ class ZoneAwareSchedulerTestCase(test.TestCase): sched.set_zone_manager(zm) fake_context = {} - self.assertRaises(driver.NoValidHost, sched.schedule, fake_context, {}) + self.assertRaises(driver.NoValidHost, sched.schedule_run_instance, + fake_context, 1, + dict(host_filter=None, instance_type={})) -- cgit From 84e8893c08cced5f7097b5c90e21a8a06740b3ab Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Tue, 17 May 2011 07:49:12 -0700 Subject: provision working correctly now --- nova/scheduler/host_filter.py | 19 ++++++++++--------- nova/scheduler/zone_aware_scheduler.py | 26 +++++++++++++++++++++----- nova/virt/fake.py | 7 ++++--- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/nova/scheduler/host_filter.py b/nova/scheduler/host_filter.py index 2b0d9af77..92ec827d3 100644 --- a/nova/scheduler/host_filter.py +++ b/nova/scheduler/host_filter.py @@ -99,9 +99,10 @@ class InstanceTypeFilter(HostFilter): capabilities = services.get('compute', {}) host_ram_mb = capabilities['host_memory_free'] disk_bytes = capabilities['disk_available'] - if host_ram_mb >= instance_type['memory_mb'] and \ - disk_bytes >= instance_type['local_gb']: - selected_hosts.append((host, capabilities)) + spec_ram = instance_type['memory_mb'] + spec_disk = instance_type['local_gb'] + if host_ram_mb >= spec_ram and disk_bytes >= spec_disk: + selected_hosts.append((host, capabilities)) return selected_hosts #host entries (currently) are like: @@ -110,15 +111,15 @@ class InstanceTypeFilter(HostFilter): # 'host_memory_total': 8244539392, # 'host_memory_overhead': 184225792, # 'host_memory_free': 3868327936, -# 'host_memory_free_computed': 3840843776}, -# 'host_other-config': {}, +# 'host_memory_free_computed': 3840843776, +# 'host_other_config': {}, # 'host_ip_address': '192.168.1.109', # 'host_cpu_info': {}, # 'disk_available': 32954957824, # 'disk_total': 50394562560, -# 'disk_used': 17439604736}, +# 'disk_used': 17439604736, # 'host_uuid': 'cedb9b39-9388-41df-8891-c5c9a0c0fe5f', -# 'host_name-label': 'xs-mini'} +# 'host_name_label': 'xs-mini'} # instance_type table has: #name = Column(String(255), unique=True) @@ -307,10 +308,10 @@ class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler): # currently. Later we'll need to snoop for more detailed # host filter requests. instance_type = request_spec['instance_type'] - query = driver.instance_type_to_filter(instance_type) + name, query = driver.instance_type_to_filter(instance_type) return driver.filter_hosts(self.zone_manager, query) def weigh_hosts(self, num, request_spec, hosts): """Derived classes must override this method and return a lists of hosts in [{weight, hostname}] format.""" - return [dict(weight=1, hostname=hostname) for host, caps in hosts] + return [dict(weight=1, hostname=host) for host, caps in hosts] diff --git a/nova/scheduler/zone_aware_scheduler.py b/nova/scheduler/zone_aware_scheduler.py index 614b1bb89..3ebb4caef 100644 --- a/nova/scheduler/zone_aware_scheduler.py +++ b/nova/scheduler/zone_aware_scheduler.py @@ -22,6 +22,8 @@ across zones. There are two expansion points to this class for: import operator +from nova import db +from nova import rpc from nova import log as logging from nova.scheduler import api from nova.scheduler import driver @@ -49,7 +51,8 @@ class ZoneAwareScheduler(driver.Scheduler): # TODO(sandy): We'll have to look for richer specs at some point. if 'blob' in request_spec: - return self.provision_instance(context, topic, request_spec) + return self.provision_resource(context, request_spec, + instance_id, kwargs) # Create build plan and provision ... build_plan = self.select(context, request_spec) @@ -57,14 +60,28 @@ class ZoneAwareScheduler(driver.Scheduler): raise driver.NoValidHost(_('No hosts were available')) for item in build_plan: - self.provision_instance(context, topic, item) + self.provision_resource(context, item, instance_id, kwargs) # Returning None short-circuits the routing to Compute (since # we've already done it here) return None - def provision_instance(context, topic, item): - """Create the requested instance in this Zone or a child zone.""" + def provision_resource(self, context, item, instance_id, kwargs): + """Create the requested resource in this Zone or a child zone.""" + if "hostname" in item: + host = item['hostname'] + kwargs['instance_id'] = instance_id + rpc.cast(context, + db.queue_get_for(context, "compute", host), + {"method": "run_instance", + "args": kwargs}) + LOG.debug(_("Casted to compute %(host)s for run_instance") + % locals()) + else: + # TODO(sandy) Provision in child zone ... + LOG.warning(_("Provision to Child Zone not supported (yet)") + % locals()) + pass return None def select(self, context, request_spec, *args, **kwargs): @@ -93,7 +110,6 @@ class ZoneAwareScheduler(driver.Scheduler): raise NotImplemented(_("Zone Aware Scheduler only understands " "Compute nodes (for now)")) - LOG.debug("specs = %s, ARGS = %s" % (request_spec, args, )) #TODO(sandy): how to infer this from OS API params? num_instances = 1 diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 3bd9fbc93..0225797d7 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -82,20 +82,21 @@ class FakeConnection(driver.ComputeDriver): def __init__(self): self.instances = {} - self.host_status = {'host_name-description': 'Fake Host', + self.host_status = { + 'host_name-description': 'Fake Host', 'host_hostname': 'fake-mini', 'host_memory_total': 8000000000, 'host_memory_overhead': 10000000, 'host_memory_free': 7900000000, 'host_memory_free_computed': 7900000000, - 'host_other-config': {}, + 'host_other_config': {}, 'host_ip_address': '192.168.1.109', 'host_cpu_info': {}, 'disk_available': 500000000000, 'disk_total': 600000000000, 'disk_used': 100000000000, 'host_uuid': 'cedb9b39-9388-41df-8891-c5c9a0c0fe5f', - 'host_name-label': 'fake-mini'} + 'host_name_label': 'fake-mini'} @classmethod def instance(cls): -- cgit From b66c689afc5923702b3d6d27a5c8f12f6749b07d Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Tue, 17 May 2011 07:52:02 -0700 Subject: provision_resource no longer returns value --- nova/scheduler/zone_aware_scheduler.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nova/scheduler/zone_aware_scheduler.py b/nova/scheduler/zone_aware_scheduler.py index 3ebb4caef..2050c8918 100644 --- a/nova/scheduler/zone_aware_scheduler.py +++ b/nova/scheduler/zone_aware_scheduler.py @@ -51,8 +51,8 @@ class ZoneAwareScheduler(driver.Scheduler): # TODO(sandy): We'll have to look for richer specs at some point. if 'blob' in request_spec: - return self.provision_resource(context, request_spec, - instance_id, kwargs) + self.provision_resource(context, request_spec, instance_id, kwargs) + return None # Create build plan and provision ... build_plan = self.select(context, request_spec) @@ -82,7 +82,6 @@ class ZoneAwareScheduler(driver.Scheduler): LOG.warning(_("Provision to Child Zone not supported (yet)") % locals()) pass - return None def select(self, context, request_spec, *args, **kwargs): """Select returns a list of weights and zone/host information -- cgit From 40f15a6ffb0d9ae965f9c7c7289654f323f2775f Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Tue, 17 May 2011 13:01:28 -0700 Subject: pep8 --- nova/scheduler/zone_aware_scheduler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/scheduler/zone_aware_scheduler.py b/nova/scheduler/zone_aware_scheduler.py index 2050c8918..dc18fc427 100644 --- a/nova/scheduler/zone_aware_scheduler.py +++ b/nova/scheduler/zone_aware_scheduler.py @@ -78,7 +78,7 @@ class ZoneAwareScheduler(driver.Scheduler): LOG.debug(_("Casted to compute %(host)s for run_instance") % locals()) else: - # TODO(sandy) Provision in child zone ... + # TODO(sandy) Provision in child zone ... LOG.warning(_("Provision to Child Zone not supported (yet)") % locals()) pass -- cgit From 714fe839580d4858417592608e4bf95ac26cf5d1 Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Mon, 23 May 2011 10:39:50 -0700 Subject: get rid of all mention of drivers ... it's filter only now --- nova/exception.py | 5 +-- nova/scheduler/host_filter.py | 55 +++++++++++++------------ nova/tests/test_host_filter.py | 93 ++++++++++++++++++++---------------------- 3 files changed, 75 insertions(+), 78 deletions(-) diff --git a/nova/exception.py b/nova/exception.py index 56c20d111..dde39f29b 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -465,9 +465,8 @@ class ZoneNotFound(NotFound): message = _("Zone %(zone_id)s could not be found.") -class SchedulerHostFilterDriverNotFound(NotFound): - message = _("Scheduler Host Filter Driver %(driver_name)s could" - " not be found.") +class SchedulerHostFilterNotFound(NotFound): + message = _("Scheduler Host Filter %(filter_name)s could not be found.") class InstanceMetadataNotFound(NotFound): diff --git a/nova/scheduler/host_filter.py b/nova/scheduler/host_filter.py index 92ec827d3..d9771754a 100644 --- a/nova/scheduler/host_filter.py +++ b/nova/scheduler/host_filter.py @@ -14,8 +14,8 @@ # under the License. """ -Host Filter is a driver mechanism for requesting instance resources. -Three drivers are included: AllHosts, Flavor & JSON. AllHosts just +Host Filter is a mechanism for requesting instance resources. +Three filters are included: AllHosts, Flavor & JSON. AllHosts just returns the full, unfiltered list of hosts. Flavor is a hard coded matching mechanism based on flavor criteria and JSON is an ad-hoc filter grammar. @@ -47,13 +47,13 @@ from nova.scheduler import zone_aware_scheduler LOG = logging.getLogger('nova.scheduler.host_filter') FLAGS = flags.FLAGS -flags.DEFINE_string('default_host_filter_driver', +flags.DEFINE_string('default_host_filter', 'nova.scheduler.host_filter.AllHostsFilter', - 'Which driver to use for filtering hosts.') + 'Which filter to use for filtering hosts.') class HostFilter(object): - """Base class for host filter drivers.""" + """Base class for host filters.""" def instance_type_to_filter(self, instance_type): """Convert instance_type into a filter for most common use-case.""" @@ -64,12 +64,12 @@ class HostFilter(object): raise NotImplementedError() def _full_name(self): - """module.classname of the filter driver""" + """module.classname of the filter.""" return "%s.%s" % (self.__module__, self.__class__.__name__) class AllHostsFilter(HostFilter): - """NOP host filter driver. Returns all hosts in ZoneManager. + """NOP host filter. Returns all hosts in ZoneManager. This essentially does what the old Scheduler+Chance used to give us.""" @@ -85,7 +85,7 @@ class AllHostsFilter(HostFilter): class InstanceTypeFilter(HostFilter): - """HostFilter driver hard-coded to work with InstanceType records.""" + """HostFilter hard-coded to work with InstanceType records.""" def instance_type_to_filter(self, instance_type): """Use instance_type to filter hosts.""" @@ -133,7 +133,7 @@ class InstanceTypeFilter(HostFilter): class JsonFilter(HostFilter): - """Host Filter driver to allow simple JSON-based grammar for + """Host Filter to allow simple JSON-based grammar for selecting hosts.""" def _equals(self, args): @@ -273,43 +273,44 @@ class JsonFilter(HostFilter): return hosts -DRIVERS = [AllHostsFilter, InstanceTypeFilter, JsonFilter] +FILTERS = [AllHostsFilter, InstanceTypeFilter, JsonFilter] -def choose_driver(driver_name=None): - """Since the caller may specify which driver to use we need +def choose_host_filter(filter_name=None): + """Since the caller may specify which filter to use we need to have an authoritative list of what is permissible. This - function checks the driver name against a predefined set - of acceptable drivers.""" + function checks the filter name against a predefined set + of acceptable filters.""" - if not driver_name: - driver_name = FLAGS.default_host_filter_driver - for driver in DRIVERS: - if "%s.%s" % (driver.__module__, driver.__name__) == driver_name: - return driver() - raise exception.SchedulerHostFilterDriverNotFound(driver_name=driver_name) + if not filter_name: + filter_name = FLAGS.default_host_filter + for filter_class in FILTERS: + if "%s.%s" % (filter_class.__module__, filter_class.__name__) == \ + filter_name: + return filter_class() + raise exception.SchedulerHostFilterNotFound(filter_name=filter_name) class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler): - """The HostFilterScheduler uses the HostFilter drivers to filter - hosts for weighing. The particular driver used may be passed in + """The HostFilterScheduler uses the HostFilter to filter + hosts for weighing. The particular filter used may be passed in as an argument or the default will be used. - request_spec = {'filter_driver': , + request_spec = {'filter_name': , 'instance_type': } """ def filter_hosts(self, num, request_spec): """Filter the full host list (from the ZoneManager)""" - driver_name = request_spec.get('filter_driver', None) - driver = choose_driver(driver_name) + filter_name = request_spec.get('filter_name', None) + host_filter = choose_host_filter(filter_name) # TODO(sandy): We're only using InstanceType-based specs # currently. Later we'll need to snoop for more detailed # host filter requests. instance_type = request_spec['instance_type'] - name, query = driver.instance_type_to_filter(instance_type) - return driver.filter_hosts(self.zone_manager, query) + name, query = host_filter.instance_type_to_filter(instance_type) + return host_filter.filter_hosts(self.zone_manager, query) def weigh_hosts(self, num, request_spec, hosts): """Derived classes must override this method and return diff --git a/nova/tests/test_host_filter.py b/nova/tests/test_host_filter.py index dd2325cc6..07817cc5a 100644 --- a/nova/tests/test_host_filter.py +++ b/nova/tests/test_host_filter.py @@ -13,7 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. """ -Tests For Scheduler Host Filter Drivers. +Tests For Scheduler Host Filters. """ import json @@ -31,7 +31,7 @@ class FakeZoneManager: class HostFilterTestCase(test.TestCase): - """Test case for host filter drivers.""" + """Test case for host filters.""" def _host_caps(self, multiplier): # Returns host capabilities in the following way: @@ -57,8 +57,8 @@ class HostFilterTestCase(test.TestCase): 'host_name-label': 'xs-%s' % multiplier} def setUp(self): - self.old_flag = FLAGS.default_host_filter_driver - FLAGS.default_host_filter_driver = \ + self.old_flag = FLAGS.default_host_filter + FLAGS.default_host_filter = \ 'nova.scheduler.host_filter.AllHostsFilter' self.instance_type = dict(name='tiny', memory_mb=50, @@ -76,52 +76,52 @@ class HostFilterTestCase(test.TestCase): self.zone_manager.service_states = states def tearDown(self): - FLAGS.default_host_filter_driver = self.old_flag + FLAGS.default_host_filter = self.old_flag - def test_choose_driver(self): - # Test default driver ... - driver = host_filter.choose_driver() - self.assertEquals(driver._full_name(), + def test_choose_filter(self): + # Test default filter ... + hf = host_filter.choose_host_filter() + self.assertEquals(hf._full_name(), 'nova.scheduler.host_filter.AllHostsFilter') - # Test valid driver ... - driver = host_filter.choose_driver( + # Test valid filter ... + hf = host_filter.choose_host_filter( 'nova.scheduler.host_filter.InstanceTypeFilter') - self.assertEquals(driver._full_name(), + self.assertEquals(hf._full_name(), 'nova.scheduler.host_filter.InstanceTypeFilter') - # Test invalid driver ... + # Test invalid filter ... try: - host_filter.choose_driver('does not exist') - self.fail("Should not find driver") - except exception.SchedulerHostFilterDriverNotFound: + host_filter.choose_host_filter('does not exist') + self.fail("Should not find host filter.") + except exception.SchedulerHostFilterNotFound: pass - def test_all_host_driver(self): - driver = host_filter.AllHostsFilter() - cooked = driver.instance_type_to_filter(self.instance_type) - hosts = driver.filter_hosts(self.zone_manager, cooked) + def test_all_host_filter(self): + hf = host_filter.AllHostsFilter() + cooked = hf.instance_type_to_filter(self.instance_type) + hosts = hf.filter_hosts(self.zone_manager, cooked) self.assertEquals(10, len(hosts)) for host, capabilities in hosts: self.assertTrue(host.startswith('host')) - def test_instance_type_driver(self): - driver = host_filter.InstanceTypeFilter() + def test_instance_type_filter(self): + hf = host_filter.InstanceTypeFilter() # filter all hosts that can support 50 ram and 500 disk - name, cooked = driver.instance_type_to_filter(self.instance_type) + name, cooked = hf.instance_type_to_filter(self.instance_type) self.assertEquals('nova.scheduler.host_filter.InstanceTypeFilter', name) - hosts = driver.filter_hosts(self.zone_manager, cooked) + hosts = hf.filter_hosts(self.zone_manager, cooked) self.assertEquals(6, len(hosts)) just_hosts = [host for host, caps in hosts] just_hosts.sort() self.assertEquals('host05', just_hosts[0]) self.assertEquals('host10', just_hosts[5]) - def test_json_driver(self): - driver = host_filter.JsonFilter() + def test_json_filter(self): + hf = host_filter.JsonFilter() # filter all hosts that can support 50 ram and 500 disk - name, cooked = driver.instance_type_to_filter(self.instance_type) + name, cooked = hf.instance_type_to_filter(self.instance_type) self.assertEquals('nova.scheduler.host_filter.JsonFilter', name) - hosts = driver.filter_hosts(self.zone_manager, cooked) + hosts = hf.filter_hosts(self.zone_manager, cooked) self.assertEquals(6, len(hosts)) just_hosts = [host for host, caps in hosts] just_hosts.sort() @@ -141,7 +141,7 @@ class HostFilterTestCase(test.TestCase): ] ] cooked = json.dumps(raw) - hosts = driver.filter_hosts(self.zone_manager, cooked) + hosts = hf.filter_hosts(self.zone_manager, cooked) self.assertEquals(5, len(hosts)) just_hosts = [host for host, caps in hosts] @@ -153,7 +153,7 @@ class HostFilterTestCase(test.TestCase): ['=', '$compute.host_memory_free', 30], ] cooked = json.dumps(raw) - hosts = driver.filter_hosts(self.zone_manager, cooked) + hosts = hf.filter_hosts(self.zone_manager, cooked) self.assertEquals(9, len(hosts)) just_hosts = [host for host, caps in hosts] @@ -163,7 +163,7 @@ class HostFilterTestCase(test.TestCase): raw = ['in', '$compute.host_memory_free', 20, 40, 60, 80, 100] cooked = json.dumps(raw) - hosts = driver.filter_hosts(self.zone_manager, cooked) + hosts = hf.filter_hosts(self.zone_manager, cooked) self.assertEquals(5, len(hosts)) just_hosts = [host for host, caps in hosts] @@ -175,35 +175,32 @@ class HostFilterTestCase(test.TestCase): raw = ['unknown command', ] cooked = json.dumps(raw) try: - driver.filter_hosts(self.zone_manager, cooked) + hf.filter_hosts(self.zone_manager, cooked) self.fail("Should give KeyError") except KeyError, e: pass - self.assertTrue(driver.filter_hosts(self.zone_manager, json.dumps([]))) - self.assertTrue(driver.filter_hosts(self.zone_manager, json.dumps({}))) - self.assertTrue(driver.filter_hosts(self.zone_manager, json.dumps( + self.assertTrue(hf.filter_hosts(self.zone_manager, json.dumps([]))) + self.assertTrue(hf.filter_hosts(self.zone_manager, json.dumps({}))) + self.assertTrue(hf.filter_hosts(self.zone_manager, json.dumps( ['not', True, False, True, False] ))) try: - driver.filter_hosts(self.zone_manager, json.dumps( + hf.filter_hosts(self.zone_manager, json.dumps( 'not', True, False, True, False )) self.fail("Should give KeyError") except KeyError, e: pass - self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps( - ['=', '$foo', 100] - ))) - self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps( - ['=', '$.....', 100] - ))) - self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps( - ['>', ['and', ['or', ['not', ['<', ['>=', ['<=', ['in', ]]]]]]]] - ))) + self.assertFalse(hf.filter_hosts(self.zone_manager, + json.dumps(['=', '$foo', 100]))) + self.assertFalse(hf.filter_hosts(self.zone_manager, + json.dumps(['=', '$.....', 100]))) + self.assertFalse(hf.filter_hosts(self.zone_manager, + json.dumps( + ['>', ['and', ['or', ['not', ['<', ['>=', ['<=', ['in', ]]]]]]]]))) - self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps( - ['=', {}, ['>', '$missing....foo']] - ))) + self.assertFalse(hf.filter_hosts(self.zone_manager, + json.dumps(['=', {}, ['>', '$missing....foo']]))) -- cgit From 788893ef2a17a4fda5e907f048a94f3ed0435bbc Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Thu, 26 May 2011 10:53:48 -0700 Subject: missed a driver reference --- nova/compute/api.py | 2 +- nova/scheduler/host_filter.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 216550e40..0b2c4e642 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -264,7 +264,7 @@ class API(base.Base): "instance_id": instance_id, "request_spec": { 'instance_type': instance_type, - 'filter_driver': + 'filter': 'nova.scheduler.host_filter.' 'InstanceTypeFilter' }, diff --git a/nova/scheduler/host_filter.py b/nova/scheduler/host_filter.py index d9771754a..ed76c90bf 100644 --- a/nova/scheduler/host_filter.py +++ b/nova/scheduler/host_filter.py @@ -296,13 +296,13 @@ class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler): hosts for weighing. The particular filter used may be passed in as an argument or the default will be used. - request_spec = {'filter_name': , + request_spec = {'filter': , 'instance_type': } """ def filter_hosts(self, num, request_spec): """Filter the full host list (from the ZoneManager)""" - filter_name = request_spec.get('filter_name', None) + filter_name = request_spec.get('filter', None) host_filter = choose_host_filter(filter_name) # TODO(sandy): We're only using InstanceType-based specs -- cgit From bd19bd2edd612dfea09e4230c59422e59c6de181 Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Fri, 27 May 2011 05:01:42 -0700 Subject: fixed docstrings and general tidying --- nova/compute/api.py | 39 ++++++++++++++++---------------- nova/scheduler/host_filter.py | 41 +++++++++++++++++++++------------- nova/scheduler/zone_aware_scheduler.py | 33 +++++++++++++++++---------- 3 files changed, 67 insertions(+), 46 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 7f1fe1b5c..3e5105050 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -88,10 +88,10 @@ class API(base.Base): {"method": "get_network_topic", "args": {'fake': 1}}) def _check_injected_file_quota(self, context, injected_files): - """Enforce quota limits on injected files. + """ + Enforce quota limits on injected files. Raises a QuotaError if any limit is exceeded. - """ if injected_files is None: return @@ -137,10 +137,10 @@ class API(base.Base): availability_zone=None, user_data=None, metadata={}, injected_files=None, admin_password=None): - """Create the number and type of instances requested. + """ + Create the number and type of instances requested. Verifies that quota and other arguments are valid. - """ if not instance_type: instance_type = instance_types.get_default_instance_type() @@ -293,13 +293,13 @@ class API(base.Base): return False def ensure_default_security_group(self, context): - """Ensure that a context has a security group. + """ + Ensure that a context has a security group. Creates a security group for the security context if it does not already exist. :param context: the security context - """ try: db.security_group_get_by_name(context, context.project_id, @@ -328,11 +328,11 @@ class API(base.Base): "args": {"security_group_id": security_group.id}}) def trigger_security_group_members_refresh(self, context, group_id): - """Called when a security group gains a new or loses a member. + """ + Called when a security group gains a new or loses a member. Sends an update request to each compute node for whom this is relevant. - """ # First, we get the security group rules that reference this group as # the grantee.. @@ -370,7 +370,8 @@ class API(base.Base): "args": {"security_group_id": group_id}}) def update(self, context, instance_id, **kwargs): - """Updates the instance in the datastore. + """ + Updates the instance in the datastore. :param context: The security context :param instance_id: ID of the instance to update @@ -379,7 +380,6 @@ class API(base.Base): updated :returns: None - """ rv = self.db.instance_update(context, instance_id, kwargs) return dict(rv.iteritems()) @@ -424,22 +424,22 @@ class API(base.Base): @scheduler_api.reroute_compute("get") def routing_get(self, context, instance_id): - """A version of get with special routing characteristics. + """ + A version of get with special routing characteristics. Use this method instead of get() if this is the only operation you intend to to. It will route to novaclient.get if the instance is not found. - """ return self.get(context, instance_id) def get_all(self, context, project_id=None, reservation_id=None, fixed_ip=None): - """Get all instances filtered by one of the given parameters. + """ + Get all instances filtered by one of the given parameters. If there is no filter and the context is an admin, it will retreive all instances in the system. - """ if reservation_id is not None: return self.db.instance_get_all_by_reservation( @@ -463,13 +463,13 @@ class API(base.Base): def _cast_compute_message(self, method, context, instance_id, host=None, params=None): - """Generic handler for RPC casts to compute. + """ + Generic handler for RPC casts to compute. :param params: Optional dictionary of arguments to be passed to the compute worker :returns: None - """ if not params: params = {} @@ -483,7 +483,8 @@ class API(base.Base): def _call_compute_message(self, method, context, instance_id, host=None, params=None): - """Generic handler for RPC calls to compute. + """ + Generic handler for RPC calls to compute. :param params: Optional dictionary of arguments to be passed to the compute worker @@ -516,10 +517,10 @@ class API(base.Base): % instance_id) def snapshot(self, context, instance_id, name): - """Snapshot the given instance. + """ + Snapshot the given instance. :returns: A dict containing image metadata - """ properties = {'instance_id': str(instance_id), 'user_id': str(context.user_id)} diff --git a/nova/scheduler/host_filter.py b/nova/scheduler/host_filter.py index ed76c90bf..89faace45 100644 --- a/nova/scheduler/host_filter.py +++ b/nova/scheduler/host_filter.py @@ -69,9 +69,11 @@ class HostFilter(object): class AllHostsFilter(HostFilter): - """NOP host filter. Returns all hosts in ZoneManager. + """ + NOP host filter. Returns all hosts in ZoneManager. This essentially does what the old Scheduler+Chance used - to give us.""" + to give us. + """ def instance_type_to_filter(self, instance_type): """Return anything to prevent base-class from raising @@ -133,8 +135,10 @@ class InstanceTypeFilter(HostFilter): class JsonFilter(HostFilter): - """Host Filter to allow simple JSON-based grammar for - selecting hosts.""" + """ + Host Filter to allow simple JSON-based grammar for + selecting hosts. + """ def _equals(self, args): """First term is == all the other terms.""" @@ -229,8 +233,10 @@ class JsonFilter(HostFilter): return (self._full_name(), json.dumps(query)) def _parse_string(self, string, host, services): - """Strings prefixed with $ are capability lookups in the - form '$service.capability[.subcap*]'""" + """ + Strings prefixed with $ are capability lookups in the + form '$service.capability[.subcap*]' + """ if not string: return None if string[0] != '$': @@ -277,22 +283,25 @@ FILTERS = [AllHostsFilter, InstanceTypeFilter, JsonFilter] def choose_host_filter(filter_name=None): - """Since the caller may specify which filter to use we need - to have an authoritative list of what is permissible. This - function checks the filter name against a predefined set - of acceptable filters.""" + """ + Since the caller may specify which filter to use we need + to have an authoritative list of what is permissible. This + function checks the filter name against a predefined set + of acceptable filters. + """ if not filter_name: filter_name = FLAGS.default_host_filter for filter_class in FILTERS: - if "%s.%s" % (filter_class.__module__, filter_class.__name__) == \ - filter_name: + host_match = "%s.%s" % (filter_class.__module__, filter_class.__name__) + if host_match == filter_name: return filter_class() raise exception.SchedulerHostFilterNotFound(filter_name=filter_name) class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler): - """The HostFilterScheduler uses the HostFilter to filter + """ + The HostFilterScheduler uses the HostFilter to filter hosts for weighing. The particular filter used may be passed in as an argument or the default will be used. @@ -313,6 +322,8 @@ class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler): return host_filter.filter_hosts(self.zone_manager, query) def weigh_hosts(self, num, request_spec, hosts): - """Derived classes must override this method and return - a lists of hosts in [{weight, hostname}] format.""" + """ + Derived classes must override this method and return + a lists of hosts in [{weight, hostname}] format. + """ return [dict(weight=1, hostname=host) for host, caps in hosts] diff --git a/nova/scheduler/zone_aware_scheduler.py b/nova/scheduler/zone_aware_scheduler.py index dc18fc427..236907626 100644 --- a/nova/scheduler/zone_aware_scheduler.py +++ b/nova/scheduler/zone_aware_scheduler.py @@ -40,13 +40,15 @@ class ZoneAwareScheduler(driver.Scheduler): def schedule_run_instance(self, context, instance_id, request_spec, *args, **kwargs): - """This method is called from nova.compute.api to provision + """ + This method is called from nova.compute.api to provision an instance. However we need to look at the parameters being passed in to see if this is a request to: 1. Create a Build Plan and then provision, or 2. Use the Build Plan information in the request parameters to simply create the instance (either in this zone or - a child zone).""" + a child zone). + """ # TODO(sandy): We'll have to look for richer specs at some point. @@ -79,15 +81,16 @@ class ZoneAwareScheduler(driver.Scheduler): % locals()) else: # TODO(sandy) Provision in child zone ... - LOG.warning(_("Provision to Child Zone not supported (yet)") - % locals()) + LOG.warning(_("Provision to Child Zone not supported (yet)")) pass def select(self, context, request_spec, *args, **kwargs): - """Select returns a list of weights and zone/host information + """ + Select returns a list of weights and zone/host information corresponding to the best hosts to service the request. Any child zone information has been encrypted so as not to reveal - anything about the children.""" + anything about the children. + """ return self._schedule(context, "compute", request_spec, *args, **kwargs) @@ -95,13 +98,15 @@ class ZoneAwareScheduler(driver.Scheduler): # so we don't implement the default "schedule()" method required # of Schedulers. def schedule(self, context, topic, request_spec, *args, **kwargs): - """The schedule() contract requires we return the one + """ + The schedule() contract requires we return the one best-suited host for this request. """ raise driver.NoValidHost(_('No hosts were available')) def _schedule(self, context, topic, request_spec, *args, **kwargs): - """Returns a list of hosts that meet the required specs, + """ + Returns a list of hosts that meet the required specs, ordered by their fitness. """ @@ -137,11 +142,15 @@ class ZoneAwareScheduler(driver.Scheduler): return weighted def filter_hosts(self, num, request_spec): - """Derived classes must override this method and return - a list of hosts in [(hostname, capability_dict)] format.""" + """ + Derived classes must override this method and return + a list of hosts in [(hostname, capability_dict)] format. + """ raise NotImplemented() def weigh_hosts(self, num, request_spec, hosts): - """Derived classes must override this method and return - a lists of hosts in [{weight, hostname}] format.""" + """ + Derived classes must override this method and return + a lists of hosts in [{weight, hostname}] format. + """ raise NotImplemented() -- cgit From 3f911877a2a9facdf153f173b3fb76a18e44a2ac Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Fri, 27 May 2011 07:24:02 -0700 Subject: docstrings again and import ordering --- nova/compute/api.py | 30 ++++++++++-------------------- nova/scheduler/host_filter.py | 18 ++++++------------ nova/scheduler/zone_aware_scheduler.py | 20 +++++++------------- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 3e5105050..35d60446c 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -88,8 +88,7 @@ class API(base.Base): {"method": "get_network_topic", "args": {'fake': 1}}) def _check_injected_file_quota(self, context, injected_files): - """ - Enforce quota limits on injected files. + """Enforce quota limits on injected files. Raises a QuotaError if any limit is exceeded. """ @@ -137,8 +136,7 @@ class API(base.Base): availability_zone=None, user_data=None, metadata={}, injected_files=None, admin_password=None): - """ - Create the number and type of instances requested. + """Create the number and type of instances requested. Verifies that quota and other arguments are valid. """ @@ -293,8 +291,7 @@ class API(base.Base): return False def ensure_default_security_group(self, context): - """ - Ensure that a context has a security group. + """Ensure that a context has a security group. Creates a security group for the security context if it does not already exist. @@ -328,8 +325,7 @@ class API(base.Base): "args": {"security_group_id": security_group.id}}) def trigger_security_group_members_refresh(self, context, group_id): - """ - Called when a security group gains a new or loses a member. + """Called when a security group gains a new or loses a member. Sends an update request to each compute node for whom this is relevant. @@ -370,8 +366,7 @@ class API(base.Base): "args": {"security_group_id": group_id}}) def update(self, context, instance_id, **kwargs): - """ - Updates the instance in the datastore. + """Updates the instance in the datastore. :param context: The security context :param instance_id: ID of the instance to update @@ -424,8 +419,7 @@ class API(base.Base): @scheduler_api.reroute_compute("get") def routing_get(self, context, instance_id): - """ - A version of get with special routing characteristics. + """A version of get with special routing characteristics. Use this method instead of get() if this is the only operation you intend to to. It will route to novaclient.get if the instance is not @@ -435,8 +429,7 @@ class API(base.Base): def get_all(self, context, project_id=None, reservation_id=None, fixed_ip=None): - """ - Get all instances filtered by one of the given parameters. + """Get all instances filtered by one of the given parameters. If there is no filter and the context is an admin, it will retreive all instances in the system. @@ -463,8 +456,7 @@ class API(base.Base): def _cast_compute_message(self, method, context, instance_id, host=None, params=None): - """ - Generic handler for RPC casts to compute. + """Generic handler for RPC casts to compute. :param params: Optional dictionary of arguments to be passed to the compute worker @@ -483,8 +475,7 @@ class API(base.Base): def _call_compute_message(self, method, context, instance_id, host=None, params=None): - """ - Generic handler for RPC calls to compute. + """Generic handler for RPC calls to compute. :param params: Optional dictionary of arguments to be passed to the compute worker @@ -517,8 +508,7 @@ class API(base.Base): % instance_id) def snapshot(self, context, instance_id, name): - """ - Snapshot the given instance. + """Snapshot the given instance. :returns: A dict containing image metadata """ diff --git a/nova/scheduler/host_filter.py b/nova/scheduler/host_filter.py index 89faace45..4260cbf42 100644 --- a/nova/scheduler/host_filter.py +++ b/nova/scheduler/host_filter.py @@ -69,8 +69,7 @@ class HostFilter(object): class AllHostsFilter(HostFilter): - """ - NOP host filter. Returns all hosts in ZoneManager. + """ NOP host filter. Returns all hosts in ZoneManager. This essentially does what the old Scheduler+Chance used to give us. """ @@ -135,8 +134,7 @@ class InstanceTypeFilter(HostFilter): class JsonFilter(HostFilter): - """ - Host Filter to allow simple JSON-based grammar for + """Host Filter to allow simple JSON-based grammar for selecting hosts. """ @@ -233,8 +231,7 @@ class JsonFilter(HostFilter): return (self._full_name(), json.dumps(query)) def _parse_string(self, string, host, services): - """ - Strings prefixed with $ are capability lookups in the + """Strings prefixed with $ are capability lookups in the form '$service.capability[.subcap*]' """ if not string: @@ -283,8 +280,7 @@ FILTERS = [AllHostsFilter, InstanceTypeFilter, JsonFilter] def choose_host_filter(filter_name=None): - """ - Since the caller may specify which filter to use we need + """Since the caller may specify which filter to use we need to have an authoritative list of what is permissible. This function checks the filter name against a predefined set of acceptable filters. @@ -300,8 +296,7 @@ def choose_host_filter(filter_name=None): class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler): - """ - The HostFilterScheduler uses the HostFilter to filter + """The HostFilterScheduler uses the HostFilter to filter hosts for weighing. The particular filter used may be passed in as an argument or the default will be used. @@ -322,8 +317,7 @@ class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler): return host_filter.filter_hosts(self.zone_manager, query) def weigh_hosts(self, num, request_spec, hosts): - """ - Derived classes must override this method and return + """Derived classes must override this method and return a lists of hosts in [{weight, hostname}] format. """ return [dict(weight=1, hostname=host) for host, caps in hosts] diff --git a/nova/scheduler/zone_aware_scheduler.py b/nova/scheduler/zone_aware_scheduler.py index 236907626..bc67c7794 100644 --- a/nova/scheduler/zone_aware_scheduler.py +++ b/nova/scheduler/zone_aware_scheduler.py @@ -23,8 +23,8 @@ across zones. There are two expansion points to this class for: import operator from nova import db -from nova import rpc from nova import log as logging +from nova import rpc from nova.scheduler import api from nova.scheduler import driver @@ -40,8 +40,7 @@ class ZoneAwareScheduler(driver.Scheduler): def schedule_run_instance(self, context, instance_id, request_spec, *args, **kwargs): - """ - This method is called from nova.compute.api to provision + """This method is called from nova.compute.api to provision an instance. However we need to look at the parameters being passed in to see if this is a request to: 1. Create a Build Plan and then provision, or @@ -85,8 +84,7 @@ class ZoneAwareScheduler(driver.Scheduler): pass def select(self, context, request_spec, *args, **kwargs): - """ - Select returns a list of weights and zone/host information + """Select returns a list of weights and zone/host information corresponding to the best hosts to service the request. Any child zone information has been encrypted so as not to reveal anything about the children. @@ -98,15 +96,13 @@ class ZoneAwareScheduler(driver.Scheduler): # so we don't implement the default "schedule()" method required # of Schedulers. def schedule(self, context, topic, request_spec, *args, **kwargs): - """ - The schedule() contract requires we return the one + """The schedule() contract requires we return the one best-suited host for this request. """ raise driver.NoValidHost(_('No hosts were available')) def _schedule(self, context, topic, request_spec, *args, **kwargs): - """ - Returns a list of hosts that meet the required specs, + """Returns a list of hosts that meet the required specs, ordered by their fitness. """ @@ -142,15 +138,13 @@ class ZoneAwareScheduler(driver.Scheduler): return weighted def filter_hosts(self, num, request_spec): - """ - Derived classes must override this method and return + """Derived classes must override this method and return a list of hosts in [(hostname, capability_dict)] format. """ raise NotImplemented() def weigh_hosts(self, num, request_spec, hosts): - """ - Derived classes must override this method and return + """Derived classes must override this method and return a lists of hosts in [{weight, hostname}] format. """ raise NotImplemented() -- cgit