UNPKG

11.4 kBJavaScriptView Raw
1'use strict';
2
3const debug = require('debug')('fun:common');
4
5const _ = require('lodash');
6const { green, red } = require('colors');
7
8const { promptForFunctionSelection } = require('./init/prompt');
9
10const SERVICE_RESOURCE = 'Aliyun::Serverless::Service';
11const FUNCTION_RESOURCE = 'Aliyun::Serverless::Function';
12
13/* eslint-disable */
14function iterateResources(resources, resType, callback) {
15 for (const [name, res] of Object.entries(resources)) {
16 if (res.Type === resType) {
17 callback(name, res);
18 }
19 }
20}
21/* eslint-enable */
22
23function findServices(resources) {
24 const services = [];
25
26 iterateResources(resources, SERVICE_RESOURCE, (serviceName, serviceRes) => {
27 services.push({
28 serviceName,
29 serviceRes
30 });
31 });
32
33 return services;
34}
35
36
37function iterateFunctions(tplContent, callback) {
38 if (tplContent.Resources) {
39 const resources = tplContent.Resources;
40
41 iterateResources(resources, SERVICE_RESOURCE, (serviceName, serviceRes) => {
42 iterateResources(serviceRes, FUNCTION_RESOURCE, (functionName, functionRes) => {
43 callback(
44 serviceName,
45 serviceRes,
46 functionName,
47 functionRes
48 );
49 });
50 });
51 }
52}
53
54function findFunctions(serviceRes) {
55
56 const functions = [];
57
58 iterateResources(serviceRes, FUNCTION_RESOURCE, (functionName, functionRes) => {
59 functions.push({
60 functionName,
61 functionRes
62 });
63 });
64
65 return functions;
66}
67
68function findHttpTriggersInFunction(functionRes) {
69 const triggers = [];
70
71 if (functionRes.Events) {
72 iterateResources(functionRes.Events, 'HTTP', (triggerName, triggerRes) => {
73 triggers.push({
74 triggerName,
75 triggerRes
76 });
77 });
78 }
79
80 return triggers;
81}
82
83function findFunctionByServiceAndFunctionName(resources, serviceName, functionName) {
84 debug('begin search serviceName and functionName');
85
86 let serviceRes = resources[serviceName];
87
88 if (!serviceRes || !serviceName || serviceRes.Type !== SERVICE_RESOURCE) {
89
90 throw new Error(`could not found service: ${serviceName}`);
91 }
92
93 let functionRes = serviceRes[functionName];
94
95 if (functionRes && functionRes.Type !== FUNCTION_RESOURCE) {
96 functionRes = null;
97 }
98
99 return {
100 serviceName,
101 serviceRes,
102 functionName,
103 functionRes
104 };
105}
106
107function findFunctionInService(funcName, serviceRes) {
108
109 debug('find function ' + funcName + ' definition in service: ' + JSON.stringify(serviceRes));
110
111 for (let { functionName, functionRes } of findFunctions(serviceRes)) {
112 debug(`functionName is ${functionName}, compare with ${functionName}`);
113 if (functionName === funcName) {
114 debug(`found function ${functionName}, functionRes is ${functionRes}`);
115
116 return functionRes;
117 }
118 }
119
120 return null;
121}
122
123function findFunctionByFunctionName(resources, functionName) {
124 // iterator all services and functions
125 for (let { serviceName, serviceRes } of findServices(resources)) {
126 debug('servicename: ' + serviceName);
127 const functionRes = findFunctionInService(functionName, serviceRes);
128
129 if (functionRes) {
130 return {
131 serviceName,
132 serviceRes,
133 functionName,
134 functionRes
135 };
136 }
137 }
138
139 return {};
140}
141
142function parseDomainRoutePath(domainRoutePath) {
143 let domainName = null;
144 let routePath = null;
145
146 if (!domainRoutePath) { return []; }
147
148 const index = domainRoutePath.indexOf('/');
149 if (index < 0) {
150 domainName = domainRoutePath;
151 } else {
152 domainName = domainRoutePath.substring(0, index);
153 routePath = domainRoutePath.substring(index);
154 }
155 return [domainName, routePath];
156}
157
158function parseFunctionPath(funcPath) {
159 let serviceName = null;
160 let functionName = null;
161
162 if (!funcPath) { return []; }
163
164 const index = funcPath.indexOf('/');
165 if (index < 0) {
166 functionName = funcPath;
167 } else {
168 serviceName = funcPath.substring(0, index);
169 functionName = funcPath.substring(index + 1);
170 }
171 debug(`invoke service: ${serviceName}`);
172 debug(`invoke function: ${functionName}`);
173 return [serviceName, functionName];
174}
175
176/**
177 * funcPath : functionName or serviceName/functionName
178 */
179function findFunctionInTpl(funcPath, tpl) {
180 const [serviceName, functionName] = parseFunctionPath(funcPath);
181 return doFindFunctionInTpl(serviceName, functionName, tpl);
182}
183
184// return first if only provide functionName
185function doFindFunctionInTpl(serviceName, functionName, tpl) {
186
187 const resources = tpl.Resources;
188
189 if (serviceName) {
190 // invokeName is serviceName/functionName
191 return findFunctionByServiceAndFunctionName(resources, serviceName, functionName);
192 }
193 // invokeName is functionName
194 return findFunctionByFunctionName(resources, functionName);
195}
196
197function findFunctionsInTpl(tpl, filter) {
198 const functions = [];
199
200 const resources = tpl.Resources;
201
202 for (let { serviceName, serviceRes } of findServices(resources)) {
203 for (let { functionName, functionRes } of findFunctions(serviceRes)) {
204
205 if (filter && !filter(functionName, functionRes)) { continue; }
206
207 functions.push({
208 serviceName,
209 serviceRes,
210 functionName,
211 functionRes
212 });
213 }
214 }
215
216 return functions;
217}
218
219function findNasConfigInService(serviceRes) {
220 if (!serviceRes) { return null; }
221
222 const serviceProps = serviceRes.Properties;
223
224 if (!serviceProps) { return null; }
225
226 return serviceProps.NasConfig;
227}
228
229function findHttpTriggersInTpl(tpl) {
230 const resources = tpl.Resources;
231
232 const httpTriggers = [];
233
234 for (let { serviceName, serviceRes } of findServices(resources)) {
235 for (let { functionName, functionRes } of findFunctions(serviceRes)) {
236 for (let { triggerName, triggerRes } of findHttpTriggersInFunction(functionRes)) {
237 httpTriggers.push({
238 serviceName,
239 serviceRes,
240 functionName,
241 functionRes,
242 triggerName,
243 triggerRes
244 });
245 }
246 }
247 }
248
249 return httpTriggers;
250}
251
252function findFirstFunctionName(tpl) {
253 const resources = tpl.Resources;
254
255 var firstInvokeName;
256
257 for (let { serviceName, serviceRes } of findServices(resources)) {
258 for (let { functionName } of findFunctions(serviceRes)) {
259 firstInvokeName = serviceName + '/' + functionName;
260 break;
261 }
262 }
263
264 if (!firstInvokeName) {
265 throw new Error(red(`Missing function definition in template.yml`));
266 }
267 return firstInvokeName;
268}
269
270// find the first service in resoueces
271function findServiceByServiceName (resources, name) {
272
273 for (let { serviceName, serviceRes } of findServices(resources)) {
274
275 if (serviceName === name) {
276 return {
277 serviceName,
278 serviceRes
279 };
280 }
281 }
282 return {};
283}
284
285function findAllFunctionsByFunctionName(resources, functionName) {
286
287 let functions = [];
288
289 for (let { serviceName, serviceRes } of findServices(resources)) {
290 debug('servicename: ' + serviceName);
291 const functionRes = findFunctionInService(functionName, serviceRes);
292
293 if (functionRes) {
294
295 functions.push({
296 serviceName,
297 serviceRes,
298 functionName,
299 functionRes
300 });
301 }
302 }
303 return functions;
304}
305
306async function matchingFuntionUnderServiceBySourceName(resources, sourceName) {
307
308 const serviceObj = findServiceByServiceName(resources, sourceName);
309
310 if (!_.isEmpty(serviceObj)) {
311
312 return {
313 serviceName: serviceObj.serviceName,
314 serviceRes: serviceObj.serviceRes
315 };
316 }
317
318 const functions = findAllFunctionsByFunctionName(resources, sourceName);
319
320 if (functions.length === 0) {
321
322 throw new Error(`could not found sourceName: ${sourceName}`);
323
324 } else if (functions.length > 1) {
325
326 const { serviceName, functionName } = await promptForFunctionSelection(functions);
327
328 const selectionFunction = functions.find(funcObj => {
329
330 return funcObj.serviceName === serviceName && funcObj.functionName === functionName;
331 });
332
333 // delete unmatch functions under a serviceRes
334 const serviceRes = deleteUnmatchFunctionsUnderServiceRes(selectionFunction);
335
336 return {
337 serviceName: selectionFunction.serviceName,
338 serviceRes
339 };
340 }
341
342 const serviceName = _.first(functions).serviceName;
343 let serviceRes = _.first(functions).serviceRes;
344
345 serviceRes = deleteUnmatchFunctionsUnderServiceRes({
346 serviceName,
347 serviceRes,
348 functionName: sourceName
349 });
350
351 return {
352 serviceName,
353 serviceRes
354 };
355}
356
357// delete unmatch functions under a serviceRes
358function deleteUnmatchFunctionsUnderServiceRes({
359 serviceName,
360 serviceRes,
361 functionName
362}) {
363
364 const functionNamesInService = findFunctions(serviceRes).map(funRes => {
365 return funRes.functionName;
366 });
367
368 if (!_.includes(functionNamesInService, functionName)) {
369
370 throw new Error(`could not found service/function:` + green(`${serviceName}`) + `/` + red(`${functionName}`));
371 }
372
373 for (let functions of findFunctions(serviceRes)) {
374
375 if (functions.functionName !== functionName) {
376
377 serviceRes = _.omit(serviceRes, functions.functionName);
378 }
379 }
380
381 return serviceRes;
382}
383
384function findServiceByCertainServiceAndFunctionName(resources, certainServiceName, certainFunctionName) {
385
386 for (let { serviceName, serviceRes } of findServices(resources)) {
387
388 if (serviceName === certainServiceName) {
389
390 serviceRes = deleteUnmatchFunctionsUnderServiceRes({
391 serviceName,
392 serviceRes,
393 functionName: certainFunctionName
394 });
395
396 return {
397 serviceName,
398 serviceRes
399 };
400 }
401 }
402
403 throw new Error(`could not found service: ${certainServiceName}`);
404}
405
406
407function ensureNasParams(nasConfig) {
408
409 const propsRequired = ['Auto', 'UserId', 'GroupId'];
410
411 const notExistParams = propsRequired.filter(paramter => {
412 return !nasConfig.hasOwnProperty(paramter);
413 });
414
415 if (!_.isEmpty(notExistParams)) {
416 console.error(red(''));
417 throw new Error(red(`Missing '${notExistParams.join(', ')}' in NasConfig.`));
418 }
419 if (!_.isEmpty(nasConfig.MountPoints)) {
420 console.error(red(''));
421 throw new Error(red(`Additional properties: 'MountPoints' in NasConfig.`));
422 }
423}
424
425function isNasAutoConfig(nasConfig) {
426
427 if (nasConfig === 'Auto') {
428 return true;
429 }
430
431 if ((nasConfig || {}).Auto) {
432 ensureNasParams(nasConfig);
433 return true;
434 }
435
436 return false;
437}
438
439function getUserIdAndGroupId(nasConfig) {
440 if (_.isEmpty(nasConfig)) { return {}; }
441
442 if (nasConfig === 'Auto') {
443 return {
444 userId: 10003,
445 groupId: 10003
446 };
447 }
448 return {
449 userId: nasConfig.UserId,
450 groupId: nasConfig.GroupId
451 };
452}
453
454function isVpcAutoConfig(vpcConfig) {
455 if (vpcConfig === 'Auto') { return true; }
456 return false;
457}
458
459// except Auto
460function onlyOneNASExists(nasConfig) {
461 const isNasAuto = isNasAutoConfig(nasConfig);
462
463 if (_.isEmpty(nasConfig || isNasAuto)) {
464 return false;
465 }
466 const mountPoints = nasConfig.MountPoints || [];
467 return mountPoints.length === 1;
468}
469
470module.exports = {
471 findFunctionInTpl, findHttpTriggersInTpl,
472 findFunctionsInTpl, findNasConfigInService,
473 findHttpTriggersInFunction, findServices,
474 findFunctions, findFirstFunctionName, matchingFuntionUnderServiceBySourceName,
475 findServiceByCertainServiceAndFunctionName, deleteUnmatchFunctionsUnderServiceRes,
476 isNasAutoConfig, isVpcAutoConfig, parseFunctionPath, iterateFunctions, parseDomainRoutePath,
477 onlyOneNASExists, findServiceByServiceName, findFunctionByServiceAndFunctionName, getUserIdAndGroupId
478};
\No newline at end of file