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:
		@@ -689,6 +689,7 @@ class ServersController(wsgi.Controller):
 | 
			
		||||
                exception.ImageNUMATopologyCPUDuplicates,
 | 
			
		||||
                exception.ImageNUMATopologyCPUsUnassigned,
 | 
			
		||||
                exception.ImageNUMATopologyMemoryOutOfRange,
 | 
			
		||||
                exception.InvalidNUMANodesNumber,
 | 
			
		||||
                exception.InstanceGroupNotFound,
 | 
			
		||||
                exception.PciRequestAliasNotDefined,
 | 
			
		||||
                exception.SnapshotNotFound,
 | 
			
		||||
 
 | 
			
		||||
@@ -372,6 +372,11 @@ class InvalidStrTime(Invalid):
 | 
			
		||||
    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):
 | 
			
		||||
    msg_fmt = _("An invalid 'name' value was provided. "
 | 
			
		||||
                "The name must be: %(reason)s")
 | 
			
		||||
 
 | 
			
		||||
@@ -3255,6 +3255,14 @@ class ServersControllerCreateTest(test.TestCase):
 | 
			
		||||
                          self.controller.create,
 | 
			
		||||
                          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',
 | 
			
		||||
                       side_effect=exception.InvalidBDMFormat(details=''))
 | 
			
		||||
    def test_create_instance_raise_invalid_bdm_format(self, mock_create):
 | 
			
		||||
 
 | 
			
		||||
@@ -856,6 +856,36 @@ class NUMATopologyTest(test.NoDBTestCase):
 | 
			
		||||
                            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
 | 
			
		||||
                # 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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
def numa_get_constraints(flavor, image_meta):
 | 
			
		||||
    """Return topology related to input request
 | 
			
		||||
@@ -1189,6 +1201,8 @@ def numa_get_constraints(flavor, image_meta):
 | 
			
		||||
    image properties are not correctly specified, or
 | 
			
		||||
    exception.ImageNUMATopologyForbidden if an attempt is
 | 
			
		||||
    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
 | 
			
		||||
    """
 | 
			
		||||
@@ -1196,12 +1210,14 @@ def numa_get_constraints(flavor, image_meta):
 | 
			
		||||
    nodes = flavor.get('extra_specs', {}).get("hw:numa_nodes")
 | 
			
		||||
    props = image_meta.properties
 | 
			
		||||
    if nodes is not None:
 | 
			
		||||
        _validate_numa_nodes(nodes)
 | 
			
		||||
        if props.obj_attr_is_set("hw_numa_nodes"):
 | 
			
		||||
            raise exception.ImageNUMATopologyForbidden(
 | 
			
		||||
                name='hw_numa_nodes')
 | 
			
		||||
        nodes = int(nodes)
 | 
			
		||||
    else:
 | 
			
		||||
        nodes = props.get("hw_numa_nodes")
 | 
			
		||||
        _validate_numa_nodes(nodes)
 | 
			
		||||
 | 
			
		||||
    pagesize = _numa_get_pagesize_constraints(
 | 
			
		||||
        flavor, image_meta)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user