Merge "Add missing support for the root_device property"

This commit is contained in:
Zuul 2018-01-24 12:48:26 +00:00 committed by Gerrit Code Review
commit 9406ef4cbe
3 changed files with 42 additions and 54 deletions

View File

@ -0,0 +1,9 @@
---
fixes:
- |
Recognizes the ``root_device`` property when enrolling nodes. We recommend
it to be set for multi-disk nodes, but the enrolling procedure does not
actually accept it.
- |
Node properties are no longer converted to strings on enrolling. This is
not required by the Bare Metal service and may yield incorrect results.

View File

@ -293,11 +293,13 @@ class NodesTest(base.TestCase):
def test_register_all_nodes(self):
node_list = [self._get_node()]
node_list[0]['root_device'] = {"serial": "abcdef"}
node_properties = {"cpus": "1",
"memory_mb": "2048",
"local_gb": "30",
"cpu_arch": "amd64",
"capabilities": "num_nics:6"}
"capabilities": "num_nics:6",
"root_device": {"serial": "abcdef"}}
ironic = mock.MagicMock()
nodes.register_all_nodes(node_list, client=ironic)
pxe_node_driver_info = {"ipmi_address": "foo.bar",
@ -441,6 +443,7 @@ class NodesTest(base.TestCase):
node = self._get_node()
node.update(interfaces)
node['root_device'] = {'serial': 'abcdef'}
ironic = mock.MagicMock()
node_map = {'mac': {'aaa': 1}}
@ -454,6 +457,8 @@ class NodesTest(base.TestCase):
{'path': '/properties/cpu_arch', 'value': 'amd64'},
{'path': '/properties/cpus', 'value': '1'},
{'path': '/properties/capabilities', 'value': 'num_nics:6'},
{'path': '/properties/root_device',
'value': {'serial': 'abcdef'}},
{'path': '/driver_info/ipmi_username', 'value': 'test'}]
for iface, value in interfaces.items():
update_patch.append({'path': '/%s' % iface, 'value': value})
@ -638,24 +643,6 @@ class NodesTest(base.TestCase):
nodes._update_or_register_ironic_node(node, node_map, client=ironic)
ironic.node.update.assert_called_once_with('abcdef', mock.ANY)
def test_register_ironic_node_int_values(self):
node_properties = {"cpus": "1",
"memory_mb": "2048",
"local_gb": "30",
"cpu_arch": "amd64",
"capabilities": "num_nics:6"}
node = self._get_node()
node['cpu'] = 1
node['memory'] = 2048
node['disk'] = 30
client = mock.MagicMock()
nodes.register_ironic_node(node, client=client)
client.node.create.assert_called_once_with(driver=mock.ANY,
name='node1',
properties=node_properties,
resource_class='baremetal',
driver_info=mock.ANY)
def test_register_ironic_node_fake_pxe(self):
node_properties = {"cpus": "1",
"memory_mb": "2048",
@ -794,35 +781,6 @@ class NodesTest(base.TestCase):
'redfish_username': 'test',
'redfish_system_id': '/redfish/v1/Systems/1'})
def test_register_ironic_node_update_int_values(self):
node = self._get_node()
ironic = mock.MagicMock()
node['cpu'] = 1
node['memory'] = 2048
node['disk'] = 30
node_map = {'mac': {'aaa': 1}}
def side_effect(*args, **kwargs):
update_patch = [
{'path': '/name', 'value': 'node1'},
{'path': '/driver_info/ipmi_password', 'value': 'random'},
{'path': '/driver_info/ipmi_address', 'value': 'foo.bar'},
{'path': '/properties/memory_mb', 'value': '2048'},
{'path': '/properties/local_gb', 'value': '30'},
{'path': '/properties/cpu_arch', 'value': 'amd64'},
{'path': '/properties/cpus', 'value': '1'},
{'path': '/properties/capabilities', 'value': 'num_nics:6'},
{'path': '/driver_info/ipmi_username', 'value': 'test'}]
for key in update_patch:
key['op'] = 'add'
self.assertThat(update_patch,
matchers.MatchesSetwise(*(map(matchers.Equals,
args[1]))))
return mock.Mock(uuid='uuid1')
ironic.node.update.side_effect = side_effect
nodes._update_or_register_ironic_node(node, node_map, client=ironic)
def test_clean_up_extra_nodes_ironic(self):
node = collections.namedtuple('node', ['uuid'])
client = mock.MagicMock()
@ -928,7 +886,8 @@ VALID_NODE_JSON = [
'cpu': 2,
'memory': 1024,
'disk': 40,
'arch': 'x86_64'},
'arch': 'x86_64',
'root_device': {'foo': 'bar'}},
{'pm_type': 'redfish',
'pm_addr': '1.2.3.4',
'pm_user': 'root',
@ -1081,3 +1040,15 @@ class TestValidateNodes(base.TestCase):
self.assertRaisesRegex(exception.InvalidNode,
'fields are missing: pm_system_id',
nodes.validate_nodes, nodes_json)
def test_invalid_root_device(self):
nodes_json = [
{'pm_type': 'pxe_ipmitool',
'pm_addr': '1.1.1.1',
'pm_user': 'root',
'pm_password': 'p@$$w0rd',
'root_device': 42}
]
self.assertRaisesRegex(exception.InvalidNode,
'Invalid root device',
nodes.validate_nodes, nodes_json)

View File

@ -328,8 +328,9 @@ def register_ironic_node(node, client):
mapping = {'cpus': 'cpu',
'memory_mb': 'memory',
'local_gb': 'disk',
'cpu_arch': 'arch'}
properties = {k: six.text_type(node.get(v))
'cpu_arch': 'arch',
'root_device': 'root_device'}
properties = {k: node[v]
for k, v in mapping.items()
if node.get(v) is not None}
@ -413,6 +414,7 @@ _NON_DRIVER_FIELDS = {'cpu': '/properties/cpus',
'memory': '/properties/memory_mb',
'disk': '/properties/local_gb',
'arch': '/properties/cpu_arch',
'root_device': '/properties/root_device',
'name': '/name',
'resource_class': '/resource_class',
'kernel_id': '/driver_info/deploy_kernel',
@ -444,9 +446,8 @@ def _update_or_register_ironic_node(node, node_map, client):
for key, value in patched.items():
if key == 'uuid':
continue # not needed during update
node_patch.append({'path': key,
'value': six.text_type(value),
'op': 'add'})
node_patch.append({'path': key, 'value': value, 'op': 'add'})
ironic_node = client.node.update(node_uuid, node_patch)
else:
ironic_node = register_ironic_node(node, client)
@ -555,6 +556,13 @@ def validate_nodes(nodes_list):
failures.append(
(index, 'Invalid capabilities: %s' % node.get('capabilities')))
if node.get('root_device') is not None:
if not isinstance(node['root_device'], dict):
failures.append(
(index,
'Invalid root device: expected dict, got %s' %
node['root_device']))
for field in node:
converted = handler.convert_key(field)
if (converted is None and field not in _NON_DRIVER_FIELDS and