aws / aws-cdk-rfcs

RFCs for the AWS CDK

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support Encode Properties for CloudFormation CustomResource

michanto opened this issue · comments

Description

When calling a CustomResource, CloudFormation turns all the JSON properties passed to the resource into strings. This makes it difficult to code a resource that processes non-string data, or to pass data to APIs that require non-string inputs.

The proposal is to add a flag to CustomResource, encodeProperties, that would encode all the properties in a custom resource other than the ServiceToken. If encodeProperties is false (the default), then the CustomResource creates a CfnResource as normal. If encodeProperties is true, the CustomResource instead creates a CfnEncodingResource:

/**
 * This resource will encode it's properties at the last possible moment - during
 * _toCloudFormation conversion of the CfnResource to CloudFormation, specifically
 * in renderProperties.  It is meant to be used for CustomResource, as it does not
 * encode the ServiceToken, and it expects one to be there.
 *
 * This is important because the properties of the resource might not be known until
 * all the Apsects have run, therefore we want to wait until they are all present
 * before encoding them.
 *
 * Why do we encode properties?  Because CloudFormation will turn numbers and booleans
 * into strings when it calls a custom resource Lambda, and that is not always desirable.
 * Encoding the properties prevents that conversion.
 */
export class CfnEncodingResource extends CfnResource {
    protected renderProperties(props: { [p: string]: any }): { [p: string]: any } {
        let serviceToken = props.ServiceToken
        delete props.ServiceToken
        let encodedProperties = {
            ServiceToken: serviceToken,
            EncodedProperties: Fn.base64(Stack.of(this).toJsonString(props))
        }
        return encodedProperties
    }
}

All lambda languages have native support for decoding Base64, so it is not necessary to add direct support for encoded resources to lambda libraries to make this work for end users. Sample code should suffice.

Example Typescript Decoding:

    if ("EncodedProperties" in event["ResourceProperties"]) {
        event["ResourceProperties"] = JSON.parse(Buffer
            .from(event["ResourceProperties"]["EncodedProperties"], "base64")
            .toString("utf8"))
        console.log(`Decoded Event: ${JSON.stringify(event)}`)
    }

Example Python Decoding:

encoded_properties = event["ResourceProperties"].get("EncodedProperties", None)
if encoded_resources:
   event["ResourceProperties"] = json.loads(base64.b64decode(encoded_properties).decode("utf-8")) 

This has become a common solution used by many custom resources. It should just be part of the CDK as an aid to CustomResource authors.

Roles

Role User
Proposed by @michanto
Author(s) @michanto
API Bar Raiser @alias
Stakeholders @alias, @alias, @alias

See RFC Process for details

Workflow

  • Tracking issue created (label: status/proposed)
  • API bar raiser assigned (ping us at #aws-cdk-rfcs if needed)
  • Kick off meeting
  • RFC pull request submitted (label: status/review)
  • Community reach out (via Slack and/or Twitter)
  • API signed-off (label api-approved applied to pull request)
  • Final comments period (label: status/final-comments-period)
  • Approved and merged (label: status/approved)
  • Execution plan submitted (label: status/planning)
  • Plan approved and merged (label: status/implementing)
  • Implementation complete (label: status/done)

Author is responsible to progress the RFC according to this checklist, and
apply the relevant labels to this issue so that the RFC table in README gets
updated.

Marking this RFCs as stale since there has been little recent activity and it is not currently close to getting accepted as-is. We appreciate the effort that has gone into this proposal. Marking an RFCs as stale is not a one-way door. If you have made substantial changes to the proposal, please open a new issue/RFC. You might also consider raising a PR to aws/aws-cdk directly or self-publishing to Construct Hub.

This proposal feels like a workaround for what's actually an underlying CloudFormation bug. Is there documentation or a bug report for the underlying "stringify all the leaf nodes in the json document" behavior?