From 5e9116d9cbbce2fb6e19b41f14e28d8198929c56 Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Mon, 12 Dec 2016 16:02:01 +0100 Subject: [PATCH 01/11] Add service wide metrics support --- docs/providers/aws/cli-reference/metrics.md | 28 +- lib/plugins/aws/metrics/awsMetrics.js | 304 +++++++++++--------- lib/plugins/aws/metrics/awsMetrics.test.js | 296 ++++++++++++++++--- lib/plugins/metrics/metrics.js | 1 - lib/plugins/metrics/metrics.test.js | 5 - 5 files changed, 443 insertions(+), 191 deletions(-) diff --git a/docs/providers/aws/cli-reference/metrics.md b/docs/providers/aws/cli-reference/metrics.md index d407d06a4..02c5d8b2a 100644 --- a/docs/providers/aws/cli-reference/metrics.md +++ b/docs/providers/aws/cli-reference/metrics.md @@ -15,12 +15,12 @@ layout: Doc Lets you watch the metrics of a specific function. ```bash -serverless metrics --function hello +serverless metrics ``` ## Options -- `--function` or `-f` The function you want to fetch the metrics for. **Required** +- `--function` or `-f` The function you want to fetch the metrics for. - `--stage` or `-s` The stage you want to view the function metrics for. If not provided, the plugin will use the default stage listed in `serverless.yml`. If that doesn't exist either it'll just fetch the metrics from the `dev` stage. - `--region` or `-r` The region you want to view the function metrics for. If not provided, the plugin will use the default region listed in `serverless.yml`. If that doesn't exist either it'll just fetch the metrics from the `us-east-1` region. - `--startTime` A specific unit in time to start fetching metrics from (ie: `2010-10-20`, `1469705761`, `30m` (30 minutes ago), `2h` (2 days ago) or `3d` (3 days ago)). Date formats should be written in ISO 8601. Defaults to 24h ago. @@ -30,18 +30,34 @@ serverless metrics --function hello **Note:** There's a small lag between invoking the function and actually having access to the metrics. It takes a few seconds for the metrics to show up right after invoking the function. -### See all metrics of the last 24h +### See service wide metrics for the last 24h + +```bash +serverless metrics +``` + +Displays service wide metrics for the last 24h. + +### See service wide metrics for a specific timespan + +```bash +serverless metrics --startTime 1970-01-01 --endTime 1970-01-02 +``` + +Displays service wide metrics for the time between January 1, 1970 and January 2, 1970. + +### See all metrics for the function `hello` of the last 24h ```bash serverless metrics --function hello ``` -Displays all metrics for the last 24h. +Displays all `hello` function metrics for the last 24h. -### See metrics for a specific timespan +### See metrics for the function `hello` of a specific timespan ```bash serverless metrics --function hello --startTime 1970-01-01 --endTime 1970-01-02 ``` -Displays all metrics for the time between January 1, 1970 and January 2, 1970. +Displays all `hello` function metrics for the time between January 1, 1970 and January 2, 1970. diff --git a/lib/plugins/aws/metrics/awsMetrics.js b/lib/plugins/aws/metrics/awsMetrics.js index d32835bcc..000234390 100644 --- a/lib/plugins/aws/metrics/awsMetrics.js +++ b/lib/plugins/aws/metrics/awsMetrics.js @@ -25,9 +25,6 @@ class AwsMetrics { extendedValidate() { this.validate(); - // validate function exists in service - this.options.function = this.serverless.service.getFunction(this.options.function).name; - const today = new Date(); let yesterday = new Date(); yesterday = yesterday.setDate(yesterday.getDate() - 1); @@ -55,160 +52,189 @@ class AwsMetrics { } getMetrics() { - const FunctionName = this.options.function; - const StartTime = this.options.startTime; - const EndTime = this.options.endTime; - const Namespace = 'AWS/Lambda'; + // get all the function names in the service + let functions = this.serverless.service.getAllFunctions() + .map((func) => this.serverless.service.getFunction(func).name); - const hoursDiff = Math.abs(EndTime - StartTime) / 36e5; - const Period = (hoursDiff > 24) ? 3600 * 24 : 3600; + if (this.options.function) { + // validate if function can be found in service + this.options.function = this.serverless.service.getFunction(this.options.function).name; - const promises = []; + // filter out the one function the user has specified through an option + functions = functions.filter((func) => func === this.options.function); + } - // get invocations - const invocationsPromise = - this.provider.request( - 'CloudWatch', - 'getMetricStatistics', - { - StartTime, - EndTime, - MetricName: 'Invocations', - Namespace, - Period, - Dimensions: [ - { - Name: 'FunctionName', - Value: FunctionName, - }, - ], - Statistics: [ - 'Sum', - ], - Unit: 'Count', - }, - this.options.stage, - this.options.region - ); - // get throttles - const throttlesPromise = - this.provider.request( - 'CloudWatch', - 'getMetricStatistics', - { - StartTime, - EndTime, - MetricName: 'Throttles', - Namespace, - Period, - Dimensions: [ - { - Name: 'FunctionName', - Value: FunctionName, - }, - ], - Statistics: [ - 'Sum', - ], - Unit: 'Count', - }, - this.options.stage, - this.options.region - ); - // get errors - const errorsPromise = - this.provider.request( - 'CloudWatch', - 'getMetricStatistics', - { - StartTime, - EndTime, - MetricName: 'Errors', - Namespace, - Period, - Dimensions: [ - { - Name: 'FunctionName', - Value: FunctionName, - }, - ], - Statistics: [ - 'Sum', - ], - Unit: 'Count', - }, - this.options.stage, - this.options.region - ); - // get avg. duration - const avgDurationPromise = - this.provider.request( - 'CloudWatch', - 'getMetricStatistics', - { - StartTime, - EndTime, - MetricName: 'Duration', - Namespace, - Period, - Dimensions: [ - { - Name: 'FunctionName', - Value: FunctionName, - }, - ], - Statistics: [ - 'Average', - ], - Unit: 'Milliseconds', - }, - this.options.stage, - this.options.region - ); + return BbPromise.map(functions, (func) => { + const FunctionName = func; + const StartTime = this.options.startTime; + const EndTime = this.options.endTime; + const Namespace = 'AWS/Lambda'; - // push all promises to the array which will be used to resolve those - promises.push(invocationsPromise); - promises.push(throttlesPromise); - promises.push(errorsPromise); - promises.push(avgDurationPromise); + const hoursDiff = Math.abs(EndTime - StartTime) / 36e5; + const Period = (hoursDiff > 24) ? 3600 * 24 : 3600; - return BbPromise.all(promises).then((metrics) => metrics); + const promises = []; + + // get invocations + const invocationsPromise = + this.provider.request( + 'CloudWatch', + 'getMetricStatistics', + { + StartTime, + EndTime, + MetricName: 'Invocations', + Namespace, + Period, + Dimensions: [ + { + Name: 'FunctionName', + Value: FunctionName, + }, + ], + Statistics: [ + 'Sum', + ], + Unit: 'Count', + }, + this.options.stage, + this.options.region + ); + // get throttles + const throttlesPromise = + this.provider.request( + 'CloudWatch', + 'getMetricStatistics', + { + StartTime, + EndTime, + MetricName: 'Throttles', + Namespace, + Period, + Dimensions: [ + { + Name: 'FunctionName', + Value: FunctionName, + }, + ], + Statistics: [ + 'Sum', + ], + Unit: 'Count', + }, + this.options.stage, + this.options.region + ); + // get errors + const errorsPromise = + this.provider.request( + 'CloudWatch', + 'getMetricStatistics', + { + StartTime, + EndTime, + MetricName: 'Errors', + Namespace, + Period, + Dimensions: [ + { + Name: 'FunctionName', + Value: FunctionName, + }, + ], + Statistics: [ + 'Sum', + ], + Unit: 'Count', + }, + this.options.stage, + this.options.region + ); + // get avg. duration + const avgDurationPromise = + this.provider.request( + 'CloudWatch', + 'getMetricStatistics', + { + StartTime, + EndTime, + MetricName: 'Duration', + Namespace, + Period, + Dimensions: [ + { + Name: 'FunctionName', + Value: FunctionName, + }, + ], + Statistics: [ + 'Average', + ], + Unit: 'Milliseconds', + }, + this.options.stage, + this.options.region + ); + + // push all promises to the array which will be used to resolve those + promises.push(invocationsPromise); + promises.push(throttlesPromise); + promises.push(errorsPromise); + promises.push(avgDurationPromise); + + return BbPromise.all(promises).then((metrics) => metrics); + }); } showMetrics(metrics) { let message = ''; - message += `${chalk.yellow.underline(this.options.function)}\n`; + if (this.options.function) { + message += `${chalk.yellow.underline(this.options.function)}\n`; + } else { + message += `${chalk.yellow.underline('Service wide metrics')}\n`; + } const formattedStartTime = moment(this.options.startTime).format('LLL'); const formattedEndTime = moment(this.options.endTime).format('LLL'); message += `${formattedStartTime} - ${formattedEndTime}\n\n`; if (metrics && metrics.length > 0) { + let invocations = 0; + let throttles = 0; + let errors = 0; + let duration = 0; + _.forEach(metrics, (metric) => { - if (metric.Label === 'Invocations') { - const datapoints = metric.Datapoints; - const invocations = datapoints - .reduce((previous, datapoint) => previous + datapoint.Sum, 0); - message += `${chalk.yellow('Invocations:', invocations, '\n')}`; - } else if (metric.Label === 'Throttles') { - const datapoints = metric.Datapoints; - const throttles = datapoints - .reduce((previous, datapoint) => previous + datapoint.Sum, 0); - message += `${chalk.yellow('Throttles:', throttles, '\n')}`; - } else if (metric.Label === 'Errors') { - const datapoints = metric.Datapoints; - const errors = datapoints - .reduce((previous, datapoint) => previous + datapoint.Sum, 0); - message += `${chalk.yellow('Errors:', errors, '\n')}`; - } else { - const datapoints = metric.Datapoints; - const duration = datapoints - .reduce((previous, datapoint) => previous + datapoint.Average, 0); - const formattedRoundedAvgDuration = `${Math.round(duration * 100) / 100}ms`; - message += `${chalk.yellow('Duration (avg.):', formattedRoundedAvgDuration)}`; - } + _.forEach(metric, (funcMetric) => { + if (funcMetric.Label === 'Invocations') { + const datapoints = funcMetric.Datapoints; + invocations += datapoints + .reduce((previous, datapoint) => previous + datapoint.Sum, 0); + } else if (funcMetric.Label === 'Throttles') { + const datapoints = funcMetric.Datapoints; + throttles += datapoints + .reduce((previous, datapoint) => previous + datapoint.Sum, 0); + } else if (funcMetric.Label === 'Errors') { + const datapoints = funcMetric.Datapoints; + errors += datapoints + .reduce((previous, datapoint) => previous + datapoint.Sum, 0); + } else { + const datapoints = funcMetric.Datapoints; + duration += datapoints + .reduce((previous, datapoint) => previous + datapoint.Average, 0); + } + }); }); + // format the duration + const functionsCount = metrics.length; + const formattedRoundedAvgDuration = + `${(Math.round(duration * 100) / 100) / functionsCount}ms`; + // display the data + message += `${chalk.yellow('Invocations:', invocations, '\n')}`; + message += `${chalk.yellow('Throttles:', throttles, '\n')}`; + message += `${chalk.yellow('Errors:', errors, '\n')}`; + message += `${chalk.yellow('Duration (avg.):', formattedRoundedAvgDuration)}`; } else { message += `${chalk.yellow('There are no metrics to show for these options')}`; } diff --git a/lib/plugins/aws/metrics/awsMetrics.test.js b/lib/plugins/aws/metrics/awsMetrics.test.js index d6a30f084..cb6df66bf 100644 --- a/lib/plugins/aws/metrics/awsMetrics.test.js +++ b/lib/plugins/aws/metrics/awsMetrics.test.js @@ -175,7 +175,14 @@ describe('AwsMetrics', () => { let requestStub; beforeEach(() => { - awsMetrics.options.function = 'function1'; + awsMetrics.serverless.service.functions = { + function1: { + name: 'func1', + }, + function2: { + name: 'func2', + }, + }; awsMetrics.options.startTime = '1970-01-01'; awsMetrics.options.endTime = '1970-01-02'; requestStub = sinon.stub(awsMetrics.provider, 'request'); @@ -185,11 +192,12 @@ describe('AwsMetrics', () => { awsMetrics.provider.request.restore(); }); - it('should should gather metrics for the function', () => { + it('should gather service wide function metrics if no function option is specified', () => { + // stubs for function1 // invocations requestStub.onCall(0).returns( BbPromise.resolve({ - ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755' }, + ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func1' }, Label: 'Invocations', Datapoints: [], }) @@ -197,7 +205,7 @@ describe('AwsMetrics', () => { // throttles requestStub.onCall(1).returns( BbPromise.resolve({ - ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2' }, + ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func1' }, Label: 'Throttles', Datapoints: [], }) @@ -205,7 +213,7 @@ describe('AwsMetrics', () => { // errors requestStub.onCall(2).returns( BbPromise.resolve({ - ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b' }, + ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func1' }, Label: 'Errors', Datapoints: [], }) @@ -213,29 +221,146 @@ describe('AwsMetrics', () => { // duration requestStub.onCall(3).returns( BbPromise.resolve({ - ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164' }, + ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func1' }, + Label: 'Duration', + Datapoints: [], + }) + ); + // stubs for function2 + // invocations + requestStub.onCall(4).returns( + BbPromise.resolve({ + ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func2' }, + Label: 'Invocations', + Datapoints: [], + }) + ); + // throttles + requestStub.onCall(5).returns( + BbPromise.resolve({ + ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func2' }, + Label: 'Throttles', + Datapoints: [], + }) + ); + // errors + requestStub.onCall(6).returns( + BbPromise.resolve({ + ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func2' }, + Label: 'Errors', + Datapoints: [], + }) + ); + // duration + requestStub.onCall(7).returns( + BbPromise.resolve({ + ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func2' }, Label: 'Duration', Datapoints: [], }) ); const expectedResult = [ - { ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755' }, + [ + { ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func1' }, + Label: 'Invocations', + Datapoints: [], + }, + { ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func1' }, + Label: 'Throttles', + Datapoints: [], + }, + { ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func1' }, + Label: 'Errors', + Datapoints: [], + }, + { ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func1' }, + Label: 'Duration', + Datapoints: [], + }, + ], + [ + { ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func2' }, + Label: 'Invocations', + Datapoints: [], + }, + { ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func2' }, + Label: 'Throttles', + Datapoints: [], + }, + { ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func2' }, + Label: 'Errors', + Datapoints: [], + }, + { ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func2' }, + Label: 'Duration', + Datapoints: [], + }, + ], + ]; + + return awsMetrics.getMetrics().then((result) => { + expect(result).to.deep.equal(expectedResult); + }); + }); + + it('should gather function metrics if function option is specified', () => { + // only display metrics for function1 + awsMetrics.options.function = 'function1'; + + // stubs for function1 + // invocations + requestStub.onCall(0).returns( + BbPromise.resolve({ + ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func1' }, Label: 'Invocations', Datapoints: [], - }, - { ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2' }, + }) + ); + // throttles + requestStub.onCall(1).returns( + BbPromise.resolve({ + ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func1' }, Label: 'Throttles', Datapoints: [], - }, - { ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b' }, + }) + ); + // errors + requestStub.onCall(2).returns( + BbPromise.resolve({ + ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func1' }, Label: 'Errors', Datapoints: [], - }, - { ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164' }, + }) + ); + // duration + requestStub.onCall(3).returns( + BbPromise.resolve({ + ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func1' }, Label: 'Duration', Datapoints: [], - }, + }) + ); + + const expectedResult = [ + [ + { ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func1' }, + Label: 'Invocations', + Datapoints: [], + }, + { ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func1' }, + Label: 'Throttles', + Datapoints: [], + }, + { ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func1' }, + Label: 'Errors', + Datapoints: [], + }, + { ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func1' }, + Label: 'Duration', + Datapoints: [], + }, + ], ]; return awsMetrics.getMetrics().then((result) => { @@ -248,7 +373,14 @@ describe('AwsMetrics', () => { let consoleLogStub; beforeEach(() => { - awsMetrics.options.function = 'function1'; + awsMetrics.serverless.service.functions = { + function1: { + name: 'func1', + }, + function2: { + name: 'func2', + }, + }; awsMetrics.options.startTime = '1970-01-01'; awsMetrics.options.endTime = '1970-01-02'; consoleLogStub = sinon.stub(serverless.cli, 'consoleLog').returns(); @@ -258,36 +390,118 @@ describe('AwsMetrics', () => { serverless.cli.consoleLog.restore(); }); - it('should display all metrics for the given function', () => { + it('should display service wide metrics if no function option is specified', () => { const metrics = [ - { - ResponseMetadata: { - RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755', + [ + { + ResponseMetadata: { + RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func1', + }, + Label: 'Invocations', + Datapoints: [{ Sum: 12 }, { Sum: 8 }], }, - Label: 'Invocations', - Datapoints: [{ Sum: 12 }, { Sum: 8 }], - }, - { - ResponseMetadata: { - RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2', + { + ResponseMetadata: { + RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func1', + }, + Label: 'Throttles', + Datapoints: [{ Sum: 15 }, { Sum: 15 }], }, - Label: 'Throttles', - Datapoints: [{ Sum: 15 }, { Sum: 15 }], - }, - { - ResponseMetadata: { - RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b', + { + ResponseMetadata: { + RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func1', + }, + Label: 'Errors', + Datapoints: [{ Sum: 0 }], }, - Label: 'Errors', - Datapoints: [{ Sum: 0 }], - }, - { - ResponseMetadata: { - RequestId: '1f63db14-b569-11e6-8501-d98a275ce164', + { + ResponseMetadata: { + RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func1', + }, + Label: 'Duration', + Datapoints: [{ Average: 1000 }], }, - Label: 'Duration', - Datapoints: [{ Average: 1000 }], - }, + ], + [ + { + ResponseMetadata: { + RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func2', + }, + Label: 'Invocations', + Datapoints: [{ Sum: 12 }, { Sum: 8 }], + }, + { + ResponseMetadata: { + RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func2', + }, + Label: 'Throttles', + Datapoints: [{ Sum: 15 }, { Sum: 15 }], + }, + { + ResponseMetadata: { + RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func2', + }, + Label: 'Errors', + Datapoints: [{ Sum: 0 }], + }, + { + ResponseMetadata: { + RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func2', + }, + Label: 'Duration', + Datapoints: [{ Average: 1000 }], + }, + ], + ]; + + let expectedMessage = ''; + expectedMessage += `${chalk.yellow.underline('Service wide metrics')}\n`; + expectedMessage += 'January 1, 1970 12:00 AM - January 2, 1970 12:00 AM\n\n'; + expectedMessage += `${chalk.yellow('Invocations: 40 \n')}`; + expectedMessage += `${chalk.yellow('Throttles: 60 \n')}`; + expectedMessage += `${chalk.yellow('Errors: 0 \n')}`; + expectedMessage += `${chalk.yellow('Duration (avg.): 1000ms')}`; + + return awsMetrics.showMetrics(metrics).then((message) => { + expect(consoleLogStub.calledOnce).to.equal(true); + expect(message).to.equal(expectedMessage); + }); + }); + + it('should display function metrics if function option is specified', () => { + awsMetrics.options.function = 'function1'; + + const metrics = [ + [ + { + ResponseMetadata: { + RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func1', + }, + Label: 'Invocations', + Datapoints: [{ Sum: 12 }, { Sum: 8 }], + }, + { + ResponseMetadata: { + RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func1', + }, + Label: 'Throttles', + Datapoints: [{ Sum: 15 }, { Sum: 15 }], + }, + { + ResponseMetadata: { + RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func1', + }, + Label: 'Errors', + Datapoints: [{ Sum: 0 }], + }, + { + ResponseMetadata: { + RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func1', + }, + Label: 'Duration', + Datapoints: [{ Average: 1000 }], + }, + ], ]; let expectedMessage = ''; @@ -305,6 +519,8 @@ describe('AwsMetrics', () => { }); it('should resolve with an error message if no metrics are available', () => { + awsMetrics.options.function = 'function1'; + let expectedMessage = ''; expectedMessage += `${chalk.yellow.underline(awsMetrics.options.function)}\n`; expectedMessage += 'January 1, 1970 12:00 AM - January 2, 1970 12:00 AM\n\n'; diff --git a/lib/plugins/metrics/metrics.js b/lib/plugins/metrics/metrics.js index 3cc54bf4b..393dc8b86 100644 --- a/lib/plugins/metrics/metrics.js +++ b/lib/plugins/metrics/metrics.js @@ -14,7 +14,6 @@ class Metrics { options: { function: { usage: 'The function name', - required: true, shortcut: 'f', }, stage: { diff --git a/lib/plugins/metrics/metrics.test.js b/lib/plugins/metrics/metrics.test.js index 7ad7afb97..f96cd08d1 100644 --- a/lib/plugins/metrics/metrics.test.js +++ b/lib/plugins/metrics/metrics.test.js @@ -25,10 +25,5 @@ describe('Metrics', () => { 'metrics', ]); }); - - it('should have a required option "function"', () => { - // eslint-disable-next-line no-unused-expressions - expect(metrics.commands.metrics.options.function.required).to.be.true; - }); }); }); From fd03e5515db9f0621963bf32c3ded17c3e9c039e Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Tue, 13 Dec 2016 08:29:29 +0100 Subject: [PATCH 02/11] Split up config CLI doc --- docs/README.md | 2 +- .../{config.md => config-credentials.md} | 24 ++++++++----------- 2 files changed, 11 insertions(+), 15 deletions(-) rename docs/providers/aws/cli-reference/{config.md => config-credentials.md} (73%) diff --git a/docs/README.md b/docs/README.md index 07d3050a6..55bce125c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -48,7 +48,7 @@ The Serverless Framework allows you to deploy auto-scaling, pay-per-execution, e
    -
  • Config
  • +
  • Config Credentials
  • Create
  • Install
  • Deploy
  • diff --git a/docs/providers/aws/cli-reference/config.md b/docs/providers/aws/cli-reference/config-credentials.md similarity index 73% rename from docs/providers/aws/cli-reference/config.md rename to docs/providers/aws/cli-reference/config-credentials.md index da26299c8..e677c0779 100644 --- a/docs/providers/aws/cli-reference/config.md +++ b/docs/providers/aws/cli-reference/config-credentials.md @@ -1,39 +1,35 @@ -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/aws/cli-reference/config) +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/aws/cli-reference/config-credentials) -# Config - -This plugin helps you to configure Serverless. - -## Configure credentials +# Config Credentials ```bash serverless config credentials --provider provider --key key --secret secret ``` -### Options +## Options - `--provider` or `-p` The provider (in this case `aws`). **Required**. - `--key` or `-k` The `aws_access_key_id`. **Required**. - `--secret` or `-s` The `aws_secret_access_key`. **Required**. - `--profile` or `-n` The name of the profile which should be created. -### Provided lifecycle events +## Provided lifecycle events - `config:credentials:config` -### Examples +## Examples -#### Configure the `default` profile +### Configure the `default` profile ```bash serverless config credentials --provider aws --key 1234 --secret 5678 @@ -41,7 +37,7 @@ serverless config credentials --provider aws --key 1234 --secret 5678 This example will configure the `default` profile with the `aws_access_key_id` of `1234` and the `aws_secret_access_key` of `5678`. -#### Configure a custom profile +### Configure a custom profile ```bash serverless config credentials --provider aws --key 1234 --secret 5678 --profile custom-profile From 142946e29585b125ad3110f53eadd5162a373902 Mon Sep 17 00:00:00 2001 From: "Eslam A. Hefnawy" Date: Tue, 13 Dec 2016 17:52:03 +0700 Subject: [PATCH 03/11] fixed bug where you can now invoke without any input data --- lib/plugins/aws/invoke/index.js | 11 ++++++++--- lib/plugins/aws/invoke/index.test.js | 8 ++++++++ lib/plugins/aws/invokeLocal/index.js | 11 ++++++++--- lib/plugins/aws/invokeLocal/index.test.js | 8 ++++++++ 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/lib/plugins/aws/invoke/index.js b/lib/plugins/aws/invoke/index.js index dd35d80c4..2e7ff2482 100644 --- a/lib/plugins/aws/invoke/index.js +++ b/lib/plugins/aws/invoke/index.js @@ -42,10 +42,15 @@ class AwsInvoke { this.options.data = this.serverless.utils.readFileSync(absolutePath); resolve(); } else { - stdin().then(input => { - this.options.data = input; + try { + stdin().then(input => { + this.options.data = input; + resolve(); + }); + } catch (exception) { + // resolve if no stdin was provided resolve(); - }); + } } }).then(() => { try { diff --git a/lib/plugins/aws/invoke/index.test.js b/lib/plugins/aws/invoke/index.test.js index 9346d016a..5230eadff 100644 --- a/lib/plugins/aws/invoke/index.test.js +++ b/lib/plugins/aws/invoke/index.test.js @@ -81,6 +81,14 @@ describe('AwsInvoke', () => { expect(() => awsInvoke.extendedValidate()).to.throw(Error); }); + it('should not throw error when there are no input data', () => { + awsInvoke.options.data = undefined; + + return awsInvoke.extendedValidate().then(() => { + expect(awsInvoke.options.data).to.equal(undefined); + }); + }); + it('should keep data if it is a simple string', () => { awsInvoke.options.data = 'simple-string'; diff --git a/lib/plugins/aws/invokeLocal/index.js b/lib/plugins/aws/invokeLocal/index.js index abbecc5b6..b605d7a98 100644 --- a/lib/plugins/aws/invokeLocal/index.js +++ b/lib/plugins/aws/invokeLocal/index.js @@ -42,10 +42,15 @@ class AwsInvokeLocal { this.options.data = this.serverless.utils.readFileSync(absolutePath); resolve(); } else { - stdin().then(input => { - this.options.data = input; + try { + stdin().then(input => { + this.options.data = input; + resolve(); + }); + } catch (exception) { + // resolve if no stdin was provided resolve(); - }); + } } }).then(() => { try { diff --git a/lib/plugins/aws/invokeLocal/index.test.js b/lib/plugins/aws/invokeLocal/index.test.js index 64f981363..feed5ff9e 100644 --- a/lib/plugins/aws/invokeLocal/index.test.js +++ b/lib/plugins/aws/invokeLocal/index.test.js @@ -78,6 +78,14 @@ describe('AwsInvokeLocal', () => { awsInvokeLocal.options.path = false; }); + it('should not throw error when there are no input data', () => { + awsInvokeLocal.options.data = undefined; + + return awsInvokeLocal.extendedValidate().then(() => { + expect(awsInvokeLocal.options.data).to.equal(undefined); + }); + }); + it('it should throw error if function is not provided', () => { serverless.service.functions = null; expect(() => awsInvokeLocal.extendedValidate()).to.throw(Error); From 08009c2945c5bf88ae42dce3906723a850da6b74 Mon Sep 17 00:00:00 2001 From: "Eslam A. Hefnawy" Date: Tue, 13 Dec 2016 18:08:05 +0700 Subject: [PATCH 04/11] handling strings --- lib/plugins/aws/invoke/index.js | 1 + lib/plugins/aws/invoke/index.test.js | 2 +- lib/plugins/aws/invokeLocal/index.js | 1 + lib/plugins/aws/invokeLocal/index.test.js | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/plugins/aws/invoke/index.js b/lib/plugins/aws/invoke/index.js index 2e7ff2482..45167a56d 100644 --- a/lib/plugins/aws/invoke/index.js +++ b/lib/plugins/aws/invoke/index.js @@ -28,6 +28,7 @@ class AwsInvoke { // validate function exists in service this.options.functionObj = this.serverless.service.getFunction(this.options.function); + this.options.data = this.options.data || ''; return new BbPromise(resolve => { if (this.options.data) { diff --git a/lib/plugins/aws/invoke/index.test.js b/lib/plugins/aws/invoke/index.test.js index 5230eadff..b5ae88b9b 100644 --- a/lib/plugins/aws/invoke/index.test.js +++ b/lib/plugins/aws/invoke/index.test.js @@ -85,7 +85,7 @@ describe('AwsInvoke', () => { awsInvoke.options.data = undefined; return awsInvoke.extendedValidate().then(() => { - expect(awsInvoke.options.data).to.equal(undefined); + expect(awsInvoke.options.data).to.equal(''); }); }); diff --git a/lib/plugins/aws/invokeLocal/index.js b/lib/plugins/aws/invokeLocal/index.js index b605d7a98..a594a049e 100644 --- a/lib/plugins/aws/invokeLocal/index.js +++ b/lib/plugins/aws/invokeLocal/index.js @@ -28,6 +28,7 @@ class AwsInvokeLocal { // validate function exists in service this.options.functionObj = this.serverless.service.getFunction(this.options.function); + this.options.data = this.options.data || ''; return new BbPromise(resolve => { if (this.options.data) { diff --git a/lib/plugins/aws/invokeLocal/index.test.js b/lib/plugins/aws/invokeLocal/index.test.js index feed5ff9e..e4737bf9e 100644 --- a/lib/plugins/aws/invokeLocal/index.test.js +++ b/lib/plugins/aws/invokeLocal/index.test.js @@ -82,7 +82,7 @@ describe('AwsInvokeLocal', () => { awsInvokeLocal.options.data = undefined; return awsInvokeLocal.extendedValidate().then(() => { - expect(awsInvokeLocal.options.data).to.equal(undefined); + expect(awsInvokeLocal.options.data).to.equal(''); }); }); From df8997e83a251d8f98db076fadf1357ccaf1b266 Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Tue, 13 Dec 2016 12:52:12 +0100 Subject: [PATCH 05/11] Update examples with more "real world" dates --- docs/providers/aws/cli-reference/metrics.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/providers/aws/cli-reference/metrics.md b/docs/providers/aws/cli-reference/metrics.md index 02c5d8b2a..64a3c98bf 100644 --- a/docs/providers/aws/cli-reference/metrics.md +++ b/docs/providers/aws/cli-reference/metrics.md @@ -41,10 +41,10 @@ Displays service wide metrics for the last 24h. ### See service wide metrics for a specific timespan ```bash -serverless metrics --startTime 1970-01-01 --endTime 1970-01-02 +serverless metrics --startTime 2016-01-01 --endTime 2016-01-02 ``` -Displays service wide metrics for the time between January 1, 1970 and January 2, 1970. +Displays service wide metrics for the time between January 1, 2016 and January 2, 2016. ### See all metrics for the function `hello` of the last 24h @@ -57,7 +57,7 @@ Displays all `hello` function metrics for the last 24h. ### See metrics for the function `hello` of a specific timespan ```bash -serverless metrics --function hello --startTime 1970-01-01 --endTime 1970-01-02 +serverless metrics --function hello --startTime 2016-01-01 --endTime 2016-01-02 ``` -Displays all `hello` function metrics for the time between January 1, 1970 and January 2, 1970. +Displays all `hello` function metrics for the time between January 1, 2016 and January 2, 2016. From a8540b319f8b3892e05d0c2a7926bce7a6e30a0c Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Tue, 13 Dec 2016 13:19:45 +0100 Subject: [PATCH 06/11] Refactor functions into reusable util functions --- lib/plugins/aws/metrics/awsMetrics.js | 24 +++++------------ lib/plugins/aws/metrics/utils.js | 9 +++++++ lib/plugins/aws/metrics/utils.test.js | 37 +++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 17 deletions(-) create mode 100644 lib/plugins/aws/metrics/utils.js create mode 100644 lib/plugins/aws/metrics/utils.test.js diff --git a/lib/plugins/aws/metrics/awsMetrics.js b/lib/plugins/aws/metrics/awsMetrics.js index 000234390..761952351 100644 --- a/lib/plugins/aws/metrics/awsMetrics.js +++ b/lib/plugins/aws/metrics/awsMetrics.js @@ -5,6 +5,7 @@ const chalk = require('chalk'); const _ = require('lodash'); const moment = require('moment'); const validate = require('../lib/validate'); +const utils = require('./utils'); class AwsMetrics { constructor(serverless, options) { @@ -208,33 +209,22 @@ class AwsMetrics { _.forEach(metrics, (metric) => { _.forEach(metric, (funcMetric) => { if (funcMetric.Label === 'Invocations') { - const datapoints = funcMetric.Datapoints; - invocations += datapoints - .reduce((previous, datapoint) => previous + datapoint.Sum, 0); + invocations += utils.reduceDatapoints(funcMetric.Datapoints, 'Sum'); } else if (funcMetric.Label === 'Throttles') { - const datapoints = funcMetric.Datapoints; - throttles += datapoints - .reduce((previous, datapoint) => previous + datapoint.Sum, 0); + throttles += utils.reduceDatapoints(funcMetric.Datapoints, 'Sum'); } else if (funcMetric.Label === 'Errors') { - const datapoints = funcMetric.Datapoints; - errors += datapoints - .reduce((previous, datapoint) => previous + datapoint.Sum, 0); + errors += utils.reduceDatapoints(funcMetric.Datapoints, 'Sum'); } else { - const datapoints = funcMetric.Datapoints; - duration += datapoints - .reduce((previous, datapoint) => previous + datapoint.Average, 0); + duration += utils.reduceDatapoints(funcMetric.Datapoints, 'Average'); } }); }); - // format the duration - const functionsCount = metrics.length; - const formattedRoundedAvgDuration = - `${(Math.round(duration * 100) / 100) / functionsCount}ms`; + const formattedDuration = `${utils.getRoundedAvgDuration(duration, metrics.length)}ms`; // display the data message += `${chalk.yellow('Invocations:', invocations, '\n')}`; message += `${chalk.yellow('Throttles:', throttles, '\n')}`; message += `${chalk.yellow('Errors:', errors, '\n')}`; - message += `${chalk.yellow('Duration (avg.):', formattedRoundedAvgDuration)}`; + message += `${chalk.yellow('Duration (avg.):', formattedDuration)}`; } else { message += `${chalk.yellow('There are no metrics to show for these options')}`; } diff --git a/lib/plugins/aws/metrics/utils.js b/lib/plugins/aws/metrics/utils.js new file mode 100644 index 000000000..55540e870 --- /dev/null +++ b/lib/plugins/aws/metrics/utils.js @@ -0,0 +1,9 @@ +'use strict'; + +module.exports = { + getRoundedAvgDuration: (duration, functionsCount) => + (Math.round(duration * 100) / 100) / functionsCount, + + reduceDatapoints: (datapoints, statistic) => datapoints + .reduce((previous, datapoint) => previous + datapoint[statistic], 0), +}; diff --git a/lib/plugins/aws/metrics/utils.test.js b/lib/plugins/aws/metrics/utils.test.js new file mode 100644 index 000000000..cab0125be --- /dev/null +++ b/lib/plugins/aws/metrics/utils.test.js @@ -0,0 +1,37 @@ +'use strict'; + +const expect = require('chai').expect; + +const getRoundedAvgDuration = require('./utils').getRoundedAvgDuration; +const reduceDatapoints = require('./utils').reduceDatapoints; + +describe('#getRoundedAvgDuration()', () => { + it('should return the rounded average duration', () => { + const duration = 2000.0000023; + const functionsCount = 2; + + const result = getRoundedAvgDuration(duration, functionsCount); + + expect(result).to.equal(1000); + }); +}); + +describe('#reduceDatapoints()', () => { + it('should reduce the given datapoints based on the statistic', () => { + const datapoints = [{ Sum: 12 }, { Sum: 8 }, { Sum: 5 }]; + const statistic = 'Sum'; + + const result = reduceDatapoints(datapoints, statistic); + + expect(result).to.equal(25); + }); + + it('should return 0 if no datapoints are available to reduce', () => { + const datapoints = []; + const statistic = ''; + + const result = reduceDatapoints(datapoints, statistic); + + expect(result).to.equal(0); + }); +}); From 443865f1c4c8362d98ee76c40995a460e5f08ef0 Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Tue, 13 Dec 2016 14:21:33 +0100 Subject: [PATCH 07/11] Remove utils file and move helper functions into class file --- lib/plugins/aws/metrics/awsMetrics.js | 18 ++++++++----- lib/plugins/aws/metrics/utils.js | 9 ------- lib/plugins/aws/metrics/utils.test.js | 37 --------------------------- 3 files changed, 12 insertions(+), 52 deletions(-) delete mode 100644 lib/plugins/aws/metrics/utils.js delete mode 100644 lib/plugins/aws/metrics/utils.test.js diff --git a/lib/plugins/aws/metrics/awsMetrics.js b/lib/plugins/aws/metrics/awsMetrics.js index 761952351..6d0e29aa3 100644 --- a/lib/plugins/aws/metrics/awsMetrics.js +++ b/lib/plugins/aws/metrics/awsMetrics.js @@ -5,7 +5,13 @@ const chalk = require('chalk'); const _ = require('lodash'); const moment = require('moment'); const validate = require('../lib/validate'); -const utils = require('./utils'); + +// helper functions +const getRoundedAvgDuration = (duration, functionsCount) => + (Math.round(duration * 100) / 100) / functionsCount; + +const reduceDatapoints = (datapoints, statistic) => datapoints + .reduce((previous, datapoint) => previous + datapoint[statistic], 0); class AwsMetrics { constructor(serverless, options) { @@ -209,17 +215,17 @@ class AwsMetrics { _.forEach(metrics, (metric) => { _.forEach(metric, (funcMetric) => { if (funcMetric.Label === 'Invocations') { - invocations += utils.reduceDatapoints(funcMetric.Datapoints, 'Sum'); + invocations += reduceDatapoints(funcMetric.Datapoints, 'Sum'); } else if (funcMetric.Label === 'Throttles') { - throttles += utils.reduceDatapoints(funcMetric.Datapoints, 'Sum'); + throttles += reduceDatapoints(funcMetric.Datapoints, 'Sum'); } else if (funcMetric.Label === 'Errors') { - errors += utils.reduceDatapoints(funcMetric.Datapoints, 'Sum'); + errors += reduceDatapoints(funcMetric.Datapoints, 'Sum'); } else { - duration += utils.reduceDatapoints(funcMetric.Datapoints, 'Average'); + duration += reduceDatapoints(funcMetric.Datapoints, 'Average'); } }); }); - const formattedDuration = `${utils.getRoundedAvgDuration(duration, metrics.length)}ms`; + const formattedDuration = `${getRoundedAvgDuration(duration, metrics.length)}ms`; // display the data message += `${chalk.yellow('Invocations:', invocations, '\n')}`; message += `${chalk.yellow('Throttles:', throttles, '\n')}`; diff --git a/lib/plugins/aws/metrics/utils.js b/lib/plugins/aws/metrics/utils.js deleted file mode 100644 index 55540e870..000000000 --- a/lib/plugins/aws/metrics/utils.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; - -module.exports = { - getRoundedAvgDuration: (duration, functionsCount) => - (Math.round(duration * 100) / 100) / functionsCount, - - reduceDatapoints: (datapoints, statistic) => datapoints - .reduce((previous, datapoint) => previous + datapoint[statistic], 0), -}; diff --git a/lib/plugins/aws/metrics/utils.test.js b/lib/plugins/aws/metrics/utils.test.js deleted file mode 100644 index cab0125be..000000000 --- a/lib/plugins/aws/metrics/utils.test.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -const expect = require('chai').expect; - -const getRoundedAvgDuration = require('./utils').getRoundedAvgDuration; -const reduceDatapoints = require('./utils').reduceDatapoints; - -describe('#getRoundedAvgDuration()', () => { - it('should return the rounded average duration', () => { - const duration = 2000.0000023; - const functionsCount = 2; - - const result = getRoundedAvgDuration(duration, functionsCount); - - expect(result).to.equal(1000); - }); -}); - -describe('#reduceDatapoints()', () => { - it('should reduce the given datapoints based on the statistic', () => { - const datapoints = [{ Sum: 12 }, { Sum: 8 }, { Sum: 5 }]; - const statistic = 'Sum'; - - const result = reduceDatapoints(datapoints, statistic); - - expect(result).to.equal(25); - }); - - it('should return 0 if no datapoints are available to reduce', () => { - const datapoints = []; - const statistic = ''; - - const result = reduceDatapoints(datapoints, statistic); - - expect(result).to.equal(0); - }); -}); From 52de4e62450f71e41745fad07d33fe83ff7acf07 Mon Sep 17 00:00:00 2001 From: Maciej Winnicki Date: Tue, 13 Dec 2016 19:24:24 +0100 Subject: [PATCH 08/11] update csharp example --- docs/providers/aws/examples/hello-world/csharp/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/providers/aws/examples/hello-world/csharp/README.md b/docs/providers/aws/examples/hello-world/csharp/README.md index d494b0b1d..277bf9fc6 100644 --- a/docs/providers/aws/examples/hello-world/csharp/README.md +++ b/docs/providers/aws/examples/hello-world/csharp/README.md @@ -27,8 +27,6 @@ zip -r ./deploy-package.zip ./* popd ``` -`./build.sh` runs the dotnet restore and package commands then creates the zip file to upload to lambda. - ## 3. Deploy `serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command From e0695366dd316cf0220f79cc982ec28eef4f68d1 Mon Sep 17 00:00:00 2001 From: Philipp Muens Date: Tue, 13 Dec 2016 19:25:31 +0100 Subject: [PATCH 09/11] Fix stdin docs for invoke --- docs/providers/aws/cli-reference/invoke-local.md | 2 +- docs/providers/aws/cli-reference/invoke.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/providers/aws/cli-reference/invoke-local.md b/docs/providers/aws/cli-reference/invoke-local.md index d11080d11..57c5a9805 100644 --- a/docs/providers/aws/cli-reference/invoke-local.md +++ b/docs/providers/aws/cli-reference/invoke-local.md @@ -47,7 +47,7 @@ serverless invoke --function functionName --data '{"a":"bar"}' ### Local function invocation with data from standard input ```bash -dataGenerator.js | serverless invoke local --function functionName +node dataGenerator.js | serverless invoke local --function functionName ``` ### Local function invocation with data passing diff --git a/docs/providers/aws/cli-reference/invoke.md b/docs/providers/aws/cli-reference/invoke.md index 0c8165198..5b88d2f58 100644 --- a/docs/providers/aws/cli-reference/invoke.md +++ b/docs/providers/aws/cli-reference/invoke.md @@ -65,7 +65,7 @@ serverless invoke --function functionName --stage dev --region us-east-1 --data #### Function invocation with data from standard input ```bash -dataGenerator.js | serverless invoke --function functionName --stage dev --region us-east-1 +node dataGenerator.js | serverless invoke --function functionName --stage dev --region us-east-1 ``` #### Function invocation with logging From 876c1d89ef0daf0e83be1bf7f6db728e4940953a Mon Sep 17 00:00:00 2001 From: Nick den Engelsman Date: Tue, 13 Dec 2016 20:46:32 +0100 Subject: [PATCH 10/11] Update apigateway.md --- docs/providers/aws/events/apigateway.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/providers/aws/events/apigateway.md b/docs/providers/aws/events/apigateway.md index db4ce5c6a..0de2eef39 100644 --- a/docs/providers/aws/events/apigateway.md +++ b/docs/providers/aws/events/apigateway.md @@ -26,25 +26,27 @@ By default, the Framework uses the `lambda-proxy` method (i.e., everything is pa ### Simple HTTP Endpoint -This setup specifies that the `index` function should be run when someone accesses the API gateway at `users/index` via +This setup specifies that the `hello` function should be run when someone accesses the API gateway at `hello` via a `GET` request. Here's an example: ```yml +# serverless.yml + functions: index: - handler: users.index + handler: handler.hello events: - - http: GET users/index + - http: GET hello ``` ```javascript -// users.js +// handler.js 'use strict'; -exports.handler = function(event, context, callback) { +module.exports.hello = function(event, context, callback) { console.log(event); // Contains incoming request data (e.g., query params, headers and more) @@ -70,6 +72,8 @@ JSON.parse(event.body); Here we've defined an POST endpoint for the path `posts/create`. ```yml +# serverless.yml + functions: create: handler: posts.create @@ -83,12 +87,14 @@ functions: To set CORS configurations for your HTTP endpoints, simply modify your event configurations as follows: ```yml +# serverless.yml + functions: hello: handler: handler.hello events: - http: - path: user/create + path: hello method: get cors: true ``` @@ -96,11 +102,11 @@ functions: If you want to use CORS with the lambda-proxy integration, remember to include `Access-Control-Allow-Origin` in your returned headers object, like this: ```javascript -// users.js +// handler.js 'use strict'; -exports.handler = function(event, context, callback) { +module.exports.hello = function(event, context, callback) { const response = { statusCode: 200, From cde9c2db283092d63ff445dafc1a81e33c133b9e Mon Sep 17 00:00:00 2001 From: Justin McMurdie Date: Tue, 13 Dec 2016 13:31:10 -0700 Subject: [PATCH 11/11] Updating section on AWS pricing Lambda has been moved to have it's own permanent free tier. It is no longer part of the Expiring offers. --- docs/providers/aws/guide/credentials.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/providers/aws/guide/credentials.md b/docs/providers/aws/guide/credentials.md index 051d7b80d..0ddbc678d 100644 --- a/docs/providers/aws/guide/credentials.md +++ b/docs/providers/aws/guide/credentials.md @@ -26,7 +26,7 @@ Here's how to set up the Serverless Framework with your Amazon Web Services acco If you're new to Amazon Web Services, make sure you put in a credit card. -New AWS users get access to the [AWS Free Tier](https://aws.amazon.com/free/), which lets you use many AWS resources for free for 1 year, like [AWS Lambda](https://aws.amazon.com/lambda/pricing/). New AWS users won't be charged for signing up. +All AWS users get access to the Free Tier for [AWS Lambda](https://aws.amazon.com/lambda/pricing/). ASW Lambda is part of the non-expiring [AWS Free Tier](https://aws.amazon.com/free/#AWS_FREE_TIER). If you don't have a credit card set up, you may not be able to deploy your resources and you may run into this error: