Skip to content

Commit d196b7d

Browse files
committed
update
1 parent c460bf3 commit d196b7d

File tree

7 files changed

+460
-12
lines changed

7 files changed

+460
-12
lines changed

.eslintcache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/index.js":{"size":689,"mtime":1549010110884,"results":{"filePath":"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/index.js","messages":[],"errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"hashOfConfig":"1icshje"},"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/package/kinesis/compileKinesisProxy.js":{"size":194,"mtime":1549010670041,"results":{"filePath":"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/package/kinesis/compileKinesisProxy.js","messages":[{"ruleId":"no-unused-vars","severity":2,"message":"'serviceProxy' is defined but never used.","line":6,"column":64,"nodeType":"Identifier","endLine":6,"endColumn":76}],"errorCount":1,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"hashOfConfig":"1icshje"},"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/utils.js":{"size":252,"mtime":1549010517992,"results":{"filePath":"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/utils.js","messages":[],"errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"hashOfConfig":"1icshje"},"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/prettier.config.js":{"size":125,"mtime":1549005304573,"results":{"filePath":"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/prettier.config.js","messages":[],"errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"hashOfConfig":"1icshje"}}
1+
{"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/index.js":{"size":689,"mtime":1549010110884,"results":{"filePath":"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/index.js","messages":[],"errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"hashOfConfig":"1icshje"},"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/package/kinesis/compileKinesisProxy.js":{"size":182,"mtime":1549010694102,"results":{"filePath":"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/package/kinesis/compileKinesisProxy.js","messages":[],"errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"hashOfConfig":"1icshje"},"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/utils.js":{"size":252,"mtime":1549010517992,"results":{"filePath":"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/lib/utils.js","messages":[],"errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"hashOfConfig":"1icshje"},"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/prettier.config.js":{"size":125,"mtime":1549005304573,"results":{"filePath":"/Users/horike/src/sls-proxy-plugin/custom_serverless_plugins/serverless-apigateway-service-proxy/prettier.config.js","messages":[],"errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"hashOfConfig":"1icshje"}}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ admin.env
4040
tmp
4141
.coveralls.yml
4242
tmpdirs-serverless
43+
.eslintcache

lib/apiGateway/validate.js

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
'use strict'
2+
const NOT_FOUND = -1
3+
const BbPromise = require('bluebird')
4+
const _ = require('lodash')
5+
6+
module.exports = {
7+
async serviceProxyValidate() {
8+
const events = []
9+
await BbPromise.all(
10+
this.getAllServiceProxies().map(async (serviceProxy) => {
11+
Object.keys(serviceProxy).forEach(async (functionName) => {
12+
await this.checkAllowedService(functionName)
13+
const corsPreflight = []
14+
const http = {
15+
path: await this.getProxyPath(serviceProxy[functionName]),
16+
method: await this.getProxyMethod(serviceProxy[functionName]),
17+
streamName: serviceProxy[functionName].streamName
18+
}
19+
20+
if (serviceProxy[functionName].cors) {
21+
http.cors = this.getCors(serviceProxy[functionName])
22+
23+
const cors = corsPreflight[http.path] || {}
24+
25+
cors.headers = _.union(http.cors.headers, cors.headers)
26+
cors.methods = _.union(http.cors.methods, cors.methods)
27+
cors.origins = _.union(http.cors.origins, cors.origins)
28+
cors.origin = http.cors.origin || '*'
29+
cors.allowCredentials = cors.allowCredentials || http.cors.allowCredentials
30+
31+
// when merging, last one defined wins
32+
if (_.has(http.cors, 'maxAge')) {
33+
cors.maxAge = http.cors.maxAge
34+
}
35+
36+
corsPreflight[http.path] = cors
37+
}
38+
39+
events.push({ functionName, http })
40+
})
41+
})
42+
)
43+
return {
44+
events,
45+
corsPreflight: {}
46+
}
47+
},
48+
49+
async checkAllowedService(serviceName) {
50+
const allowedProxies = ['kinesis']
51+
if (allowedProxies.indexOf(serviceName) === NOT_FOUND) {
52+
const errorMessage = [
53+
`Invalid APIG proxy "${serviceName}".`,
54+
` This plugin supported Proxies are: ${allowedProxies.join(', ')}.`
55+
].join('')
56+
return BbPromise.reject(new this.serverless.classes.Error(errorMessage))
57+
}
58+
},
59+
60+
async getProxyPath(proxy) {
61+
if (typeof proxy.path === 'string') {
62+
return proxy.path.replace(/^\//, '').replace(/\/$/, '')
63+
}
64+
return BbPromise.reject(new this.serverless.classes.Error('Invalid service proxy syntax'))
65+
},
66+
67+
getProxyMethod(proxy) {
68+
if (typeof proxy.method === 'string') {
69+
const method = proxy.method.toLowerCase()
70+
71+
const allowedMethods = ['get', 'post', 'put', 'patch', 'options', 'head', 'delete', 'any']
72+
if (allowedMethods.indexOf(method) === NOT_FOUND) {
73+
const errorMessage = [
74+
`Invalid APIG method "${proxy.method}" in AWS service proxy.`,
75+
` AWS supported methods are: ${allowedMethods.join(', ')}.`
76+
].join('')
77+
throw new this.serverless.classes.Error(errorMessage)
78+
}
79+
return method
80+
}
81+
return BbPromise.reject(new this.serverless.classes.Error('Invalid service proxy syntax'))
82+
},
83+
84+
getCors(proxy) {
85+
const headers = [
86+
'Content-Type',
87+
'X-Amz-Date',
88+
'Authorization',
89+
'X-Api-Key',
90+
'X-Amz-Security-Token',
91+
'X-Amz-User-Agent'
92+
]
93+
94+
let cors = {
95+
origins: ['*'],
96+
origin: '*',
97+
methods: ['OPTIONS'],
98+
headers,
99+
allowCredentials: false
100+
}
101+
102+
if (typeof proxy.cors === 'object') {
103+
cors = proxy.cors
104+
cors.methods = cors.methods || []
105+
cors.allowCredentials = Boolean(cors.allowCredentials)
106+
107+
if (cors.origins && cors.origin) {
108+
const errorMessage = [
109+
'You can only use "origin" or "origins",',
110+
' but not both at the same time to configure CORS.',
111+
' Please check the docs for more info.'
112+
].join('')
113+
throw new this.serverless.classes.Error(errorMessage)
114+
}
115+
116+
if (cors.headers) {
117+
if (!Array.isArray(cors.headers)) {
118+
const errorMessage = [
119+
'CORS header values must be provided as an array.',
120+
' Please check the docs for more info.'
121+
].join('')
122+
throw new this.serverless.classes.Error(errorMessage)
123+
}
124+
} else {
125+
cors.headers = headers
126+
}
127+
128+
if (cors.methods.indexOf('OPTIONS') === NOT_FOUND) {
129+
cors.methods.push('OPTIONS')
130+
}
131+
132+
if (cors.methods.indexOf(proxy.method.toUpperCase()) === NOT_FOUND) {
133+
cors.methods.push(proxy.method.toUpperCase())
134+
}
135+
} else {
136+
cors.methods.push(proxy.method.toUpperCase())
137+
}
138+
139+
return cors
140+
}
141+
}

lib/index.js

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
'use strict'
2+
const chalk = require('chalk')
3+
const BbPromise = require('bluebird')
4+
const _ = require('lodash')
5+
26
const utils = require('./utils')
3-
const compileKinesisProxy = require('./package/kinesis/compileKinesisProxy')
7+
const validate = require('./apiGateway/validate')
8+
const compileRestApi = require('serverless/lib/plugins/aws/package/compile/events/apiGateway/lib/restApi')
9+
const compileResources = require('serverless/lib/plugins/aws/package/compile/events/apiGateway/lib/resources')
10+
const compileDeployment = require('serverless/lib/plugins/aws/package/compile/events/apiGateway/lib/deployment')
11+
const getStackInfo = require('serverless/lib/plugins/aws/info/getStackInfo')
12+
const compileKinesisMethods = require('./package/kinesis/methods')
13+
const compileToKinesisIamRole = require('./package/kinesis/compileToKinesisIamRole')
414

515
class ServerlessApigatewayServiceProxy {
616
constructor(serverless, options) {
@@ -10,14 +20,93 @@ class ServerlessApigatewayServiceProxy {
1020
this.service = this.serverless.service.service
1121
this.region = this.provider.getRegion()
1222
this.stage = this.provider.getStage()
13-
Object.assign(this, compileKinesisProxy, utils)
23+
Object.assign(
24+
this,
25+
compileRestApi,
26+
compileResources,
27+
compileKinesisMethods,
28+
compileToKinesisIamRole,
29+
compileDeployment,
30+
getStackInfo,
31+
validate,
32+
utils
33+
)
1434

1535
this.hooks = {
1636
'package:compileEvents': async () => {
17-
await this.compileKinesisProxy()
37+
if (this.getAllServiceProxies().length > 0) {
38+
this.validated = await this.serviceProxyValidate()
39+
await this.compileRestApi()
40+
await this.compileResources()
41+
if (await this.existsDeployment()) {
42+
await this.compileDeployment()
43+
}
44+
await this.compileKinesisMethods()
45+
await this.compileToKinesisIamRole()
46+
}
47+
},
48+
'after:deploy:deploy': async () => {
49+
if (this.getAllServiceProxies().length > 0) {
50+
await this.getStackInfo()
51+
await this.display()
52+
}
1853
}
1954
}
2055
}
56+
57+
async existsDeployment() {
58+
let exists = true
59+
Object.keys(this.serverless.service.provider.compiledCloudFormationTemplate.Resources).forEach(
60+
async (resource) => {
61+
if (
62+
this.serverless.service.provider.compiledCloudFormationTemplate.Resources[resource][
63+
'Type'
64+
] == 'AWS::ApiGateway::Deployment'
65+
) {
66+
exists = false
67+
}
68+
}
69+
)
70+
return exists
71+
}
72+
73+
async display() {
74+
let message = ''
75+
let serviceProxyMessages = ''
76+
77+
const endpointInfo = this.gatheredData.info.endpoint
78+
message += `${chalk.yellow.underline('Serverless Apigateway Service proxy OutPuts')}\n`
79+
message += `${chalk.yellow('endpoints:')}`
80+
81+
await BbPromise.all(
82+
this.getAllServiceProxies().map(async (serviceProxy) => {
83+
Object.keys(serviceProxy).forEach(async (serviceName) => {
84+
let path
85+
const method = serviceProxy[serviceName].method.toUpperCase()
86+
path = serviceProxy[serviceName].path
87+
path =
88+
path !== '/'
89+
? `/${path
90+
.split('/')
91+
.filter((p) => p !== '')
92+
.join('/')}`
93+
: ''
94+
serviceProxyMessages += `\n ${method} - ${endpointInfo}${path}`
95+
})
96+
})
97+
)
98+
99+
if (_.isEmpty(serviceProxyMessages)) {
100+
return ''
101+
}
102+
103+
message += serviceProxyMessages
104+
message += '\n'
105+
106+
this.serverless.cli.consoleLog(message)
107+
108+
return message
109+
}
21110
}
22111

23112
module.exports = ServerlessApigatewayServiceProxy

lib/package/kinesis/compileKinesisProxy.js

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use strict'
2+
const BbPromise = require('bluebird')
3+
const _ = require('lodash')
4+
5+
module.exports = {
6+
async compileToKinesisIamRole() {
7+
await BbPromise.all(
8+
this.getAllServiceProxies().map(async (serviceProxy) => {
9+
Object.keys(serviceProxy).forEach(async (serviceName) => {
10+
if (serviceName == 'kinesis') {
11+
const template = {
12+
Type: 'AWS::IAM::Role',
13+
Properties: {
14+
AssumeRolePolicyDocument: {
15+
Version: '2012-10-17',
16+
Statement: [
17+
{
18+
Effect: 'Allow',
19+
Principal: {
20+
Service: 'apigateway.amazonaws.com'
21+
},
22+
Action: 'sts:AssumeRole'
23+
}
24+
]
25+
},
26+
Policies: [
27+
{
28+
PolicyName: 'apigatewaytokinesis',
29+
PolicyDocument: {
30+
Version: '2012-10-17',
31+
Statement: [
32+
{
33+
Effect: 'Allow',
34+
Action: ['kinesis:PutRecord'],
35+
Resource: '*'
36+
}
37+
]
38+
}
39+
}
40+
]
41+
}
42+
}
43+
44+
_.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, {
45+
ApigatewayToKinesisRole: template
46+
})
47+
}
48+
})
49+
})
50+
)
51+
}
52+
}

0 commit comments

Comments
 (0)