Skip to content

Instantly share code, notes, and snippets.

@hakimio
Created September 9, 2019 11:59
Show Gist options
  • Select an option

  • Save hakimio/01e51dfda185094ba4806f460d425ec3 to your computer and use it in GitHub Desktop.

Select an option

Save hakimio/01e51dfda185094ba4806f460d425ec3 to your computer and use it in GitHub Desktop.
diff --git a/node_modules/serverless/bin/serverless.js b/node_modules/serverless/bin/serverless.js
index 82bc47a..77d4a01 100644
--- a/node_modules/serverless/bin/serverless.js
+++ b/node_modules/serverless/bin/serverless.js
@@ -2,6 +2,13 @@
'use strict';
+// global graceful-fs patch
+// https://github.com/isaacs/node-graceful-fs#global-patching
+const realFs = require('fs');
+const gracefulFs = require('graceful-fs');
+
+gracefulFs.gracefulify(realFs);
+
const userNodeVersion = Number(process.version.split('.')[0].slice(1));
// only check for components if user is running Node 8
diff --git a/node_modules/serverless/lib/classes/Utils.js b/node_modules/serverless/lib/classes/Utils.js
index 38a4a1e..d85fb52 100644
--- a/node_modules/serverless/lib/classes/Utils.js
+++ b/node_modules/serverless/lib/classes/Utils.js
@@ -10,6 +10,7 @@ const fse = BbPromise.promisifyAll(require('fs-extra'));
const _ = require('lodash');
const fileExistsSync = require('../utils/fs/fileExistsSync');
const writeFileSync = require('../utils/fs/writeFileSync');
+const writeFileDir = require('../utils/fs/writeFileDir');
const copyDirContentsSync = require('../utils/fs/copyDirContentsSync');
const readFileSync = require('../utils/fs/readFileSync');
const walkDirSync = require('../utils/fs/walkDirSync');
@@ -48,7 +49,7 @@ class Utils {
}
writeFileDir(filePath) {
- return fse.mkdirsSync(path.dirname(filePath));
+ return writeFileDir(filePath);
}
writeFileSync(filePath, contents, cycles) {
diff --git a/node_modules/serverless/lib/plugins/aws/customResources/index.js b/node_modules/serverless/lib/plugins/aws/customResources/index.js
index 2a035f5..b24620a 100644
--- a/node_modules/serverless/lib/plugins/aws/customResources/index.js
+++ b/node_modules/serverless/lib/plugins/aws/customResources/index.js
@@ -3,7 +3,6 @@
const path = require('path');
const crypto = require('crypto');
const BbPromise = require('bluebird');
-const _ = require('lodash');
const fse = BbPromise.promisifyAll(require('fs-extra'));
const childProcess = BbPromise.promisifyAll(require('child_process'));
const getTmpDirPath = require('../../../utils/fs/getTmpDirPath');
@@ -14,17 +13,22 @@ function copyCustomResources(srcDirPath, destDirPath) {
}
function installDependencies(dirPath) {
- return childProcess.execAsync(`npm install --prefix ${dirPath}`);
+ // only install production depenencies
+ // see: https://github.com/serverless/serverless/issues/6557
+ return childProcess.execAsync(`npm install --prefix ${dirPath} --production`);
}
function addCustomResourceToService(awsProvider, resourceName, iamRoleStatements) {
- let FunctionName;
+ let functionName;
+ let absoluteFunctionName;
let Handler;
let customResourceFunctionLogicalId;
const { serverless } = awsProvider;
const { cliOptions } = serverless.pluginManager;
- const { Resources } = serverless.service.provider.compiledCloudFormationTemplate;
+ const providerConfig = serverless.service.provider;
+ const shouldWriteLogs = providerConfig.logs && providerConfig.logs.frameworkLambda;
+ const { Resources } = providerConfig.compiledCloudFormationTemplate;
const customResourcesRoleLogicalId = awsProvider.naming.getCustomResourcesRoleLogicalId();
const srcDirPath = path.join(__dirname, 'resources');
const destDirPath = path.join(
@@ -39,31 +43,32 @@ function addCustomResourceToService(awsProvider, resourceName, iamRoleStatements
// check which custom resource should be used
if (resourceName === 's3') {
- FunctionName = `${funcPrefix}-${awsProvider.naming.getCustomResourceS3HandlerFunctionName()}`;
+ functionName = awsProvider.naming.getCustomResourceS3HandlerFunctionName();
Handler = 's3/handler.handler';
customResourceFunctionLogicalId = awsProvider.naming.getCustomResourceS3HandlerFunctionLogicalId();
} else if (resourceName === 'cognitoUserPool') {
- FunctionName = `${funcPrefix}-${awsProvider.naming.getCustomResourceCognitoUserPoolHandlerFunctionName()}`;
+ functionName = awsProvider.naming.getCustomResourceCognitoUserPoolHandlerFunctionName();
Handler = 'cognitoUserPool/handler.handler';
customResourceFunctionLogicalId = awsProvider.naming.getCustomResourceCognitoUserPoolHandlerFunctionLogicalId();
} else if (resourceName === 'eventBridge') {
- FunctionName = `${funcPrefix}-${awsProvider.naming.getCustomResourceEventBridgeHandlerFunctionName()}`;
+ functionName = awsProvider.naming.getCustomResourceEventBridgeHandlerFunctionName();
Handler = 'eventBridge/handler.handler';
customResourceFunctionLogicalId = awsProvider.naming.getCustomResourceEventBridgeHandlerFunctionLogicalId();
} else if (resourceName === 'apiGatewayCloudWatchRole') {
- FunctionName = `${funcPrefix}-${awsProvider.naming.getCustomResourceApiGatewayAccountCloudWatchRoleHandlerFunctionName()}`;
+ functionName = awsProvider.naming.getCustomResourceApiGatewayAccountCloudWatchRoleHandlerFunctionName();
Handler = 'apiGatewayCloudWatchRole/handler.handler';
customResourceFunctionLogicalId = awsProvider.naming.getCustomResourceApiGatewayAccountCloudWatchRoleHandlerFunctionLogicalId();
} else {
return BbPromise.reject(`No implementation found for Custom Resource "${resourceName}"`);
}
- if (FunctionName.length > 64) {
+ absoluteFunctionName = `${funcPrefix}-${functionName}`;
+ if (absoluteFunctionName.length > 64) {
// Function names cannot be longer than 64.
// Temporary solution until we have https://github.com/serverless/serverless/issues/6598
// (which doesn't change names of already deployed functions)
- FunctionName = `${FunctionName.slice(0, 32)}${crypto
+ absoluteFunctionName = `${absoluteFunctionName.slice(0, 32)}${crypto
.createHash('md5')
- .update(FunctionName)
+ .update(absoluteFunctionName)
.digest('hex')}`;
}
@@ -114,20 +119,47 @@ function addCustomResourceToService(awsProvider, resourceName, iamRoleStatements
},
PolicyDocument: {
Version: '2012-10-17',
- Statement: iamRoleStatements,
+ Statement: [],
},
},
],
},
};
- } else {
- const { Statement } = customResourceRole.Properties.Policies[0].PolicyDocument;
- iamRoleStatements.forEach(newStmt => {
- if (!Statement.find(existingStmt => existingStmt.Resource === newStmt.Resource)) {
- Statement.push(newStmt);
- }
- });
+
+ if (shouldWriteLogs) {
+ const logGroupsPrefix = awsProvider.naming.getLogGroupName(funcPrefix);
+ customResourceRole.Properties.Policies[0].PolicyDocument.Statement.push(
+ {
+ Effect: 'Allow',
+ Action: ['logs:CreateLogStream'],
+ Resource: [
+ {
+ 'Fn::Sub':
+ 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' +
+ `:log-group:${logGroupsPrefix}*:*`,
+ },
+ ],
+ },
+ {
+ Effect: 'Allow',
+ Action: ['logs:PutLogEvents'],
+ Resource: [
+ {
+ 'Fn::Sub':
+ 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' +
+ `:log-group:${logGroupsPrefix}*:*:*`,
+ },
+ ],
+ }
+ );
+ }
}
+ const { Statement } = customResourceRole.Properties.Policies[0].PolicyDocument;
+ iamRoleStatements.forEach(newStmt => {
+ if (!Statement.find(existingStmt => existingStmt.Resource === newStmt.Resource)) {
+ Statement.push(newStmt);
+ }
+ });
const customResourceFunction = {
Type: 'AWS::Lambda::Function',
@@ -136,7 +168,7 @@ function addCustomResourceToService(awsProvider, resourceName, iamRoleStatements
S3Bucket,
S3Key,
},
- FunctionName,
+ FunctionName: absoluteFunctionName,
Handler,
MemorySize: 1024,
Role: {
@@ -148,10 +180,25 @@ function addCustomResourceToService(awsProvider, resourceName, iamRoleStatements
DependsOn: [customResourcesRoleLogicalId],
};
- _.merge(Resources, {
+ Object.assign(Resources, {
[customResourceFunctionLogicalId]: customResourceFunction,
[customResourcesRoleLogicalId]: customResourceRole,
});
+
+ if (shouldWriteLogs) {
+ const customResourceLogGroupLogicalId = awsProvider.naming.getLogGroupLogicalId(
+ functionName
+ );
+ customResourceFunction.DependsOn.push(customResourceLogGroupLogicalId);
+ Object.assign(Resources, {
+ [customResourceLogGroupLogicalId]: {
+ Type: 'AWS::Logs::LogGroup',
+ Properties: {
+ LogGroupName: awsProvider.naming.getLogGroupName(absoluteFunctionName),
+ },
+ },
+ });
+ }
});
}
diff --git a/node_modules/serverless/lib/plugins/package/lib/zipService.js b/node_modules/serverless/lib/plugins/package/lib/zipService.js
index 739d40b..8532634 100644
--- a/node_modules/serverless/lib/plugins/package/lib/zipService.js
+++ b/node_modules/serverless/lib/plugins/package/lib/zipService.js
@@ -1,14 +1,14 @@
'use strict';
const BbPromise = require('bluebird');
-const archiver = require('archiver');
const os = require('os');
const path = require('path');
const crypto = require('crypto');
-const fs = BbPromise.promisifyAll(require('graceful-fs'));
+const fs = BbPromise.promisifyAll(require('fs'));
const childProcess = BbPromise.promisifyAll(require('child_process'));
const globby = require('globby');
const _ = require('lodash');
+const createZipFile = require('../../../utils/fs/createZipFile');
module.exports = {
zipService(exclude, include, zipFileName) {
@@ -63,56 +63,10 @@ module.exports = {
* used for golang support on windows.
*/
zipFiles(files, zipFileName, prefix, filesToChmodPlusX) {
- if (files.length === 0) {
- const error = new this.serverless.classes.Error('No files to package');
- return BbPromise.reject(error);
- }
-
- const zip = archiver.create('zip');
- // Create artifact in temp path and move it to the package path (if any) later
- const artifactFilePath = path.join(
- this.serverless.config.servicePath,
- '.serverless',
- zipFileName
- );
- this.serverless.utils.writeFileDir(artifactFilePath);
-
- const output = fs.createWriteStream(artifactFilePath);
-
- return new BbPromise((resolve, reject) => {
- output.on('close', () => resolve(artifactFilePath));
- output.on('error', err => reject(err));
- zip.on('error', err => reject(err));
-
- output.on('open', () => {
- zip.pipe(output);
+ const srcDirPath = this.serverless.config.servicePath;
+ const zipFilePath = path.join(this.serverless.config.servicePath, '.serverless', zipFileName);
- const normalizedFiles = _.uniq(files.map(file => path.normalize(file)));
-
- return BbPromise.all(normalizedFiles.map(this.getFileContentAndStat.bind(this)))
- .then(contents => {
- _.forEach(_.sortBy(contents, ['filePath']), file => {
- const name = file.filePath.slice(prefix ? `${prefix}${path.sep}`.length : 0);
- let mode = file.stat.mode;
- if (
- filesToChmodPlusX &&
- _.includes(filesToChmodPlusX, name) &&
- file.stat.mode % 2 === 0
- ) {
- mode += 1;
- }
- zip.append(file.data, {
- name,
- mode,
- date: new Date(0), // necessary to get the same hash when zipping the same content
- });
- });
-
- zip.finalize();
- })
- .catch(reject);
- });
- });
+ return createZipFile(srcDirPath, zipFilePath, files, { files, prefix, filesToChmodPlusX });
},
getFileContentAndStat(filePath) {
diff --git a/node_modules/serverless/lib/utils/fs/createZipFile.js b/node_modules/serverless/lib/utils/fs/createZipFile.js
index 5207313..35e79f3 100644
--- a/node_modules/serverless/lib/utils/fs/createZipFile.js
+++ b/node_modules/serverless/lib/utils/fs/createZipFile.js
@@ -1,38 +1,87 @@
'use strict';
-const fs = require('fs');
const path = require('path');
+const _ = require('lodash');
const archiver = require('archiver');
const BbPromise = require('bluebird');
-const walkDirSync = require('../fs/walkDirSync');
+const fs = BbPromise.promisifyAll(require('fs'));
+const walkDirSync = require('./walkDirSync');
+const writeFileDir = require('./writeFileDir');
+const getFileContent = require('./getFileContent');
-function createZipFile(srcDirPath, outputFilePath) {
- const files = walkDirSync(srcDirPath).map(file => ({
- input: file,
- output: file.replace(path.join(srcDirPath, path.sep), ''),
+function getFileContentAndStat(filePath, fullPath) {
+ return BbPromise.all([
+ // Get file contents and stat in parallel
+ getFileContent(fullPath),
+ fs.statAsync(fullPath),
+ ]).then(result => ({
+ data: result[0],
+ stat: result[1],
+ filePath,
}));
+}
+
+function createZipFile(srcDirPath, zipFilePath, opts) {
+ let files;
+ let prefix;
+ let filesToChmodPlusX;
+ if (opts) {
+ files = opts.prefix;
+ prefix = opts.prefix;
+ filesToChmodPlusX = opts.filesToChmodPlusX;
+
+ if (files && files.length === 0) {
+ return BbPromise.reject('No files to package');
+ }
+ }
+
+ if (!files) {
+ // NOTE: this can be really slow for large directories
+ files = walkDirSync(srcDirPath).map(file => file.replace(path.join(srcDirPath, path.sep), ''));
+ }
+
+ const zip = archiver.create('zip');
+ writeFileDir(zipFilePath);
+
+ const output = fs.createWriteStream(zipFilePath);
return new BbPromise((resolve, reject) => {
- const output = fs.createWriteStream(outputFilePath);
- const archive = archiver('zip', {
- zlib: { level: 9 },
- });
+ output.on('close', () => resolve(zipFilePath));
+ output.on('error', err => reject(err));
+ zip.on('error', err => reject(err));
output.on('open', () => {
- archive.pipe(output);
+ zip.pipe(output);
- files.forEach(file => {
- // TODO: update since this is REALLY slow
- if (fs.lstatSync(file.input).isFile()) {
- archive.append(fs.createReadStream(file.input), { name: file.output });
- }
- });
+ const normalizedFiles = _.uniq(files.map(file => path.normalize(file)));
- archive.finalize();
- });
+ return BbPromise.all(
+ normalizedFiles.map(filePath =>
+ getFileContentAndStat(filePath, path.resolve(srcDirPath, filePath))
+ )
+ )
+ .then(contents => {
+ _.forEach(_.sortBy(contents, ['filePath']), file => {
+ const name = file.filePath.slice(prefix ? `${prefix}${path.sep}`.length : 0);
+ let mode = file.stat.mode;
+ if (
+ filesToChmodPlusX &&
+ _.includes(filesToChmodPlusX, name) &&
+ file.stat.mode % 2 === 0
+ ) {
+ mode += 1;
+ }
+ zip.append(file.data, {
+ name,
+ mode,
+ date: new Date(0), // necessary to get the same hash when zipping the same content
+ });
+ });
- archive.on('error', err => reject(err));
- output.on('close', () => resolve(outputFilePath));
+ zip.finalize();
+ })
+ .catch(reject);
+ });
});
}
diff --git a/node_modules/serverless/lib/utils/fs/getFileContent.js b/node_modules/serverless/lib/utils/fs/getFileContent.js
new file mode 100644
index 0000000..00c9f1e
--- /dev/null
+++ b/node_modules/serverless/lib/utils/fs/getFileContent.js
@@ -0,0 +1,10 @@
+'use strict';
+
+const BbPromise = require('bluebird');
+const fs = BbPromise.promisifyAll(require('fs'));
+
+function getFileContent(fullPath) {
+ return fs.readFileAsync(fullPath);
+}
+
+module.exports = getFileContent;
diff --git a/node_modules/serverless/lib/utils/fs/writeFileDir.js b/node_modules/serverless/lib/utils/fs/writeFileDir.js
new file mode 100644
index 0000000..f225ce0
--- /dev/null
+++ b/node_modules/serverless/lib/utils/fs/writeFileDir.js
@@ -0,0 +1,10 @@
+'use strict';
+
+const path = require('path');
+const fse = require('fs-extra');
+
+function writeFileDir(filePath) {
+ return fse.mkdirsSync(path.dirname(filePath));
+}
+
+module.exports = writeFileDir;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment