# keystone.common.resource_options.options.immutable

# Source code for keystone.common.resource_options.options.immutable

    # Licensed under the Apache License, Version 2.0 (the "License"); you may
    # not use this file except in compliance with the License. You may obtain
    # a copy of the License at
    #
    # http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    # License for the specific language governing permissions and limitations
    # under the License.

    # Implement the "Immutable" resource option
    from keystone.common.resource_options import core as ro_core
    from keystone.common.validation import parameter_types
    from keystone import exception

    IMMUTABLE_OPT = ro_core.ResourceOption(
        option_id='IMMU',
        option_name='immutable',
        validator=ro_core.boolean_validator,
        json_schema_validation=parameter_types.boolean,
    )

    def check_resource_immutable(resource_ref):
        """Check to see if a resource is immutable.

        :param resource_ref: a dict reference of a resource to inspect
        """
        return resource_ref.get('options', {}).get(
            IMMUTABLE_OPT.option_name, False
        )

    def check_immutable_update(
        original_resource_ref, new_resource_ref, type, resource_id
    ):
        """Check if an update is allowed to an immutable resource.

        Valid cases where an update is allowed:

            * Resource is not immutable
            * Resource is immutable, and update to set immutable to False or None

        :param original_resource_ref: a dict resource reference representing
                                      the current resource
        :param new_resource_ref: a dict reference of the updates to perform
        :param type: the resource type, e.g. 'project'
        :param resource_id: the id of the resource (e.g. project['id']),
                            usually a UUID
        :raises: ResourceUpdateForbidden
        """
        immutable = check_resource_immutable(original_resource_ref)
        if immutable:
            new_options = new_resource_ref.get('options', {})
            if type == "domain":
                if (
                    new_resource_ref.get("is_domain", False) == True
                    and not new_resource_ref.get("domain_id")
                    and not new_resource_ref.get("parent_id")
                ):
                    # To keep next check happy - reject certain props for the domain set by default in
                    # `get_project_from_domain` if those ARE default
                    new_resource_ref.pop("is_domain")
                    new_resource_ref.pop("domain_id")
                    new_resource_ref.pop("parent_id")
            # If resource is currently immutable - raise error in attempt to
            # update more then 1 property while making resource mutable
            # (first make mutable then update rest)
            if (
                (len(new_resource_ref.keys()) > 1)
                or (IMMUTABLE_OPT.option_name not in new_options)
                or (new_options[IMMUTABLE_OPT.option_name] not in (False, None))
            ):
                raise exception.ResourceUpdateForbidden(
                    type=type, resource_id=resource_id
                )

    def check_immutable_delete(resource_ref, resource_type, resource_id):
        """Check if a delete is allowed on a resource.

        :param resource_ref: dict reference of the resource
        :param resource_type: resource type (str) e.g. 'project'
        :param resource_id: id of the resource (str) e.g. project['id']
        :raises: ResourceDeleteForbidden
        """
        if check_resource_immutable(resource_ref):
            raise exception.ResourceDeleteForbidden(
                type=resource_type, resource_id=resource_id
            )

this page last updated: 2026-06-11 21:50:20

Except where otherwise noted, this document is licensed under Creative Commons Attribution 3.0 License. See all OpenStack Legal Documents.

found an error? report a bug