aws-cloudformation / cloudformation-coverage-roadmap

The AWS CloudFormation Public Coverage Roadmap
https://aws.amazon.com/cloudformation/
Creative Commons Attribution Share Alike 4.0 International
1.1k stars 53 forks source link

AWS::CloudFormation::CustomResource #246

Open fmmasood opened 4 years ago

fmmasood commented 4 years ago

When using ZipFile property to specify function code interacting with cloudformation, Cloudformation automatically include cfnresponse with your python lambda function (custom resource).

Module Source Code

This module depends on vendored which will soon be removed from botocore.

Are there any plans to update this module?

rjlohan commented 4 years ago

As you may have seen, we have just launched support for the CloudFormation Registry and CloudFormation CLI. Whilst not directly deprecating Custom Resources at this time, we believe this is a better experience for Custom Resource developers and this new model does address some of your ask here I believe.

rjlohan commented 4 years ago

Here is the relevant announcement: https://aws.amazon.com/about-aws/whats-new/2019/11/now-extend-aws-cloudformation-to-model-provision-and-manage-third-party-resources/

zbiegiel-aws commented 4 years ago

As you may have seen, we have just launched support for the CloudFormation Registry and CloudFormation CLI. Whilst not directly deprecating Custom Resources at this time, we believe this is a better experience for Custom Resource developers and this new model does address some of your ask here I believe.

While this may be an option going forward, it will not address the existing CloudFormation templates that include custom resource definitions already. If they are already deployed in an AWS account, a Lambda-backed custom resource may be relying on that function to update and possibly delete the custom resource.

fmmasood commented 4 years ago

How can I submit a pull request ? Looking at the code in AWS Docs, we only need minor tweaks as urllibxx comes bundled with Lambda:

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-lambda-function-code-cfnresponsemodule.html

(Updated Code) For Python 3 functions:


import json
import urllib3

SUCCESS = "SUCCESS"
FAILED = "FAILED"

http = urllib3.PoolManager()

def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False):
    responseUrl = event['ResponseURL']

    print(responseUrl)

    responseBody = {}
    responseBody['Status'] = responseStatus
    responseBody['Reason'] = 'See the details in CloudWatch Log Stream: ' + context.log_stream_name
    responseBody['PhysicalResourceId'] = physicalResourceId or context.log_stream_name
    responseBody['StackId'] = event['StackId']
    responseBody['RequestId'] = event['RequestId']
    responseBody['LogicalResourceId'] = event['LogicalResourceId']
    responseBody['NoEcho'] = noEcho
    responseBody['Data'] = responseData

    json_responseBody = json.dumps(responseBody)

    print("Response body:\n" + json_responseBody)

    headers = {
        'content-type' : '',
        'content-length' : str(len(json_responseBody))
    }

    try:
        response = http.request('PUT', responseUrl, body=json_responseBody, headers=headers)

        print("Status code: " + response.status)
    except Exception as e:
        print("send(..) failed executing http.request(..): " + str(e))
fmmasood commented 4 years ago

(Updated Code) For Python 2 functions:

import urllib2
import json

SUCCESS = "SUCCESS"
FAILED = "FAILED"

def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False):
    responseUrl = event['ResponseURL']

    print responseUrl

    responseBody = {}
    responseBody['Status'] = responseStatus
    responseBody['Reason'] = 'See the details in CloudWatch Log Stream: ' + context.log_stream_name
    responseBody['PhysicalResourceId'] = physicalResourceId or context.log_stream_name
    responseBody['StackId'] = event['StackId']
    responseBody['RequestId'] = event['RequestId']
    responseBody['LogicalResourceId'] = event['LogicalResourceId']
    responseBody['NoEcho'] = noEcho
    responseBody['Data'] = responseData

    json_responseBody = json.dumps(responseBody)

    print "Response body:\n" + json_responseBody

    try:
        opener = urllib2.build_opener(urllib2.HTTPHandler)

        request = urllib2.Request(responseUrl, data=json_responseBody)
        request.add_header('Content-Type', '')
        request.add_header('Content-Length', str(len(json_responseBody)))

        request.get_method = lambda: 'PUT'

        print "Status code: " + response.getcode()
    except Exception as e:
        print "send(..) failed executing urllib2.Request(..): " + str(e)