From a7a16dc44efcabd8f9ac042c432f6594cffabe20 Mon Sep 17 00:00:00 2001 From: Rohan Kanade Date: Fri, 28 Mar 2014 13:46:55 +0100 Subject: [PATCH] Adds exact match filters to nova scheduler Add exact match ram, disk, core filters which will match exact values of requested metrics, this is required for Baremetal/Ironic instance filtering. Unit tests have been proposed to nova at https://review.openstack.org/#/c/83728 Change-Id: I20faa1c17f4121429bbbea80e59b168095909b48 Closes-Bug: #1291396 --- .../scheduler/filters/exact_core_filter.py | 50 +++++++++++++++++++ .../scheduler/filters/exact_disk_filter.py | 41 +++++++++++++++ .../scheduler/filters/exact_ram_filter.py | 37 ++++++++++++++ ironic/nova/scheduler/ironic_host_manager.py | 28 +++++++++++ 4 files changed, 156 insertions(+) create mode 100644 ironic/nova/scheduler/filters/exact_core_filter.py create mode 100644 ironic/nova/scheduler/filters/exact_disk_filter.py create mode 100644 ironic/nova/scheduler/filters/exact_ram_filter.py diff --git a/ironic/nova/scheduler/filters/exact_core_filter.py b/ironic/nova/scheduler/filters/exact_core_filter.py new file mode 100644 index 0000000000..c3ca29228d --- /dev/null +++ b/ironic/nova/scheduler/filters/exact_core_filter.py @@ -0,0 +1,50 @@ +# Copyright (c) 2014 OpenStack Foundation +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +from nova.openstack.common.gettextutils import _ +from nova.openstack.common import log as logging +from nova.scheduler import filters + +LOG = logging.getLogger(__name__) + + +class ExactCoreFilter(filters.BaseHostFilter): + + def host_passes(self, host_state, filter_properties): + """Return True if host has sufficient CPU cores.""" + instance_type = filter_properties.get('instance_type') + if not instance_type: + return True + + if not host_state.vcpus_total: + # Fail safe + LOG.warning(_("VCPUs not set; assuming CPU collection broken")) + return True + + required_vcpus = instance_type['vcpus'] + usable_vcpus = host_state.vcpus_total - host_state.vcpus_used + + if required_vcpus != usable_vcpus: + LOG.debug(_("%(host_state)s does not have %(requested_vcpus)s " + "cores of usable vcpu, it only has %(usable_vcpus)s " + "cores of usable vcpu."), + {'host_state': host_state, + 'requested_vcpus': required_vcpus, + 'usable_vcpus': usable_vcpus}) + return False + + return True diff --git a/ironic/nova/scheduler/filters/exact_disk_filter.py b/ironic/nova/scheduler/filters/exact_disk_filter.py new file mode 100644 index 0000000000..5dd2568017 --- /dev/null +++ b/ironic/nova/scheduler/filters/exact_disk_filter.py @@ -0,0 +1,41 @@ +# Copyright (c) 2014 OpenStack Foundation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from nova.openstack.common.gettextutils import _ +from nova.openstack.common import log as logging +from nova.scheduler import filters + +LOG = logging.getLogger(__name__) + + +class ExactDiskFilter(filters.BaseHostFilter): + """Exact Disk Filter.""" + + def host_passes(self, host_state, filter_properties): + """Filter based on disk usage.""" + instance_type = filter_properties.get('instance_type') + requested_disk = (1024 * (instance_type['root_gb'] + + instance_type['ephemeral_gb']) + + instance_type['swap']) + + if requested_disk != host_state.free_disk_mb: + LOG.debug(_("%(host_state)s does not have %(requested_disk)s MB " + "usable disk, it only has %(usable_disk_mb)s MB usable " + "disk."), {'host_state': host_state, + 'requested_disk': requested_disk, + 'usable_disk_mb': host_state.free_disk_mb}) + return False + + return True diff --git a/ironic/nova/scheduler/filters/exact_ram_filter.py b/ironic/nova/scheduler/filters/exact_ram_filter.py new file mode 100644 index 0000000000..47be299017 --- /dev/null +++ b/ironic/nova/scheduler/filters/exact_ram_filter.py @@ -0,0 +1,37 @@ +# Copyright (c) 2014 OpenStack Foundation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from nova.openstack.common.gettextutils import _ +from nova.openstack.common import log as logging +from nova.scheduler import filters + +LOG = logging.getLogger(__name__) + + +class ExactRamFilter(filters.BaseHostFilter): + + def host_passes(self, host_state, filter_properties): + """Only return hosts with sufficient available RAM.""" + instance_type = filter_properties.get('instance_type') + requested_ram = instance_type['memory_mb'] + if requested_ram != host_state.free_ram_mb: + LOG.debug(_("%(host_state)s does not have %(requested_ram)s MB " + "usable ram, it only has %(usable_ram)s MB usable ram."), + {'host_state': host_state, + 'requested_ram': requested_ram, + 'usable_ram': host_state.free_ram_mb}) + return False + + return True diff --git a/ironic/nova/scheduler/ironic_host_manager.py b/ironic/nova/scheduler/ironic_host_manager.py index b9bba07ba8..c855f8370e 100644 --- a/ironic/nova/scheduler/ironic_host_manager.py +++ b/ironic/nova/scheduler/ironic_host_manager.py @@ -20,10 +20,35 @@ This host manager will consume all cpu's, disk space, and ram from a host / node as it is supporting Baremetal hosts, which can not be subdivided into multiple instances. """ +from oslo.config import cfg from nova.openstack.common import log as logging from nova.scheduler import host_manager +host_manager_opts = [ + cfg.ListOpt('baremetal_scheduler_default_filters', + default=[ + 'RetryFilter', + 'AvailabilityZoneFilter', + 'ComputeFilter', + 'ComputeCapabilitiesFilter', + 'ImagePropertiesFilter', + 'ExactRamFilter', + 'ExactDiskFilter', + 'ExactCoreFilter', + ], + help='Which filter class names to use for filtering ' + 'baremetal hosts when not specified in the request.'), + cfg.BoolOpt('scheduler_use_baremetal_filters', + default=False, + help='Flag to decide whether to use ' + 'baremetal_scheduler_default_filters or not.'), + + ] + +CONF = cfg.CONF +CONF.register_opts(host_manager_opts) + LOG = logging.getLogger(__name__) @@ -76,3 +101,6 @@ class IronicHostManager(host_manager.HostManager): def __init__(self): super(IronicHostManager, self).__init__() + if CONF.scheduler_use_baremetal_filters: + baremetal_default = CONF.baremetal_scheduler_default_filters + CONF.scheduler_default_filters = baremetal_default