Repository: ambari
Updated Branches:
  refs/heads/branch-2.1 b9b85ca9a -> 3b4835ed5


AMBARI-13600 Allow The Removal Of Hosts in Maintenance Mode Via The Web Client 
During An Upgrade. (atkach)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/3b4835ed
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/3b4835ed
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/3b4835ed

Branch: refs/heads/branch-2.1
Commit: 3b4835ed501dcda354d7f887e45e9332c95d3d64
Parents: b9b85ca
Author: Andrii Tkach <atk...@hortonworks.com>
Authored: Wed Oct 28 14:04:59 2015 +0200
Committer: Andrii Tkach <atk...@hortonworks.com>
Committed: Wed Oct 28 14:19:21 2015 +0200

----------------------------------------------------------------------
 .../main/admin/stack_and_upgrade_controller.js  |   6 +
 ambari-web/app/messages.js                      |   5 +
 .../stack_upgrade/stack_upgrade_wizard.hbs      | 145 ++++++++++++-------
 .../admin/stack_upgrade/upgrade_wizard_view.js  |  58 +++++++-
 .../stack_upgrade/upgrade_wizard_view_test.js   | 131 ++++++++++++++++-
 5 files changed, 289 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/3b4835ed/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js
----------------------------------------------------------------------
diff --git 
a/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js 
b/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js
index a8a9853..97badf7 100644
--- a/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js
+++ b/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js
@@ -148,6 +148,12 @@ App.MainAdminStackAndUpgradeController = 
Em.Controller.extend(App.LocalStorage,
   finalizeContext: 'Confirm Finalize',
 
   /**
+   * context for Resolve hosts item
+   * @type {string}
+   */
+  resolveHostsContext: 'Check Unhealthy Hosts',
+
+  /**
    * Check if current item is Finalize
    * @type {boolean}
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b4835ed/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 564440b..2aa9d1a 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -1522,6 +1522,11 @@ Em.I18n.translations = {
     " <b>You cannot go back to the original version once the downgrade is 
finalized.</b>",
   'admin.stackUpgrade.finalize.message.skippedServiceChecks': "During the 
upgrade, checks for the following services failed and were skipped:",
   'admin.stackUpgrade.finalize.message.testServices': "You are strongly 
recommended to test these services before finalizing upgrade.",
+  'admin.stackUpgrade.failedHosts.message': "Upgrade did not succeed on",
+  'admin.stackUpgrade.failedHosts.showHosts': "{0} hosts",
+  'admin.stackUpgrade.failedHosts.options': "Your options:",
+  'admin.stackUpgrade.failedHosts.options.first': "<b>Pause Upgrade</b>, 
delete the unhealthy hosts and return to the Upgrade Wizard to Proceed.",
+  'admin.stackUpgrade.failedHosts.options.second': "Perform a 
<b>Downgrade</b>, which will revert all hosts to the previous stack version.",
   'admin.stackUpgrade.doThisLater': "Do This Later",
   'admin.stackUpgrade.pauseUpgrade': "Pause Upgrade",
   'admin.stackUpgrade.pauseDowngrade': "Pause Downgrade",  

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b4835ed/ambari-web/app/templates/main/admin/stack_upgrade/stack_upgrade_wizard.hbs
----------------------------------------------------------------------
diff --git 
a/ambari-web/app/templates/main/admin/stack_upgrade/stack_upgrade_wizard.hbs 
b/ambari-web/app/templates/main/admin/stack_upgrade/stack_upgrade_wizard.hbs
index a45bad1..9fae26c 100644
--- a/ambari-web/app/templates/main/admin/stack_upgrade/stack_upgrade_wizard.hbs
+++ b/ambari-web/app/templates/main/admin/stack_upgrade/stack_upgrade_wizard.hbs
@@ -87,68 +87,105 @@
             {{/if}}
           </div>
         {{/if}}
-        {{#if view.manualItem}}
-          {{#if view.isFinalizeItem}}
-            <div class="box details-box">
-              <p><strong>{{t admin.stackUpgrade.dialog.manual}}</strong></p>
+        {{#if view.plainManualItem}}
+          <div class="box details-box">
+            <p><strong>{{t admin.stackUpgrade.dialog.manual}}</strong></p>
+            <p>{{view.manualItem.text}}</p>
+            <label class="message">
+              {{view Em.Checkbox checkedBinding="view.isManualDone"}}
+              {{t admin.stackUpgrade.dialog.manualDone}}
+            </label>
+
+            <div class="button-row">
+              {{#if view.isDowngradeAvailable}}
+                <button
+                  class="btn btn-danger" {{bindAttr 
disabled="controller.requestInProgress"}} {{action confirmDowngrade 
view.manualItem target="controller"}}>{{t common.downgrade}}</button>
+              {{/if}}
               {{#if isDowngrade}}
-                <p>{{t admin.stackUpgrade.finalize.message.downgrade}}</p>
+                <button class="btn" {{action closeWizard 
target="view.parentView"}}>{{t admin.stackUpgrade.pauseDowngrade}}</button>
               {{else}}
-                <p>{{t admin.stackUpgrade.finalize.message.upgrade}}</p>
+                <button class="btn" {{action pauseUpgrade target="view"}}>{{t 
admin.stackUpgrade.pauseUpgrade}}</button>
               {{/if}}
+              <button class="btn btn-success" {{bindAttr 
disabled="view.isManualProceedDisabled"}} {{action complete view.manualItem 
target="view"}}>
+                {{t common.proceed}}
+              </button>
+            </div>
+          </div>
+        {{/if}}
+        {{#if view.isFinalizeItem}}
+          <div class="box details-box">
+            <p><strong>{{t admin.stackUpgrade.dialog.manual}}</strong></p>
+            {{#if isDowngrade}}
+              <p>{{t admin.stackUpgrade.finalize.message.downgrade}}</p>
+            {{else}}
+              <p>{{t admin.stackUpgrade.finalize.message.upgrade}}</p>
+            {{/if}}
 
-              {{#if areSkippedServiceChecksLoaded}}
-                {{#if skippedServiceChecks.length}}
-                  <div>{{t 
admin.stackUpgrade.finalize.message.skippedServiceChecks}}</div>
-                  <ul>
-                    {{#each serviceName in skippedServiceChecks}}
-                      <li>{{serviceName}}</li>
-                    {{/each}}
-                  </ul>
-                  <div>{{t 
admin.stackUpgrade.finalize.message.testServices}}</div>
-                {{/if}}
-              {{else}}
-                <div class="spinner"></div>
+            {{#if areSkippedServiceChecksLoaded}}
+              {{#if skippedServiceChecks.length}}
+                <div>{{t 
admin.stackUpgrade.finalize.message.skippedServiceChecks}}</div>
+                <ul>
+                  {{#each serviceName in skippedServiceChecks}}
+                    <li>{{serviceName}}</li>
+                  {{/each}}
+                </ul>
+                <div>{{t 
admin.stackUpgrade.finalize.message.testServices}}</div>
               {{/if}}
+            {{else}}
+              <div class="spinner"></div>
+            {{/if}}
 
-              <label class="message">
-                {{view Em.Checkbox checkedBinding="view.isManualDone"}}
-                {{t admin.stackUpgrade.dialog.manualDone}}
-              </label>
-              <div class="button-row">
-                {{#if view.isDowngradeAvailable}}
-                  <button class="btn btn-danger" {{bindAttr 
disabled="controller.requestInProgress"}} {{action confirmDowngrade 
view.manualItem target="controller"}}>{{t common.downgrade}}</button>
-                {{/if}}
-                <button class="btn" {{action pauseUpgrade target="view"}}>{{t 
admin.stackUpgrade.finalize.later}}</button>
-                <button class="btn btn-success" {{bindAttr 
disabled="view.isManualProceedDisabled"}} {{action complete view.manualItem 
target="view"}}>
-                  {{t common.finalize}}
-                </button>
-              </div>
+            <label class="message">
+              {{view Em.Checkbox checkedBinding="view.isManualDone"}}
+              {{t admin.stackUpgrade.dialog.manualDone}}
+            </label>
+            <div class="button-row">
+              {{#if view.isDowngradeAvailable}}
+                <button class="btn btn-danger" {{bindAttr 
disabled="controller.requestInProgress"}} {{action confirmDowngrade 
view.manualItem target="controller"}}>{{t common.downgrade}}</button>
+              {{/if}}
+              <button class="btn" {{action pauseUpgrade target="view"}}>{{t 
admin.stackUpgrade.finalize.later}}</button>
+              <button class="btn btn-success" {{bindAttr 
disabled="view.isManualProceedDisabled"}} {{action complete view.manualItem 
target="view"}}>
+                {{t common.finalize}}
+              </button>
             </div>
-          {{else}}
-            <div class="box details-box">
-              <p><strong>{{t admin.stackUpgrade.dialog.manual}}</strong></p>
-              <p>{{view.manualItem.text}}</p>
-
-              <label class="message">
-                {{view Em.Checkbox checkedBinding="view.isManualDone"}}
-                {{t admin.stackUpgrade.dialog.manualDone}}
-              </label>
-              <div class="button-row">
-                {{#if view.isDowngradeAvailable}}
-                  <button class="btn btn-danger" {{bindAttr 
disabled="controller.requestInProgress"}} {{action confirmDowngrade 
view.manualItem target="controller"}}>{{t common.downgrade}}</button>
-                {{/if}}
-                {{#if isDowngrade}}
-                  <button class="btn" {{action closeWizard 
target="view.parentView"}}>{{t admin.stackUpgrade.pauseDowngrade}}</button>
-                {{else}}
-                  <button class="btn" {{action closeWizard 
target="view.parentView"}}>{{t admin.stackUpgrade.pauseUpgrade}}</button>
-                {{/if}}
-                <button class="btn btn-success" {{bindAttr 
disabled="view.isManualProceedDisabled"}} {{action complete view.manualItem 
target="view"}}>
-                  {{t common.proceed}}
-                </button>
-              </div>
+          </div>
+        {{/if}}
+        {{#if view.isResolveHostsItem}}
+          <div class="box details-box">
+            <p><strong>{{t admin.stackUpgrade.dialog.manual}}</strong></p>
+            <p>
+            {{#if controller.isLoaded}}
+              {{t admin.stackUpgrade.failedHosts.message}}
+              <a href="#" {{action showFailedHosts 
target="view"}}>{{view.failedHostsMessage}}</a>
+            {{else}}
+              <div class="spinner"></div>
+            {{/if}}
+            </p>
+            <p>
+              {{t admin.stackUpgrade.failedHosts.options}}
+              <ul>
+                <li>{{t admin.stackUpgrade.failedHosts.options.first}}</li>
+                <li>{{t admin.stackUpgrade.failedHosts.options.second}}</li>
+              </ul>
+            </p>
+            <label class="message">
+              {{view Em.Checkbox checkedBinding="view.isManualDone"}}
+              {{t admin.stackUpgrade.dialog.manualDone}}
+            </label>
+            <div class="button-row">
+              {{#if view.isDowngradeAvailable}}
+                <button class="btn btn-danger" {{bindAttr 
disabled="controller.requestInProgress"}} {{action confirmDowngrade 
view.manualItem target="controller"}}>{{t common.downgrade}}</button>
+              {{/if}}
+              {{#if isDowngrade}}
+                <button class="btn" {{action closeWizard 
target="view.parentView"}}>{{t admin.stackUpgrade.pauseDowngrade}}</button>
+              {{else}}
+                <button class="btn" {{action pauseUpgrade target="view"}}>{{t 
admin.stackUpgrade.pauseUpgrade}}</button>
+              {{/if}}
+              <button class="btn btn-success" {{bindAttr 
disabled="view.isManualProceedDisabled"}} {{action complete view.manualItem 
target="view"}}>
+                {{t common.proceed}}
+              </button>
             </div>
-          {{/if}}
+          </div>
         {{/if}}
         {{#if view.noActiveItem}}
           <div class="box details-box">

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b4835ed/ambari-web/app/views/main/admin/stack_upgrade/upgrade_wizard_view.js
----------------------------------------------------------------------
diff --git 
a/ambari-web/app/views/main/admin/stack_upgrade/upgrade_wizard_view.js 
b/ambari-web/app/views/main/admin/stack_upgrade/upgrade_wizard_view.js
index aff8f94..e9bfe91 100644
--- a/ambari-web/app/views/main/admin/stack_upgrade/upgrade_wizard_view.js
+++ b/ambari-web/app/views/main/admin/stack_upgrade/upgrade_wizard_view.js
@@ -170,6 +170,14 @@ App.upgradeWizardView = Em.View.extend({
   }.property('activeGroup.upgradeItems.@each.status'),
 
   /**
+   * plain manual item
+   * @type {object|undefined}
+   */
+  plainManualItem: function () {
+    return this.get('manualItem') && ![this.get('controller.finalizeContext'), 
this.get('controller.resolveHostsContext')].contains(this.get('manualItem.context'));
+  }.property('manualItem.context'),
+
+  /**
    * indicate whether the step is Finalize
    * @type {boolean}
    */
@@ -178,6 +186,33 @@ App.upgradeWizardView = Em.View.extend({
   }.property('manualItem.context'),
 
   /**
+   * indicate whether the step is Resolve Hosts
+   * @type {boolean}
+   */
+  isResolveHostsItem: function () {
+    return this.get('manualItem.context') === 
this.get('controller.resolveHostsContext');
+  }.property('manualItem.context'),
+
+  /**
+   * hosts failed to be upgraded
+   * @type {Array}
+   */
+  failedHosts: function() {
+    if (this.get('isResolveHostsItem')) {
+      var version = App.RepositoryVersion.find().findProperty('displayName', 
this.get('controller.upgradeVersion'));
+      return version ? version.get('notInstalledHosts') : [];
+    }
+    return [];
+  }.property('isResolveHostsItem', 'controller.upgradeVersion', 
'controller.isLoaded'),
+
+  /**
+   * @type {string}
+   */
+  failedHostsMessage: function() {
+    return 
Em.I18n.t('admin.stackUpgrade.failedHosts.showHosts').format(this.get('failedHosts.length'));
+  }.property('failedHosts'),
+
+  /**
    * label of Upgrade status
    * @type {string}
    */
@@ -216,6 +251,18 @@ App.upgradeWizardView = Em.View.extend({
   }.property('controller.upgradeData.Upgrade.request_status', 
'controller.isDowngrade', 'controller.isSuspended'),
 
   /**
+   * load versions page
+   */
+  loadVersionPage: function () {
+    var controller = this.get('controller');
+    if (!controller.get('isLoaded') && App.get('clusterName')) {
+      controller.load().done(function () {
+        controller.set('isLoaded', true);
+      });
+    }
+  }.observes('App.clusterName'),
+
+  /**
    * toggle details box
    */
   toggleDetails: function () {
@@ -360,9 +407,18 @@ App.upgradeWizardView = Em.View.extend({
   },
 
   pauseUpgrade: function() {
-    if (this.get('isFinalizeItem')) {
+    if (this.get('isFinalizeItem') || this.get('isResolveHostsItem')) {
       this.get('controller').suspendUpgrade();
     }
     this.get('parentView').closeWizard();
+  },
+
+  showFailedHosts: function() {
+    return App.ModalPopup.show({
+      content: this.get('failedHosts').join(", "),
+      header: Em.I18n.t('common.hosts'),
+      bodyClass: App.SelectablePopupBodyView,
+      secondary: null
+    });
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b4835ed/ambari-web/test/views/main/admin/stack_upgrade/upgrade_wizard_view_test.js
----------------------------------------------------------------------
diff --git 
a/ambari-web/test/views/main/admin/stack_upgrade/upgrade_wizard_view_test.js 
b/ambari-web/test/views/main/admin/stack_upgrade/upgrade_wizard_view_test.js
index d75c3c6..67fddff 100644
--- a/ambari-web/test/views/main/admin/stack_upgrade/upgrade_wizard_view_test.js
+++ b/ambari-web/test/views/main/admin/stack_upgrade/upgrade_wizard_view_test.js
@@ -27,13 +27,16 @@ describe('App.upgradeWizardView', function () {
   view.reopen({
     controller: Em.Object.create({
       finalizeContext: 'Confirm Finalize',
+      resolveHostsContext: 'Check Unhealthy Hosts',
       upgradeData: Em.Object.create(),
       loadUpgradeData: Em.K,
       setUpgradeItemStatus: Em.K,
-      getUpgradeItem: Em.K
+      getUpgradeItem: Em.K,
+      load: Em.K
     })
   });
   view.removeObserver('App.clusterName', view, 'startPolling');
+  view.removeObserver('App.clusterName', view, 'loadVersionPage');
 
   describe("#upgradeGroups", function () {
     it("upgradeGroups is null", function () {
@@ -96,12 +99,16 @@ describe('App.upgradeWizardView', function () {
           }
         }
       });
+      sinon.stub(view.get('controller'), 'load', function() {
+        return {done: Em.K};
+      });
       sinon.stub(view, 'doPolling', Em.K);
       view.set('isLoaded', false);
     });
     afterEach(function () {
       view.get('controller').loadUpgradeData.restore();
       view.doPolling.restore();
+      view.get('controller').load.restore();
     });
     it("clusterName is null", function () {
       App.set('clusterName', null);
@@ -118,6 +125,61 @@ describe('App.upgradeWizardView', function () {
     });
   });
 
+  describe("#loadVersionPage()", function () {
+    beforeEach(function () {
+      sinon.stub(view.get('controller'), 'load', function () {
+        return {
+          done: function (callback) {
+            callback();
+          }
+        }
+      });
+      view.set('isLoaded', false);
+    });
+    afterEach(function () {
+      view.get('controller').load.restore();
+    });
+    it("clusterName is null", function () {
+      App.set('clusterName', null);
+      view.set('controller.isLoaded', false);
+      view.loadVersionPage();
+      expect(view.get('controller').load.called).to.be.false;
+      expect(view.get('controller.isLoaded')).to.be.false;
+    });
+    it("controller already loaded", function () {
+      App.set('clusterName', 'c1');
+      view.set('controller.isLoaded', true);
+      view.loadVersionPage();
+      expect(view.get('controller').load.called).to.be.false;
+      expect(view.get('controller.isLoaded')).to.be.true;
+    });
+    it("controller not loaded and clusterName present", function () {
+      App.set('clusterName', 'c1');
+      view.set('controller.isLoaded', false);
+      view.loadVersionPage();
+      expect(view.get('controller').load.calledOnce).to.be.true;
+      expect(view.get('controller.isLoaded')).to.be.true;
+    });
+  });
+
+  describe("#showFailedHosts()", function () {
+    beforeEach(function () {
+      sinon.stub(App.ModalPopup, 'show');
+    });
+    afterEach(function () {
+      App.ModalPopup.show.restore();
+    });
+    it("", function () {
+      view.showFailedHosts();
+      expect(App.ModalPopup.show.calledWith({
+        content: "",
+        header: Em.I18n.t('common.hosts'),
+        bodyClass: App.SelectablePopupBodyView,
+        secondary: null
+      })).to.be.true;
+    });
+  });
+
   describe("#willInsertElement()", function () {
     before(function () {
       sinon.stub(view, 'startPolling', Em.K);
@@ -424,6 +486,30 @@ describe('App.upgradeWizardView', function () {
     });
   });
 
+  describe("#plainManualItem", function () {
+    it("depends of manualItem.context", function () {
+      view.reopen({
+        manualItem: {
+          context: 'context'
+        }
+      });
+      view.propertyDidChange('plainManualItem');
+      expect(view.get('plainManualItem')).to.be.true;
+    });
+  });
+
+  describe("#isResolveHostsItem", function () {
+    it("depends of manualItem.context", function () {
+      view.reopen({
+        manualItem: {
+          context: 'Check Unhealthy Hosts'
+        }
+      });
+      view.propertyDidChange('isResolveHostsItem');
+      expect(view.get('isResolveHostsItem')).to.be.true;
+    });
+  });
+
   describe("#isFinalizeItem", function () {
     it("depends of manualItem.context", function () {
       view.reopen({
@@ -436,6 +522,49 @@ describe('App.upgradeWizardView', function () {
     });
   });
 
+  describe("#failedHosts", function() {
+    beforeEach(function () {
+      sinon.stub(App.RepositoryVersion, 'find').returns([Em.Object.create({
+        displayName: 'HDP-1',
+        notInstalledHosts: ['host1']
+      })]);
+      view.set('controller.upgradeVersion', 'HDP-1');
+    });
+    afterEach(function () {
+      App.RepositoryVersion.find.restore();
+    });
+    it("not resolve context", function() {
+      view.reopen({
+        manualItem: {
+          context: 'not resolve context'
+        }
+      });
+      view.propertyDidChange('isResolveHostsItem');
+      view.propertyDidChange('failedHosts');
+      expect(view.get('failedHosts')).to.be.empty;
+    });
+    it("host resolve context", function() {
+      view.reopen({
+        manualItem: {
+          context: 'Check Unhealthy Hosts'
+        }
+      });
+      view.propertyDidChange('isResolveHostsItem');
+      view.propertyDidChange('failedHosts');
+      expect(view.get('failedHosts')).to.eql(['host1']);
+    });
+  });
+
+  describe("#failedHostsMessage", function() {
+    it("", function() {
+      view.reopen({
+        failedHosts: ['host1']
+      });
+      view.propertyDidChange('failedHostsMessage');
+      
expect(view.get('failedHostsMessage')).to.equal(Em.I18n.t('admin.stackUpgrade.failedHosts.showHosts').format(1));
+    });
+  });
+
   describe("#toggleDetails()", function () {
     before(function () {
       sinon.stub(view, 'toggleProperty', Em.K);

Reply via email to