UNPKG

34.9 kBJavaScriptView Raw
1/*
2
3 ----------------------------------------------------------------------------
4 | qewd-up: Rapid QEWD API Development |
5 | |
6 | Copyright (c) 2018-20 M/Gateway Developments Ltd, |
7 | Redhill, Surrey UK. |
8 | All rights reserved. |
9 | |
10 | http://www.mgateway.com |
11 | Email: rtweed@mgateway.com |
12 | |
13 | |
14 | Licensed under the Apache License, Version 2.0 (the "License"); |
15 | you may not use this file except in compliance with the License. |
16 | You may obtain a copy of the License at |
17 | |
18 | http://www.apache.org/licenses/LICENSE-2.0 |
19 | |
20 | Unless required by applicable law or agreed to in writing, software |
21 | distributed under the License is distributed on an "AS IS" BASIS, |
22 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
23 | See the License for the specific language governing permissions and |
24 | limitations under the License. |
25 ----------------------------------------------------------------------------
26
27 12 May 2020
28
29*/
30
31//console.log('Loading /up/run.js in process ' + process.pid);
32
33var fs = require('fs-extra');
34var path = require('path');
35var os = require('os');
36var module_exists = require('module-exists');
37var child_process = require('child_process');
38var qewd = require('../lib/master');
39var uuid = require('uuid/v4'); // loaded as dependency of ewd-session
40
41function getDirectories(path) {
42 return fs.readdirSync(path).filter(function(file) {
43 return fs.statSync(path + '/' + file).isDirectory();
44 });
45}
46
47function createModuleMap(cwd, config) {
48 var qewdAppsPath = cwd + '/qewd-apps';
49 if (fs.existsSync(qewdAppsPath)) {
50 if (!config.moduleMap) {
51 config.moduleMap = {};
52 }
53 var appList = getDirectories(qewdAppsPath);
54 appList.forEach(function(appName) {
55 var appPath = qewdAppsPath + '/' + appName;
56 var indexPath = appPath + '/index.js';
57 var handlerList = getDirectories(appPath);
58 // if handler modules exist, create the dynamic handler for this path
59 // otherwise use the existing index.js
60 if (handlerList.length > 0) {
61 var text;
62 //text = "module.exports = require('" + __dirname + "/qewdAppHandler" + "')('" + appPath + "');"
63 var reqPath = path.join(__dirname, 'qewdAppHandler');
64 var appPath2 = path.normalize(appPath);
65 if (os.platform() === 'win32') {
66 reqPath = reqPath.split('\\').join('\\\\');
67 appPath2 = appPath2.split('\\').join('\\\\');
68 }
69 text = "module.exports = require('" + reqPath + "')('" + appPath2 + "');"
70 fs.writeFileSync(indexPath, text);
71 }
72 if (fs.existsSync(indexPath)) {
73 config.moduleMap[appName] = appPath;
74 }
75 });
76 }
77}
78
79function installModule(moduleName, modulePath) {
80 var pieces = moduleName.split('@');
81 var rootName;
82 if (moduleName.startsWith('@')) {
83 rootName = '@' + pieces[1];
84 }
85 else {
86 rootName = pieces[0];
87 }
88 if (!module_exists(rootName) && !fs.existsSync(modulePath + '/node_modules/' + rootName)) {
89 var prefix = '';
90 if (typeof modulePath !== 'undefined') {
91 prefix = ' --prefix ' + modulePath;
92 }
93 child_process.execSync('npm install --unsafe-perm ' + moduleName + prefix, {stdio:[0,1,2]});
94 console.log('\n' + moduleName + ' installed');
95 }
96 else {
97 console.log(moduleName + ' already installed');
98 }
99}
100
101function installModules(cwd) {
102 var npmModules;
103 var modulePath;
104 if (fs.existsSync(cwd + '/install_modules.json')) {
105 if (!fs.existsSync(cwd + '/node_modules')) {
106 fs.mkdirSync(cwd + '/node_modules');
107 }
108
109 process.env.NODE_PATH = cwd + '/node_modules:' + process.env.NODE_PATH;
110 require('module').Module._initPaths();
111
112 npmModules = require(cwd + '/install_modules.json');
113 npmModules.forEach(function(moduleName) {
114 console.log('\nInstalling module ' + moduleName + ' to ' + cwd);
115 installModule(moduleName, cwd);
116 });
117 console.log('** NODE_PATH = ' + process.env.NODE_PATH);
118 }
119}
120
121function linkMonitor(cwd, name) {
122 if (name !== '') {
123 name = '/' + name;
124 var path1 = cwd + name;
125 if (process.env.mode && process.env.microservice) {
126 path1 = cwd;
127 }
128 if (!fs.existsSync(path1)) {
129 fs.mkdirSync(path1);
130 }
131 }
132 var webServerRootPath = cwd + name + '/www';
133 if (process.env.mode && process.env.microservice) {
134 webServerRootPath = cwd + '/www';
135 }
136 if (!fs.existsSync(webServerRootPath)) {
137 fs.mkdirSync(webServerRootPath);
138 }
139 if (process.platform === 'win32') {
140 fs.copySync(process.cwd() + '/node_modules/qewd-monitor/www', webServerRootPath + '/qewd-monitor');
141 fs.copySync(process.cwd() + '/node_modules/ewd-client/lib/proto/ewd-client.js', webServerRootPath + '/ewd-client.js');
142 let fromPath = process.cwd() + '/www/qewd-client.js';
143 let toPath = webServerRootPath + '/qewd-client.js';
144 if (!fs.existsSync(toPath) && fs.existsSync(fromPath)) {
145 fs.copySync(fromPath, toPath);
146 }
147 fromPath = process.cwd() + '/www/mg-webComponents.js';
148 toPath = webServerRootPath + '/mg-webComponents.js';
149 if (!fs.existsSync(toPath) && fs.existsSync(fromPath)) {
150 fs.copySync(fromPath, toPath);
151 }
152 fromPath = process.cwd() + '/www/components';
153 toPath = webServerRootPath + '/components';
154 if (!fs.existsSync(toPath) && fs.existsSync(fromPath)) {
155 fs.copySync(fromPath, toPath);
156 }
157 fromPath = process.cwd() + '/www/qewd-monitor-adminui';
158 toPath = webServerRootPath + '/qewd-monitor-adminui';
159 if (!fs.existsSync(toPath) && fs.existsSync(fromPath)) {
160 fs.copySync(fromPath, toPath);
161 }
162 }
163 else {
164 var cmd = 'ln -sf ' + process.cwd() + '/node_modules/qewd-monitor/www ' + webServerRootPath + '/qewd-monitor';
165 child_process.execSync(cmd, {stdio:[0,1,2]});
166 cmd = 'ln -sf ' + process.cwd() + '/node_modules/ewd-client/lib/proto/ewd-client.js ' + webServerRootPath + '/ewd-client.js';
167 child_process.execSync(cmd, {stdio:[0,1,2]});
168 if (fs.existsSync(process.cwd() + '/www/qewd-client.js')) {
169 cmd = 'ln -sf ' + process.cwd() + '/www/qewd-client.js ' + webServerRootPath + '/qewd-client.js';
170 child_process.execSync(cmd, {stdio:[0,1,2]});
171 }
172 if (fs.existsSync(process.cwd() + '/www/mg-webComponents.js')) {
173 cmd = 'ln -sf ' + process.cwd() + '/www/mg-webComponents.js ' + webServerRootPath + '/mg-webComponents.js';
174 child_process.execSync(cmd, {stdio:[0,1,2]});
175 if (!fs.existsSync(webServerRootPath + '/components')) {
176 fs.mkdirSync(webServerRootPath + '/components');
177 }
178 if (fs.existsSync(process.cwd() + '/www/components/adminui') && !fs.existsSync(webServerRootPath + '/components/adminui')) {
179 fs.mkdirSync(webServerRootPath + '/components/adminui');
180 cmd = 'cp -r ' + process.cwd() + '/www/components/adminui ' + webServerRootPath + '/components';
181 child_process.execSync(cmd, {stdio:[0,1,2]});
182 }
183 if (fs.existsSync(process.cwd() + '/www/components/leaflet') && !fs.existsSync(webServerRootPath + '/components/leaflet')) {
184 fs.mkdirSync(webServerRootPath + '/components/leaflet');
185 cmd = 'cp -r ' + process.cwd() + '/www/components/leaflet ' + webServerRootPath + '/components';
186 child_process.execSync(cmd, {stdio:[0,1,2]});
187 }
188 if (fs.existsSync(process.cwd() + '/www/components/d3') && !fs.existsSync(webServerRootPath + '/components/d3')) {
189 fs.mkdirSync(webServerRootPath + '/components/d3');
190 cmd = 'cp -r ' + process.cwd() + '/www/components/d3 ' + webServerRootPath + '/components';
191 child_process.execSync(cmd, {stdio:[0,1,2]});
192 }
193
194 if (fs.existsSync(process.cwd() + '/www/qewd-monitor-adminui') && !fs.existsSync(webServerRootPath + '/qewd-monitor-adminui')) {
195 fs.mkdirSync(webServerRootPath + '/qewd-monitor-adminui');
196 cmd = 'cp -r ' + process.cwd() + '/www/qewd-monitor-adminui ' + webServerRootPath;
197 child_process.execSync(cmd, {stdio:[0,1,2]});
198 if (!fs.existsSync(cwd + '/qewd-apps/qewd-monitor-adminui')) {
199 fs.mkdirSync(cwd + '/qewd-apps/qewd-monitor-adminui');
200 cmd = 'mv ' + webServerRootPath + '/qewd-monitor-adminui/qewd-apps/* ' + cwd + '/qewd-apps/qewd-monitor-adminui';
201 child_process.execSync(cmd, {stdio:[0,1,2]});
202 cmd = 'rm -r ' + webServerRootPath + '/qewd-monitor-adminui/qewd-apps';
203 child_process.execSync(cmd, {stdio:[0,1,2]});
204 }
205 }
206 }
207 }
208}
209
210function unlinkMonitor(cwd, name) {
211 if (name !== '') name = '/' + name;
212 var path = cwd + name + '/www/qewd-monitor'
213 if (process.env.mode && process.env.microservice) {
214 path = cwd + '/www/qewd-monitor';
215 }
216 if (fs.existsSync(path)) {
217 var cmd = 'unlink ' + path;
218 child_process.execSync(cmd, {stdio:[0,1,2]});
219 }
220}
221
222function updateRoutes(json) {
223 fs.writeFileSync('/opt/qewd/mapped/configuration/routes.json', JSON.stringify(json, null, 2));
224}
225
226function addImportRoute(config_data, routes) {
227 var startMode = 'normal';
228 if (!config_data.microservices) return startMode;
229
230 var on_microservices = [];
231 config_data.microservices.forEach(function(ms) {
232 if (ms.apis && ms.apis.import && !ms.apis.imported) {
233 // this microservice needs to be imported
234 on_microservices.push(ms.name);
235 }
236 });
237
238 if (on_microservices.length > 0) {
239
240 startMode = 'import';
241
242 // add temporary route to allow import of microservice routes
243
244 routes.push({
245 uri: '/qewd/importRoutes/:destination',
246 method: 'POST',
247 on_microservices: on_microservices,
248 authenticate: false,
249 bypassJWTCheck: true
250 });
251
252 updateRoutes(routes);
253 }
254 return startMode;
255}
256
257function setup(isDocker, service_name, isNative) {
258
259 if (isNative) {
260 process.env.qewd_service_name = service_name;
261 process.env.qewd_isNative = true;
262 if (service_name !== 'orchestrator') {
263 process.env.mode = 'microservice';
264 }
265 }
266
267 var cwd = process.cwd();
268 if (service_name) {
269 if (isNative) {
270 // leave cwd alone
271 }
272 else {
273 cwd = cwd + '/' + service_name;
274 }
275 }
276 var ms_name = process.env.microservice;
277 var mode = process.env.mode;
278 var startupMode = 'normal';
279
280 if (isDocker) {
281 cwd = cwd + '/mapped';
282 installModules(cwd);
283 }
284
285 var config_data;
286 console.log('** loading ' + cwd + '/configuration/config.json');
287 try {
288 config_data = require(cwd + '/configuration/config.json');
289 }
290 catch(err) {
291 config_data = {
292 //orchestrator: {}
293 };
294 }
295
296 /*
297 if (!isDocker && !config_data.orchestrator && config_data.qewd) {
298 config_data.orchestrator = {
299 qewd: config_data.qewd
300 };
301 }
302 */
303
304 var routes;
305 var ms_config;
306 var routes_data;
307 var ms_index = {};
308 var webServerRootPath = process.cwd() + '/www/';
309 var serviceName;
310
311 if (ms_name || mode) {
312 if (ms_name) {
313 webServerRootPath = cwd + '/' + ms_name + '/www/';
314 }
315 // this is running a microservice container
316 if (config_data.microservices) {
317 config_data.microservices.forEach(function(microservice, index) {
318 ms_index[microservice.name] = index;
319 if (microservice.name === ms_name) {
320 ms_config = microservice;
321 }
322 });
323 }
324
325 if (!mode && !ms_config) {
326 console.log('Error: Unable to find configuration details for a microservice named ' + ms_name);
327 return;
328 }
329
330 if (mode) {
331 ms_config = config_data;
332 }
333 if (!ms_config.qewd) {
334 ms_config.qewd = {};
335 }
336
337 if (ms_config.qewd['qewd-monitor'] !== false) {
338 //console.log('1 enabling qewd-monitor');
339 if (ms_name) {
340 linkMonitor(cwd, ms_name);
341 }
342 else {
343 linkMonitor(cwd, '');
344 }
345 }
346 else {
347 unlinkMonitor(cwd, ms_name);
348 }
349
350 }
351 else {
352
353 // not a microservice - either native or docker monolith, or docker orchestrator
354
355 if (config_data.orchestrator) {
356 if (isDocker || service_name) {
357 webServerRootPath = cwd + '/orchestrator/www/';
358 //orchPath = cwd + '/orchestrator';
359 //if (!fs.existsSync(orchPath)) {
360 // fs.mkdirSync(orchPath);
361 //}
362 serviceName = 'orchestrator';
363 }
364 else {
365 webServerRootPath = cwd + '/www/';
366 serviceName = '';
367 }
368 if (config_data.orchestrator['qewd-monitor'] !== false) {
369 //console.log('2 enabling qewd-monitor');
370 linkMonitor(cwd, serviceName);
371 }
372 else {
373 unlinkMonitor(cwd, serviceName);
374 }
375 }
376 else {
377 if (isDocker || service_name) {
378 if (config_data.microservices) {
379 // this is Docker orchestrator
380 webServerRootPath = cwd + '/orchestrator/www/';
381 serviceName = 'orchestrator';
382 //console.log('3 enabling qewd-monitor *');
383 linkMonitor(cwd, serviceName);
384 }
385 else {
386 // Docker monolith
387 webServerRootPath = cwd + '/www/';
388 serviceName = '';
389
390 if (config_data['qewd-monitor'] !== false) {
391 //console.log('4 enabling qewd-monitor');
392 linkMonitor(cwd, serviceName);
393 }
394 else {
395 unlinkMonitor(cwd, serviceName);
396 }
397 }
398 }
399 else {
400 webServerRootPath = cwd + '/www/';
401 serviceName = '';
402 if (!config_data.qewd || (config_data.qewd && config_data.qewd['qewd-monitor'] !== false)) {
403 //console.log('5 enabling qewd-monitor');
404 linkMonitor(cwd, serviceName);
405 }
406 else {
407 unlinkMonitor(cwd, serviceName);
408 }
409 }
410 }
411
412 try {
413 routes_data = require(cwd + '/configuration/routes.json');
414 }
415 catch(err) {
416 routes_data = [];
417 }
418
419 routes = [];
420 var roots = {};
421 }
422
423 var transform = require('qewd-transform-json').transform;
424 var helpers = {
425 getBodyParser(bodyParser) {
426 if (typeof bodyParser !== 'undefined' || bodyParser !== '') {
427 try {
428 return require(bodyParser);
429 }
430 catch(err) {
431 return false;
432 }
433 }
434 else {
435 console.log('No bodyParser specified - use default');
436 return false;
437 }
438 }
439 };
440
441 var default_db = 'gtm';
442 if (isDocker) {
443 default_db = 'dbx';
444 }
445
446 var config_template = {
447 managementPassword: '=> either(qewd.managementPassword, "keepThisSecret!")',
448 serverName: '=> either(qewd.serverName, "QEWD Server")',
449 port: '=> either(qewd.port, 8080)',
450 poolSize: '=> either(qewd.poolSize, 2)',
451 database: {
452 type: '=> either(qewd.database.type, default_db)',
453 params: '=> either(qewd.database.params, "<!delete>")',
454 },
455 webServer: '{<qewd.webServer>}',
456 ssl: '{<qewd.ssl>}',
457 webServerRootPath: webServerRootPath,
458 cors: '=> either(qewd.cors, true)',
459 bodyParser: '=> getBodyParser(qewd.bodyParser)',
460 mode: '=> either(qewd.mode, "production")',
461 max_queue_length: '{<qewd.max_queue_length>}'
462 };
463
464 var config;
465 var addMiddlewarePath;
466
467 if (ms_name) {
468 config = transform(config_template, ms_config, helpers);
469 addMiddlewarePath = cwd + '/' + ms_name + '/addMiddleware.js';
470 }
471 else {
472 if (isDocker || service_name) {
473 if (config_data.orchestrator) {
474 config = transform(config_template, config_data.orchestrator, helpers);
475 }
476 else {
477 config = transform(config_template, config_data, helpers);
478 }
479 if (config_data.microservices) {
480 addMiddlewarePath = cwd + '/orchestrator/addMiddleware.js';
481 }
482 else {
483 addMiddlewarePath = cwd + '/addMiddleware.js';
484 }
485 }
486 else {
487 config = transform(config_template, config_data, helpers);
488 addMiddlewarePath = cwd + '/addMiddleware.js';
489 }
490 }
491 if (fs.existsSync(addMiddlewarePath)) {
492 config.addMiddlewareUp = require(addMiddlewarePath);
493 }
494 config.qewd_up = true;
495 config.permit_application_switch = config_data.permit_application_switch;
496
497 // ** set service name if running orchestrator or microservice standalone
498
499 if (process.env.qewd_service_name) {
500 config.service_name = process.env.qewd_service_name
501 }
502 if (process.env.mode && process.env.microservice) {
503 config.service_name = process.env.microservice;
504 }
505
506 /*
507 console.log('process.env.qewd_service_name = ' + process.env.qewd_service_name);
508 console.log('process.env.mode = ' + process.env.mode);
509 console.log('process.env.microservice = ' + process.env.microservice);
510 console.log('isDocker = ' + isDocker);
511 console.log('service_name = ' + service_name);
512 console.log('ms_name = ' + ms_name);
513 console.log('config_data = ' + JSON.stringify(config_data, null, 2));
514 */
515
516 if (isDocker || service_name) {
517
518 if (ms_name || mode === 'microservice') {
519 // This is a micro-service, not the orchestrator
520
521 if (!mode) createModuleMap(cwd + '/' + ms_name, config);
522
523 var routePath;
524 if (ms_name && !service_name) {
525 routePath = ms_config.name;
526 }
527 else {
528 // standalone MS running in microservice mode
529 // if running integrated microservice natively, use service_name
530 routePath = config_data.ms_name || mode || service_name;
531 }
532
533 routes = [{
534 path: routePath,
535 module: __dirname + '/ms_handlers',
536 errors: {
537 notfound: {
538 text: 'Resource Not Recognised',
539 statusCode: 404
540 }
541 }
542 }];
543
544 try {
545 console.log('loading ' + cwd + '/configuration/routes.json');
546 routes_data = require(cwd + '/configuration/routes.json');
547 }
548 catch(err) {
549 console.log('unable to load ' + cwd + '/configuration/routes.json');
550 routes_data = [];
551 }
552
553 // if this is a standalone microservice running in microservice mode,
554 // AND the imported flag has not yet been set, then add the temporary
555 // route that will accept the request from the orchestrator so the
556 // microservice's routes can be imported into the orchestrator.
557 // Also add the handler API & method for it
558
559 if (mode === 'microservice' && !config_data.imported) {
560
561 startupMode = 'export';
562
563 var importRouteFound = false;
564 routes_data.forEach(function(route) {
565 if (route.uri === '/qewd/importRoutes/:destination') {
566 importRouteFound = true;
567 }
568 });
569
570 if (!importRouteFound) {
571 routes_data.push({
572 uri: '/qewd/importRoutes/:destination',
573 method: 'POST',
574 handler: 'importRoutes',
575 authenticate: false,
576 bypassJWTCheck: true
577 });
578
579 updateRoutes(routes_data);
580 }
581
582 var apiPath = cwd + '/apis';
583 if (!fs.existsSync(apiPath)) {
584 fs.mkdirSync(apiPath);
585 }
586 apiPath = cwd + '/apis/importRoutes';
587 if (!fs.existsSync(apiPath)) {
588 fs.mkdirSync(apiPath);
589 }
590 var cmd = 'cp ' + process.cwd() + '/node_modules/qewd/up/exportRoutesFromMs.js ' + cwd + '/apis/importRoutes/index.js';
591 child_process.execSync(cmd, {stdio:[0,1,2]});
592 cmd = 'cp ' + process.cwd() + '/node_modules/qewd/up/stopMSAfterExport.js ' + cwd + '/apis/importRoutes/onMSResponse.js';
593 child_process.execSync(cmd, {stdio:[0,1,2]});
594
595 }
596
597 // dynamically create connections info from routes if not already defined in the config.json information
598 routes_data.forEach(function(route) {
599 if (route.from_microservices) {
600 route.from_microservices.forEach(function(ms) {
601 if (ms === ms_name) {
602 if (route.on_microservice) {
603 if (!ms_config.connections) {
604 ms_config.connections = [];
605 }
606 ms_config.connections.push(route.on_microservice);
607 }
608 }
609 });
610 }
611 });
612
613 if (ms_config.connections) {
614 config.u_services = {
615 destinations: {}
616 };
617
618 ms_config.connections.forEach(function(ms_name) {
619 var index = ms_index[ms_name];
620 if (typeof index !== 'undefined') {
621 var ms_info = config_data.microservices[index];
622 var host = ms_info.host || ms_info.name; // default to Docker name
623 if (!host.startsWith('http://') && !host.startsWith('https://')) {
624 host = 'http://' + host;
625 }
626 var port = ms_info.port || 8080;
627 if (port !== 80 && port !== 443) {
628 host = host + ':' + port;
629 }
630 config.u_services.destinations[ms_info.name] = {
631 host: host,
632 application: ms_info.name
633 };
634 }
635 });
636
637
638 var ms_routes = [];
639 routes_data.forEach(function(route) {
640 if (route.from_microservices) {
641 route.from_microservices.forEach(function(from_ms) {
642 if (from_ms === ms_name) {
643 ms_routes.push(route);
644 }
645 });
646 }
647 });
648 if (ms_routes.length > 0) {
649 config.u_services.routes = [];
650 ms_routes.forEach(function(route) {
651 config.u_services.routes.push({
652 path: route.uri,
653 method: route.method,
654 destination: route.on_microservice
655 });
656 });
657 }
658 }
659
660 }
661 else {
662 // This is the orchestrator (or Docker monolith)
663
664 // check if microservices need importing, and if so, add import route
665
666 startupMode = addImportRoute(config_data, routes_data)
667
668 // Add module map if necessary
669
670 createModuleMap(cwd, config);
671
672 // Add in microservice definitions if present
673
674 //console.log('config_data.microservices: ' + JSON.stringify(config_data.microservices, null, 2));
675
676 if (config_data.microservices && Array.isArray(config_data.microservices)) {
677 config.u_services = {
678 destinations: {},
679 routes: []
680 };
681 var destinations = config.u_services.destinations;
682 config_data.microservices.forEach(function(microservice) {
683
684 var host;
685 var port;
686
687 if (microservice.members) {
688 // group destination
689 destinations[microservice.name] = {
690 destinations: microservice.members
691 }
692 }
693 else {
694 // physical endpoint destination
695
696 host = microservice.host || microservice.name;
697 if (!host.startsWith('http://') && !host.startsWith('https://')) {
698 host = 'http://' + host;
699 }
700 port = microservice.port || 8080;
701 if (port !== 80 && port !== 443) {
702 host = host + ':' + port;
703 }
704
705 destinations[microservice.name] = {
706 host: host,
707 application: microservice.name
708 };
709 }
710 });
711
712 routes_data.forEach(function(route) {
713 var routeObj;
714 var onOrchResponseFn;
715
716 if (route.on_microservice || route.on_microservices) {
717
718 if (route.from_microservices) {
719 // is this route not sourced by conductor? If so, ignore on conductor
720 var onConductor = false;
721 route.from_microservices.forEach(function(ms_name) {
722 if (ms_name === 'orchestrator') {
723 onConductor = true;
724 }
725 });
726 if (!onConductor) return;
727 }
728
729 routeObj = {
730 path: route.uri,
731 method: route.method,
732 destination: route.on_microservice
733 };
734
735 if (route.authenticate === false) {
736 routeObj.bypassJWTCheck = true;
737 }
738
739 /*
740
741 //var onRequestPath = cwd + '/' + route.on_microservice + '/handlers/' + route.handler + '/onRequest.js';
742 var onRequestPath = cwd + '/' + route.on_microservice + '/' + route.handler + '/onRequest.js';
743 console.log('Checking for onRequest path: ' + onRequestPath);
744 if (fs.existsSync(onRequestPath)) {
745 routeObj.onRequest = require(onRequestPath);
746 console.log('Adding onRequest handler for ' + route.uri + ': ' + onRequestPath);
747 }
748
749 */
750
751 //var onResponsePath = cwd + '/' + route.on_microservice + '/handlers/' + route.handler + '/onResponse.js';
752 if (route.handler) {
753 onOrchResponsePaths = [
754 cwd + '/' + route.on_microservice + '/' + route.handler + '/onOrchResponse.js',
755 cwd + '/' + route.on_microservice + '/apis/' + route.handler + '/onOrchResponse.js',
756 cwd + '/onOrchResponse/' + route.on_microservice + '/' + route.handler + '.js'
757 ];
758 for (var i = 0; i < onOrchResponsePaths.length; i++) {
759 console.log('checking onOrchResponsePath: ' + onOrchResponsePaths[i]);
760 if (fs.existsSync(onOrchResponsePaths[i])) {
761 try {
762 onOrchResponseFn = require(onOrchResponsePaths[i]);
763 console.log('onOrchResponse handler loaded from ' + onOrchResponsePaths[i]);
764 }
765 catch(err) {
766 console.log('** Warning - onOrchResponse handler could not be loaded from ' + onOrchResponsePaths[i]);
767 }
768 break;
769 }
770 }
771 }
772
773 if (onOrchResponseFn) {
774 routeObj.onResponse = function(args) {
775 var _this = this;
776
777 function handleResponse(obj) {
778 if (!obj.message) {
779 obj = {
780 message: obj
781 };
782 }
783 args.handleResponse.call(_this, obj);
784 }
785
786 function forwardToMS(message, callback) {
787 var msgObj = message;
788 if (!msgObj.headers) {
789 msgObj.headers = {};
790 }
791 msgObj.headers.authorization = 'Bearer ' + args.responseObj.message.token;
792 //console.log('sending ' + JSON.stringify(msgObj, null, 2));
793 var status = args.send(msgObj, callback);
794 //console.log('status = ' + status);
795 if (status === false) {
796 callback({error: 'No such route: ' + message.method + ' ' + message.path})
797 }
798 }
799
800 function getJWTProperty(name) {
801 return _this.jwt.handlers.getProperty(name, args.responseObj.message.token);
802 }
803
804 return onOrchResponseFn.call(this, args.responseObj, args.message, forwardToMS, handleResponse, getJWTProperty);
805 };
806 }
807
808 config.u_services.routes.push(routeObj);
809 }
810
811 else if (route.router) {
812 // dynamically-controlled routing to other API
813
814 var onRequestPath = cwd + '/orchestrator/routers/' + route.router + '.js';
815
816 routeObj = {
817 path: route.uri,
818 method: route.method
819 };
820 if (fs.existsSync(onRequestPath)) {
821 routeObj.onRequest = require(onRequestPath);
822 console.log('Adding onRequest handler for ' + route.uri + ': ' + onRequestPath);
823 }
824 config.u_services.routes.push(routeObj);
825 }
826
827 });
828 }
829 else {
830 console.log('*** orchestrator without any microservices ***');
831 }
832
833 }
834
835 if (!config_data.jwt || !config_data.jwt.secret) {
836 config_data.jwt = {
837 secret: uuid()
838 };
839 // write it back to cwd + '/configuration/config.json'
840 fs.writeFileSync(cwd + '/configuration/config.json', JSON.stringify(config_data, null, 2));
841 }
842 config.jwt = Object.assign({}, config_data.jwt); // prevent it being simply by reference
843 }
844 else {
845 // native app
846 createModuleMap(cwd, config);
847 }
848
849 if (!ms_name && !mode) {
850
851 routes_data.forEach(function(route) {
852 if (route.else) return;
853
854 var path_root = '/' + route.uri.split('/')[1];
855 if (!roots[path_root]) {
856
857 var routeObj = {
858 path: path_root,
859 module: __dirname + '/handlers'
860 };
861
862 //var handlerPath = cwd + '/apis';
863 var handlerPath = cwd;
864 //var orchestratorHandlerPath = cwd + '/orchestrator/apis';
865 var orchestratorHandlerPath = cwd + '/orchestrator';
866 if (fs.existsSync(orchestratorHandlerPath)) {
867 handlerPath = orchestratorHandlerPath;
868 }
869 //var beforeRouterPath = handlerPath + path_root + '/beforeRouter.js';
870 var onWSRequestPath = handlerPath + '/onWSRequest.js';
871 console.log('onWSRequestPath: ' + onWSRequestPath);
872 if (fs.existsSync(onWSRequestPath)) {
873 routeObj.beforeRouter = [require(onWSRequestPath)];
874 }
875
876 //var afterRouterPath = handlerPath + path_root + '/afterRouter.js';
877 var onWSResponsePath = handlerPath + '/onWSResponse.js';
878 console.log('onWSResponsePath: ' + onWSResponsePath);
879 if (fs.existsSync(onWSResponsePath)) {
880 routeObj.afterRouter = [require(onWSResponsePath)];
881 }
882
883 routes.push(routeObj);
884 roots[path_root] = true;
885 }
886 });
887 }
888
889 return {
890 routes: routes,
891 config: config,
892 cwd: cwd,
893 startupMode: startupMode
894 };
895}
896
897module.exports = function(isDocker, serviceName, isNative) {
898
899 var results = setup(isDocker, serviceName, isNative);
900
901 console.log('** results = ' + JSON.stringify(results, null, 2));
902
903 if (!results) return;
904 var config = results.config;
905 var routes = results.routes;
906 var startupMode = results.startupMode;
907 var cwd = results.cwd;
908
909 //console.log('routes: ' + JSON.stringify(routes, null, 2));
910
911 var ms_name = process.env.microservice;
912
913 var onStartedPath;
914 var onStartedPath2;
915
916 if (ms_name) {
917 onStartedPath = cwd + '/' + ms_name + '/onStarted.js';
918 }
919 else {
920 onStartedPath = cwd + '/orchestrator/onStarted.js';
921 onStartedPath2 = cwd + '/onStarted.js';
922 }
923
924 if (isDocker) {
925
926 if (startupMode === 'export') {
927 console.log('\n===============================================');
928 console.log(' This QEWD-Up MicroService has started in');
929 console.log(' export mode. When the Orchestrator');
930 console.log(' starts and connects to this MicroService,');
931 console.log(' it will export its routes to the');
932 console.log(' Orchestrator, its JWT secret will be');
933 console.log(' changed to the one used by the Orchestrator');
934 console.log(' and it will then shut down.');
935 console.log(' ');
936 console.log(' You should then restart this MicroService');
937 console.log('===============================================');
938 console.log(' ');
939 }
940
941 if (startupMode === 'import') {
942 console.log('\n===============================================');
943 console.log(' This QEWD-Up Orchestrator has started in');
944 console.log(' import mode. When it connects to each');
945 console.log(' MicroService, it will import its routes.');
946 console.log(' When all MicroService routes are imported');
947 console.log(' the Orchestrator will shut down.');
948 console.log(' ');
949 console.log(' You should then restart the Orchestrator');
950 console.log('===============================================');
951 console.log(' ');
952 }
953
954 var exportObj = {
955 config: config,
956 routes: routes
957 };
958
959 if (fs.existsSync(onStartedPath)) {
960 exportObj.onStarted = require(onStartedPath);
961 }
962 else if (fs.existsSync(onStartedPath2)) {
963 exportObj.onStarted = require(onStartedPath2);
964 }
965 return exportObj;
966 }
967 else {
968
969 if (config.database && config.database.type === 'gtm') {
970
971 try {
972 console.log('Running down YottaDB...');
973 child_process.execSync(process.env.ydb_dist + '/mupip rundown -region DEFAULT', {stdio:[0,1,2]});
974 child_process.execSync(process.env.ydb_dist + '/mupip rundown -region qewdreg', {stdio:[0,1,2]});
975 console.log('Rundown completed');
976 }
977 catch(err) {
978 console.log('Error running down YottaDB: ' + err);
979 console.log('Recovering journal...');
980 try {
981 child_process.execSync(process.env.ydb_dist + '/mupip journal -recover -backward ' + process.env.ydb_dir + '/' + process.env.ydb_rel + '/g/yottadb.mjl', {stdio:[0,1,2]});
982 console.log('Journal recovered');
983 }
984 catch(err) {
985 console.log('YottaDB is probably already in use');
986 }
987 }
988 }
989
990 console.log('config: ' + JSON.stringify(config, null, 2));
991 console.log('routes: ' + JSON.stringify(routes, null, 2));
992
993 var q = qewd.start(config, routes);
994 var xp = qewd.intercept();
995
996 if (fs.existsSync(onStartedPath)) {
997 require(onStartedPath).call(q, config, xp.app, xp.qx.router, xp.qx);
998 }
999 else if (fs.existsSync(onStartedPath2)) {
1000 require(onStartedPath2).call(q, config, xp.app, xp.qx.router, xp.qx);
1001 }
1002 }
1003};