diff --git a/lower-constraints.txt b/lower-constraints.txt index 31fdc46c5902..2fb27f47e24f 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -66,7 +66,7 @@ os-brick==2.6.2 os-client-config==1.29.0 os-resource-classes==0.4.0 os-service-types==1.7.0 -os-traits==2.1.0 +os-traits==2.2.0 os-vif==1.14.0 os-win==3.0.0 os-xenapi==0.3.3 diff --git a/nova/scheduler/request_filter.py b/nova/scheduler/request_filter.py index 0b783ae64c20..de05d3d1e46d 100644 --- a/nova/scheduler/request_filter.py +++ b/nova/scheduler/request_filter.py @@ -250,6 +250,22 @@ def compute_status_filter(ctxt, request_spec): return True +@trace_request_filter +def accelerators_filter(ctxt, request_spec): + """Allow only compute nodes with accelerator support. + + This filter retains only nodes whose compute manager published the + COMPUTE_ACCELERATORS trait, thus indicating the version of n-cpu is + sufficient to handle accelerator requests. + """ + trait_name = os_traits.COMPUTE_ACCELERATORS + if request_spec.flavor.extra_specs.get('accel:device_profile'): + request_spec.root_required.add(trait_name) + LOG.debug('accelerators_filter request filter added required ' + 'trait %s', trait_name) + return True + + ALL_REQUEST_FILTERS = [ require_tenant_aggregate, map_az_to_placement_aggregate, @@ -257,6 +273,7 @@ ALL_REQUEST_FILTERS = [ compute_status_filter, isolate_aggregates, transform_image_metadata, + accelerators_filter, ] diff --git a/nova/tests/functional/integrated_helpers.py b/nova/tests/functional/integrated_helpers.py index 0782dab202cf..007984ae2318 100644 --- a/nova/tests/functional/integrated_helpers.py +++ b/nova/tests/functional/integrated_helpers.py @@ -447,6 +447,7 @@ class ProviderUsageBaseTestCase(test.TestCase, InstanceHelperMixin): # nova.virt.libvirt.driver.LibvirtDriver.capabilities expected_libvirt_driver_capability_traits = set([ six.u(trait) for trait in [ + os_traits.COMPUTE_ACCELERATORS, os_traits.COMPUTE_DEVICE_TAGGING, os_traits.COMPUTE_NET_ATTACH_INTERFACE, os_traits.COMPUTE_NET_ATTACH_INTERFACE_WITH_TAG, @@ -466,6 +467,7 @@ class ProviderUsageBaseTestCase(test.TestCase, InstanceHelperMixin): # nova.virt.fake.FakeDriver.capabilities expected_fake_driver_capability_traits = set([ six.u(trait) for trait in [ + os_traits.COMPUTE_ACCELERATORS, os_traits.COMPUTE_IMAGE_TYPE_RAW, os_traits.COMPUTE_DEVICE_TAGGING, os_traits.COMPUTE_NET_ATTACH_INTERFACE, diff --git a/nova/tests/unit/scheduler/test_request_filter.py b/nova/tests/unit/scheduler/test_request_filter.py index a7f590da2fcd..e1f17cd9cd0b 100644 --- a/nova/tests/unit/scheduler/test_request_filter.py +++ b/nova/tests/unit/scheduler/test_request_filter.py @@ -435,3 +435,42 @@ class TestRequestFilter(test.NoDBTestCase): request_filter.transform_image_metadata(self.context, reqspec) ) self.assertEqual(set(), reqspec.root_required) + + @mock.patch.object(request_filter, 'LOG') + def test_accelerators_filter_with_device_profile(self, mock_log): + # First ensure that accelerators_filter is included + self.assertIn(request_filter.accelerators_filter, + request_filter.ALL_REQUEST_FILTERS) + + es = {'accel:device_profile': 'mydp'} + reqspec = objects.RequestSpec(flavor=objects.Flavor(extra_specs=es)) + self.assertEqual(set(), reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) + + # Request filter puts the trait into the request spec + request_filter.accelerators_filter(self.context, reqspec) + self.assertEqual({ot.COMPUTE_ACCELERATORS}, reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) + + # Assert both the in-method logging and trace decorator. + log_lines = [c[0][0] for c in mock_log.debug.call_args_list] + self.assertIn('added required trait', log_lines[0]) + self.assertIn('took %.1f seconds', log_lines[1]) + + @mock.patch.object(request_filter, 'LOG') + def test_accelerators_filter_no_device_profile(self, mock_log): + # First ensure that accelerators_filter is included + self.assertIn(request_filter.accelerators_filter, + request_filter.ALL_REQUEST_FILTERS) + + reqspec = objects.RequestSpec(flavor=objects.Flavor(extra_specs={})) + self.assertEqual(set(), reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) + + # Request filter puts the trait into the request spec + request_filter.accelerators_filter(self.context, reqspec) + self.assertEqual(set(), reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) + + # Assert about logging + mock_log.assert_not_called() diff --git a/nova/virt/driver.py b/nova/virt/driver.py index 3d046a3db05a..f1deacad9499 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -110,6 +110,7 @@ CAPABILITY_TRAITS_MAP = { "supports_multiattach": os_traits.COMPUTE_VOLUME_MULTI_ATTACH, # Added in os-traits 0.8.0. "supports_trusted_certs": os_traits.COMPUTE_TRUSTED_CERTS, + "supports_accelerators": os_traits.COMPUTE_ACCELERATORS, # Image type support flags, added in os-traits 0.12.0 "supports_image_type_aki": os_traits.COMPUTE_IMAGE_TYPE_AKI, @@ -176,6 +177,7 @@ class ComputeDriver(object): "supports_multiattach": False, "supports_trusted_certs": False, "supports_pcpus": False, + "supports_accelerators": False, # Image type support flags "supports_image_type_aki": False, diff --git a/nova/virt/fake.py b/nova/virt/fake.py index b6a2c71f0293..d0b811045e65 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -113,6 +113,7 @@ class FakeDriver(driver.ComputeDriver): "supports_multiattach": True, "supports_trusted_certs": True, "supports_pcpus": False, + "supports_accelerators": True, # Supported image types "supports_image_type_raw": True, diff --git a/nova/virt/hyperv/driver.py b/nova/virt/hyperv/driver.py index a399682d6128..e47a962d2aba 100644 --- a/nova/virt/hyperv/driver.py +++ b/nova/virt/hyperv/driver.py @@ -101,6 +101,7 @@ class HyperVDriver(driver.ComputeDriver): "supports_multiattach": False, "supports_trusted_certs": False, "supports_pcpus": False, + "supports_accelerators": False, # Supported image types "supports_image_type_vhd": True, diff --git a/nova/virt/ironic/driver.py b/nova/virt/ironic/driver.py index b9a4c013a934..f8bf2d70c70a 100644 --- a/nova/virt/ironic/driver.py +++ b/nova/virt/ironic/driver.py @@ -163,6 +163,7 @@ class IronicDriver(virt_driver.ComputeDriver): "supports_multiattach": False, "supports_trusted_certs": False, "supports_pcpus": False, + "supports_accelerators": False, # Image type support flags "supports_image_type_aki": False, diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 55799858994c..443d331de5ab 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -332,6 +332,7 @@ class LibvirtDriver(driver.ComputeDriver): "supports_image_type_qcow2": not requires_raw_image, "supports_image_type_ploop": requires_ploop_image, "supports_pcpus": True, + "supports_accelerators": True, } super(LibvirtDriver, self).__init__(virtapi) diff --git a/nova/virt/powervm/driver.py b/nova/virt/powervm/driver.py index 8f39ec89a1b4..4c565ba96061 100644 --- a/nova/virt/powervm/driver.py +++ b/nova/virt/powervm/driver.py @@ -78,6 +78,7 @@ class PowerVMDriver(driver.ComputeDriver): 'supports_multiattach': False, 'supports_trusted_certs': False, 'supports_pcpus': False, + "supports_accelerators": False, # Supported image types "supports_image_type_aki": False, diff --git a/nova/virt/vmwareapi/driver.py b/nova/virt/vmwareapi/driver.py index 214252652b65..3357c018a24b 100644 --- a/nova/virt/vmwareapi/driver.py +++ b/nova/virt/vmwareapi/driver.py @@ -70,6 +70,7 @@ class VMwareVCDriver(driver.ComputeDriver): "supports_multiattach": False, "supports_trusted_certs": False, "supports_pcpus": False, + "supports_accelerators": False, # Image type support flags "supports_image_type_aki": False, diff --git a/nova/virt/xenapi/driver.py b/nova/virt/xenapi/driver.py index 72b9639f74ca..cf44b8272934 100644 --- a/nova/virt/xenapi/driver.py +++ b/nova/virt/xenapi/driver.py @@ -70,6 +70,7 @@ class XenAPIDriver(driver.ComputeDriver): "supports_multiattach": False, "supports_trusted_certs": False, "supports_pcpus": False, + "supports_accelerators": False, # Image type support flags "supports_image_type_aki": False, diff --git a/requirements.txt b/requirements.txt index 21b207d69144..ec11b519eb80 100644 --- a/requirements.txt +++ b/requirements.txt @@ -55,7 +55,7 @@ psutil>=3.2.2 # BSD oslo.versionedobjects>=1.35.0 # Apache-2.0 os-brick>=2.6.2 # Apache-2.0 os-resource-classes>=0.4.0 # Apache-2.0 -os-traits>=2.1.0 # Apache-2.0 +os-traits>=2.2.0 # Apache-2.0 os-vif>=1.14.0 # Apache-2.0 os-win>=3.0.0 # Apache-2.0 castellan>=0.16.0 # Apache-2.0