使用 Cloudformation 在 S3 存储桶中创建文件夹
create folder inside S3 bucket using Cloudformation
我可以使用 cloudformation 创建 S3 存储桶,但我想在 S3 存储桶中创建一个文件夹..like
<mybucket>--><myfolder>
请告诉我用于在存储桶内创建文件夹的模板...两者应同时创建...
我正在使用 AWS lambda,如下所示
stackname = 'myStack'
client = boto3.client('cloudformation')
response = client.create_stack(
StackName= (stackname),
TemplateURL= 'https://s3.amazonaws.com/<myS3bucket>/<myfolder>/nestedstack.json',
Parameters=<params>
)
使用 AWS CloudFormation 模板无法做到这一点。
需要说明的是,文件夹实际上并不存在于 Amazon S3 中。相反,对象的路径被添加到对象的名称 (key
) 之前。
因此,存储在名为 foo
的文件夹中的文件 bar.txt
实际上存储的密钥为:foo/bar.txt
您也可以将文件复制到一个不存在的文件夹中,该文件夹将自动创建(实际上并非如此,因为该文件夹本身并不存在)。但是管理控制台会提供这样一个文件夹的外观,路径会提示存放在这样一个文件夹中。
底线:无需预先创建文件夹。就像它已经存在一样使用它。
AWS 不提供官方 CloudFormation 资源来在 S3 存储桶中创建对象。但是,您可以创建一个 Lambda-backed Custom Resource to perform this function using the AWS SDK, and in fact the gilt/cloudformation-helpers GitHub 存储库,它提供了一个现成的自定义资源来执行此操作。
与任何自定义资源设置一样有点冗长,因为您需要首先部署 Lambda 函数和 IAM 权限,然后将其作为堆栈模板中的自定义资源引用。
首先,将 Lambda::Function
和关联的 IAM::Role
资源添加到您的堆栈模板:
"S3PutObjectFunctionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [ "lambda.amazonaws.com" ]
},
"Action": [ "sts:AssumeRole" ]
}
]
},
"ManagedPolicyArns": [
{ "Ref": "RoleBasePolicy" }
],
"Policies": [
{
"PolicyName": "S3Writer",
"PolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:DeleteObject",
"s3:ListBucket",
"s3:PutObject"
],
"Resource": "*"
}
]
}
}
]
}
},
"S3PutObjectFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": "com.gilt.public.backoffice",
"S3Key": "lambda_functions/cloudformation-helpers.zip"
},
"Description": "Used to put objects into S3.",
"Handler": "aws/s3.putObject",
"Role": {"Fn::GetAtt" : [ "S3PutObjectFunctionRole", "Arn" ] },
"Runtime": "nodejs",
"Timeout": 30
},
"DependsOn": [
"S3PutObjectFunctionRole"
]
},
然后您可以使用 Lambda 函数作为自定义资源来创建您的 S3 对象:
"MyFolder": {
"Type": "Custom::S3PutObject",
"Properties": {
"ServiceToken": { "Fn::GetAtt" : ["S3PutObjectFunction", "Arn"] },
"Bucket": "mybucket",
"Key": "myfolder/"
}
},
除了 Bucket
和 Key
之外,您还可以通过添加 Body
参数来使用相同的自定义资源编写基于字符串的 S3 对象(请参阅 docs).
我们无法(至少目前)无法在 s3 存储桶中创建子文件夹。
您可以尝试使用以下命令:
aws s3 mb s3://yavdhesh-bucket/inside-folder
然后尝试使用命令列出存储桶中的所有文件夹:
aws s3 ls s3://yavdhesh-bucket
你会发现子文件夹没有创建。
只有一种方法可以创建子文件夹,即 creating/copying 在不存在的子文件夹或子目录(相对于存储桶)中创建一个文件
例如,
aws s3 cp demo.txt s3://yavdhesh-bucket/inside-folder/
现在,如果您列出子文件夹中的文件,它应该可以工作。
aws s3 ls s3://yavdhesh-bucket/inside-folder/
它应该列出该子文件夹中存在的所有文件。
希望对您有所帮助。
我最终得到了一个小 python 脚本。它应该是 运行 手动,但它会自动同步。它适用于不想创建 Lambda 支持的自定义资源的懒人。
import subprocess
import json
STACK_NAME = ...
S3_RESOURCE = <name of your s3 resource, as in CloudFormation template file>
LOCAL_DIR = <path of your local dir>
res = subprocess.run(
['aws', 'cloudformation', 'describe-stack-resource', '--stack-name', STACK_NAME, '--logical-resource-id', S3_RESOURCE],
capture_output=True,
)
out = res.stdout.decode('utf-8')
resource_details = json.loads(out)
resource_id = resource_details['StackResourceDetail']['PhysicalResourceId']
res = subprocess.run(
['aws', 's3', 'sync', LOCAL_DIR, f's3://{resource_id}/', '--acl', 'public-read']
)
我可以使用 cloudformation 创建 S3 存储桶,但我想在 S3 存储桶中创建一个文件夹..like
<mybucket>--><myfolder>
请告诉我用于在存储桶内创建文件夹的模板...两者应同时创建...
我正在使用 AWS lambda,如下所示
stackname = 'myStack'
client = boto3.client('cloudformation')
response = client.create_stack(
StackName= (stackname),
TemplateURL= 'https://s3.amazonaws.com/<myS3bucket>/<myfolder>/nestedstack.json',
Parameters=<params>
)
使用 AWS CloudFormation 模板无法做到这一点。
需要说明的是,文件夹实际上并不存在于 Amazon S3 中。相反,对象的路径被添加到对象的名称 (key
) 之前。
因此,存储在名为 foo
的文件夹中的文件 bar.txt
实际上存储的密钥为:foo/bar.txt
您也可以将文件复制到一个不存在的文件夹中,该文件夹将自动创建(实际上并非如此,因为该文件夹本身并不存在)。但是管理控制台会提供这样一个文件夹的外观,路径会提示存放在这样一个文件夹中。
底线:无需预先创建文件夹。就像它已经存在一样使用它。
AWS 不提供官方 CloudFormation 资源来在 S3 存储桶中创建对象。但是,您可以创建一个 Lambda-backed Custom Resource to perform this function using the AWS SDK, and in fact the gilt/cloudformation-helpers GitHub 存储库,它提供了一个现成的自定义资源来执行此操作。
与任何自定义资源设置一样有点冗长,因为您需要首先部署 Lambda 函数和 IAM 权限,然后将其作为堆栈模板中的自定义资源引用。
首先,将 Lambda::Function
和关联的 IAM::Role
资源添加到您的堆栈模板:
"S3PutObjectFunctionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [ "lambda.amazonaws.com" ]
},
"Action": [ "sts:AssumeRole" ]
}
]
},
"ManagedPolicyArns": [
{ "Ref": "RoleBasePolicy" }
],
"Policies": [
{
"PolicyName": "S3Writer",
"PolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:DeleteObject",
"s3:ListBucket",
"s3:PutObject"
],
"Resource": "*"
}
]
}
}
]
}
},
"S3PutObjectFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": "com.gilt.public.backoffice",
"S3Key": "lambda_functions/cloudformation-helpers.zip"
},
"Description": "Used to put objects into S3.",
"Handler": "aws/s3.putObject",
"Role": {"Fn::GetAtt" : [ "S3PutObjectFunctionRole", "Arn" ] },
"Runtime": "nodejs",
"Timeout": 30
},
"DependsOn": [
"S3PutObjectFunctionRole"
]
},
然后您可以使用 Lambda 函数作为自定义资源来创建您的 S3 对象:
"MyFolder": {
"Type": "Custom::S3PutObject",
"Properties": {
"ServiceToken": { "Fn::GetAtt" : ["S3PutObjectFunction", "Arn"] },
"Bucket": "mybucket",
"Key": "myfolder/"
}
},
除了 Bucket
和 Key
之外,您还可以通过添加 Body
参数来使用相同的自定义资源编写基于字符串的 S3 对象(请参阅 docs).
我们无法(至少目前)无法在 s3 存储桶中创建子文件夹。
您可以尝试使用以下命令:
aws s3 mb s3://yavdhesh-bucket/inside-folder
然后尝试使用命令列出存储桶中的所有文件夹:
aws s3 ls s3://yavdhesh-bucket
你会发现子文件夹没有创建。
只有一种方法可以创建子文件夹,即 creating/copying 在不存在的子文件夹或子目录(相对于存储桶)中创建一个文件
例如,
aws s3 cp demo.txt s3://yavdhesh-bucket/inside-folder/
现在,如果您列出子文件夹中的文件,它应该可以工作。
aws s3 ls s3://yavdhesh-bucket/inside-folder/
它应该列出该子文件夹中存在的所有文件。
希望对您有所帮助。
我最终得到了一个小 python 脚本。它应该是 运行 手动,但它会自动同步。它适用于不想创建 Lambda 支持的自定义资源的懒人。
import subprocess
import json
STACK_NAME = ...
S3_RESOURCE = <name of your s3 resource, as in CloudFormation template file>
LOCAL_DIR = <path of your local dir>
res = subprocess.run(
['aws', 'cloudformation', 'describe-stack-resource', '--stack-name', STACK_NAME, '--logical-resource-id', S3_RESOURCE],
capture_output=True,
)
out = res.stdout.decode('utf-8')
resource_details = json.loads(out)
resource_id = resource_details['StackResourceDetail']['PhysicalResourceId']
res = subprocess.run(
['aws', 's3', 'sync', LOCAL_DIR, f's3://{resource_id}/', '--acl', 'public-read']
)