Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

readOnlyProperties not being remembered #168

Open
danieljarrett74 opened this issue Oct 14, 2021 · 1 comment
Open

readOnlyProperties not being remembered #168

danieljarrett74 opened this issue Oct 14, 2021 · 1 comment
Assignees

Comments

@danieljarrett74
Copy link

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='[email protected]', 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='[email protected]', 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:*"            ]
        }
    }
}

@luisbarrueco
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants