Add transform_image_metadata request filter

Add a table-driven prefilter to transform image metadata into required
traits. This requires a new config option to make the filter optional.

Change-Id: I257ff81e23cdae6f2b62ec3d071b8f8f32d97781
Implements: blueprint image-metadata-prefiltering
Co-Authored-By: Stephen Finucane <sfinucan@redhat.com>
This commit is contained in:
Sean Mooney 2019-06-17 23:53:05 +01:00
parent 03750fa649
commit d1c4f13d7c
4 changed files with 99 additions and 1 deletions

View File

@ -198,7 +198,17 @@ flavor/image. If an aggregate is configured with a property with key
and/or image metadata must also contain ``trait:$TRAIT_NAME=required`` to be
eligible to be scheduled to hosts in that aggregate. More technical details
at https://docs.openstack.org/nova/latest/reference/isolate-aggregates.html
""")
"""),
cfg.BoolOpt("image_metadata_prefilter",
default=False,
help="""
This setting causes the scheduler to transform well known image metadata
properties into placement required traits to filter host based on image
metadata. This feature requires host support and is currently supported by the
following compute drivers:
- ``libvirt.LibvirtDriver`` (since Ussuri (21.0.0))
"""),
]
filter_scheduler_group = cfg.OptGroup(name="filter_scheduler",

View File

@ -193,6 +193,47 @@ def require_image_type_support(ctxt, request_spec):
return True
@trace_request_filter
def transform_image_metadata(ctxt, request_spec):
"""Transform image metadata to required traits.
This will modify the request_spec to request hosts that support
virtualisation capabilities based on the image metadata properties.
"""
if not CONF.scheduler.image_metadata_prefilter:
return False
prefix_map = {
'hw_cdrom_bus': 'COMPUTE_STORAGE_BUS',
'hw_disk_bus': 'COMPUTE_STORAGE_BUS',
'hw_video_model': 'COMPUTE_GRAPHICS_MODEL',
'hw_vif_model': 'COMPUTE_NET_VIF_MODEL',
}
trait_names = []
for key, prefix in prefix_map.items():
if key in request_spec.image.properties:
value = request_spec.image.properties.get(key).replace(
'-', '_').upper()
trait_name = f'{prefix}_{value}'
if not hasattr(os_traits, trait_name):
LOG.error(('Computed trait name %r is not valid; '
'is os-traits up to date?'), trait_name)
return False
trait_names.append(trait_name)
for trait_name in trait_names:
LOG.debug(
'transform_image_metadata request filter added required '
'trait %s', trait_name
)
request_spec.root_required.add(trait_name)
return True
@trace_request_filter
def compute_status_filter(ctxt, request_spec):
"""Pre-filter compute node resource providers using COMPUTE_STATUS_DISABLED
@ -215,6 +256,7 @@ ALL_REQUEST_FILTERS = [
require_image_type_support,
compute_status_filter,
isolate_aggregates,
transform_image_metadata,
]

View File

@ -12,11 +12,13 @@
import mock
import os_traits as ot
from oslo_utils.fixture import uuidsentinel as uuids
from oslo_utils import timeutils
from nova import context as nova_context
from nova import exception
from nova.network import model as network_model
from nova import objects
from nova.scheduler import request_filter
from nova import test
@ -400,3 +402,36 @@ class TestRequestFilter(test.NoDBTestCase):
log_lines = [c[0][0] for c in mock_log.debug.call_args_list]
self.assertIn('added forbidden trait', log_lines[0])
self.assertIn('took %.1f seconds', log_lines[1])
@mock.patch.object(request_filter, 'LOG', new=mock.Mock())
def test_transform_image_metadata(self):
self.flags(image_metadata_prefilter=True, group='scheduler')
properties = objects.ImageMetaProps(
hw_disk_bus=objects.fields.DiskBus.SATA,
hw_cdrom_bus=objects.fields.DiskBus.IDE,
hw_video_model=objects.fields.VideoModel.QXL,
hw_vif_model=network_model.VIF_MODEL_VIRTIO
)
reqspec = objects.RequestSpec(
image=objects.ImageMeta(properties=properties),
flavor=objects.Flavor(extra_specs={}),
)
self.assertTrue(
request_filter.transform_image_metadata(None, reqspec)
)
expected = {
'COMPUTE_GRAPHICS_MODEL_QXL',
'COMPUTE_NET_VIF_MODEL_VIRTIO',
'COMPUTE_STORAGE_BUS_IDE',
'COMPUTE_STORAGE_BUS_SATA',
}
self.assertEqual(expected, reqspec.root_required)
def test_transform_image_metadata__disabled(self):
self.flags(image_metadata_prefilter=False, group='scheduler')
reqspec = objects.RequestSpec(flavor=objects.Flavor(extra_specs={}))
# Assert that we completely skip the filter if disabled
self.assertFalse(
request_filter.transform_image_metadata(self.context, reqspec)
)
self.assertEqual(set(), reqspec.root_required)

View File

@ -0,0 +1,11 @@
---
features:
- |
A new image metadata prefilter has been added to allow translation of
hypervisor-specific device model requests to standard traits. When this
feature is enabled, nova is able to utilize placement to select hosts that
are capable of emulating the requested devices, avoiding hosts that
could not support the request. This feature is currently supported by the
libvirt driver and can be enabled by configuring the
``[scheduler]/image_metadata_prefilter`` to ``True`` in the controller
``nova.conf``.