Merge "Add 'cpu_policy' and 'cpu_thread_policy' fields"
This commit is contained in:
@@ -1974,6 +1974,11 @@ class ImageCPUPinningForbidden(Forbidden):
|
||||
"CPU pinning policy set against the flavor")
|
||||
|
||||
|
||||
class ImageCPUThreadPolicyForbidden(Forbidden):
|
||||
msg_fmt = _("Image property 'hw_cpu_thread_policy' is not permitted to "
|
||||
"override CPU thread pinning policy set against the flavor")
|
||||
|
||||
|
||||
class UnsupportedPolicyException(Invalid):
|
||||
msg_fmt = _("ServerGroup policy is not supported: %(reason)s")
|
||||
|
||||
@@ -2015,6 +2020,11 @@ class RealtimeConfigurationInvalid(Invalid):
|
||||
"cpu pinning policy")
|
||||
|
||||
|
||||
class CPUThreadPolicyConfigurationInvalid(Invalid):
|
||||
msg_fmt = _("Cannot set cpu thread pinning policy in a non dedicated "
|
||||
"cpu pinning policy")
|
||||
|
||||
|
||||
class RequestSpecNotFound(NotFound):
|
||||
msg_fmt = _("RequestSpec not found for instance %(instance_uuid)s")
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import versionutils
|
||||
|
||||
from nova import db
|
||||
from nova import exception
|
||||
@@ -28,7 +29,16 @@ class InstanceNUMACell(base.NovaObject,
|
||||
# Version 1.0: Initial version
|
||||
# Version 1.1: Add pagesize field
|
||||
# Version 1.2: Add cpu_pinning_raw and topology fields
|
||||
VERSION = '1.2'
|
||||
# Version 1.3: Add cpu_policy and cpu_thread_policy fields
|
||||
VERSION = '1.3'
|
||||
|
||||
def obj_make_compatible(self, primitive, target_version):
|
||||
super(InstanceNUMACell, self).obj_make_compatible(primitive,
|
||||
target_version)
|
||||
target_version = versionutils.convert_version_to_tuple(target_version)
|
||||
if target_version < (1, 3):
|
||||
primitive.pop('cpu_policy', None)
|
||||
primitive.pop('cpu_thread_policy', None)
|
||||
|
||||
fields = {
|
||||
'id': obj_fields.IntegerField(),
|
||||
@@ -37,8 +47,11 @@ class InstanceNUMACell(base.NovaObject,
|
||||
'pagesize': obj_fields.IntegerField(nullable=True),
|
||||
'cpu_topology': obj_fields.ObjectField('VirtCPUTopology',
|
||||
nullable=True),
|
||||
'cpu_pinning_raw': obj_fields.DictOfIntegersField(nullable=True)
|
||||
}
|
||||
'cpu_pinning_raw': obj_fields.DictOfIntegersField(nullable=True),
|
||||
'cpu_policy': obj_fields.CPUAllocationPolicyField(nullable=True),
|
||||
'cpu_thread_policy': obj_fields.CPUThreadAllocationPolicyField(
|
||||
nullable=True),
|
||||
}
|
||||
|
||||
cpu_pinning = obj_fields.DictProxyField('cpu_pinning_raw')
|
||||
|
||||
@@ -53,6 +66,12 @@ class InstanceNUMACell(base.NovaObject,
|
||||
if 'cpu_pinning' not in kwargs:
|
||||
self.cpu_pinning = None
|
||||
self.obj_reset_changes(['cpu_pinning_raw'])
|
||||
if 'cpu_policy' not in kwargs:
|
||||
self.cpu_policy = None
|
||||
self.obj_reset_changes(['cpu_policy'])
|
||||
if 'cpu_thread_policy' not in kwargs:
|
||||
self.cpu_thread_policy = None
|
||||
self.obj_reset_changes(['cpu_thread_policy'])
|
||||
|
||||
def __len__(self):
|
||||
return len(self.cpuset)
|
||||
|
||||
@@ -1148,7 +1148,7 @@ object_data = {
|
||||
'InstanceList': '2.0-6c8ba6147cca3082b1e4643f795068bf',
|
||||
'InstanceMapping': '1.0-47ef26034dfcbea78427565d9177fe50',
|
||||
'InstanceMappingList': '1.0-9e982e3de1613b9ada85e35f69b23d47',
|
||||
'InstanceNUMACell': '1.2-535ef30e0de2d6a0d26a71bd58ecafc4',
|
||||
'InstanceNUMACell': '1.3-6991a20992c5faa57fae71a45b40241b',
|
||||
'InstanceNUMATopology': '1.2-d944a7d6c21e1c773ffdf09c6d025954',
|
||||
'InstancePCIRequest': '1.1-b1d75ebc716cb12906d9d513890092bf',
|
||||
'InstancePCIRequests': '1.1-65e38083177726d806684cb1cc0136d2',
|
||||
|
||||
@@ -23,6 +23,7 @@ from nova import context
|
||||
from nova import exception
|
||||
from nova import objects
|
||||
from nova.objects import base as base_obj
|
||||
from nova.objects import fields
|
||||
from nova.pci import stats
|
||||
from nova import test
|
||||
from nova.virt import hardware as hw
|
||||
@@ -1103,6 +1104,37 @@ class NUMATopologyTest(test.NoDBTestCase):
|
||||
},
|
||||
"expect": exception.RealtimeConfigurationInvalid,
|
||||
},
|
||||
{
|
||||
# Invalid CPU thread pinning override
|
||||
"flavor": objects.Flavor(vcpus=4, memory_mb=2048,
|
||||
extra_specs={
|
||||
"hw:numa_nodes": 2, "hw:cpu_policy": "dedicated",
|
||||
"hw:cpu_thread_policy":
|
||||
fields.CPUThreadAllocationPolicy.ISOLATE,
|
||||
}),
|
||||
"image": {
|
||||
"properties": {
|
||||
"hw_cpu_policy": "dedicated",
|
||||
"hw_cpu_thread_policy":
|
||||
fields.CPUThreadAllocationPolicy.REQUIRE,
|
||||
}
|
||||
},
|
||||
"expect": exception.ImageCPUThreadPolicyForbidden,
|
||||
},
|
||||
{
|
||||
# Invalid CPU pinning policy with CPU thread pinning
|
||||
"flavor": objects.Flavor(vcpus=4, memory_mb=2048,
|
||||
extra_specs={
|
||||
"hw:cpu_policy": "shared",
|
||||
"hw:cpu_thread_policy":
|
||||
fields.CPUThreadAllocationPolicy.ISOLATE,
|
||||
}),
|
||||
"image": {
|
||||
"properties": {}
|
||||
},
|
||||
"expect": exception.CPUThreadPolicyConfigurationInvalid,
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
for testitem in testdata:
|
||||
|
||||
+21
-2
@@ -27,6 +27,7 @@ from nova import context
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova import objects
|
||||
from nova.objects import fields
|
||||
from nova.objects import instance as obj_instance
|
||||
|
||||
|
||||
@@ -1018,21 +1019,38 @@ def _add_cpu_pinning_constraint(flavor, image_meta, numa_topology):
|
||||
if rt and pi != "dedicated":
|
||||
raise exception.RealtimeConfigurationInvalid()
|
||||
|
||||
flavor_thread_policy = flavor.get('extra_specs', {}).get(
|
||||
'hw:cpu_thread_policy')
|
||||
image_thread_policy = image_meta.properties.get('hw_cpu_thread_policy')
|
||||
|
||||
if not requested:
|
||||
if flavor_thread_policy or image_thread_policy:
|
||||
raise exception.CPUThreadPolicyConfigurationInvalid()
|
||||
return numa_topology
|
||||
|
||||
if flavor_thread_policy in [None, fields.CPUThreadAllocationPolicy.PREFER]:
|
||||
cpu_thread_policy = image_thread_policy
|
||||
elif image_thread_policy and image_thread_policy != flavor_thread_policy:
|
||||
raise exception.ImageCPUThreadPolicyForbidden()
|
||||
else:
|
||||
cpu_thread_policy = flavor_thread_policy
|
||||
|
||||
if numa_topology:
|
||||
# NOTE(ndipanov) Setting the cpu_pinning attribute to a non-None value
|
||||
# means CPU pinning was requested
|
||||
# TODO(sfinucan) Instead of using the "magic" described above, make use
|
||||
# of the 'InstanceNUMACell.cpu_policy' parameter
|
||||
for cell in numa_topology.cells:
|
||||
cell.cpu_pinning = {}
|
||||
cell.cpu_thread_policy = cpu_thread_policy
|
||||
return numa_topology
|
||||
else:
|
||||
single_cell = objects.InstanceNUMACell(
|
||||
id=0,
|
||||
cpuset=set(range(flavor.vcpus)),
|
||||
memory=flavor.memory_mb,
|
||||
cpu_pinning={})
|
||||
cpu_pinning={},
|
||||
cpu_thread_policy=cpu_thread_policy)
|
||||
numa_topology = objects.InstanceNUMATopology(cells=[single_cell])
|
||||
return numa_topology
|
||||
|
||||
@@ -1254,7 +1272,8 @@ def instance_topology_from_instance(instance):
|
||||
cpuset=set(cell['cpuset']),
|
||||
memory=cell['memory'],
|
||||
pagesize=cell.get('pagesize'),
|
||||
cpu_pinning=cell.get('cpu_pinning_raw'))
|
||||
cpu_pinning=cell.get('cpu_pinning_raw'),
|
||||
cpu_thread_policy=cell.get('cpu_thread_policy'))
|
||||
for cell in dict_cells]
|
||||
instance_numa_topology = objects.InstanceNUMATopology(
|
||||
cells=cells)
|
||||
|
||||
Reference in New Issue
Block a user