summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-08-22 07:02:45 +0000
committerGerrit Code Review <review@openstack.org>2012-08-22 07:02:45 +0000
commitb090bdd0887317bb4f1f2a8ecec577b16fb94363 (patch)
treeeddf432cbc8beb1873d27c698424013f9aa9501c
parent962efab370f168bb077447eeb15d43063c8b2272 (diff)
parent5ea7db9b7195132df4d8efea0a8e41e4f994b23c (diff)
downloadnova-b090bdd0887317bb4f1f2a8ecec577b16fb94363.tar.gz
nova-b090bdd0887317bb4f1f2a8ecec577b16fb94363.tar.xz
nova-b090bdd0887317bb4f1f2a8ecec577b16fb94363.zip
Merge "Introduce ImagePropertiesFilter scheduler filter"
-rw-r--r--doc/source/devref/filter_scheduler.rst27
-rw-r--r--etc/nova/nova.conf.sample2
-rw-r--r--nova/scheduler/filters/arch_filter.py44
-rw-r--r--nova/scheduler/filters/compute_filter.py57
-rw-r--r--nova/scheduler/filters/image_props_filter.py86
-rw-r--r--nova/scheduler/host_manager.py3
-rw-r--r--nova/tests/scheduler/test_host_filters.py151
7 files changed, 146 insertions, 224 deletions
diff --git a/doc/source/devref/filter_scheduler.rst b/doc/source/devref/filter_scheduler.rst
index d6ceb08ef..807fdceec 100644
--- a/doc/source/devref/filter_scheduler.rst
+++ b/doc/source/devref/filter_scheduler.rst
@@ -27,8 +27,9 @@ There are some standard filter classes to use (:mod:`nova.scheduler.filters`):
* |AllHostsFilter| - frankly speaking, this filter does no operation. It
passes all the available hosts.
-* |ArchFilter| - filters hosts based on architecture. It passes hosts
- that can support the architecture specified in the instance properties.
+* |ImagePropertiesFilter| - filters hosts based on properties defined
+ on the instance's image. It passes hosts that can support the specified
+ image properties contained in the instance.
* |AvailabilityZoneFilter| - filters hosts by availability zone. It passes
hosts matching the availability zone specfied in the instance properties.
* |ComputeCapabilityFilter| - checks that the capabilities provided by the
@@ -86,10 +87,17 @@ scheduler with availability zones support and can configure availability zones
on each compute host. This classes method `host_passes` returns `True` if
availability zone mentioned in request is the same on the current compute host.
-The |ArchFilter| filters hosts based on the architecture specified in the
-instance properties. E.g., an instance might require a host that supports
-the arm architecture. The |ArchFilter| will only pass hosts that can
-support the architecture requested by the instance.
+The |ImagePropertiesFilter| filters hosts based on the architecture,
+hypervisor type, and virtual machine mode specified in the
+instance. E.g., an instance might require a host that supports the arm
+architecture on a qemu compute host. The |ImagePropertiesFilter| will only
+pass hosts that can statisfy this request. These instance
+properties are populated from properties define on the instance's image.
+E.g. an image can be decorated with these properties using
+`glance image-update img-uuid --property architecture=arm --property
+hypervisor_type=qemu`
+Only hosts that statify these requirements will pass the
+|ImagePropertiesFilter|.
|ComputeCapabilitesFilter| checks if the host satisfies any 'extra specs'
specfied on the instance type. The 'extra specs' can contain key/value pairs,
@@ -160,11 +168,12 @@ The default values for these settings in nova.conf are:
::
--scheduler_available_filters=nova.scheduler.filters.standard_filters
- --scheduler_default_filters=RamFilter,ComputeFilter,AvailabilityZoneFilter,ComputeCapabilityFilter
+ --scheduler_default_filters=RamFilter,ComputeFilter,AvailabilityZoneFilter,ComputeCapabilityFilter,ImagePropertiesFilter
With this configuration, all filters in `nova.scheduler.filters`
would be available, and by default the |RamFilter|, |ComputeFilter|,
-|AvailabilityZoneFilter|, and |ComputeCapabilityFilter| would be used.
+|AvailabilityZoneFilter|, |ComputeCapabilityFilter|, and
+|ImagePropertiesFilter| would be used.
If you want to create **your own filter** you just need to inherit from
|BaseHostFilter| and implement one method:
@@ -278,7 +287,7 @@ P.S.: you can find more examples of using Filter Scheduler and standard filters
in :mod:`nova.tests.scheduler`.
.. |AllHostsFilter| replace:: :class:`AllHostsFilter <nova.scheduler.filters.all_hosts_filter.AllHostsFilter>`
-.. |ArchFilter| replace:: :class:`ArchFilter <nova.scheduler.filters.arch_filter.ArchFilter>`
+.. |ImagePropertiesFilter| replace:: :class:`ImagePropertiesFilter <nova.scheduler.filters.image_props_filter.ImagePropertiesFilter>`
.. |AvailabilityZoneFilter| replace:: :class:`AvailabilityZoneFilter <nova.scheduler.filters.availability_zone_filter.AvailabilityZoneFilter>`
.. |BaseHostFilter| replace:: :class:`BaseHostFilter <nova.scheduler.filters.BaseHostFilter>`
.. |ComputeCapabilitiesFilter| replace:: :class:`ComputeCapabilitiesFilter <nova.scheduler.filters.compute_capabilities_filter.ComputeCapabilitiesFilter>`
diff --git a/etc/nova/nova.conf.sample b/etc/nova/nova.conf.sample
index 32f33e557..178ed5830 100644
--- a/etc/nova/nova.conf.sample
+++ b/etc/nova/nova.conf.sample
@@ -1208,7 +1208,7 @@
#### "nova.scheduler.filters.standard_filters" maps to all
#### filters included with nova.
-# scheduler_default_filters=AvailabilityZoneFilter,RamFilter,ComputeFilter,ComputeCapabilitiesFilter
+# scheduler_default_filters=AvailabilityZoneFilter,RamFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter
#### (ListOpt) Which filter class names to use for filtering hosts when not
#### specified in the request.
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 f373a2ef3..33ba2c160 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 5e42fed6f..49486162a 100644
--- a/nova/tests/scheduler/test_host_filters.py
+++ b/nova/tests/scheduler/test_host_filters.py
@@ -412,104 +412,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):
@@ -1256,60 +1233,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']()