Skip to content

Commit 6500e23

Browse files
abetomoDeviaVir
authored andcommitted
Add class for uploading deploy package to S3 (#454)
* Add class for uploading deploy package to S3 * Sort regions
1 parent 2349017 commit 6500e23

File tree

2 files changed

+218
-0
lines changed

2 files changed

+218
-0
lines changed

lib/s3_deploy.js

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
'use strict'
2+
3+
const crypto = require('crypto')
4+
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#createBucket-property
5+
const S3_LOCATION_POSSIBLE_VALUES = [
6+
'EU',
7+
'ap-northeast-1',
8+
'ap-south-1',
9+
'ap-southeast-1',
10+
'ap-southeast-2',
11+
'cn-north-1',
12+
'eu-central-1',
13+
'eu-west-1',
14+
'sa-east-1',
15+
'us-west-1',
16+
'us-west-2'
17+
]
18+
19+
class S3Deploy {
20+
constructor (aws, region) {
21+
// Authenticated `aws` object in `lib/main.js`
22+
this.s3 = new aws.S3({
23+
region: region,
24+
apiVersion: '2006-03-01'
25+
})
26+
}
27+
28+
_md5 (str) {
29+
return crypto
30+
.createHash('md5')
31+
.update(str, 'utf8')
32+
.digest('hex')
33+
}
34+
35+
_bucketName (params) {
36+
return [
37+
params.FunctionName,
38+
params.region,
39+
this._md5(params.FunctionName + params.region)
40+
]
41+
.join('-')
42+
.substr(0, 63)
43+
}
44+
45+
_s3Key (params) {
46+
return `deploy-package-${params.FunctionName}.zip`
47+
}
48+
49+
_getS3Location (region) {
50+
return S3_LOCATION_POSSIBLE_VALUES.includes(region) ? region : null
51+
}
52+
53+
_createBucket (params) {
54+
const _params = {
55+
Bucket: params.bucketName
56+
}
57+
const s3Locatoin = this._getS3Location(params.region)
58+
if (s3Locatoin != null) {
59+
_params.CreateBucketConfiguration = {
60+
LocationConstraint: s3Locatoin
61+
}
62+
}
63+
return new Promise((resolve, reject) => {
64+
this.s3.createBucket(_params, (err, data) => {
65+
if (err) {
66+
// Ignored created
67+
if (err.code === 'BucketAlreadyOwnedByYou') return resolve({})
68+
return reject(err)
69+
}
70+
resolve(data)
71+
})
72+
})
73+
}
74+
75+
_putObject (params, buffer) {
76+
const _params = {
77+
Body: buffer,
78+
Bucket: params.bucketName,
79+
Key: params.s3Key
80+
}
81+
return new Promise((resolve, reject) => {
82+
this.s3.putObject(_params, (err, data) => {
83+
if (err) reject(err)
84+
resolve(data)
85+
})
86+
})
87+
}
88+
89+
putPackage (params, region, buffer) {
90+
const _params = Object.assign({region: region}, params)
91+
_params.bucketName = this._bucketName(_params)
92+
_params.s3Key = this._s3Key(_params)
93+
94+
return this._createBucket(_params).then((result) => {
95+
if (result.Location != null) {
96+
console.log('=> S3 Bucket created:')
97+
console.log(`===> ${_params.bucketName}`)
98+
}
99+
return this._putObject(_params, buffer)
100+
}).then((result) => {
101+
console.log('=> Deploy the zip file to S3:')
102+
console.log(`===> ${_params.bucketName}/${_params.s3Key}`)
103+
return {
104+
S3Bucket: _params.bucketName,
105+
S3Key: _params.s3Key
106+
}
107+
})
108+
}
109+
}
110+
111+
module.exports = S3Deploy

test/s3_deploy.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
'use strict'
2+
3+
const {assert} = require('chai')
4+
const path = require('path')
5+
const aws = require('aws-sdk-mock')
6+
aws.setSDK(path.resolve('node_modules/aws-sdk'))
7+
const S3Deploy = require('../lib/s3_deploy')
8+
9+
const mockResponse = {
10+
createBucket: {'Location': 'createBucket'},
11+
putObject: {'ETag': 'putObject'}
12+
}
13+
14+
var s3Deploy = null
15+
16+
/* global describe, it, before, after */
17+
describe('lib/s3_deploy', () => {
18+
before(() => {
19+
aws.mock('S3', 'putObject', (params, callback) => {
20+
callback(null, mockResponse.putObject)
21+
})
22+
aws.mock('S3', 'createBucket', (params, callback) => {
23+
callback(null, mockResponse.createBucket)
24+
})
25+
26+
s3Deploy = new S3Deploy(require('aws-sdk'))
27+
})
28+
29+
after(() => {
30+
aws.restore('S3')
31+
})
32+
33+
describe('_md5', () => {
34+
it('md5("hoge") === "ea703e7aa1efda0064eaa507d9e8ab7e"', () => {
35+
assert.equal(s3Deploy._md5('hoge'), 'ea703e7aa1efda0064eaa507d9e8ab7e')
36+
})
37+
})
38+
39+
describe('_bucketName', () => {
40+
it('FunctionName + region + md5()', () => {
41+
const params = {
42+
FunctionName: 'node-lambda-name',
43+
region: 'test_region'
44+
}
45+
assert.equal(
46+
s3Deploy._bucketName(params),
47+
'node-lambda-name-test_region-aac849d59d2be828b793609e03d8241d'
48+
)
49+
})
50+
})
51+
52+
describe('_s3Key', () => {
53+
it('"deploy-package" + FunctionName + ".zip"', () => {
54+
const params = {FunctionName: 'node-lambda-name'}
55+
assert.equal(
56+
s3Deploy._s3Key(params),
57+
'deploy-package-node-lambda-name.zip'
58+
)
59+
})
60+
})
61+
62+
describe('_getS3Location', () => {
63+
it('is null', () => {
64+
assert.isNull(s3Deploy._getS3Location('hoge'))
65+
})
66+
67+
it('=== "ap-southeast-1"', () => {
68+
assert.equal(s3Deploy._getS3Location('ap-southeast-1'), 'ap-southeast-1')
69+
})
70+
})
71+
72+
describe('_createBucket', () => {
73+
it('using mock', () => {
74+
const params = {
75+
bucketName: 'node-lambda-test-bucket',
76+
region: 'ap-southeast-1'
77+
}
78+
return s3Deploy._createBucket(params).then((result) => {
79+
assert.deepEqual(result, mockResponse.createBucket)
80+
})
81+
})
82+
})
83+
84+
describe('_putObject', () => {
85+
it('using mock', () => {
86+
const params = {
87+
bucketName: 'node-lambda-test-bucket',
88+
s3Key: 'testKey'
89+
}
90+
return s3Deploy._putObject(params, 'buffer').then((result) => {
91+
assert.deepEqual(result, mockResponse.putObject)
92+
})
93+
})
94+
})
95+
96+
describe('putPackage', () => {
97+
it('using mock', () => {
98+
const params = {FunctionName: 'node-lambda-test-bucket-20180801'}
99+
return s3Deploy.putPackage(params, 'ap-southeast-1', 'buffer').then((result) => {
100+
assert.deepEqual(result, {
101+
S3Bucket: 'node-lambda-test-bucket-20180801-ap-southeast-1-6c696118a497125',
102+
S3Key: 'deploy-package-node-lambda-test-bucket-20180801.zip'
103+
})
104+
})
105+
})
106+
})
107+
})

0 commit comments

Comments
 (0)