Skip to content

Commit

Permalink
Added unit tests and slight refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
henhal committed Oct 22, 2019
1 parent d095768 commit a796584
Show file tree
Hide file tree
Showing 5 changed files with 1,054 additions and 38 deletions.
8 changes: 8 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
root = true

[*.js]
indent_style = space
indent_size = 2

[Makefile]
indent_style = tab
99 changes: 62 additions & 37 deletions LayerManagerPlugin.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
const {
LOG_LEVEL = 'info'
} = process.env;

const {execSync} = require('child_process');
const pascalcase = require('pascalcase');
const fs = require('fs');
Expand All @@ -9,71 +13,85 @@ const DEFAULT_CONFIG = {
exportPrefix: '${AWS::StackName}-'
};

function getLayers(serverless) {
return serverless.service.layers || {};
}

function getConfig(serverless) {
const custom = serverless.service.custom || {};

return {...DEFAULT_CONFIG, ...custom.layerConfig};
}
const LEVELS = {
none: 0,
info: 1,
verbose: 2
};

function log(...s) {
console.log('[layer-manager]', ...s);
}

function verbose({level}, ...s) {
level === 'verbose' && log(...s);
LEVELS[level] >= LEVELS.verbose && log(...s);
}

function info({level}, ...s) {
log(...s);
LEVELS[level] >= LEVELS.info && log(...s);
}

function getLayers(serverless) {
return serverless.service.layers || {};
}

function getConfig(serverless) {
const custom = serverless.service.custom || {};

return {...DEFAULT_CONFIG, ...custom.layerConfig};
}

class LayerManagerPlugin {
constructor(sls, options = {}) {
this.level = options.v || options.verbose ? 'verbose' : 'info';
this.level = options.v || options.verbose ? 'verbose' : LOG_LEVEL;
this.config = getConfig(sls);

info(this, `Invoking layer-manager plugin`);
verbose(this, `Config: `, this.config);

this.hooks = {
'package:initialize': () => this.installLayers(sls),
'before:deploy:deploy': () => this.transformLayerResources(sls)
};
}

installLayer(path) {
const nodeLayerPath = `${path}/nodejs`;

if (fs.existsSync(nodeLayerPath)) {
verbose(this, `Installing nodejs layer ${path}`);
execSync(`npm install --prefix ${nodeLayerPath}`, {
stdio: 'inherit'
});
return true;
}

return false;
}

installLayers(sls) {
const config = getConfig(sls);
const {installLayers} = this.config;

if (!config.installLayers) {
if (!installLayers) {
verbose(this, `Skipping installation of layers as per config`);
return;
}

const layers = getLayers(sls);
let i = 0;
Object.values(layers).forEach(({path}) => {
const nodeLayerPath = `${path}/nodejs`;

if (fs.existsSync(nodeLayerPath)) {
verbose(this, `Installing nodejs layer ${path}`);
execSync(`npm install --prefix ${nodeLayerPath}`, {
stdio: 'inherit'
});
i++;
}
});
const installedLayers = Object.values(layers)
.filter(({path}) => this.installLayer(path));

info(this, `Installed ${installedLayers.length} layers`);

info(this, `Installed ${i} layers`);
return {installedLayers};
}

transformLayerResources(sls) {
const config = getConfig(sls);
const {exportLayers, exportPrefix, upgradeLayerReferences} = this.config;
const layers = getLayers(sls);
const {compiledCloudFormationTemplate: cf} = sls.service.provider;

Object.keys(layers).forEach(id => {
return Object.keys(layers).reduce((result, id) => {
const name = pascalcase(id);
const exportName = `${name}LambdaLayerQualifiedArn`;
const output = cf.Outputs[exportName];
Expand All @@ -82,28 +100,30 @@ class LayerManagerPlugin {
return;
}

if (config.exportLayers) {
if (exportLayers) {
output.Export = {
Name: {
'Fn::Sub': config.exportPrefix + exportName
'Fn::Sub': exportPrefix + exportName
}
};
result.exportedLayers.push(output);
}

if (config.upgradeLayerReferences) {
if (upgradeLayerReferences) {
const resourceRef = `${name}LambdaLayer`;
const versionedResourceRef = output.Value.Ref;

if (resourceRef !== versionedResourceRef) {
info(this, `Replacing references to ${resourceRef} with ${versionedResourceRef}`);

Object.entries(cf.Resources)
.forEach(([id, {Type, Properties: {Layers = []} = {}}]) => {
if (Type === 'AWS::Lambda::Function') {
Layers.forEach(Layer => {
if (Layer.Ref === resourceRef) {
.forEach(([id, {Type: type, Properties: {Layers: layers = []} = {}}]) => {
if (type === 'AWS::Lambda::Function') {
layers.forEach(layer => {
if (layer.Ref === resourceRef) {
verbose(this, `${id}: Updating reference to layer version ${versionedResourceRef}`);
Layer.Ref = versionedResourceRef;
layer.Ref = versionedResourceRef;
result.upgradedLayerReferences.push(layer);
}
})
}
Expand All @@ -112,6 +132,11 @@ class LayerManagerPlugin {
}

verbose(this, 'CF after transformation:\n', JSON.stringify(cf, null, 2));

return result;
}, {
exportedLayers: [],
upgradedLayerReferences: []
});
}
}
Expand Down
Loading

0 comments on commit a796584

Please sign in to comment.