Repository: ambari Updated Branches: refs/heads/branch-2.5 8581975f9 -> 4db1a1e98
AMBARI-10908 Usability: ability to perform bulk delete host (zhewang) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/4db1a1e9 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/4db1a1e9 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/4db1a1e9 Branch: refs/heads/branch-2.5 Commit: 4db1a1e982fba628bf876c8bf983ea49b2fdec3a Parents: 8581975 Author: Zhe (Joe) Wang <[email protected]> Authored: Tue Jun 7 11:24:41 2016 -0700 Committer: Zhe (Joe) Wang <[email protected]> Committed: Tue Sep 13 13:06:00 2016 -0700 ---------------------------------------------------------------------- .../main/host/bulk_operations_controller.js | 202 +++++++++++++++++++ ambari-web/app/messages.js | 12 ++ ambari-web/app/styles/application.less | 4 + .../main/host/delete_hosts_dry_run_popup.hbs | 34 ++++ .../templates/main/host/delete_hosts_popup.hbs | 32 +++ .../main/host/delete_hosts_result_popup.hbs | 44 ++++ ambari-web/app/utils/ajax/ajax.js | 14 ++ .../views/main/host/hosts_table_menu_view.js | 9 + 8 files changed, 351 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/4db1a1e9/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 09d6a52..0e73c0c 100644 --- a/ambari-web/app/controllers/main/host/bulk_operations_controller.js +++ b/ambari-web/app/controllers/main/host/bulk_operations_controller.js @@ -61,6 +61,9 @@ App.BulkOperationsController = Em.Controller.extend({ else if (operationData.action === 'REINSTALL'){ this.bulkOperationForHostsReinstall(operationData, hosts); } + else if (operationData.action === 'DELETE'){ + this.bulkOperationForHostsDeleteDryRun(operationData, hosts); + } else { if (operationData.action === 'PASSIVE_STATE') { this.bulkOperationForHostsPassiveState(operationData, hosts); @@ -255,6 +258,205 @@ App.BulkOperationsController = Em.Controller.extend({ }, /** + * Calling dry_run for bulk delete selected hosts + * @param {Object} operationData - data about bulk operation (action, hostComponents etc) + * @param {Ember.Enumerable} hosts - list of affected hosts + */ + bulkOperationForHostsDeleteDryRun: function (operationData, hosts) { + var self = this; + App.get('router.mainAdminKerberosController').getKDCSessionState(function () { + return App.ajax.send({ + name: 'common.hosts.delete', + sender: self, + data: { + urlParams: "/?dry_run=true", + query: 'Hosts/host_name.in(' + hosts.mapProperty('hostName').join(',') + ')', + hosts: hosts.mapProperty('hostName') + }, + success: 'bulkOperationForHostsDeleteDryRunCallback', + error: 'bulkOperationForHostsDeleteDryRunCallback' + }); + }); + }, + + /** + * Show popup after dry_run for bulk delete hosts + * @method bulkOperationForHostsDeleteDryRunCallback + */ + bulkOperationForHostsDeleteDryRunCallback: function (arg0, arg1, arg2, arg3, arg4) { + var self = this; + var deletableHosts = []; + 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) { + deletableHosts.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] + } + }; + deletableHosts.push(host); + } + } + + if (undeletableHosts.length) { + return App.ModalPopup.show({ + header: Em.I18n.t('hosts.bulkOperation.deleteHosts.dryRun.header'), + + primary: deletableHosts.length ? Em.I18n.t('hosts.bulkOperation.deleteHosts.dryRun.primary').format(deletableHosts.length) : null, + + onPrimary: function () { + this._super(); + self.bulkOperationForHostsDelete(deletableHosts); + }, + bodyClass: Em.View.extend({ + templateName: require('templates/main/host/delete_hosts_dry_run_popup'), + message: Em.I18n.t('hosts.bulkOperation.deleteHosts.dryRun.message').format(undeletableHosts.length), + undeletableHosts: undeletableHosts, + onToggleHost: function (host) { + host.contexts[0].toggleProperty('isCollapsed'); + } + }) + }); + } else if (deletableHosts.length) { + this.bulkOperationForHostsDelete(deletableHosts); + } + }, + + /** + * Bulk delete selected hosts + * @param {Ember.Enumerable} hosts - list of affected hosts + */ + bulkOperationForHostsDelete: function (hosts) { + var self = this; + App.get('router.mainAdminKerberosController').getKDCSessionState(function () { + return App.ModalPopup.show({ + header: Em.I18n.t('hosts.bulkOperation.deleteHosts.confirmation.header'), + + onPrimary: function () { + this._super(); + return App.ajax.send({ + name: 'common.hosts.delete', + sender: self, + data: { + query: 'Hosts/host_name.in(' + hosts.mapProperty('deleted.key').join(',') + ')', + hosts: hosts.mapProperty('deleted.key') + }, + success: 'bulkOperationForHostsDeleteCallback', + error: 'bulkOperationForHostsDeleteCallback' + }); + }, + bodyClass: Em.View.extend({ + templateName: require('templates/main/host/delete_hosts_popup'), + hosts: hosts + }) + }); + }); + }, + + /** + * Show popup after bulk delete hosts + * @method bulkOperationForHostsDeleteCallback + */ + bulkOperationForHostsDeleteCallback: 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.deleteHosts.result.header'), + + secondary: null, + + bodyClass: Em.View.extend({ + templateName: require('templates/main/host/delete_hosts_result_popup'), + message: Em.I18n.t('hosts.bulkOperation.deleteHosts.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 turn on/off passive state for selected hosts * @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/4db1a1e9/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 076aa6d..751f64f 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -2404,6 +2404,17 @@ Em.I18n.translations = { 'hosts.bulkOperation.confirmation.add.component':'You are going to <strong>{0} {1}</strong> on the following {2} hosts.', 'hosts.bulkOperation.confirmation.add.component.skip':'The following hosts are skipped as they already have {0} installed.', 'hosts.bulkOperation.confirmation.add.component.nothingToDo.body': 'All the selected hosts have {0} installed already.', + 'hosts.bulkOperation.deleteHosts.dryRun.header':'Confirm Bulk Delete Hosts', + 'hosts.bulkOperation.deleteHosts.dryRun.message':'There are <strong>{0} host(s)</strong> that cannot be deleted (expand for reason):', + 'hosts.bulkOperation.deleteHosts.dryRun.primary':'Delete The Other {0} Host(s)', + 'hosts.bulkOperation.deleteHosts.confirmation.header':'Confirm Bulk Delete Hosts', + 'hosts.bulkOperation.deleteHosts.confirmation.body': 'Are you sure you want to delete host(s):', + 'hosts.bulkOperation.deleteHosts.confirmation.body.msg1': 'By removing above hosts, Ambari will ignore future communication from them. Software packages will not be removed from the hosts. The components on the hosts should not be restarted. If you wish to readd the hosts to the cluster, be sure to clean them.', + 'hosts.bulkOperation.deleteHosts.confirmation.body.msg2': '<b>WARNING!</b> If the agent is still heartbeating, the hosts will still exist in the database.', + 'hosts.bulkOperation.deleteHosts.confirmation.body.msg3': 'To completely delete the hosts, first stop ambari-agent on them.', + '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.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.', @@ -2478,6 +2489,7 @@ Em.I18n.translations = { 'hosts.host.details.startAllComponents':'Start All Components', 'hosts.host.details.stopAllComponents':'Stop All Components', 'hosts.host.details.restartAllComponents':'Restart All Components', + 'hosts.host.details.deleteHosts':'Delete Hosts', 'hosts.host.details.refreshConfigs':'Refresh configs', 'hosts.host.details.for.postfix':'{0} for host', 'hosts.host.details.setRackId':'Set Rack', http://git-wip-us.apache.org/repos/asf/ambari/blob/4db1a1e9/ambari-web/app/styles/application.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less index 691580d..7fb5639 100644 --- a/ambari-web/app/styles/application.less +++ b/ambari-web/app/styles/application.less @@ -6165,6 +6165,10 @@ input[type="radio"].align-checkbox, input[type="checkbox"].align-checkbox { background-color: #FFFFFF; } +.accordion-heading { + background-color: #f0f0f0; +} + .config-manage-nav { .config-groups-dropdown { display: inline-block; http://git-wip-us.apache.org/repos/asf/ambari/blob/4db1a1e9/ambari-web/app/templates/main/host/delete_hosts_dry_run_popup.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/host/delete_hosts_dry_run_popup.hbs b/ambari-web/app/templates/main/host/delete_hosts_dry_run_popup.hbs new file mode 100644 index 0000000..7424459 --- /dev/null +++ b/ambari-web/app/templates/main/host/delete_hosts_dry_run_popup.hbs @@ -0,0 +1,34 @@ +{{! +* 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. +}} +<p>{{{view.message}}}</p> +{{#each host in view.undeletableHosts}} + <div class="accordion"> + <div class="accordion-heading" {{action "onToggleHost" host target="view"}}> + <i {{bindAttr class=":pull-left :accordion-toggle host.isCollapsed:icon-caret-right:icon-caret-down"}}></i> + <a class="accordion-toggle"> + <p>{{host.error.key}}</p> + </a> + </div> + + <div class="accordion-body collapse in" {{bindAttr style="host.isBodyVisible"}}> + <div class="accordion-inner"> + <p>{{host.error.message}}</p> + </div> + </div> + </div> +{{/each}} http://git-wip-us.apache.org/repos/asf/ambari/blob/4db1a1e9/ambari-web/app/templates/main/host/delete_hosts_popup.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/host/delete_hosts_popup.hbs b/ambari-web/app/templates/main/host/delete_hosts_popup.hbs new file mode 100644 index 0000000..d45dab8 --- /dev/null +++ b/ambari-web/app/templates/main/host/delete_hosts_popup.hbs @@ -0,0 +1,32 @@ +{{! +* 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. +}} +<p><i class="icon-warning-sign"></i> {{t hosts.bulkOperation.deleteHosts.confirmation.body}}</p> +{{#each host in view.hosts}} + <div><i>{{{host.deleted.key}}}</i></div> +{{/each}} +<br /> +<div class='alert'>{{{t common.important.strong}}} + {{t hosts.bulkOperation.deleteHosts.confirmation.body.msg1}} +</div> + +<div class='alert'> + {{t hosts.bulkOperation.deleteHosts.confirmation.body.msg2}} + <span style="color: red;">{{t hosts.bulkOperation.deleteHosts.confirmation.body.msg3}}</span> +</div> + +<div class='alert'>{{{t common.important.strong}}} {{t hosts.bulkOperation.deleteHosts.confirmation.body.msg4}}</div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/4db1a1e9/ambari-web/app/templates/main/host/delete_hosts_result_popup.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/host/delete_hosts_result_popup.hbs b/ambari-web/app/templates/main/host/delete_hosts_result_popup.hbs new file mode 100644 index 0000000..9e9c772 --- /dev/null +++ b/ambari-web/app/templates/main/host/delete_hosts_result_popup.hbs @@ -0,0 +1,44 @@ +{{! +* 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. +}} +{{#if view.deletedHosts}} + <p>{{t hosts.bulkOperation.deleteHosts.result.body}}</p> +{{/if}} + +{{#each deletedHost in view.deletedHosts}} + <div><i>{{{deletedHost.deleted.key}}}</i></div> +{{/each}} +<br /> +{{#if view.undeletableHosts}} + <p>{{{view.message}}}</p> + {{#each undeletableHost in view.undeletableHosts}} + <div class="accordion"> + <div class="accordion-heading" {{action "onToggleHost" undeletableHost target="view"}}> + <i {{bindAttr class=":pull-left :accordion-toggle undeletableHost.isCollapsed:icon-caret-right:icon-caret-down"}}></i> + <a class="accordion-toggle"> + <p>{{undeletableHost.error.key}}</p> + </a> + </div> + + <div class="accordion-body collapse in" {{bindAttr style="undeletableHost.isBodyVisible"}}> + <div class="accordion-inner"> + <p>{{undeletableHost.error.message}}</p> + </div> + </div> + </div> + {{/each}} +{{/if}} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/4db1a1e9/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 e148363..38a75e4 100644 --- a/ambari-web/app/utils/ajax/ajax.js +++ b/ambari-web/app/utils/ajax/ajax.js @@ -285,6 +285,20 @@ var urls = { } }, + 'common.hosts.delete': { + 'real': '/clusters/{clusterName}/hosts{urlParams}', + 'type': 'DELETE', + 'format': function (data) { + return { + data: JSON.stringify({ + RequestInfo: { + query: data.query + }, + }) + } + } + }, + 'common.service.passive': { 'real': '/clusters/{clusterName}/services/{serviceName}', 'mock': '', http://git-wip-us.apache.org/repos/asf/ambari/blob/4db1a1e9/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 5e4b0e0..dccffaa 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 @@ -306,6 +306,15 @@ App.HostTableMenuView = Em.View.extend({ message: Em.I18n.t('hosts.host.details.setRackId').format('hosts') }) })); + if (App.isAuthorized("HOST.ADD_DELETE_HOSTS")) { + result = result.concat(O.create({ + label: Em.I18n.t('hosts.host.details.deleteHosts'), + operationData: O.create({ + action: 'DELETE', + message: Em.I18n.t('hosts.host.details.deleteHosts') + }) + })); + } return result; }.property(),
