diff --git a/nova/exception.py b/nova/exception.py index 9105d6a51120..0e0af13535d9 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -1956,3 +1956,8 @@ class UnsupportedImageModel(Invalid): class HostMappingNotFound(Invalid): msg_fmt = _("Host '%(name)s' is not mapped to any cell") + + +class RealtimeConfigurationInvalid(Invalid): + msg_fmt = _("Cannot set realtime policy in a non dedicated " + "cpu pinning policy") diff --git a/nova/tests/unit/virt/test_hardware.py b/nova/tests/unit/virt/test_hardware.py index 27d8fe6f2930..fb38601fc2f3 100644 --- a/nova/tests/unit/virt/test_hardware.py +++ b/nova/tests/unit/virt/test_hardware.py @@ -1090,6 +1090,18 @@ class NUMATopologyTest(test.NoDBTestCase): }, "expect": exception.ImageCPUPinningForbidden, }, + { + # Invalid CPU pinning policy with realtime + "flavor": objects.Flavor(vcpus=4, memory_mb=2048, + extra_specs={ + "hw:cpu_policy": "shared", + "hw:cpu_realtime": "yes", + }), + "image": { + "properties": {} + }, + "expect": exception.RealtimeConfigurationInvalid, + }, ] for testitem in testdata: diff --git a/nova/virt/hardware.py b/nova/virt/hardware.py index 0b87b795ac26..b44dadbab1f6 100644 --- a/nova/virt/hardware.py +++ b/nova/virt/hardware.py @@ -958,6 +958,11 @@ def _numa_get_constraints_manual(nodes, flavor, cpu_list, mem_list): return objects.InstanceNUMATopology(cells=cells) +def is_realtime_enabled(flavor): + flavor_rt = flavor.get('extra_specs', {}).get("hw:cpu_realtime") + return strutils.bool_from_string(flavor_rt) + + def _numa_get_constraints_auto(nodes, flavor): if ((flavor.vcpus % nodes) > 0 or (flavor.memory_mb % nodes) > 0): @@ -988,6 +993,11 @@ def _add_cpu_pinning_constraint(flavor, image_meta, numa_topology): else: requested = image_pinning == "dedicated" + rt = is_realtime_enabled(flavor) + pi = image_pinning or flavor_pinning + if rt and pi != "dedicated": + raise exception.RealtimeConfigurationInvalid() + if not requested: return numa_topology