Throw exception if numa_nodes is not set to integer greater than 0
As [1] is abandoned, I used that patchset to create a new one. This patchset is freshened to the current master branch. This patch introduces InvalidNUMANodesNumber exception, which is thrown when trying to boot an instance with a flavor that has hw:numa_nodes=0 extra spec set. That means that NUMA nodes is set to 0, which is incorrect. [1]: https://review.openstack.org/#/c/190267 Change-Id: I6bd8f69e582c537a5fec40064638a8887a08cac4 Co-Authored-By: Karim Boumedhel <karimboumedhel@gmail.com> Closes-Bug: #1402709
This commit is contained in:
parent
b61cb28e98
commit
47d8aa5e7f
@ -689,6 +689,7 @@ class ServersController(wsgi.Controller):
|
|||||||
exception.ImageNUMATopologyCPUDuplicates,
|
exception.ImageNUMATopologyCPUDuplicates,
|
||||||
exception.ImageNUMATopologyCPUsUnassigned,
|
exception.ImageNUMATopologyCPUsUnassigned,
|
||||||
exception.ImageNUMATopologyMemoryOutOfRange,
|
exception.ImageNUMATopologyMemoryOutOfRange,
|
||||||
|
exception.InvalidNUMANodesNumber,
|
||||||
exception.InstanceGroupNotFound,
|
exception.InstanceGroupNotFound,
|
||||||
exception.PciRequestAliasNotDefined,
|
exception.PciRequestAliasNotDefined,
|
||||||
exception.SnapshotNotFound,
|
exception.SnapshotNotFound,
|
||||||
|
@ -372,6 +372,11 @@ class InvalidStrTime(Invalid):
|
|||||||
msg_fmt = _("Invalid datetime string: %(reason)s")
|
msg_fmt = _("Invalid datetime string: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidNUMANodesNumber(Invalid):
|
||||||
|
msg_fmt = _("The property 'numa_nodes' cannot be '%(nodes)s'. "
|
||||||
|
"It must be a number greater than 0")
|
||||||
|
|
||||||
|
|
||||||
class InvalidName(Invalid):
|
class InvalidName(Invalid):
|
||||||
msg_fmt = _("An invalid 'name' value was provided. "
|
msg_fmt = _("An invalid 'name' value was provided. "
|
||||||
"The name must be: %(reason)s")
|
"The name must be: %(reason)s")
|
||||||
|
@ -3255,6 +3255,14 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
self.controller.create,
|
self.controller.create,
|
||||||
self.req, body=self.body)
|
self.req, body=self.body)
|
||||||
|
|
||||||
|
@mock.patch.object(compute_api.API, 'create',
|
||||||
|
side_effect=exception.InvalidNUMANodesNumber(
|
||||||
|
details=''))
|
||||||
|
def test_create_instance_raise_invalid_numa_nodes(self, mock_create):
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
|
self.controller.create,
|
||||||
|
self.req, body=self.body)
|
||||||
|
|
||||||
@mock.patch.object(compute_api.API, 'create',
|
@mock.patch.object(compute_api.API, 'create',
|
||||||
side_effect=exception.InvalidBDMFormat(details=''))
|
side_effect=exception.InvalidBDMFormat(details=''))
|
||||||
def test_create_instance_raise_invalid_bdm_format(self, mock_create):
|
def test_create_instance_raise_invalid_bdm_format(self, mock_create):
|
||||||
|
@ -856,6 +856,36 @@ class NUMATopologyTest(test.NoDBTestCase):
|
|||||||
memory=2048, pagesize=2048)
|
memory=2048, pagesize=2048)
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
# a nodes number of zero should lead to an
|
||||||
|
# exception
|
||||||
|
"flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={
|
||||||
|
"hw:numa_nodes": 0
|
||||||
|
}),
|
||||||
|
"image": {
|
||||||
|
},
|
||||||
|
"expect": exception.InvalidNUMANodesNumber,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# a negative nodes number should lead to an
|
||||||
|
# exception
|
||||||
|
"flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={
|
||||||
|
"hw:numa_nodes": -1
|
||||||
|
}),
|
||||||
|
"image": {
|
||||||
|
},
|
||||||
|
"expect": exception.InvalidNUMANodesNumber,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# a nodes number not numeric should lead to an
|
||||||
|
# exception
|
||||||
|
"flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={
|
||||||
|
"hw:numa_nodes": 'x'
|
||||||
|
}),
|
||||||
|
"image": {
|
||||||
|
},
|
||||||
|
"expect": exception.InvalidNUMANodesNumber,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
# vcpus is not a multiple of nodes, so it
|
# vcpus is not a multiple of nodes, so it
|
||||||
# is an error to not provide cpu/mem mapping
|
# is an error to not provide cpu/mem mapping
|
||||||
|
@ -1178,6 +1178,18 @@ def _add_cpu_pinning_constraint(flavor, image_meta, numa_topology):
|
|||||||
return numa_topology
|
return numa_topology
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_numa_nodes(nodes):
|
||||||
|
"""Validate NUMA nodes number
|
||||||
|
|
||||||
|
:param nodes: The number of NUMA nodes
|
||||||
|
:raises: exception.InvalidNUMANodesNumber if the given
|
||||||
|
parameter is not a number or less than 1
|
||||||
|
"""
|
||||||
|
if nodes is not None and (not strutils.is_int_like(nodes) or
|
||||||
|
int(nodes) < 1):
|
||||||
|
raise exception.InvalidNUMANodesNumber(nodes=nodes)
|
||||||
|
|
||||||
|
|
||||||
# TODO(sahid): Move numa related to hardward/numa.py
|
# TODO(sahid): Move numa related to hardward/numa.py
|
||||||
def numa_get_constraints(flavor, image_meta):
|
def numa_get_constraints(flavor, image_meta):
|
||||||
"""Return topology related to input request
|
"""Return topology related to input request
|
||||||
@ -1189,6 +1201,8 @@ def numa_get_constraints(flavor, image_meta):
|
|||||||
image properties are not correctly specified, or
|
image properties are not correctly specified, or
|
||||||
exception.ImageNUMATopologyForbidden if an attempt is
|
exception.ImageNUMATopologyForbidden if an attempt is
|
||||||
made to override flavor settings with image properties.
|
made to override flavor settings with image properties.
|
||||||
|
exception.InvalidNUMANodesNumber if the number of NUMA
|
||||||
|
nodes is less than 1 (or not an integer).
|
||||||
|
|
||||||
:returns: InstanceNUMATopology or None
|
:returns: InstanceNUMATopology or None
|
||||||
"""
|
"""
|
||||||
@ -1196,12 +1210,14 @@ def numa_get_constraints(flavor, image_meta):
|
|||||||
nodes = flavor.get('extra_specs', {}).get("hw:numa_nodes")
|
nodes = flavor.get('extra_specs', {}).get("hw:numa_nodes")
|
||||||
props = image_meta.properties
|
props = image_meta.properties
|
||||||
if nodes is not None:
|
if nodes is not None:
|
||||||
|
_validate_numa_nodes(nodes)
|
||||||
if props.obj_attr_is_set("hw_numa_nodes"):
|
if props.obj_attr_is_set("hw_numa_nodes"):
|
||||||
raise exception.ImageNUMATopologyForbidden(
|
raise exception.ImageNUMATopologyForbidden(
|
||||||
name='hw_numa_nodes')
|
name='hw_numa_nodes')
|
||||||
nodes = int(nodes)
|
nodes = int(nodes)
|
||||||
else:
|
else:
|
||||||
nodes = props.get("hw_numa_nodes")
|
nodes = props.get("hw_numa_nodes")
|
||||||
|
_validate_numa_nodes(nodes)
|
||||||
|
|
||||||
pagesize = _numa_get_pagesize_constraints(
|
pagesize = _numa_get_pagesize_constraints(
|
||||||
flavor, image_meta)
|
flavor, image_meta)
|
||||||
|
Loading…
Reference in New Issue
Block a user