You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by zh...@apache.org on 2016/06/07 18:25:11 UTC

ambari git commit: AMBARI-10908 Usability: ability to perform bulk delete host (zhewang)

Repository: ambari
Updated Branches:
  refs/heads/trunk 4d622167d -> bd58a5038


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/bd58a503
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/bd58a503
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/bd58a503

Branch: refs/heads/trunk
Commit: bd58a5038032445831996a33ae52a08f387a2335
Parents: 4d62216
Author: Zhe (Joe) Wang <zh...@apache.org>
Authored: Tue Jun 7 11:24:41 2016 -0700
Committer: Zhe (Joe) Wang <zh...@apache.org>
Committed: Tue Jun 7 11:24:41 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/bd58a503/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/bd58a503/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 2e1b253..2ea1560 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -2400,6 +2400,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.',
@@ -2474,6 +2485,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/bd58a503/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index 5ee09cc..e7fe6f4 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -6167,6 +6167,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/bd58a503/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/bd58a503/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/bd58a503/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/bd58a503/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 195dab4..03a77ef 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/bd58a503/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(),