summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2011-10-13 00:17:49 +0000
committerGerrit Code Review <review@openstack.org>2011-10-13 00:17:49 +0000
commitd83f45faf1ded92a0766548d6ebaef3d4c7e08e9 (patch)
treefad4652c0ac90c2062c1e54e3ebbe2369166edbd
parent01e68c3de5b3c1cb6630bea862807089b77926d0 (diff)
parent80e196069fa94edb8981415f9b8d432bbf92888f (diff)
downloadnova-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.py4
-rw-r--r--nova/scheduler/base_scheduler.py27
-rw-r--r--nova/scheduler/filters/abstract_filter.py7
-rw-r--r--nova/scheduler/filters/all_hosts_filter.py11
-rw-r--r--nova/scheduler/filters/instance_type_filter.py14
-rw-r--r--nova/scheduler/filters/json_filter.py20
-rw-r--r--nova/scheduler/host_filter.py41
-rw-r--r--nova/scheduler/least_cost.py9
-rw-r--r--nova/tests/scheduler/test_abstract_scheduler.py3
-rw-r--r--nova/tests/scheduler/test_host_filter.py74
-rw-r--r--nova/tests/scheduler/test_least_cost_scheduler.py40
-rwxr-xr-xplugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost1
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", "")