如何使用AWS CDK中的自定义资源将文件上传到S3存储桶

时间:2020-08-15 15:05:20

标签: aws-cdk

创建后,我需要将zip文件上传到s3存储桶。我知道s3_deployment软件包,但是它不适合我的用例,因为我需要在堆栈创建时仅将文件上传一次。 s3_deployment软件包将在每次更新时上传zip。

我定义了以下自定义资源,但是我不确定如何将文件正文传递给自定义资源。我尝试以二进制模式打开文件,但这会返回错误。

app_data_bootstrap = AwsCustomResource(self, "BootstrapData",
    on_create={
        "service": "S3",
        "action": "putObject",
        "parameters": {
            "Body": open('app_data.zip', 'rb'),
            "Bucket": f"my-app-data",
            "Key": "app_data.zip",
        },
        "physical_resource_id": PhysicalResourceId.of("BootstrapDataBucket")
    },
    policy=AwsCustomResourcePolicy.from_sdk_calls(resources=AwsCustomResourcePolicy.ANY_RESOURCE)
)

1 个答案:

答案 0 :(得分:1)

除非您编写自定义脚本并在cdk deploy之前运行以将本地文件上传到中间S3存储桶,否则我认为这是不可能的。然后,您可以编写一个自定义资源,将on_create事件中的中间存储桶的内容复制到通过CDK创建的存储桶。

从CDK文档的s3_deployment中阅读本段内容:

这是在幕后发生的事情:

  1. 在部署此堆栈时(通过cdk deploy或通过CI / CD),将对本地website-dist目录的内容进行归档并将其上载到中间资产存储桶。如果来源不止一个,则会分别上传。

  2. BucketDeployment构造将模板Custom :: CDKBucketDeployment类型的自定义CloudFormation资源合成到模板中。源存储桶/密钥设置为指向资产存储桶。

  3. 自定义资源下载.zip存档,将其解压缩并针对目标存储桶(在本例中为websiteBucket)发出aws s3 sync --delete。如果有多个来源,则将在此步骤下载并合并这些来源,然后进行预部署。

因此,为了进行步骤1的复制,您必须编写一个小的脚本来创建一个中间存储桶,并将本地文件上传到该存储桶。该脚本的示例可以像这样:

#!/bin/sh
aws s3 mb <intermediary_bucket> --region <region_name>
aws s3 sync <intermediary_bucket> s3://<your_bucket_name>

然后您的自定义资源可以是这样的:

*请注意,这将适用于复制一个对象,您可以更改代码以复制多个对象。

import json
import boto3
import cfnresponse

def lambda_handler(event, context):
    print('Received request:\n%s' % json.dumps(event, indent=4))

    resource_properties = event['ResourceProperties']

    if event['RequestType'] in ['Create']: #What happens when resource is created
        try:
            s3 = boto3.resource('s3')
            copy_source = {
                'Bucket': 'intermediary_bucket',
                'Key': 'path/to/filename.extension'
            }
            bucket = s3.Bucket('otherbucket')
            obj = bucket.Object('otherkey')
            obj.copy(copy_source)

        except:
            cfnresponse.send(event, context, cfnresponse.FAILED, {})
            raise
        else:
            cfnresponse.send(event, context, cfnresponse.SUCCESS,
                             {'FileContent': response['fileContent'].decode('utf-8')})
    elif event['RequestType'] == 'Delete': # What happens when resource is deleted
        cfnresponse.send(event, context, cfnresponse.SUCCESS, {})

所有这些的替代方法是在AWS CDK的Github repo中打开一个问题,并要求他们添加您的用例。

相关问题