Enable removing name when updating node

Name is an optional property and should be removable(set back to None).
Enable removing name when updating node with 'remove name' argument.
Also add test cases for that.

Change-Id: Ie89b6bd80ac773b357861ca8dc77f72fdc137aed
Closes-Bug: #1533248
This commit is contained in:
Kan 2016-01-14 06:12:49 +00:00
parent 36970f97f9
commit 47e18981b4
5 changed files with 49 additions and 13 deletions

View File

@ -1042,12 +1042,11 @@ class NodesController(rest.RestController):
:raises: exception.NotAcceptable :raises: exception.NotAcceptable
:raises: wsme.exc.ClientSideError :raises: wsme.exc.ClientSideError
""" """
if name: if not api_utils.allow_node_logical_names():
if not api_utils.allow_node_logical_names(): raise exception.NotAcceptable()
raise exception.NotAcceptable() if not api_utils.is_valid_node_name(name):
if not api_utils.is_valid_node_name(name): raise wsme.exc.ClientSideError(
raise wsme.exc.ClientSideError( error_msg, status_code=http_client.BAD_REQUEST)
error_msg, status_code=http_client.BAD_REQUEST)
def _update_changed_fields(self, node, rpc_node): def _update_changed_fields(self, node, rpc_node):
"""Update rpc_node based on changed fields in a node. """Update rpc_node based on changed fields in a node.
@ -1220,9 +1219,10 @@ class NodesController(rest.RestController):
e.code = http_client.BAD_REQUEST e.code = http_client.BAD_REQUEST
raise e raise e
error_msg = _("Cannot create node with invalid name " if node.name:
"%(name)s") % {'name': node.name} error_msg = _("Cannot create node with invalid name "
self._check_name_acceptable(node.name, error_msg) "%(name)s") % {'name': node.name}
self._check_name_acceptable(node.name, error_msg)
node.provision_state = api_utils.initial_node_provision_state() node.provision_state = api_utils.initial_node_provision_state()
new_node = objects.Node(pecan.request.context, new_node = objects.Node(pecan.request.context,
@ -1270,9 +1270,11 @@ class NodesController(rest.RestController):
msg % node_ident, status_code=http_client.CONFLICT) msg % node_ident, status_code=http_client.CONFLICT)
name = api_utils.get_patch_value(patch, '/name') name = api_utils.get_patch_value(patch, '/name')
error_msg = _("Node %(node)s: Cannot change name to invalid " if name:
"name '%(name)s'") % {'node': node_ident, 'name': name} error_msg = _("Node %(node)s: Cannot change name to invalid "
self._check_name_acceptable(name, error_msg) "name '%(name)s'") % {'node': node_ident,
'name': name}
self._check_name_acceptable(name, error_msg)
try: try:
node_dict = rpc_node.as_dict() node_dict = rpc_node.as_dict()
# NOTE(lucasagomes): # NOTE(lucasagomes):

View File

@ -68,7 +68,7 @@ def apply_jsonpatch(doc, patch):
def get_patch_value(patch, path): def get_patch_value(patch, path):
for p in patch: for p in patch:
if p['path'] == path: if p['path'] == path and p['op'] != 'remove':
return p['value'] return p['value']

View File

@ -1276,6 +1276,18 @@ class TestPatch(test_api_base.BaseApiTest):
self.assertEqual(http_client.CONFLICT, response.status_code) self.assertEqual(http_client.CONFLICT, response.status_code)
self.assertTrue(response.json['error_message']) self.assertTrue(response.json['error_message'])
@mock.patch.object(api_node.NodesController, '_check_name_acceptable')
def test_patch_name_remove_ok(self, cna_mock):
self.mock_update_node.return_value = self.node
response = self.patch_json('/nodes/%s' % self.node.uuid,
[{'path': '/name',
'op': 'remove'}],
headers={api_base.Version.string:
"1.5"})
self.assertEqual('application/json', response.content_type)
self.assertEqual(http_client.OK, response.status_code)
self.assertFalse(cna_mock.called)
@mock.patch.object(api_utils, 'get_rpc_node') @mock.patch.object(api_utils, 'get_rpc_node')
def test_patch_update_drive_console_enabled(self, mock_rpc_node): def test_patch_update_drive_console_enabled(self, mock_rpc_node):
self.node.console_enabled = True self.node.console_enabled = True

View File

@ -56,6 +56,24 @@ class TestApiUtils(base.TestCase):
utils.validate_sort_dir, utils.validate_sort_dir,
'fake-sort') 'fake-sort')
def test_get_patch_value_no_path(self):
patch = [{'path': '/name', 'op': 'update', 'value': 'node-0'}]
path = '/invalid'
value = utils.get_patch_value(patch, path)
self.assertIsNone(value)
def test_get_patch_value_remove(self):
patch = [{'path': '/name', 'op': 'remove'}]
path = '/name'
value = utils.get_patch_value(patch, path)
self.assertIsNone(value)
def test_get_patch_value_success(self):
patch = [{'path': '/name', 'op': 'replace', 'value': 'node-x'}]
path = '/name'
value = utils.get_patch_value(patch, path)
self.assertEqual('node-x', value)
def test_check_for_invalid_fields(self): def test_check_for_invalid_fields(self):
requested = ['field_1', 'field_3'] requested = ['field_1', 'field_3']
supported = ['field_1', 'field_2', 'field_3'] supported = ['field_1', 'field_2', 'field_3']

View File

@ -0,0 +1,4 @@
---
fixes:
- Fixes an issue that prevented the node name to be
removed as part of the node update.