From aa5b1326c86c408ce9cc4546e1c7a310fbce3136 Mon Sep 17 00:00:00 2001 From: Mohammed Naser Date: Fri, 4 May 2018 21:06:46 -0400 Subject: [PATCH] Added ability to configure default architecture for ImagePropertiesFilter When using ImagePropertiesFilter with multiple architectures inside the same deployment, it is possible that images can be uploaded without the hw_architecture property defined. This results in behaviour where the instance could be scheduled on any type of hypervisor, resulting in an instance that will successfully transition to ACTIVE but never properly run because of the difference in architecture. This makes the ImagePropertiesFilter problematic as most images are generally uploaded without the architecture property set because most documentation does not encourage doing that. The addition of this flag allows to make using the filter possible because it allows the deployer to assume a default architecture if the user did not supply one (assuming it would be the most common architecture in their deployment, such as x86_64) yet if the user wants a more specific architecture, they can do it in their image properties. In order to avoid a circular import loop, the references to the architecture field have been moved to a seperate module so that they can be properly and cleaned imported inside configuration. Change-Id: Ib52deb095028e93619b93ef9e5f70775df2a403a Closes-Bug: #1769283 --- nova/conf/scheduler.py | 17 ++++ nova/objects/fields.py | 79 +++++++++---------- nova/scheduler/filters/image_props_filter.py | 10 ++- .../filters/test_image_props_filters.py | 15 ++++ nova/virt/arch.py | 65 +++++++++++++++ ...h-image-props-filter-f2e885aa53d585ea.yaml | 9 +++ 6 files changed, 151 insertions(+), 44 deletions(-) create mode 100644 nova/virt/arch.py create mode 100644 releasenotes/notes/fix-multiarch-image-props-filter-f2e885aa53d585ea.yaml 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.