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);