mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
Merge pull request #1794 from nicka/feature/refactor-aws-cloudformation-endpoint-outputs
Refactor for the CLI endpoints outputs
This commit is contained in:
commit
2a97b5bdfd
@ -25,6 +25,22 @@ module.exports = {
|
||||
|
||||
_.merge(this.serverless.service.resources.Resources, newDeploymentObject);
|
||||
|
||||
// create CLF Output for endpoint
|
||||
const outputServiceEndpointTemplate = `
|
||||
{
|
||||
"Description": "URL of the service endpoint",
|
||||
"Value": { "Fn::Join" : [ "", [ "https://", { "Ref": "RestApiApigEvent" },
|
||||
".execute-api.${this.options.region}.amazonaws.com/${this.options.stage}"] ] }
|
||||
}`;
|
||||
|
||||
const newOutputEndpointObject = {
|
||||
ServiceEndpoint: JSON.parse(outputServiceEndpointTemplate),
|
||||
};
|
||||
|
||||
this.serverless.service.resources.Outputs =
|
||||
this.serverless.service.resources.Outputs || {};
|
||||
_.merge(this.serverless.service.resources.Outputs, newOutputEndpointObject);
|
||||
|
||||
return BbPromise.resolve();
|
||||
},
|
||||
};
|
||||
|
||||
@ -5,8 +5,6 @@ const _ = require('lodash');
|
||||
|
||||
module.exports = {
|
||||
compileMethods() {
|
||||
let endpointCounter = 1;
|
||||
|
||||
_.forEach(this.serverless.service.functions, (functionObject, functionName) => {
|
||||
functionObject.events.forEach(event => {
|
||||
if (event.http) {
|
||||
@ -164,22 +162,6 @@ module.exports = {
|
||||
_.merge(this.serverless.service.resources.Resources,
|
||||
methodObject);
|
||||
|
||||
// create CLF Output for endpoint
|
||||
const outputEndpointTemplate = `
|
||||
{
|
||||
"Description": "Endpoint info",
|
||||
"Value": { "Fn::Join" : [ "", [ "${method.toUpperCase()} - https://", { "Ref": "RestApiApigEvent" },
|
||||
".execute-api.${this.options.region}.amazonaws.com/${this.options.stage}/${path}"] ] }
|
||||
}`;
|
||||
|
||||
const newOutputEndpointObject = {
|
||||
[`Endpoint${endpointCounter++}`]: JSON.parse(outputEndpointTemplate),
|
||||
};
|
||||
|
||||
this.serverless.service.resources.Outputs =
|
||||
this.serverless.service.resources.Outputs || {};
|
||||
_.merge(this.serverless.service.resources.Outputs, newOutputEndpointObject);
|
||||
|
||||
// store a method logical id in memory to be used
|
||||
// by Deployment resources "DependsOn" property
|
||||
if (this.methodDependencies) {
|
||||
|
||||
@ -19,6 +19,21 @@ describe('#compileDeployment()', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
Outputs: {
|
||||
ServiceEndpoint: {
|
||||
Description: 'URL of the service endpoint',
|
||||
Value: {
|
||||
'Fn::Join': [
|
||||
'',
|
||||
[
|
||||
'https://',
|
||||
{ Ref: 'RestApiApigEvent' },
|
||||
'.execute-api.us-east-1.amazonaws.com/dev',
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
@ -43,4 +58,14 @@ describe('#compileDeployment()', () => {
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
it('should add service endpoint output', () => awsCompileApigEvents
|
||||
.compileDeployment().then(() => {
|
||||
expect(
|
||||
awsCompileApigEvents.serverless.service.resources.Outputs.ServiceEndpoint
|
||||
).to.deep.equal(
|
||||
serviceResourcesAwsResourcesObjectMock.Outputs.ServiceEndpoint
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
@ -202,60 +202,4 @@ describe('#compileMethods()', () => {
|
||||
)).to.equal(JSON.stringify(lambdaUriObject));
|
||||
});
|
||||
});
|
||||
|
||||
it("should initiate the Outputs section if it's not available", () => {
|
||||
awsCompileApigEvents.serverless.service.resources.Outputs = false;
|
||||
awsCompileApigEvents.compileMethods().then(() => {
|
||||
expect(awsCompileApigEvents.serverless.service.resources.Outputs)
|
||||
.to.have.all.keys('Endpoint1', 'Endpoint2');
|
||||
});
|
||||
});
|
||||
|
||||
it('should create corresponding endpoint output objects', () => {
|
||||
const expectedOutputs = {
|
||||
Endpoint1: {
|
||||
Description: 'Endpoint info',
|
||||
Value: { 'Fn::Join': ['', ['POST - https://', { Ref: 'RestApiApigEvent' },
|
||||
'.execute-api.us-east-1.amazonaws.com/dev/users/create']] },
|
||||
},
|
||||
Endpoint2: {
|
||||
Description: 'Endpoint info',
|
||||
Value: { 'Fn::Join': ['', ['GET - https://', { Ref: 'RestApiApigEvent' },
|
||||
'.execute-api.us-east-1.amazonaws.com/dev/users/list']] },
|
||||
},
|
||||
};
|
||||
|
||||
awsCompileApigEvents.compileMethods().then(() => {
|
||||
expect(awsCompileApigEvents.serverless.service.resources.Outputs)
|
||||
.to.deep.equal(expectedOutputs);
|
||||
});
|
||||
});
|
||||
|
||||
it("should initiate the Outputs section if it's not available", () => {
|
||||
awsCompileApigEvents.serverless.service.resources.Outputs = false;
|
||||
awsCompileApigEvents.compileMethods().then(() => {
|
||||
expect(awsCompileApigEvents.serverless.service.resources.Outputs)
|
||||
.to.have.all.keys('Endpoint1', 'Endpoint2');
|
||||
});
|
||||
});
|
||||
|
||||
it('should create corresponding endpoint output objects', () => {
|
||||
const expectedOutputs = {
|
||||
Endpoint1: {
|
||||
Description: 'Endpoint info',
|
||||
Value: { 'Fn::Join': ['', ['POST - https://', { Ref: 'RestApiApigEvent' },
|
||||
'.execute-api.us-east-1.amazonaws.com/dev/users/create']] },
|
||||
},
|
||||
Endpoint2: {
|
||||
Description: 'Endpoint info',
|
||||
Value: { 'Fn::Join': ['', ['GET - https://', { Ref: 'RestApiApigEvent' },
|
||||
'.execute-api.us-east-1.amazonaws.com/dev/users/list']] },
|
||||
},
|
||||
};
|
||||
|
||||
awsCompileApigEvents.compileMethods().then(() => {
|
||||
expect(awsCompileApigEvents.serverless.service.resources.Outputs)
|
||||
.to.deep.equal(expectedOutputs);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,4 +5,44 @@ This plugin displays information about the service.
|
||||
## How it works
|
||||
|
||||
`Info` hooks into the [`info:info`](/lib/plugins/info) lifecycle. It will get the general information about the service and will query
|
||||
CloudFormation for the Outputs of the stack. Outputs will include Lambda functions ARNs, endpoints and other resources.
|
||||
CloudFormation for the `Outputs` of the stack. Outputs will include Lambda function ARN's, a `ServiceEndpoint` for the API Gateway endpoint and user provided custom Outputs.
|
||||
|
||||
### Lambda function ARN's
|
||||
|
||||
It uses the `Function[0-9]` CloudFormation Outputs.
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
$ serverless info
|
||||
|
||||
service: my-service
|
||||
stage: dev
|
||||
region: us-east-1
|
||||
accountId: 12345678
|
||||
endpoints:
|
||||
None
|
||||
functions:
|
||||
my-service-dev-hello: arn:aws:lambda:us-east-1:12345678:function:my-service-dev-hello
|
||||
```
|
||||
|
||||
### API Gateway Endpoints
|
||||
|
||||
It uses the `ServiceEndpoint` CloudFormation Output together with the functions http events.
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
$ serverless info
|
||||
|
||||
service: my-service
|
||||
stage: dev
|
||||
region: us-east-1
|
||||
accountId: 12345678
|
||||
endpoints:
|
||||
GET - https://..../dev/users
|
||||
GET - https://..../dev/likes
|
||||
functions:
|
||||
my-service-dev-users: arn:aws:lambda:us-east-1:12345678:function:my-service-dev-users
|
||||
my-service-dev-likes: arn:aws:lambda:us-east-1:12345678:function:my-service-dev-likes
|
||||
```
|
||||
|
||||
@ -4,6 +4,7 @@ const BbPromise = require('bluebird');
|
||||
const validate = require('../lib/validate');
|
||||
const SDK = require('../');
|
||||
const chalk = require('chalk');
|
||||
const _ = require('lodash');
|
||||
|
||||
class AwsInfo {
|
||||
constructor(serverless, options) {
|
||||
@ -59,11 +60,9 @@ class AwsInfo {
|
||||
});
|
||||
|
||||
// Endpoints
|
||||
info.endpoints = [];
|
||||
outputs.filter(x => x.OutputKey.match(/^Endpoint\d+$/))
|
||||
outputs.filter(x => x.OutputKey.match(/^ServiceEndpoint/))
|
||||
.forEach(x => {
|
||||
const endpointInfo = { endpoint: x.OutputValue };
|
||||
info.endpoints.push(endpointInfo);
|
||||
info.endpoint = x.OutputValue;
|
||||
});
|
||||
|
||||
// Resources
|
||||
@ -100,9 +99,24 @@ ${chalk.yellow('region:')} ${info.region}`;
|
||||
|
||||
let endpointsMessage = `\n${chalk.yellow('endpoints:')}`;
|
||||
|
||||
if (info.endpoints && info.endpoints.length > 0) {
|
||||
info.endpoints.forEach((e) => {
|
||||
endpointsMessage = endpointsMessage.concat(`\n ${e.endpoint}`);
|
||||
if (info.endpoint) {
|
||||
_.forEach(this.serverless.service.functions, (functionObject) => {
|
||||
functionObject.events.forEach(event => {
|
||||
if (event.http) {
|
||||
let method;
|
||||
let path;
|
||||
|
||||
if (typeof event.http === 'object') {
|
||||
method = event.http.method.toUpperCase();
|
||||
path = event.http.path;
|
||||
} else if (typeof event.http === 'string') {
|
||||
method = event.http.split(' ')[0].toUpperCase();
|
||||
path = event.http.split(' ')[1];
|
||||
}
|
||||
|
||||
endpointsMessage = endpointsMessage.concat(`\n ${method} - ${info.endpoint}/${path}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
endpointsMessage = endpointsMessage.concat(`\n None`);
|
||||
|
||||
@ -10,10 +10,31 @@ const chalk = require('chalk');
|
||||
|
||||
describe('AwsInfo', () => {
|
||||
const serverless = new Serverless();
|
||||
serverless.service.functions = {
|
||||
function1: {
|
||||
events: [
|
||||
{
|
||||
http: {
|
||||
path: 'function1',
|
||||
method: 'GET',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
function2: {
|
||||
events: [
|
||||
{
|
||||
http: {
|
||||
path: 'function2',
|
||||
method: 'POST',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const options = {
|
||||
stage: 'dev',
|
||||
region: 'us-east-1',
|
||||
function: 'first',
|
||||
};
|
||||
const awsInfo = new AwsInfo(serverless, options);
|
||||
|
||||
@ -81,17 +102,17 @@ describe('AwsInfo', () => {
|
||||
{
|
||||
Description: 'Lambda function info',
|
||||
OutputKey: 'Function1Arn',
|
||||
OutputValue: 'arn:aws:iam::12345678:function:my-first-function',
|
||||
OutputValue: 'arn:aws:iam::12345678:function:function1',
|
||||
},
|
||||
{
|
||||
Description: 'Lambda function info',
|
||||
OutputKey: 'Function2Arn',
|
||||
OutputValue: 'arn:aws:iam::12345678:function:my-second-function',
|
||||
OutputValue: 'arn:aws:iam::12345678:function:function2',
|
||||
},
|
||||
{
|
||||
Description: 'Endpoint info',
|
||||
OutputKey: 'Endpoint1',
|
||||
OutputValue: 'GET - https://ab12cd34ef.execute-api.us-east-1.amazonaws.com/dev/hello',
|
||||
Description: 'URL of the service endpoint',
|
||||
OutputKey: 'ServiceEndpoint',
|
||||
OutputValue: 'ab12cd34ef.execute-api.us-east-1.amazonaws.com/dev',
|
||||
},
|
||||
],
|
||||
StackStatusReason: null,
|
||||
@ -130,12 +151,12 @@ describe('AwsInfo', () => {
|
||||
it('should get function name and Arn', () => {
|
||||
const expectedFunctions = [
|
||||
{
|
||||
name: 'my-first-function',
|
||||
arn: 'arn:aws:iam::12345678:function:my-first-function',
|
||||
name: 'function1',
|
||||
arn: 'arn:aws:iam::12345678:function:function1',
|
||||
},
|
||||
{
|
||||
name: 'my-second-function',
|
||||
arn: 'arn:aws:iam::12345678:function:my-second-function',
|
||||
name: 'function2',
|
||||
arn: 'arn:aws:iam::12345678:function:function2',
|
||||
},
|
||||
];
|
||||
|
||||
@ -144,15 +165,11 @@ describe('AwsInfo', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should get endpoints', () => {
|
||||
const expectedEndpoints = [
|
||||
{
|
||||
endpoint: 'GET - https://ab12cd34ef.execute-api.us-east-1.amazonaws.com/dev/hello',
|
||||
},
|
||||
];
|
||||
it('should get endpoint', () => {
|
||||
const expectedEndpoint = 'ab12cd34ef.execute-api.us-east-1.amazonaws.com/dev';
|
||||
|
||||
return awsInfo.gather().then((info) => {
|
||||
expect(info.endpoints).to.deep.equal(expectedEndpoints);
|
||||
expect(info.endpoint).to.deep.equal(expectedEndpoint);
|
||||
});
|
||||
});
|
||||
|
||||
@ -197,15 +214,15 @@ describe('AwsInfo', () => {
|
||||
service: 'my-first',
|
||||
stage: 'dev',
|
||||
region: 'eu-west-1',
|
||||
endpoints: [
|
||||
{
|
||||
endpoint: 'GET - https://ab12cd34ef.execute-api.us-east-1.amazonaws.com/dev/hello',
|
||||
},
|
||||
],
|
||||
endpoint: 'ab12cd34ef.execute-api.us-east-1.amazonaws.com/dev',
|
||||
functions: [
|
||||
{
|
||||
name: 'my-first-dev-hello',
|
||||
arn: 'arn:aws:lambda:eu-west-1:12345678:function:my-first-dev-hello',
|
||||
name: 'function1',
|
||||
arn: 'arn:aws:iam::12345678:function:function1',
|
||||
},
|
||||
{
|
||||
name: 'function2',
|
||||
arn: 'arn:aws:iam::12345678:function:function2',
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -216,9 +233,11 @@ ${chalk.yellow('service:')} my-first
|
||||
${chalk.yellow('stage:')} dev
|
||||
${chalk.yellow('region:')} eu-west-1
|
||||
${chalk.yellow('endpoints:')}
|
||||
GET - https://ab12cd34ef.execute-api.us-east-1.amazonaws.com/dev/hello
|
||||
GET - ab12cd34ef.execute-api.us-east-1.amazonaws.com/dev/function1
|
||||
POST - ab12cd34ef.execute-api.us-east-1.amazonaws.com/dev/function2
|
||||
${chalk.yellow('functions:')}
|
||||
my-first-dev-hello: arn:aws:lambda:eu-west-1:12345678:function:my-first-dev-hello
|
||||
function1: arn:aws:iam::12345678:function:function1
|
||||
function2: arn:aws:iam::12345678:function:function2
|
||||
`;
|
||||
|
||||
expect(awsInfo.display(info)).to.equal(expectedMessage);
|
||||
@ -257,7 +276,7 @@ ${chalk.yellow('functions:')}
|
||||
stage: 'dev',
|
||||
region: 'eu-west-1',
|
||||
functions: [],
|
||||
endpoints: [],
|
||||
endpoint: undefined,
|
||||
};
|
||||
|
||||
const expectedMessage = `
|
||||
|
||||
@ -22,10 +22,5 @@ $ serverless info
|
||||
service: my-service
|
||||
stage: dev
|
||||
region: us-east-1
|
||||
accountId: 12345678
|
||||
endpoints:
|
||||
GET - https://..../dev/hello
|
||||
functions:
|
||||
my-service-dev-hello: arn:aws:lambda:us-east-1:12345678:function:my-service-dev-hello
|
||||
|
||||
```
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user