Reset parent_node values to uuids instead of names

So, I got myself nice and confused with testing parent_node logic
when I used a name, but the ironic internals are modeled around
queries involving UUID matching.

We now identify names, and reset the values to be a UUID.

Change-Id: I46ece586c254c58b80723bc905cad3144691fc5d
This commit is contained in:
Julia Kreger 2023-07-26 12:52:32 -07:00
parent 81b35931d4
commit d1ca14289e
3 changed files with 51 additions and 5 deletions

View File

@ -2695,6 +2695,13 @@ class NodesController(rest.RestController):
chassis = _replace_chassis_uuid_with_id(node)
chassis_uuid = chassis and chassis.uuid or None
if ('parent_node' in node
and not uuidutils.is_uuid_like(node['parent_node'])):
parent_node = api_utils.check_node_policy_and_retrieve(
'baremetal:node:get', node['parent_node'])
node['parent_node'] = parent_node.uuid
new_node = objects.Node(context, **node)
try:
@ -2721,6 +2728,7 @@ class NodesController(rest.RestController):
return api_node
def _validate_patch(self, patch, reset_interfaces):
corrected_values = {}
if self.from_chassis:
raise exception.OperationNotPermitted()
@ -2751,17 +2759,21 @@ class NodesController(rest.RestController):
for network_data in network_data_fields:
validate_network_data(network_data)
parent_node = api_utils.get_patch_values(patch, '/parent_node')
if parent_node:
# At this point, if there *is* a parent_node, there is a value
# in the patch value list.
try:
# Verify we can see the parent node
api_utils.check_node_policy_and_retrieve(
req_parent_node = api_utils.check_node_policy_and_retrieve(
'baremetal:node:get', parent_node[0])
# If we can't see the node, an exception gets raised.
except Exception:
msg = _("Unable to apply the requested parent_node. "
"Requested value was invalid.")
raise exception.Invalid(msg)
corrected_values['parent_node'] = req_parent_node.uuid
return corrected_values
def _authorize_patch_and_get_node(self, node_ident, patch):
# deal with attribute-specific policy rules
@ -2843,7 +2855,7 @@ class NodesController(rest.RestController):
api_utils.allow_reset_interfaces()):
raise exception.NotAcceptable()
self._validate_patch(patch, reset_interfaces)
corrected_values = self._validate_patch(patch, reset_interfaces)
context = api.request.context
rpc_node = self._authorize_patch_and_get_node(node_ident, patch)
@ -2899,7 +2911,6 @@ class NodesController(rest.RestController):
msg, status_code=http_client.CONFLICT)
except exception.AllocationNotFound:
pass
names = api_utils.get_patch_values(patch, '/name')
if len(names):
error_msg = (_("Node %s: Cannot change name to invalid name ")
@ -2915,6 +2926,12 @@ class NodesController(rest.RestController):
node_dict['chassis_uuid'] = _get_chassis_uuid(rpc_node)
node_dict = api_utils.apply_jsonpatch(node_dict, patch)
if corrected_values:
# If we determined in our schema validation that someone
# provided non-fatal, but incorrect input, that we correct
# it here from the output returned from validation.
for key in corrected_values.keys():
node_dict[key] = corrected_values[key]
api_utils.patched_validate_with_schema(
node_dict, node_patch_schema(), node_patch_validator)
@ -2942,7 +2959,6 @@ class NodesController(rest.RestController):
new_node = api.request.rpcapi.update_node(context,
rpc_node, topic,
reset_interfaces)
api_node = node_convert_with_links(new_node)
chassis_uuid = api_node.get('chassis_uuid')
notify.emit_end_notification(context, new_node, 'update',

View File

@ -8419,6 +8419,16 @@ class TestNodeParentNodePost(test_api_base.BaseApiTest):
'/nodes', ndict, expect_errors=True, headers=headers)
self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_int)
def test_create_node_with_named_parent_node_succeeds(self):
ndict = test_api_utils.post_get_test_node(
uuid=uuidutils.generate_uuid())
ndict['parent_node'] = 'din'
headers = {api_base.Version.string: '1.83'}
response = self.post_json('/nodes', ndict, expect_errors=True,
headers=headers)
self.assertEqual(http_client.CREATED, response.status_int)
self.assertEqual(self.node.uuid, response.json['parent_node'])
class TestNodeParentNodePatch(test_api_base.BaseApiTest):
def setUp(self):
@ -8472,6 +8482,20 @@ class TestNodeParentNodePatch(test_api_base.BaseApiTest):
self.mock_update_node.assert_not_called()
self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_code)
def test_node_add_parent_node_not_uuid(self):
headers = {api_base.Version.string: '1.83'}
body = [{
'path': '/parent_node',
'value': 'djarin',
'op': 'add',
}]
self.patch_json('/nodes/%s' % self.child_node.uuid,
body, expect_errors=True, headers=headers)
self.mock_update_node.assert_called_once()
test_node = self.mock_update_node.call_args.args[2]
self.assertEqual(self.node.uuid, test_node.parent_node)
def test_node_remove_parent(self):
self.mock_update_node.return_value = self.node
(self

View File

@ -0,0 +1,6 @@
---
fixes:
- |
The ``parent_node`` field, a newly added API field, has been constrained
to store UUIDs over the names of nodes. When names are used, the value is
changed to the UUID of the node.