UNPKG

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