You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ja...@apache.org on 2014/12/05 02:02:18 UTC
ambari git commit: AMBARI-8552. Batch the call to create and install
hostComponents in the wizard progress page controller mixin. (jaimin)
Repository: ambari
Updated Branches:
refs/heads/trunk 356309d16 -> 96c9e2045
AMBARI-8552. Batch the call to create and install hostComponents in the wizard progress page controller mixin. (jaimin)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/96c9e204
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/96c9e204
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/96c9e204
Branch: refs/heads/trunk
Commit: 96c9e2045f5b30b1289846c60528deaddbc6a423
Parents: 356309d
Author: Jaimin Jetly <ja...@hortonworks.com>
Authored: Thu Dec 4 17:01:26 2014 -0800
Committer: Jaimin Jetly <ja...@hortonworks.com>
Committed: Thu Dec 4 17:01:33 2014 -0800
----------------------------------------------------------------------
ambari-web/app/assets/test/tests.js | 1 +
.../wizard/wizardProgressPageController.js | 139 ++++++++++++-------
.../wizard/wizardProgressPageController_test.js | 138 ++++++++++++++++++
3 files changed, 225 insertions(+), 53 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/96c9e204/ambari-web/app/assets/test/tests.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js
index 77f2869..35a80cf 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -128,6 +128,7 @@ var files = ['test/init_model_test',
'test/mixins/common/table_server_view_mixin_test',
'test/mixins/main/host/details/host_components/decommissionable_test',
'test/mixins/wizard/wizard_menu_view_test',
+ 'test/mixins/wizard/wizardProgressPageController_test',
'test/utils/ajax/ajax_test',
'test/utils/ajax/ajax_queue_test',
'test/utils/batch_scheduled_requests_test',
http://git-wip-us.apache.org/repos/asf/ambari/blob/96c9e204/ambari-web/app/mixins/wizard/wizardProgressPageController.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/wizard/wizardProgressPageController.js b/ambari-web/app/mixins/wizard/wizardProgressPageController.js
index 074d249..63a5fc7 100644
--- a/ambari-web/app/mixins/wizard/wizardProgressPageController.js
+++ b/ambari-web/app/mixins/wizard/wizardProgressPageController.js
@@ -177,8 +177,8 @@ App.wizardProgressPageControllerMixin = Em.Mixin.create({
/**
* check whether component installed on specified hosts
- * @param componentName
- * @param hostNames
+ * @param {string} componentName
+ * @param {string[]} hostNames
* @return {$.ajax}
*/
checkInstalledComponents: function (componentName, hostNames) {
@@ -188,49 +188,73 @@ App.wizardProgressPageControllerMixin = Em.Mixin.create({
data: {
componentName: componentName,
hostNames: hostNames.join(',')
- },
- success: 'checkInstalledComponentsSuccessCallback'
+ }
});
},
- checkInstalledComponentsSuccessCallback: function (data, opt, params) {
- installedComponents = data.items;
- },
-
+
+ /**
+ * Create component on single or multiple hosts.
+ *
+ * @method createComponent
+ * @param {string} componentName - name of the component
+ * @param {(string|string[])} hostName - host/hosts where components should be installed
+ * @param {string} serviceName - name of the services
+ */
createComponent: function (componentName, hostName, serviceName) {
var hostNames = (Array.isArray(hostName)) ? hostName : [hostName];
var self = this;
- this.checkInstalledComponents(componentName, hostNames).complete(function () {
- var result = [];
-
- hostNames.forEach(function (hostName) {
- result.push({
+ this.checkInstalledComponents(componentName, hostNames).then(function (data) {
+ var hostsWithComponents = data.items.mapProperty('HostRoles.host_name');
+ var result = hostNames.map(function(item) {
+ return {
componentName: componentName,
- hostName: hostName,
- hasComponent: installedComponents.someProperty('HostRoles.host_name', hostName)
- });
+ hostName: item,
+ hasComponent: hostsWithComponents.contains(item)
+ };
});
-
- result.forEach(function (host, index, array) {
- if (!host.hasComponent) {
- App.ajax.send({
- name: 'admin.high_availability.create_component',
- sender: this,
- data: {
- hostName: host.hostName,
- componentName: host.componentName,
- serviceName: serviceName,
- taskNum: array.length
- },
- success: 'onCreateComponent',
- error: 'onCreateComponentError'
- });
- } else {
- // Simulates format returned from ajax.send
- this.onCreateComponent(null, null, {hostName: host.hostName, componentName: host.componentName, taskNum: array.length});
+ var hostsWithoutComponents = result.filterProperty('hasComponent', false).mapProperty('hostName');
+ var taskNum = 1;
+ var requestData = {
+ "RequestInfo": {
+ "query": hostsWithoutComponents.map(function(item) {
+ return 'Hosts/host_name=' + item;
+ }).join('|')
+ },
+ "Body": {
+ "host_components": [
+ {
+ "HostRoles": {
+ "component_name": componentName
+ }
+ }
+ ]
}
- }, self)
+ };
+ if (!!hostsWithoutComponents.length) {
+ App.ajax.send({
+ name: 'wizard.step8.register_host_to_component',
+ sender: self,
+ data: {
+ data: JSON.stringify(requestData),
+ hostName: result.mapProperty('hostName'),
+ componentName: componentName,
+ serviceName: serviceName,
+ taskNum: taskNum,
+ cluster: App.get('clusterName')
+ },
+ success: 'onCreateComponent',
+ error: 'onCreateComponent'
+ });
+ } else {
+ self.onCreateComponent(null, null, {
+ hostName: result.mapProperty('hostName'),
+ componentName: componentName,
+ serviceName: serviceName,
+ taskNum: taskNum
+ }, self);
+ }
});
},
@@ -250,29 +274,38 @@ App.wizardProgressPageControllerMixin = Em.Mixin.create({
}
},
+ /**
+ * Update component status on selected hosts.
+ *
+ * @param {string} componentName
+ * @param {(string|string[])} hostName
+ * @param {string} serviceName
+ * @param {string} context
+ * @param {number} taskNum
+ * @returns {$.ajax}
+ */
updateComponent: function (componentName, hostName, serviceName, context, taskNum) {
if (!(hostName instanceof Array)) {
hostName = [hostName];
}
var state = context.toLowerCase() == "start" ? "STARTED" : "INSTALLED";
- for (var i = 0; i < hostName.length; i++) {
- App.ajax.send({
- name: 'common.host.host_component.update',
- sender: this,
- data: {
- context: context + " " + App.format.role(componentName),
- hostName: hostName[i],
- serviceName: serviceName,
- componentName: componentName,
- taskNum: taskNum || hostName.length,
- HostRoles: {
- state: state
- }
+ return App.ajax.send({
+ name: 'common.host_components.update',
+ sender: this,
+ data: {
+ HostRoles: {
+ state: state
},
- success: 'startPolling',
- error: 'onTaskError'
- });
- }
+ query: 'HostRoles/component_name=' + componentName + '&HostRoles/host_name.in(' + hostName.join(',') + ')&HostRoles/maintenance_state=OFF',
+ context: context + " " + App.format.role(componentName),
+ hostName: hostName,
+ taskNum: taskNum || 1,
+ componentName: componentName,
+ serviceName: serviceName
+ },
+ success: 'startPolling',
+ error: 'onTaskError'
+ });
},
startPolling: function (data) {
@@ -332,7 +365,7 @@ App.wizardProgressPageControllerMixin = Em.Mixin.create({
var progress = Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsPerHost * 100);
this.get('tasks').findProperty('id', currentTaskId).set('progress', progress);
window.setTimeout(function () {
- self.doPolling()
+ self.doPolling();
}, self.POLL_INTERVAL);
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/96c9e204/ambari-web/test/mixins/wizard/wizardProgressPageController_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mixins/wizard/wizardProgressPageController_test.js b/ambari-web/test/mixins/wizard/wizardProgressPageController_test.js
new file mode 100644
index 0000000..d72b3f6
--- /dev/null
+++ b/ambari-web/test/mixins/wizard/wizardProgressPageController_test.js
@@ -0,0 +1,138 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+describe('App.wizardProgressPageControllerMixin', function() {
+ var mixedObject = Em.Object.extend(App.wizardProgressPageControllerMixin, {});
+
+ describe('#createComponent', function() {
+ var mixedObjectInstance;
+ beforeEach(function() {
+ mixedObjectInstance = mixedObject.create({});
+ sinon.stub(App.ajax, 'send', function(params) {
+ return params;
+ });
+ sinon.spy(mixedObjectInstance, 'onCreateComponent');
+ sinon.spy(mixedObjectInstance, 'updateComponent');
+ sinon.stub(mixedObjectInstance, 'checkInstalledComponents', function(componentName, hostNames) {
+ var def = $.Deferred();
+ var data = {
+ 'ZOOKEEPER_SERVER': {
+ items: []
+ },
+ 'ZOOKEEPER_CLIENT': {
+ items: [
+ { HostRoles: { host_name: 'host1' } }
+ ]
+ }
+ };
+ def.resolve(data[componentName]);
+ return def.promise();
+ });
+ });
+
+ afterEach(function() {
+ App.ajax.send.restore();
+ mixedObjectInstance.onCreateComponent.restore();
+ mixedObjectInstance.updateComponent.restore();
+ mixedObjectInstance.checkInstalledComponents.restore();
+ });
+
+ it('should call `checkInstalledComponents` method', function() {
+ mixedObjectInstance.createComponent('ZOOKEEPER_SERVER', 'host1', 'ZOOKEEPER');
+ expect(mixedObjectInstance.checkInstalledComponents.called).to.be.true;
+ });
+
+ it('should call `checkInstalledComponents` method with host name converted to Array', function() {
+ mixedObjectInstance.createComponent('ZOOKEEPER_SERVER', 'host1', 'ZOOKEEPER');
+ expect(mixedObjectInstance.checkInstalledComponents.calledWith('ZOOKEEPER_SERVER', ['host1'])).to.be.true;
+ });
+
+ it('no ZooKeeper Servers installed. install on host1, host2. ajax request should be called with appropriate params', function() {
+ mixedObjectInstance.createComponent('ZOOKEEPER_SERVER', ['host1', 'host2'], 'ZOOKEEPER');
+ var args = App.ajax.send.args[0][0];
+ var queryObject = JSON.parse(args.data.data);
+ expect(args.data.hostName).to.be.eql(['host1', 'host2']);
+ expect(queryObject.RequestInfo.query).to.be.eql('Hosts/host_name=host1|Hosts/host_name=host2');
+ expect(queryObject.Body.host_components[0].HostRoles.component_name).to.be.eql('ZOOKEEPER_SERVER');
+ expect(args.data.taskNum).to.be.eql(1);
+ // invoke callback
+ args.sender[args.success].apply(args.sender, [null, null, args.data]);
+ expect(mixedObjectInstance.updateComponent.called).to.be.true;
+ });
+
+ it('ZooKeeper Client installed on host1. install on host1, host2. ajax request should be called with appropriate params', function() {
+ mixedObjectInstance.createComponent('ZOOKEEPER_CLIENT', ['host1', 'host2'], 'ZOOKEEPER');
+ var args = App.ajax.send.args[0][0];
+ var queryObject = JSON.parse(args.data.data);
+ expect(args.data.hostName).to.be.eql(['host1', 'host2']);
+ expect(queryObject.RequestInfo.query).to.be.eql('Hosts/host_name=host2');
+ expect(queryObject.Body.host_components[0].HostRoles.component_name).to.be.eql('ZOOKEEPER_CLIENT');
+ expect(mixedObjectInstance.onCreateComponent.called).to.be.false;
+ // invoke callback
+ args.sender[args.success].apply(args.sender, [null, null, args.data]);
+ expect(mixedObjectInstance.updateComponent.called).to.be.true;
+ });
+ });
+
+ describe('#updateComponent', function() {
+ var testsAjax = [
+ {
+ callParams: ['ZOOKEEPER_SERVER', 'host1', 'ZOOKEEPER', 'Install', 1],
+ e: [
+ { key: 'data.HostRoles.state', value: 'INSTALLED'},
+ { key: 'data.hostName[0]', value: 'host1'},
+ { key: 'data.query', value: 'HostRoles/component_name=ZOOKEEPER_SERVER&HostRoles/host_name.in(host1)&HostRoles/maintenance_state=OFF'}
+ ]
+ },
+ {
+ callParams: ['ZOOKEEPER_SERVER', ['host1', 'host2'], 'ZOOKEEPER', 'start', 1],
+ e: [
+ { key: 'data.HostRoles.state', value: 'STARTED'},
+ { key: 'data.hostName[0]', value: 'host1'},
+ { key: 'data.hostName[1]', value: 'host2'},
+ { key: 'data.query', value: 'HostRoles/component_name=ZOOKEEPER_SERVER&HostRoles/host_name.in(host1,host2)&HostRoles/maintenance_state=OFF'}
+ ]
+ }
+ ];
+
+ testsAjax.forEach(function(test) {
+ describe('called with params: ' + JSON.stringify(test.callParams), function() {
+ before(function() {
+ sinon.stub(App.ajax, 'send', Em.K);
+ var mixedObjectInstance = mixedObject.create({});
+ mixedObjectInstance.updateComponent.apply(mixedObjectInstance, test.callParams);
+ });
+
+ after(function() {
+ App.ajax.send.restore();
+ });
+
+ test.e.forEach(function(eKey) {
+ it('key: {0} should have value: {1}'.format(eKey.key, eKey.value), function() {
+ var args = App.ajax.send.args[0][0];
+ expect(args).to.have.deep.property(eKey.key, eKey.value);
+ });
+ });
+ });
+ });
+ });
+
+
+});