5 * Copyright 2016 RIFT.IO Inc
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * Main skyquake module.
24 * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
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');
35 for (var i
= 0; i
< constants
.SOCKET_POOL_LENGTH
; i
++) {
36 freePorts
[i
] = constants
.SOCKET_BASE_PORT
+ i
;
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
) {
47 port
: freePorts
.shift()
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
);
57 cluster
.on('online', function(worker
) {
58 console
.log("Worker Started pid : " + worker
.process
.pid
);
60 cluster
.on('exit', function(worker
, code
, signal
) {
61 console
.log('worker ' + worker
.process
.pid
+ ' stopped');
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');
83 // SSL related configuration bootstrap
84 var httpServer
= null;
85 var secureHttpServer
= null;
87 var httpsConfigured
= false;
89 var sslOptions
= null;
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;
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
;
103 var devServerAddress
= argv
['dev-server-address'] ? argv
['dev-server-address'] : null;
106 if (argv
['enable-https']) {
107 var keyFilePath
= argv
['keyfile-path'];
108 var certFilePath
= argv
['certfile-path'];
111 key
: fs
.readFileSync(keyFilePath
),
112 cert
: fs
.readFileSync(certFilePath
)
115 httpsConfigured
= true;
118 console
.log('HTTPS enabled but file paths missing/incorrect');
119 process
.exit(code
= -1);
124 app
.set('views', __dirname
+ '/framework/core/views');
125 app
.engine('html', require('ejs').renderFile
);
126 app
.set('view engine', 'ejs');
129 secret
: 'riftio rocks',
131 saveUninitialized
: true
133 // clickjack attach suppression
134 app
.use(lusca
.xframe('SAMEORIGIN')); // for older browsers
135 app
.use(lusca
.csp({ policy
: { 'frame-ancestors': '\'none\'' }}));
137 app
.use(bodyParser
.json());
139 app
.use(bodyParser
.urlencoded({
143 var csrfTarget
= (devServerAddress
? devServerAddress
: launchpadAddress
)
149 CSRFManager
.configure(csrfConfig
);
152 idpServerProtocol
: idpServerProtocol
,
153 idpServerAddress
: launchpadAddress
,
154 idpServerPortNumber
: idpServerPortNumber
,
155 callbackServerProtocol
: callbackServerProtocol
,
156 callbackAddress
: callbackAddress
,
157 callbackPortNumber
: callbackPortNumber
160 var authManager
= new AuthorizationManager(openidConfig
);
166 var socketManager
= new Sockets();
168 httpsConfigured
: httpsConfigured
171 if (httpsConfigured
) {
172 socketConfig
.sslOptions
= sslOptions
;
175 var sessionsConfig
= {
176 authManager
: authManager
,
177 api_server
: apiServer
,
178 api_server_protocol
: apiServerProtocol
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');
203 * Processing when a plugin is added or modified
204 * @param {string} plugin_name - Name of the plugin
206 function onPluginAdded(plugin_name
) {
207 // Load plugin config
208 var plugin_config
= reload('./plugins/' + plugin_name
+ '/config.json');
210 // Load all app's views
211 app
.use('/' + plugin_name
, express
.static('./plugins/' + plugin_name
+ '/' + plugin_config
.root
));
213 // Load all app's routes
214 app
.use('/' + plugin_name
, require('./plugins/' + plugin_name
+ '/routes'));
216 // Publish navigation links
217 if (plugin_config
.routes
&& _
.isArray(plugin_config
.routes
)) {
218 skyquakeEmitter
.emit('config_discoverer.navigation_discovered', plugin_name
, plugin_config
);
226 app
.use('/jquery', express
.static('./node_modules/jquery/dist/jquery.min.js'));
230 app
.use('/img', express
.static('./framework/style/img'));
233 * Start listening on a port
234 * @param {string} port - Port to listen on
235 * @param {object} httpServer - httpServer created with http(s).createServer
237 function startListening(port
, httpServer
) {
238 var server
= httpServer
.listen(port
, function () {
239 var host
= server
.address().address
;
241 var port
= server
.address().port
;
243 console
.log('Express server listening on port', port
);
249 * Initialize skyquake
252 skyquakeEmitter
.on('plugin_discoverer.plugin_discovered', onPluginAdded
);
253 skyquakeEmitter
.on('plugin_discoverer.plugin_updated', onPluginAdded
);
260 // Conigure any globals
261 process
.env
.NODE_TLS_REJECT_UNAUTHORIZED
=0;
263 // Configure auth manager
264 authManager
.configure(authConfig
);
266 // Configure auth router
267 auth_routes
.routes(authManager
);
268 app
.use(auth_routes
.router
);
270 //Configure session route(s)
271 session_routes
.routes(sessionsConfig
);
272 app
.use(session_routes
.router
);
274 // Configure navigation router
275 app
.use(navigation_routes
);
277 // Configure restconf router
278 app
.use(restconf_routes
);
280 //Configure inactivity route(s)
281 app
.use(inactivity_routes
);
283 // Configure global config with ssl enabled/disabled
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
296 globalConfig
.upload_server
= uploadServer
;
298 if (devDownloadServer
) {
299 globalConfig
.dev_download_server
= devDownloadServer
;
302 configurationAPI
.globalConfiguration
.update(globalConfig
);
304 // Configure configuration route(s)
305 app
.use(configuration_routes
);
307 // Configure schema api
308 app
.use(schemaAPI
.getRouter());
310 // Configure model api
311 app
.use(modelAPI
.getRouter());
313 // Configure config api
314 app
.use(appConfigAPI
.getRouter());
316 //Configure descriptor route(s)
317 app
.use(descriptor_routes
);
319 //Configure user management route(s)
320 app
.use(userManagement_routes
);
322 //Configure project management route(s)
323 app
.use(projectManagement_routes
);
325 // app.get('/testme', function(req, res) {
326 // res.sendFile(__dirname + '/index.html');
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
);
338 res
.writeHead(301, { "Location": "https://" + host
+ req
.url
});
342 socketConfig
.httpServer
= secureHttpServer
;
344 httpServer
= http
.createServer(app
);
345 socketConfig
.httpServer
= httpServer
;
348 // Configure socket manager
349 socketManager
.configure(socketConfig
);
351 // Configure socket router
352 socket_routes
.routes(socketManager
);
353 app
.use(socket_routes
.router
);
355 // Serve multiplex-client
356 app
.get('/multiplex-client', function(req
, res
) {
357 res
.sendFile(__dirname
+ '/node_modules/websocket-multiplex/multiplex_client.js');
360 // handle requests for gzip'd files
361 app
.get('*gzip*', function (req
, res
, next
) {
362 res
.set('Content-Encoding', 'gzip');
369 * Run skyquake functionality
373 // Start plugin_discoverer
374 var navigation_manager
= require('./framework/core/modules/navigation_manager');
375 var plugin_discoverer
= require('./framework/core/modules/plugin_discoverer');
377 // Initialize asynchronous modules
378 navigation_manager
.init();
379 plugin_discoverer
.init();
381 // Configure asynchronous modules
382 navigation_manager
.config()
383 plugin_discoverer
.config({
384 plugins_path
: './plugins'
387 // Run asynchronous modules
388 navigation_manager
.run();
389 plugin_discoverer
.run();
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
);
398 // Start listening on SERVER_PORT (8000)
399 var server
= startListening(constants
.SERVER_PORT
, httpServer
);