You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by an...@apache.org on 2017/11/17 06:28:46 UTC

ignite git commit: IGNITE-6920 Added direct-install build for Web Console.

Repository: ignite
Updated Branches:
  refs/heads/master caad1e912 -> 69eced659


IGNITE-6920 Added direct-install build for Web Console.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/69eced65
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/69eced65
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/69eced65

Branch: refs/heads/master
Commit: 69eced65909f7ab72197e5a256c1ccde68167e7a
Parents: caad1e9
Author: Andrey Novikov <an...@gridgain.com>
Authored: Fri Nov 17 13:28:14 2017 +0700
Committer: Andrey Novikov <an...@gridgain.com>
Committed: Fri Nov 17 13:28:14 2017 +0700

----------------------------------------------------------------------
 modules/web-console/.gitignore                  |  11 +-
 modules/web-console/DEVNOTES.txt                |  13 +-
 modules/web-console/backend/.gitignore          |   6 -
 modules/web-console/backend/app/apiServer.js    |  76 ++--
 .../web-console/backend/app/browsersHandler.js  | 442 +++++++++----------
 modules/web-console/backend/app/mongo.js        |  73 ++-
 modules/web-console/backend/app/nconf.js        |  44 +-
 modules/web-console/backend/app/routes.js       |  26 +-
 modules/web-console/backend/app/settings.js     |  84 ++--
 modules/web-console/backend/index.js            |  25 +-
 modules/web-console/backend/injector.js         |   4 +-
 modules/web-console/backend/package.json        |  22 +-
 .../compose/frontend/nginx/web-console.conf     |   1 -
 .../docker/standalone/nginx/web-console.conf    |   1 -
 modules/web-console/frontend/.gitignore         |   8 +-
 .../generator/JavaTransformer.service.js        |   2 +
 .../frontend/webpack/webpack.dev.babel.js       |   5 +-
 17 files changed, 466 insertions(+), 377 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-console/.gitignore b/modules/web-console/.gitignore
index 9ddddc4..8648ae5 100644
--- a/modules/web-console/.gitignore
+++ b/modules/web-console/.gitignore
@@ -1,6 +1,5 @@
-docker/standalone/backend/build
-docker/standalone/frontend/build
-docker/standalone/data
-docker/compose/backend/build
-docker/compose/frontend/build
-docker/dev/data
+.npmrc
+package-lock.json
+build/
+node_modules/
+data/

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/DEVNOTES.txt
----------------------------------------------------------------------
diff --git a/modules/web-console/DEVNOTES.txt b/modules/web-console/DEVNOTES.txt
index aa8702e..4ff68a7 100644
--- a/modules/web-console/DEVNOTES.txt
+++ b/modules/web-console/DEVNOTES.txt
@@ -1,8 +1,5 @@
-Ignite Web Console Instructions
-======================================
-
-How to deploy locally:
-
+Ignite Web Console Build Instructions
+=====================================
 1. Install locally MongoDB (version >=3.2.x) follow instructions from site http://docs.mongodb.org/manual/installation.
 2. Install locally NodeJS (version >=6.5.x) using installer from site https://nodejs.org/en/download/current for your OS.
 3. Change directory to '$IGNITE_HOME/modules/web-console/backend' and
@@ -13,10 +10,10 @@ How to deploy locally:
 6. Copy ignite-web-agent-<version>.zip from '$IGNITE_HOME/modules/web-console/web-agent/target'
  to '$IGNITE_HOME/modules/web-console/backend/agent_dists' folder.
 
-Steps 1 - 6 should be executed once.
-
-How to run console in development mode:
+Steps 1 - 4 should be executed once.
 
+Ignite Web Console Run In Development Mode
+==========================================
 1. Configure MongoDB to run as service or in terminal change dir to $MONGO_INSTALL_DIR/server/3.2/bin
   and start MongoDB by executing "mongod".
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/backend/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/.gitignore b/modules/web-console/backend/.gitignore
index 0aa3ece..e5b9047 100644
--- a/modules/web-console/backend/.gitignore
+++ b/modules/web-console/backend/.gitignore
@@ -1,8 +1,2 @@
-*.idea
-*.log
-.npmrc
-node_modules
 agent_dists/*.zip
 config/*.json
-yarn.lock
-package-lock.json

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/backend/app/apiServer.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/apiServer.js b/modules/web-console/backend/app/apiServer.js
index affb9c9..cb09750 100644
--- a/modules/web-console/backend/app/apiServer.js
+++ b/modules/web-console/backend/app/apiServer.js
@@ -21,48 +21,64 @@
 
 module.exports = {
     implements: 'api-server',
-    inject: ['require(express)', 'configure', 'routes']
-};
-
-module.exports.factory = function(Express, configure, routes) {
-    /**
-     * Connected agents manager.
-     */
-    class ApiServer {
+    inject: ['require(fs)', 'require(path)', 'require(express)', 'settings', 'configure', 'routes'],
+    factory(fs, path, Express, settings, configure, routes) {
         /**
-         * @param {Server} srv
+         * Connected agents manager.
          */
-        attach(srv) {
-            const app = new Express();
+        class ApiServer {
+            /**
+             * @param {Server} srv
+             */
+            attach(srv) {
+                const app = new Express();
+
+                configure.express(app);
 
-            configure.express(app);
+                routes.register(app);
 
-            routes.register(app);
+                if (settings.packaged) {
+                    const staticDir = path.join(process.cwd(), 'libs/frontend');
 
-            // Catch 404 and forward to error handler.
-            app.use((req, res, next) => {
-                const err = new Error('Not Found: ' + req.originalUrl);
+                    try {
+                        fs.accessSync(staticDir, fs.F_OK);
 
-                err.status = 404;
+                        app.use('/', Express.static(staticDir));
 
-                next(err);
-            });
+                        app.get('*', function(req, res) {
+                            res.sendFile(path.join(staticDir, 'index.html'));
+                        });
+                    }
+                    catch (e) {
+                        console.log(`Failed to find folder with frontend files: ${staticDir}`);
+                    }
+                }
 
-            // Production error handler: no stacktraces leaked to user.
-            app.use((err, req, res) => {
-                res.status(err.status || 500);
+                // Catch 404 and forward to error handler.
+                app.use((req, res, next) => {
+                    const err = new Error('Not Found: ' + req.originalUrl);
 
-                res.render('error', {
-                    message: err.message,
-                    error: {}
+                    err.status = 404;
+
+                    next(err);
                 });
-            });
 
-            srv.addListener('request', app);
+                // Production error handler: no stacktraces leaked to user.
+                app.use((err, req, res) => {
+                    res.status(err.status || 500);
 
-            return app;
+                    res.render('error', {
+                        message: err.message,
+                        error: {}
+                    });
+                });
+
+                srv.addListener('request', app);
+
+                return app;
+            }
         }
-    }
 
-    return new ApiServer();
+        return new ApiServer();
+    }
 };

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/backend/app/browsersHandler.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/browsersHandler.js b/modules/web-console/backend/app/browsersHandler.js
index f4ff23c..8b1385d 100644
--- a/modules/web-console/backend/app/browsersHandler.js
+++ b/modules/web-console/backend/app/browsersHandler.js
@@ -24,291 +24,289 @@
  */
 module.exports = {
     implements: 'browsers-handler',
-    inject: ['require(lodash)', 'require(socket.io)', 'configure', 'errors', 'mongo']
-};
+    inject: ['require(lodash)', 'require(socket.io)', 'configure', 'errors', 'mongo'],
+    factory: (_, socketio, configure, errors, mongo) => {
+        class BrowserSockets {
+            constructor() {
+                this.sockets = new Map();
+            }
 
-module.exports.factory = (_, socketio, configure, errors, mongo) => {
-    class BrowserSockets {
-        constructor() {
-            this.sockets = new Map();
-        }
+            /**
+             * @param {Socket} sock
+             */
+            add(sock) {
+                const token = sock.request.user.token;
 
-        /**
-         * @param {Socket} sock
-         */
-        add(sock) {
-            const token = sock.request.user.token;
+                if (this.sockets.has(token))
+                    this.sockets.get(token).push(sock);
+                else
+                    this.sockets.set(token, [sock]);
 
-            if (this.sockets.has(token))
-                this.sockets.get(token).push(sock);
-            else
-                this.sockets.set(token, [sock]);
+                return this.sockets.get(token);
+            }
 
-            return this.sockets.get(token);
-        }
+            /**
+             * @param {Socket} sock
+             */
+            remove(sock) {
+                const token = sock.request.user.token;
 
-        /**
-         * @param {Socket} sock
-         */
-        remove(sock) {
-            const token = sock.request.user.token;
+                const sockets = this.sockets.get(token);
 
-            const sockets = this.sockets.get(token);
+                _.pull(sockets, sock);
 
-            _.pull(sockets, sock);
+                return sockets;
+            }
 
-            return sockets;
-        }
+            get(token) {
+                if (this.sockets.has(token))
+                    return this.sockets.get(token);
 
-        get(token) {
-            if (this.sockets.has(token))
-                return this.sockets.get(token);
+                return [];
+            }
 
-            return [];
+            demo(token) {
+                return _.filter(this.sockets.get(token), (sock) => sock.request._query.IgniteDemoMode === 'true');
+            }
         }
 
-        demo(token) {
-            return _.filter(this.sockets.get(token), (sock) => sock.request._query.IgniteDemoMode === 'true');
-        }
-    }
+        class BrowsersHandler {
+            /**
+             * @constructor
+             */
+            constructor() {
+                /**
+                 * Connected browsers.
+                 * @type {BrowserSockets}
+                 */
+                this._browserSockets = new BrowserSockets();
+
+                /**
+                 * Registered Visor task.
+                 * @type {Map}
+                 */
+                this._visorTasks = new Map();
+            }
 
-    class BrowsersHandler {
-        /**
-         * @constructor
-         */
-        constructor() {
             /**
-             * Connected browsers.
-             * @type {BrowserSockets}
+             * @param {Error} err
+             * @return {{code: number, message: *}}
              */
-            this._browserSockets = new BrowserSockets();
+            errorTransformer(err) {
+                return {
+                    code: err.code || 1,
+                    message: err.message || err
+                };
+            }
 
             /**
-             * Registered Visor task.
-             * @type {Map}
+             * @param {String} token
+             * @param {Array.<Socket>} [socks]
              */
-            this._visorTasks = new Map();
-        }
+            agentStats(token, socks = this._browserSockets.get(token)) {
+                return this._agentHnd.agents(token)
+                    .then((agentSocks) => {
+                        const stat = _.reduce(agentSocks, (acc, agentSock) => {
+                            acc.count += 1;
+                            acc.hasDemo |= _.get(agentSock, 'demo.enabled');
 
-        /**
-         * @param {Error} err
-         * @return {{code: number, message: *}}
-         */
-        errorTransformer(err) {
-            return {
-                code: err.code || 1,
-                message: err.message || err
-            };
-        }
+                            if (agentSock.cluster)
+                                acc.clusters.push(agentSock.cluster);
 
-        /**
-         * @param {String} token
-         * @param {Array.<Socket>} [socks]
-         */
-        agentStats(token, socks = this._browserSockets.get(token)) {
-            return this._agentHnd.agents(token)
-                .then((agentSocks) => {
-                    const stat = _.reduce(agentSocks, (acc, agentSock) => {
-                        acc.count += 1;
-                        acc.hasDemo |= _.get(agentSock, 'demo.enabled');
-
-                        if (agentSock.cluster)
-                            acc.clusters.push(agentSock.cluster);
-
-                        return acc;
-                    }, {count: 0, hasDemo: false, clusters: []});
-
-                    stat.clusters = _.uniqWith(stat.clusters, _.isEqual);
-
-                    return stat;
-                })
-                .catch(() => ({count: 0, hasDemo: false, clusters: []}))
-                .then((stat) => _.forEach(socks, (sock) => sock.emit('agents:stat', stat)));
-        }
+                            return acc;
+                        }, {count: 0, hasDemo: false, clusters: []});
 
-        emitNotification(sock) {
-            sock.emit('user:notifications', this.notification);
-        }
+                        stat.clusters = _.uniqWith(stat.clusters, _.isEqual);
 
-        /**
-         * @param {String} notification Notification message.
-         */
-        updateNotification(notification) {
-            this.notification = notification;
+                        return stat;
+                    })
+                    .catch(() => ({count: 0, hasDemo: false, clusters: []}))
+                    .then((stat) => _.forEach(socks, (sock) => sock.emit('agents:stat', stat)));
+            }
 
-            for (const socks of this._browserSockets.sockets.values()) {
-                for (const sock of socks)
-                    this.emitNotification(sock);
+            emitNotification(sock) {
+                sock.emit('user:notifications', this.notification);
             }
-        }
 
-        executeOnAgent(token, demo, event, ...args) {
-            const cb = _.last(args);
+            /**
+             * @param {String} notification Notification message.
+             */
+            updateNotification(notification) {
+                this.notification = notification;
 
-            return this._agentHnd.agent(token, demo)
-                .then((agentSock) => agentSock.emitEvent(event, ..._.dropRight(args)))
-                .then((res) => cb(null, res))
-                .catch((err) => cb(this.errorTransformer(err)));
-        }
+                for (const socks of this._browserSockets.sockets.values()) {
+                    for (const sock of socks)
+                        this.emitNotification(sock);
+                }
+            }
 
-        agentListeners(sock) {
-            const demo = sock.request._query.IgniteDemoMode === 'true';
-            const token = () => sock.request.user.token;
+            executeOnAgent(token, demo, event, ...args) {
+                const cb = _.last(args);
 
-            // Return available drivers to browser.
-            sock.on('schemaImport:drivers', (...args) => {
-                this.executeOnAgent(token(), demo, 'schemaImport:drivers', ...args);
-            });
+                return this._agentHnd.agent(token, demo)
+                    .then((agentSock) => agentSock.emitEvent(event, ..._.dropRight(args)))
+                    .then((res) => cb(null, res))
+                    .catch((err) => cb(this.errorTransformer(err)));
+            }
 
-            // Return schemas from database to browser.
-            sock.on('schemaImport:schemas', (...args) => {
-                this.executeOnAgent(token(), demo, 'schemaImport:schemas', ...args);
-            });
+            agentListeners(sock) {
+                const demo = sock.request._query.IgniteDemoMode === 'true';
+                const token = () => sock.request.user.token;
 
-            // Return tables from database to browser.
-            sock.on('schemaImport:metadata', (...args) => {
-                this.executeOnAgent(token(), demo, 'schemaImport:metadata', ...args);
-            });
-        }
+                // Return available drivers to browser.
+                sock.on('schemaImport:drivers', (...args) => {
+                    this.executeOnAgent(token(), demo, 'schemaImport:drivers', ...args);
+                });
 
-        /**
-         * @param {Promise.<AgentSocket>} agent
-         * @param {Boolean} demo
-         * @param {Object.<String, String>} params
-         * @return {Promise.<T>}
-         */
-        executeOnNode(agent, demo, params) {
-            return agent
-                .then((agentSock) => agentSock.emitEvent('node:rest', {uri: 'ignite', demo, params}))
-                .then((res) => {
-                    if (res.status === 0) {
-                        if (res.zipped)
-                            return res;
-
-                        return JSON.parse(res.data);
-                    }
-
-                    throw new Error(res.error);
+                // Return schemas from database to browser.
+                sock.on('schemaImport:schemas', (...args) => {
+                    this.executeOnAgent(token(), demo, 'schemaImport:schemas', ...args);
                 });
-        }
 
-        registerVisorTask(taskId, taskCls, ...argCls) {
-            this._visorTasks.set(taskId, {
-                taskCls,
-                argCls
-            });
-        }
+                // Return tables from database to browser.
+                sock.on('schemaImport:metadata', (...args) => {
+                    this.executeOnAgent(token(), demo, 'schemaImport:metadata', ...args);
+                });
+            }
 
-        nodeListeners(sock) {
-            // Return command result from grid to browser.
-            sock.on('node:rest', (clusterId, params, cb) => {
-                const demo = sock.request._query.IgniteDemoMode === 'true';
-                const token = sock.request.user.token;
+            /**
+             * @param {Promise.<AgentSocket>} agent
+             * @param {Boolean} demo
+             * @param {Object.<String, String>} params
+             * @return {Promise.<T>}
+             */
+            executeOnNode(agent, demo, params) {
+                return agent.then((agentSock) => agentSock.emitEvent('node:rest', {uri: 'ignite', demo, params}))
+                    .then((res) => {
+                        if (res.status === 0) {
+                            if (res.zipped)
+                                return res;
 
-                const agent = this._agentHnd.agent(token, demo, clusterId);
+                            return JSON.parse(res.data);
+                        }
 
-                this.executeOnNode(agent, demo, params)
-                    .then((data) => cb(null, data))
-                    .catch((err) => cb(this.errorTransformer(err)));
-            });
+                        throw new Error(res.error);
+                    });
+            }
 
-            const internalVisor = (postfix) => `org.apache.ignite.internal.visor.${postfix}`;
+            registerVisorTask(taskId, taskCls, ...argCls) {
+                this._visorTasks.set(taskId, {
+                    taskCls,
+                    argCls
+                });
+            }
 
-            this.registerVisorTask('querySql', internalVisor('query.VisorQueryTask'), internalVisor('query.VisorQueryArg'));
-            this.registerVisorTask('querySqlV2', internalVisor('query.VisorQueryTask'), internalVisor('query.VisorQueryArgV2'));
-            this.registerVisorTask('querySqlV3', internalVisor('query.VisorQueryTask'), internalVisor('query.VisorQueryArgV3'));
-            this.registerVisorTask('querySqlX2', internalVisor('query.VisorQueryTask'), internalVisor('query.VisorQueryTaskArg'));
+            nodeListeners(sock) {
+                // Return command result from grid to browser.
+                sock.on('node:rest', (clusterId, params, cb) => {
+                    const demo = sock.request._query.IgniteDemoMode === 'true';
+                    const token = sock.request.user.token;
 
-            this.registerVisorTask('queryScanX2', internalVisor('query.VisorScanQueryTask'), internalVisor('query.VisorScanQueryTaskArg'));
+                    const agent = this._agentHnd.agent(token, demo, clusterId);
 
-            this.registerVisorTask('queryFetch', internalVisor('query.VisorQueryNextPageTask'), 'org.apache.ignite.lang.IgniteBiTuple', 'java.lang.String', 'java.lang.Integer');
-            this.registerVisorTask('queryFetchX2', internalVisor('query.VisorQueryNextPageTask'), internalVisor('query.VisorQueryNextPageTaskArg'));
+                    this.executeOnNode(agent, demo, params)
+                        .then((data) => cb(null, data))
+                        .catch((err) => cb(this.errorTransformer(err)));
+                });
 
-            this.registerVisorTask('queryClose', internalVisor('query.VisorQueryCleanupTask'), 'java.util.Map', 'java.util.UUID', 'java.util.Set');
-            this.registerVisorTask('queryCloseX2', internalVisor('query.VisorQueryCleanupTask'), internalVisor('query.VisorQueryCleanupTaskArg'));
+                const internalVisor = (postfix) => `org.apache.ignite.internal.visor.${postfix}`;
 
+                this.registerVisorTask('querySql', internalVisor('query.VisorQueryTask'), internalVisor('query.VisorQueryArg'));
+                this.registerVisorTask('querySqlV2', internalVisor('query.VisorQueryTask'), internalVisor('query.VisorQueryArgV2'));
+                this.registerVisorTask('querySqlV3', internalVisor('query.VisorQueryTask'), internalVisor('query.VisorQueryArgV3'));
+                this.registerVisorTask('querySqlX2', internalVisor('query.VisorQueryTask'), internalVisor('query.VisorQueryTaskArg'));
 
-            // Return command result from grid to browser.
-            sock.on('node:visor', (clusterId, taskId, nids, ...args) => {
-                const demo = sock.request._query.IgniteDemoMode === 'true';
-                const token = sock.request.user.token;
+                this.registerVisorTask('queryScanX2', internalVisor('query.VisorScanQueryTask'), internalVisor('query.VisorScanQueryTaskArg'));
 
-                const cb = _.last(args);
-                args = _.dropRight(args);
+                this.registerVisorTask('queryFetch', internalVisor('query.VisorQueryNextPageTask'), 'org.apache.ignite.lang.IgniteBiTuple', 'java.lang.String', 'java.lang.Integer');
+                this.registerVisorTask('queryFetchX2', internalVisor('query.VisorQueryNextPageTask'), internalVisor('query.VisorQueryNextPageTaskArg'));
 
-                const desc = this._visorTasks.get(taskId);
+                this.registerVisorTask('queryClose', internalVisor('query.VisorQueryCleanupTask'), 'java.util.Map', 'java.util.UUID', 'java.util.Set');
+                this.registerVisorTask('queryCloseX2', internalVisor('query.VisorQueryCleanupTask'), internalVisor('query.VisorQueryCleanupTaskArg'));
 
-                if (_.isNil(desc))
-                    return cb(this.errorTransformer(new errors.IllegalArgumentException(`Failed to find Visor task for id: ${taskId}`)));
 
-                const params = {
-                    cmd: 'exe',
-                    name: 'org.apache.ignite.internal.visor.compute.VisorGatewayTask',
-                    p1: nids,
-                    p2: desc.taskCls
-                };
+                // Return command result from grid to browser.
+                sock.on('node:visor', (clusterId, taskId, nids, ...args) => {
+                    const demo = sock.request._query.IgniteDemoMode === 'true';
+                    const token = sock.request.user.token;
 
-                _.forEach(_.concat(desc.argCls, args), (param, idx) => { params[`p${idx + 3}`] = param; });
+                    const cb = _.last(args);
+                    args = _.dropRight(args);
 
-                const agent = this._agentHnd.agent(token, demo, clusterId);
+                    const desc = this._visorTasks.get(taskId);
 
-                this.executeOnNode(agent, demo, params)
-                    .then((data) => {
-                        if (data.zipped)
-                            return cb(null, data);
+                    if (_.isNil(desc))
+                        return cb(this.errorTransformer(new errors.IllegalArgumentException(`Failed to find Visor task for id: ${taskId}`)));
 
-                        if (data.finished)
-                            return cb(null, data.result);
+                    const params = {
+                        cmd: 'exe',
+                        name: 'org.apache.ignite.internal.visor.compute.VisorGatewayTask',
+                        p1: nids,
+                        p2: desc.taskCls
+                    };
 
-                        cb(this.errorTransformer(data.error));
-                    })
-                    .catch((err) => cb(this.errorTransformer(err)));
-            });
-        }
+                    _.forEach(_.concat(desc.argCls, args), (param, idx) => { params[`p${idx + 3}`] = param; });
 
-        /**
-         *
-         * @param server
-         * @param {AgentsHandler} agentHnd
-         */
-        attach(server, agentHnd) {
-            this._agentHnd = agentHnd;
+                    const agent = this._agentHnd.agent(token, demo, clusterId);
 
-            if (this.io)
-                throw 'Browser server already started!';
+                    this.executeOnNode(agent, demo, params)
+                        .then((data) => {
+                            if (data.zipped)
+                                return cb(null, data);
 
-            mongo.Notifications.findOne().sort('-date').exec()
-                .then((notification) => {
-                    this.notification = notification;
-                })
-                .then(() => {
-                    const io = socketio(server);
+                            if (data.finished)
+                                return cb(null, data.result);
 
-                    configure.socketio(io);
+                            cb(this.errorTransformer(data.error));
+                        })
+                        .catch((err) => cb(this.errorTransformer(err)));
+                });
+            }
 
-                    // Handle browser connect event.
-                    io.sockets.on('connection', (sock) => {
-                        this._browserSockets.add(sock);
+            /**
+             *
+             * @param server
+             * @param {AgentsHandler} agentHnd
+             */
+            attach(server, agentHnd) {
+                this._agentHnd = agentHnd;
 
-                        // Handle browser disconnect event.
-                        sock.on('disconnect', () => {
-                            this._browserSockets.remove(sock);
+                if (this.io)
+                    throw 'Browser server already started!';
 
-                            const demo = sock.request._query.IgniteDemoMode === 'true';
+                mongo.Notifications.findOne().sort('-date').exec()
+                    .then((notification) => {
+                        this.notification = notification;
+                    })
+                    .then(() => {
+                        const io = socketio(server);
 
-                            // Stop demo if latest demo tab for this token.
-                            demo && agentHnd.tryStopDemo(sock);
-                        });
+                        configure.socketio(io);
 
-                        this.agentListeners(sock);
-                        this.nodeListeners(sock);
+                        // Handle browser connect event.
+                        io.sockets.on('connection', (sock) => {
+                            this._browserSockets.add(sock);
 
-                        this.agentStats(sock.request.user.token, [sock]);
-                        this.emitNotification(sock);
+                            // Handle browser disconnect event.
+                            sock.on('disconnect', () => {
+                                this._browserSockets.remove(sock);
+
+                                const demo = sock.request._query.IgniteDemoMode === 'true';
+
+                                // Stop demo if latest demo tab for this token.
+                                demo && agentHnd.tryStopDemo(sock);
+                            });
+
+                            this.agentListeners(sock);
+                            this.nodeListeners(sock);
+
+                            this.agentStats(sock.request.user.token, [sock]);
+                            this.emitNotification(sock);
+                        });
                     });
-                });
+            }
         }
-    }
 
-    return new BrowsersHandler();
+        return new BrowsersHandler();
+    }
 };

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/backend/app/mongo.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/mongo.js b/modules/web-console/backend/app/mongo.js
index 7043fcd..81076af 100644
--- a/modules/web-console/backend/app/mongo.js
+++ b/modules/web-console/backend/app/mongo.js
@@ -24,16 +24,10 @@
  */
 module.exports = {
     implements: 'mongo',
-    inject: ['require(passport-local-mongoose)', 'settings', 'ignite_modules/mongo:*', 'mongoose']
+    inject: ['require(passport-local-mongoose)', 'settings', 'mongoose']
 };
 
-module.exports.factory = function(passportMongo, settings, pluginMongo, mongoose) {
-    // Use native promises
-    mongoose.Promise = global.Promise;
-
-    // Connect to mongoDB database.
-    mongoose.connect(settings.mongoUrl, {server: {poolSize: 4}});
-
+const defineSchema = (passportMongo, mongoose) => {
     const Schema = mongoose.Schema;
     const ObjectId = mongoose.Schema.Types.ObjectId;
     const result = { connection: mongoose.connection };
@@ -1147,12 +1141,6 @@ module.exports.factory = function(passportMongo, settings, pluginMongo, mongoose
     // Define Notifications model.
     result.Notifications = mongoose.model('Notifications', NotificationsSchema);
 
-    // Registering the routes of all plugin modules
-    for (const name in pluginMongo) {
-        if (pluginMongo.hasOwnProperty(name))
-            pluginMongo[name].register(mongoose, result);
-    }
-
     result.handleError = function(res, err) {
         // TODO IGNITE-843 Send error to admin
         res.status(err.code || 500).send(err.message);
@@ -1160,3 +1148,60 @@ module.exports.factory = function(passportMongo, settings, pluginMongo, mongoose
 
     return result;
 };
+
+module.exports.factory = function(passportMongo, settings, mongoose) {
+    // Use native promises
+    mongoose.Promise = global.Promise;
+
+    console.log('Trying to connect to local MongoDB...');
+
+    // Connect to mongoDB database.
+    return mongoose.connect(settings.mongoUrl, {server: {poolSize: 4}})
+        .catch(() => {
+            console.log('Failed to connect to local MongoDB, will try to download and start embedded MongoDB');
+
+            const {MongodHelper} = require('mongodb-prebuilt');
+            const {MongoDBDownload} = require('mongodb-download');
+
+            const helper = new MongodHelper(['--port', '27017', '--dbpath', `${process.cwd()}/user_data`]);
+
+            helper.mongoBin.mongoDBPrebuilt.mongoDBDownload = new MongoDBDownload({
+                downloadDir: `${process.cwd()}/libs/mongodb`,
+                version: '3.4.7'
+            });
+
+            let mongodRun;
+
+            if (settings.packaged) {
+                mongodRun = new Promise((resolve, reject) => {
+                    helper.resolveLink = resolve;
+                    helper.rejectLink = reject;
+
+                    helper.mongoBin.runCommand()
+                        .then(() => {
+                            helper.mongoBin.childProcess.removeAllListeners('close');
+
+                            helper.mongoBin.childProcess.stderr.on('data', (data) => helper.stderrHandler(data));
+                            helper.mongoBin.childProcess.stdout.on('data', (data) => helper.stdoutHandler(data));
+                            helper.mongoBin.childProcess.on('close', (code) => helper.closeHandler(code));
+                        });
+                });
+            }
+            else
+                mongodRun = helper.run();
+
+            return mongodRun
+                .catch((err) => console.log('Failed to start embedded MongoDB', err))
+                .then(() => {
+                    console.log('Embedded MongoDB successfully started');
+
+                    return mongoose.connect(settings.mongoUrl, {server: {poolSize: 4}});
+                })
+                .catch((err) => {
+                    console.log('Failed to connect to embedded MongoDB', err);
+
+                    return Promise.reject(err);
+                });
+        })
+        .then(() => defineSchema(passportMongo, mongoose));
+};

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/backend/app/nconf.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/nconf.js b/modules/web-console/backend/app/nconf.js
index c585ac6..6813f0f 100644
--- a/modules/web-console/backend/app/nconf.js
+++ b/modules/web-console/backend/app/nconf.js
@@ -24,25 +24,29 @@
  */
 module.exports = {
     implements: 'nconf',
-    inject: ['require(nconf)', 'require(fs)']
-};
-
-module.exports.factory = function(nconf, fs) {
-    const default_config = './config/settings.json';
-    const file = process.env.SETTINGS || default_config;
-
-    nconf.env({separator: '_'});
-
-    try {
-        fs.accessSync(file, fs.F_OK);
-
-        nconf.file({file});
-    } catch (ignore) {
-        nconf.file({file: default_config});
+    inject: ['require(nconf)', 'require(fs)'],
+    factory(nconf, fs) {
+        nconf.env({separator: '_'}).argv();
+
+        const dfltFile = 'config/settings.json';
+        const customFile = nconf.get('settings') || dfltFile;
+
+        try {
+            fs.accessSync(customFile, fs.F_OK);
+
+            nconf.file({file: customFile});
+        }
+        catch (ignored) {
+            try {
+                fs.accessSync(dfltFile, fs.F_OK);
+
+                nconf.file({file: dfltFile});
+            }
+            catch (ignored2) {
+                // No-op.
+            }
+        }
+
+        return nconf;
     }
-
-    if (process.env.CONFIG_PATH && fs.existsSync(process.env.CONFIG_PATH))
-        nconf.file({file: process.env.CONFIG_PATH});
-
-    return nconf;
 };

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/backend/app/routes.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/routes.js b/modules/web-console/backend/app/routes.js
index 826407b..aa6efae 100644
--- a/modules/web-console/backend/app/routes.js
+++ b/modules/web-console/backend/app/routes.js
@@ -44,22 +44,22 @@ module.exports.factory = function(publicRoute, adminRoute, profilesRoute, demoRo
             };
 
             // Registering the standard routes
-            app.use('/', publicRoute);
-            app.use('/admin', _mustAuthenticated, _adminOnly, adminRoute);
-            app.use('/profile', _mustAuthenticated, profilesRoute);
-            app.use('/demo', _mustAuthenticated, demoRoute);
+            app.use('/api/v1/', publicRoute);
+            app.use('/api/v1/admin', _mustAuthenticated, _adminOnly, adminRoute);
+            app.use('/api/v1/profile', _mustAuthenticated, profilesRoute);
+            app.use('/api/v1/demo', _mustAuthenticated, demoRoute);
 
-            app.all('/configuration/*', _mustAuthenticated);
+            app.all('/api/v1/configuration/*', _mustAuthenticated);
 
-            app.use('/configuration', configurationsRoute);
-            app.use('/configuration/clusters', clustersRoute);
-            app.use('/configuration/domains', domainsRoute);
-            app.use('/configuration/caches', cachesRoute);
-            app.use('/configuration/igfs', igfssRoute);
+            app.use('/api/v1/configuration', configurationsRoute);
+            app.use('/api/v1/configuration/clusters', clustersRoute);
+            app.use('/api/v1/configuration/domains', domainsRoute);
+            app.use('/api/v1/configuration/caches', cachesRoute);
+            app.use('/api/v1/configuration/igfs', igfssRoute);
 
-            app.use('/notebooks', _mustAuthenticated, notebooksRoute);
-            app.use('/downloads', _mustAuthenticated, downloadsRoute);
-            app.use('/activities', _mustAuthenticated, activitiesRoute);
+            app.use('/api/v1/notebooks', _mustAuthenticated, notebooksRoute);
+            app.use('/api/v1/downloads', _mustAuthenticated, downloadsRoute);
+            app.use('/api/v1/activities', _mustAuthenticated, activitiesRoute);
         }
     };
 };

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/backend/app/settings.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/settings.js b/modules/web-console/backend/app/settings.js
index 05cb7f6..5032443 100644
--- a/modules/web-console/backend/app/settings.js
+++ b/modules/web-console/backend/app/settings.js
@@ -24,50 +24,56 @@
  */
 module.exports = {
     implements: 'settings',
-    inject: ['nconf', 'require(fs)']
-};
+    inject: ['nconf', 'require(fs)'],
+    factory(nconf, fs) {
+        /**
+         * Normalize a port into a number, string, or false.
+         */
+        const _normalizePort = function(val) {
+            const port = parseInt(val, 10);
+
+            // named pipe
+            if (isNaN(port))
+                return val;
 
-module.exports.factory = function(nconf, fs) {
-    /**
-     * Normalize a port into a number, string, or false.
-     */
-    const _normalizePort = function(val) {
-        const port = parseInt(val, 10);
+            // port number
+            if (port >= 0)
+                return port;
 
-        // named pipe
-        if (isNaN(port))
-            return val;
+            return false;
+        };
 
-        // port number
-        if (port >= 0)
-            return port;
+        const mail = nconf.get('mail') || {};
 
-        return false;
-    };
+        mail.address = (username, email) => username ? '"' + username + '" <' + email + '>' : email;
 
-    const mail = nconf.get('mail') || {};
+        const packaged = __dirname.startsWith('/snapshot/') || __dirname.startsWith('C:\\snapshot\\');
 
-    mail.address = (username, email) => username ? '"' + username + '" <' + email + '>' : email;
+        const dfltAgentDists = packaged ? 'libs/agent_dists' : 'agent_dists';
+        const dfltHost = packaged ? '0.0.0.0' : '127.0.0.1';
+        const dfltPort = packaged ? 80 : 3000;
 
-    return {
-        agent: {
-            dists: 'agent_dists'
-        },
-        server: {
-            host: nconf.get('server:host') || '127.0.0.1',
-            port: _normalizePort(nconf.get('server:port') || 3000),
-            SSLOptions: nconf.get('server:ssl') && {
-                enable301Redirects: true,
-                trustXFPHeader: true,
-                key: fs.readFileSync(nconf.get('server:key')),
-                cert: fs.readFileSync(nconf.get('server:cert')),
-                passphrase: nconf.get('server:keyPassphrase')
-            }
-        },
-        mail,
-        mongoUrl: nconf.get('mongodb:url') || 'mongodb://127.0.0.1/console',
-        cookieTTL: 3600000 * 24 * 30,
-        sessionSecret: nconf.get('server:sessionSecret') || 'keyboard cat',
-        tokenLength: 20
-    };
+        return {
+            agent: {
+                dists: nconf.get('agent:dists') || dfltAgentDists
+            },
+            packaged,
+            server: {
+                host: nconf.get('server:host') || dfltHost,
+                port: _normalizePort(nconf.get('server:port') || dfltPort),
+                SSLOptions: nconf.get('server:ssl') && {
+                    enable301Redirects: true,
+                    trustXFPHeader: true,
+                    key: fs.readFileSync(nconf.get('server:key')),
+                    cert: fs.readFileSync(nconf.get('server:cert')),
+                    passphrase: nconf.get('server:keyPassphrase')
+                }
+            },
+            mail,
+            mongoUrl: nconf.get('mongodb:url') || 'mongodb://127.0.0.1/console',
+            cookieTTL: 3600000 * 24 * 30,
+            sessionSecret: nconf.get('server:sessionSecret') || 'keyboard cat',
+            tokenLength: 20
+        };
+    }
 };

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/backend/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/index.js b/modules/web-console/backend/index.js
index 8454789..266fa54 100644
--- a/modules/web-console/backend/index.js
+++ b/modules/web-console/backend/index.js
@@ -17,14 +17,21 @@
 
 'use strict';
 
-const _ = require('lodash');
 const fs = require('fs');
 const path = require('path');
+
+require('app-module-path').addPath(path.join(__dirname, 'node_modules'));
+
+const _ = require('lodash');
+const getos = require('getos');
 const http = require('http');
 const https = require('https');
 const MigrateMongoose = require('migrate-mongoose');
 
-const igniteModules = process.env.IGNITE_MODULES ?
+
+const packaged = __dirname.startsWith('/snapshot/') || __dirname.startsWith('C:\\snapshot\\');
+
+const igniteModules = !packaged && process.env.IGNITE_MODULES ?
     path.join(path.normalize(process.env.IGNITE_MODULES), 'backend') : path.join(__dirname, 'ignite_modules');
 
 let injector;
@@ -34,6 +41,8 @@ try {
 
     fs.accessSync(igniteModulesInjector, fs.F_OK);
 
+    process.env.NODE_PATH = path.join(__dirname, 'node_modules');
+
     injector = require(igniteModulesInjector);
 }
 catch (ignore) {
@@ -93,7 +102,7 @@ const init = ([settings, apiSrv, agentsHnd, browsersHnd]) => {
 
 /**
  * Run mongo model migration.
- * 
+ *
  * @param dbConnectionUri Mongo connection url.
  * @param group Migrations group.
  * @param migrationsPath Migrations path.
@@ -122,6 +131,16 @@ const migrate = (dbConnectionUri, group, migrationsPath) => {
         });
 };
 
+getos(function(e, os) {
+    if (e)
+        return console.log(e);
+
+    console.log('Your OS is: ' + JSON.stringify(os));
+});
+
+injector.log.info = () => {};
+injector.log.debug = () => {};
+
 Promise.all([injector('settings'), injector('mongo')])
     .then(([{mongoUrl}]) => {
         return migrate(mongoUrl, 'Ignite', path.join(__dirname, 'migrations'))

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/backend/injector.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/injector.js b/modules/web-console/backend/injector.js
index a5996b3..754967f 100644
--- a/modules/web-console/backend/injector.js
+++ b/modules/web-console/backend/injector.js
@@ -21,10 +21,10 @@ module.exports = fireUp.newInjector({
     basePath: __dirname,
     modules: [
         './app/**/*.js',
-        './config/**/*.js',
         './errors/**/*.js',
         './middlewares/**/*.js',
         './routes/**/*.js',
-        './services/**/*.js'
+        './services/**/*.js',
+        './ignite_modules/**/*.js'
     ]
 });

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/backend/package.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/package.json b/modules/web-console/backend/package.json
index 29aa734..f0b2b5e 100644
--- a/modules/web-console/backend/package.json
+++ b/modules/web-console/backend/package.json
@@ -7,7 +7,8 @@
     "ci-test": "cross-env NODE_ENV=test MOCHA_REPORTER=mocha-teamcity-reporter node ./test/index.js",
     "test": "cross-env NODE_ENV=test CONFIG_PATH='./test/config/settings.json' node ./test/index.js",
     "eslint": "eslint --env node --format node_modules/eslint-friendly-formatter ./ -- --eff-by-issue",
-    "start": "node ./index.js"
+    "start": "node ./index.js",
+    "build": "pkg . --out-path build"
   },
   "author": "",
   "contributors": [
@@ -30,7 +31,23 @@
     "linux",
     "win32"
   ],
+  "bin": "index.js",
+  "pkg": {
+    "assets": [
+      "app/*.js",
+      "errors/*.js",
+      "ignite_modules/*",
+      "injector.js",
+      "middlewares/*.js",
+      "migrations/*",
+      "node_modules/getos/logic/*.js",
+      "routes/*.js",
+      "routes/**/*.json",
+      "services/*.js"
+    ]
+  },
   "dependencies": {
+    "app-module-path": "2.2.0",
     "body-parser": "1.17.2",
     "connect-mongo": "1.3.2",
     "cookie-parser": "1.4.3",
@@ -38,9 +55,11 @@
     "express-session": "1.15.4",
     "fire-up": "1.0.0",
     "glob": "7.1.2",
+    "getos": "3.1.0",
     "jszip": "3.1.3",
     "lodash": "4.17.4",
     "migrate-mongoose": "3.2.2",
+    "mongodb-prebuilt": "6.3.3",
     "mongoose": "4.11.4",
     "morgan": "1.8.2",
     "nconf": "0.8.4",
@@ -59,6 +78,7 @@
     "mocha": "3.4.2",
     "mocha-teamcity-reporter": "1.1.1",
     "mockgoose": "6.0.8",
+    "pkg": "4.2.4",
     "supertest": "3.0.0"
   }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/docker/compose/frontend/nginx/web-console.conf
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/compose/frontend/nginx/web-console.conf b/modules/web-console/docker/compose/frontend/nginx/web-console.conf
index 323826e..3f5157d 100644
--- a/modules/web-console/docker/compose/frontend/nginx/web-console.conf
+++ b/modules/web-console/docker/compose/frontend/nginx/web-console.conf
@@ -39,7 +39,6 @@ server {
   }
 
   location /api/v1 {
-    rewrite /api/v1/(.*) /$1 break;
     proxy_set_header Host $http_host;
     proxy_pass http://backend-api;
   }

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/docker/standalone/nginx/web-console.conf
----------------------------------------------------------------------
diff --git a/modules/web-console/docker/standalone/nginx/web-console.conf b/modules/web-console/docker/standalone/nginx/web-console.conf
index 3d83075..6e36eed 100644
--- a/modules/web-console/docker/standalone/nginx/web-console.conf
+++ b/modules/web-console/docker/standalone/nginx/web-console.conf
@@ -34,7 +34,6 @@ server {
   }
 
   location /api/v1 {
-    rewrite /api/v1/(.*) /$1 break;
     proxy_set_header Host $http_host;
     proxy_pass http://backend-api;
   }

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/frontend/.gitignore
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/.gitignore b/modules/web-console/frontend/.gitignore
index 138a2cf..4fc11f46 100644
--- a/modules/web-console/frontend/.gitignore
+++ b/modules/web-console/frontend/.gitignore
@@ -1,9 +1,3 @@
-*.idea
-*.log
 *.log.*
-.npmrc
-build/*
-node_modules
 public/stylesheets/*.css
-yarn.lock
-package-lock.json
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js b/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
index 4e6204f..e5f4804 100644
--- a/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
+++ b/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
@@ -1654,6 +1654,8 @@ export default class IgniteJavaTransformer extends AbstractTransformer {
         }
 
         if ((_.nonEmpty(clientNearCaches) || demo) && shortFactoryCls) {
+            imports.push('org.apache.ignite.Ignite');
+
             sb.append(`Ignite ignite = Ignition.start(${cfgRef});`);
 
             _.forEach(clientNearCaches, (cache, idx) => {

http://git-wip-us.apache.org/repos/asf/ignite/blob/69eced65/modules/web-console/frontend/webpack/webpack.dev.babel.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/webpack/webpack.dev.babel.js b/modules/web-console/frontend/webpack/webpack.dev.babel.js
index 56371cda..88bf5c6 100644
--- a/modules/web-console/frontend/webpack/webpack.dev.babel.js
+++ b/modules/web-console/frontend/webpack/webpack.dev.babel.js
@@ -77,10 +77,7 @@ export default merge(commonCfg, {
                 ws: true
             },
             '/api/v1/*': {
-                target: `http://localhost:${backendPort}`,
-                pathRewrite: {
-                    '^/api/v1': ''
-                }
+                target: `http://localhost:${backendPort}`
             }
         },
         watchOptions: {