UNPKG

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