You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ag...@apache.org on 2017/04/18 10:37:29 UTC
[33/50] [abbrv] ignite git commit: IGNITE-4995 Multi-cluster support
for Web Console.
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/backend/app/browser.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/app/browser.js b/modules/web-console/backend/app/browser.js
deleted file mode 100644
index e9266a8..0000000
--- a/modules/web-console/backend/app/browser.js
+++ /dev/null
@@ -1,539 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-'use strict';
-
-// Fire me up!
-
-/**
- * Module interaction with browsers.
- */
-module.exports = {
- implements: 'browser-manager',
- inject: ['require(lodash)', 'require(socket.io)', 'agent-manager', 'configure']
-};
-
-module.exports.factory = (_, socketio, agentMgr, configure) => {
- const _errorToJson = (err) => {
- return {
- message: err.message || err,
- code: err.code || 1
- };
- };
-
- return {
- attach: (server) => {
- const io = socketio(server);
-
- configure.socketio(io);
-
- io.sockets.on('connection', (socket) => {
- const user = socket.request.user;
-
- const demo = socket.request._query.IgniteDemoMode === 'true';
-
- const accountId = () => user._id;
-
- // Return available drivers to browser.
- socket.on('schemaImport:drivers', (cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.availableDrivers())
- .then((drivers) => cb(null, drivers))
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Return schemas from database to browser.
- socket.on('schemaImport:schemas', (preset, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => {
- const jdbcInfo = {user: preset.user, password: preset.password};
-
- return agent.metadataSchemas(preset.jdbcDriverJar, preset.jdbcDriverClass, preset.jdbcUrl, jdbcInfo);
- })
- .then((schemas) => cb(null, schemas))
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Return tables from database to browser.
- socket.on('schemaImport:tables', (preset, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => {
- const jdbcInfo = {user: preset.user, password: preset.password};
-
- return agent.metadataTables(preset.jdbcDriverJar, preset.jdbcDriverClass, preset.jdbcUrl, jdbcInfo,
- preset.schemas, preset.tablesOnly);
- })
- .then((tables) => cb(null, tables))
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Return topology command result from grid to browser.
- socket.on('node:topology', (attr, mtr, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.topology(demo, attr, mtr))
- .then((clusters) => cb(null, clusters))
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Close query on node.
- socket.on('node:query:close', (nid, queryId, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.queryClose(demo, nid, queryId))
- .then(() => cb())
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Execute query on node and return first page to browser.
- socket.on('node:query', (nid, cacheName, query, distributedJoins, enforceJoinOrder, local, pageSize, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.fieldsQuery(demo, nid, cacheName, query, distributedJoins, enforceJoinOrder, local, pageSize))
- .then((res) => cb(null, res))
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Fetch next page for query and return result to browser.
- socket.on('node:query:fetch', (nid, queryId, pageSize, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.queryFetch(demo, nid, queryId, pageSize))
- .then((res) => cb(null, res))
- .catch((err) => cb(_errorToJson(err)));
- });
-
- const fetchResult = (acc) => {
- if (!acc.hasMore)
- return acc;
-
- return agent.queryFetch(demo, acc.responseNodeId, acc.queryId, pageSize)
- .then(({result}) => {
- acc.rows = acc.rows.concat(result.rows);
- acc.hasMore = result.hasMore;
-
- return fetchResult(acc);
- });
- };
-
- // Execute query on node and return full result to browser.
- socket.on('node:query:getAll', (nid, cacheName, query, distributedJoins, enforceJoinOrder, local, cb) => {
- // Set page size for query.
- const pageSize = 1024;
-
- agentMgr.findAgent(accountId())
- .then((agent) => {
- const firstPage = agent.fieldsQuery(demo, nid, cacheName, query, distributedJoins, enforceJoinOrder, local, pageSize)
- .then(({result}) => {
- if (result.error)
- return Promise.reject(result.error);
-
- return result.result;
- });
-
- return firstPage
- .then(fetchResult);
- })
- .then((res) => cb(null, res))
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Collect cache query metrics and return result to browser.
- socket.on('node:query:metrics', (nids, since, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.queryDetailMetrics(demo, nids, since))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Collect cache query metrics and return result to browser.
- socket.on('node:query:reset:metrics', (nids, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.queryResetDetailMetrics(demo, nids))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Collect running queries from all nodes in grid.
- socket.on('node:query:running', (duration, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.queryCollectRunning(demo, duration))
- .then((data) => {
-
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Cancel running query by query id on node.
- socket.on('node:query:cancel', (nid, queryId, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.queryCancel(demo, nid, queryId))
- .then((data) => {
-
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Execute scan query on node and return first page to browser.
- socket.on('node:scan', (nid, cacheName, filter, regEx, caseSensitive, near, local, pageSize, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.queryScan(demo, nid, cacheName, filter, regEx, caseSensitive, near, local, pageSize))
- .then((res) => cb(null, res))
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Execute scan on node and return full result to browser.
- socket.on('node:scan:getAll', (nid, cacheName, filter, regEx, caseSensitive, near, local, cb) => {
- // Set page size for query.
- const pageSize = 1024;
-
- agentMgr.findAgent(accountId())
- .then((agent) => {
- const firstPage = agent.queryScan(demo, nid, cacheName, filter, regEx, caseSensitive, near, local, pageSize)
- .then(({result}) => {
- if (result.error)
- return Promise.reject(result.error);
-
- return result.result;
- });
-
- return firstPage
- .then(fetchResult);
- })
- .then((res) => cb(null, res))
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Return cache metadata from all nodes in grid.
- socket.on('node:cache:metadata', (cacheName, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.metadata(demo, cacheName))
- .then((caches) => {
- let types = [];
-
- const _compact = (className) => {
- return className.replace('java.lang.', '').replace('java.util.', '').replace('java.sql.', '');
- };
-
- const _typeMapper = (meta, typeName) => {
- const maskedName = _.isEmpty(meta.cacheName) ? '<default>' : meta.cacheName;
-
- let fields = meta.fields[typeName];
-
- let columns = [];
-
- for (const fieldName in fields) {
- if (fields.hasOwnProperty(fieldName)) {
- const fieldClass = _compact(fields[fieldName]);
-
- columns.push({
- type: 'field',
- name: fieldName,
- clazz: fieldClass,
- system: fieldName === '_KEY' || fieldName === '_VAL',
- cacheName: meta.cacheName,
- typeName,
- maskedName
- });
- }
- }
-
- const indexes = [];
-
- for (const index of meta.indexes[typeName]) {
- fields = [];
-
- for (const field of index.fields) {
- fields.push({
- type: 'index-field',
- name: field,
- order: index.descendings.indexOf(field) < 0,
- unique: index.unique,
- cacheName: meta.cacheName,
- typeName,
- maskedName
- });
- }
-
- if (fields.length > 0) {
- indexes.push({
- type: 'index',
- name: index.name,
- children: fields,
- cacheName: meta.cacheName,
- typeName,
- maskedName
- });
- }
- }
-
- columns = _.sortBy(columns, 'name');
-
- if (!_.isEmpty(indexes)) {
- columns = columns.concat({
- type: 'indexes',
- name: 'Indexes',
- cacheName: meta.cacheName,
- typeName,
- maskedName,
- children: indexes
- });
- }
-
- return {
- type: 'type',
- cacheName: meta.cacheName || '',
- typeName,
- maskedName,
- children: columns
- };
- };
-
- for (const meta of caches) {
- const cacheTypes = meta.types.map(_typeMapper.bind(null, meta));
-
- if (!_.isEmpty(cacheTypes))
- types = types.concat(cacheTypes);
- }
-
- return cb(null, types);
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Fetch next page for query and return result to browser.
- socket.on('node:visor:collect', (evtOrderKey, evtThrottleCntrKey, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.collect(demo, evtOrderKey, evtThrottleCntrKey))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Gets node configuration for specified node.
- socket.on('node:configuration', (nid, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.collectNodeConfiguration(demo, nid))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Gets cache configurations for specified node and caches deployment IDs.
- socket.on('cache:configuration', (nid, caches, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.collectCacheConfigurations(demo, nid, caches))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Reset metrics specified cache on specified node and return result to browser.
- socket.on('node:cache:reset:metrics', (nid, cacheName, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.cacheResetMetrics(demo, nid, cacheName))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Clear specified cache on specified node and return result to browser.
- socket.on('node:cache:clear', (nid, cacheName, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.cacheClear(demo, nid, cacheName))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Start specified cache and return result to browser.
- socket.on('node:cache:start', (nids, near, cacheName, cfg, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.cacheStart(demo, nids, near, cacheName, cfg))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Stop specified cache on specified node and return result to browser.
- socket.on('node:cache:stop', (nid, cacheName, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.cacheStop(demo, nid, cacheName))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
-
- // Ping node and return result to browser.
- socket.on('node:ping', (taskNid, nid, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.ping(demo, taskNid, nid))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // GC node and return result to browser.
- socket.on('node:gc', (nids, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.gc(demo, nids))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Thread dump for node.
- socket.on('node:thread:dump', (nid, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.threadDump(demo, nid))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Collect cache partitions.
- socket.on('node:cache:partitions', (nids, cacheName, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.partitions(demo, nids, cacheName))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Stops given node IDs
- socket.on('node:stop', (nids, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.stopNodes(demo, nids))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Restarts given node IDs.
- socket.on('node:restart', (nids, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.restartNodes(demo, nids))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Collect service information from grid.
- socket.on('service:collect', (nid, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.services(demo, nid))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- // Collect service information from grid.
- socket.on('service:cancel', (nid, name, cb) => {
- agentMgr.findAgent(accountId())
- .then((agent) => agent.serviceCancel(demo, nid, name))
- .then((data) => {
- if (data.finished)
- return cb(null, data.result);
-
- cb(_errorToJson(data.error));
- })
- .catch((err) => cb(_errorToJson(err)));
- });
-
- const count = agentMgr.addAgentListener(user._id, socket);
-
- socket.emit('agent:count', {count});
- });
-
- // Handle browser disconnect event.
- io.sockets.on('disconnect', (socket) =>
- agentMgr.removeAgentListener(socket.client.request.user._id, socket)
- );
- }
- };
-};
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/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
new file mode 100644
index 0000000..793fd5b
--- /dev/null
+++ b/modules/web-console/backend/app/browsersHandler.js
@@ -0,0 +1,279 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+// Fire me up!
+
+/**
+ * Module interaction with browsers.
+ */
+module.exports = {
+ implements: 'browsers-handler',
+ inject: ['require(lodash)', 'require(socket.io)', 'configure', 'errors']
+};
+
+module.exports.factory = (_, socketio, configure, errors) => {
+ class BrowserSockets {
+ constructor() {
+ this.sockets = new Map();
+
+ this.agentHnd = null;
+ }
+
+ /**
+ * @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]);
+
+ return this.sockets.get(token);
+ }
+
+ /**
+ * @param {Socket} sock
+ */
+ remove(sock) {
+ const token = sock.request.user.token;
+
+ const sockets = this.sockets.get(token);
+
+ _.pull(sockets, sock);
+
+ return sockets;
+ }
+
+ get(token) {
+ if (this.sockets.has(token))
+ return this.sockets.get(token);
+
+ return [];
+ }
+
+ demo(token) {
+ return _.filter(this.sockets.get(token), (sock) => sock.request._query.IgniteDemoMode === 'true');
+ }
+ }
+
+ return class BrowsersHandler {
+ /**
+ * @constructor
+ */
+ constructor() {
+ /**
+ * Connected browsers.
+ * @type {BrowserSockets}
+ */
+ this._browserSockets = new BrowserSockets();
+
+ /**
+ * Registered Visor task.
+ * @type {Map}
+ */
+ this._visorTasks = new Map();
+ }
+
+ /**
+ * @param {Error} err
+ * @return {{code: number, message: *}}
+ */
+ errorTransformer(err) {
+ return {
+ code: err.code || 1,
+ message: err.message || err
+ };
+ }
+
+ /**
+ * @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.add({
+ id: agentSock.cluster.id
+ });
+ }
+
+ return acc;
+ }, {count: 0, hasDemo: false, clusters: new Set()});
+
+ stat.clusters = Array.from(stat.clusters);
+
+ return stat;
+ })
+ .catch(() => ({count: 0, hasDemo: false, clusters: []}))
+ .then((stat) => _.forEach(socks, (sock) => sock.emit('agents:stat', stat)));
+ }
+
+ executeOnAgent(token, demo, event, ...args) {
+ const cb = _.last(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)));
+ }
+
+ agentListeners(sock) {
+ const demo = sock.request._query.IgniteDemoMode === 'true';
+ const token = () => sock.request.user.token;
+
+ // Return available drivers to browser.
+ sock.on('schemaImport:drivers', (...args) => {
+ this.executeOnAgent(token(), demo, 'schemaImport:drivers', ...args);
+ });
+
+ // Return schemas from database to browser.
+ sock.on('schemaImport:schemas', (...args) => {
+ this.executeOnAgent(token(), demo, 'schemaImport:schemas', ...args);
+ });
+
+ // Return tables from database to browser.
+ sock.on('schemaImport:tables', (...args) => {
+ this.executeOnAgent(token(), demo, 'schemaImport:tables', ...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, method: 'GET'}))
+ .then((res) => {
+ if (res.status === 0)
+ return JSON.parse(res.data);
+
+ throw new Error(res.error);
+ });
+ }
+
+ registerVisorTask(taskId, taskCls, ...argCls) {
+ this._visorTasks.set(taskId, {
+ taskCls,
+ argCls
+ });
+ }
+
+ 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;
+
+ const agent = this._agentHnd.agent(token, demo, clusterId);
+
+ this.executeOnNode(agent, demo, params)
+ .then((data) => cb(null, data))
+ .catch((err) => cb(this.errorTransformer(err)));
+ });
+
+ const internalVisor = (postfix) => `org.apache.ignite.internal.visor.${postfix}`;
+
+ this.registerVisorTask('querySql', internalVisor('query.VisorQueryTask'), internalVisor('query.VisorQueryArg'));
+ this.registerVisorTask('queryScan', internalVisor('query.VisorScanQueryTask'), internalVisor('query.VisorScanQueryArg'));
+ this.registerVisorTask('queryFetch', internalVisor('query.VisorQueryNextPageTask'), internalVisor('query.VisorQueryNextPageTaskArg'));
+ this.registerVisorTask('queryClose', internalVisor('query.VisorQueryCleanupTask'),
+ 'java.util.Map', 'java.util.UUID', 'java.util.Set');
+
+ // 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;
+
+ const cb = _.last(args);
+ args = _.dropRight(args);
+
+ const desc = this._visorTasks.get(taskId);
+
+ 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
+ };
+
+ _.forEach(_.concat(desc.argCls, args), (param, idx) => { params[`p${idx + 3}`] = param; });
+
+ const agent = this._agentHnd.agent(token, demo, clusterId);
+
+ this.executeOnNode(agent, demo, params)
+ .then((data) => {
+ if (data.finished)
+ return cb(null, data.result);
+
+ cb(this.errorTransformer(data.error));
+ })
+ .catch((err) => cb(this.errorTransformer(err)));
+ });
+ }
+
+ /**
+ *
+ * @param server
+ * @param {AgentsHandler} agentHnd
+ */
+ attach(server, agentHnd) {
+ this._agentHnd = agentHnd;
+
+ if (this.io)
+ throw 'Browser server already started!';
+
+ const io = socketio(server);
+
+ configure.socketio(io);
+
+ // Handle browser connect event.
+ io.sockets.on('connection', (sock) => {
+ this._browserSockets.add(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]);
+ });
+ }
+ };
+};
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/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 6b5d052..826407b 100644
--- a/modules/web-console/backend/app/routes.js
+++ b/modules/web-console/backend/app/routes.js
@@ -22,11 +22,11 @@
module.exports = {
implements: 'routes',
inject: ['routes/public', 'routes/admin', 'routes/profiles', 'routes/demo', 'routes/clusters', 'routes/domains',
- 'routes/caches', 'routes/igfss', 'routes/notebooks', 'routes/agents', 'routes/configurations', 'routes/activities']
+ 'routes/caches', 'routes/igfss', 'routes/notebooks', 'routes/downloads', 'routes/configurations', 'routes/activities']
};
module.exports.factory = function(publicRoute, adminRoute, profilesRoute, demoRoute,
- clustersRoute, domainsRoute, cachesRoute, igfssRoute, notebooksRoute, agentsRoute, configurationsRoute, activitiesRoute) {
+ clustersRoute, domainsRoute, cachesRoute, igfssRoute, notebooksRoute, downloadsRoute, configurationsRoute, activitiesRoute) {
return {
register: (app) => {
const _mustAuthenticated = (req, res, next) => {
@@ -58,7 +58,7 @@ module.exports.factory = function(publicRoute, adminRoute, profilesRoute, demoRo
app.use('/configuration/igfs', igfssRoute);
app.use('/notebooks', _mustAuthenticated, notebooksRoute);
- app.use('/agent', _mustAuthenticated, agentsRoute);
+ app.use('/downloads', _mustAuthenticated, downloadsRoute);
app.use('/activities', _mustAuthenticated, activitiesRoute);
}
};
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/backend/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/index.js b/modules/web-console/backend/index.js
index 27d7298..7416f51 100644
--- a/modules/web-console/backend/index.js
+++ b/modules/web-console/backend/index.js
@@ -32,7 +32,8 @@ try {
fs.accessSync(igniteModulesInjector, fs.F_OK);
injector = require(igniteModulesInjector);
-} catch (ignore) {
+}
+catch (ignore) {
injector = require(path.join(__dirname, './injector'));
}
@@ -71,25 +72,36 @@ const _onListening = (addr) => {
console.log('Start listening on ' + bind);
};
-Promise.all([injector('settings'), injector('app'), injector('agent-manager'), injector('browser-manager')])
- .then(([settings, app, agentMgr, browserMgr]) => {
- // Start rest server.
- const server = settings.server.SSLOptions
- ? https.createServer(settings.server.SSLOptions) : http.createServer();
+/**
+ * @param settings
+ * @param {ApiServer} apiSrv
+ * @param {AgentsHandler} agentsHnd
+ * @param {BrowsersHandler} BrowsersHandler
+ */
+const init = ([settings, apiSrv, agentsHnd, BrowsersHandler]) => {
+ // Start rest server.
+ const srv = settings.server.SSLOptions ? https.createServer(settings.server.SSLOptions) : http.createServer();
+
+ srv.listen(settings.server.port);
- server.listen(settings.server.port);
- server.on('error', _onError.bind(null, settings.server.port));
- server.on('listening', _onListening.bind(null, server.address()));
+ srv.on('error', _onError.bind(null, settings.server.port));
+ srv.on('listening', _onListening.bind(null, srv.address()));
- app.listen(server);
+ apiSrv.attach(srv);
- agentMgr.attach(server);
- browserMgr.attach(server);
+ const browsersHnd = new BrowsersHandler();
+
+ agentsHnd.attach(srv, browsersHnd);
+ browsersHnd.attach(srv, agentsHnd);
+
+ // Used for automated test.
+ if (process.send)
+ process.send('running');
+};
- // Used for automated test.
- if (process.send)
- process.send('running');
- }).catch((err) => {
+Promise.all([injector('settings'), injector('api-server'), injector('agents-handler'), injector('browsers-handler')])
+ .then(init)
+ .catch((err) => {
console.error(err);
process.exit(1);
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/backend/package.json
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/package.json b/modules/web-console/backend/package.json
index d50136f..2af7787 100644
--- a/modules/web-console/backend/package.json
+++ b/modules/web-console/backend/package.json
@@ -29,34 +29,34 @@
"win32"
],
"dependencies": {
- "body-parser": "^1.15.0",
- "connect-mongo": "^1.1.0",
+ "body-parser": "1.17.1",
+ "connect-mongo": "1.3.2",
"cookie-parser": "~1.4.0",
- "express": "^4.14.0",
- "express-session": "^1.12.0",
- "fire-up": "^1.0.0",
- "glob": "^7.0.3",
- "jszip": "^3.0.0",
- "lodash": "^4.8.2",
- "mongoose": "^4.4.11",
- "morgan": "^1.7.0",
- "nconf": "^0.8.2",
- "nodemailer": "^2.3.0",
- "passport": "^0.3.2",
- "passport-local": "^1.0.0",
- "passport-local-mongoose": "^4.0.0",
- "passport.socketio": "^3.6.1",
- "socket.io": "^1.4.5"
+ "express": "4.15.2",
+ "express-session": "1.15.2",
+ "fire-up": "1.0.0",
+ "glob": "7.1.1",
+ "jszip": "3.1.3",
+ "lodash": "4.17.4",
+ "mongoose": "4.9.4",
+ "morgan": "1.8.1",
+ "nconf": "0.8.4",
+ "nodemailer": "3.1.4",
+ "passport": "0.3.2",
+ "passport-local": "1.0.0",
+ "passport-local-mongoose": "4.0.0",
+ "passport.socketio": "3.7.0",
+ "socket.io": "1.7.3"
},
"devDependencies": {
- "chai": "^3.5.0",
- "cross-env": "^1.0.7",
- "eslint": "^2.9.0",
- "eslint-friendly-formatter": "^2.0.5",
- "jasmine-core": "^2.4.1",
- "mocha": "~2.5.3",
- "mocha-teamcity-reporter": "^1.0.0",
- "mockgoose": "^6.0.6",
- "supertest": "^2.0.0"
+ "chai": "3.5.0",
+ "cross-env": "4.0.0",
+ "eslint": "3.19.0",
+ "eslint-friendly-formatter": "2.0.7",
+ "jasmine-core": "2.5.2",
+ "mocha": "3.2.0",
+ "mocha-teamcity-reporter": "1.1.1",
+ "mockgoose": "6.0.8",
+ "supertest": "3.0.0"
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/backend/routes/agent.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/agent.js b/modules/web-console/backend/routes/agent.js
deleted file mode 100644
index 5ae807b..0000000
--- a/modules/web-console/backend/routes/agent.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
- implements: 'routes/agents',
- inject: ['require(lodash)', 'require(express)', 'services/agents', 'services/activities']
-};
-
-/**
- * @param _
- * @param express
- * @param {AgentsService} agentsService
- * @param {ActivitiesService} activitiesService
- * @returns {Promise}
- */
-module.exports.factory = function(_, express, agentsService, activitiesService) {
- return new Promise((resolveFactory) => {
- const router = new express.Router();
-
- /* Get grid topology. */
- router.get('/download/zip', (req, res) => {
- activitiesService.merge(req.user._id, {
- group: 'agent',
- action: '/agent/download'
- });
-
- agentsService.getArchive(req.origin(), req.user.token)
- .then(({fileName, buffer}) => {
- // Set the archive name.
- res.attachment(fileName);
-
- res.send(buffer);
- })
- .catch(res.api.error);
- });
-
- resolveFactory(router);
- });
-};
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/backend/routes/demo.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/demo.js b/modules/web-console/backend/routes/demo.js
index 3f4166d..b200d83 100644
--- a/modules/web-console/backend/routes/demo.js
+++ b/modules/web-console/backend/routes/demo.js
@@ -26,10 +26,20 @@ const igfss = require('./demo/igfss.json');
module.exports = {
implements: 'routes/demo',
- inject: ['require(lodash)', 'require(express)', 'settings', 'mongo', 'services/spaces', 'errors']
+ inject: ['require(lodash)', 'require(express)', 'errors', 'settings', 'mongo', 'services/spaces']
};
-module.exports.factory = (_, express, settings, mongo, spacesService, errors) => {
+/**
+ *
+ * @param _
+ * @param express
+ * @param errors
+ * @param settings
+ * @param mongo
+ * @param spacesService
+ * @return {Promise}
+ */
+module.exports.factory = (_, express, errors, settings, mongo, spacesService) => {
return new Promise((factoryResolve) => {
const router = new express.Router();
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/backend/routes/downloads.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/routes/downloads.js b/modules/web-console/backend/routes/downloads.js
new file mode 100644
index 0000000..88a1923
--- /dev/null
+++ b/modules/web-console/backend/routes/downloads.js
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+ implements: 'routes/downloads',
+ inject: ['require(lodash)', 'require(express)', 'services/agents', 'services/activities']
+};
+
+/**
+ * @param _
+ * @param express
+ * @param {DownloadsService} downloadsService
+ * @param {ActivitiesService} activitiesService
+ * @returns {Promise}
+ */
+module.exports.factory = function(_, express, downloadsService, activitiesService) {
+ return new Promise((resolveFactory) => {
+ const router = new express.Router();
+
+ /* Get grid topology. */
+ router.get('/agent', (req, res) => {
+ activitiesService.merge(req.user._id, {
+ group: 'agent',
+ action: '/agent/download'
+ });
+
+ downloadsService.prepareArchive(req.origin(), req.user.token)
+ .then(({fileName, buffer}) => {
+ // Set the archive name.
+ res.attachment(fileName);
+
+ res.send(buffer);
+ })
+ .catch(res.api.error);
+ });
+
+ resolveFactory(router);
+ });
+};
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/backend/services/agents.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/agents.js b/modules/web-console/backend/services/agents.js
deleted file mode 100644
index 4931bf8..0000000
--- a/modules/web-console/backend/services/agents.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-'use strict';
-
-// Fire me up!
-
-module.exports = {
- implements: 'services/agents',
- inject: ['require(lodash)', 'require(fs)', 'require(path)', 'require(jszip)', 'settings', 'agent-manager', 'errors']
-};
-
-/**
- * @param _
- * @param fs
- * @param path
- * @param JSZip
- * @param settings
- * @param agentMgr
- * @param errors
- * @returns {AgentsService}
- */
-module.exports.factory = (_, fs, path, JSZip, settings, agentMgr, errors) => {
- class AgentsService {
- /**
- * Get agent archive with user agent configuration.
- *
- * @returns {*} - readable stream for further piping. (http://stuk.github.io/jszip/documentation/api_jszip/generate_node_stream.html)
- */
- static getArchive(host, token) {
- const latest = agentMgr.supportedAgents.latest;
-
- if (_.isEmpty(latest))
- throw new errors.MissingResourceException('Missing agent zip on server. Please ask webmaster to upload agent zip!');
-
- const filePath = latest.filePath;
- const fileName = latest.fileName;
-
- const folder = path.basename(latest.fileName, '.zip');
-
- // Read a zip file.
- return new Promise((resolve, reject) => {
- fs.readFile(filePath, (errFs, data) => {
- if (errFs)
- reject(new errors.ServerErrorException(errFs));
-
- JSZip.loadAsync(data)
- .then((zip) => {
- const prop = [];
-
- prop.push('tokens=' + token);
- prop.push(`server-uri=${host}`);
- prop.push('#Uncomment following options if needed:');
- prop.push('#node-uri=http://localhost:8080');
- prop.push('#driver-folder=./jdbc-drivers');
-
- zip.file(folder + '/default.properties', prop.join('\n'));
-
- return zip.generateAsync({type: 'nodebuffer', platform: 'UNIX'})
- .then((buffer) => resolve({filePath, fileName, buffer}));
- })
- .catch(reject);
- });
- });
- }
- }
-
- return AgentsService;
-};
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/backend/services/downloads.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/downloads.js b/modules/web-console/backend/services/downloads.js
new file mode 100644
index 0000000..3dfc2be
--- /dev/null
+++ b/modules/web-console/backend/services/downloads.js
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+// Fire me up!
+
+module.exports = {
+ implements: 'services/agents',
+ inject: ['require(lodash)', 'require(fs)', 'require(path)', 'require(jszip)', 'settings', 'agents-handler', 'errors']
+};
+
+/**
+ * @param _
+ * @param fs
+ * @param path
+ * @param JSZip
+ * @param settings
+ * @param agentsHnd
+ * @param errors
+ * @returns {DownloadsService}
+ */
+module.exports.factory = (_, fs, path, JSZip, settings, agentsHnd, errors) => {
+ class DownloadsService {
+ /**
+ * Get agent archive with user agent configuration.
+ *
+ * @returns {*} - readable stream for further piping. (http://stuk.github.io/jszip/documentation/api_jszip/generate_node_stream.html)
+ */
+ prepareArchive(host, token) {
+ if (_.isEmpty(agentsHnd.currentAgent))
+ throw new errors.MissingResourceException('Missing agent zip on server. Please ask webmaster to upload agent zip!');
+
+ const {filePath, fileName} = agentsHnd.currentAgent;
+
+ const folder = path.basename(fileName, '.zip');
+
+ // Read a zip file.
+ return new Promise((resolve, reject) => {
+ fs.readFile(filePath, (errFs, data) => {
+ if (errFs)
+ reject(new errors.ServerErrorException(errFs));
+
+ JSZip.loadAsync(data)
+ .then((zip) => {
+ const prop = [];
+
+ prop.push(`tokens=${token}`);
+ prop.push(`server-uri=${host}`);
+ prop.push('#Uncomment following options if needed:');
+ prop.push('#node-uri=http://localhost:8080');
+ prop.push('#driver-folder=./jdbc-drivers');
+
+ zip.file(`${folder}/default.properties`, prop.join('\n'));
+
+ return zip.generateAsync({type: 'nodebuffer', platform: 'UNIX'})
+ .then((buffer) => resolve({filePath, fileName, buffer}));
+ })
+ .catch(reject);
+ });
+ });
+ }
+ }
+
+ return new DownloadsService();
+};
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/backend/services/users.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/services/users.js b/modules/web-console/backend/services/users.js
index 0aff45f..51b88e9 100644
--- a/modules/web-console/backend/services/users.js
+++ b/modules/web-console/backend/services/users.js
@@ -21,21 +21,21 @@
module.exports = {
implements: 'services/users',
- inject: ['require(lodash)', 'mongo', 'settings', 'services/spaces', 'services/mails', 'services/activities', 'agent-manager', 'errors']
+ inject: ['require(lodash)', 'errors', 'settings', 'mongo', 'services/spaces', 'services/mails', 'services/activities', 'agents-handler']
};
/**
* @param _
* @param mongo
+ * @param errors
* @param settings
* @param {SpacesService} spacesService
* @param {MailsService} mailsService
* @param {ActivitiesService} activitiesService
- * @param agentMgr
- * @param errors
+ * @param {AgentsHandler} agentHnd
* @returns {UsersService}
*/
-module.exports.factory = (_, mongo, settings, spacesService, mailsService, activitiesService, agentMgr, errors) => {
+module.exports.factory = (_, errors, settings, mongo, spacesService, mailsService, activitiesService, agentHnd) => {
const _randomString = () => {
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const possibleLen = possible.length;
@@ -132,7 +132,7 @@ module.exports.factory = (_, mongo, settings, spacesService, mailsService, activ
})
.then((user) => {
if (changed.token && user.token !== changed.token)
- agentMgr.close(user._id, user.token);
+ agentHnd.onTokenReset(user);
_.extend(user, changed);
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/backend/test/app/httpAgent.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/app/httpAgent.js b/modules/web-console/backend/test/app/httpAgent.js
index 1394dc5..76b191e 100644
--- a/modules/web-console/backend/test/app/httpAgent.js
+++ b/modules/web-console/backend/test/app/httpAgent.js
@@ -21,11 +21,11 @@
module.exports = {
implements: 'agentFactory',
- inject: ['app', 'require(http)', 'require(supertest)']
+ inject: ['api-server', 'require(http)', 'require(supertest)']
};
-module.exports.factory = (app, http, request) => {
- const express = app.listen(http.createServer());
+module.exports.factory = (apiSrv, http, request) => {
+ const express = apiSrv.attach(http.createServer());
let authAgentInstance = null;
return {
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/backend/test/routes/clusters.js
----------------------------------------------------------------------
diff --git a/modules/web-console/backend/test/routes/clusters.js b/modules/web-console/backend/test/routes/clusters.js
index 5dd7a60..b9f6565 100644
--- a/modules/web-console/backend/test/routes/clusters.js
+++ b/modules/web-console/backend/test/routes/clusters.js
@@ -53,7 +53,7 @@ suite('routes.clusters', () => {
});
test('Remove cluster model', (done) => {
- return agentFactory.authAgent(db.mocks.accounts[0])
+ agentFactory.authAgent(db.mocks.accounts[0])
.then((agent) => {
agent.post('/configuration/clusters/remove')
.send({_id: db.mocks.clusters[0]._id})
@@ -68,7 +68,7 @@ suite('routes.clusters', () => {
});
test('Remove all clusters', (done) => {
- return agentFactory.authAgent(db.mocks.accounts[0])
+ agentFactory.authAgent(db.mocks.accounts[0])
.then((agent) => {
agent.post('/configuration/clusters/remove/all')
.expect(200)
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/frontend/app/app.config.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/app.config.js b/modules/web-console/frontend/app/app.config.js
index 3ca5c3b..cf527e6 100644
--- a/modules/web-console/frontend/app/app.config.js
+++ b/modules/web-console/frontend/app/app.config.js
@@ -42,6 +42,7 @@ igniteConsoleCfg.config(['$animateProvider', ($animateProvider) => {
igniteConsoleCfg.config(['$modalProvider', ($modalProvider) => {
angular.extend($modalProvider.defaults, {
animation: 'am-fade-and-scale',
+ placement: 'center',
html: true
});
}]);
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/frontend/app/app.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/app.js b/modules/web-console/frontend/app/app.js
index 80e32a1..a8460e9 100644
--- a/modules/web-console/frontend/app/app.js
+++ b/modules/web-console/frontend/app/app.js
@@ -114,6 +114,7 @@ import resetPassword from './controllers/reset-password.controller';
// Components
import igniteListOfRegisteredUsers from './components/list-of-registered-users';
import IgniteActivitiesUserDialog from './components/activities-user-dialog';
+import clusterSelect from './components/cluster-select';
import './components/input-dialog';
// Inject external modules.
@@ -197,6 +198,7 @@ angular
.directive('igniteOnFocusOut', igniteOnFocusOut)
.directive('igniteRestoreInputFocus', igniteRestoreInputFocus)
.directive('igniteListOfRegisteredUsers', igniteListOfRegisteredUsers)
+.directive('igniteClusterSelect', clusterSelect)
// Services.
.service('IgniteErrorPopover', ErrorPopover)
.service('JavaTypes', JavaTypes)
@@ -241,10 +243,10 @@ angular
abstract: true,
template: baseTemplate
})
- .state('settings', {
+ .state('base.settings', {
url: '/settings',
abstract: true,
- template: baseTemplate
+ template: '<ui-view></ui-view>'
});
$urlRouterProvider.otherwise('/404');
@@ -256,8 +258,8 @@ angular
$root.$meta = $meta;
$root.gettingStarted = gettingStarted;
}])
-.run(['$rootScope', 'IgniteAgentMonitor', ($root, agentMonitor) => {
- $root.$on('user', () => agentMonitor.init());
+.run(['$rootScope', 'AgentManager', ($root, agentMgr) => {
+ $root.$on('user', () => agentMgr.connect());
}])
.run(['$rootScope', ($root) => {
$root.$on('$stateChangeStart', () => {
@@ -272,7 +274,7 @@ angular
.then((user) => {
$root.$broadcast('user', user);
- $state.go('settings.admin');
+ $state.go('base.settings.admin');
})
.then(() => Notebook.load())
.catch(Messages.showError);
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/frontend/app/components/activities-user-dialog/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/activities-user-dialog/index.js b/modules/web-console/frontend/app/components/activities-user-dialog/index.js
index 2f8fdef..02c7c1e 100644
--- a/modules/web-console/frontend/app/components/activities-user-dialog/index.js
+++ b/modules/web-console/frontend/app/components/activities-user-dialog/index.js
@@ -25,7 +25,6 @@
resolve: {
user: () => user
},
- placement: 'center',
controller,
controllerAs: 'ctrl'
});
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/frontend/app/components/cluster-select/cluster-select.controller.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-select/cluster-select.controller.js b/modules/web-console/frontend/app/components/cluster-select/cluster-select.controller.js
new file mode 100644
index 0000000..a318172
--- /dev/null
+++ b/modules/web-console/frontend/app/components/cluster-select/cluster-select.controller.js
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export default ['$scope', 'AgentManager', function($scope, agentMgr) {
+ const ctrl = this;
+
+ ctrl.counter = 1;
+
+ ctrl.cluster = null;
+ ctrl.clusters = [];
+
+ $scope.$watchCollection(() => agentMgr.clusters, (clusters) => {
+ if (_.isEmpty(clusters))
+ return ctrl.clusters.length = 0;
+
+ const removed = _.differenceBy(ctrl.clusters, clusters, 'id');
+
+ if (_.nonEmpty(removed))
+ _.pullAll(ctrl.clusters, removed);
+
+ const added = _.differenceBy(clusters, ctrl.clusters, 'id');
+
+ _.forEach(added, (cluster) => {
+ ctrl.clusters.push({
+ id: cluster.id,
+ name: `Cluster ${cluster.id.substring(0, 8).toUpperCase()}`,
+ click: () => {
+ if (cluster.id === ctrl.cluster.id)
+ return;
+
+ agentMgr.saveToStorage(cluster);
+
+ window.open(window.location.href, '_blank');
+ }
+ });
+ });
+
+ if (_.isNil(ctrl.cluster))
+ ctrl.cluster = _.find(ctrl.clusters, {id: agentMgr.cluster.id});
+ });
+}];
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug b/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug
new file mode 100644
index 0000000..9c1ab75
--- /dev/null
+++ b/modules/web-console/frontend/app/components/cluster-select/cluster-select.pug
@@ -0,0 +1,40 @@
+//-
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ul.nav.navbar-nav(ng-if='!IgniteDemoMode' ng-switch='ctrl.clusters.length' style='padding-right: 5px')
+ li.disabled(ng-switch-when='0')
+ a
+ i.icon-cluster
+ label.padding-left-dflt(bs-tooltip='' data-placement='bottom' data-title='Check that Web Agent(s) started and connected to cluster(s)') No clusters available
+
+ li.disabled(ng-switch-when='1')
+ a
+ i.icon-cluster
+ label.padding-left-dflt {{ctrl.cluster.name}}
+
+ li(ng-switch-default)
+ a.dropdown-toggle(bs-dropdown='' data-placement='bottom-left' data-trigger='hover focus' data-container='self' data-animation='' ng-click='$event.stopPropagation()' aria-haspopup='true' aria-expanded='expanded')
+ i.icon-cluster
+ label.padding-left-dflt {{ctrl.cluster.name}}
+ span.caret
+ ul.dropdown-menu(role='menu')
+ li(ng-repeat='item in ctrl.clusters' ng-class='{active: ctrl.cluster === item}')
+ div(ng-click='item.click()')
+ i.icon-cluster.pull-left(style='margin: 0; padding-left: 10px;')
+ div: a {{item.name}}
+i.icon-help(bs-tooltip='' data-placement='bottom' data-html=true style='padding-right: 20px; line-height: 25px'
+ data-title='Multi-Cluster Support<br/>\
+ <a href="https://apacheignite-tools.readme.io/docs/multi-cluster-support" target="_blank">More info</a>')
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/frontend/app/components/cluster-select/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/cluster-select/index.js b/modules/web-console/frontend/app/components/cluster-select/index.js
new file mode 100644
index 0000000..b73845e
--- /dev/null
+++ b/modules/web-console/frontend/app/components/cluster-select/index.js
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import template from './cluster-select.pug';
+import controller from './cluster-select.controller';
+
+export default [() => {
+ return {
+ restrict: 'E',
+ template,
+ controller,
+ controllerAs: 'ctrl'
+ };
+}];
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/frontend/app/components/input-dialog/input-dialog.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/input-dialog/input-dialog.service.js b/modules/web-console/frontend/app/components/input-dialog/input-dialog.service.js
index fc3cb85..4a48b46 100644
--- a/modules/web-console/frontend/app/components/input-dialog/input-dialog.service.js
+++ b/modules/web-console/frontend/app/components/input-dialog/input-dialog.service.js
@@ -49,7 +49,6 @@ export default class InputDialog {
toValidValue
})
},
- placement: 'center',
controller,
controllerAs: 'ctrl'
});
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.column-defs.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.column-defs.js b/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.column-defs.js
index 54bfb03..5bacce4 100644
--- a/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.column-defs.js
+++ b/modules/web-console/frontend/app/components/list-of-registered-users/list-of-registered-users.column-defs.js
@@ -19,7 +19,7 @@ const ICON_SORT = '<span ui-grid-one-bind-id-grid="col.uid + \'-sortdir-text\'"
const USER_TEMPLATE = '<div class="ui-grid-cell-contents"><i class="pull-left" ng-class="row.entity.admin ? \'icon-admin\' : \'icon-user\'"></i> {{ COL_FIELD }}</div>';
-const CLUSTER_HEADER_TEMPLATE = `<div class='ui-grid-cell-contents' bs-tooltip data-title='{{ col.headerTooltip(col) }}' data-placement='top'><i class='fa fa-sitemap'></i>${ICON_SORT}</div>`;
+const CLUSTER_HEADER_TEMPLATE = `<div class='ui-grid-cell-contents' bs-tooltip data-title='{{ col.headerTooltip(col) }}' data-placement='top'><i class='icon-cluster'></i>${ICON_SORT}</div>`;
const MODEL_HEADER_TEMPLATE = `<div class='ui-grid-cell-contents' bs-tooltip data-title='{{ col.headerTooltip(col) }}' data-placement='top'><i class='fa fa-object-group'></i>${ICON_SORT}</div>`;
const CACHE_HEADER_TEMPLATE = `<div class='ui-grid-cell-contents' bs-tooltip data-title='{{ col.headerTooltip(col) }}' data-placement='top'><i class='fa fa-database'></i>${ICON_SORT}</div>`;
const IGFS_HEADER_TEMPLATE = `<div class='ui-grid-cell-contents' bs-tooltip data-title='{{ col.headerTooltip(col) }}' data-placement='top'><i class='fa fa-folder-o'></i>${ICON_SORT}</div>`;
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/frontend/app/helpers/jade/form/form-field-text.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/form/form-field-text.pug b/modules/web-console/frontend/app/helpers/jade/form/form-field-text.pug
index 8444eb4..5a7aa2e 100644
--- a/modules/web-console/frontend/app/helpers/jade/form/form-field-text.pug
+++ b/modules/web-console/frontend/app/helpers/jade/form/form-field-text.pug
@@ -43,7 +43,7 @@ mixin ignite-form-field-text(label, model, name, disabled, required, placeholder
+ignite-form-field__label(label, name, required)
.ignite-form-field__control
+tooltip(tip, tipOpts)
-
+
if block
block
@@ -58,6 +58,23 @@ mixin ignite-form-field-url(label, model, name, required, placeholder, tip)
.ignite-form-field
+ignite-form-field__label(label, name, required)
.ignite-form-field__control
+ +tooltip(tip, tipOpts)
+
+ if block
+ block
+
+ +form-field-feedback(name, 'required', errLbl + ' could not be empty!')
+ +form-field-feedback(name, 'url', errLbl + ' should be a valid URL!')
+
+ .input-tip
+ +ignite-form-field-url-input(name, model, false, required, placeholder)(attributes=attributes)
+
+mixin ignite-form-field-url(label, model, name, required, placeholder, tip)
+ -var errLbl = label.substring(0, label.length - 1)
+
+ .ignite-form-field
+ +ignite-form-field__label(label, name, required)
+ .ignite-form-field__control
if tip
i.tipField.icon-help(bs-tooltip='' data-title=tip)
http://git-wip-us.apache.org/repos/asf/ignite/blob/323e3870/modules/web-console/frontend/app/helpers/jade/mixins.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/helpers/jade/mixins.pug b/modules/web-console/frontend/app/helpers/jade/mixins.pug
index e6990f6..672b8f8 100644
--- a/modules/web-console/frontend/app/helpers/jade/mixins.pug
+++ b/modules/web-console/frontend/app/helpers/jade/mixins.pug
@@ -209,6 +209,12 @@ mixin url(lbl, model, name, required, placeholder, tip)
if block
block
+//- Mixin for text field.
+mixin url(lbl, model, name, required, placeholder, tip)
+ +ignite-form-field-url(lbl, model, name, required, placeholder, tip)
+ if block
+ block
+
//- Mixin for password field.
mixin password(lbl, model, name, required, placeholder, tip)
+ignite-form-field-password(lbl, model, name, false, required, placeholder, tip)