Created
September 9, 2019 11:59
-
-
Save hakimio/01e51dfda185094ba4806f460d425ec3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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