From f678e45b027823fb677e808f09deaf5822e9f102 Mon Sep 17 00:00:00 2001 From: Vlad Golubev Date: Fri, 6 Jan 2017 16:17:41 +0200 Subject: [PATCH 1/9] Add support of numeric template creation path, fix #3063 --- lib/plugins/create/create.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/plugins/create/create.js b/lib/plugins/create/create.js index 8da0f8a30..1bc0991e6 100644 --- a/lib/plugins/create/create.js +++ b/lib/plugins/create/create.js @@ -3,6 +3,7 @@ const BbPromise = require('bluebird'); const path = require('path'); const fse = require('fs-extra'); +const _ = require('lodash'); // class wide constants const validTemplates = [ @@ -66,9 +67,8 @@ class Create { } // store the custom options for the service if given - const boilerplatePath = this.options - .path && this.options.path.length ? this.options.path : null; - const serviceName = this.options.name && this.options.name.length ? this.options.name : null; + const boilerplatePath = _.toString(this.options.path); + const serviceName = _.toString(this.options.name); // create (if not yet present) and chdir into the directory for the service if (boilerplatePath) { From 0420a9c55b5993585f84da625df1b98e6b7ed0d6 Mon Sep 17 00:00:00 2001 From: Vlad Golubev Date: Fri, 6 Jan 2017 16:30:31 +0200 Subject: [PATCH 2/9] Add test: should create a service in the directory if using the "path" option with digits --- lib/plugins/create/create.test.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/plugins/create/create.test.js b/lib/plugins/create/create.test.js index d35e8f4c5..5597ec357 100644 --- a/lib/plugins/create/create.test.js +++ b/lib/plugins/create/create.test.js @@ -311,6 +311,30 @@ describe('Create', () => { }); }); + it('should create a service in the directory if using the "path" option with digits', () => { + const cwd = process.cwd(); + fse.mkdirsSync(tmpDir); + process.chdir(tmpDir); + + create.options.path = 123; + create.options.name = null; + + // using the nodejs template (this test is completely be independent from the template) + create.options.template = 'aws-nodejs'; + + return create.create().then(() => { + const serviceDir = path.join(tmpDir, String(create.options.path)); + + // check if files are created in the correct directory + expect(create.serverless.utils.fileExistsSync( + path.join(serviceDir, 'serverless.yml'))).to.be.equal(true); + expect(create.serverless.utils.fileExistsSync( + path.join(serviceDir, 'handler.js'))).to.be.equal(true); + + process.chdir(cwd); + }); + }); + it('should create a custom renamed service in the directory if using ' + 'the "path" and "name" option', () => { const cwd = process.cwd(); From 7c855a481b0725adb3bf478055134d59b1cd32df Mon Sep 17 00:00:00 2001 From: Vlad Golubev Date: Sat, 7 Jan 2017 00:41:10 +0200 Subject: [PATCH 3/9] 4x speed increase of ESLint by adding --cache --- .gitignore | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b7952abc4..266ff9083 100755 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,6 @@ admin.env tmp .coveralls.yml tmpdirs-serverless + +# ESLint cache +.eslintcache diff --git a/package.json b/package.json index e35fcc094..4ca9249b6 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ }, "scripts": { "test": "istanbul cover -x '**/*.test.js' node_modules/mocha/bin/_mocha '!(node_modules)/**/*.test.js' -- -R spec --recursive", - "lint": "eslint .", + "lint": "eslint . --cache", "docs": "node scripts/generate-readme.js", "simple-integration-test": "jest --maxWorkers=5 simple-suite", "complex-integration-test": "jest --maxWorkers=5 integration", From ce8bbc4885c6b4fe6aafa82ab49d585920696066 Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Sun, 8 Jan 2017 14:19:25 +0100 Subject: [PATCH 4/9] Add Docker detection --- lib/classes/Utils.js | 15 +++++++++++ lib/classes/Utils.test.js | 52 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/lib/classes/Utils.js b/lib/classes/Utils.js index 01dbc1566..781b3891b 100644 --- a/lib/classes/Utils.js +++ b/lib/classes/Utils.js @@ -20,6 +20,10 @@ class Utils { return version; } + getRootPath() { + return (os.platform() === 'win32') ? process.cwd().split(path.sep)[0] : '/'; + } + dirExistsSync(dirPath) { try { const stats = fse.statSync(dirPath); @@ -296,6 +300,16 @@ class Utils { hasCustomVariableSyntaxDefined = true; } + // wrap in try catch to make sure that missing permissions won't break anything + let isDockerContainer = false; + try { + const dockerenvFile = '.dockerenv'; + const dockerenvFilePath = path.join(this.getRootPath(), dockerenvFile); + isDockerContainer = this.fileExistsSync(dockerenvFilePath) || false; + } catch (exception) { + // do nothing + } + const data = { userId, event: 'framework_stat', @@ -336,6 +350,7 @@ class Utils { userAgent: (process.env.SERVERLESS_DASHBOARD) ? 'dashboard' : 'cli', serverlessVersion: serverless.version, nodeJsVersion: process.version, + isDockerContainer, isCISystem: !!((process.env.CI || process.env.JENKINS_URL) || false), }, }, diff --git a/lib/classes/Utils.test.js b/lib/classes/Utils.test.js index b45f139a1..cf758dc6e 100644 --- a/lib/classes/Utils.test.js +++ b/lib/classes/Utils.test.js @@ -371,6 +371,58 @@ describe('Utils', () => { }); }); + describe('when detecting Docker containers', () => { + let rootPathStub; + let rootDirPath; + let dockerenvFilePath; + + beforeEach(() => { + rootDirPath = testUtils.getTmpDirPath(); + dockerenvFilePath = path.join(rootDirPath, '.dockerenv'); + fse.mkdirsSync(rootDirPath); + fse.ensureFileSync(dockerenvFilePath); + + rootPathStub = sinon.stub(utils, 'getRootPath').returns(rootDirPath); + }); + + afterEach(() => { + utils.getRootPath.restore(); + }); + + it('should be able to detect Docker containers', () => + utils.logStat(serverless).then(() => { + expect(rootPathStub.calledOnce).to.equal(true); + expect(fetchStub.calledOnce).to.equal(true); + expect(fetchStub.args[0][0]).to.equal('https://api.segment.io/v1/track'); + expect(fetchStub.args[0][1].method).to.equal('POST'); + expect(fetchStub.args[0][1].timeout).to.equal('1000'); + + const parsedBody = JSON.parse(fetchStub.args[0][1].body); + + expect(parsedBody.properties.general.isDockerContainer) + .to.equal(true); + }) + ); + + it('should not throw error if .dockerenv file is not accessible', () => { + fs.chmodSync(dockerenvFilePath, '000'); + fs.chmodSync(rootDirPath, '400'); + + utils.logStat(serverless).then(() => { + expect(rootPathStub.calledOnce).to.equal(true); + expect(fetchStub.calledOnce).to.equal(true); + expect(fetchStub.args[0][0]).to.equal('https://api.segment.io/v1/track'); + expect(fetchStub.args[0][1].method).to.equal('POST'); + expect(fetchStub.args[0][1].timeout).to.equal('1000'); + + const parsedBody = JSON.parse(fetchStub.args[0][1].body); + + expect(parsedBody.properties.general.isDockerContainer) + .to.equal(false); + }); + }); + }); + it('should send the gathered information', () => { serverless.service = { service: 'new-service', From 2d2ba4521d2112ffdc78e044e6ce185ee114f2eb Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Mon, 9 Jan 2017 11:15:12 -0800 Subject: [PATCH 5/9] Update Docker detection to be cgroup based This ensures a more stable detection strategy since .dockerenv might be not around for the long term. --- lib/classes/Utils.js | 6 +++--- lib/classes/Utils.test.js | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/classes/Utils.js b/lib/classes/Utils.js index 781b3891b..31fad2ae3 100644 --- a/lib/classes/Utils.js +++ b/lib/classes/Utils.js @@ -303,9 +303,9 @@ class Utils { // wrap in try catch to make sure that missing permissions won't break anything let isDockerContainer = false; try { - const dockerenvFile = '.dockerenv'; - const dockerenvFilePath = path.join(this.getRootPath(), dockerenvFile); - isDockerContainer = this.fileExistsSync(dockerenvFilePath) || false; + const cgroupFilePath = path.join(this.getRootPath(), 'proc', '1', 'cgroup'); + const cgroupFileContent = fs.readFileSync(cgroupFilePath).toString(); + isDockerContainer = !!cgroupFileContent.match(/docker/); } catch (exception) { // do nothing } diff --git a/lib/classes/Utils.test.js b/lib/classes/Utils.test.js index cf758dc6e..8a404f61f 100644 --- a/lib/classes/Utils.test.js +++ b/lib/classes/Utils.test.js @@ -374,13 +374,15 @@ describe('Utils', () => { describe('when detecting Docker containers', () => { let rootPathStub; let rootDirPath; - let dockerenvFilePath; + let cgroupFilePath; beforeEach(() => { rootDirPath = testUtils.getTmpDirPath(); - dockerenvFilePath = path.join(rootDirPath, '.dockerenv'); + cgroupFilePath = path.join(rootDirPath, 'proc', '1', 'cgroup'); + const cgroupFileContent = '6:devices:/docker/3601745b3bd54d9780436faa5f0e4f72'; fse.mkdirsSync(rootDirPath); - fse.ensureFileSync(dockerenvFilePath); + fse.ensureFileSync(cgroupFilePath); + fs.writeFileSync(cgroupFilePath, cgroupFileContent); rootPathStub = sinon.stub(utils, 'getRootPath').returns(rootDirPath); }); @@ -404,8 +406,8 @@ describe('Utils', () => { }) ); - it('should not throw error if .dockerenv file is not accessible', () => { - fs.chmodSync(dockerenvFilePath, '000'); + it('should not throw error if cgroup file is not accessible', () => { + fs.chmodSync(cgroupFilePath, '000'); fs.chmodSync(rootDirPath, '400'); utils.logStat(serverless).then(() => { From dc8fe5c22f640b7a402a2b95228d6a43fbe6741c Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Tue, 10 Jan 2017 08:16:17 -0800 Subject: [PATCH 6/9] Remove unnecessary getRootPath method --- lib/classes/Utils.js | 6 +--- lib/classes/Utils.test.js | 63 ++++++++++----------------------------- 2 files changed, 17 insertions(+), 52 deletions(-) diff --git a/lib/classes/Utils.js b/lib/classes/Utils.js index 31fad2ae3..ec57f161c 100644 --- a/lib/classes/Utils.js +++ b/lib/classes/Utils.js @@ -20,10 +20,6 @@ class Utils { return version; } - getRootPath() { - return (os.platform() === 'win32') ? process.cwd().split(path.sep)[0] : '/'; - } - dirExistsSync(dirPath) { try { const stats = fse.statSync(dirPath); @@ -303,7 +299,7 @@ class Utils { // wrap in try catch to make sure that missing permissions won't break anything let isDockerContainer = false; try { - const cgroupFilePath = path.join(this.getRootPath(), 'proc', '1', 'cgroup'); + const cgroupFilePath = path.join('/', 'proc', '1', 'cgroup'); const cgroupFileContent = fs.readFileSync(cgroupFilePath).toString(); isDockerContainer = !!cgroupFileContent.match(/docker/); } catch (exception) { diff --git a/lib/classes/Utils.test.js b/lib/classes/Utils.test.js index 8a404f61f..7effb8bde 100644 --- a/lib/classes/Utils.test.js +++ b/lib/classes/Utils.test.js @@ -371,57 +371,26 @@ describe('Utils', () => { }); }); - describe('when detecting Docker containers', () => { - let rootPathStub; - let rootDirPath; - let cgroupFilePath; + it('should be able to detect Docker containers', () => { + const cgroupFileContent = '6:devices:/docker/3601745b3bd54d9780436faa5f0e4f72'; + const cgroupFilePath = path.join('/', 'proc', '1', 'cgroup'); + const cgroupFileContentStub = sinon.stub(fs, 'readFileSync') + .withArgs(cgroupFilePath) + .returns(cgroupFileContent); - beforeEach(() => { - rootDirPath = testUtils.getTmpDirPath(); - cgroupFilePath = path.join(rootDirPath, 'proc', '1', 'cgroup'); - const cgroupFileContent = '6:devices:/docker/3601745b3bd54d9780436faa5f0e4f72'; - fse.mkdirsSync(rootDirPath); - fse.ensureFileSync(cgroupFilePath); - fs.writeFileSync(cgroupFilePath, cgroupFileContent); + utils.logStat(serverless).then(() => { + expect(cgroupFileContentStub.calledOnce).to.equal(true); + expect(fetchStub.calledOnce).to.equal(true); + expect(fetchStub.args[0][0]).to.equal('https://api.segment.io/v1/track'); + expect(fetchStub.args[0][1].method).to.equal('POST'); + expect(fetchStub.args[0][1].timeout).to.equal('1000'); - rootPathStub = sinon.stub(utils, 'getRootPath').returns(rootDirPath); - }); + const parsedBody = JSON.parse(fetchStub.args[0][1].body); - afterEach(() => { - utils.getRootPath.restore(); - }); + expect(parsedBody.properties.general.isDockerContainer) + .to.equal(true); - it('should be able to detect Docker containers', () => - utils.logStat(serverless).then(() => { - expect(rootPathStub.calledOnce).to.equal(true); - expect(fetchStub.calledOnce).to.equal(true); - expect(fetchStub.args[0][0]).to.equal('https://api.segment.io/v1/track'); - expect(fetchStub.args[0][1].method).to.equal('POST'); - expect(fetchStub.args[0][1].timeout).to.equal('1000'); - - const parsedBody = JSON.parse(fetchStub.args[0][1].body); - - expect(parsedBody.properties.general.isDockerContainer) - .to.equal(true); - }) - ); - - it('should not throw error if cgroup file is not accessible', () => { - fs.chmodSync(cgroupFilePath, '000'); - fs.chmodSync(rootDirPath, '400'); - - utils.logStat(serverless).then(() => { - expect(rootPathStub.calledOnce).to.equal(true); - expect(fetchStub.calledOnce).to.equal(true); - expect(fetchStub.args[0][0]).to.equal('https://api.segment.io/v1/track'); - expect(fetchStub.args[0][1].method).to.equal('POST'); - expect(fetchStub.args[0][1].timeout).to.equal('1000'); - - const parsedBody = JSON.parse(fetchStub.args[0][1].body); - - expect(parsedBody.properties.general.isDockerContainer) - .to.equal(false); - }); + fs.readFileSync.restore(); }); }); From 791880911a4f008e7794b5bc1ff206c4e5d5537a Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Tue, 10 Jan 2017 08:57:43 -0800 Subject: [PATCH 7/9] Remove unnecessary assertions --- lib/classes/Utils.test.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/classes/Utils.test.js b/lib/classes/Utils.test.js index 7effb8bde..03f438d1b 100644 --- a/lib/classes/Utils.test.js +++ b/lib/classes/Utils.test.js @@ -380,10 +380,6 @@ describe('Utils', () => { utils.logStat(serverless).then(() => { expect(cgroupFileContentStub.calledOnce).to.equal(true); - expect(fetchStub.calledOnce).to.equal(true); - expect(fetchStub.args[0][0]).to.equal('https://api.segment.io/v1/track'); - expect(fetchStub.args[0][1].method).to.equal('POST'); - expect(fetchStub.args[0][1].timeout).to.equal('1000'); const parsedBody = JSON.parse(fetchStub.args[0][1].body); From b18f67e27bad1c4d324b177c8ae3dbcba7604b80 Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Tue, 10 Jan 2017 17:16:42 -0800 Subject: [PATCH 8/9] Fix Preuninstall Promise problem --- scripts/postinstall.js | 3 +-- scripts/preuninstall.js | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/postinstall.js b/scripts/postinstall.js index fde4a3cbc..24c69ecd2 100644 --- a/scripts/postinstall.js +++ b/scripts/postinstall.js @@ -1,10 +1,9 @@ -const BbPromise = require('bluebird'); const Serverless = require('../lib/Serverless'); const serverless = new Serverless(); (() => { serverless.init().then(() => { - serverless.utils.logStat(serverless, 'install').catch(() => BbPromise.resolve()); + serverless.utils.logStat(serverless, 'install').catch(() => Promise.resolve()); }); })(); diff --git a/scripts/preuninstall.js b/scripts/preuninstall.js index 085d6c2b4..7f372539a 100644 --- a/scripts/preuninstall.js +++ b/scripts/preuninstall.js @@ -1,10 +1,9 @@ -const BbPromise = require('bluebird'); const Serverless = require('../lib/Serverless'); const serverless = new Serverless(); (() => { serverless.init().then(() => { - serverless.utils.logStat(serverless, 'uninstall').catch(() => BbPromise.resolve()); + serverless.utils.logStat(serverless, 'uninstall').catch(() => Promise.resolve()); }); })(); From 912a40ac047822bae85418c68f56819c66f30a96 Mon Sep 17 00:00:00 2001 From: Alasdair Nicol Date: Wed, 11 Jan 2017 22:45:22 +0000 Subject: [PATCH 9/9] Update Python hello wold example to be consistent with Node.js --- .../aws/examples/hello-world/python/README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/providers/aws/examples/hello-world/python/README.md b/docs/providers/aws/examples/hello-world/python/README.md index 011ee4d61..d1e432b60 100644 --- a/docs/providers/aws/examples/hello-world/python/README.md +++ b/docs/providers/aws/examples/hello-world/python/README.md @@ -1,7 +1,7 @@ @@ -13,13 +13,14 @@ layout: Doc Make sure `serverless` is installed. [See installation guide](../../../guide/installation.md). -## 1. Deploy +## 1. Create a service +`serverless create --template aws-python --path myService` or `sls create --template aws-python --path myService`, where 'myService' is a new folder to be created with template service files. Change directories into this new folder. +## 2. Deploy `serverless deploy` or `sls deploy`. `sls` is shorthand for the serverless CLI command -## 2. Invoke deployed function - -`serverless invoke --function helloWorld` or `serverless invoke -f helloWorld` +## 3. Invoke deployed function +`serverless invoke --function hello` or `serverless invoke -f hello` `-f` is shorthand for `--function` @@ -27,7 +28,8 @@ In your terminal window you should see the response from AWS Lambda ```bash { - "message": "Hello World" + "statusCode": 200, + "body": "{\"message\":\"Go Serverless v1.0! Your function executed successfully!\",\"input\":{}}" } ```