diff options
| author | Jim Fehlig <jfehlig@suse.com> | 2012-08-17 15:26:01 -0600 |
|---|---|---|
| committer | Jim Fehlig <jfehlig@suse.com> | 2012-08-17 22:25:54 -0600 |
| commit | 5ea7db9b7195132df4d8efea0a8e41e4f994b23c (patch) | |
| tree | 78a936dfd62404e5804f9c50962fb682538eff25 /nova | |
| parent | a10be151ad9f62bb916498c8dae42e4b54dfc779 (diff) | |
| download | nova-5ea7db9b7195132df4d8efea0a8e41e4f994b23c.tar.gz nova-5ea7db9b7195132df4d8efea0a8e41e4f994b23c.tar.xz nova-5ea7db9b7195132df4d8efea0a8e41e4f994b23c.zip | |
Introduce ImagePropertiesFilter scheduler filter
Commit d39137fa added functionality to the ComputeFilter to filter on
architecture, hypervisor_type, and vm_mode. The existing ArchFilter
already filtered on architecture. This patch merges the ComputeFilter
functionality introduced in d39137fa with the ArchFilter to create the
ImagePropertiesFilter. The ImagePropertiesFilter uses image properties
specified in the request_spec to filter hosts.
This patch also adds the ImagePropertiesFilter to the list of default
filters specified by the scheduler_default_filters FLAG.
Fixes LP Bug #1037339
DocImpact
Change-Id: Ifa6fccf2db266b0fe3457d58fc81fdb50ffcbc0f
Diffstat (limited to 'nova')
| -rw-r--r-- | nova/scheduler/filters/arch_filter.py | 44 | ||||
| -rw-r--r-- | nova/scheduler/filters/compute_filter.py | 57 | ||||
| -rw-r--r-- | nova/scheduler/filters/image_props_filter.py | 86 | ||||
| -rw-r--r-- | nova/scheduler/host_manager.py | 3 | ||||
| -rw-r--r-- | nova/tests/scheduler/test_host_filters.py | 151 |
5 files changed, 127 insertions, 214 deletions
diff --git a/nova/scheduler/filters/arch_filter.py b/nova/scheduler/filters/arch_filter.py deleted file mode 100644 index 625ce2909..000000000 --- a/nova/scheduler/filters/arch_filter.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) 2011-2012 OpenStack, LLC -# Copyright (c) 2012 Canonical Ltd -# 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 import log as logging -from nova.scheduler import filters -from nova import utils - - -LOG = logging.getLogger(__name__) - - -class ArchFilter(filters.BaseHostFilter): - """Filter out hosts that can not support the guest architecture. - Note: This is supported for libvirt only now. - """ - - def host_passes(self, host_state, filter_properties): - spec = filter_properties.get('request_spec', {}) - props = spec.get('instance_properties', {}) - - cpu_info = host_state.capabilities.get('cpu_info') - permitted_instances = cpu_info.get('permitted_instance_types', None) - - instance_arch = utils.sys_platform_translate(props.get('architecture')) - - if permitted_instances and instance_arch in permitted_instances: - return True - - LOG.warn(_('%(host_state)s fails permitted_instance_types'), locals()) - return False diff --git a/nova/scheduler/filters/compute_filter.py b/nova/scheduler/filters/compute_filter.py index c0ee98762..2d7c898d6 100644 --- a/nova/scheduler/filters/compute_filter.py +++ b/nova/scheduler/filters/compute_filter.py @@ -22,59 +22,10 @@ LOG = logging.getLogger(__name__) class ComputeFilter(filters.BaseHostFilter): - """Filter on active Compute nodes that satisfy the instance properties""" - - def _instance_supported(self, capabilities, instance_meta): - """Check if the instance is supported by the hypervisor. - - The instance may specify an architecture, hypervisor, and - vm_mode, e.g. (x86_64, kvm, hvm). - """ - inst_arch = instance_meta.get('image_architecture', None) - inst_h_type = instance_meta.get('image_hypervisor_type', None) - inst_vm_mode = instance_meta.get('image_vm_mode', None) - inst_props_req = (inst_arch, inst_h_type, inst_vm_mode) - - # Supported if no compute-related instance properties are specified - if not any(inst_props_req): - return True - - supp_instances = capabilities.get('supported_instances', None) - # Not supported if an instance property is requested but nothing - # advertised by the host. - if not supp_instances: - LOG.debug(_("Instance contains properties %(instance_meta)s, " - "but no corresponding capabilities are advertised " - "by the compute node"), locals()) - return False - - def _compare_props(props, other_props): - for i in props: - if i and i not in other_props: - return False - return True - - for supp_inst in supp_instances: - if _compare_props(inst_props_req, supp_inst): - LOG.debug(_("Instance properties %(instance_meta)s " - "are satisfied by compute host capabilities " - "%(capabilities)s"), locals()) - return True - - LOG.debug(_("Instance contains properties %(instance_meta)s " - "that are not provided by the compute node " - "capabilities %(capabilities)s"), locals()) - return False + """Filter on active Compute nodes""" def host_passes(self, host_state, filter_properties): - """Check if host passes instance compute properties. - - Returns True for active compute nodes that satisfy - the compute properties specified in the instance. - """ - spec = filter_properties.get('request_spec', {}) - instance_props = spec.get('instance_properties', {}) - instance_meta = instance_props.get('system_metadata', {}) + """Returns True for only active compute nodes""" instance_type = filter_properties.get('instance_type') if host_state.topic != 'compute' or not instance_type: return True @@ -89,8 +40,4 @@ class ComputeFilter(filters.BaseHostFilter): LOG.debug(_("%(host_state)s is disabled via capabilities"), locals()) return False - if not self._instance_supported(capabilities, instance_meta): - LOG.debug(_("%(host_state)s does not support requested " - "instance_properties"), locals()) - return False return True diff --git a/nova/scheduler/filters/image_props_filter.py b/nova/scheduler/filters/image_props_filter.py new file mode 100644 index 000000000..5eb710882 --- /dev/null +++ b/nova/scheduler/filters/image_props_filter.py @@ -0,0 +1,86 @@ +# Copyright (c) 2011-2012 OpenStack, LLC +# Copyright (c) 2012 Canonical Ltd +# Copyright (c) 2012 SUSE LINUX Products GmbH +# 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 import log as logging +from nova.scheduler import filters +from nova import utils + + +LOG = logging.getLogger(__name__) + + +class ImagePropertiesFilter(filters.BaseHostFilter): + """Filter compute nodes that satisfy instance image properties. + + The ImagePropertiesFilter filters compute nodes that satisfy + any architecture, hpervisor type, or virtual machine mode properties + specified on the instance's image properties. Image properties are + contained in the image dictionary in the request_spec. + """ + + def _instance_supported(self, capabilities, image_props): + img_arch = image_props.get('architecture', None) + img_h_type = image_props.get('hypervisor_type', None) + img_vm_mode = image_props.get('vm_mode', None) + checked_img_props = (img_arch, img_h_type, img_vm_mode) + + # Supported if no compute-related instance properties are specified + if not any(checked_img_props): + return True + + supp_instances = capabilities.get('supported_instances', None) + # Not supported if an instance property is requested but nothing + # advertised by the host. + if not supp_instances: + LOG.debug(_("Instance contains properties %(image_props)s, " + "but no corresponding capabilities are advertised " + "by the compute node"), locals()) + return False + + def _compare_props(props, other_props): + for i in props: + if i and i not in other_props: + return False + return True + + for supp_inst in supp_instances: + if _compare_props(checked_img_props, supp_inst): + LOG.debug(_("Instance properties %(image_props)s " + "are satisfied by compute host capabilities " + "%(capabilities)s"), locals()) + return True + + LOG.debug(_("Instance contains properties %(image_props)s " + "that are not provided by the compute node " + "capabilities %(capabilities)s"), locals()) + return False + + def host_passes(self, host_state, filter_properties): + """Check if host passes specified image properties. + + Returns True for compute nodes that satisfy image properties + contained in the request_spec. + """ + spec = filter_properties.get('request_spec', {}) + image_props = spec.get('image', {}).get('properties', {}) + capabilities = host_state.capabilities + + if not self._instance_supported(capabilities, image_props): + LOG.debug(_("%(host_state)s does not support requested " + "instance_properties"), locals()) + return False + return True diff --git a/nova/scheduler/host_manager.py b/nova/scheduler/host_manager.py index 0403dffdf..f459df165 100644 --- a/nova/scheduler/host_manager.py +++ b/nova/scheduler/host_manager.py @@ -47,7 +47,8 @@ host_manager_opts = [ 'AvailabilityZoneFilter', 'RamFilter', 'ComputeFilter', - 'ComputeCapabilitiesFilter' + 'ComputeCapabilitiesFilter', + 'ImagePropertiesFilter' ], help='Which filter class names to use for filtering hosts ' 'when not specified in the request.'), diff --git a/nova/tests/scheduler/test_host_filters.py b/nova/tests/scheduler/test_host_filters.py index d6f083576..e49cf925a 100644 --- a/nova/tests/scheduler/test_host_filters.py +++ b/nova/tests/scheduler/test_host_filters.py @@ -394,104 +394,81 @@ class HostFiltersTestCase(test.TestCase): 'service': service}) self.assertTrue(filt_cls.host_passes(host, filter_properties)) - def test_compute_filter_passes_same_inst_props(self): + def test_image_properties_filter_passes_same_inst_props(self): self._stub_service_is_up(True) - filt_cls = self.class_map['ComputeFilter']() - inst_meta = {'system_metadata': {'image_architecture': 'x86_64', - 'image_hypervisor_type': 'kvm', - 'image_vm_mode': 'hvm'}} - req_spec = {'instance_properties': inst_meta} - filter_properties = {'instance_type': {'memory_mb': 1024}, - 'request_spec': req_spec} + filt_cls = self.class_map['ImagePropertiesFilter']() + img_props = {'properties': {'_architecture': 'x86_64', + 'hypervisor_type': 'kvm', + 'vm_mode': 'hvm'}} + filter_properties = {'request_spec': {'image': img_props}} capabilities = {'enabled': True, 'supported_instances': [ ('x86_64', 'kvm', 'hvm')]} - service = {'disabled': False} host = fakes.FakeHostState('host1', 'compute', - {'free_ram_mb': 1024, 'capabilities': capabilities, - 'service': service}) + {'capabilities': capabilities}) self.assertTrue(filt_cls.host_passes(host, filter_properties)) - def test_compute_filter_fails_different_inst_props(self): + def test_image_properties_filter_fails_different_inst_props(self): self._stub_service_is_up(True) - filt_cls = self.class_map['ComputeFilter']() - inst_meta = {'system_metadata': {'image_architecture': 'arm', - 'image_hypervisor_type': 'qemu', - 'image_vm_mode': 'hvm'}} - req_spec = {'instance_properties': inst_meta} - filter_properties = {'instance_type': {'memory_mb': 1024}, - 'request_spec': req_spec} + filt_cls = self.class_map['ImagePropertiesFilter']() + img_props = {'properties': {'architecture': 'arm', + 'hypervisor_type': 'qemu', + 'vm_mode': 'hvm'}} + filter_properties = {'request_spec': {'image': img_props}} capabilities = {'enabled': True, 'supported_instances': [ ('x86_64', 'kvm', 'hvm')]} - service = {'disabled': False} host = fakes.FakeHostState('host1', 'compute', - {'free_ram_mb': 1024, 'capabilities': capabilities, - 'service': service}) + {'capabilities': capabilities}) self.assertFalse(filt_cls.host_passes(host, filter_properties)) - def test_compute_filter_passes_partial_inst_props(self): + def test_image_properties_filter_passes_partial_inst_props(self): self._stub_service_is_up(True) - filt_cls = self.class_map['ComputeFilter']() - inst_meta = {'system_metadata': {'image_architecture': 'x86_64', - 'image_vm_mode': 'hvm'}} - req_spec = {'instance_properties': inst_meta} - filter_properties = {'instance_type': {'memory_mb': 1024}, - 'request_spec': req_spec} + filt_cls = self.class_map['ImagePropertiesFilter']() + img_props = {'properties': {'architecture': 'x86_64', + 'vm_mode': 'hvm'}} + filter_properties = {'request_spec': {'image': img_props}} capabilities = {'enabled': True, 'supported_instances': [ ('x86_64', 'kvm', 'hvm')]} - service = {'disabled': False} host = fakes.FakeHostState('host1', 'compute', - {'free_ram_mb': 1024, 'capabilities': capabilities, - 'service': service}) + {'capabilities': capabilities}) self.assertTrue(filt_cls.host_passes(host, filter_properties)) - def test_compute_filter_fails_partial_inst_props(self): + def test_image_properties_filter_fails_partial_inst_props(self): self._stub_service_is_up(True) - filt_cls = self.class_map['ComputeFilter']() - inst_meta = {'system_metadata': {'image_architecture': 'x86_64', - 'image_vm_mode': 'hvm'}} - req_spec = {'instance_properties': inst_meta} - filter_properties = {'instance_type': {'memory_mb': 1024}, - 'request_spec': req_spec} + filt_cls = self.class_map['ImagePropertiesFilter']() + img_props = {'properties': {'architecture': 'x86_64', + 'vm_mode': 'hvm'}} + filter_properties = {'request_spec': {'image': img_props}} capabilities = {'enabled': True, 'supported_instances': [ ('x86_64', 'xen', 'xen')]} - service = {'disabled': False} host = fakes.FakeHostState('host1', 'compute', - {'free_ram_mb': 1024, 'capabilities': capabilities, - 'service': service}) + {'capabilities': capabilities}) self.assertFalse(filt_cls.host_passes(host, filter_properties)) - def test_compute_filter_passes_without_inst_props(self): + def test_image_properties_filter_passes_without_inst_props(self): self._stub_service_is_up(True) - filt_cls = self.class_map['ComputeFilter']() - filter_properties = {'instance_type': {'memory_mb': 1024}, - 'request_spec': {}} + filt_cls = self.class_map['ImagePropertiesFilter']() + filter_properties = {'request_spec': {}} capabilities = {'enabled': True, 'supported_instances': [ ('x86_64', 'kvm', 'hvm')]} - service = {'disabled': False} host = fakes.FakeHostState('host1', 'compute', - {'free_ram_mb': 1024, 'capabilities': capabilities, - 'service': service}) + {'capabilities': capabilities}) self.assertTrue(filt_cls.host_passes(host, filter_properties)) - def test_compute_filter_fails_without_host_props(self): + def test_image_properties_filter_fails_without_host_props(self): self._stub_service_is_up(True) - filt_cls = self.class_map['ComputeFilter']() - inst_meta = {'system_metadata': {'image_architecture': 'x86_64', - 'image_hypervisor_type': 'kvm', - 'image_vm_mode': 'hvm'}} - req_spec = {'instance_properties': inst_meta} - filter_properties = {'instance_type': {'memory_mb': 1024}, - 'request_spec': req_spec} + filt_cls = self.class_map['ImagePropertiesFilter']() + img_props = {'properties': {'architecture': 'x86_64', + 'hypervisor_type': 'kvm', + 'vm_mode': 'hvm'}} + filter_properties = {'request_spec': {'image': img_props}} capabilities = {'enabled': True} - service = {'disabled': False} host = fakes.FakeHostState('host1', 'compute', - {'free_ram_mb': 1024, 'capabilities': capabilities, - 'service': service}) + {'capabilities': capabilities}) self.assertFalse(filt_cls.host_passes(host, filter_properties)) def _do_test_compute_filter_extra_specs(self, ecaps, especs, passes): @@ -1214,60 +1191,6 @@ class HostFiltersTestCase(test.TestCase): host = fakes.FakeHostState('host1', 'compute', {'service': service}) self.assertFalse(filt_cls.host_passes(host, request)) - def test_arch_filter_same(self): - permitted_instances = ['x86_64'] - filt_cls = self.class_map['ArchFilter']() - filter_properties = { - 'request_spec': { - 'instance_properties': {'architecture': 'x86_64'} - } - } - capabilities = {'enabled': True, - 'cpu_info': { - 'permitted_instance_types': permitted_instances - } - } - service = {'disabled': False} - host = fakes.FakeHostState('host1', 'compute', - {'capabilities': capabilities, 'service': service}) - self.assertTrue(filt_cls.host_passes(host, filter_properties)) - - def test_arch_filter_different(self): - permitted_instances = ['arm'] - filt_cls = self.class_map['ArchFilter']() - filter_properties = { - 'request_spec': { - 'instance_properties': {'architecture': 'x86_64'} - } - } - capabilities = {'enabled': True, - 'cpu_info': { - 'permitted_instance_types': permitted_instances - } - } - service = {'disabled': False} - host = fakes.FakeHostState('host1', 'compute', - {'capabilities': capabilities, 'service': service}) - self.assertFalse(filt_cls.host_passes(host, filter_properties)) - - def test_arch_filter_without_permitted_instances(self): - permitted_instances = [] - filt_cls = self.class_map['ArchFilter']() - filter_properties = { - 'request_spec': { - 'instance_properties': {'architecture': 'x86_64'} - } - } - capabilities = {'enabled': True, - 'cpu_info': { - 'permitted_instance_types': permitted_instances - } - } - service = {'disabled': False} - host = fakes.FakeHostState('host1', 'compute', - {'capabilities': capabilities, 'service': service}) - self.assertFalse(filt_cls.host_passes(host, filter_properties)) - def test_retry_filter_disabled(self): """Test case where retry/re-scheduling is disabled""" filt_cls = self.class_map['RetryFilter']() |
