2019-08-14 23:27:08 +09:00

141 lines
4.4 KiB
JavaScript

'use strict';
const crypto = require('crypto');
const BbPromise = require('bluebird');
const _ = require('lodash');
const path = require('path');
class AwsCompileLayers {
constructor(serverless, options) {
this.serverless = serverless;
this.options = options;
const servicePath = this.serverless.config.servicePath || '';
this.packagePath =
this.serverless.service.package.path || path.join(servicePath || '.', '.serverless');
this.provider = this.serverless.getProvider('aws');
this.hooks = {
'package:compileLayers': () => BbPromise.bind(this).then(this.compileLayers),
};
}
compileLayer(layerName) {
const newLayer = this.cfLambdaLayerTemplate();
const layerObject = this.serverless.service.getLayer(layerName);
layerObject.package = layerObject.package || {};
const artifactFileName = this.provider.naming.getLayerArtifactName(layerName);
const artifactFilePath =
layerObject.package && layerObject.package.artifact
? layerObject.package.artifact
: path.join(this.serverless.config.servicePath, '.serverless', artifactFileName);
if (this.serverless.service.package.deploymentBucket) {
newLayer.Properties.Content.S3Bucket = this.serverless.service.package.deploymentBucket;
}
const s3Folder = this.serverless.service.package.artifactDirectoryName;
const s3FileName = artifactFilePath.split(path.sep).pop();
newLayer.Properties.Content.S3Key = `${s3Folder}/${s3FileName}`;
newLayer.Properties.LayerName = layerObject.name || layerName;
if (layerObject.description) {
newLayer.Properties.Description = layerObject.description;
}
if (layerObject.licenseInfo) {
newLayer.Properties.LicenseInfo = layerObject.licenseInfo;
}
if (layerObject.compatibleRuntimes) {
newLayer.Properties.CompatibleRuntimes = layerObject.compatibleRuntimes;
}
let layerLogicalId = this.provider.naming.getLambdaLayerLogicalId(layerName);
if (layerObject.retain) {
const sha = crypto
.createHash('sha1')
.update(JSON.stringify(_.omit(newLayer, ['Properties.Content.S3Key'])))
.digest('hex');
layerLogicalId = `${layerLogicalId}${sha}`;
newLayer.DeletionPolicy = 'Retain';
}
const newLayerObject = {
[layerLogicalId]: newLayer,
};
if (layerObject.allowedAccounts) {
layerObject.allowedAccounts.map(account => {
let parsedAccount = account;
// cast to string if account is number
if (typeof account === 'number' && !isNaN(account)) {
parsedAccount = `${account}`;
}
const newPermission = this.cfLambdaLayerPermissionTemplate();
newPermission.Properties.LayerVersionArn = { Ref: layerLogicalId };
newPermission.Properties.Principal = parsedAccount;
const layerPermLogicalId = this.provider.naming.getLambdaLayerPermissionLogicalId(
layerName,
parsedAccount
);
newLayerObject[layerPermLogicalId] = newPermission;
return newPermission;
});
}
_.merge(
this.serverless.service.provider.compiledCloudFormationTemplate.Resources,
newLayerObject
);
// Add layer to Outputs section
const layerOutputLogicalId = this.provider.naming.getLambdaLayerOutputLogicalId(layerName);
const newLayerOutput = this.cfOutputLayerTemplate();
newLayerOutput.Value = { Ref: layerLogicalId };
_.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Outputs, {
[layerOutputLogicalId]: newLayerOutput,
});
}
compileLayers() {
const allLayers = this.serverless.service.getAllLayers();
return BbPromise.each(allLayers, layerName => this.compileLayer(layerName));
}
cfLambdaLayerTemplate() {
return {
Type: 'AWS::Lambda::LayerVersion',
Properties: {
Content: {
S3Bucket: {
Ref: 'ServerlessDeploymentBucket',
},
S3Key: 'S3Key',
},
LayerName: 'LayerName',
},
};
}
cfLambdaLayerPermissionTemplate() {
return {
Type: 'AWS::Lambda::LayerVersionPermission',
Properties: {
Action: 'lambda:GetLayerVersion',
LayerVersionArn: 'LayerVersionArn',
Principal: 'Principal',
},
};
}
cfOutputLayerTemplate() {
return {
Description: 'Current Lambda layer version',
Value: 'Value',
};
}
}
module.exports = AwsCompileLayers;