Merge "Prepare filters for using RequestSpec object"
This commit is contained in:
commit
1254e3978a
@ -27,13 +27,13 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
class BaseFilter(object):
|
||||
"""Base class for all filter classes."""
|
||||
def _filter_one(self, obj, filter_properties):
|
||||
def _filter_one(self, obj, spec_obj):
|
||||
"""Return True if it passes the filter, False otherwise.
|
||||
Override this in a subclass.
|
||||
"""
|
||||
return True
|
||||
|
||||
def filter_all(self, filter_obj_list, filter_properties):
|
||||
def filter_all(self, filter_obj_list, spec_obj):
|
||||
"""Yield objects that pass the filter.
|
||||
|
||||
Can be overridden in a subclass, if you need to base filtering
|
||||
@ -41,7 +41,7 @@ class BaseFilter(object):
|
||||
_filter_one() to filter a single object.
|
||||
"""
|
||||
for obj in filter_obj_list:
|
||||
if self._filter_one(obj, filter_properties):
|
||||
if self._filter_one(obj, spec_obj):
|
||||
yield obj
|
||||
|
||||
# Set to true in a subclass if a filter only needs to be run once
|
||||
@ -65,7 +65,7 @@ class BaseFilterHandler(loadables.BaseLoader):
|
||||
This class should be subclassed where one needs to use filters.
|
||||
"""
|
||||
|
||||
def get_filtered_objects(self, filters, objs, filter_properties, index=0):
|
||||
def get_filtered_objects(self, filters, objs, spec_obj, index=0):
|
||||
list_objs = list(objs)
|
||||
LOG.debug("Starting with %d host(s)", len(list_objs))
|
||||
# Track the hosts as they are removed. The 'full_filter_results' list
|
||||
@ -82,7 +82,7 @@ class BaseFilterHandler(loadables.BaseLoader):
|
||||
if filter_.run_filter_for_index(index):
|
||||
cls_name = filter_.__class__.__name__
|
||||
start_count = len(list_objs)
|
||||
objs = filter_.filter_all(list_objs, filter_properties)
|
||||
objs = filter_.filter_all(list_objs, spec_obj)
|
||||
if objs is None:
|
||||
LOG.debug("Filter %s says to stop filtering", cls_name)
|
||||
return
|
||||
@ -104,9 +104,17 @@ class BaseFilterHandler(loadables.BaseLoader):
|
||||
{'cls_name': cls_name, 'obj_len': len(list_objs)})
|
||||
if not list_objs:
|
||||
# Log the filtration history
|
||||
rspec = filter_properties.get("request_spec", {})
|
||||
inst_props = rspec.get("instance_properties", {})
|
||||
msg_dict = {"inst_uuid": inst_props.get("uuid", ""),
|
||||
# NOTE(sbauza): Since the Cells scheduler still provides a legacy
|
||||
# dictionary for filter_props, and since we agreed on not modifying
|
||||
# the Cells scheduler to support that because of Cells v2, we
|
||||
# prefer to define a compatible way to address both types
|
||||
if isinstance(spec_obj, dict):
|
||||
rspec = spec_obj.get("request_spec", {})
|
||||
inst_props = rspec.get("instance_properties", {})
|
||||
inst_uuid = inst_props.get("uuid", "")
|
||||
else:
|
||||
inst_uuid = spec_obj.instance_uuid
|
||||
msg_dict = {"inst_uuid": inst_uuid,
|
||||
"str_results": str(full_filter_results),
|
||||
}
|
||||
full_msg = ("Filtering removed all hosts for the request with "
|
||||
|
@ -127,23 +127,12 @@ class FilterScheduler(driver.Scheduler):
|
||||
|
||||
selected_hosts = []
|
||||
num_instances = spec_obj.num_instances
|
||||
# TODO(sbauza): Modify the interfaces for HostManager and filters to
|
||||
# accept the RequestSpec object directly (in a later patch hopefully)
|
||||
filter_properties = spec_obj.to_legacy_filter_properties_dict()
|
||||
# NOTE(sbauza): Adding temporarly some keys since filters are
|
||||
# directly using it - until we provide directly RequestSpec
|
||||
filter_properties.update(
|
||||
{'request_spec': spec_obj.to_legacy_request_spec_dict(),
|
||||
'instance_type': spec_obj.flavor})
|
||||
# TODO(sbauza): Adding two keys not used in-tree but which will be
|
||||
# provided as non-fields for the RequestSpec once we provide it to the
|
||||
# filters
|
||||
filter_properties.update({'context': context,
|
||||
'config_options': config_options})
|
||||
# NOTE(sbauza): Adding one field for any out-of-tree need
|
||||
spec_obj.config_options = config_options
|
||||
for num in range(num_instances):
|
||||
# Filter local hosts based on requirements ...
|
||||
hosts = self.host_manager.get_filtered_hosts(hosts,
|
||||
filter_properties, index=num)
|
||||
spec_obj, index=num)
|
||||
if not hosts:
|
||||
# Can't get any more locally.
|
||||
break
|
||||
@ -151,7 +140,7 @@ class FilterScheduler(driver.Scheduler):
|
||||
LOG.debug("Filtered %(hosts)s", {'hosts': hosts})
|
||||
|
||||
weighed_hosts = self.host_manager.get_weighed_hosts(hosts,
|
||||
filter_properties)
|
||||
spec_obj)
|
||||
|
||||
LOG.debug("Weighed %(hosts)s", {'hosts': weighed_hosts})
|
||||
|
||||
@ -169,8 +158,10 @@ class FilterScheduler(driver.Scheduler):
|
||||
# Now consume the resources so the filter/weights
|
||||
# will change for the next instance.
|
||||
chosen_host.obj.consume_from_request(spec_obj)
|
||||
if filter_properties.get('group_updated') is True:
|
||||
filter_properties['group_hosts'].add(chosen_host.obj.host)
|
||||
if spec_obj.instance_group is not None:
|
||||
spec_obj.instance_group.hosts.append(chosen_host.obj.host)
|
||||
# hosts has to be not part of the updates when saving
|
||||
spec_obj.instance_group.obj_reset_changes(['hosts'])
|
||||
return selected_hosts
|
||||
|
||||
def _get_all_host_states(self, context):
|
||||
|
@ -16,8 +16,10 @@
|
||||
"""
|
||||
Scheduler host filters
|
||||
"""
|
||||
import functools
|
||||
|
||||
from nova import filters
|
||||
from nova import objects
|
||||
|
||||
|
||||
class BaseHostFilter(filters.BaseFilter):
|
||||
@ -45,3 +47,31 @@ def all_filters():
|
||||
and should return a list of all filter classes available.
|
||||
"""
|
||||
return HostFilterHandler().get_all_classes()
|
||||
|
||||
|
||||
# TODO(sbauza): Remove that decorator once all filters are using RequestSpec
|
||||
# object directly.
|
||||
def compat_legacy_props(function):
|
||||
"""Decorator for returning a legacy filter_properties dictionary.
|
||||
|
||||
This is used for keeping unchanged the existing filters without yet using
|
||||
the RequestSpec fields by returning a legacy dictionary.
|
||||
"""
|
||||
|
||||
@functools.wraps(function)
|
||||
def decorated_host_passes(self, host_state, filter_properties):
|
||||
if isinstance(filter_properties, objects.RequestSpec):
|
||||
legacy_props = filter_properties.to_legacy_filter_properties_dict()
|
||||
legacy_props.update({'request_spec': (
|
||||
filter_properties.to_legacy_request_spec_dict()),
|
||||
'instance_type': filter_properties.flavor})
|
||||
# TODO(sbauza): Adding two keys not used in-tree but which will be
|
||||
# provided as non-fields for the RequestSpec once we provide it to
|
||||
# the filters
|
||||
legacy_props.update(
|
||||
{'context': filter_properties._context,
|
||||
'config_options': filter_properties.config_options})
|
||||
filter_properties = legacy_props
|
||||
return function(self, host_state, filter_properties)
|
||||
|
||||
return decorated_host_passes
|
||||
|
@ -30,6 +30,7 @@ class DifferentHostFilter(filters.BaseHostFilter):
|
||||
# The hosts the instances are running on doesn't change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
scheduler_hints = filter_properties.get('scheduler_hints') or {}
|
||||
|
||||
@ -49,6 +50,7 @@ class SameHostFilter(filters.BaseHostFilter):
|
||||
# The hosts the instances are running on doesn't change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
scheduler_hints = filter_properties.get('scheduler_hints') or {}
|
||||
|
||||
@ -67,6 +69,7 @@ class SimpleCIDRAffinityFilter(filters.BaseHostFilter):
|
||||
# The address of a host doesn't change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
scheduler_hints = filter_properties.get('scheduler_hints') or {}
|
||||
|
||||
@ -87,6 +90,7 @@ class _GroupAntiAffinityFilter(filters.BaseHostFilter):
|
||||
"""Schedule the instance on a different host from a set of group
|
||||
hosts.
|
||||
"""
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
# Only invoke the filter is 'anti-affinity' is configured
|
||||
policies = filter_properties.get('group_policies', [])
|
||||
@ -113,6 +117,7 @@ class ServerGroupAntiAffinityFilter(_GroupAntiAffinityFilter):
|
||||
class _GroupAffinityFilter(filters.BaseHostFilter):
|
||||
"""Schedule the instance on to host from a set of group hosts.
|
||||
"""
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
# Only invoke the filter is 'affinity' is configured
|
||||
policies = filter_properties.get('group_policies', [])
|
||||
|
@ -40,6 +40,7 @@ class AggregateImagePropertiesIsolation(filters.BaseHostFilter):
|
||||
# Aggregate data and instance type does not change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Checks a host in an aggregate that metadata key/value match
|
||||
with image properties.
|
||||
|
@ -33,6 +33,7 @@ class AggregateInstanceExtraSpecsFilter(filters.BaseHostFilter):
|
||||
# Aggregate data and instance type does not change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Return a list of hosts that can create instance_type
|
||||
|
||||
|
@ -28,6 +28,7 @@ class AggregateMultiTenancyIsolation(filters.BaseHostFilter):
|
||||
# Aggregate data and tenant do not change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""If a host is in an aggregate that has the metadata key
|
||||
"filter_tenant_id" it can only create instances from that tenant(s).
|
||||
|
@ -23,5 +23,6 @@ class AllHostsFilter(filters.BaseHostFilter):
|
||||
# list of hosts doesn't change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
return True
|
||||
|
@ -36,6 +36,7 @@ class AvailabilityZoneFilter(filters.BaseHostFilter):
|
||||
# Availability zones do not change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
spec = filter_properties.get('request_spec', {})
|
||||
props = spec.get('instance_properties', {})
|
||||
|
@ -92,6 +92,7 @@ class ComputeCapabilitiesFilter(filters.BaseHostFilter):
|
||||
return False
|
||||
return True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Return a list of hosts that can create instance_type."""
|
||||
instance_type = filter_properties.get('instance_type')
|
||||
|
@ -34,6 +34,7 @@ class ComputeFilter(filters.BaseHostFilter):
|
||||
# Host state does not change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Returns True for only active compute nodes."""
|
||||
service = host_state.service
|
||||
|
@ -29,6 +29,7 @@ class BaseCoreFilter(filters.BaseHostFilter):
|
||||
def _get_cpu_allocation_ratio(self, host_state, filter_properties):
|
||||
raise NotImplementedError
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Return True if host has sufficient CPU cores."""
|
||||
instance_type = filter_properties.get('instance_type')
|
||||
|
@ -35,6 +35,7 @@ class DiskFilter(filters.BaseHostFilter):
|
||||
def _get_disk_allocation_ratio(self, host_state, filter_properties):
|
||||
return CONF.disk_allocation_ratio
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Filter based on disk usage."""
|
||||
instance_type = filter_properties.get('instance_type')
|
||||
|
@ -25,6 +25,7 @@ LOG = logging.getLogger(__name__)
|
||||
class ExactCoreFilter(filters.BaseHostFilter):
|
||||
"""Exact Core Filter."""
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Return True if host has the exact number of CPU cores."""
|
||||
instance_type = filter_properties.get('instance_type')
|
||||
|
@ -23,6 +23,7 @@ LOG = logging.getLogger(__name__)
|
||||
class ExactDiskFilter(filters.BaseHostFilter):
|
||||
"""Exact Disk Filter."""
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Return True if host has the exact amount of disk available."""
|
||||
instance_type = filter_properties.get('instance_type')
|
||||
|
@ -23,6 +23,7 @@ LOG = logging.getLogger(__name__)
|
||||
class ExactRamFilter(filters.BaseHostFilter):
|
||||
"""Exact RAM Filter."""
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Return True if host has the exact amount of RAM available."""
|
||||
instance_type = filter_properties.get('instance_type')
|
||||
|
@ -95,6 +95,7 @@ class ImagePropertiesFilter(filters.BaseHostFilter):
|
||||
'hypervisor_version': hypervisor_version})
|
||||
return False
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Check if host passes specified image properties.
|
||||
|
||||
|
@ -39,6 +39,7 @@ class IoOpsFilter(filters.BaseHostFilter):
|
||||
def _get_max_io_ops_per_host(self, host_state, filter_properties):
|
||||
return CONF.max_io_ops_per_host
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Use information about current vm and task states collected from
|
||||
compute node statistics to decide whether to filter.
|
||||
|
@ -39,6 +39,7 @@ class IsolatedHostsFilter(filters.BaseHostFilter):
|
||||
# The configuration values do not change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Result Matrix with 'restrict_isolated_hosts_to_isolated_images' set
|
||||
to True::
|
||||
|
@ -126,6 +126,7 @@ class JsonFilter(filters.BaseHostFilter):
|
||||
result = method(self, cooked_args)
|
||||
return result
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Return a list of hosts that can fulfill the requirements
|
||||
specified in the query.
|
||||
|
@ -43,6 +43,7 @@ class MetricsFilter(filters.BaseHostFilter):
|
||||
name="metrics.weight_setting")
|
||||
self.keys = set([x[0] for x in opts])
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
metrics_on_host = set(m.name for m in host_state.metrics)
|
||||
if not self.keys.issubset(metrics_on_host):
|
||||
|
@ -36,6 +36,7 @@ class NumInstancesFilter(filters.BaseHostFilter):
|
||||
def _get_max_instances_per_host(self, host_state, filter_properties):
|
||||
return CONF.max_instances_per_host
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
num_instances = host_state.num_instances
|
||||
max_instances = self._get_max_instances_per_host(
|
||||
|
@ -18,6 +18,7 @@ from nova.virt import hardware
|
||||
class NUMATopologyFilter(filters.BaseHostFilter):
|
||||
"""Filter on requested NUMA topology."""
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
ram_ratio = host_state.ram_allocation_ratio
|
||||
cpu_ratio = host_state.cpu_allocation_ratio
|
||||
|
@ -40,6 +40,7 @@ class PciPassthroughFilter(filters.BaseHostFilter):
|
||||
|
||||
"""
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Return true if the host has the required PCI devices."""
|
||||
request_spec = filter_properties.get('request_spec', {})
|
||||
|
@ -28,6 +28,7 @@ class BaseRamFilter(filters.BaseHostFilter):
|
||||
def _get_ram_allocation_ratio(self, host_state, filter_properties):
|
||||
raise NotImplementedError
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Only return hosts with sufficient available RAM."""
|
||||
instance_type = filter_properties.get('instance_type')
|
||||
|
@ -25,6 +25,7 @@ class RetryFilter(filters.BaseHostFilter):
|
||||
purposes
|
||||
"""
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Skip nodes that have already been attempted."""
|
||||
retry = filter_properties.get('retry', None)
|
||||
|
@ -265,6 +265,7 @@ class TrustedFilter(filters.BaseHostFilter):
|
||||
# The hosts the instances are running on doesn't change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
instance_type = filter_properties.get('instance_type', {})
|
||||
extra = instance_type.get('extra_specs', {})
|
||||
|
@ -25,6 +25,7 @@ class TypeAffinityFilter(filters.BaseHostFilter):
|
||||
(spread) set to 1 (default).
|
||||
"""
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
"""Dynamically limits hosts to one instance type
|
||||
|
||||
@ -48,6 +49,7 @@ class AggregateTypeAffinityFilter(filters.BaseHostFilter):
|
||||
# Aggregate data does not change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
instance_type = filter_properties.get('instance_type')
|
||||
|
||||
|
@ -449,7 +449,7 @@ class HostManager(object):
|
||||
raise exception.SchedulerHostFilterNotFound(filter_name=msg)
|
||||
return good_filters
|
||||
|
||||
def get_filtered_hosts(self, hosts, filter_properties,
|
||||
def get_filtered_hosts(self, hosts, spec_obj,
|
||||
filter_class_names=None, index=0):
|
||||
"""Filter hosts and return only ones passing all filters."""
|
||||
|
||||
@ -499,9 +499,9 @@ class HostManager(object):
|
||||
filters = self.default_filters
|
||||
else:
|
||||
filters = self._choose_host_filters(filter_class_names)
|
||||
ignore_hosts = filter_properties.get('ignore_hosts', [])
|
||||
force_hosts = filter_properties.get('force_hosts', [])
|
||||
force_nodes = filter_properties.get('force_nodes', [])
|
||||
ignore_hosts = spec_obj.ignore_hosts or []
|
||||
force_hosts = spec_obj.force_hosts or []
|
||||
force_nodes = spec_obj.force_nodes or []
|
||||
|
||||
if ignore_hosts or force_hosts or force_nodes:
|
||||
# NOTE(deva): we can't assume "host" is unique because
|
||||
@ -523,12 +523,12 @@ class HostManager(object):
|
||||
hosts = six.itervalues(name_to_cls_map)
|
||||
|
||||
return self.filter_handler.get_filtered_objects(filters,
|
||||
hosts, filter_properties, index)
|
||||
hosts, spec_obj, index)
|
||||
|
||||
def get_weighed_hosts(self, hosts, weight_properties):
|
||||
def get_weighed_hosts(self, hosts, spec_obj):
|
||||
"""Weigh the hosts."""
|
||||
return self.weight_handler.get_weighed_objects(self.weighers,
|
||||
hosts, weight_properties)
|
||||
hosts, spec_obj)
|
||||
|
||||
def get_all_host_states(self, context):
|
||||
"""Returns a list of HostStates that represents all the hosts
|
||||
|
@ -74,7 +74,8 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
os_type='Linux',
|
||||
uuid='fake-uuid',
|
||||
pci_requests=None,
|
||||
numa_topology=None)
|
||||
numa_topology=None,
|
||||
instance_group=None)
|
||||
self.mox.ReplayAll()
|
||||
weighed_hosts = self.driver._schedule(self.context, spec_obj)
|
||||
self.assertEqual(len(weighed_hosts), 10)
|
||||
@ -143,7 +144,8 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
ephemeral_gb=0,
|
||||
vcpus=1),
|
||||
pci_requests=None,
|
||||
numa_topology=None)
|
||||
numa_topology=None,
|
||||
instance_group=None)
|
||||
self.mox.ReplayAll()
|
||||
hosts = self.driver._schedule(self.context, spec_obj)
|
||||
|
||||
@ -178,7 +180,8 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
ephemeral_gb=0,
|
||||
vcpus=1),
|
||||
pci_requests=None,
|
||||
numa_topology=None)
|
||||
numa_topology=None,
|
||||
instance_group=None)
|
||||
self.mox.ReplayAll()
|
||||
hosts = self.driver._schedule(self.context, spec_obj)
|
||||
|
||||
@ -222,7 +225,8 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
ephemeral_gb=0,
|
||||
vcpus=1),
|
||||
pci_requests=None,
|
||||
numa_topology=None)
|
||||
numa_topology=None,
|
||||
instance_group=None)
|
||||
|
||||
self.stubs.Set(weights.HostWeightHandler,
|
||||
'get_weighed_objects', _fake_weigh_objects)
|
||||
|
@ -23,6 +23,7 @@ from six.moves import range
|
||||
|
||||
from nova import filters
|
||||
from nova import loadables
|
||||
from nova import objects
|
||||
from nova import test
|
||||
|
||||
|
||||
@ -46,18 +47,18 @@ class FiltersTestCase(test.NoDBTestCase):
|
||||
|
||||
def test_filter_all(self):
|
||||
filter_obj_list = ['obj1', 'obj2', 'obj3']
|
||||
filter_properties = 'fake_filter_properties'
|
||||
spec_obj = objects.RequestSpec()
|
||||
base_filter = filters.BaseFilter()
|
||||
|
||||
self.mox.StubOutWithMock(base_filter, '_filter_one')
|
||||
|
||||
base_filter._filter_one('obj1', filter_properties).AndReturn(True)
|
||||
base_filter._filter_one('obj2', filter_properties).AndReturn(False)
|
||||
base_filter._filter_one('obj3', filter_properties).AndReturn(True)
|
||||
base_filter._filter_one('obj1', spec_obj).AndReturn(True)
|
||||
base_filter._filter_one('obj2', spec_obj).AndReturn(False)
|
||||
base_filter._filter_one('obj3', spec_obj).AndReturn(True)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
result = base_filter.filter_all(filter_obj_list, filter_properties)
|
||||
result = base_filter.filter_all(filter_obj_list, spec_obj)
|
||||
self.assertTrue(inspect.isgenerator(result))
|
||||
self.assertEqual(['obj1', 'obj3'], list(result))
|
||||
|
||||
@ -67,7 +68,7 @@ class FiltersTestCase(test.NoDBTestCase):
|
||||
# call filter_all() with generators returned from previous calls
|
||||
# to filter_all().
|
||||
filter_obj_list = ['obj1', 'obj2', 'obj3']
|
||||
filter_properties = 'fake_filter_properties'
|
||||
spec_obj = objects.RequestSpec()
|
||||
base_filter = filters.BaseFilter()
|
||||
|
||||
self.mox.StubOutWithMock(base_filter, '_filter_one')
|
||||
@ -83,16 +84,16 @@ class FiltersTestCase(test.NoDBTestCase):
|
||||
# After that, 'obj3' gets yielded 'total_iterations' number of
|
||||
# times.
|
||||
for x in range(total_iterations):
|
||||
base_filter._filter_one('obj1', filter_properties).AndReturn(True)
|
||||
base_filter._filter_one('obj2', filter_properties).AndReturn(False)
|
||||
base_filter._filter_one('obj1', spec_obj).AndReturn(True)
|
||||
base_filter._filter_one('obj2', spec_obj).AndReturn(False)
|
||||
for x in range(total_iterations):
|
||||
base_filter._filter_one('obj3', filter_properties).AndReturn(True)
|
||||
base_filter._filter_one('obj3', spec_obj).AndReturn(True)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
objs = iter(filter_obj_list)
|
||||
for x in range(total_iterations):
|
||||
# Pass in generators returned from previous calls.
|
||||
objs = base_filter.filter_all(objs, filter_properties)
|
||||
objs = base_filter.filter_all(objs, spec_obj)
|
||||
self.assertTrue(inspect.isgenerator(objs))
|
||||
self.assertEqual(['obj1', 'obj3'], list(objs))
|
||||
|
||||
@ -100,7 +101,7 @@ class FiltersTestCase(test.NoDBTestCase):
|
||||
filter_objs_initial = ['initial', 'filter1', 'objects1']
|
||||
filter_objs_second = ['second', 'filter2', 'objects2']
|
||||
filter_objs_last = ['last', 'filter3', 'objects3']
|
||||
filter_properties = 'fake_filter_properties'
|
||||
spec_obj = objects.RequestSpec()
|
||||
|
||||
def _fake_base_loader_init(*args, **kwargs):
|
||||
pass
|
||||
@ -122,10 +123,10 @@ class FiltersTestCase(test.NoDBTestCase):
|
||||
|
||||
filt1_mock.run_filter_for_index(0).AndReturn(True)
|
||||
filt1_mock.filter_all(filter_objs_initial,
|
||||
filter_properties).AndReturn(filter_objs_second)
|
||||
spec_obj).AndReturn(filter_objs_second)
|
||||
filt2_mock.run_filter_for_index(0).AndReturn(True)
|
||||
filt2_mock.filter_all(filter_objs_second,
|
||||
filter_properties).AndReturn(filter_objs_last)
|
||||
spec_obj).AndReturn(filter_objs_last)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@ -133,7 +134,7 @@ class FiltersTestCase(test.NoDBTestCase):
|
||||
filter_mocks = [filt1_mock, filt2_mock]
|
||||
result = filter_handler.get_filtered_objects(filter_mocks,
|
||||
filter_objs_initial,
|
||||
filter_properties)
|
||||
spec_obj)
|
||||
self.assertEqual(filter_objs_last, result)
|
||||
|
||||
def test_get_filtered_objects_for_index(self):
|
||||
@ -142,7 +143,7 @@ class FiltersTestCase(test.NoDBTestCase):
|
||||
"""
|
||||
filter_objs_initial = ['initial', 'filter1', 'objects1']
|
||||
filter_objs_second = ['second', 'filter2', 'objects2']
|
||||
filter_properties = 'fake_filter_properties'
|
||||
spec_obj = objects.RequestSpec()
|
||||
|
||||
def _fake_base_loader_init(*args, **kwargs):
|
||||
pass
|
||||
@ -164,7 +165,7 @@ class FiltersTestCase(test.NoDBTestCase):
|
||||
|
||||
filt1_mock.run_filter_for_index(0).AndReturn(True)
|
||||
filt1_mock.filter_all(filter_objs_initial,
|
||||
filter_properties).AndReturn(filter_objs_second)
|
||||
spec_obj).AndReturn(filter_objs_second)
|
||||
# return false so filter_all will not be called
|
||||
filt2_mock.run_filter_for_index(0).AndReturn(False)
|
||||
|
||||
@ -174,11 +175,11 @@ class FiltersTestCase(test.NoDBTestCase):
|
||||
filter_mocks = [filt1_mock, filt2_mock]
|
||||
filter_handler.get_filtered_objects(filter_mocks,
|
||||
filter_objs_initial,
|
||||
filter_properties)
|
||||
spec_obj)
|
||||
|
||||
def test_get_filtered_objects_none_response(self):
|
||||
filter_objs_initial = ['initial', 'filter1', 'objects1']
|
||||
filter_properties = 'fake_filter_properties'
|
||||
spec_obj = objects.RequestSpec()
|
||||
|
||||
def _fake_base_loader_init(*args, **kwargs):
|
||||
pass
|
||||
@ -200,26 +201,86 @@ class FiltersTestCase(test.NoDBTestCase):
|
||||
|
||||
filt1_mock.run_filter_for_index(0).AndReturn(True)
|
||||
filt1_mock.filter_all(filter_objs_initial,
|
||||
filter_properties).AndReturn(None)
|
||||
spec_obj).AndReturn(None)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
filter_handler = filters.BaseFilterHandler(filters.BaseFilter)
|
||||
filter_mocks = [filt1_mock, filt2_mock]
|
||||
result = filter_handler.get_filtered_objects(filter_mocks,
|
||||
filter_objs_initial,
|
||||
filter_properties)
|
||||
spec_obj)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_get_filtered_objects_info_log_none_returned(self):
|
||||
LOG = filters.LOG
|
||||
|
||||
class FilterA(filters.BaseFilter):
|
||||
def filter_all(self, list_objs, filter_properties):
|
||||
def filter_all(self, list_objs, spec_obj):
|
||||
# return all but the first object
|
||||
return list_objs[1:]
|
||||
|
||||
class FilterB(filters.BaseFilter):
|
||||
def filter_all(self, list_objs, filter_properties):
|
||||
def filter_all(self, list_objs, spec_obj):
|
||||
# return an empty list
|
||||
return []
|
||||
|
||||
filter_a = FilterA()
|
||||
filter_b = FilterB()
|
||||
all_filters = [filter_a, filter_b]
|
||||
hosts = ["Host0", "Host1", "Host2"]
|
||||
fake_uuid = "uuid"
|
||||
spec_obj = objects.RequestSpec(instance_uuid=fake_uuid)
|
||||
with mock.patch.object(LOG, "info") as mock_log:
|
||||
result = self.filter_handler.get_filtered_objects(
|
||||
all_filters, hosts, spec_obj)
|
||||
self.assertFalse(result)
|
||||
# FilterA should leave Host1 and Host2; FilterB should leave None.
|
||||
exp_output = ("['FilterA: (start: 3, end: 2)', "
|
||||
"'FilterB: (start: 2, end: 0)']")
|
||||
cargs = mock_log.call_args[0][0]
|
||||
self.assertIn("with instance ID '%s'" % fake_uuid, cargs)
|
||||
self.assertIn(exp_output, cargs)
|
||||
|
||||
def test_get_filtered_objects_debug_log_none_returned(self):
|
||||
LOG = filters.LOG
|
||||
|
||||
class FilterA(filters.BaseFilter):
|
||||
def filter_all(self, list_objs, spec_obj):
|
||||
# return all but the first object
|
||||
return list_objs[1:]
|
||||
|
||||
class FilterB(filters.BaseFilter):
|
||||
def filter_all(self, list_objs, spec_obj):
|
||||
# return an empty list
|
||||
return []
|
||||
|
||||
filter_a = FilterA()
|
||||
filter_b = FilterB()
|
||||
all_filters = [filter_a, filter_b]
|
||||
hosts = ["Host0", "Host1", "Host2"]
|
||||
fake_uuid = "uuid"
|
||||
spec_obj = objects.RequestSpec(instance_uuid=fake_uuid)
|
||||
with mock.patch.object(LOG, "debug") as mock_log:
|
||||
result = self.filter_handler.get_filtered_objects(
|
||||
all_filters, hosts, spec_obj)
|
||||
self.assertFalse(result)
|
||||
# FilterA should leave Host1 and Host2; FilterB should leave None.
|
||||
exp_output = ("[('FilterA', [('Host1', ''), ('Host2', '')]), " +
|
||||
"('FilterB', None)]")
|
||||
cargs = mock_log.call_args[0][0]
|
||||
self.assertIn("with instance ID '%s'" % fake_uuid, cargs)
|
||||
self.assertIn(exp_output, cargs)
|
||||
|
||||
def test_get_filtered_objects_compatible_with_filt_props_dicts(self):
|
||||
LOG = filters.LOG
|
||||
|
||||
class FilterA(filters.BaseFilter):
|
||||
def filter_all(self, list_objs, spec_obj):
|
||||
# return all but the first object
|
||||
return list_objs[1:]
|
||||
|
||||
class FilterB(filters.BaseFilter):
|
||||
def filter_all(self, list_objs, spec_obj):
|
||||
# return an empty list
|
||||
return []
|
||||
|
||||
@ -240,34 +301,3 @@ class FiltersTestCase(test.NoDBTestCase):
|
||||
cargs = mock_log.call_args[0][0]
|
||||
self.assertIn("with instance ID '%s'" % fake_uuid, cargs)
|
||||
self.assertIn(exp_output, cargs)
|
||||
|
||||
def test_get_filtered_objects_debug_log_none_returned(self):
|
||||
LOG = filters.LOG
|
||||
|
||||
class FilterA(filters.BaseFilter):
|
||||
def filter_all(self, list_objs, filter_properties):
|
||||
# return all but the first object
|
||||
return list_objs[1:]
|
||||
|
||||
class FilterB(filters.BaseFilter):
|
||||
def filter_all(self, list_objs, filter_properties):
|
||||
# return an empty list
|
||||
return []
|
||||
|
||||
filter_a = FilterA()
|
||||
filter_b = FilterB()
|
||||
all_filters = [filter_a, filter_b]
|
||||
hosts = ["Host0", "Host1", "Host2"]
|
||||
fake_uuid = "uuid"
|
||||
filt_props = {"request_spec": {"instance_properties": {
|
||||
"uuid": fake_uuid}}}
|
||||
with mock.patch.object(LOG, "debug") as mock_log:
|
||||
result = self.filter_handler.get_filtered_objects(
|
||||
all_filters, hosts, filt_props)
|
||||
self.assertFalse(result)
|
||||
# FilterA should leave Host1 and Host2; FilterB should leave None.
|
||||
exp_output = ("[('FilterA', [('Host1', ''), ('Host2', '')]), " +
|
||||
"('FilterB', None)]")
|
||||
cargs = mock_log.call_args[0][0]
|
||||
self.assertIn("with instance ID '%s'" % fake_uuid, cargs)
|
||||
self.assertIn(exp_output, cargs)
|
||||
|
@ -14,7 +14,9 @@
|
||||
"""
|
||||
Tests For Scheduler Host Filters.
|
||||
"""
|
||||
import mock
|
||||
|
||||
from nova import objects
|
||||
from nova.scheduler import filters
|
||||
from nova.scheduler.filters import all_hosts_filter
|
||||
from nova.scheduler.filters import compute_filter
|
||||
@ -36,3 +38,27 @@ class HostFiltersTestCase(test.NoDBTestCase):
|
||||
filt_cls = all_hosts_filter.AllHostsFilter()
|
||||
host = fakes.FakeHostState('host1', 'node1', {})
|
||||
self.assertTrue(filt_cls.host_passes(host, {}))
|
||||
|
||||
@mock.patch.object(objects.RequestSpec, 'to_legacy_request_spec_dict')
|
||||
@mock.patch.object(objects.RequestSpec, 'to_legacy_filter_properties_dict')
|
||||
def test_compat_legacy_props(self, to_props, to_spec):
|
||||
fake_flavor = objects.Flavor()
|
||||
fake_context = mock.Mock()
|
||||
fake_spec = objects.RequestSpec(context=fake_context,
|
||||
flavor=fake_flavor)
|
||||
fake_spec.config_options = None
|
||||
to_props.return_value = {'prop1': 'val1'}
|
||||
to_spec.return_value = {'spec1': 'val2'}
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def fake_host_passes(self, host_state, filter_properties):
|
||||
# NOTE(sbauza): Convenient way to verify the passed properties
|
||||
return filter_properties
|
||||
|
||||
expected = {'prop1': 'val1',
|
||||
'request_spec': {'spec1': 'val2'},
|
||||
'instance_type': fake_flavor,
|
||||
'context': fake_context,
|
||||
'config_options': None}
|
||||
self.assertEqual(expected,
|
||||
fake_host_passes('self', 'host_state', fake_spec))
|
||||
|
@ -207,7 +207,10 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(set(info['expected_objs']), set(result))
|
||||
|
||||
def test_get_filtered_hosts(self):
|
||||
fake_properties = {'moo': 1, 'cow': 2}
|
||||
fake_properties = objects.RequestSpec(ignore_hosts=[],
|
||||
instance_uuid='fake-uuid1',
|
||||
force_hosts=[],
|
||||
force_nodes=[])
|
||||
|
||||
info = {'expected_objs': self.fake_hosts,
|
||||
'expected_fprops': fake_properties}
|
||||
@ -220,7 +223,10 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
|
||||
@mock.patch.object(FakeFilterClass2, '_filter_one', return_value=True)
|
||||
def test_get_filtered_hosts_with_specified_filters(self, mock_filter_one):
|
||||
fake_properties = {'moo': 1, 'cow': 2}
|
||||
fake_properties = objects.RequestSpec(ignore_hosts=[],
|
||||
instance_uuid='fake-uuid1',
|
||||
force_hosts=[],
|
||||
force_nodes=[])
|
||||
|
||||
specified_filters = ['FakeFilterClass1', 'FakeFilterClass2']
|
||||
info = {'expected_objs': self.fake_hosts,
|
||||
@ -232,8 +238,12 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
self._verify_result(info, result)
|
||||
|
||||
def test_get_filtered_hosts_with_ignore(self):
|
||||
fake_properties = {'ignore_hosts': ['fake_host1', 'fake_host3',
|
||||
'fake_host5', 'fake_multihost']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid1',
|
||||
ignore_hosts=['fake_host1', 'fake_host3',
|
||||
'fake_host5', 'fake_multihost'],
|
||||
force_hosts=[],
|
||||
force_nodes=[])
|
||||
|
||||
# [1] and [3] are host2 and host4
|
||||
info = {'expected_objs': [self.fake_hosts[1], self.fake_hosts[3]],
|
||||
@ -245,8 +255,11 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
self._verify_result(info, result)
|
||||
|
||||
def test_get_filtered_hosts_with_force_hosts(self):
|
||||
fake_properties = {'force_hosts': ['fake_host1', 'fake_host3',
|
||||
'fake_host5']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid1',
|
||||
ignore_hosts=[],
|
||||
force_hosts=['fake_host1', 'fake_host3', 'fake_host5'],
|
||||
force_nodes=[])
|
||||
|
||||
# [0] and [2] are host1 and host3
|
||||
info = {'expected_objs': [self.fake_hosts[0], self.fake_hosts[2]],
|
||||
@ -258,7 +271,11 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
self._verify_result(info, result, False)
|
||||
|
||||
def test_get_filtered_hosts_with_no_matching_force_hosts(self):
|
||||
fake_properties = {'force_hosts': ['fake_host5', 'fake_host6']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid1',
|
||||
ignore_hosts=[],
|
||||
force_hosts=['fake_host5', 'fake_host6'],
|
||||
force_nodes=[])
|
||||
|
||||
info = {'expected_objs': [],
|
||||
'expected_fprops': fake_properties}
|
||||
@ -270,8 +287,11 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_ignore_and_force_hosts(self):
|
||||
# Ensure ignore_hosts processed before force_hosts in host filters.
|
||||
fake_properties = {'force_hosts': ['fake_host3', 'fake_host1'],
|
||||
'ignore_hosts': ['fake_host1']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid1',
|
||||
ignore_hosts=['fake_host1'],
|
||||
force_hosts=['fake_host3', 'fake_host1'],
|
||||
force_nodes=[])
|
||||
|
||||
# only fake_host3 should be left.
|
||||
info = {'expected_objs': [self.fake_hosts[2]],
|
||||
@ -284,7 +304,11 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_force_host_and_many_nodes(self):
|
||||
# Ensure all nodes returned for a host with many nodes
|
||||
fake_properties = {'force_hosts': ['fake_multihost']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid1',
|
||||
ignore_hosts=[],
|
||||
force_hosts=['fake_multihost'],
|
||||
force_nodes=[])
|
||||
|
||||
info = {'expected_objs': [self.fake_hosts[4], self.fake_hosts[5],
|
||||
self.fake_hosts[6], self.fake_hosts[7]],
|
||||
@ -296,8 +320,11 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
self._verify_result(info, result, False)
|
||||
|
||||
def test_get_filtered_hosts_with_force_nodes(self):
|
||||
fake_properties = {'force_nodes': ['fake-node2', 'fake-node4',
|
||||
'fake-node9']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid1',
|
||||
ignore_hosts=[],
|
||||
force_hosts=[],
|
||||
force_nodes=['fake-node2', 'fake-node4', 'fake-node9'])
|
||||
|
||||
# [5] is fake-node2, [7] is fake-node4
|
||||
info = {'expected_objs': [self.fake_hosts[5], self.fake_hosts[7]],
|
||||
@ -310,8 +337,11 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_force_hosts_and_nodes(self):
|
||||
# Ensure only overlapping results if both force host and node
|
||||
fake_properties = {'force_hosts': ['fake_host1', 'fake_multihost'],
|
||||
'force_nodes': ['fake-node2', 'fake-node9']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid1',
|
||||
ignore_hosts=[],
|
||||
force_hosts=['fake-host1', 'fake_multihost'],
|
||||
force_nodes=['fake-node2', 'fake-node9'])
|
||||
|
||||
# [5] is fake-node2
|
||||
info = {'expected_objs': [self.fake_hosts[5]],
|
||||
@ -324,8 +354,11 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_force_hosts_and_wrong_nodes(self):
|
||||
# Ensure non-overlapping force_node and force_host yield no result
|
||||
fake_properties = {'force_hosts': ['fake_multihost'],
|
||||
'force_nodes': ['fake-node']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid1',
|
||||
ignore_hosts=[],
|
||||
force_hosts=['fake_multihost'],
|
||||
force_nodes=['fake-node'])
|
||||
|
||||
info = {'expected_objs': [],
|
||||
'expected_fprops': fake_properties}
|
||||
@ -337,8 +370,11 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_ignore_hosts_and_force_nodes(self):
|
||||
# Ensure ignore_hosts can coexist with force_nodes
|
||||
fake_properties = {'force_nodes': ['fake-node4', 'fake-node2'],
|
||||
'ignore_hosts': ['fake_host1', 'fake_host2']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid1',
|
||||
ignore_hosts=['fake_host1', 'fake_host2'],
|
||||
force_hosts=[],
|
||||
force_nodes=['fake-node4', 'fake-node2'])
|
||||
|
||||
info = {'expected_objs': [self.fake_hosts[5], self.fake_hosts[7]],
|
||||
'expected_fprops': fake_properties}
|
||||
@ -350,8 +386,11 @@ class HostManagerTestCase(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_ignore_hosts_and_force_same_nodes(self):
|
||||
# Ensure ignore_hosts is processed before force_nodes
|
||||
fake_properties = {'force_nodes': ['fake_node4', 'fake_node2'],
|
||||
'ignore_hosts': ['fake_multihost']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid1',
|
||||
ignore_hosts=['fake_multihost'],
|
||||
force_hosts=[],
|
||||
force_nodes=['fake_node4', 'fake_node2'])
|
||||
|
||||
info = {'expected_objs': [],
|
||||
'expected_fprops': fake_properties}
|
||||
@ -885,9 +924,9 @@ class HostStateTestCase(test.NoDBTestCase):
|
||||
numa_fit_mock.return_value = fake_numa_topology
|
||||
instance_init_mock.return_value = fake_instance
|
||||
spec_obj = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
flavor=objects.Flavor(root_gb=0, ephemeral_gb=0, memory_mb=0,
|
||||
vcpus=0),
|
||||
uuid='fake-uuid',
|
||||
numa_topology=fake_numa_topology,
|
||||
pci_requests=objects.InstancePCIRequests(requests=[]))
|
||||
host = host_manager.HostState("fakehost", "fakenode")
|
||||
@ -905,9 +944,9 @@ class HostStateTestCase(test.NoDBTestCase):
|
||||
second_numa_topology = objects.InstanceNUMATopology(
|
||||
cells=[objects.InstanceNUMACell()])
|
||||
spec_obj = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
flavor=objects.Flavor(root_gb=0, ephemeral_gb=0, memory_mb=0,
|
||||
vcpus=0),
|
||||
uuid='fake-uuid',
|
||||
numa_topology=second_numa_topology,
|
||||
pci_requests=objects.InstancePCIRequests(requests=[]))
|
||||
second_host_numa_topology = mock.Mock()
|
||||
@ -936,6 +975,7 @@ class HostStateTestCase(test.NoDBTestCase):
|
||||
for r in fake_requests],
|
||||
instance_uuid='fake-uuid')
|
||||
req_spec = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
project_id='12345',
|
||||
numa_topology=inst_topology,
|
||||
pci_requests=fake_requests_obj,
|
||||
@ -968,6 +1008,7 @@ class HostStateTestCase(test.NoDBTestCase):
|
||||
for r in fake_requests],
|
||||
instance_uuid='fake-uuid')
|
||||
req_spec = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
project_id='12345',
|
||||
numa_topology=None,
|
||||
pci_requests=fake_requests_obj,
|
||||
|
@ -329,7 +329,11 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
self.assertEqual(set(info['expected_objs']), set(result))
|
||||
|
||||
def test_get_filtered_hosts(self):
|
||||
fake_properties = {'moo': 1, 'cow': 2}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=[],
|
||||
force_hosts=[],
|
||||
force_nodes=[])
|
||||
|
||||
info = {'expected_objs': self.fake_hosts,
|
||||
'expected_fprops': fake_properties}
|
||||
@ -342,7 +346,11 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
|
||||
@mock.patch.object(FakeFilterClass2, '_filter_one', return_value=True)
|
||||
def test_get_filtered_hosts_with_specified_filters(self, mock_filter_one):
|
||||
fake_properties = {'moo': 1, 'cow': 2}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=[],
|
||||
force_hosts=[],
|
||||
force_nodes=[])
|
||||
|
||||
specified_filters = ['FakeFilterClass1', 'FakeFilterClass2']
|
||||
info = {'expected_objs': self.fake_hosts,
|
||||
@ -354,8 +362,12 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
self._verify_result(info, result)
|
||||
|
||||
def test_get_filtered_hosts_with_ignore(self):
|
||||
fake_properties = {'ignore_hosts': ['fake_host1', 'fake_host3',
|
||||
'fake_host5', 'fake_multihost']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=['fake_host1', 'fake_host3',
|
||||
'fake_host5', 'fake_multihost'],
|
||||
force_hosts=[],
|
||||
force_nodes=[])
|
||||
|
||||
# [1] and [3] are host2 and host4
|
||||
info = {'expected_objs': [self.fake_hosts[1], self.fake_hosts[3]],
|
||||
@ -367,8 +379,11 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
self._verify_result(info, result)
|
||||
|
||||
def test_get_filtered_hosts_with_force_hosts(self):
|
||||
fake_properties = {'force_hosts': ['fake_host1', 'fake_host3',
|
||||
'fake_host5']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=[],
|
||||
force_hosts=['fake_host1', 'fake_host3', 'fake_host5'],
|
||||
force_nodes=[])
|
||||
|
||||
# [0] and [2] are host1 and host3
|
||||
info = {'expected_objs': [self.fake_hosts[0], self.fake_hosts[2]],
|
||||
@ -380,7 +395,11 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
self._verify_result(info, result, False)
|
||||
|
||||
def test_get_filtered_hosts_with_no_matching_force_hosts(self):
|
||||
fake_properties = {'force_hosts': ['fake_host5', 'fake_host6']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=[],
|
||||
force_hosts=['fake_host5', 'fake_host6'],
|
||||
force_nodes=[])
|
||||
|
||||
info = {'expected_objs': [],
|
||||
'expected_fprops': fake_properties}
|
||||
@ -392,8 +411,11 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_ignore_and_force_hosts(self):
|
||||
# Ensure ignore_hosts processed before force_hosts in host filters.
|
||||
fake_properties = {'force_hosts': ['fake_host3', 'fake_host1'],
|
||||
'ignore_hosts': ['fake_host1']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=['fake_host1'],
|
||||
force_hosts=['fake_host3', 'fake_host1'],
|
||||
force_nodes=[])
|
||||
|
||||
# only fake_host3 should be left.
|
||||
info = {'expected_objs': [self.fake_hosts[2]],
|
||||
@ -406,7 +428,11 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_force_host_and_many_nodes(self):
|
||||
# Ensure all nodes returned for a host with many nodes
|
||||
fake_properties = {'force_hosts': ['fake_multihost']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=[],
|
||||
force_hosts=['fake_multihost'],
|
||||
force_nodes=[])
|
||||
|
||||
info = {'expected_objs': [self.fake_hosts[4], self.fake_hosts[5],
|
||||
self.fake_hosts[6], self.fake_hosts[7]],
|
||||
@ -418,8 +444,11 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
self._verify_result(info, result, False)
|
||||
|
||||
def test_get_filtered_hosts_with_force_nodes(self):
|
||||
fake_properties = {'force_nodes': ['fake-node2', 'fake-node4',
|
||||
'fake-node9']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=[],
|
||||
force_hosts=[],
|
||||
force_nodes=['fake-node2', 'fake-node4', 'fake-node9'])
|
||||
|
||||
# [5] is fake-node2, [7] is fake-node4
|
||||
info = {'expected_objs': [self.fake_hosts[5], self.fake_hosts[7]],
|
||||
@ -432,8 +461,11 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_force_hosts_and_nodes(self):
|
||||
# Ensure only overlapping results if both force host and node
|
||||
fake_properties = {'force_hosts': ['fake_host1', 'fake_multihost'],
|
||||
'force_nodes': ['fake-node2', 'fake-node9']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=[],
|
||||
force_hosts=['fake_host1', 'fake_multihost'],
|
||||
force_nodes=['fake-node2', 'fake-node9'])
|
||||
|
||||
# [5] is fake-node2
|
||||
info = {'expected_objs': [self.fake_hosts[5]],
|
||||
@ -446,8 +478,11 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_force_hosts_and_wrong_nodes(self):
|
||||
# Ensure non-overlapping force_node and force_host yield no result
|
||||
fake_properties = {'force_hosts': ['fake_multihost'],
|
||||
'force_nodes': ['fake-node']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=[],
|
||||
force_hosts=['fake_multihost'],
|
||||
force_nodes=['fake-node'])
|
||||
|
||||
info = {'expected_objs': [],
|
||||
'expected_fprops': fake_properties}
|
||||
@ -459,8 +494,11 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_ignore_hosts_and_force_nodes(self):
|
||||
# Ensure ignore_hosts can coexist with force_nodes
|
||||
fake_properties = {'force_nodes': ['fake-node4', 'fake-node2'],
|
||||
'ignore_hosts': ['fake_host1', 'fake_host2']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=['fake_host1', 'fake_host2'],
|
||||
force_hosts=[],
|
||||
force_nodes=['fake-node4', 'fake-node2'])
|
||||
|
||||
info = {'expected_objs': [self.fake_hosts[5], self.fake_hosts[7]],
|
||||
'expected_fprops': fake_properties}
|
||||
@ -472,8 +510,11 @@ class IronicHostManagerTestFilters(test.NoDBTestCase):
|
||||
|
||||
def test_get_filtered_hosts_with_ignore_hosts_and_force_same_nodes(self):
|
||||
# Ensure ignore_hosts is processed before force_nodes
|
||||
fake_properties = {'force_nodes': ['fake_node4', 'fake_node2'],
|
||||
'ignore_hosts': ['fake_multihost']}
|
||||
fake_properties = objects.RequestSpec(
|
||||
instance_uuid='fake-uuid',
|
||||
ignore_hosts=['fake_multihost'],
|
||||
force_hosts=[],
|
||||
force_nodes=['fake_node4', 'fake_node2'])
|
||||
|
||||
info = {'expected_objs': [],
|
||||
'expected_fprops': fake_properties}
|
||||
|
@ -0,0 +1,9 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
Filters internal interface changed using now the RequestSpec NovaObject
|
||||
instead of an old filter_properties dictionary.
|
||||
In case you run out-of-tree filters, you need to modify the host_passes()
|
||||
method to accept a new RequestSpec object and modify the filter internals
|
||||
to use that new object. You can see other in-tree filters for getting the
|
||||
logic or ask for help in #openstack-nova IRC channel.
|
Loading…
x
Reference in New Issue
Block a user