From 87c0602537688c3da2291792a98caf9d9faf9d6c Mon Sep 17 00:00:00 2001 From: Balazs Gibizer Date: Thu, 5 Jan 2023 19:32:13 +0100 Subject: Factor out a mixin class for candidate aware filters blueprint: pci-device-tracking-in-placement Change-Id: Id044131162e582cef41e424aa751e3cd3618ed0c --- nova/scheduler/filters/__init__.py | 41 ++++++++++++++++++++++++ nova/scheduler/filters/numa_topology_filter.py | 40 ++++++++--------------- nova/scheduler/filters/pci_passthrough_filter.py | 33 ++++++------------- 3 files changed, 65 insertions(+), 49 deletions(-) diff --git a/nova/scheduler/filters/__init__.py b/nova/scheduler/filters/__init__.py index 74e24b7bc3..785a13279e 100644 --- a/nova/scheduler/filters/__init__.py +++ b/nova/scheduler/filters/__init__.py @@ -16,8 +16,12 @@ """ Scheduler host filters """ +from oslo_log import log as logging + from nova import filters +LOG = logging.getLogger(__name__) + class BaseHostFilter(filters.BaseFilter): """Base class for host filters.""" @@ -53,6 +57,43 @@ class BaseHostFilter(filters.BaseFilter): raise NotImplementedError() +class CandidateFilterMixin: + """Mixing that helps to implement a Filter that needs to filter host by + Placement allocation candidates. + """ + + def filter_candidates(self, host_state, filter_func): + """Checks still viable allocation candidates by the filter_func and + keep only those that are passing it. + + :param host_state: HostState object holding the list of still viable + allocation candidates + :param filter_func: A callable that takes an allocation candidate and + returns a True like object if the candidate passed the filter or a + False like object if it doesn't. + """ + good_candidates = [] + for candidate in host_state.allocation_candidates: + LOG.debug( + f'{self.__class__.__name__} tries allocation candidate: ' + f'{candidate}', + ) + if filter_func(candidate): + LOG.debug( + f'{self.__class__.__name__} accepted allocation ' + f'candidate: {candidate}', + ) + good_candidates.append(candidate) + else: + LOG.debug( + f'{self.__class__.__name__} rejected allocation ' + f'candidate: {candidate}', + ) + + host_state.allocation_candidates = good_candidates + return good_candidates + + class HostFilterHandler(filters.BaseFilterHandler): def __init__(self): super(HostFilterHandler, self).__init__(BaseHostFilter) diff --git a/nova/scheduler/filters/numa_topology_filter.py b/nova/scheduler/filters/numa_topology_filter.py index 7ec9ca5648..ae50db90e5 100644 --- a/nova/scheduler/filters/numa_topology_filter.py +++ b/nova/scheduler/filters/numa_topology_filter.py @@ -20,7 +20,10 @@ from nova.virt import hardware LOG = logging.getLogger(__name__) -class NUMATopologyFilter(filters.BaseHostFilter): +class NUMATopologyFilter( + filters.BaseHostFilter, + filters.CandidateFilterMixin, +): """Filter on requested NUMA topology.""" # NOTE(sean-k-mooney): In change I0322d872bdff68936033a6f5a54e8296a6fb343 @@ -97,34 +100,19 @@ class NUMATopologyFilter(filters.BaseHostFilter): if network_metadata: limits.network_metadata = network_metadata - good_candidates = [] - for candidate in host_state.allocation_candidates: - LOG.debug( - 'NUMATopologyFilter tries allocation candidate: %s, %s', - candidate, requested_topology - ) - instance_topology = (hardware.numa_fit_instance_to_host( - host_topology, requested_topology, + good_candidates = self.filter_candidates( + host_state, + lambda candidate: hardware.numa_fit_instance_to_host( + host_topology, + requested_topology, limits=limits, pci_requests=pci_requests, pci_stats=host_state.pci_stats, - provider_mapping=candidate['mappings'], - )) - if instance_topology: - LOG.debug( - 'NUMATopologyFilter accepted allocation candidate: %s', - candidate - ) - good_candidates.append(candidate) - else: - LOG.debug( - 'NUMATopologyFilter rejected allocation candidate: %s', - candidate - ) - - host_state.allocation_candidates = good_candidates - - if not host_state.allocation_candidates: + provider_mapping=candidate["mappings"], + ), + ) + + if not good_candidates: LOG.debug("%(host)s, %(node)s fails NUMA topology " "requirements. The instance does not fit on this " "host.", {'host': host_state.host, diff --git a/nova/scheduler/filters/pci_passthrough_filter.py b/nova/scheduler/filters/pci_passthrough_filter.py index 36f0b5901c..992879072a 100644 --- a/nova/scheduler/filters/pci_passthrough_filter.py +++ b/nova/scheduler/filters/pci_passthrough_filter.py @@ -20,7 +20,10 @@ from nova.scheduler import filters LOG = logging.getLogger(__name__) -class PciPassthroughFilter(filters.BaseHostFilter): +class PciPassthroughFilter( + filters.BaseHostFilter, + filters.CandidateFilterMixin, +): """Pci Passthrough Filter based on PCI request Filter that schedules instances on a host if the host has devices @@ -54,28 +57,12 @@ class PciPassthroughFilter(filters.BaseHostFilter): {'host_state': host_state, 'requests': pci_requests}) return False - good_candidates = [] - for candidate in host_state.allocation_candidates: - LOG.debug( - 'PciPassthroughFilter tries allocation candidate: %s', - candidate - ) - if host_state.pci_stats.support_requests( - pci_requests.requests, - provider_mapping=candidate['mappings'] - ): - LOG.debug( - 'PciPassthroughFilter accepted allocation candidate: %s', - candidate - ) - good_candidates.append(candidate) - else: - LOG.debug( - 'PciPassthroughFilter rejected allocation candidate: %s', - candidate - ) - - host_state.allocation_candidates = good_candidates + good_candidates = self.filter_candidates( + host_state, + lambda candidate: host_state.pci_stats.support_requests( + pci_requests.requests, provider_mapping=candidate["mappings"] + ), + ) if not good_candidates: LOG.debug("%(host_state)s doesn't have the required PCI devices" -- cgit v1.2.1