diff options
| author | Jenkins <jenkins@review.openstack.org> | 2011-10-13 00:17:49 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2011-10-13 00:17:49 +0000 |
| commit | d83f45faf1ded92a0766548d6ebaef3d4c7e08e9 (patch) | |
| tree | fad4652c0ac90c2062c1e54e3ebbe2369166edbd | |
| parent | 01e68c3de5b3c1cb6630bea862807089b77926d0 (diff) | |
| parent | 80e196069fa94edb8981415f9b8d432bbf92888f (diff) | |
| download | nova-d83f45faf1ded92a0766548d6ebaef3d4c7e08e9.tar.gz nova-d83f45faf1ded92a0766548d6ebaef3d4c7e08e9.tar.xz nova-d83f45faf1ded92a0766548d6ebaef3d4c7e08e9.zip | |
Merge "Restructure host filtering to be easier to use."
| -rw-r--r-- | nova/scheduler/abstract_scheduler.py | 4 | ||||
| -rw-r--r-- | nova/scheduler/base_scheduler.py | 27 | ||||
| -rw-r--r-- | nova/scheduler/filters/abstract_filter.py | 7 | ||||
| -rw-r--r-- | nova/scheduler/filters/all_hosts_filter.py | 11 | ||||
| -rw-r--r-- | nova/scheduler/filters/instance_type_filter.py | 14 | ||||
| -rw-r--r-- | nova/scheduler/filters/json_filter.py | 20 | ||||
| -rw-r--r-- | nova/scheduler/host_filter.py | 41 | ||||
| -rw-r--r-- | nova/scheduler/least_cost.py | 9 | ||||
| -rw-r--r-- | nova/tests/scheduler/test_abstract_scheduler.py | 3 | ||||
| -rw-r--r-- | nova/tests/scheduler/test_host_filter.py | 74 | ||||
| -rw-r--r-- | nova/tests/scheduler/test_least_cost_scheduler.py | 40 | ||||
| -rwxr-xr-x | plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost | 1 |
12 files changed, 131 insertions, 120 deletions
diff --git a/nova/scheduler/abstract_scheduler.py b/nova/scheduler/abstract_scheduler.py index e8712e5df..725f0b342 100644 --- a/nova/scheduler/abstract_scheduler.py +++ b/nova/scheduler/abstract_scheduler.py @@ -271,7 +271,7 @@ class AbstractScheduler(driver.Scheduler): # weigh the selected hosts. # weighted_hosts = [{weight=weight, hostname=hostname, # capabilities=capabs}, ...] - weighted_hosts = self.weigh_hosts(topic, request_spec, filtered_hosts) + weighted_hosts = self.weigh_hosts(request_spec, filtered_hosts) # Next, tack on the host weights from the child zones json_spec = json.dumps(request_spec) all_zones = db.zone_get_all(context.elevated()) @@ -306,7 +306,7 @@ class AbstractScheduler(driver.Scheduler): return [(host, services) for host, services in host_list if basic_ram_filter(host, services, request_spec)] - def weigh_hosts(self, topic, request_spec, hosts): + def weigh_hosts(self, request_spec, hosts): """This version assigns a weight of 1 to all hosts, making selection of any host basically a random event. Override this method in your subclass to add logic to prefer one potential host over another. diff --git a/nova/scheduler/base_scheduler.py b/nova/scheduler/base_scheduler.py index 132b8a493..77617a190 100644 --- a/nova/scheduler/base_scheduler.py +++ b/nova/scheduler/base_scheduler.py @@ -38,9 +38,20 @@ class BaseScheduler(abstract_scheduler.AbstractScheduler): """ def filter_hosts(self, topic, request_spec, hosts=None): """Filter the full host list (from the ZoneManager)""" - filter_name = request_spec.get('filter', None) - # Make sure that the requested filter is legitimate. - selected_filter = host_filter.choose_host_filter(filter_name) + filters = request_spec.get('filter') + if filters is None: + # Not specified; use the default + filters = FLAGS.default_host_filters + if not isinstance(filters, (list, tuple)): + filters = [filters] + if hosts is None: + # Get the full list (only considering 'compute' services) + all_hosts = self.zone_manager.service_states.iteritems() + hosts = [(host, services["compute"]) + for host, services in all_hosts + if "compute" in services] + # Make sure that the requested filters are legitimate. + selected_filters = host_filter.choose_host_filters(filters) # TODO(sandy): We're only using InstanceType-based specs # currently. Later we'll need to snoop for more detailed @@ -48,11 +59,13 @@ class BaseScheduler(abstract_scheduler.AbstractScheduler): instance_type = request_spec.get("instance_type", None) if instance_type is None: # No way to select; return the specified hosts - return hosts or [] - name, query = selected_filter.instance_type_to_filter(instance_type) - return selected_filter.filter_hosts(self.zone_manager, query) + return hosts + for selected_filter in selected_filters: + query = selected_filter.instance_type_to_filter(instance_type) + hosts = selected_filter.filter_hosts(hosts, query) + return hosts - def weigh_hosts(self, topic, request_spec, hosts): + def weigh_hosts(self, request_spec, hosts): """Derived classes may override this to provide more sophisticated scheduling objectives """ diff --git a/nova/scheduler/filters/abstract_filter.py b/nova/scheduler/filters/abstract_filter.py index a1d00d562..5784f8791 100644 --- a/nova/scheduler/filters/abstract_filter.py +++ b/nova/scheduler/filters/abstract_filter.py @@ -15,11 +15,6 @@ import nova.scheduler -from nova import flags - -FLAGS = flags.FLAGS -flags.DEFINE_string('default_host_filter', 'AllHostsFilter', - 'Which filter to use for filtering hosts') class AbstractHostFilter(object): @@ -28,7 +23,7 @@ class AbstractHostFilter(object): """Convert instance_type into a filter for most common use-case.""" raise NotImplementedError() - def filter_hosts(self, zone_manager, query): + def filter_hosts(self, host_list, query): """Return a list of hosts that fulfill the filter.""" raise NotImplementedError() diff --git a/nova/scheduler/filters/all_hosts_filter.py b/nova/scheduler/filters/all_hosts_filter.py index e80d829ca..7e6d2573b 100644 --- a/nova/scheduler/filters/all_hosts_filter.py +++ b/nova/scheduler/filters/all_hosts_filter.py @@ -15,7 +15,7 @@ import nova.scheduler -from nova.scheduler.filters import abstract_filter +import abstract_filter class AllHostsFilter(abstract_filter.AbstractHostFilter): @@ -24,9 +24,8 @@ class AllHostsFilter(abstract_filter.AbstractHostFilter): """Return anything to prevent base-class from raising exception. """ - return (self._full_name(), instance_type) + return instance_type - def filter_hosts(self, zone_manager, query): - """Return a list of hosts from ZoneManager list.""" - return [(host, services) - for host, services in zone_manager.service_states.iteritems()] + def filter_hosts(self, host_list, query): + """Return the entire list of supplied hosts.""" + return list(host_list) diff --git a/nova/scheduler/filters/instance_type_filter.py b/nova/scheduler/filters/instance_type_filter.py index 62b9ee414..43f1cf8d1 100644 --- a/nova/scheduler/filters/instance_type_filter.py +++ b/nova/scheduler/filters/instance_type_filter.py @@ -22,7 +22,7 @@ class InstanceTypeFilter(abstract_filter.AbstractHostFilter): """HostFilter hard-coded to work with InstanceType records.""" def instance_type_to_filter(self, instance_type): """Use instance_type to filter hosts.""" - return (self._full_name(), instance_type) + return instance_type def _satisfies_extra_specs(self, capabilities, instance_type): """Check that the capabilities provided by the compute service @@ -40,14 +40,19 @@ class InstanceTypeFilter(abstract_filter.AbstractHostFilter): return False return True - def filter_hosts(self, zone_manager, query): + def filter_hosts(self, host_list, query): """Return a list of hosts that can create instance_type.""" instance_type = query selected_hosts = [] - for host, services in zone_manager.service_states.iteritems(): - capabilities = services.get('compute', {}) + for host, capabilities in host_list: + # In case the capabilities have not yet been extracted from + # the zone manager's services dict... + capabilities = capabilities.get("compute", capabilities) if not capabilities: continue + if not capabilities.get("enabled", True): + # Host is disabled + continue host_ram_mb = capabilities['host_memory_free'] disk_bytes = capabilities['disk_available'] spec_ram = instance_type['memory_mb'] @@ -70,6 +75,7 @@ class InstanceTypeFilter(abstract_filter.AbstractHostFilter): # 'host_other_config': {}, # 'host_ip_address': '192.168.1.109', # 'host_cpu_info': {}, +# 'enabled': True, # 'disk_available': 32954957824, # 'disk_total': 50394562560, # 'disk_used': 17439604736, diff --git a/nova/scheduler/filters/json_filter.py b/nova/scheduler/filters/json_filter.py index caf22f5d5..6e30fda4d 100644 --- a/nova/scheduler/filters/json_filter.py +++ b/nova/scheduler/filters/json_filter.py @@ -94,7 +94,7 @@ class JsonFilter(abstract_filter.AbstractHostFilter): query = ['and', ['>=', '$compute.host_memory_free', required_ram], ['>=', '$compute.disk_available', required_disk]] - return (self._full_name(), json.dumps(query)) + return json.dumps(query) def _parse_string(self, string, host, services): """Strings prefixed with $ are capability lookups in the @@ -112,7 +112,7 @@ class JsonFilter(abstract_filter.AbstractHostFilter): return None return services - def _process_filter(self, zone_manager, query, host, services): + def _process_filter(self, query, host, services): """Recursively parse the query structure.""" if not query: return True @@ -121,7 +121,7 @@ class JsonFilter(abstract_filter.AbstractHostFilter): cooked_args = [] for arg in query[1:]: if isinstance(arg, list): - arg = self._process_filter(zone_manager, arg, host, services) + arg = self._process_filter(arg, host, services) elif isinstance(arg, basestring): arg = self._parse_string(arg, host, services) if arg is not None: @@ -129,18 +129,22 @@ class JsonFilter(abstract_filter.AbstractHostFilter): result = method(self, cooked_args) return result - def filter_hosts(self, zone_manager, query): + def filter_hosts(self, host_list, query): """Return a list of hosts that can fulfill the requirements specified in the query. """ expanded = json.loads(query) filtered_hosts = [] - for host, services in zone_manager.service_states.iteritems(): - result = self._process_filter(zone_manager, expanded, host, - services) + for host, capabilities in host_list: + if not capabilities: + continue + if not capabilities.get("enabled", True): + # Host is disabled + continue + result = self._process_filter(expanded, host, capabilities) if isinstance(result, list): # If any succeeded, include the host result = any(result) if result: - filtered_hosts.append((host, services)) + filtered_hosts.append((host, capabilities)) return filtered_hosts diff --git a/nova/scheduler/host_filter.py b/nova/scheduler/host_filter.py index 9f7d34ea7..cb77f1565 100644 --- a/nova/scheduler/host_filter.py +++ b/nova/scheduler/host_filter.py @@ -32,17 +32,16 @@ from nova import exception from nova import flags import nova.scheduler -# NOTE(Vek): Even though we don't use filters in here anywhere, we -# depend on default_host_filter being available in FLAGS, -# and that happens only when filters/abstract_filter.py is -# imported. from nova.scheduler import filters FLAGS = flags.FLAGS +flags.DEFINE_list('default_host_filters', ['AllHostsFilter'], + 'Which filters to use for filtering hosts when not specified ' + 'in the request.') -def _get_filters(): +def _get_filter_classes(): # Imported here to avoid circular imports from nova.scheduler import filters @@ -55,15 +54,29 @@ def _get_filters(): and get_itm(itm) is not filters.AbstractHostFilter] -def choose_host_filter(filter_name=None): - """Since the caller may specify which filter to use we need +def choose_host_filters(filters=None): + """Since the caller may specify which filters to use we need to have an authoritative list of what is permissible. This - function checks the filter name against a predefined set + function checks the filter names against a predefined set of acceptable filters. """ - if not filter_name: - filter_name = FLAGS.default_host_filter - for filter_class in _get_filters(): - if filter_class.__name__ == filter_name: - return filter_class() - raise exception.SchedulerHostFilterNotFound(filter_name=filter_name) + if not filters: + filters = FLAGS.default_host_filters + if not isinstance(filters, (list, tuple)): + filters = [filters] + good_filters = [] + bad_filters = [] + filter_classes = _get_filter_classes() + for filter_name in filters: + found_class = False + for cls in filter_classes: + if cls.__name__ == filter_name: + good_filters.append(cls()) + found_class = True + break + if not found_class: + bad_filters.append(filter_name) + if bad_filters: + msg = ", ".join(bad_filters) + raise exception.SchedulerHostFilterNotFound(filter_name=msg) + return good_filters diff --git a/nova/scheduler/least_cost.py b/nova/scheduler/least_cost.py index 1a6ef990c..b35e31601 100644 --- a/nova/scheduler/least_cost.py +++ b/nova/scheduler/least_cost.py @@ -114,10 +114,13 @@ class LeastCostScheduler(base_scheduler.BaseScheduler): self.cost_fns_cache = {} super(LeastCostScheduler, self).__init__(*args, **kwargs) - def get_cost_fns(self, topic): + def get_cost_fns(self, topic=None): """Returns a list of tuples containing weights and cost functions to use for weighing hosts """ + if topic is None: + # Schedulers only support compute right now. + topic = "compute" if topic in self.cost_fns_cache: return self.cost_fns_cache[topic] cost_fns = [] @@ -151,11 +154,11 @@ class LeastCostScheduler(base_scheduler.BaseScheduler): self.cost_fns_cache[topic] = cost_fns return cost_fns - def weigh_hosts(self, topic, request_spec, hosts): + def weigh_hosts(self, request_spec, hosts): """Returns a list of dictionaries of form: [ {weight: weight, hostname: hostname, capabilities: capabs} ] """ - cost_fns = self.get_cost_fns(topic) + cost_fns = self.get_cost_fns() costs = weighted_sum(domain=hosts, weighted_fns=cost_fns) weighted = [] diff --git a/nova/tests/scheduler/test_abstract_scheduler.py b/nova/tests/scheduler/test_abstract_scheduler.py index da25f1544..08b0b9cde 100644 --- a/nova/tests/scheduler/test_abstract_scheduler.py +++ b/nova/tests/scheduler/test_abstract_scheduler.py @@ -455,8 +455,7 @@ class BaseSchedulerTestCase(test.TestCase): # Call weigh_hosts() num_instances = len(hostlist) * 2 + len(hostlist) / 2 - instlist = sched.weigh_hosts('compute', - dict(num_instances=num_instances), + instlist = sched.weigh_hosts(dict(num_instances=num_instances), hostlist) # Should be enough entries to cover all instances diff --git a/nova/tests/scheduler/test_host_filter.py b/nova/tests/scheduler/test_host_filter.py index 17431fc7e..a21f4c380 100644 --- a/nova/tests/scheduler/test_host_filter.py +++ b/nova/tests/scheduler/test_host_filter.py @@ -18,10 +18,10 @@ Tests For Scheduler Host Filters. import json +import nova from nova import exception from nova import test from nova.scheduler import host_filter -from nova.scheduler import filters class FakeZoneManager: @@ -52,12 +52,13 @@ class HostFilterTestCase(test.TestCase): 'disk_total': 1000, 'disk_used': 0, 'host_uuid': 'xxx-%d' % multiplier, - 'host_name-label': 'xs-%s' % multiplier} + 'host_name-label': 'xs-%s' % multiplier, + 'enabled': True} def setUp(self): super(HostFilterTestCase, self).setUp() - default_host_filter = 'AllHostsFilter' - self.flags(default_host_filter=default_host_filter) + default_host_filters = ['AllHostsFilter'] + self.flags(default_host_filters=default_host_filters) self.instance_type = dict(name='tiny', memory_mb=50, vcpus=10, @@ -96,34 +97,41 @@ class HostFilterTestCase(test.TestCase): host09['xpu_arch'] = 'fermi' host09['xpu_info'] = 'Tesla 2150' + def _get_all_hosts(self): + return self.zone_manager.service_states.items() + def test_choose_filter(self): # Test default filter ... - hf = host_filter.choose_host_filter() + hfs = host_filter.choose_host_filters() + hf = hfs[0] self.assertEquals(hf._full_name().split(".")[-1], 'AllHostsFilter') # Test valid filter ... - hf = host_filter.choose_host_filter('InstanceTypeFilter') + hfs = host_filter.choose_host_filters('InstanceTypeFilter') + hf = hfs[0] self.assertEquals(hf._full_name().split(".")[-1], 'InstanceTypeFilter') # Test invalid filter ... try: - host_filter.choose_host_filter('does not exist') + host_filter.choose_host_filters('does not exist') self.fail("Should not find host filter.") except exception.SchedulerHostFilterNotFound: pass def test_all_host_filter(self): - hf = filters.AllHostsFilter() + hfs = host_filter.choose_host_filters('AllHostsFilter') + hf = hfs[0] + all_hosts = self._get_all_hosts() cooked = hf.instance_type_to_filter(self.instance_type) - hosts = hf.filter_hosts(self.zone_manager, cooked) + hosts = hf.filter_hosts(all_hosts, cooked) self.assertEquals(10, len(hosts)) for host, capabilities in hosts: self.assertTrue(host.startswith('host')) def test_instance_type_filter(self): - hf = filters.InstanceTypeFilter() + hf = nova.scheduler.filters.InstanceTypeFilter() # filter all hosts that can support 50 ram and 500 disk - name, cooked = hf.instance_type_to_filter(self.instance_type) - self.assertEquals(name.split(".")[-1], 'InstanceTypeFilter') - hosts = hf.filter_hosts(self.zone_manager, cooked) + cooked = hf.instance_type_to_filter(self.instance_type) + all_hosts = self._get_all_hosts() + hosts = hf.filter_hosts(all_hosts, cooked) self.assertEquals(6, len(hosts)) just_hosts = [host for host, caps in hosts] just_hosts.sort() @@ -131,21 +139,21 @@ class HostFilterTestCase(test.TestCase): self.assertEquals('host10', just_hosts[5]) def test_instance_type_filter_extra_specs(self): - hf = filters.InstanceTypeFilter() + hf = nova.scheduler.filters.InstanceTypeFilter() # filter all hosts that can support 50 ram and 500 disk - name, cooked = hf.instance_type_to_filter(self.gpu_instance_type) - self.assertEquals(name.split(".")[-1], 'InstanceTypeFilter') - hosts = hf.filter_hosts(self.zone_manager, cooked) + cooked = hf.instance_type_to_filter(self.gpu_instance_type) + all_hosts = self._get_all_hosts() + hosts = hf.filter_hosts(all_hosts, cooked) self.assertEquals(1, len(hosts)) just_hosts = [host for host, caps in hosts] self.assertEquals('host07', just_hosts[0]) def test_json_filter(self): - hf = filters.JsonFilter() + hf = nova.scheduler.filters.JsonFilter() # filter all hosts that can support 50 ram and 500 disk - name, cooked = hf.instance_type_to_filter(self.instance_type) - self.assertEquals(name.split(".")[-1], 'JsonFilter') - hosts = hf.filter_hosts(self.zone_manager, cooked) + cooked = hf.instance_type_to_filter(self.instance_type) + all_hosts = self._get_all_hosts() + hosts = hf.filter_hosts(all_hosts, cooked) self.assertEquals(6, len(hosts)) just_hosts = [host for host, caps in hosts] just_hosts.sort() @@ -165,7 +173,7 @@ class HostFilterTestCase(test.TestCase): ] ] cooked = json.dumps(raw) - hosts = hf.filter_hosts(self.zone_manager, cooked) + hosts = hf.filter_hosts(all_hosts, cooked) self.assertEquals(5, len(hosts)) just_hosts = [host for host, caps in hosts] @@ -177,7 +185,7 @@ class HostFilterTestCase(test.TestCase): ['=', '$compute.host_memory_free', 30], ] cooked = json.dumps(raw) - hosts = hf.filter_hosts(self.zone_manager, cooked) + hosts = hf.filter_hosts(all_hosts, cooked) self.assertEquals(9, len(hosts)) just_hosts = [host for host, caps in hosts] @@ -187,7 +195,7 @@ class HostFilterTestCase(test.TestCase): raw = ['in', '$compute.host_memory_free', 20, 40, 60, 80, 100] cooked = json.dumps(raw) - hosts = hf.filter_hosts(self.zone_manager, cooked) + hosts = hf.filter_hosts(all_hosts, cooked) self.assertEquals(5, len(hosts)) just_hosts = [host for host, caps in hosts] just_hosts.sort() @@ -198,32 +206,32 @@ class HostFilterTestCase(test.TestCase): raw = ['unknown command', ] cooked = json.dumps(raw) try: - hf.filter_hosts(self.zone_manager, cooked) + hf.filter_hosts(all_hosts, cooked) self.fail("Should give KeyError") except KeyError, e: pass - 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( + self.assertTrue(hf.filter_hosts(all_hosts, json.dumps([]))) + self.assertTrue(hf.filter_hosts(all_hosts, json.dumps({}))) + self.assertTrue(hf.filter_hosts(all_hosts, json.dumps( ['not', True, False, True, False], ))) try: - hf.filter_hosts(self.zone_manager, json.dumps( + hf.filter_hosts(all_hosts, json.dumps( 'not', True, False, True, False, )) self.fail("Should give KeyError") except KeyError, e: pass - self.assertFalse(hf.filter_hosts(self.zone_manager, + self.assertFalse(hf.filter_hosts(all_hosts, json.dumps(['=', '$foo', 100]))) - self.assertFalse(hf.filter_hosts(self.zone_manager, + self.assertFalse(hf.filter_hosts(all_hosts, json.dumps(['=', '$.....', 100]))) - self.assertFalse(hf.filter_hosts(self.zone_manager, + self.assertFalse(hf.filter_hosts(all_hosts, json.dumps( ['>', ['and', ['or', ['not', ['<', ['>=', ['<=', ['in', ]]]]]]]]))) - self.assertFalse(hf.filter_hosts(self.zone_manager, + self.assertFalse(hf.filter_hosts(all_hosts, json.dumps(['=', {}, ['>', '$missing....foo']]))) diff --git a/nova/tests/scheduler/test_least_cost_scheduler.py b/nova/tests/scheduler/test_least_cost_scheduler.py index b8847a2bf..589308e38 100644 --- a/nova/tests/scheduler/test_least_cost_scheduler.py +++ b/nova/tests/scheduler/test_least_cost_scheduler.py @@ -82,7 +82,7 @@ class LeastCostSchedulerTestCase(test.TestCase): super(LeastCostSchedulerTestCase, self).tearDown() def assertWeights(self, expected, num, request_spec, hosts): - weighted = self.sched.weigh_hosts("compute", request_spec, hosts) + weighted = self.sched.weigh_hosts(request_spec, hosts) self.assertDictListMatch(weighted, expected, approx_equal=True) def test_no_hosts(self): @@ -97,50 +97,20 @@ class LeastCostSchedulerTestCase(test.TestCase): self.flags(least_cost_scheduler_cost_functions=[ 'nova.scheduler.least_cost.noop_cost_fn'], noop_cost_fn_weight=1) - num = 1 request_spec = {} hosts = self.sched.filter_hosts(num, request_spec) - - expected = [dict(weight=1, hostname=hostname) - for hostname, caps in hosts] + expected = [{"hostname": hostname, "weight": 1, "capabilities": caps} + for hostname, caps in hosts] self.assertWeights(expected, num, request_spec, hosts) def test_cost_fn_weights(self): self.flags(least_cost_scheduler_cost_functions=[ 'nova.scheduler.least_cost.noop_cost_fn'], noop_cost_fn_weight=2) - num = 1 request_spec = {} hosts = self.sched.filter_hosts(num, request_spec) - - expected = [dict(weight=2, hostname=hostname) - for hostname, caps in hosts] - self.assertWeights(expected, num, request_spec, hosts) - - def test_compute_fill_first_cost_fn(self): - self.flags(least_cost_scheduler_cost_functions=[ - 'nova.scheduler.least_cost.compute_fill_first_cost_fn'], - compute_fill_first_cost_fn_weight=1) - num = 1 - instance_type = {'memory_mb': 1024} - request_spec = {'instance_type': instance_type} - svc_states = self.sched.zone_manager.service_states.iteritems() - all_hosts = [(host, services["compute"]) - for host, services in svc_states - if "compute" in services] - hosts = self.sched.filter_hosts('compute', request_spec, all_hosts) - - expected = [] - for idx, (hostname, services) in enumerate(hosts): - caps = copy.deepcopy(services) - # Costs are normalized so over 10 hosts, each host with increasing - # free ram will cost 1/N more. Since the lowest cost host has some - # free ram, we add in the 1/N for the base_cost - weight = 0.1 + (0.1 * idx) - wtd_dict = dict(hostname=hostname, weight=weight, - capabilities=caps) - expected.append(wtd_dict) - + expected = [{"hostname": hostname, "weight": 2, "capabilities": caps} + for hostname, caps in hosts] self.assertWeights(expected, num, request_spec, hosts) diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost index 36c61f78d..f02597afc 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost @@ -271,6 +271,7 @@ def cleanup(dct): # avv["major"] = safe_int(dct.get("API-version-major", "")) # avv["minor"] = safe_int(dct.get("API-version-minor", "")) + out["enabled"] = dct.get("enabled", True) out["host_uuid"] = dct.get("uuid", None) out["host_name-label"] = dct.get("name-label", "") out["host_name-description"] = dct.get("name-description", "") |
