gumluvinisgoodluvin
gumluvinisgoodluvin

Reputation: 87

How to Display a Resource From a Custom Lambda

I have a custom CloudFormation resource that creates an S3 bucket if it doesn't exist. Here is the code:

  S3CustomResource:
Type: Custom::S3CustomResource
Properties:
  ServiceToken: !GetAtt AWSLambdaFunction.Arn
  the_bucket: !Ref S3BucketName

  AWSLambdaFunction:
 Type: "AWS::Lambda::Function"
 Properties:
   Description: "Work with S3 Buckets!"
   FunctionName: !Sub '${AWS::StackName}-${AWS::Region}-lambda'
   Handler: index.handler
   Role: !GetAtt AWSLambdaExecutionRole.Arn
   Timeout: 360
   Runtime: python3.6
   Code:
     ZipFile: |
      import boto3
      import cfnresponse
      def handler(event, context):
          # Init ...
          the_event = event['RequestType']
          print("The event is: ", str(the_event))
          response_data = {}
          s_3 = boto3.client('s3')
          # Retrieve parameters
          the_bucket = event['ResourceProperties']['the_bucket']
          try:
              if the_event in ('Create', 'Update'):
                  print("Requested to create S3 bucket: ", str(the_bucket))
                  for bucket_name in the_bucket:
                      print("Creating: ", str(bucket_name))
                      s_3.create_bucket(Bucket=the_bucket)
              elif the_event == 'Delete':
                  print("Whoopsie, this bucket has some seriuos information in it - let's not delete it")
              # Everything OK... send the signal back
              print("Execution succesfull!")
              cfnresponse.send(event,
                               context,
                               cfnresponse.SUCCESS,
                               response_data)
          except Exception as e:
              print("Execution failed...")
              print(str(e))
              response_data['Data'] = str(e)
              cfnresponse.send(event,
                               context,
                               cfnresponse.FAILED,
                               response_data)

I would like to reference the ARN of this bucket in my other CloudFormation resources. The S3CustomResource resource only shows the PhysicalID of the CloudWatch Log name. How can I get CloudFormation to show the bucket ARN as a PhysicalID in the Resource tab?

Upvotes: 3

Views: 472

Answers (1)

Marcin
Marcin

Reputation: 238747

Bucket ARNs have fixed format, so you just use that in your code (assuming aws partition):

bucket_arn = "arn:aws:s3:::" + bucket_name

and you return them in response_data. Below is fully working, amended code that can create multiple buckets using custom resource and returns their ARN to cloudformation for future use. The code has a lot of room for improvement, e.g. return arns of buckets if they exist, check if buckets were correctly created and more. Thus its not ideal code, but it works and shows the key elements:

  • passing lists to custom resource
  • returning lists of arns to CFN
  • accessing the list in CFN

Parameters:

  S3BucketName:
    Type: CommaDelimitedList  
    Default: test-bucket-312ddfff,test-bucket3333-312ddfff

Resources:

  S3CustomResource:
    Type: Custom::S3CustomResource
    Properties:
      ServiceToken: !GetAtt AWSLambdaFunction.Arn
      the_bucket: !Ref S3BucketName

  AWSLambdaFunction:
     Type: "AWS::Lambda::Function"
     Properties:
       Description: "Work with S3 Buckets!"
       FunctionName: !Sub '${AWS::StackName}-${AWS::Region}-lambda'
       Handler: index.handler
       Role: !GetAtt AWSLambdaExecutionRole.Arn
       Timeout: 360
       Runtime: python3.6
       Code:
         ZipFile: |
          import boto3
          import cfnresponse

          s_3 = boto3.client('s3')
          s3_waiter = s_3.get_waiter('bucket_exists')

          def handler(event, context):
              # Init ...
              
              print(event)

              the_event = event['RequestType']
              print("The event is: ", str(the_event))
              
              response_data = {}              

              # Retrieve parameters
              the_bucket = event['ResourceProperties']['the_bucket']
              
              print("the_bucket", the_bucket)
              
              bucket_arns = []

              try:
                  if the_event in ('Create', 'Update'):

                      print("Requested to create S3 bucket: ", 
                             str(the_bucket))

                      for bucket_name in the_bucket:
                      
                          print("Creating: ", str(bucket_name))
                          
                          s_3.create_bucket(Bucket=bucket_name)
                          
                          s3_waiter.wait(Bucket=bucket_name)
                          
                          bucket_arn = "arn:aws:s3:::" + bucket_name
                          
                          bucket_arns.append(bucket_arn)

                  elif the_event == 'Delete':
                      print("Whoopsie, this bucket has some"
                            "seriuos information in it "
                            "- let's not delete it")
                      cfnresponse.send(event, context,
                                       cfnresponse.SUCCESS,
                                       response_data)
                      return

                  # Everything OKindex... send the signal back

                  print("Execution successful!")
                  
                  response_data['arns'] = ','.join(bucket_arns)

                  cfnresponse.send(event,
                                   context,
                                   cfnresponse.SUCCESS,
                                   response_data)

              except Exception as e:

                  print("Execution failed...")
                  print(str(e))
                  
                  response_data['Data'] = str(e)

                  cfnresponse.send(event,
                                   context,
                                   cfnresponse.FAILED,
                                   response_data)
               
               
  AWSLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'               
        Statement:
          - Effect: Allow
            Principal: {'Service': ['lambda.amazonaws.com']}
            Action: ['sts:AssumeRole']
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AWSLambdaExecute
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
      Path: '/'
      
      
Outputs:

  BucketArns:
    Value: !GetAtt S3CustomResource.arns

Upvotes: 2

Related Questions