From d2a5333e9968edc88bdd9e854d6d5404435c5d60 Mon Sep 17 00:00:00 2001 From: Anastasiya Date: Wed, 18 Jan 2017 09:16:34 +0400 Subject: [PATCH] Limit the minimal RAM amount for OVS+DPDK to 1024MB * min value was set in consts * appropriate validator was added * tests for validator were changed * test for serializer were changed Change-Id: Ib8ccb0658bd401ce492257f855013d1d7e0f2dac Closes-Bug: #1653081 --- nailgun/nailgun/api/v1/validators/node.py | 17 +++++ nailgun/nailgun/consts.py | 2 + .../test_orchestrator_serializer_90.py | 8 +- .../unit/test_node_attributes_validator.py | 76 +++++++++++++++++-- 4 files changed, 94 insertions(+), 9 deletions(-) diff --git a/nailgun/nailgun/api/v1/validators/node.py b/nailgun/nailgun/api/v1/validators/node.py index c247bd8717..5be2a06d97 100644 --- a/nailgun/nailgun/api/v1/validators/node.py +++ b/nailgun/nailgun/api/v1/validators/node.py @@ -503,6 +503,23 @@ class NodeAttributesValidator(base.BasicAttributesValidator): ) ) + dpdk_hugepages = utils.get_in(attrs, 'hugepages', 'dpdk', 'value') + if objects.Node.dpdk_enabled(node): + min_dpdk_hugepages = consts.MIN_DPDK_HUGEPAGES_MEMORY + if dpdk_hugepages < min_dpdk_hugepages: + raise errors.InvalidData( + "Node {0} does not have enough hugepages for dpdk. " + "Need to allocate at least {1} MB.".format( + node.id, + min_dpdk_hugepages + ) + ) + elif dpdk_hugepages != 0: + raise errors.InvalidData( + "Hugepages for dpdk should be equal to 0 " + "if dpdk is disabled." + ) + try: objects.NodeAttributes.distribute_hugepages(node, attrs) except ValueError as exc: diff --git a/nailgun/nailgun/consts.py b/nailgun/nailgun/consts.py index c60b1c2a31..93007ab25b 100644 --- a/nailgun/nailgun/consts.py +++ b/nailgun/nailgun/consts.py @@ -518,6 +518,8 @@ DEFAULT_DEPLOYMENT_GRAPH_TYPE = 'default' DEFAULT_HUGEPAGE_SIZE = '2048' HUGE_PAGES_SIZE_MAP = [('2048', '2M'), ('1048576', '1G')] DPDK_OVS_CORE_CPUS = 1 +# minimal RAM amount for OVS+DPDK in MB +MIN_DPDK_HUGEPAGES_MEMORY = 1024 MEMORY_RESERVED_FOR_OPERATING_SYSTEM = 1024 ** 3 # one GiB in bytes diff --git a/nailgun/nailgun/test/integration/test_orchestrator_serializer_90.py b/nailgun/nailgun/test/integration/test_orchestrator_serializer_90.py index ee22c875c3..a7ba96ff51 100644 --- a/nailgun/nailgun/test/integration/test_orchestrator_serializer_90.py +++ b/nailgun/nailgun/test/integration/test_orchestrator_serializer_90.py @@ -488,7 +488,7 @@ class TestDeploymentAttributesSerialization90( numa_nodes.append({ 'id': i, 'cpus': [i], - 'memory': 1024 ** 3 + 'memory': 2 * 1024 ** 3 }) meta = { @@ -501,17 +501,19 @@ class TestDeploymentAttributesSerialization90( cluster_id=self.cluster_db.id, roles=['compute'], meta=meta) + node.interfaces[0].attributes.get('dpdk', {}).get( + 'enabled', {})['value'] = True node.attributes.update({ 'hugepages': { 'dpdk': { - 'value': 128}, + 'value': 1024}, 'nova': { 'value': {'2048': 1}}}} ) serialized_for_astute = self.serialize() serialized_node = serialized_for_astute['nodes'][0] self.assertEquals( - [128, 128, 128], + [1024, 1024, 1024], serialized_node['dpdk']['ovs_socket_mem']) self.assertTrue(serialized_node['nova']['enable_hugepages']) diff --git a/nailgun/nailgun/test/unit/test_node_attributes_validator.py b/nailgun/nailgun/test/unit/test_node_attributes_validator.py index eb800fb03d..4b565e3f11 100644 --- a/nailgun/nailgun/test/unit/test_node_attributes_validator.py +++ b/nailgun/nailgun/test/unit/test_node_attributes_validator.py @@ -28,7 +28,7 @@ validator = node_validator.NodeAttributesValidator.validate def mock_cluster_attributes(func): def wrapper(*args, **kwargs): - attr_mock = mock.patch.object( + cluster_attr_mock = mock.patch.object( objects.Cluster, 'get_editable_attributes', return_value={ @@ -39,7 +39,12 @@ def mock_cluster_attributes(func): } } ) - with attr_mock: + node_dpdk_mock = mock.patch.object( + objects.Node, + 'dpdk_enabled', + return_value=True + ) + with cluster_attr_mock, node_dpdk_mock: func(*args, **kwargs) return wrapper @@ -54,8 +59,8 @@ class BaseNodeAttributeValidatorTest(base.BaseTestCase): meta['numa_topology'] = { "supported_hugepages": [2048, 1048576], "numa_nodes": [ - {"id": 0, "cpus": [0, 1], 'memory': 2 * 1024 ** 3}, - {"id": 1, "cpus": [2, 3], 'memory': 2 * 1024 ** 3}, + {"id": 0, "cpus": [0, 1], 'memory': 3 * 1024 ** 3}, + {"id": 1, "cpus": [2, 3], 'memory': 3 * 1024 ** 3}, ] } meta['cpu']['total'] = 4 @@ -68,7 +73,7 @@ class BaseNodeAttributeValidatorTest(base.BaseTestCase): }, 'dpdk': { 'type': 'number', - 'value': 0, + 'value': 1024, }, }, 'cpu_pinning': { @@ -107,7 +112,7 @@ class TestNodeAttributesValidatorHugepages(BaseNodeAttributeValidatorTest): }, }, 'dpdk': { - 'value': 2, + 'value': 1024, }, } } @@ -132,6 +137,65 @@ class TestNodeAttributesValidatorHugepages(BaseNodeAttributeValidatorTest): errors.InvalidData, 'Not enough memory for components', validator, json.dumps(data), self.node, self.cluster) + @mock_cluster_attributes + def test_not_enough_dpdk_hugepages(self, m_dpdk_nics): + data = { + 'hugepages': { + 'nova': { + 'value': { + '2048': 1, + '1048576': 0, + }, + }, + 'dpdk': { + 'value': 1023, + 'min': 1024 + }, + } + } + message = ("Node {0} does not have enough hugepages for dpdk. " + "Need to allocate at least {1} MB.").format(self.node.id, + 1024) + self.assertRaisesWithMessageIn( + errors.InvalidData, message, + validator, json.dumps(data), self.node, self.cluster) + + @mock_cluster_attributes + @mock.patch.object(objects.Node, 'dpdk_enabled', return_value=False) + def test_valid_hugepages_non_dpdk(self, m_dpdk_nics, m_dpdk_enabled): + data = { + 'hugepages': { + 'nova': { + 'value': { + '2048': 1, + '1048576': 1, + }, + }, + 'dpdk': { + 'value': 0, + }, + } + } + self.assertNotRaises(errors.InvalidData, validator, + json.dumps(data), self.node, self.cluster) + + @mock_cluster_attributes + @mock.patch.object(objects.Node, 'dpdk_enabled', return_value=False) + def test_non_zero_value_hugepages_non_dpdk(self, m_dpdk_nics, + m_dpdk_enabled): + data = { + 'hugepages': { + 'dpdk': { + 'value': 1, + }, + } + } + message = ("Hugepages for dpdk should be equal to 0 " + "if dpdk is disabled.") + self.assertRaisesWithMessageIn( + errors.InvalidData, message, + validator, json.dumps(data), self.node, self.cluster) + @mock_cluster_attributes def test_dpdk_requires_too_much(self, m_dpdk_nics): data = {