def test_is_path_removed_similar_subpath(self): patch = [{ 'path': '/local_link_connection_info/switch_id', 'op': 'remove' }] path = '/local_link_connection' value = utils.is_path_removed(patch, path) self.assertFalse(value)
def patch(self, port_uuid, patch): """Update an existing port. :param port_uuid: UUID of a port. :param patch: a json PATCH document to apply to this port. :raises: NotAcceptable """ cdict = pecan.request.context.to_dict() policy.authorize('baremetal:port:update', cdict, cdict) if self.parent_node_ident: raise exception.OperationNotPermitted() if not api_utils.allow_port_advanced_net_fields(): for field in self.advanced_net_fields: field_path = '/%s' % field if (api_utils.get_patch_values(patch, field_path) or api_utils.is_path_removed(patch, field_path)): raise exception.NotAcceptable() rpc_port = objects.Port.get_by_uuid(pecan.request.context, port_uuid) try: port_dict = rpc_port.as_dict() # NOTE(lucasagomes): # 1) Remove node_id because it's an internal value and # not present in the API object # 2) Add node_uuid port_dict['node_uuid'] = port_dict.pop('node_id', None) port = Port(**api_utils.apply_jsonpatch(port_dict, patch)) except api_utils.JSONPATCH_EXCEPTIONS as e: raise exception.PatchError(patch=patch, reason=e) # Update only the fields that have changed for field in objects.Port.fields: try: patch_val = getattr(port, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if rpc_port[field] != patch_val: rpc_port[field] = patch_val rpc_node = objects.Node.get_by_id(pecan.request.context, rpc_port.node_id) topic = pecan.request.rpcapi.get_topic_for(rpc_node) new_port = pecan.request.rpcapi.update_port(pecan.request.context, rpc_port, topic) return Port.convert_with_links(new_port)
def patch(self, port_uuid, patch): """Update an existing port. :param port_uuid: UUID of a port. :param patch: a json PATCH document to apply to this port. :raises: NotAcceptable """ if self.from_nodes: raise exception.OperationNotPermitted() if not api_utils.allow_port_advanced_net_fields(): for field in self.advanced_net_fields: field_path = '/%s' % field if (api_utils.get_patch_values(patch, field_path) or api_utils.is_path_removed(patch, field_path)): raise exception.NotAcceptable() rpc_port = objects.Port.get_by_uuid(pecan.request.context, port_uuid) try: port_dict = rpc_port.as_dict() # NOTE(lucasagomes): # 1) Remove node_id because it's an internal value and # not present in the API object # 2) Add node_uuid port_dict['node_uuid'] = port_dict.pop('node_id', None) port = Port(**api_utils.apply_jsonpatch(port_dict, patch)) except api_utils.JSONPATCH_EXCEPTIONS as e: raise exception.PatchError(patch=patch, reason=e) # Update only the fields that have changed for field in objects.Port.fields: try: patch_val = getattr(port, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if rpc_port[field] != patch_val: rpc_port[field] = patch_val rpc_node = objects.Node.get_by_id(pecan.request.context, rpc_port.node_id) topic = pecan.request.rpcapi.get_topic_for(rpc_node) new_port = pecan.request.rpcapi.update_port( pecan.request.context, rpc_port, topic) return Port.convert_with_links(new_port)
def patch(self, port_uuid, patch): """Update an existing port. :param port_uuid: UUID of a port. :param patch: a json PATCH document to apply to this port. :raises: NotAcceptable, HTTPNotFound """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:port:update', cdict, cdict) if self.parent_node_ident or self.parent_portgroup_ident: raise exception.OperationNotPermitted() fields_to_check = set() for field in (self.advanced_net_fields + ['portgroup_uuid', 'physical_network']): field_path = '/%s' % field if (api_utils.get_patch_values(patch, field_path) or api_utils.is_path_removed(patch, field_path)): fields_to_check.add(field) self._check_allowed_port_fields(fields_to_check) rpc_port = objects.Port.get_by_uuid(context, port_uuid) try: port_dict = rpc_port.as_dict() # NOTE(lucasagomes): # 1) Remove node_id because it's an internal value and # not present in the API object # 2) Add node_uuid port_dict['node_uuid'] = port_dict.pop('node_id', None) # NOTE(vsaienko): # 1) Remove portgroup_id because it's an internal value and # not present in the API object # 2) Add portgroup_uuid port_dict['portgroup_uuid'] = port_dict.pop('portgroup_id', None) port = Port(**api_utils.apply_jsonpatch(port_dict, patch)) except api_utils.JSONPATCH_EXCEPTIONS as e: raise exception.PatchError(patch=patch, reason=e) if api_utils.is_path_removed(patch, '/portgroup_uuid'): rpc_port.portgroup_id = None # Update only the fields that have changed for field in objects.Port.fields: try: patch_val = getattr(port, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if rpc_port[field] != patch_val: rpc_port[field] = patch_val rpc_node = objects.Node.get_by_id(context, rpc_port.node_id) notify_extra = {'node_uuid': rpc_node.uuid, 'portgroup_uuid': port.portgroup_uuid} notify.emit_start_notification(context, rpc_port, 'update', **notify_extra) with notify.handle_error_notification(context, rpc_port, 'update', **notify_extra): topic = pecan.request.rpcapi.get_topic_for(rpc_node) new_port = pecan.request.rpcapi.update_port(context, rpc_port, topic) api_port = Port.convert_with_links(new_port) notify.emit_end_notification(context, new_port, 'update', **notify_extra) return api_port
def patch(self, port_uuid, patch): """Update an existing port. :param port_uuid: UUID of a port. :param patch: a json PATCH document to apply to this port. :raises: NotAcceptable, HTTPNotFound """ if self.parent_node_ident or self.parent_portgroup_ident: raise exception.OperationNotPermitted() rpc_port, rpc_node = api_utils.check_port_policy_and_retrieve( 'baremetal:port:update', port_uuid) context = api.request.context fields_to_check = set() for field in (self.advanced_net_fields + [ 'portgroup_uuid', 'physical_network', 'is_smartnic', 'local_link_connection/network_type' ]): field_path = '/%s' % field if (api_utils.get_patch_values(patch, field_path) or api_utils.is_path_removed(patch, field_path)): fields_to_check.add(field) self._check_allowed_port_fields(fields_to_check) port_dict = rpc_port.as_dict() # NOTE(lucasagomes): # 1) Remove node_id because it's an internal value and # not present in the API object # 2) Add node_uuid port_dict['node_uuid'] = port_dict.pop('node_id', None) # NOTE(vsaienko): # 1) Remove portgroup_id because it's an internal value and # not present in the API object # 2) Add portgroup_uuid port_dict['portgroup_uuid'] = port_dict.pop('portgroup_id', None) port = Port(**api_utils.apply_jsonpatch(port_dict, patch)) api_utils.handle_patch_port_like_extra_vif(rpc_port, port, patch) if api_utils.is_path_removed(patch, '/portgroup_uuid'): rpc_port.portgroup_id = None # Update only the fields that have changed for field in objects.Port.fields: try: patch_val = getattr(port, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if rpc_port[field] != patch_val: rpc_port[field] = patch_val if (rpc_node.provision_state == ir_states.INSPECTING and api_utils.allow_inspect_wait_state()): msg = _('Cannot update port "%(port)s" on "%(node)s" while it is ' 'in state "%(state)s".') % { 'port': rpc_port.uuid, 'node': rpc_node.uuid, 'state': ir_states.INSPECTING } raise exception.ClientSideError(msg, status_code=http_client.CONFLICT) notify_extra = { 'node_uuid': rpc_node.uuid, 'portgroup_uuid': port.portgroup_uuid } notify.emit_start_notification(context, rpc_port, 'update', **notify_extra) with notify.handle_error_notification(context, rpc_port, 'update', **notify_extra): topic = api.request.rpcapi.get_topic_for(rpc_node) new_port = api.request.rpcapi.update_port(context, rpc_port, topic) api_port = Port.convert_with_links(new_port) notify.emit_end_notification(context, new_port, 'update', **notify_extra) return api_port
def patch(self, port_uuid, patch): """Update an existing port. :param port_uuid: UUID of a port. :param patch: a json PATCH document to apply to this port. :raises: NotAcceptable, HTTPNotFound """ if self.parent_node_ident or self.parent_portgroup_ident: raise exception.OperationNotPermitted() api_utils.patch_validate_allowed_fields(patch, PATCH_ALLOWED_FIELDS) context = api.request.context fields_to_check = set() for field in (self.advanced_net_fields + ['portgroup_uuid', 'physical_network', 'is_smartnic', 'local_link_connection/network_type']): field_path = '/%s' % field if (api_utils.get_patch_values(patch, field_path) or api_utils.is_path_removed(patch, field_path)): fields_to_check.add(field) self._check_allowed_port_fields(fields_to_check) rpc_port, rpc_node = api_utils.check_port_policy_and_retrieve( 'baremetal:port:update', port_uuid) port_dict = rpc_port.as_dict() # NOTE(lucasagomes): # 1) Remove node_id because it's an internal value and # not present in the API object # 2) Add node_uuid port_dict.pop('node_id', None) port_dict['node_uuid'] = rpc_node.uuid # NOTE(vsaienko): # 1) Remove portgroup_id because it's an internal value and # not present in the API object # 2) Add portgroup_uuid portgroup = None if port_dict.get('portgroup_id'): portgroup = objects.Portgroup.get_by_id( context, port_dict.pop('portgroup_id')) port_dict['portgroup_uuid'] = portgroup and portgroup.uuid or None port_dict = api_utils.apply_jsonpatch(port_dict, patch) api_utils.handle_patch_port_like_extra_vif( rpc_port, port_dict['internal_info'], patch) try: if api_utils.is_path_updated(patch, '/portgroup_uuid'): if port_dict.get('portgroup_uuid'): portgroup = objects.Portgroup.get_by_uuid( context, port_dict['portgroup_uuid']) else: portgroup = None except exception.PortGroupNotFound as e: # Change error code because 404 (NotFound) is inappropriate # response for a PATCH request to change a Port e.code = http_client.BAD_REQUEST # BadRequest raise try: if port_dict['node_uuid'] != rpc_node.uuid: rpc_node = objects.Node.get( api.request.context, port_dict['node_uuid']) except exception.NodeNotFound as e: # Change error code because 404 (NotFound) is inappropriate # response for a PATCH request to change a Port e.code = http_client.BAD_REQUEST # BadRequest raise api_utils.patched_validate_with_schema( port_dict, PORT_PATCH_SCHEMA, PORT_PATCH_VALIDATOR) api_utils.patch_update_changed_fields( port_dict, rpc_port, fields=objects.Port.fields, schema=PORT_PATCH_SCHEMA, id_map={ 'node_id': rpc_node.id, 'portgroup_id': portgroup and portgroup.id or None } ) if (rpc_node.provision_state == ir_states.INSPECTING and api_utils.allow_inspect_wait_state()): msg = _('Cannot update port "%(port)s" on "%(node)s" while it is ' 'in state "%(state)s".') % {'port': rpc_port.uuid, 'node': rpc_node.uuid, 'state': ir_states.INSPECTING} raise exception.ClientSideError(msg, status_code=http_client.CONFLICT) if (api_utils.is_path_updated(patch, '/physical_network') and rpc_port['physical_network'] is not None and not rpc_port['physical_network']): raise exception.Invalid('A non-empty value is required when ' 'setting physical_network') notify_extra = {'node_uuid': rpc_node.uuid, 'portgroup_uuid': portgroup and portgroup.uuid or None} notify.emit_start_notification(context, rpc_port, 'update', **notify_extra) with notify.handle_error_notification(context, rpc_port, 'update', **notify_extra): topic = api.request.rpcapi.get_topic_for(rpc_node) new_port = api.request.rpcapi.update_port(context, rpc_port, topic) api_port = convert_with_links(new_port) notify.emit_end_notification(context, new_port, 'update', **notify_extra) return api_port
def test_is_path_removed_success(self): patch = [{"path": "/name", "op": "remove"}] path = "/name" value = utils.is_path_removed(patch, path) self.assertTrue(value)
def test_is_path_removed_subpath_success(self): patch = [{'path': '/local_link_connection/switch_id', 'op': 'remove'}] path = '/local_link_connection' value = utils.is_path_removed(patch, path) self.assertTrue(value)
def test_is_path_removed_success(self): patch = [{'path': '/name', 'op': 'remove'}] path = '/name' value = utils.is_path_removed(patch, path) self.assertTrue(value)
def test_is_path_removed_replace(self): patch = [{'path': '/name', 'op': 'replace', 'value': 'node-x'}] path = '/name' value = utils.is_path_removed(patch, path) self.assertFalse(value)
def patch(self, port_uuid, patch): """Update an existing port. :param port_uuid: UUID of a port. :param patch: a json PATCH document to apply to this port. :raises: NotAcceptable, HTTPNotFound """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:port:update', cdict, cdict) if self.parent_node_ident or self.parent_portgroup_ident: raise exception.OperationNotPermitted() fields_to_check = set() for field in (self.advanced_net_fields + ['portgroup_uuid', 'physical_network', 'is_smartnic']): field_path = '/%s' % field if (api_utils.get_patch_values(patch, field_path) or api_utils.is_path_removed(patch, field_path)): fields_to_check.add(field) self._check_allowed_port_fields(fields_to_check) rpc_port = objects.Port.get_by_uuid(context, port_uuid) port_dict = rpc_port.as_dict() # NOTE(lucasagomes): # 1) Remove node_id because it's an internal value and # not present in the API object # 2) Add node_uuid port_dict['node_uuid'] = port_dict.pop('node_id', None) # NOTE(vsaienko): # 1) Remove portgroup_id because it's an internal value and # not present in the API object # 2) Add portgroup_uuid port_dict['portgroup_uuid'] = port_dict.pop('portgroup_id', None) port = Port(**api_utils.apply_jsonpatch(port_dict, patch)) api_utils.handle_patch_port_like_extra_vif(rpc_port, port, patch) if api_utils.is_path_removed(patch, '/portgroup_uuid'): rpc_port.portgroup_id = None # Update only the fields that have changed for field in objects.Port.fields: try: patch_val = getattr(port, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if rpc_port[field] != patch_val: rpc_port[field] = patch_val rpc_node = objects.Node.get_by_id(context, rpc_port.node_id) if (rpc_node.provision_state == ir_states.INSPECTING and api_utils.allow_inspect_wait_state()): msg = _('Cannot update port "%(port)s" on "%(node)s" while it is ' 'in state "%(state)s".') % {'port': rpc_port.uuid, 'node': rpc_node.uuid, 'state': ir_states.INSPECTING} raise wsme.exc.ClientSideError(msg, status_code=http_client.CONFLICT) notify_extra = {'node_uuid': rpc_node.uuid, 'portgroup_uuid': port.portgroup_uuid} notify.emit_start_notification(context, rpc_port, 'update', **notify_extra) with notify.handle_error_notification(context, rpc_port, 'update', **notify_extra): topic = pecan.request.rpcapi.get_topic_for(rpc_node) new_port = pecan.request.rpcapi.update_port(context, rpc_port, topic) api_port = Port.convert_with_links(new_port) notify.emit_end_notification(context, new_port, 'update', **notify_extra) return api_port
def test_is_path_removed_similar_subpath(self): patch = [{"path": "/local_link_connection_info/switch_id", "op": "remove"}] path = "/local_link_connection" value = utils.is_path_removed(patch, path) self.assertFalse(value)
def test_is_path_removed_subpath_success(self): patch = [{"path": "/local_link_connection/switch_id", "op": "remove"}] path = "/local_link_connection" value = utils.is_path_removed(patch, path) self.assertTrue(value)
def test_is_path_removed_similar_subpath(self): patch = [{'path': '/local_link_connection_info/switch_id', 'op': 'remove'}] path = '/local_link_connection' value = utils.is_path_removed(patch, path) self.assertFalse(value)
def patch(self, port_uuid, patch): """Update an existing port. :param port_uuid: UUID of a port. :param patch: a json PATCH document to apply to this port. :raises: NotAcceptable, HTTPNotFound """ context = pecan.request.context cdict = context.to_policy_values() policy.authorize('baremetal:port:update', cdict, cdict) if self.parent_node_ident or self.parent_portgroup_ident: raise exception.OperationNotPermitted() fields_to_check = set() for field in (self.advanced_net_fields + ['portgroup_uuid', 'physical_network']): field_path = '/%s' % field if (api_utils.get_patch_values(patch, field_path) or api_utils.is_path_removed(patch, field_path)): fields_to_check.add(field) self._check_allowed_port_fields(fields_to_check) rpc_port = objects.Port.get_by_uuid(context, port_uuid) try: port_dict = rpc_port.as_dict() # NOTE(lucasagomes): # 1) Remove node_id because it's an internal value and # not present in the API object # 2) Add node_uuid port_dict['node_uuid'] = port_dict.pop('node_id', None) # NOTE(vsaienko): # 1) Remove portgroup_id because it's an internal value and # not present in the API object # 2) Add portgroup_uuid port_dict['portgroup_uuid'] = port_dict.pop('portgroup_id', None) port = Port(**api_utils.apply_jsonpatch(port_dict, patch)) except api_utils.JSONPATCH_EXCEPTIONS as e: raise exception.PatchError(patch=patch, reason=e) if api_utils.is_path_removed(patch, '/portgroup_uuid'): rpc_port.portgroup_id = None # Update only the fields that have changed for field in objects.Port.fields: try: patch_val = getattr(port, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if rpc_port[field] != patch_val: rpc_port[field] = patch_val rpc_node = objects.Node.get_by_id(context, rpc_port.node_id) notify_extra = { 'node_uuid': rpc_node.uuid, 'portgroup_uuid': port.portgroup_uuid } notify.emit_start_notification(context, rpc_port, 'update', **notify_extra) with notify.handle_error_notification(context, rpc_port, 'update', **notify_extra): topic = pecan.request.rpcapi.get_topic_for(rpc_node) new_port = pecan.request.rpcapi.update_port( context, rpc_port, topic) api_port = Port.convert_with_links(new_port) notify.emit_end_notification(context, new_port, 'update', **notify_extra) return api_port
def test_is_path_removed_replace(self): patch = [{"path": "/name", "op": "replace", "value": "node-x"}] path = "/name" value = utils.is_path_removed(patch, path) self.assertFalse(value)