1 |
|
2 | 'use strict'
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | const path = require('path')
|
11 |
|
12 | const execa = require('execa')
|
13 | const loadJsonFile = require('load-json-file')
|
14 | const semver = require('semver')
|
15 | const writeJsonFile = require('write-json-file')
|
16 |
|
17 | const nonAlphaNumericToDashes = require('./utils/non-alpha-numeric-to-dashes.js')
|
18 | const readCors = require('./cors/read.js')
|
19 | const readRoutes = require('./routes/read.js')
|
20 | const scope = require('./scope.js')
|
21 | const variables = require('./variables.js')
|
22 | const network = require('./network.js')
|
23 | const updateYamlFile = require('./utils/yaml.js').updateYamlFile
|
24 | const copyRecursive = require('./utils/copy-recursive.js')
|
25 | const validateCors = require('./cors/validate.js')
|
26 | const values = require('./values.js')
|
27 |
|
28 | const HANDLER = 'handler'
|
29 | const WRAPPER = path.join(__dirname, '..', 'dist', 'wrapper.js')
|
30 |
|
31 | function applyTemplate(cwd /* : string */) /* : Promise<void> */ {
|
32 | return executeSLSCommand(['create', '--template', 'aws-nodejs'], { cwd })
|
33 | }
|
34 |
|
35 | function copyConfiguration(
|
36 | target /* : string */,
|
37 | projectPath /* : string */,
|
38 | env /* : string */
|
39 | ) /* : Promise<void> */ {
|
40 | const configPath = path.join(target, 'bm-server.json')
|
41 | return Promise.all([
|
42 | readCors(projectPath).then(cors => (cors ? validateCors(cors) : false)),
|
43 | readRoutes(projectPath),
|
44 | scope.read(projectPath)
|
45 | ]).then(results =>
|
46 | writeJsonFile(configPath, {
|
47 | cors: results[0],
|
48 | routes: results[1].map((routeConfig, index) => {
|
49 | routeConfig.module = path.posix.join('project', routeConfig.module)
|
50 | return routeConfig
|
51 | }),
|
52 | scope: results[2].project,
|
53 | env
|
54 | })
|
55 | )
|
56 | }
|
57 |
|
58 | function copyProject(
|
59 | source /* : string */,
|
60 | target /* : string */
|
61 | ) /* : Promise<string> */ {
|
62 | const projectPath = path.join(target, 'project')
|
63 | return copyRecursive(source, projectPath).then(() => projectPath)
|
64 | }
|
65 |
|
66 | function copyWrapper(target /* : string */) /* : Promise<void> */ {
|
67 | const wrapperPath = path.join(target, `${HANDLER}.js`)
|
68 | return copyRecursive(WRAPPER, wrapperPath)
|
69 | }
|
70 |
|
71 | function executeSLSCommand(
|
72 | args /* : Array<string> */,
|
73 | options /* : { [id:string]: any } */
|
74 | ) /* : Promise<void> */ {
|
75 | return execa(
|
76 | 'serverless',
|
77 | args,
|
78 | Object.assign({}, options, {
|
79 | preferLocal: true,
|
80 | localDir: path.join(__dirname, '..')
|
81 | })
|
82 | )
|
83 | }
|
84 |
|
85 | function getFunctionName(
|
86 | cfg /* : BlinkMRCServer */,
|
87 | env /* : string */
|
88 | ) /* : string */ {
|
89 |
|
90 | const arr = [cfg.project || '', env]
|
91 | const mapped = arr.map(nonAlphaNumericToDashes)
|
92 | return mapped.join('-')
|
93 | }
|
94 |
|
95 | function registerFunctions(
|
96 | target /* : string */,
|
97 | projectPath /* : string */,
|
98 | env /* : string */
|
99 | ) /* : Promise<void> */ {
|
100 | return scope.read(projectPath).then(cfg =>
|
101 | updateServerlessYamlFile(target, config => {
|
102 | config.service = nonAlphaNumericToDashes(cfg.project || '')
|
103 | config.provider = config.provider || {}
|
104 | config.provider.region = cfg.region
|
105 | config.provider.stage = env
|
106 |
|
107 | const functionName = getFunctionName(cfg, env)
|
108 | config.functions = {
|
109 | [functionName]: {
|
110 | events: [
|
111 | {
|
112 | http: 'ANY {path+}'
|
113 | }
|
114 | ],
|
115 | handler: `${HANDLER}.handler`,
|
116 | name: functionName,
|
117 | description: `Server CLI Lambda function for project: ${cfg.project ||
|
118 | ''}`,
|
119 | timeout: cfg.timeout || values.DEFAULT_TIMEOUT_SECONDS
|
120 | }
|
121 | }
|
122 |
|
123 | return config
|
124 | })
|
125 | )
|
126 | }
|
127 |
|
128 | function registerDeploymentBucket(
|
129 | target /* : string */,
|
130 | deploymentBucket /* : string | void */
|
131 | ) /* : Promise<void> */ {
|
132 | if (!deploymentBucket) {
|
133 | return Promise.resolve()
|
134 | }
|
135 | return updateServerlessYamlFile(target, config => {
|
136 | config.provider = config.provider || {}
|
137 | config.provider.deploymentBucket = deploymentBucket
|
138 | return config
|
139 | })
|
140 | }
|
141 |
|
142 | function registerExecutionRole(
|
143 | target /* : string */,
|
144 | executionRole /* : string | void */
|
145 | ) /* : Promise<void> */ {
|
146 | if (!executionRole) {
|
147 | return Promise.resolve()
|
148 | }
|
149 | return updateServerlessYamlFile(target, config => {
|
150 | config.provider = config.provider || {}
|
151 | config.provider.role = executionRole
|
152 | return config
|
153 | })
|
154 | }
|
155 |
|
156 | function registerRootProxy(
|
157 | target /* : string */,
|
158 | env /* : string */
|
159 | ) /* : Promise<void> */ {
|
160 |
|
161 |
|
162 |
|
163 |
|
164 | return loadJsonFile(path.join(__dirname, 'root-route-proxy.json')).then(
|
165 | resources =>
|
166 | updateServerlessYamlFile(target, config => {
|
167 | config.resources = resources
|
168 | return config
|
169 | })
|
170 | )
|
171 | }
|
172 |
|
173 | function registerVariables(
|
174 | target /* : string */,
|
175 | projectPath /* : string */,
|
176 | env /* : string */,
|
177 | analyticsConfig /* : AnalyticsConfig */
|
178 | ) /* : Promise<void> */ {
|
179 | return variables.read(projectPath, env).then(envVars => {
|
180 | if (analyticsConfig.origin && analyticsConfig.collectorToken) {
|
181 | envVars.ONEBLINK_ANALYTICS_ORIGIN = analyticsConfig.origin
|
182 | envVars.ONEBLINK_ANALYTICS_COLLECTOR_TOKEN =
|
183 | analyticsConfig.collectorToken
|
184 | }
|
185 |
|
186 | if (!Object.keys(envVars).length) {
|
187 | return
|
188 | }
|
189 |
|
190 | return updateServerlessYamlFile(target, config => {
|
191 | config.provider = config.provider || {}
|
192 | config.provider.environment = envVars
|
193 | return config
|
194 | })
|
195 | })
|
196 | }
|
197 |
|
198 | async function registerVpc(
|
199 | target /* : string */,
|
200 | projectPath /* : string */,
|
201 | env /* : string */,
|
202 | vpcSecurityGroups /* : string | void */,
|
203 | vpcSubnets /* : string | void */,
|
204 | separator /* : string */
|
205 | ) /* : Promise<void> */ {
|
206 | const securityGroupIds = []
|
207 | const subnetIds = []
|
208 |
|
209 |
|
210 | const networkConfiguration = await network.readNetwork(projectPath, env)
|
211 | if (networkConfiguration) {
|
212 | securityGroupIds.push(...networkConfiguration.vpcSecurityGroups)
|
213 | subnetIds.push(...networkConfiguration.vpcSubnets)
|
214 | } else {
|
215 | if (typeof vpcSecurityGroups === 'string') {
|
216 | securityGroupIds.push(...vpcSecurityGroups.split(separator))
|
217 | }
|
218 | if (typeof vpcSubnets === 'string') {
|
219 | subnetIds.push(...vpcSubnets.split(separator))
|
220 | }
|
221 | }
|
222 |
|
223 |
|
224 | return updateServerlessYamlFile(target, config => {
|
225 | config.provider = config.provider || {}
|
226 | config.provider.vpc = {
|
227 | securityGroupIds: securityGroupIds
|
228 | .map(securityGroup => securityGroup.trim())
|
229 | .filter(securityGroup => !!securityGroup),
|
230 | subnetIds: subnetIds
|
231 | .map(subnet => subnet.trim())
|
232 | .filter(subnet => !!subnet)
|
233 | }
|
234 | return config
|
235 | })
|
236 | }
|
237 |
|
238 | function registerNodeVersion(
|
239 | target /* : string */,
|
240 | bmServerVersion /* : string */
|
241 | ) /* : Promise<void> */ {
|
242 | return updateServerlessYamlFile(target, config => {
|
243 | config.provider = config.provider || {}
|
244 | switch (semver.major(bmServerVersion)) {
|
245 | case 0:
|
246 | case 1: {
|
247 | config.provider.runtime = 'nodejs4.3'
|
248 | break
|
249 | }
|
250 | case 2: {
|
251 | config.provider.runtime = 'nodejs6.10'
|
252 | break
|
253 | }
|
254 | case 3: {
|
255 | config.provider.runtime = 'nodejs8.10'
|
256 | break
|
257 | }
|
258 | }
|
259 | return config
|
260 | })
|
261 | }
|
262 |
|
263 | function updateServerlessYamlFile(
|
264 | target /* : string */,
|
265 | updater /* : (data: Object) => Object */
|
266 | ) /* : Promise<void> */ {
|
267 | const configPath = path.join(target, 'serverless.yml')
|
268 | return updateYamlFile(configPath, updater)
|
269 | }
|
270 |
|
271 | module.exports = {
|
272 | applyTemplate,
|
273 | copyConfiguration,
|
274 | copyProject,
|
275 | copyWrapper,
|
276 | executeSLSCommand,
|
277 | getFunctionName,
|
278 | registerDeploymentBucket,
|
279 | registerExecutionRole,
|
280 | registerFunctions,
|
281 | registerNodeVersion,
|
282 | registerRootProxy,
|
283 | registerVariables,
|
284 | registerVpc
|
285 | }
|