Skip to content

readOnlyProperties not being remembered #168

Open

Description

@danieljarrett74

I have a few readOnlyProperties that aren't being set or returned when performing a delete.

My create handler looks as follows and I'm outputting the progress event before returning it:


@resource.handler(Action.CREATE)
def create_handler(
        session: Optional[SessionProxy],
        request: ResourceHandlerRequest,
        callback_context: MutableMapping[str, Any],
) -> ProgressEvent:
    model = request.desiredResourceState
    awsAccountId = request.awsAccountId
    region = request.region
    logicalResourceIdentifier = request.logicalResourceIdentifier
    LOG.debug("CREATE")
    LOG.debug(callback_context)
    LOG.debug(request.desiredResourceState)
    try:
        if isinstance(session, SessionProxy):
            progress = handle_create(
                aws_account_id=awsAccountId,
                region=region,
                agw_client=session.client("apigateway"),
                lambda_client=session.client("lambda"),
                dynamodb_resource=session.resource("dynamodb"),
                iam_client=session.client("iam"),
                model=model,
                callback_context=callback_context
            )
            LOG.debug(progress)
            return progress
        else:
            LOG.error("No session available")
            raise TypeError
    except TypeError as e:
        raise exceptions.InternalFailure(f"was not expecting type {e}")

And in my logs I can see that I am setting my readOnlyProperties. EG ApiId

ProgressEvent(status=<OperationStatus.SUCCESS: 'SUCCESS'>, errorCode=None, message='', callbackContext={}, callbackDelaySeconds=0, resourceModel=ResourceModel(DefaultSender=DefaultSender(EmailAddress='test@test.com', Name=None), SenderMode='MULTIPLE', ApiId='is6k89ctyh', Templates=None, CognitoTemplates=None, Endpoint='https://1234567.execute-api.us-east-1.amazonaws.com/test', CognitoCustomMessageArn='arn:aws:lambda:us-east-1:1234567890:function:CustomMessagesLambda', Tags=None), resourceModels=None, nextToken=None)

When I DELETE the stack containing the resource I get an error because ApiId is set to None. Somewhere along the way it's being forgotten.

@resource.handler(Action.DELETE)
def delete_handler(
        session: Optional[SessionProxy],
        request: ResourceHandlerRequest,
        callback_context: MutableMapping[str, Any],
) -> ProgressEvent:
    model = request.previousResourceState
    awsAccountId = request.awsAccountId
    region = request.region
    logicalResourceIdentifier = request.logicalResourceIdentifier
    LOG.debug("DELETE")
    LOG.debug(request)
    try:
        if isinstance(session, SessionProxy):
            progress = handle_delete(
                aws_account_id=awsAccountId,
                region=region,
                agw_client=session.client("apigateway"),
                lambda_client=session.client("lambda"),
                dynamodb_client=session.client("dynamodb"),
                iam_client=session.client("iam"),
                model=model,
                callback_context=callback_context
            )
            return progress
        else:
            LOG.error("No session available")
            raise TypeError
    except TypeError as e:
        raise exceptions.InternalFailure(f"was not expecting type {e}")

As you can see above I'm logging the entire request, which you can see here:

BaseResourceHandlerRequest(clientRequestToken='e3aa83a2-9bc8-4a35-d8b2-1234567890', desiredResourceState=ResourceModel(DefaultSender=DefaultSender(EmailAddress='test@test.com', Name=None), SenderMode='MULTIPLE', ApiId=None, Templates=None, CognitoTemplates=None, Endpoint='https://1234567.execute-api.us-east-1.amazonaws.com/test', CognitoCustomMessageArn=None, Tags=None), previousResourceState=None, desiredResourceTags=None, previousResourceTags=None, systemTags=None, previousSystemTags=None, awsAccountId='1234567890', logicalResourceIdentifier='NotificationsApi', typeConfiguration=None, nextToken=None, region='us-east-1', awsPartition='aws', stackId='arn:aws:cloudformation:us-east-1:1234567890:stack/drj-notifications-api-test/5ddc1250-2b04-11ec-9b2e-1234567890')

My Configuration JSON file looks as follows:
{
    "typeName": "DRJ::Notifications::Api",
    "description": "DRJ Notifications Api Resource",
    "sourceUrl": "https://github.com/aws-cloudformation/aws-cloudformation-rpdk.git",
    "definitions": {
        "DefaultSender": {
            "type": "object",
            "properties": {
                "EmailAddress": {
                    "type": "string"
                },
                "Name": {
                    "type": "string"
                }
            },
            "required": [
                "EmailAddress"
            ],
            "additionalProperties": false
        },
        "Template": {
            "type": "object",
            "properties": {
                "TemplateId": {
                    "type": "string"
                },
                "TemplateDescription": {
                    "type": "string"
                },
                "Subject": {
                    "type": "string"
                },
                "HtmlPart": {
                    "type": "string"
                },
                "TextPart": {
                    "type": "string"
                }
            },
            "required": [
                "Subject",
                "HtmlPart",
                "TextPart",
                "TemplateId"
            ],
            "additionalProperties": false
        },
        "CognitoTemplate": {
            "type": "object",
            "properties": {
                "Subject": {
                    "type": "string"
                },
                "HtmlPart": {
                    "type": "string"
                },
                "TextPart": {
                    "type": "string"
                }
            },
            "required": [
                "Subject",
                "HtmlPart",
                "TextPart"
            ],
            "additionalProperties": false
        },        
        "CognitoTemplates": {
            "type": "object",
            "properties": {
                "SignUp": {
                    "$ref": "#/definitions/CognitoTemplate"
                },
                "AdminCreateUser": {
                    "$ref": "#/definitions/CognitoTemplate"
                },
                "ResendCode": {
                    "$ref": "#/definitions/CognitoTemplate"
                },
                "ForgotPassword": {
                    "$ref": "#/definitions/CognitoTemplate"
                },
                "UpdateUserAttribute": {
                    "$ref": "#/definitions/CognitoTemplate"
                },
                "VerifyUserAttribute": {
                    "$ref": "#/definitions/CognitoTemplate"
                }
            },
            "required": [],
            "additionalProperties": false
        },
        "Tag": {
            "description": "A key-value pair to associate with a resource.",
            "type": "object",
            "properties": {
                "Key": {
                    "type": "string",
                    "description": "The key name of the tag. You can specify a value that is 1 to 128 Unicode characters in length and cannot be prefixed with aws:. You can use any of the following characters: the set of Unicode letters, digits, whitespace, _, ., /, =, +, and -.",
                    "minLength": 1,
                    "maxLength": 128
                },
                "Value": {
                    "type": "string",
                    "description": "The value for the tag. You can specify a value that is 0 to 256 Unicode characters in length and cannot be prefixed with aws:. You can use any of the following characters: the set of Unicode letters, digits, whitespace, _, ., /, =, +, and -.",
                    "minLength": 0,
                    "maxLength": 256
                }
            },
            "required": [
                "Key",
                "Value"
            ],
            "additionalProperties": false
        }
    },
    "properties": {
        "DefaultSender" : {
            "$ref": "#/definitions/DefaultSender"
        },
        "SenderMode": {
            "type": "string",
            "enum": [
                "MULTIPLE",
                "SINGLE"
            ]
        },
        "ApiId" : {
            "type": "string"
        },
        "Templates": {
            "type": "array",
            "items": {
                "$ref": "#/definitions/Template"
            }
        },        
        "CognitoTemplates": {
            "$ref": "#/definitions/CognitoTemplates"
        },
        "Endpoint": {
            "type": "string"
        },
        "CognitoCustomMessageArn": {
            "type": "string"
        },
        "Tags": {
            "description": "An array of key-value pairs to apply to this resource.",
            "type": "array",
            "uniqueItems": true,
            "insertionOrder": false,
            "items": {
                "$ref": "#/definitions/Tag"
            }
        }
    },
    "additionalProperties": false,
    "required": [
        "DefaultSender"
    ],
    "readOnlyProperties": [
        "/properties/Endpoint",
        "/properties/ApiId",
        "/properties/CognitoCustomMessageArn"
    ],
    "primaryIdentifier": [
        "/properties/Endpoint"
    ],
    "handlers": {
        "create": {
            "permissions": [
                "iam:*",
                "dynamodb:*",
                "apigateway:*",
                "lambda:*"
            ]
        },
        "read": {
            "permissions": [
                "iam:*",
                "dynamodb:*",
                "apigateway:*",
                "lambda:*"            ]
        },
        "update": {
            "permissions": [
                "iam:*",
                "dynamodb:*",
                "apigateway:*",
                "lambda:*"            ]
        },
        "delete": {
            "permissions": [
                "iam:*",
                "dynamodb:*",
                "apigateway:*",
                "lambda:*"            ]
        },
        "list": {
            "permissions": [
                "iam:*",
                "dynamodb:*",
                "apigateway:*",
                "lambda:*"            ]
        }
    }
}

Activity

  1. luisbarrueco commented on Nov 5, 2021

    @luisbarrueco

    Hi! I'm pretty sure you need to include /properties/ApiId in your primaryIdentifier for it to be passed in the delete handler request.

  2. self-assigned this
    on Oct 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions