Merge "Added reset-css node module to fix styling"
[osm/UI.git] / skyquake / skyquake.js
1
2
3 /*
4 *
5 * Copyright 2016 RIFT.IO Inc
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */
20
21 /**
22 * Main skyquake module.
23 * @module skyquake
24 * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
25 */
26
27 // Standard library imports for forking
28 var cluster = require("cluster");
29 var cpu = require('os').cpus().length;
30 var clusteredLaunch = process.env.CLUSTER_SUPPORT || false;
31 var constants = require('./framework/core/api_utils/constants');
32 // Uncomment for Replay support
33 // const Replay = require('replay');
34 var freePorts = [];
35 for (var i = 0; i < constants.SOCKET_POOL_LENGTH; i++) {
36 freePorts[i] = constants.SOCKET_BASE_PORT + i;
37 };
38
39
40 if (cluster.isMaster && clusteredLaunch) {
41 console.log(cpu, 'CPUs found');
42 for (var i = 0; i < cpu; i ++) {
43 var worker = cluster.fork();
44 worker.on('message', function(msg) {
45 if (msg && msg.getPort) {
46 worker.send({
47 port: freePorts.shift()
48 });
49 console.log('freePorts after shift for worker', this.process.pid, ':', freePorts);
50 } else if (msg && msg.freePort) {
51 freePorts.unshift(msg.port);
52 console.log('freePorts after unshift of', msg.port, 'for worker', this.process.pid, ':', freePorts);
53 }
54 });
55 }
56
57 cluster.on('online', function(worker) {
58 console.log("Worker Started pid : " + worker.process.pid);
59 });
60 cluster.on('exit', function(worker, code, signal) {
61 console.log('worker ' + worker.process.pid + ' stopped');
62 });
63 } else {
64 // Standard library imports
65 require('require-json');
66 var argv = require('minimist')(process.argv.slice(2));
67 var pid = process.pid;
68 var fs = require('fs');
69 var https = require('https');
70 var http = require('http');
71 var express = require('express');
72 var session = require('express-session');
73 var cors = require('cors');
74 var lusca = require('lusca');
75 var bodyParser = require('body-parser');
76 var _ = require('lodash');
77 var reload = require('require-reload')(require);
78 var Sockets = require('./framework/core/api_utils/sockets.js');
79 var AuthorizationManager = require('./framework/core/api_utils/auth.js');
80 var utils = require('./framework/core/api_utils/utils.js');
81 var CSRFManager = require('./framework/core/api_utils/csrf.js');
82
83 // SSL related configuration bootstrap
84 var httpServer = null;
85 var secureHttpServer = null;
86
87 var httpsConfigured = false;
88
89 var sslOptions = null;
90
91 var apiServer = argv['api-server'] ? argv['api-server'] : 'localhost';
92 var apiServerProtocol = argv['api-server-protocol'] ? argv['api-server-protocol'] : 'https';
93 var uploadServer = argv['upload-server'] ? argv['upload-server'] : null;
94 var devDownloadServer = argv['dev-download-server'] ? argv['dev-download-server'] : null;
95
96 var launchpadAddress = argv['launchpad-address'] ? argv['launchpad-address'] : constants.LAUNCHPAD_ADDRESS;
97 var idpServerPortNumber = argv['idp-port-number'] ? argv['idp-port-number'] : constants.IDP_PORT_NUMBER;
98 var idpServerProtocol = argv['idp-server-protocol'] ? argv['idp-server-protocol'] : constants.IDP_SERVER_PROTOCOL;
99 var callbackServerProtocol = argv['callback-server-protocol'] ? argv['callback-server-protocol'] : constants.CALLBACK_SERVER_PROTOCOL;
100 var callbackPortNumber = argv['callback-port-number'] ? argv['callback-port-number'] : constants.CALLBACK_PORT_NUMBER;
101 var callbackAddress = argv['callback-address'] ? argv['callback-address'] : constants.CALLBACK_ADDRESS;
102
103 var devServerAddress = argv['dev-server-address'] ? argv['dev-server-address'] : null;
104
105 try {
106 if (argv['enable-https']) {
107 var keyFilePath = argv['keyfile-path'];
108 var certFilePath = argv['certfile-path'];
109
110 sslOptions = {
111 key: fs.readFileSync(keyFilePath),
112 cert: fs.readFileSync(certFilePath)
113 };
114
115 httpsConfigured = true;
116 }
117 } catch (e) {
118 console.log('HTTPS enabled but file paths missing/incorrect');
119 process.exit(code = -1);
120 }
121
122 var app = express();
123
124 app.set('views', __dirname + '/framework/core/views');
125 app.engine('html', require('ejs').renderFile);
126 app.set('view engine', 'ejs');
127
128 app.use(session({
129 secret: 'riftio rocks',
130 resave: false,
131 saveUninitialized: true
132 }));
133 // clickjack attach suppression
134 app.use(lusca.xframe('SAMEORIGIN')); // for older browsers
135 app.use(lusca.csp({ policy: { 'frame-ancestors': '\'none\'' }}));
136
137 app.use(bodyParser.json());
138 app.use(cors());
139 app.use(bodyParser.urlencoded({
140 extended: true
141 }));
142
143 var csrfTarget = (devServerAddress ? devServerAddress : launchpadAddress)
144
145 var csrfConfig = {
146 target: csrfTarget
147 }
148
149 CSRFManager.configure(csrfConfig);
150
151 var openidConfig = {
152 idpServerProtocol: idpServerProtocol,
153 idpServerAddress: launchpadAddress,
154 idpServerPortNumber: idpServerPortNumber,
155 callbackServerProtocol: callbackServerProtocol,
156 callbackAddress: callbackAddress,
157 callbackPortNumber: callbackPortNumber
158 }
159
160 var authManager = new AuthorizationManager(openidConfig);
161 var authConfig = {
162 app: app
163 };
164
165
166 var socketManager = new Sockets();
167 var socketConfig = {
168 httpsConfigured: httpsConfigured
169 };
170
171 if (httpsConfigured) {
172 socketConfig.sslOptions = sslOptions;
173 };
174
175 var sessionsConfig = {
176 authManager: authManager,
177 api_server: apiServer,
178 api_server_protocol: apiServerProtocol
179 }
180
181 // Rift framework imports
182 var constants = require('./framework/core/api_utils/constants');
183 var skyquakeEmitter = require('./framework/core/modules/skyquakeEmitter');
184 var auth_routes = require('./framework/core/modules/routes/auth');
185 var navigation_routes = require('./framework/core/modules/routes/navigation');
186 var socket_routes = require('./framework/core/modules/routes/sockets');
187 var restconf_routes = require('./framework/core/modules/routes/restconf');
188 var inactivity_routes = require('./framework/core/modules/routes/inactivity');
189 var descriptor_routes = require('./framework/core/modules/routes/descriptorModel');
190 var configuration_routes = require('./framework/core/modules/routes/configuration');
191 var configurationAPI = require('./framework/core/modules/api/configuration');
192 var userManagement_routes = require('./framework/core/modules/routes/userManagement');
193 var projectManagement_routes = require('./framework/core/modules/routes/projectManagement');
194 var session_routes = require('./framework/core/modules/routes/sessions');
195 var schemaAPI = require('./framework/core/modules/api/schemaAPI');
196 var modelAPI = require('./framework/core/modules/api/modelAPI');
197 var appConfigAPI = require('./framework/core/modules/api/appConfigAPI');
198
199 schemaAPI.init();
200 modelAPI.init();
201 appConfigAPI.init();
202 /**
203 * Processing when a plugin is added or modified
204 * @param {string} plugin_name - Name of the plugin
205 */
206 function onPluginAdded(plugin_name) {
207 // Load plugin config
208 var plugin_config = reload('./plugins/' + plugin_name + '/config.json');
209
210 // Load all app's views
211 app.use('/' + plugin_name, express.static('./plugins/' + plugin_name + '/' + plugin_config.root));
212
213 // Load all app's routes
214 app.use('/' + plugin_name, require('./plugins/' + plugin_name + '/routes'));
215
216 // Publish navigation links
217 if (plugin_config.routes && _.isArray(plugin_config.routes)) {
218 skyquakeEmitter.emit('config_discoverer.navigation_discovered', plugin_name, plugin_config);
219 }
220
221 }
222
223 /**
224 * Serve jquery
225 */
226 app.use('/jquery', express.static('./node_modules/jquery/dist/jquery.min.js'));
227 /**
228 * Serve images
229 */
230 app.use('/img', express.static('./framework/style/img'));
231
232 /**
233 * Start listening on a port
234 * @param {string} port - Port to listen on
235 * @param {object} httpServer - httpServer created with http(s).createServer
236 */
237 function startListening(port, httpServer) {
238 var server = httpServer.listen(port, function () {
239 var host = server.address().address;
240
241 var port = server.address().port;
242
243 console.log('Express server listening on port', port);
244 });
245 return server;
246 }
247
248 /**
249 * Initialize skyquake
250 */
251 function init() {
252 skyquakeEmitter.on('plugin_discoverer.plugin_discovered', onPluginAdded);
253 skyquakeEmitter.on('plugin_discoverer.plugin_updated', onPluginAdded);
254 }
255
256 /**
257 * Configure skyquake
258 */
259 function config() {
260 // Conigure any globals
261 process.env.NODE_TLS_REJECT_UNAUTHORIZED=0;
262
263 // Configure auth manager
264 authManager.configure(authConfig);
265
266 // Configure auth router
267 auth_routes.routes(authManager);
268 app.use(auth_routes.router);
269
270 //Configure session route(s)
271 session_routes.routes(sessionsConfig);
272 app.use(session_routes.router);
273
274 // Configure navigation router
275 app.use(navigation_routes);
276
277 // Configure restconf router
278 app.use(restconf_routes);
279
280 //Configure inactivity route(s)
281 app.use(inactivity_routes);
282
283 // Configure global config with ssl enabled/disabled
284 var globalConfig = {
285 ssl_enabled: httpsConfigured,
286 api_server: apiServer,
287 api_server_protocol: apiServerProtocol,
288 api_server_port_number: constants.LAUNCHPAD_PORT,
289 idp_server_address: launchpadAddress,
290 idp_server_protocol: idpServerProtocol,
291 idp_server_port_number: idpServerPortNumber,
292 csrf_target: csrfTarget
293 };
294
295 if (uploadServer) {
296 globalConfig.upload_server = uploadServer;
297 }
298 if (devDownloadServer) {
299 globalConfig.dev_download_server = devDownloadServer;
300 }
301
302 configurationAPI.globalConfiguration.update(globalConfig);
303
304 // Configure configuration route(s)
305 app.use(configuration_routes);
306
307 // Configure schema api
308 app.use(schemaAPI.getRouter());
309
310 // Configure model api
311 app.use(modelAPI.getRouter());
312
313 // Configure config api
314 app.use(appConfigAPI.getRouter());
315
316 //Configure descriptor route(s)
317 app.use(descriptor_routes);
318
319 //Configure user management route(s)
320 app.use(userManagement_routes);
321
322 //Configure project management route(s)
323 app.use(projectManagement_routes);
324
325 // app.get('/testme', function(req, res) {
326 // res.sendFile(__dirname + '/index.html');
327 // });
328
329 // Configure HTTP/HTTPS server and populate socketConfig.
330 if (httpsConfigured) {
331 console.log('HTTPS configured. Will create 2 servers');
332 secureHttpServer = https.createServer(sslOptions, app);
333 // Add redirection on SERVER_PORT
334 httpServer = http.createServer(function(req, res) {
335 var host = req.headers['host'];
336 host = host.replace(/:\d+$/, ":" + constants.SECURE_SERVER_PORT);
337
338 res.writeHead(301, { "Location": "https://" + host + req.url });
339 res.end();
340 });
341
342 socketConfig.httpServer = secureHttpServer;
343 } else {
344 httpServer = http.createServer(app);
345 socketConfig.httpServer = httpServer;
346 }
347
348 // Configure socket manager
349 socketManager.configure(socketConfig);
350
351 // Configure socket router
352 socket_routes.routes(socketManager);
353 app.use(socket_routes.router);
354
355 // Serve multiplex-client
356 app.get('/multiplex-client', function(req, res) {
357 res.sendFile(__dirname + '/node_modules/websocket-multiplex/multiplex_client.js');
358 });
359
360 // handle requests for gzip'd files
361 app.get('*gzip*', function (req, res, next) {
362 res.set('Content-Encoding', 'gzip');
363 next();
364 });
365
366 }
367
368 /**
369 * Run skyquake functionality
370 */
371 function run() {
372
373 // Start plugin_discoverer
374 var navigation_manager = require('./framework/core/modules/navigation_manager');
375 var plugin_discoverer = require('./framework/core/modules/plugin_discoverer');
376
377 // Initialize asynchronous modules
378 navigation_manager.init();
379 plugin_discoverer.init();
380
381 // Configure asynchronous modules
382 navigation_manager.config()
383 plugin_discoverer.config({
384 plugins_path: './plugins'
385 });
386
387 // Run asynchronous modules
388 navigation_manager.run();
389 plugin_discoverer.run();
390
391
392 // Server start
393 if (httpsConfigured) {
394 console.log('HTTPS configured. Will start 2 servers');
395 // Start listening on SECURE_SERVER_PORT (8443)
396 var secureServer = startListening(constants.SECURE_SERVER_PORT, secureHttpServer);
397 }
398 // Start listening on SERVER_PORT (8000)
399 var server = startListening(constants.SERVER_PORT, httpServer);
400
401 }
402
403 init();
404
405 config();
406
407 run();
408 }