微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

CloudFormation 为现有 s3 存储桶添加触发器

如何解决CloudFormation 为现有 s3 存储桶添加触发器

我的目标是将每次上传到存储桶的图像时调用的 lambda 代码打包到 CloudFormation 模板中。到目前为止,我实现了创建新资源并从头开始触发,但我有现有的存储桶,我需要向其中添加触发器并在两种情况下出现错误

  1. 当我将 lambda 的创建和触发器配置放在一个模板中并尝试将堆栈创建为新资源时 - 它表示该存储桶已存在
  2. 当我将触发器移动到新文件时 - 首先像 1. 一样创建新资源,然后将现有资源导入堆栈 - 我得到:

创建此更改集时出错

您在模板中修改了未导入的资源 [ScaleImages,ScaleImagesRole]。导入操作期间无法执行更新、创建或删除操作。

我的模板看起来像:

  • lambda 创建 - 新 lambda 和角色 - 使用新资源创建堆栈
# A tibble: 4 x 2
#     id score
#  <int> <int>
#1     2    10
#2     2    85
#3     3    80
#4     3   100
  • 添加触发器 - 存储桶存在 - 导入资源
example_df <- structure(list(id = c(1L,1L,2L,3L,3L),score = c(50L,90L,10L,85L,80L,100L)),class = "data.frame",row.names = c("1:","2:","3:","4:","5:","6:"))

在最后一个我也尝试了 { "AWstemplateFormatVersion": "2010-09-09","Resources": { "ScaleImages": { "Type": "AWS::Lambda::Function","DeletionPolicy": "Retain","Properties": { "FunctionName": "ScaleImages","Handler": "index.handler","Role": { "Fn::GetAtt": [ "ScaleImagesRole","Arn" ] },"Code": { "S3Bucket": "example-test","S3Key": "example-resize.zip" },"Runtime": "nodejs12.x","MemorySize": 1024,"Timeout": 300 } },"ScaleImagesRole": { "Type": "AWS::IAM::Role","Properties": { "RoleName": "ScaleImagesRole","AssumeRolePolicyDocument": { "Version": "2012-10-17","Statement": [ { "Effect": "Allow","Principal": { "Service": [ "lambda.amazonaws.com" ] },"Action": [ "sts:AssumeRole" ] } ] },"Path": "/","Policies": [ { "PolicyName": "AWSLambdaBasicExecutionRole","PolicyDocument": { "Version": "2012-10-17","Statement": [ { "Effect": "Allow","Action": [ "logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents" ],"Resource": "*" } ] } },{ "PolicyName": "AmazonS3FullAccess","Action": "s3:*","Resource": [ "arn:aws:s3:::example-test","arn:aws:s3:::example-test/*","arn:aws:s3:::example-test-output","arn:aws:s3:::example-test-output/*" ] } ] } } ] } } } } ,但在这两种情况下我都有同样的错误

修改模板中的资源 [ScaleImages,ScaleImagesRole]

有人能解释一下我做错了什么吗?

解决方法

你必须在阶段

1.创建新堆栈

尚无存储桶,只需与您缺少的函数和 lambda 权限 叠加即可。

    {
      "AWSTemplateFormatVersion": "2010-09-09","Resources": {
        "ScaleImages": {
          "Type": "AWS::Lambda::Function","Properties": {
            "FunctionName": "ScaleImages","Handler": "index.handler","Role": {
              "Fn::GetAtt": [
                "ScaleImagesRole","Arn"
              ]
            },"Code": {
              "S3Bucket": "example-test","S3Key": "example-resize.zip"
            },"Runtime": "nodejs12.x","MemorySize": 1024,"Timeout": 300
          }
        },"ScaleImagesRole": {
          "Type": "AWS::IAM::Role","Properties": {
            "RoleName": "ScaleImagesRole","AssumeRolePolicyDocument": {
              "Version": "2012-10-17","Statement": [
                {
                  "Effect": "Allow","Principal": {
                    "Service": [
                      "lambda.amazonaws.com"
                    ]
                  },"Action": [
                    "sts:AssumeRole"
                  ]
                }
              ]
            },"Path": "/","Policies": [
              {
                "PolicyName": "AWSLambdaBasicExecutionRole","PolicyDocument": {
                  "Version": "2012-10-17","Statement": [
                    {
                      "Effect": "Allow","Action": [
                        "logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"
                      ],"Resource": [
                        "arn:aws:s3:::example-test","arn:aws:s3:::example-test/*","arn:aws:s3:::example-test-output","arn:aws:s3:::example-test-output/*"
                      ]
                    }
                  ]
                }
              },{
                "PolicyName": "AmazonS3FullAccess","Action": "s3:*","Resource": "*"
                    }
                  ]
                }
              }
            ]
          }
        },"s3Permission": {
    "Type": "AWS::Lambda::Permission","Properties": {
        "FunctionName": {
            "Fn::GetAtt": [
                "ScaleImages","Arn"
            ]
        },"Action": "lambda:InvokeFunction","Principal": "s3.amazonaws.com","SourceAccount": {
            "Ref": "AWS::AccountId"
        }
    }
}



      }
    }

2.将存储桶导入现有堆栈

使用 Import resources into stack 选项并使用此模板上传堆栈。它添加了存储桶,但还没有通知

    {
      "AWSTemplateFormatVersion": "2010-09-09","SourceAccount": {
            "Ref": "AWS::AccountId"
        }
    }
},"PutOriginalImage": {
      "Type": "AWS::S3::Bucket","DeletionPolicy": "Retain","Properties": {
        "BucketName": "example-test"
      }
    }

      }
    }

3.更新堆栈

通过向存储桶添加通知来更新堆栈。使用以下模板:

    {
      "AWSTemplateFormatVersion": "2010-09-09","Properties": {
        "BucketName": "example-test","NotificationConfiguration": {
          "LambdaConfigurations": [
            {
              "Event": "s3:ObjectCreated:Put","Filter": {
                "S3Key": {
                  "Rules": [
                    {
                      "Name": "prefix","Value": "original2/"
                    }
                  ]
                }
              },"Function": {
                "Fn::GetAtt": [
                  "ScaleImages","Arn"
                ]
              }
            }
          ]
        }


      }
    }



      }
    }
,

一种略有不同的方法,让您无需遵循 3 个步骤即可一次性完成。在 Cloudformation 中导入现有资源时,我经历了一些艰难时期,我将通过自定义资源处理 lambda 中的复杂性

                s3 = boto3.resource('s3')
                
                def lambda_handler(event,context):
                    print("Received event: " + json.dumps(event,indent=2))
                    responseData={}
                    try:
                        if event['RequestType'] == 'Delete':
                            print("Request Type:",event['RequestType'])
                            Bucket=event['ResourceProperties']['Bucket']
                            delete_notification(Bucket)
                            print("Sending response to custom resource after Delete")
                        elif event['RequestType'] == 'Create' or event['RequestType'] == 'Update':
                            print("Request Type:",event['RequestType'])
                            LambdaArn=event['ResourceProperties']['LambdaArn']
                            Bucket=event['ResourceProperties']['Bucket']
                            add_notification(LambdaArn,Bucket)
                            responseData={'Bucket':Bucket}
                            print("Sending response to custom resource")
                        responseStatus = 'SUCCESS'
                    except Exception as e:
                        print('Failed to process:',e)
                        responseStatus = 'FAILURE'
                        responseData = {'Failure': 'Something bad happened.'}
                    cfnresponse.send(event,context,responseStatus,responseData)
    
                def add_notification(LambdaArn,Bucket):
                    bucket_notification = s3.BucketNotification(Bucket)
                    response = bucket_notification.put(
                      NotificationConfiguration={
                        'LambdaFunctionConfigurations': [
                          {
                              'LambdaFunctionArn': LambdaArn,'Events': [
                                  's3:ObjectCreated:*'
                              ]
                          }
                        ]
                      }
                    )
                    print("Put request completed....")
                  
                def delete_notification(Bucket):
                    bucket_notification = s3.BucketNotification(Bucket)
                    response = bucket_notification.put(
                        NotificationConfiguration={}
                    )
                    print("Delete request completed....")

可以找到完整的模板和解决方案here

注意:AWS CloudFormation Repo on github 上已经存在一个未解决的问题。最初来自serverless folks

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。