Repository: ambari Updated Branches: refs/heads/trunk b95615065 -> 16e04b2ba
AMBARI-15309 UI: ability to perform bulk delete host components (zhewang) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/16e04b2b Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/16e04b2b Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/16e04b2b Branch: refs/heads/trunk Commit: 16e04b2ba3eaeedf6d6633b43c6e001593de9198 Parents: b956150 Author: Zhe (Joe) Wang <[email protected]> Authored: Fri Aug 26 14:58:07 2016 -0700 Committer: Zhe (Joe) Wang <[email protected]> Committed: Fri Aug 26 14:58:24 2016 -0700 ---------------------------------------------------------------------- .../main/host/bulk_operations_controller.js | 194 +++++++++++++++++++ ambari-web/app/messages.js | 6 + ambari-web/app/utils/ajax/ajax.js | 10 + .../views/main/host/hosts_table_menu_view.js | 11 ++ 4 files changed, 221 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/16e04b2b/ambari-web/app/controllers/main/host/bulk_operations_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/host/bulk_operations_controller.js b/ambari-web/app/controllers/main/host/bulk_operations_controller.js index 0e73c0c..aca50bf 100644 --- a/ambari-web/app/controllers/main/host/bulk_operations_controller.js +++ b/ambari-web/app/controllers/main/host/bulk_operations_controller.js @@ -41,6 +41,9 @@ App.BulkOperationsController = Em.Controller.extend({ else if (operationData.action === 'ADD') { this.bulkOperationForHostComponentsAdd(operationData, hosts); } + else if (operationData.action === 'DELETE') { + this.bulkOperationForHostComponentsDelete(operationData, hosts); + } else { if (operationData.action.indexOf('DECOMMISSION') == -1) { this.bulkOperationForHostComponents(operationData, hosts); @@ -644,6 +647,197 @@ App.BulkOperationsController = Em.Controller.extend({ }, /** + * Confirm bulk delete for selected hostComponent + * @param {Object} operationData - data about bulk operation (action, hostComponent etc) + * @param {Array} hosts - list of affected hosts + */ + bulkOperationForHostComponentsDelete: function (operationData, hosts) { + var self = this; + return batchUtils.getComponentsFromServer({ + components: [operationData.componentName], + hosts: hosts.mapProperty('hostName'), + displayParams: ['host_components/HostRoles/state'] + }, function (data) { + return self._getComponentsFromServerForHostComponentsDeleteCallback(operationData, data); + }); + }, + + _getComponentsFromServerForHostComponentsDeleteCallback: function (operationData, data) { + var self = this; + var minToInstall = App.StackServiceComponent.find(operationData.componentName).get('minToInstall'); + var installedCount = App.HostComponent.getCount(operationData.componentName, 'totalCount'); + var installedHosts = data.items.mapProperty('Hosts.host_name'); + var hostsToDelete = data.items.filter(function (host) { + var state = host.host_components[0].HostRoles.state; + return [App.HostComponentStatus.stopped, App.HostComponentStatus.unknown, App.HostComponentStatus.install_failed, App.HostComponentStatus.upgrade_failed, App.HostComponentStatus.init].contains(state); + }).mapProperty('Hosts.host_name'); + + if (!hostsToDelete.length) { + return App.ModalPopup.show({ + header: Em.I18n.t('rolling.nothingToDo.header'), + body: Em.I18n.t('hosts.bulkOperation.confirmation.delete.component.nothingToDo.body').format(operationData.componentNameFormatted), + secondary: false + }); + } + if (installedCount - hostsToDelete.length < minToInstall) { + return App.ModalPopup.show({ + header: Em.I18n.t('rolling.nothingToDo.header'), + body: Em.I18n.t('hosts.bulkOperation.confirmation.delete.component.minimum.body').format(minToInstall, operationData.componentNameFormatted), + secondary: false + }); + } + + var hostsToSkip = installedHosts.filter(function (host) { + return !hostsToDelete.contains(host); + }); + + var minShown = 3; + + return App.ModalPopup.show({ + header: Em.I18n.t('hosts.bulkOperation.confirmation.header'), + hostNames: hostsToDelete.join("\n"), + visibleHosts: self._showHostNames(hostsToDelete, "\n", minShown), + hostNamesSkippedVisible: self._showHostNames(hostsToSkip, "\n", minShown), + expanded: false, + + hostNamesSkipped: function() { + return hostsToSkip.length ? hostsToSkip.join("\n") : false; + }.property(), + + didInsertElement: function() { + this.set('expanded', hostsToDelete.length <= minShown); + }, + + onPrimary: function() { + self.bulkDeleteHostComponents(operationData, hostsToDelete); + this._super(); + }, + bodyClass: Em.View.extend({ + templateName: require('templates/main/host/bulk_operation_confirm_popup'), + message: Em.I18n.t('hosts.bulkOperation.confirmation.add.component').format(operationData.message, operationData.componentNameFormatted, hostsToDelete.length), + warningInfo: Em.I18n.t('hosts.bulkOperation.confirmation.delete.component.skip').format(operationData.componentNameFormatted), + textareaVisible: false, + textTrigger: function() { + this.toggleProperty('textareaVisible'); + }, + + showAll: function() { + this.set('parentView.visibleHosts', this.get('parentView.hostNames')); + this.set('parentView.hostNamesSkippedVisible', this.get('parentView.hostNamesSkipped')); + this.set('parentView.expanded', true); + }, + putHostNamesToTextarea: function() { + var hostNames = this.get('parentView.hostNames'); + if (this.get('textareaVisible')) { + var wrapper = $(".task-detail-log-maintext"); + $('.task-detail-log-clipboard').html(hostNames).width(wrapper.width()).height(250); + Em.run.next(function() { + $('.task-detail-log-clipboard').select(); + }); + } + }.observes('textareaVisible') + }) + }); + }, + + /** + * Bulk delete for selected hostComponent + * @param {Object} operationData - data about bulk operation (action, hostComponent etc) + * @param {Array} hostNames - list of affected hosts' names + */ + bulkDeleteHostComponents: function (operationData, hostNames) { + var self= this; + App.get('router.mainAdminKerberosController').getKDCSessionState(function () { + App.ajax.send({ + name: 'host.host_component.delete_components', + sender: self, + data: { + data: JSON.stringify({ + RequestInfo: { + query: 'HostRoles/host_name.in(' + hostNames.join(',') + ')&HostRoles/component_name.in(' + operationData.componentName + ')' + } + }) + }, + success: 'bulkOperationForHostComponentsDeleteCallback' + }); + }); + }, + + /** + * Show popup after bulk delete host_components + * @method bulkOperationForHostComponentsDeleteCallback + */ + bulkOperationForHostComponentsDeleteCallback: function (arg0, arg1, arg2, arg3, arg4) { + var deletedHosts = []; + var undeletableHosts = []; + if (arg1 == "error") { + var request = arg0; + var params = arg4; + var response = JSON.parse(request.responseText); + var host = Ember.Object.create({ + error: { + key: params.hosts[0], + code: response.status, + message: response.message + }, + isCollapsed: true, + isBodyVisible: Em.computed.ifThenElse('isCollapsed', 'display: none;', 'display: block;') + }); + undeletableHosts.push(host); + } else { + var data = arg0; + var params = arg2; + if (data) { + data.deleteResult.forEach(function (host) { + if (host.deleted) { + deletedHosts.push(host); + } else { + var _host = Ember.Object.create({ + error: host.error, + isCollapsed: true, + isBodyVisible: Em.computed.ifThenElse('isCollapsed', 'display: none;', 'display: block;') + }); + undeletableHosts.push(_host); + } + }); + } else { + var host = { + deleted: { + key: params.hosts[0] + } + }; + deletedHosts.push(host); + } + } + + return App.ModalPopup.show({ + header: Em.I18n.t('hosts.bulkOperation.delete.component.result.header'), + + secondary: null, + + bodyClass: Em.View.extend({ + templateName: require('templates/main/host/delete_hosts_result_popup'), + message: Em.I18n.t('hosts.bulkOperation.delete.component.dryRun.message').format(undeletableHosts.length), + undeletableHosts: undeletableHosts, + deletedHosts: deletedHosts, + onToggleHost: function (host) { + host.contexts[0].toggleProperty('isCollapsed'); + } + }), + + onPrimary: function () { + location.reload(); + this._super(); + }, + + onClose: function () { + location.reload(); + this._super(); + } + }); + }, + + /** * Bulk operation for selected hostComponents * @param {Object} operationData - data about bulk operation (action, hostComponents etc) * @param {Array} hosts - list of affected hosts http://git-wip-us.apache.org/repos/asf/ambari/blob/16e04b2b/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 4cf3564..b216918 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -2446,6 +2446,12 @@ Em.I18n.translations = { 'hosts.bulkOperation.deleteHosts.confirmation.body.msg4': 'If the hosts were hosting a Zookeeper Server, the Zookeeper Service should be restarted. Go to the <i>Services</i> page.', 'hosts.bulkOperation.deleteHosts.result.header':'Delete Hosts', 'hosts.bulkOperation.deleteHosts.result.body': 'The following hosts were deleted successfully:', + 'hosts.bulkOperation.confirmation.delete.component.minimum.body': 'At least {0} {1} should be installed in the cluster.', + 'hosts.bulkOperation.confirmation.delete.component.nothingToDo.body': '{0} are neither installed on selected hosts nor in the states that can be deleted.', + 'hosts.bulkOperation.confirmation.delete.component.skip':'The following hosts are skipped as {0} on them are not in the states that can be deleted.', + 'hosts.bulkOperation.delete.component.result.header':'Delete Hosts', + 'hosts.bulkOperation.delete.component.result.body': 'The following hosts were deleted successfully:', + 'hosts.bulkOperation.delete.component.dryRun.message':'There are <strong>{0} host(s)</strong> that cannot be deleted (expand for reason):', 'hosts.selectHostsDialog.title': 'Select Configuration Group Hosts', 'hosts.selectHostsDialog.message': 'Select hosts that should belong to this {0} Configuration Group. All hosts belonging to this group will have the same set of configurations.', http://git-wip-us.apache.org/repos/asf/ambari/blob/16e04b2b/ambari-web/app/utils/ajax/ajax.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js index 5538e6d..dd15f9f 100644 --- a/ambari-web/app/utils/ajax/ajax.js +++ b/ambari-web/app/utils/ajax/ajax.js @@ -924,6 +924,16 @@ var urls = { } }, + 'host.host_component.delete_components': { + 'real': '/clusters/{clusterName}/host_components', + 'format': function (data) { + return { + type: 'DELETE', + data: data.data + } + } + }, + 'host.host_component.slave_desired_admin_state': { 'real': '/clusters/{clusterName}/hosts/{hostName}/host_components/{componentName}/?fields=HostRoles/desired_admin_state', 'mock': '/data/hosts/HDP2/decommission_state.json' http://git-wip-us.apache.org/repos/asf/ambari/blob/16e04b2b/ambari-web/app/views/main/host/hosts_table_menu_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/host/hosts_table_menu_view.js b/ambari-web/app/views/main/host/hosts_table_menu_view.js index dccffaa..8849244 100644 --- a/ambari-web/app/views/main/host/hosts_table_menu_view.js +++ b/ambari-web/app/views/main/host/hosts_table_menu_view.js @@ -136,6 +136,17 @@ App.HostTableMenuView = Em.View.extend({ serviceName: content.serviceName, componentNameFormatted: content.componentNameFormatted }) + }), + O.create({ + label: Em.I18n.t('common.delete'), + delete: true, + operationData: O.create({ + action: 'DELETE', + message: Em.I18n.t('common.delete'), + componentName: content.componentName, + serviceName: content.serviceName, + componentNameFormatted: content.componentNameFormatted + }) }) ]) }
