You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2017/06/20 10:34:36 UTC
ambari git commit: AMBARI-21283 Integrate cluster-env configs update
with websocket events. (atkach)
Repository: ambari
Updated Branches:
refs/heads/branch-3.0-perf d986503ca -> 11f16c83a
AMBARI-21283 Integrate cluster-env configs update with websocket events. (atkach)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/11f16c83
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/11f16c83
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/11f16c83
Branch: refs/heads/branch-3.0-perf
Commit: 11f16c83ac8f2ebbf4609240a895a4a3d078b946
Parents: d986503
Author: Andrii Tkach <at...@apache.org>
Authored: Tue Jun 20 13:08:27 2017 +0300
Committer: Andrii Tkach <at...@apache.org>
Committed: Tue Jun 20 13:08:27 2017 +0300
----------------------------------------------------------------------
.../app/controllers/global/update_controller.js | 10 ++-
.../main/dashboard/config_history_controller.js | 4 +-
ambari-web/app/utils/stomp_client.js | 71 ++++++++++++++++---
.../global/update_controller_test.js | 18 ++++-
.../dashboard/config_history_controller_test.js | 12 ++--
ambari-web/test/controllers/main_test.js | 6 ++
ambari-web/test/utils/stomp_client_test.js | 73 +++++++++++++++++---
7 files changed, 163 insertions(+), 31 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/11f16c83/ambari-web/app/controllers/global/update_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/update_controller.js b/ambari-web/app/controllers/global/update_controller.js
index d9c882f..5063db3 100644
--- a/ambari-web/app/controllers/global/update_controller.js
+++ b/ambari-web/app/controllers/global/update_controller.js
@@ -188,10 +188,10 @@ App.UpdateController = Em.Controller.extend({
updateAll: function () {
var socket = App.socketEventsMapper;
if (this.get('isWorking') && !App.get('isOnlyViewUser')) {
- //TODO limit updates by location
App.StompClient.subscribe('/events/hostcomponents', socket.applyHostComponentStatusEvents.bind(socket));
App.StompClient.subscribe('/events/alerts', socket.applyAlertDefinitionSummaryEvents.bind(socket));
App.StompClient.subscribe('/events/topologies', App.topologyMapper.map.bind(App.topologyMapper));
+ App.StompClient.subscribe('/events/configs', this.makeCallForClusterEnv.bind(this));
App.updater.run(this, 'updateServices', 'isWorking');
App.updater.run(this, 'updateHost', 'isWorking');
@@ -205,13 +205,13 @@ App.UpdateController = Em.Controller.extend({
if (!App.get('router.mainAlertInstancesController.isUpdating')) {
App.updater.run(this, 'updateUnhealthyAlertInstances', 'updateAlertInstances', App.alertInstancesUpdateInterval, '\/main\/alerts.*');
}
- App.updater.run(this, 'updateClusterEnv', 'isWorking', App.clusterEnvUpdateInterval);
App.updater.run(this, 'updateUpgradeState', 'isWorking', App.bgOperationsUpdateInterval);
App.updater.run(this, 'updateWizardWatcher', 'isWorking', App.bgOperationsUpdateInterval);
} else {
App.StompClient.unsubscribe('/events/hostcomponents');
App.StompClient.unsubscribe('/events/alerts');
App.StompClient.unsubscribe('/events/topologies');
+ App.StompClient.unsubscribe('/events/configs');
}
}.observes('isWorking', 'App.router.mainAlertInstancesController.isUpdating'),
@@ -621,6 +621,12 @@ App.UpdateController = Em.Controller.extend({
}
},
+ makeCallForClusterEnv: function(event) {
+ if (event.configs.someProperty('type', 'cluster-env')) {
+ this.updateClusterEnv();
+ }
+ },
+
//TODO - update service auto-start to use this
updateClusterEnv: function (callback) {
this.loadClusterConfig(callback).done(function (data) {
http://git-wip-us.apache.org/repos/asf/ambari/blob/11f16c83/ambari-web/app/controllers/main/dashboard/config_history_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/dashboard/config_history_controller.js b/ambari-web/app/controllers/main/dashboard/config_history_controller.js
index 197a88b..70e608c 100644
--- a/ambari-web/app/controllers/main/dashboard/config_history_controller.js
+++ b/ambari-web/app/controllers/main/dashboard/config_history_controller.js
@@ -233,11 +233,11 @@ App.MainConfigHistoryController = Em.ArrayController.extend(App.TableServerMixin
},
subscribeToUpdates: function() {
- App.StompClient.subscribe('/events/configs', this.load.bind(this));
+ App.StompClient.addHandler('/events/configs', 'history', this.load.bind(this));
},
unsubscribeOfUpdates: function() {
- App.StompClient.unsubscribe('/events/configs');
+ App.StompClient.removeHandler('/events/configs', 'history');
},
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/11f16c83/ambari-web/app/utils/stomp_client.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/stomp_client.js b/ambari-web/app/utils/stomp_client.js
index 1e63164..11a62b7 100644
--- a/ambari-web/app/utils/stomp_client.js
+++ b/ambari-web/app/utils/stomp_client.js
@@ -25,12 +25,13 @@ module.exports = Em.Object.extend({
client: null,
/**
- * TODO set actual url
- * @type string
+ * @type {string}
*/
webSocketUrl: 'ws://{hostname}:8080/api/stomp/v1',
- //TODO set actual url
+ /**
+ * @type {string}
+ */
sockJsUrl: 'http://{hostname}:8080/api/stomp/v1',
/**
@@ -43,6 +44,10 @@ module.exports = Em.Object.extend({
*/
isWebSocketSupported: true,
+ /**
+ * @type {number}
+ * @const
+ */
RECONNECT_TIMEOUT: 6000,
/**
@@ -56,6 +61,11 @@ module.exports = Em.Object.extend({
*/
headers: {},
+ /**
+ *
+ * @param {boolean} useSockJS
+ * @returns {$.Deferred}
+ */
connect: function(useSockJS) {
const dfd = $.Deferred();
const socket = this.getSocket(useSockJS);
@@ -98,8 +108,7 @@ module.exports = Em.Object.extend({
this.reconnect();
} else {
//if webSocket failed on initial connect then switch to SockJS
- //TODO enable when SockJS API provided
- //this.connect(true);
+ this.connect(true);
}
},
@@ -110,7 +119,10 @@ module.exports = Em.Object.extend({
this.connect().done(() => {
for (var i in subscriptions) {
subscriptions[i].unsubscribe();
- this.subscribe(subscriptions[i].destination, subscriptions[i].callback);
+ this.subscribe(subscriptions[i].destination, subscriptions[i].handlers['default']);
+ for (var key in subscriptions[i].handlers) {
+ key !== 'default' && this.addHandler(subscriptions[i].destination, key, subscriptions[i].handlers[key]);
+ }
}
});
}, this.RECONNECT_TIMEOUT);
@@ -137,23 +149,60 @@ module.exports = Em.Object.extend({
/**
*
* @param destination
- * @param callback
+ * @param {function} handler
* @returns {*}
*/
- subscribe: function(destination, callback = Em.K) {
- if (!this.get('client.connected')) {
+ subscribe: function(destination, handler = Em.K) {
+ const handlers = {
+ default: handler
+ };
+ if (!this.get('client.connected') || this.get('subscriptions')[destination]) {
return null;
}
const subscription = this.get('client').subscribe(destination, (message) => {
- callback(JSON.parse(message.body));
+ for (var i in handlers) {
+ handlers[i](JSON.parse(message.body));
+ }
});
subscription.destination = destination;
- subscription.callback = callback;
+ subscription.handlers = handlers;
this.get('subscriptions')[destination] = subscription;
return subscription;
},
/**
+ * If trying to add handler to not existing subscription then it will be created and handler added as default
+ * @param {string} destination
+ * @param {string} key
+ * @param {function} handler
+ */
+ addHandler: function(destination, key, handler) {
+ const subscription = this.get('subscriptions')[destination];
+ if (!subscription) {
+ this.subscribe(destination);
+ return this.addHandler(destination, key, handler);
+ }
+ if (subscription.handlers[key]) {
+ console.error('You can\'t override subscription handler');
+ return;
+ }
+ subscription.handlers[key] = handler;
+ },
+
+ /**
+ * If removed handler is last and subscription have zero handlers then topic will be unsubscribed
+ * @param {string} destination
+ * @param {string} key
+ */
+ removeHandler: function(destination, key) {
+ const subscription = this.get('subscriptions')[destination];
+ delete subscription.handlers[key];
+ if (Em.keys(subscription.handlers).length === 0) {
+ this.unsubscribe(destination);
+ }
+ },
+
+ /**
*
* @param {string} destination
* @returns {boolean}
http://git-wip-us.apache.org/repos/asf/ambari/blob/11f16c83/ambari-web/test/controllers/global/update_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/update_controller_test.js b/ambari-web/test/controllers/global/update_controller_test.js
index 0725944..efacf3a 100644
--- a/ambari-web/test/controllers/global/update_controller_test.js
+++ b/ambari-web/test/controllers/global/update_controller_test.js
@@ -72,14 +72,16 @@ describe('App.UpdateController', function () {
expect(App.StompClient.unsubscribe.calledWith('/events/hostcomponents')).to.be.true;
expect(App.StompClient.unsubscribe.calledWith('/events/alerts')).to.be.true;
expect(App.StompClient.unsubscribe.calledWith('/events/topologies')).to.be.true;
+ expect(App.StompClient.unsubscribe.calledWith('/events/configs')).to.be.true;
});
it('isWorking = true', function () {
controller.set('isWorking', true);
- expect(App.updater.run.callCount).to.equal(12);
+ expect(App.updater.run.callCount).to.equal(11);
expect(App.StompClient.subscribe.calledWith('/events/hostcomponents')).to.be.true;
expect(App.StompClient.subscribe.calledWith('/events/alerts')).to.be.true;
expect(App.StompClient.subscribe.calledWith('/events/topologies')).to.be.true;
+ expect(App.StompClient.subscribe.calledWith('/events/configs')).to.be.true;
});
});
@@ -676,4 +678,18 @@ describe('App.UpdateController', function () {
expect(args).to.exists;
});
});
+
+ describe('#makeCallForClusterEnv', function() {
+ beforeEach(function() {
+ sinon.stub(c, 'updateClusterEnv');
+ });
+ afterEach(function() {
+ c.updateClusterEnv.restore();
+ });
+
+ it('updateClusterEnv should be called', function() {
+ c.makeCallForClusterEnv({configs: [{type: 'cluster-env'}]});
+ expect(c.updateClusterEnv.calledOnce).to.be.true;
+ });
+ });
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/11f16c83/ambari-web/test/controllers/main/dashboard/config_history_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/dashboard/config_history_controller_test.js b/ambari-web/test/controllers/main/dashboard/config_history_controller_test.js
index 771fd16..b2b0442 100644
--- a/ambari-web/test/controllers/main/dashboard/config_history_controller_test.js
+++ b/ambari-web/test/controllers/main/dashboard/config_history_controller_test.js
@@ -133,29 +133,29 @@ describe('MainConfigHistoryController', function () {
describe('#subscribeToUpdates', function() {
beforeEach(function() {
- sinon.stub(App.StompClient, 'subscribe');
+ sinon.stub(App.StompClient, 'addHandler');
});
afterEach(function() {
- App.StompClient.subscribe.restore();
+ App.StompClient.addHandler.restore();
});
it('App.StompClient.subscribe should be called', function() {
controller.subscribeToUpdates();
- expect(App.StompClient.subscribe.calledWith('/events/configs')).to.be.true;
+ expect(App.StompClient.addHandler.calledWith('/events/configs', 'history')).to.be.true;
});
});
describe('#unsubscribeOfUpdates', function() {
beforeEach(function() {
- sinon.stub(App.StompClient, 'unsubscribe');
+ sinon.stub(App.StompClient, 'removeHandler');
});
afterEach(function() {
- App.StompClient.unsubscribe.restore();
+ App.StompClient.removeHandler.restore();
});
it('App.StompClient.subscribe should be called', function() {
controller.unsubscribeOfUpdates();
- expect(App.StompClient.unsubscribe.calledWith('/events/configs')).to.be.true;
+ expect(App.StompClient.removeHandler.calledWith('/events/configs', 'history')).to.be.true;
});
});
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/11f16c83/ambari-web/test/controllers/main_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main_test.js b/ambari-web/test/controllers/main_test.js
index 573b1e9..4ab423e 100644
--- a/ambari-web/test/controllers/main_test.js
+++ b/ambari-web/test/controllers/main_test.js
@@ -33,14 +33,20 @@ describe('App.MainController', function () {
initialize = true;
}
});
+ sinon.stub(App.StompClient, 'connect');
});
afterEach(function () {
App.router.get.restore();
+ App.StompClient.connect.restore();
});
it ('Should return true', function() {
mainController.initialize();
expect(initialize).to.be.true;
});
+ it ('App.StompClient.connect should be called', function() {
+ mainController.initialize();
+ expect(App.StompClient.connect.calledOnce).to.be.true;
+ });
});
describe('#dataLoading', function() {
http://git-wip-us.apache.org/repos/asf/ambari/blob/11f16c83/ambari-web/test/utils/stomp_client_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/stomp_client_test.js b/ambari-web/test/utils/stomp_client_test.js
index a85e6cc..5ee7a5e 100644
--- a/ambari-web/test/utils/stomp_client_test.js
+++ b/ambari-web/test/utils/stomp_client_test.js
@@ -20,10 +20,14 @@ var App = require('app');
var stompClientClass = require('utils/stomp_client');
describe('App.StompClient', function () {
- var stomp;
+ var stomp, mockStomp;
beforeEach(function() {
stomp = stompClientClass.create();
+ mockStomp = sinon.stub(Stomp, 'over').returns({connect: Em.K});
+ });
+ afterEach(function() {
+ Stomp.over.restore();
});
describe('#connect', function() {
@@ -31,31 +35,28 @@ describe('App.StompClient', function () {
sinon.stub(stomp, 'onConnectionSuccess');
sinon.stub(stomp, 'onConnectionError');
sinon.stub(stomp, 'getSocket');
- this.mockStomp = sinon.stub(Stomp, 'over');
});
afterEach(function() {
stomp.onConnectionSuccess.restore();
stomp.onConnectionError.restore();
stomp.getSocket.restore();
- this.mockStomp.restore();
});
it('onConnectionSuccess should be called', function() {
- this.mockStomp.returns({connect: function(headers, success, error) {
+ mockStomp.returns({connect: function(headers, success, error) {
success();
}});
stomp.connect();
expect(stomp.onConnectionSuccess.calledOnce).to.be.true;
});
it('onConnectionError should be called', function() {
- this.mockStomp.returns({connect: function(headers, success, error) {
+ mockStomp.returns({connect: function(headers, success, error) {
error();
}});
stomp.connect();
expect(stomp.onConnectionError.calledOnce).to.be.true;
});
it('should set client', function() {
- this.mockStomp.returns({connect: Em.K});
stomp.connect();
expect(stomp.get('client')).to.be.eql({
connect: Em.K,
@@ -83,9 +84,11 @@ describe('App.StompClient', function () {
describe('#onConnectionError', function() {
beforeEach(function() {
sinon.stub(stomp, 'reconnect');
+ sinon.stub(stomp, 'connect');
});
afterEach(function() {
stomp.reconnect.restore();
+ stomp.connect.restore();
});
it('reconnect should be called when isConnected true', function() {
@@ -93,6 +96,12 @@ describe('App.StompClient', function () {
stomp.onConnectionError();
expect(stomp.reconnect.calledOnce).to.be.true;
});
+
+ it('connect should be called when isConnected false', function() {
+ stomp.set('isConnected', false);
+ stomp.onConnectionError();
+ expect(stomp.connect.calledOnce).to.be.true;
+ });
});
describe('#reconnect', function() {
@@ -113,7 +122,7 @@ describe('App.StompClient', function () {
var subscriptions = {
'foo': {
destination: 'foo',
- callback: Em.K,
+ handlers: { default: Em.K },
unsubscribe: sinon.spy()
}
};
@@ -166,18 +175,64 @@ describe('App.StompClient', function () {
};
stomp.set('client', client);
expect(stomp.subscribe('foo')).to.be.eql({
- callback: Em.K,
+ handlers: { default: Em.K },
destination: 'foo',
id: 1
});
expect(stomp.get('subscriptions')['foo']).to.be.eql({
- callback: Em.K,
+ handlers: { default: Em.K },
destination: 'foo',
id: 1
});
});
});
+ describe('#addHandler', function() {
+ beforeEach(function() {
+ sinon.stub(stomp, 'subscribe', function(dest) {
+ stomp.get('subscriptions')[dest] = {
+ handlers: {}
+ };
+ });
+ });
+ afterEach(function() {
+ stomp.subscribe.restore();
+ });
+
+ it('should add handler and subscribe because there is no subscription', function() {
+ stomp.addHandler('dest1', 'handler1', Em.K);
+ expect(stomp.subscribe.calledWith('dest1')).to.be.true;
+ expect(stomp.get('subscriptions')['dest1'].handlers).to.be.eql({handler1: Em.K});
+ });
+ it('should add handler', function() {
+ stomp.get('subscriptions')['dest2'] = {
+ handlers: {}
+ };
+ stomp.addHandler('dest2', 'handler2', Em.K);
+ expect(stomp.get('subscriptions')['dest2'].handlers).to.be.eql({handler2: Em.K});
+ });
+ });
+
+ describe('#removeHandler', function() {
+ beforeEach(function() {
+ sinon.stub(stomp, 'unsubscribe');
+ });
+ afterEach(function() {
+ stomp.unsubscribe.restore();
+ });
+
+ it('should remove handler', function() {
+ stomp.get('subscriptions')['dest1'] = {
+ handlers: {
+ handler1: Em.K
+ }
+ };
+ stomp.removeHandler('dest1', 'handler1');
+ expect(stomp.get('subscriptions')['dest1'].handlers).to.be.empty;
+ expect(stomp.unsubscribe.calledOnce).to.be.true;
+ });
+ });
+
describe('#unsubscribe', function() {
it('should not unsubscribe when no subscription found', function() {
stomp.set('subscriptions', {});