Example #1
0
    def patch(self, uuid, patch):
        """Update an existing chassis."""
        chassis = objects.Chassis.get_by_uuid(pecan.request.context, uuid)
        chassis_dict = chassis.as_dict()

        utils.validate_patch(patch)
        try:
            patched_chassis = jsonpatch.apply_patch(chassis_dict,
                                                    jsonpatch.JsonPatch(patch))
        except jsonpatch.JsonPatchException as e:
            LOG.exception(e)
            raise wsme.exc.ClientSideError(_("Patching Error: %s") % e)

        defaults = objects.Chassis.get_defaults()
        for key in defaults:
            # Internal values that shouldn't be part of the patch
            if key in ['id', 'updated_at', 'created_at']:
                continue

            # In case of a remove operation, add the missing fields back
            # to the document with their default value
            if key in chassis_dict and key not in patched_chassis:
                patched_chassis[key] = defaults[key]

            # Update only the fields that have changed
            if chassis[key] != patched_chassis[key]:
                chassis[key] = patched_chassis[key]

        chassis.save()
        return Chassis.convert_with_links(chassis)
Example #2
0
    def patch(self, uuid, patch):
        """Update an existing node."""
        if self._from_chassis:
            raise exception.OperationNotPermitted

        node = objects.Node.get_by_uuid(pecan.request.context, uuid)
        node_dict = node.as_dict()

        utils.validate_patch(patch)
        patch_obj = jsonpatch.JsonPatch(patch)

        # Prevent states from being updated
        state_rel_path = ['/power_state', '/target_power_state',
                          '/provision_state', '/target_provision_state']
        if any(p['path'] in state_rel_path for p in patch_obj):
            raise wsme.exc.ClientSideError(_("Changing states is not allowed "
                                             "here; You must use the "
                                             "nodes/%s/state interface.")
                                             % uuid)

        # Prevent node from being updated when there's a state
        # change in progress
        if any(node.get(tgt) for tgt in ["target_power_state",
                                         "target_provision_state"]):
            raise wsme.exc.ClientSideError(_("Can not update node %s while "
                                             "a state transition is in "
                                             "progress.") % uuid,
                                             status_code=409)

        try:
            patched_node = jsonpatch.apply_patch(node_dict, patch_obj)
        except jsonpatch.JsonPatchException as e:
            LOG.exception(e)
            raise wsme.exc.ClientSideError(_("Patching Error: %s") % e)

        try:
            self. _convert_chassis_uuid_to_id(patched_node)
            defaults = objects.Node.get_defaults()
            for key in defaults:
                # Internal values that shouldn't be part of the patch
                if key in ['id', 'updated_at', 'created_at']:
                    continue

                # In case of a remove operation, add the missing fields back
                # to the document with their default value
                if key in node_dict and key not in patched_node:
                    patched_node[key] = defaults[key]

                # Update only the fields that have changed
                if node[key] != patched_node[key]:
                    node[key] = patched_node[key]

            node = pecan.request.rpcapi.update_node(pecan.request.context,
                                                    node)

        except exception.IronicException as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(e)

        return Node.convert_with_links(node)
Example #3
0
    def patch(self, uuid, patch):
        """Update an existing port."""
        if self._from_nodes:
            raise exception.OperationNotPermitted

        port = objects.Port.get_by_uuid(pecan.request.context, uuid)
        port_dict = port.as_dict()

        api_utils.validate_patch(patch)

        try:
            patched_port = jsonpatch.apply_patch(port_dict,
                                                 jsonpatch.JsonPatch(patch))
        except jsonpatch.JsonPatchException as e:
            LOG.exception(e)
            raise wsme.exc.ClientSideError(_("Patching Error: %s") % e)

        # Required fields
        missing_attr = [attr for attr in ['address', 'node_id']
                        if attr not in patched_port]
        if missing_attr:
            msg = _("Attribute(s): %s can not be removed")
            raise wsme.exc.ClientSideError(msg % ', '.join(missing_attr))

        if port_dict['address'] != patched_port['address']:
            self._check_address(patched_port)

        self._convert_node_uuid_to_id(patched_port)

        defaults = objects.Port.get_defaults()
        for key in defaults:
            # Internal values that shouldn't be part of the patch
            if key in ['id', 'updated_at', 'created_at']:
                continue

            # In case of a remove operation, add the missing fields back
            # to the document with their default value
            if key in port_dict and key not in patched_port:
                patched_port[key] = defaults[key]

            # Update only the fields that have changed
            if port[key] != patched_port[key]:
                port[key] = patched_port[key]

        port.save()
        return Port.convert_with_links(port)
Example #4
0
    def test_validate_patch(self):
        patch = [{'op': 'remove', 'value': 'bar', 'path': '/foo'}]
        utils.validate_patch(patch)

        patch = [{'op': 'add', 'value': 'bar', 'path': '/extra/foo'}]
        utils.validate_patch(patch)

        patch = [{'op': 'replace', 'value': 'bar', 'path': '/foo'}]
        utils.validate_patch(patch)
Example #5
0
    def patch(self, uuid, patch):
        """Update an existing node.

        TODO(deva): add exception handling
        """
        node = objects.Node.get_by_uuid(pecan.request.context, uuid)
        node_dict = node.as_dict()

        utils.validate_patch(patch)
        patch_obj = jsonpatch.JsonPatch(patch)

        # Prevent states from being updated
        state_rel_path = ['/power_state', '/target_power_state',
                          '/provision_state', '/target_provision_state']
        if any(p['path'] in state_rel_path for p in patch_obj):
            raise wsme.exc.ClientSideError(_("Changing states is not allowed "
                                             "here; You must use the "
                                             "nodes/%s/state interface.")
                                             % uuid)

        # Prevent node from being updated when there's a state
        # change in progress
        if any(node.get(tgt) for tgt in ["target_power_state",
                                         "target_provision_state"]):
            raise wsme.exc.ClientSideError(_("Can not update node %s because "
                                             "a state change is already in "
                                             "progress.") % uuid)

        try:
            patched_node = jsonpatch.apply_patch(node_dict, patch_obj)
        except jsonpatch.JsonPatchException as e:
            LOG.exception(e)
            raise wsme.exc.ClientSideError(_("Patching Error: %s") % e)

        response = wsme.api.Response(Node(), status_code=200)
        try:
            defaults = objects.Node.get_defaults()
            for key in defaults:
                # Internal values that shouldn't be part of the patch
                if key in ['id', 'updated_at', 'created_at']:
                    continue

                # In case of a remove operation, add the missing fields back
                # to the document with their default value
                if key in node_dict and key not in patched_node:
                    patched_node[key] = defaults[key]

                # Update only the fields that have changed
                if node[key] != patched_node[key]:
                    node[key] = patched_node[key]

            node = pecan.request.rpcapi.update_node(pecan.request.context,
                                                    node)
            response.obj = node
        except exception.InvalidParameterValue:
            response.status_code = 400
        except exception.NodeInWrongPowerState:
            response.status_code = 409
        except exception.IronicException as e:
            LOG.exception(e)
            response.status_code = 500

        # TODO(deva): return the response object instead of raising
        #             after wsme 0.5b3 is released
        if response.status_code not in [200, 202]:
            raise wsme.exc.ClientSideError(_(
                    "Error updating node %s") % uuid)

        return Node.convert_with_links(response.obj)