diff --git a/nova/conf/scheduler.py b/nova/conf/scheduler.py index a36425e5c16e..401e7606cb50 100644 --- a/nova/conf/scheduler.py +++ b/nova/conf/scheduler.py @@ -15,6 +15,8 @@ from oslo_config import cfg +from nova.virt import arch + scheduler_group = cfg.OptGroup(name="scheduler", title="Scheduler configuration") @@ -572,6 +574,21 @@ In such case enabling this option will reduce contention and chances for rescheduling events. At the same time it will make the instance packing (even in unweighed case) less dense. +"""), + cfg.StrOpt( + "image_properties_default_architecture", + choices=arch.ALL, + help=""" +The default architecture to be used when using the image properties filter. + +When using the ImagePropertiesFilter, it is possible that you want to define +a default architecture to make the user experience easier and avoid having +something like x86_64 images landing on aarch64 compute nodes because the +user did not specify the 'hw_architecture' property in Glance. + +Possible values: + +* CPU Architectures such as x86_64, aarch64, s390x. """), # TODO(mikal): replace this option with something involving host aggregates cfg.ListOpt("isolated_images", diff --git a/nova/objects/fields.py b/nova/objects/fields.py index b19422edfec9..ab9e8ec69037 100644 --- a/nova/objects/fields.py +++ b/nova/objects/fields.py @@ -22,6 +22,7 @@ import six from nova import exception from nova.i18n import _ from nova.network import model as network_model +from nova.virt import arch # Import field errors from oslo.versionedobjects @@ -103,56 +104,48 @@ class Architecture(BaseNovaEnum): ever adding new ones then ensure it matches libvirt's expectation. """ - ALPHA = 'alpha' - ARMV6 = 'armv6' - ARMV7 = 'armv7l' - ARMV7B = 'armv7b' + ALPHA = arch.ALPHA + ARMV6 = arch.ARMV6 + ARMV7 = arch.ARMV7 + ARMV7B = arch.ARMV7B - AARCH64 = 'aarch64' - CRIS = 'cris' - I686 = 'i686' - IA64 = 'ia64' - LM32 = 'lm32' + AARCH64 = arch.AARCH64 + CRIS = arch.CRIS + I686 = arch.I686 + IA64 = arch.IA64 + LM32 = arch.LM32 - M68K = 'm68k' - MICROBLAZE = 'microblaze' - MICROBLAZEEL = 'microblazeel' - MIPS = 'mips' - MIPSEL = 'mipsel' + M68K = arch.M68K + MICROBLAZE = arch.MICROBLAZE + MICROBLAZEEL = arch.MICROBLAZEEL + MIPS = arch.MIPS + MIPSEL = arch.MIPSEL - MIPS64 = 'mips64' - MIPS64EL = 'mips64el' - OPENRISC = 'openrisc' - PARISC = 'parisc' - PARISC64 = 'parisc64' + MIPS64 = arch.MIPS64 + MIPS64EL = arch.MIPS64EL + OPENRISC = arch.OPENRISC + PARISC = arch.PARISC + PARISC64 = arch.PARISC64 - PPC = 'ppc' - PPCLE = 'ppcle' - PPC64 = 'ppc64' - PPC64LE = 'ppc64le' - PPCEMB = 'ppcemb' + PPC = arch.PPC + PPCLE = arch.PPCLE + PPC64 = arch.PPC64 + PPC64LE = arch.PPC64LE + PPCEMB = arch.PPCEMB - S390 = 's390' - S390X = 's390x' - SH4 = 'sh4' - SH4EB = 'sh4eb' - SPARC = 'sparc' + S390 = arch.S390 + S390X = arch.S390X + SH4 = arch.SH4 + SH4EB = arch.SH4EB + SPARC = arch.SPARC - SPARC64 = 'sparc64' - UNICORE32 = 'unicore32' - X86_64 = 'x86_64' - XTENSA = 'xtensa' - XTENSAEB = 'xtensaeb' + SPARC64 = arch.SPARC64 + UNICORE32 = arch.UNICORE32 + X86_64 = arch.X86_64 + XTENSA = arch.XTENSA + XTENSAEB = arch.XTENSAEB - ALL = ( - ALPHA, ARMV6, ARMV7, ARMV7B, - AARCH64, CRIS, I686, IA64, LM32, - M68K, MICROBLAZE, MICROBLAZEEL, MIPS, MIPSEL, - MIPS64, MIPS64EL, OPENRISC, PARISC, PARISC64, - PPC, PPCLE, PPC64, PPC64LE, PPCEMB, - S390, S390X, SH4, SH4EB, SPARC, - SPARC64, UNICORE32, X86_64, XTENSA, XTENSAEB, - ) + ALL = arch.ALL @classmethod def from_host(cls): diff --git a/nova/scheduler/filters/image_props_filter.py b/nova/scheduler/filters/image_props_filter.py index f6977dffb244..bf60a9f90081 100644 --- a/nova/scheduler/filters/image_props_filter.py +++ b/nova/scheduler/filters/image_props_filter.py @@ -19,12 +19,15 @@ from distutils import versionpredicate from oslo_log import log as logging from oslo_utils import versionutils +import nova.conf from nova.objects import fields from nova.scheduler import filters LOG = logging.getLogger(__name__) +CONF = nova.conf.CONF + class ImagePropertiesFilter(filters.BaseHostFilter): """Filter compute nodes that satisfy instance image properties. @@ -41,9 +44,14 @@ class ImagePropertiesFilter(filters.BaseHostFilter): # a request run_filter_once_per_request = True + def _get_default_architecture(self): + return CONF.filter_scheduler.image_properties_default_architecture + def _instance_supported(self, host_state, image_props, hypervisor_version): - img_arch = image_props.get('hw_architecture') + default_img_arch = self._get_default_architecture() + + img_arch = image_props.get('hw_architecture', default_img_arch) img_h_type = image_props.get('img_hv_type') img_vm_mode = image_props.get('hw_vm_mode') checked_img_props = ( diff --git a/nova/tests/unit/scheduler/filters/test_image_props_filters.py b/nova/tests/unit/scheduler/filters/test_image_props_filters.py index 18a4346b61ef..da7a3a8cd0be 100644 --- a/nova/tests/unit/scheduler/filters/test_image_props_filters.py +++ b/nova/tests/unit/scheduler/filters/test_image_props_filters.py @@ -43,6 +43,21 @@ class TestImagePropsFilter(test.NoDBTestCase): host = fakes.FakeHostState('host1', 'node1', capabilities) self.assertTrue(self.filt_cls.host_passes(host, spec_obj)) + def test_image_properties_filter_uses_default_conf_value(self): + self.flags(image_properties_default_architecture='x86_64', + group='filter_scheduler') + img_props = objects.ImageMeta(properties=objects.ImageMetaProps()) + hypervisor_version = versionutils.convert_version_to_int('6.0.0') + spec_obj = objects.RequestSpec(image=img_props) + capabilities = { + 'supported_instances': [( + obj_fields.Architecture.AARCH64, + obj_fields.HVType.KVM, + obj_fields.VMMode.HVM)], + 'hypervisor_version': hypervisor_version} + host = fakes.FakeHostState('host1', 'node1', capabilities) + self.assertFalse(self.filt_cls.host_passes(host, spec_obj)) + def test_image_properties_filter_fails_different_inst_props(self): img_props = objects.ImageMeta( properties=objects.ImageMetaProps( diff --git a/nova/virt/arch.py b/nova/virt/arch.py new file mode 100644 index 000000000000..7518ab9ab333 --- /dev/null +++ b/nova/virt/arch.py @@ -0,0 +1,65 @@ +# Copyright 2018 VEXXHOST, Inc. +# 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. + +ALPHA = 'alpha' +ARMV6 = 'armv6' +ARMV7 = 'armv7l' +ARMV7B = 'armv7b' + +AARCH64 = 'aarch64' +CRIS = 'cris' +I686 = 'i686' +IA64 = 'ia64' +LM32 = 'lm32' + +M68K = 'm68k' +MICROBLAZE = 'microblaze' +MICROBLAZEEL = 'microblazeel' +MIPS = 'mips' +MIPSEL = 'mipsel' + +MIPS64 = 'mips64' +MIPS64EL = 'mips64el' +OPENRISC = 'openrisc' +PARISC = 'parisc' +PARISC64 = 'parisc64' + +PPC = 'ppc' +PPCLE = 'ppcle' +PPC64 = 'ppc64' +PPC64LE = 'ppc64le' +PPCEMB = 'ppcemb' + +S390 = 's390' +S390X = 's390x' +SH4 = 'sh4' +SH4EB = 'sh4eb' +SPARC = 'sparc' + +SPARC64 = 'sparc64' +UNICORE32 = 'unicore32' +X86_64 = 'x86_64' +XTENSA = 'xtensa' +XTENSAEB = 'xtensaeb' + +ALL = ( + ALPHA, ARMV6, ARMV7, ARMV7B, + AARCH64, CRIS, I686, IA64, LM32, + M68K, MICROBLAZE, MICROBLAZEEL, MIPS, MIPSEL, + MIPS64, MIPS64EL, OPENRISC, PARISC, PARISC64, + PPC, PPCLE, PPC64, PPC64LE, PPCEMB, + S390, S390X, SH4, SH4EB, SPARC, + SPARC64, UNICORE32, X86_64, XTENSA, XTENSAEB, +) diff --git a/releasenotes/notes/fix-multiarch-image-props-filter-f2e885aa53d585ea.yaml b/releasenotes/notes/fix-multiarch-image-props-filter-f2e885aa53d585ea.yaml new file mode 100644 index 000000000000..5af2cf005817 --- /dev/null +++ b/releasenotes/notes/fix-multiarch-image-props-filter-f2e885aa53d585ea.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - The behaviour of ImagePropertiesFilter when using multiple architectures + in a cloud can be unpredictable for a user if they forget to set the + architecture property in their image. Nova now allows the deployer to + specify a fallback in ``[filter_scheduler]image_properties_default_architecture`` + to use a default architecture if none is specified. Without this, it + is possible that a VM would get scheduled on a compute node that does not + support the image.