【问题标题】:How to Display a Resource From a Custom Lambda如何显示来自自定义 Lambda 的资源
【发布时间】:2021-03-15 00:26:53
【问题描述】:

我有一个自定义 CloudFormation 资源,如果它不存在,它会创建一个 S3 存储桶。代码如下:

  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)

我想在我的其他 CloudFormation 资源中引用此存储桶的 ARN。 S3CustomResource 资源仅显示 CloudWatch 日志名称的 PhysicalID。如何让 CloudFormation 将存储桶 ARN 显示为“资源”选项卡中的 PhysicalID?

【问题讨论】:

    标签: amazon-web-services aws-lambda amazon-cloudformation aws-cloudformation-custom-resource


    【解决方案1】:

    存储桶 ARN 具有固定格式,因此您只需在代码中使用它(假设 aws 分区):

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

    然后您将它们返回到response_data。下面是完全工作,修改后的代码可以使用自定义资源创建多个存储桶,并将其 ARN 返回到 cloudformation 以供将来使用。该代码有很大的改进空间,例如如果存在,则返回存储桶的 arns,检查存储桶是否正确创建等等。因此它不是理想的代码,但它可以工作并显示关键元素:

    • 将列表传递给自定义资源
    • 将 arn 列表返回给 CFN
    • 访问 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
    

    【讨论】:

    • 此解决方案为我提供了 ARN 的输出,而不是资源字段中的 PhysicalID。输出是否可以在其他资源的同一模板文件中引用?
    • 还有一件事,输出返回给我这个结果BucketArns arn:aws:s3:::b,arn:aws:s3:::b,arn:aws:s3:::d,arn:aws:s3:::n,arn:aws:s3:::a,arn:aws:s3:::x,arn:aws:s3:::u,arn:aws:s3:::i,arn:aws:s3:::1,arn:aws:s3:::0 你能帮我理解为什么它复制了 arn 的第一部分并添加了存储桶名称的第一个字符(等等)吗?
    • @gumluvinisgoodluvin 我不知道你在代码中做了什么改变。正如我测试的那样,它按预期工作。
    • 代码工作完美,但我只想使用 1 个桶(不是多个逗号分隔)。有什么建议可以改变吗?
    • 对对对。感谢您的帮助,案件已结案。
    猜你喜欢
    • 2019-07-23
    • 2021-05-11
    • 2020-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-14
    • 1970-01-01
    相关资源
    最近更新 更多