# Buggy code
def apply_patches():
    """Apply patches to make LocalStack seamlessly interact with the moto backend.
    TODO: Eventually, these patches should be contributed to the upstream repo!"""

    # Patch S3Backend.get_key method in moto to use S3 API from LocalStack

    def get_key(self, bucket_name, key_name, version_id=None):
        s3_client = aws_stack.connect_to_service("s3")
        value = b""
        if bucket_name != BUCKET_MARKER_LOCAL:
            value = s3_client.get_object(Bucket=bucket_name, Key=key_name)[
                "Body"
            ].read()
        return s3_models.FakeKey(name=key_name, value=value)

    s3_models.S3Backend.get_key = get_key

    # Patch clean_json in moto

    def clean_json(resource_json, resources_map):
        result = clean_json_orig(resource_json, resources_map)
        if isinstance(result, BaseModel):
            if isinstance(resource_json, dict) and "Ref" in resource_json:
                entity_id = get_entity_id(result, resource_json)
                if entity_id:
                    return entity_id
                LOG.warning(
                    'Unable to resolve "Ref" attribute for: %s - %s - %s',
                    resource_json,
                    result,
                    type(result),
                )
        return result

    clean_json_orig = parsing.clean_json
    parsing.clean_json = clean_json

    # add model mappings to moto

    parsing.MODEL_MAP.update(MODEL_MAP)

    # Patch parse_and_create_resource method in moto to deploy resources in LocalStack

    def parse_and_create_resource(
        logical_id, resource_json, resources_map, region_name
    ):
        try:
            return _parse_and_create_resource(
                logical_id, resource_json, resources_map, region_name
            )
        except Exception as e:
            LOG.error(
                'Unable to parse and create resource "%s": %s %s'
                % (logical_id, e, traceback.format_exc())
            )
            raise

    def _parse_and_create_resource(
        logical_id, resource_json, resources_map, region_name
    ):
        stack_name = resources_map.get("AWS::StackName")
        resource_hash_key = (stack_name, logical_id)

        # If the current stack is being updated, avoid infinite recursion
        updating = CURRENTLY_UPDATING_RESOURCES.get(resource_hash_key)
        LOG.debug(
            "Currently updating stack resource %s/%s: %s"
            % (stack_name, logical_id, updating)
        )
        if updating:
            return None

        # parse and get final resource JSON
        resource_tuple = parsing.parse_resource(
            logical_id, resource_json, resources_map
        )
        if not resource_tuple:
            return None
        _, resource_json, _ = resource_tuple

        # add some missing default props which otherwise cause deployments to fail
        props = resource_json["Properties"] = resource_json.get("Properties") or {}
        if resource_json["Type"] == "AWS::Lambda::EventSourceMapping" and not props.get(
            "StartingPosition"
        ):
            props["StartingPosition"] = "LATEST"

        # check if this resource already exists in the resource map
        resource = resources_map._parsed_resources.get(logical_id)

        # check whether this resource needs to be deployed
        resource_wrapped = {logical_id: resource_json}
        should_be_created = template_deployer.should_be_deployed(
            logical_id, resource_wrapped, stack_name
        )
        if not should_be_created:
            # This resource is either not deployable or already exists. Check if it can be updated
            if not template_deployer.is_updateable(
                logical_id, resource_wrapped, stack_name
            ):
                LOG.debug(
                    "Resource %s need not be deployed: %s" % (logical_id, resource_json)
                )
                if resource:
                    return resource

        if not resource:
            # fix resource ARNs, make sure to convert account IDs 000000000000 to 123456789012
            resource_json_arns_fixed = clone(
                json_safe(convert_objs_to_ids(resource_json))
            )
            set_moto_account_ids(resource_json_arns_fixed)
            # create resource definition and store CloudFormation metadata in moto
            resource = parse_and_create_resource_orig(
                logical_id, resource_json_arns_fixed, resources_map, region_name
            )
            # Fix for moto which sometimes hard-codes region name as 'us-east-1'
            if hasattr(resource, "region_name") and resource.region_name != region_name:
                LOG.debug(
                    "Updating incorrect region from %s to %s"
                    % (resource.region_name, region_name)
                )
                resource.region_name = region_name

        # Apply some fixes/patches to the resource names, then deploy resource in LocalStack
        update_resource_name(resource, resource_json)
        LOG.debug("Deploying CloudFormation resource: %s" % resource_json)

        try:
            CURRENTLY_UPDATING_RESOURCES[resource_hash_key] = True
            deploy_func = (
                template_deployer.deploy_resource
                if should_be_created
                else template_deployer.update_resource
            )
            result = deploy_func(logical_id, resource_wrapped, stack_name=stack_name)
        finally:
            CURRENTLY_UPDATING_RESOURCES[resource_hash_key] = False

        if not should_be_created:
            # skip the parts below for update requests
            return resource

        def find_id(resource):
            """Find ID of the given resource."""
            for id_attr in ("Id", "id", "ResourceId", "RestApiId", "DeploymentId"):
                if id_attr in resource:
                    return resource[id_attr]

        # update resource IDs to avoid mismatch between CF moto and LocalStack backend resources
        if hasattr(resource, "id") or (
            isinstance(resource, dict) and resource.get("id")
        ):
            existing_id = resource.id if hasattr(resource, "id") else resource["id"]
            new_res_id = find_id(result)
            LOG.debug(
                "Updating resource id: %s - %s, %s - %s"
                % (existing_id, new_res_id, resource, resource_json)
            )
            if new_res_id:
                LOG.info(
                    "Updating resource ID from %s to %s (%s)"
                    % (existing_id, new_res_id, region_name)
                )
                update_resource_id(resource, new_res_id, props, region_name)
            else:
                LOG.warning(
                    "Unable to extract id for resource %s: %s" % (logical_id, result)
                )

        # update physical_resource_id field
        update_physical_resource_id(resource)

        return resource

    def update_resource_name(resource, resource_json):
        """Some resources require minor fixes in their CF resource definition
        before we can pass them on to deployment."""
        props = resource_json["Properties"] = resource_json.get("Properties") or {}
        if isinstance(resource, sfn_models.StateMachine) and not props.get(
            "StateMachineName"
        ):
            props["StateMachineName"] = resource.name

    def update_resource_id(resource, new_id, props, region_name):
        """Update and fix the ID(s) of the given resource."""

        # NOTE: this is a bit of a hack, which is required because
        # of the order of events when CloudFormation resources are created.
        # When we process a request to create a CF resource that's part of a
        # stack, say, an API Gateway Resource, then we (1) create the object
        # in memory in moto, which generates a random ID for the resource, and
        # (2) create the actual resource in the backend service using
        # template_deployer.deploy_resource(..) (see above).
        # The resource created in (2) now has a different ID than the resource
        # created in (1), which leads to downstream problems. Hence, we need
        # the logic below to reconcile the ids, i.e., apply IDs from (2) to (1).

        backend = apigw_models.apigateway_backends[region_name]
        if isinstance(resource, apigw_models.RestAPI):
            backend.apis.pop(resource.id, None)
            backend.apis[new_id] = resource
            # We also need to fetch the resources to replace the root resource
            # that moto automatically adds to newly created RestAPI objects
            client = aws_stack.connect_to_service("apigateway")
            resources = client.get_resources(restApiId=new_id, limit=500)["items"]
            # make sure no resources have been added in addition to the root /
            assert len(resource.resources) == 1
            resource.resources = {}
            for res in resources:
                res_path_part = res.get("pathPart") or res.get("path")
                child = resource.add_child(res_path_part, res.get("parentId"))
                resource.resources.pop(child.id)
                child.id = res["id"]
                child.api_id = new_id
                resource.resources[child.id] = child
            resource.id = new_id
        elif isinstance(resource, apigw_models.Resource):
            api_id = props["RestApiId"]
            backend.apis[api_id].resources.pop(resource.id, None)
            backend.apis[api_id].resources[new_id] = resource
            resource.id = new_id
        elif isinstance(resource, apigw_models.Deployment):
            api_id = props["RestApiId"]
            backend.apis[api_id].deployments.pop(resource["id"], None)
            backend.apis[api_id].deployments[new_id] = resource
            resource["id"] = new_id
        else:
            LOG.warning(
                "Unexpected resource type when updating ID: %s" % type(resource)
            )

    def update_physical_resource_id(resource):
        phys_res_id = getattr(resource, "physical_resource_id", None)
        if not phys_res_id:
            if isinstance(resource, lambda_models.LambdaFunction):
                func_arn = aws_stack.lambda_function_arn(resource.function_name)
                resource.function_arn = resource.physical_resource_id = func_arn
            elif isinstance(resource, sfn_models.StateMachine):
                sm_arn = aws_stack.state_machine_arn(resource.name)
                resource.physical_resource_id = sm_arn
            elif isinstance(resource, service_models.StepFunctionsActivity):
                act_arn = aws_stack.stepfunctions_activity_arn(
                    resource.params.get("Name")
                )
                resource.physical_resource_id = act_arn
            else:
                LOG.warning(
                    "Unable to determine physical_resource_id for resource %s"
                    % type(resource)
                )

    parse_and_create_resource_orig = parsing.parse_and_create_resource
    parsing.parse_and_create_resource = parse_and_create_resource

    # Patch CloudFormation parse_output(..) method to fix a bug in moto

    def parse_output(output_logical_id, output_json, resources_map):
        try:
            return parse_output_orig(output_logical_id, output_json, resources_map)
        except KeyError:
            output = Output()
            output.key = output_logical_id
            output.value = None
            output.description = output_json.get("Description")
            return output

    parse_output_orig = parsing.parse_output
    parsing.parse_output = parse_output

    # Patch DynamoDB get_cfn_attribute(..) method in moto

    def DynamoDB_Table_get_cfn_attribute(self, attribute_name):
        try:
            return DynamoDB_Table_get_cfn_attribute_orig(self, attribute_name)
        except Exception:
            if attribute_name == "Arn":
                return aws_stack.dynamodb_table_arn(table_name=self.name)
            raise

    DynamoDB_Table_get_cfn_attribute_orig = dynamodb_models.Table.get_cfn_attribute
    dynamodb_models.Table.get_cfn_attribute = DynamoDB_Table_get_cfn_attribute

    # Patch DynamoDB get_cfn_attribute(..) method in moto

    def DynamoDB2_Table_get_cfn_attribute(self, attribute_name):
        if attribute_name == "Arn":
            return aws_stack.dynamodb_table_arn(table_name=self.name)
        elif attribute_name == "StreamArn":
            if (self.stream_specification or {}).get("StreamEnabled"):
                return aws_stack.dynamodb_stream_arn(self.name, "latest")
            return None
        raise UnformattedGetAttTemplateException()

    dynamodb2_models.Table.get_cfn_attribute = DynamoDB2_Table_get_cfn_attribute

    # Patch SQS get_cfn_attribute(..) method in moto

    def SQS_Queue_get_cfn_attribute(self, attribute_name):
        if attribute_name == "Arn":
            return aws_stack.sqs_queue_arn(queue_name=self.name)
        return SQS_Queue_get_cfn_attribute_orig(self, attribute_name)

    SQS_Queue_get_cfn_attribute_orig = sqs_models.Queue.get_cfn_attribute
    sqs_models.Queue.get_cfn_attribute = SQS_Queue_get_cfn_attribute

    # Patch SQS physical_resource_id(..) method in moto

    @property
    def SQS_Queue_physical_resource_id(self):
        result = SQS_Queue_physical_resource_id_orig.fget(self)
        if "://" not in result:
            # convert ID to queue URL
            return aws_stack.get_sqs_queue_url(result)
        return result

    SQS_Queue_physical_resource_id_orig = sqs_models.Queue.physical_resource_id
    sqs_models.Queue.physical_resource_id = SQS_Queue_physical_resource_id

    # Patch Lambda get_cfn_attribute(..) method in moto

    def Lambda_Function_get_cfn_attribute(self, attribute_name):
        try:
            if attribute_name == "Arn":
                return self.function_arn
            return Lambda_Function_get_cfn_attribute_orig(self, attribute_name)
        except Exception:
            if attribute_name in ("Name", "FunctionName"):
                return self.function_name
            raise

    Lambda_Function_get_cfn_attribute_orig = (
        lambda_models.LambdaFunction.get_cfn_attribute
    )
    lambda_models.LambdaFunction.get_cfn_attribute = Lambda_Function_get_cfn_attribute

    # Patch DynamoDB get_cfn_attribute(..) method in moto

    def DynamoDB_Table_get_cfn_attribute(self, attribute_name):
        try:
            if attribute_name == "StreamArn":
                streams = aws_stack.connect_to_service("dynamodbstreams").list_streams(
                    TableName=self.name
                )["Streams"]
                return streams[0]["StreamArn"] if streams else None
            return DynamoDB_Table_get_cfn_attribute_orig(self, attribute_name)
        except Exception as e:
            LOG.warning(
                'Unable to get attribute "%s" from resource %s: %s'
                % (attribute_name, type(self), e)
            )
            raise

    DynamoDB_Table_get_cfn_attribute_orig = dynamodb_models.Table.get_cfn_attribute
    dynamodb_models.Table.get_cfn_attribute = DynamoDB_Table_get_cfn_attribute

    # Patch IAM get_cfn_attribute(..) method in moto

    def IAM_Role_get_cfn_attribute(self, attribute_name):
        try:
            return IAM_Role_get_cfn_attribute_orig(self, attribute_name)
        except Exception:
            if attribute_name == "Arn":
                return aws_stack.role_arn(self.name)
            raise

    IAM_Role_get_cfn_attribute_orig = iam_models.Role.get_cfn_attribute
    iam_models.Role.get_cfn_attribute = IAM_Role_get_cfn_attribute

    # Patch LambdaFunction create_from_cloudformation_json(..) method in moto

    @classmethod
    def Lambda_create_from_cloudformation_json(
        cls, resource_name, cloudformation_json, region_name
    ):
        resource_name = (
            cloudformation_json.get("Properties", {}).get("FunctionName")
            or resource_name
        )
        return Lambda_create_from_cloudformation_json_orig(
            resource_name, cloudformation_json, region_name
        )

    Lambda_create_from_cloudformation_json_orig = (
        lambda_models.LambdaFunction.create_from_cloudformation_json
    )
    lambda_models.LambdaFunction.create_from_cloudformation_json = (
        Lambda_create_from_cloudformation_json
    )

    # add CloudWatch types

    parsing.MODEL_MAP["AWS::ApiGateway::Deployment"] = apigw_models.Deployment
    parsing.MODEL_MAP["AWS::ApiGateway::Method"] = apigw_models.Method
    parsing.MODEL_MAP["AWS::ApiGateway::Resource"] = apigw_models.Resource
    parsing.MODEL_MAP["AWS::ApiGateway::RestApi"] = apigw_models.RestAPI
    parsing.MODEL_MAP["AWS::StepFunctions::StateMachine"] = sfn_models.StateMachine

    @classmethod
    def RestAPI_create_from_cloudformation_json(
        cls, resource_name, cloudformation_json, region_name
    ):
        props = cloudformation_json["Properties"]
        name = props["Name"]
        region_name = props.get("Region") or aws_stack.get_region()
        description = props.get("Description") or ""
        id = props.get("Id") or short_uid()
        return apigw_models.RestAPI(id, region_name, name, description)

    def RestAPI_get_cfn_attribute(self, attribute_name):
        if attribute_name == "Id":
            return self.id
        if attribute_name == "Region":
            return self.region_name
        if attribute_name == "Name":
            return self.name
        if attribute_name == "Description":
            return self.description
        if attribute_name == "RootResourceId":
            for id, resource in self.resources.items():
                if resource.parent_id is None:
                    return resource.id
            return None
        raise UnformattedGetAttTemplateException()

    @classmethod
    def Deployment_create_from_cloudformation_json(
        cls, resource_name, cloudformation_json, region_name
    ):
        props = cloudformation_json["Properties"]
        name = props["StageName"]
        deployment_id = props.get("Id") or short_uid()
        description = props.get("Description") or ""
        return apigw_models.Deployment(deployment_id, name, description)

    @classmethod
    def Resource_create_from_cloudformation_json(
        cls, resource_name, cloudformation_json, region_name
    ):
        props = cloudformation_json["Properties"]
        region_name = props.get("Region") or aws_stack.get_region()
        path_part = props.get("PathPart")
        api_id = props.get("RestApiId")
        parent_id = props.get("ParentId")
        id = props.get("Id") or short_uid()
        return apigw_models.Resource(id, region_name, api_id, path_part, parent_id)

    @classmethod
    def Method_create_from_cloudformation_json(
        cls, resource_name, cloudformation_json, region_name
    ):
        props = cloudformation_json["Properties"]
        method_type = props.get("HttpMethod")
        authorization_type = props.get("AuthorizationType")
        return apigw_models.Method(method_type, authorization_type)

    apigw_models.RestAPI.create_from_cloudformation_json = (
        RestAPI_create_from_cloudformation_json
    )
    apigw_models.RestAPI.get_cfn_attribute = RestAPI_get_cfn_attribute
    apigw_models.Deployment.create_from_cloudformation_json = (
        Deployment_create_from_cloudformation_json
    )
    apigw_models.Resource.create_from_cloudformation_json = (
        Resource_create_from_cloudformation_json
    )
    apigw_models.Method.create_from_cloudformation_json = (
        Method_create_from_cloudformation_json
    )
    # TODO: add support for AWS::ApiGateway::Model, AWS::ApiGateway::RequestValidator, ...

    # fix AttributeError in moto's CloudFormation describe_stack_resource

    def describe_stack_resource(self):
        stack_name = self._get_param("StackName")
        stack = self.cloudformation_backend.get_stack(stack_name)
        logical_resource_id = self._get_param("LogicalResourceId")

        for stack_resource in stack.stack_resources:
            # Note: Line below has been patched
            # if stack_resource.logical_resource_id == logical_resource_id:
            if (
                stack_resource
                and stack_resource.logical_resource_id == logical_resource_id
            ):
                resource = stack_resource
                break
        else:
            raise ValidationError(logical_resource_id)

        template = self.response_template(
            responses.DESCRIBE_STACK_RESOURCE_RESPONSE_TEMPLATE
        )
        return template.render(stack=stack, resource=resource)

    responses.CloudFormationResponse.describe_stack_resource = describe_stack_resource


# Traceback (botocore.errorfactory.ResourceAlreadyExistsException)
{"Type": "Server", "message": "Error executing Lambda function arn:aws:lambda:ap-northeast-1:000000000000:function:service-stage-functionName: An error occurred (ResourceAlreadyExistsException) when calling the CreateLogGroup operation: The specified log group already exists Traceback (most recent call last):\n
File \"/opt/code/localstack/localstack/services/awslambda/lambda_api.py\", line 338, in run_lambda\n
event, context=context, version=version, asynchronous=asynchronous)\n
File \"/opt/code/localstack/localstack/services/awslambda/lambda_executors.py\", line 81, in execute\n
return do_execute()\n File \"/opt/code/localstack/localstack/services/awslambda/lambda_executors.py\", line 70, in do_execute\n self._store_logs(func_details, log_output, invocation_time)\n
File \"/opt/code/localstack/localstack/services/awslambda/lambda_executors.py\", line 105, in _store_logs\n logs_client.create_log_group(logGroupName=log_group_name)\n
File \"/opt/code/localstack/.venv/lib/python3.6/site-packages/botocore/client.py\", line 357, in _api_call\n
return self._make_api_call(operation_name, kwargs)\n
File \"/opt/code/localstack/.venv/lib/python3.6/site-packages/botocore/client.py\", line 661, in _make_api_call\n
raise error_class(parsed_response, operation_name)\n
botocore.errorfactory.ResourceAlreadyExistsException: An error occurred (ResourceAlreadyExistsException) when calling the CreateLogGroup operation: The specified log group already exists\n", "__type": "InternalFailure"}

# Fixed code
def apply_patches():
    """Apply patches to make LocalStack seamlessly interact with the moto backend.
    TODO: Eventually, these patches should be contributed to the upstream repo!"""

    # Patch S3Backend.get_key method in moto to use S3 API from LocalStack

    def get_key(self, bucket_name, key_name, version_id=None):
        s3_client = aws_stack.connect_to_service("s3")
        value = b""
        if bucket_name != BUCKET_MARKER_LOCAL:
            value = s3_client.get_object(Bucket=bucket_name, Key=key_name)[
                "Body"
            ].read()
        return s3_models.FakeKey(name=key_name, value=value)

    s3_models.S3Backend.get_key = get_key

    # Patch clean_json in moto

    def clean_json(resource_json, resources_map):
        result = clean_json_orig(resource_json, resources_map)
        if isinstance(result, BaseModel):
            if isinstance(resource_json, dict) and "Ref" in resource_json:
                entity_id = get_entity_id(result, resource_json)
                if entity_id:
                    return entity_id
                LOG.warning(
                    'Unable to resolve "Ref" attribute for: %s - %s - %s',
                    resource_json,
                    result,
                    type(result),
                )
        return result

    clean_json_orig = parsing.clean_json
    parsing.clean_json = clean_json

    # add model mappings to moto

    parsing.MODEL_MAP.update(MODEL_MAP)

    # Patch parse_and_create_resource method in moto to deploy resources in LocalStack

    def parse_and_create_resource(
        logical_id, resource_json, resources_map, region_name
    ):
        try:
            return _parse_and_create_resource(
                logical_id, resource_json, resources_map, region_name
            )
        except Exception as e:
            LOG.error(
                'Unable to parse and create resource "%s": %s %s'
                % (logical_id, e, traceback.format_exc())
            )
            raise

    def parse_and_update_resource(
        logical_id, resource_json, resources_map, region_name
    ):
        try:
            return _parse_and_create_resource(
                logical_id, resource_json, resources_map, region_name, update=True
            )
        except Exception as e:
            LOG.error(
                'Unable to parse and update resource "%s": %s %s'
                % (logical_id, e, traceback.format_exc())
            )
            raise

    def _parse_and_create_resource(
        logical_id, resource_json, resources_map, region_name, update=False
    ):
        stack_name = resources_map.get("AWS::StackName")
        resource_hash_key = (stack_name, logical_id)

        # If the current stack is being updated, avoid infinite recursion
        updating = CURRENTLY_UPDATING_RESOURCES.get(resource_hash_key)
        LOG.debug(
            "Currently updating stack resource %s/%s: %s"
            % (stack_name, logical_id, updating)
        )
        if updating:
            return None

        # parse and get final resource JSON
        resource_tuple = parsing.parse_resource(
            logical_id, resource_json, resources_map
        )
        if not resource_tuple:
            return None
        _, resource_json, _ = resource_tuple

        # add some missing default props which otherwise cause deployments to fail
        props = resource_json["Properties"] = resource_json.get("Properties") or {}
        if resource_json["Type"] == "AWS::Lambda::EventSourceMapping" and not props.get(
            "StartingPosition"
        ):
            props["StartingPosition"] = "LATEST"

        # check if this resource already exists in the resource map
        resource = resources_map._parsed_resources.get(logical_id)
        if resource and not update:
            return resource

        # check whether this resource needs to be deployed
        resource_wrapped = {logical_id: resource_json}
        should_be_created = template_deployer.should_be_deployed(
            logical_id, resource_wrapped, stack_name
        )
        if not should_be_created:
            # This resource is either not deployable or already exists. Check if it can be updated
            if not template_deployer.is_updateable(
                logical_id, resource_wrapped, stack_name
            ):
                LOG.debug(
                    "Resource %s need not be deployed: %s" % (logical_id, resource_json)
                )
                if resource:
                    return resource

        # fix resource ARNs, make sure to convert account IDs 000000000000 to 123456789012
        resource_json_arns_fixed = clone(json_safe(convert_objs_to_ids(resource_json)))
        set_moto_account_ids(resource_json_arns_fixed)
        # create resource definition and store CloudFormation metadata in moto
        if resource or update:
            parse_and_update_resource_orig(
                logical_id, resource_json_arns_fixed, resources_map, region_name
            )
        elif not resource:
            resource = parse_and_create_resource_orig(
                logical_id, resource_json_arns_fixed, resources_map, region_name
            )
        # Fix for moto which sometimes hard-codes region name as 'us-east-1'
        if hasattr(resource, "region_name") and resource.region_name != region_name:
            LOG.debug(
                "Updating incorrect region from %s to %s"
                % (resource.region_name, region_name)
            )
            resource.region_name = region_name

        # Apply some fixes/patches to the resource names, then deploy resource in LocalStack
        update_resource_name(resource, resource_json)
        LOG.debug("Deploying CloudFormation resource: %s" % resource_json)

        try:
            CURRENTLY_UPDATING_RESOURCES[resource_hash_key] = True
            deploy_func = (
                template_deployer.update_resource
                if update
                else template_deployer.deploy_resource
            )
            result = deploy_func(logical_id, resource_wrapped, stack_name=stack_name)
        finally:
            CURRENTLY_UPDATING_RESOURCES[resource_hash_key] = False

        if not should_be_created:
            # skip the parts below for update requests
            return resource

        def find_id(resource):
            """Find ID of the given resource."""
            for id_attr in ("Id", "id", "ResourceId", "RestApiId", "DeploymentId"):
                if id_attr in resource:
                    return resource[id_attr]

        # update resource IDs to avoid mismatch between CF moto and LocalStack backend resources
        if hasattr(resource, "id") or (
            isinstance(resource, dict) and resource.get("id")
        ):
            existing_id = resource.id if hasattr(resource, "id") else resource["id"]
            new_res_id = find_id(result)
            LOG.debug(
                "Updating resource id: %s - %s, %s - %s"
                % (existing_id, new_res_id, resource, resource_json)
            )
            if new_res_id:
                LOG.info(
                    "Updating resource ID from %s to %s (%s)"
                    % (existing_id, new_res_id, region_name)
                )
                update_resource_id(resource, new_res_id, props, region_name)
            else:
                LOG.warning(
                    "Unable to extract id for resource %s: %s" % (logical_id, result)
                )

        # update physical_resource_id field
        update_physical_resource_id(resource)

        return resource

    def update_resource_name(resource, resource_json):
        """Some resources require minor fixes in their CF resource definition
        before we can pass them on to deployment."""
        props = resource_json["Properties"] = resource_json.get("Properties") or {}
        if isinstance(resource, sfn_models.StateMachine) and not props.get(
            "StateMachineName"
        ):
            props["StateMachineName"] = resource.name

    def update_resource_id(resource, new_id, props, region_name):
        """Update and fix the ID(s) of the given resource."""

        # NOTE: this is a bit of a hack, which is required because
        # of the order of events when CloudFormation resources are created.
        # When we process a request to create a CF resource that's part of a
        # stack, say, an API Gateway Resource, then we (1) create the object
        # in memory in moto, which generates a random ID for the resource, and
        # (2) create the actual resource in the backend service using
        # template_deployer.deploy_resource(..) (see above).
        # The resource created in (2) now has a different ID than the resource
        # created in (1), which leads to downstream problems. Hence, we need
        # the logic below to reconcile the ids, i.e., apply IDs from (2) to (1).

        backend = apigw_models.apigateway_backends[region_name]
        if isinstance(resource, apigw_models.RestAPI):
            backend.apis.pop(resource.id, None)
            backend.apis[new_id] = resource
            # We also need to fetch the resources to replace the root resource
            # that moto automatically adds to newly created RestAPI objects
            client = aws_stack.connect_to_service("apigateway")
            resources = client.get_resources(restApiId=new_id, limit=500)["items"]
            # make sure no resources have been added in addition to the root /
            assert len(resource.resources) == 1
            resource.resources = {}
            for res in resources:
                res_path_part = res.get("pathPart") or res.get("path")
                child = resource.add_child(res_path_part, res.get("parentId"))
                resource.resources.pop(child.id)
                child.id = res["id"]
                child.api_id = new_id
                resource.resources[child.id] = child
            resource.id = new_id
        elif isinstance(resource, apigw_models.Resource):
            api_id = props["RestApiId"]
            backend.apis[api_id].resources.pop(resource.id, None)
            backend.apis[api_id].resources[new_id] = resource
            resource.id = new_id
        elif isinstance(resource, apigw_models.Deployment):
            api_id = props["RestApiId"]
            backend.apis[api_id].deployments.pop(resource["id"], None)
            backend.apis[api_id].deployments[new_id] = resource
            resource["id"] = new_id
        else:
            LOG.warning(
                "Unexpected resource type when updating ID: %s" % type(resource)
            )

    def update_physical_resource_id(resource):
        phys_res_id = getattr(resource, "physical_resource_id", None)
        if not phys_res_id:
            if isinstance(resource, lambda_models.LambdaFunction):
                func_arn = aws_stack.lambda_function_arn(resource.function_name)
                resource.function_arn = resource.physical_resource_id = func_arn
            elif isinstance(resource, sfn_models.StateMachine):
                sm_arn = aws_stack.state_machine_arn(resource.name)
                resource.physical_resource_id = sm_arn
            elif isinstance(resource, service_models.StepFunctionsActivity):
                act_arn = aws_stack.stepfunctions_activity_arn(
                    resource.params.get("Name")
                )
                resource.physical_resource_id = act_arn
            else:
                LOG.warning(
                    "Unable to determine physical_resource_id for resource %s"
                    % type(resource)
                )

    parse_and_create_resource_orig = parsing.parse_and_create_resource
    parsing.parse_and_create_resource = parse_and_create_resource
    parse_and_update_resource_orig = parsing.parse_and_update_resource
    parsing.parse_and_update_resource = parse_and_update_resource

    # Patch CloudFormation parse_output(..) method to fix a bug in moto

    def parse_output(output_logical_id, output_json, resources_map):
        try:
            return parse_output_orig(output_logical_id, output_json, resources_map)
        except KeyError:
            output = Output()
            output.key = output_logical_id
            output.value = None
            output.description = output_json.get("Description")
            return output

    parse_output_orig = parsing.parse_output
    parsing.parse_output = parse_output

    # Patch DynamoDB get_cfn_attribute(..) method in moto

    def DynamoDB_Table_get_cfn_attribute(self, attribute_name):
        try:
            return DynamoDB_Table_get_cfn_attribute_orig(self, attribute_name)
        except Exception:
            if attribute_name == "Arn":
                return aws_stack.dynamodb_table_arn(table_name=self.name)
            raise

    DynamoDB_Table_get_cfn_attribute_orig = dynamodb_models.Table.get_cfn_attribute
    dynamodb_models.Table.get_cfn_attribute = DynamoDB_Table_get_cfn_attribute

    # Patch DynamoDB get_cfn_attribute(..) method in moto

    def DynamoDB2_Table_get_cfn_attribute(self, attribute_name):
        if attribute_name == "Arn":
            return aws_stack.dynamodb_table_arn(table_name=self.name)
        elif attribute_name == "StreamArn":
            if (self.stream_specification or {}).get("StreamEnabled"):
                return aws_stack.dynamodb_stream_arn(self.name, "latest")
            return None
        raise UnformattedGetAttTemplateException()

    dynamodb2_models.Table.get_cfn_attribute = DynamoDB2_Table_get_cfn_attribute

    # Patch SQS get_cfn_attribute(..) method in moto

    def SQS_Queue_get_cfn_attribute(self, attribute_name):
        if attribute_name == "Arn":
            return aws_stack.sqs_queue_arn(queue_name=self.name)
        return SQS_Queue_get_cfn_attribute_orig(self, attribute_name)

    SQS_Queue_get_cfn_attribute_orig = sqs_models.Queue.get_cfn_attribute
    sqs_models.Queue.get_cfn_attribute = SQS_Queue_get_cfn_attribute

    # Patch SQS physical_resource_id(..) method in moto

    @property
    def SQS_Queue_physical_resource_id(self):
        result = SQS_Queue_physical_resource_id_orig.fget(self)
        if "://" not in result:
            # convert ID to queue URL
            return aws_stack.get_sqs_queue_url(result)
        return result

    SQS_Queue_physical_resource_id_orig = sqs_models.Queue.physical_resource_id
    sqs_models.Queue.physical_resource_id = SQS_Queue_physical_resource_id

    # Patch Lambda get_cfn_attribute(..) method in moto

    def Lambda_Function_get_cfn_attribute(self, attribute_name):
        try:
            if attribute_name == "Arn":
                return self.function_arn
            return Lambda_Function_get_cfn_attribute_orig(self, attribute_name)
        except Exception:
            if attribute_name in ("Name", "FunctionName"):
                return self.function_name
            raise

    Lambda_Function_get_cfn_attribute_orig = (
        lambda_models.LambdaFunction.get_cfn_attribute
    )
    lambda_models.LambdaFunction.get_cfn_attribute = Lambda_Function_get_cfn_attribute

    # Patch DynamoDB get_cfn_attribute(..) method in moto

    def DynamoDB_Table_get_cfn_attribute(self, attribute_name):
        try:
            if attribute_name == "StreamArn":
                streams = aws_stack.connect_to_service("dynamodbstreams").list_streams(
                    TableName=self.name
                )["Streams"]
                return streams[0]["StreamArn"] if streams else None
            return DynamoDB_Table_get_cfn_attribute_orig(self, attribute_name)
        except Exception as e:
            LOG.warning(
                'Unable to get attribute "%s" from resource %s: %s'
                % (attribute_name, type(self), e)
            )
            raise

    DynamoDB_Table_get_cfn_attribute_orig = dynamodb_models.Table.get_cfn_attribute
    dynamodb_models.Table.get_cfn_attribute = DynamoDB_Table_get_cfn_attribute

    # Patch IAM get_cfn_attribute(..) method in moto

    def IAM_Role_get_cfn_attribute(self, attribute_name):
        try:
            return IAM_Role_get_cfn_attribute_orig(self, attribute_name)
        except Exception:
            if attribute_name == "Arn":
                return aws_stack.role_arn(self.name)
            raise

    IAM_Role_get_cfn_attribute_orig = iam_models.Role.get_cfn_attribute
    iam_models.Role.get_cfn_attribute = IAM_Role_get_cfn_attribute

    # Patch LambdaFunction create_from_cloudformation_json(..) method in moto

    @classmethod
    def Lambda_create_from_cloudformation_json(
        cls, resource_name, cloudformation_json, region_name
    ):
        resource_name = (
            cloudformation_json.get("Properties", {}).get("FunctionName")
            or resource_name
        )
        return Lambda_create_from_cloudformation_json_orig(
            resource_name, cloudformation_json, region_name
        )

    Lambda_create_from_cloudformation_json_orig = (
        lambda_models.LambdaFunction.create_from_cloudformation_json
    )
    lambda_models.LambdaFunction.create_from_cloudformation_json = (
        Lambda_create_from_cloudformation_json
    )

    # Patch LambdaFunction update_from_cloudformation_json(..) method in moto

    @classmethod
    def Lambda_update_from_cloudformation_json(
        cls, original_resource, new_resource_name, cloudformation_json, region_name
    ):
        resource_name = (
            cloudformation_json.get("Properties", {}).get("FunctionName")
            or new_resource_name
        )
        return Lambda_create_from_cloudformation_json_orig(
            resource_name, cloudformation_json, region_name
        )

    if not hasattr(lambda_models.LambdaFunction, "update_from_cloudformation_json"):
        lambda_models.LambdaFunction.update_from_cloudformation_json = (
            Lambda_update_from_cloudformation_json
        )

    # patch ApiGateway Deployment

    def depl_delete_from_cloudformation_json(resource_name, resource_json, region_name):
        properties = resource_json["Properties"]
        LOG.info(
            "TODO: apigateway.Deployment.delete_from_cloudformation_json %s"
            % properties
        )

    if not hasattr(apigw_models.Deployment, "delete_from_cloudformation_json"):
        apigw_models.Deployment.delete_from_cloudformation_json = (
            depl_delete_from_cloudformation_json
        )

    # patch Lambda Version

    def vers_delete_from_cloudformation_json(resource_name, resource_json, region_name):
        properties = resource_json["Properties"]
        LOG.info(
            "TODO: apigateway.Deployment.delete_from_cloudformation_json %s"
            % properties
        )

    if not hasattr(lambda_models.LambdaVersion, "delete_from_cloudformation_json"):
        lambda_models.LambdaVersion.delete_from_cloudformation_json = (
            vers_delete_from_cloudformation_json
        )

    # add CloudWatch types

    parsing.MODEL_MAP["AWS::ApiGateway::Deployment"] = apigw_models.Deployment
    parsing.MODEL_MAP["AWS::ApiGateway::Method"] = apigw_models.Method
    parsing.MODEL_MAP["AWS::ApiGateway::Resource"] = apigw_models.Resource
    parsing.MODEL_MAP["AWS::ApiGateway::RestApi"] = apigw_models.RestAPI
    parsing.MODEL_MAP["AWS::StepFunctions::StateMachine"] = sfn_models.StateMachine

    @classmethod
    def RestAPI_create_from_cloudformation_json(
        cls, resource_name, cloudformation_json, region_name
    ):
        props = cloudformation_json["Properties"]
        name = props["Name"]
        region_name = props.get("Region") or aws_stack.get_region()
        description = props.get("Description") or ""
        id = props.get("Id") or short_uid()
        return apigw_models.RestAPI(id, region_name, name, description)

    def RestAPI_get_cfn_attribute(self, attribute_name):
        if attribute_name == "Id":
            return self.id
        if attribute_name == "Region":
            return self.region_name
        if attribute_name == "Name":
            return self.name
        if attribute_name == "Description":
            return self.description
        if attribute_name == "RootResourceId":
            for id, resource in self.resources.items():
                if resource.parent_id is None:
                    return resource.id
            return None
        raise UnformattedGetAttTemplateException()

    @classmethod
    def Deployment_create_from_cloudformation_json(
        cls, resource_name, cloudformation_json, region_name
    ):
        props = cloudformation_json["Properties"]
        name = props["StageName"]
        deployment_id = props.get("Id") or short_uid()
        description = props.get("Description") or ""
        return apigw_models.Deployment(deployment_id, name, description)

    @classmethod
    def Resource_create_from_cloudformation_json(
        cls, resource_name, cloudformation_json, region_name
    ):
        props = cloudformation_json["Properties"]
        region_name = props.get("Region") or aws_stack.get_region()
        path_part = props.get("PathPart")
        api_id = props.get("RestApiId")
        parent_id = props.get("ParentId")
        id = props.get("Id") or short_uid()
        return apigw_models.Resource(id, region_name, api_id, path_part, parent_id)

    @classmethod
    def Method_create_from_cloudformation_json(
        cls, resource_name, cloudformation_json, region_name
    ):
        props = cloudformation_json["Properties"]
        method_type = props.get("HttpMethod")
        authorization_type = props.get("AuthorizationType")
        return apigw_models.Method(method_type, authorization_type)

    apigw_models.RestAPI.create_from_cloudformation_json = (
        RestAPI_create_from_cloudformation_json
    )
    apigw_models.RestAPI.get_cfn_attribute = RestAPI_get_cfn_attribute
    apigw_models.Deployment.create_from_cloudformation_json = (
        Deployment_create_from_cloudformation_json
    )
    apigw_models.Resource.create_from_cloudformation_json = (
        Resource_create_from_cloudformation_json
    )
    apigw_models.Method.create_from_cloudformation_json = (
        Method_create_from_cloudformation_json
    )
    # TODO: add support for AWS::ApiGateway::Model, AWS::ApiGateway::RequestValidator, ...

    # fix AttributeError in moto's CloudFormation describe_stack_resource

    def describe_stack_resource(self):
        stack_name = self._get_param("StackName")
        stack = self.cloudformation_backend.get_stack(stack_name)
        logical_resource_id = self._get_param("LogicalResourceId")

        for stack_resource in stack.stack_resources:
            # Note: Line below has been patched
            # if stack_resource.logical_resource_id == logical_resource_id:
            if (
                stack_resource
                and stack_resource.logical_resource_id == logical_resource_id
            ):
                resource = stack_resource
                break
        else:
            raise ValidationError(logical_resource_id)

        template = self.response_template(
            responses.DESCRIBE_STACK_RESOURCE_RESPONSE_TEMPLATE
        )
        return template.render(stack=stack, resource=resource)

    responses.CloudFormationResponse.describe_stack_resource = describe_stack_resource