I'm wondering if it's possible to leverage serverless.yml
to create a bucket and add a specific file to it during the deploy process of serverless-framework.
So far, I've been able to add the S3 resource that creates the bucket, but not sure how to add a specific file.
resources:
Resources:
UploadBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.s3.bucket}
AccessControl: Private
CorsConfiguration:
CorsRules:
- AllowedMethods:
- GET
- PUT
- POST
- HEAD
AllowedOrigins:
- "*"
AllowedHeaders:
- "*"
Not sure if it's possible, or how to leverage the serverless.yml
to upload a default file during the deploy process if it's not there yet.
You simply need an item in your S3 bucket that you can move for the purposes of creating a new folder. Select the dummy file (check the box) and select Move from the dropdown menu and click the Apply button. In the destination path, specify the folder name (e.g. newfolder) that you would like to create.
There is no official AWS CloudFormation resource that will manage (add/delete) an individual S3 Object within a Bucket, but you can create one with a Custom Resource that uses a Lambda function to call the PUT Object
/DELETE Object
APIs using the AWS SDK for NodeJS.
Here's a complete example CloudFormation template:
Description: Create an S3 Object using a Custom Resource.
Parameters:
BucketName:
Description: S3 Bucket Name (must not already exist)
Type: String
Key:
Description: S3 Object Key
Type: String
Body:
Description: S3 Object Body
Type: String
Resources:
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
S3Object:
Type: Custom::S3Object
Properties:
ServiceToken: !GetAtt S3ObjectFunction.Arn
Bucket: !Ref Bucket
Key: !Ref Key
Body: !Ref Body
S3ObjectFunction:
Type: AWS::Lambda::Function
Properties:
Description: S3 Object Custom Resource
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: !Sub |
var response = require('cfn-response');
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
exports.handler = function(event, context) {
var respond = (e) => response.send(event, context, e ? response.FAILED : response.SUCCESS, e ? e : {});
var params = event.ResourceProperties;
delete params.ServiceToken;
if (event.RequestType == 'Create' || event.RequestType == 'Update') {
s3.putObject(params).promise()
.then((data)=>respond())
.catch((e)=>respond(e));
} else if (event.RequestType == 'Delete') {
delete params.Body;
s3.deleteObject(params).promise()
.then((data)=>respond())
.catch((e)=>respond(e));
} else {
respond({Error: 'Invalid request type'});
}
};
Timeout: 30
Runtime: nodejs4.3
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: {Service: [lambda.amazonaws.com]}
Action: ['sts:AssumeRole']
Path: /
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
Policies:
- PolicyName: S3Policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 's3:PutObject'
- 'S3:DeleteObject'
Resource: !Sub "arn:aws:s3:::${BucketName}/${Key}"
You should be able to also use these resources within a serverless.yml
configuration file, though I'm not positive about how exactly Serverless integrates with CloudFormation resources/parameters.
If you're doing this to deploy a website, you can use serverless-finch and it will create the bucket for you automatically if it doesn't already exist.
Have you looked into the serverless-s3-sync plugin. It allows you to upload a folder to S3 from your local machine as part of the deployment.
plugins:
- serverless-s3-sync
custom:
s3Sync:
- bucketName: ${self:custom.s3.bucket} # required
bucketPrefix: assets/ # optional
localDir: dist/assets # required
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With