You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2015/09/17 13:56:14 UTC

ambari git commit: AMBARI-13123 Usability: do not force redirect the user to the currently running wizard if another user logs in. (atkach)

Repository: ambari
Updated Branches:
  refs/heads/trunk a2260c7f0 -> 9763e6447


AMBARI-13123 Usability: do not force redirect the user to the currently running wizard if another user logs in. (atkach)


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

Branch: refs/heads/trunk
Commit: 9763e6447a34206e12bbd5a52de926793d75ad5d
Parents: a2260c7
Author: Andrii Tkach <at...@hortonworks.com>
Authored: Thu Sep 17 14:53:29 2015 +0300
Committer: Andrii Tkach <at...@hortonworks.com>
Committed: Thu Sep 17 14:55:53 2015 +0300

----------------------------------------------------------------------
 ambari-web/app/app.js                           |  11 +-
 ambari-web/app/assets/test/tests.js             |   1 +
 ambari-web/app/controllers.js                   |   1 +
 .../controllers/global/cluster_controller.js    |   1 +
 .../app/controllers/global/update_controller.js |   7 +-
 .../global/wizard_watcher_controller.js         | 107 +++++++++++++
 .../nameNode/wizard_controller.js               |   5 +
 .../rangerAdmin/wizard_controller.js            |   5 +
 .../resourceManager/wizard_controller.js        |   5 +
 .../main/admin/kerberos/wizard_controller.js    |   5 +
 .../app/controllers/main/host/add_controller.js |   5 +
 .../controllers/main/service/add_controller.js  |   5 +
 .../main/service/reassign_controller.js         |   5 +
 ambari-web/app/messages.js                      |   4 +-
 ambari-web/app/router.js                        |  38 ++---
 ambari-web/app/routes/add_host_routes.js        |   2 +
 ambari-web/app/routes/add_kerberos_routes.js    |   2 +
 ambari-web/app/routes/add_service_routes.js     |   2 +
 .../app/routes/high_availability_routes.js      |   2 +
 .../app/routes/ra_high_availability_routes.js   |   2 +
 ambari-web/app/routes/reassign_master_routes.js |   2 +
 .../app/routes/rm_high_availability_routes.js   |   2 +
 ambari-web/app/templates/application.hbs        |   7 +-
 ambari-web/app/utils/helper.js                  |  14 +-
 ambari-web/app/views/main/menu.js               |   9 +-
 ambari-web/test/app_test.js                     |  14 +-
 .../global/update_controller_test.js            |  26 ++--
 .../global/wizard_watcher_controller_test.js    | 151 +++++++++++++++++++
 28 files changed, 390 insertions(+), 50 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/app.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/app.js b/ambari-web/app/app.js
index dfcfb95..6f1ed78 100644
--- a/ambari-web/app/app.js
+++ b/ambari-web/app/app.js
@@ -83,11 +83,12 @@ module.exports = Em.Application.create({
 
   /**
    * flag is true when upgrade process is running or aborted
+   * or wizard used by another user
    * @returns {boolean}
    */
-  upgradeIsNotFinished: function () {
-    return this.get('upgradeIsRunning') || this.get('upgradeAborted');
-  }.property('upgradeIsRunning', 'upgradeAborted'),
+  wizardIsNotFinished: function () {
+    return this.get('upgradeIsRunning') || this.get('upgradeAborted') || App.router.get('wizardWatcherController.isNonWizardUser');
+  }.property('upgradeIsRunning', 'upgradeAborted', 'router.wizardWatcherController.isNonWizardUser'),
 
   /**
    * compute user access rights by permission type
@@ -105,6 +106,10 @@ module.exports = Em.Application.create({
       return false;
     }
 
+    if (App.router.get('wizardWatcherController').get('isNonWizardUser')) {
+      return false;
+    }
+
     if (type.contains('upgrade_')) {
       //slice off "upgrade_" prefix to have actual permission type
       type = type.slice(8);

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/assets/test/tests.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js
index 268e678..c1e2c2b 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -47,6 +47,7 @@ var files = [
   'test/controllers/global/cluster_controller_test',
   'test/controllers/global/update_controller_test',
   'test/controllers/global/configuration_controller_test',
+  'test/controllers/global/wizard_watcher_controller_test',
   'test/controllers/main/alert_definitions_controller_test',
   'test/controllers/main/alerts/alert_definitions_actions_controller_test',
   'test/controllers/main/alerts/definitions_configs_controller_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/controllers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js
index 7748790..d593676 100644
--- a/ambari-web/app/controllers.js
+++ b/ambari-web/app/controllers.js
@@ -24,6 +24,7 @@ require('controllers/login_controller');
 require('controllers/wizard');
 require('controllers/installer');
 require('controllers/global/background_operations_controller');
+require('controllers/global/wizard_watcher_controller');
 require('controllers/main');
 require('controllers/main/dashboard');
 require('controllers/main/dashboard/config_history_controller');

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/controllers/global/cluster_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/cluster_controller.js b/ambari-web/app/controllers/global/cluster_controller.js
index 803c2d6..ab3d18c 100644
--- a/ambari-web/app/controllers/global/cluster_controller.js
+++ b/ambari-web/app/controllers/global/cluster_controller.js
@@ -206,6 +206,7 @@ App.ClusterController = Em.Controller.extend(App.ReloadPopupMixin, {
       self.restoreUpgradeState();
     }
 
+    App.router.get('wizardWatcherController').getUser();
 
     var updater = App.router.get('updateController');
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/controllers/global/update_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/update_controller.js b/ambari-web/app/controllers/global/update_controller.js
index ac19d19..084425d 100644
--- a/ambari-web/app/controllers/global/update_controller.js
+++ b/ambari-web/app/controllers/global/update_controller.js
@@ -154,6 +154,7 @@ App.UpdateController = Em.Controller.extend({
         App.updater.run(this, 'updateUnhealthyAlertInstances', 'updateAlertInstances', App.alertInstancesUpdateInterval, '\/main\/alerts.*');
       }
       App.updater.run(this, 'updateUpgradeState', 'isWorking', App.bgOperationsUpdateInterval);
+      App.updater.run(this, 'updateWizardWatcher', 'isWorking', App.bgOperationsUpdateInterval);
     }
   }.observes('isWorking', 'App.router.mainAlertInstancesController.isUpdating'),
 
@@ -570,11 +571,15 @@ App.UpdateController = Em.Controller.extend({
     var currentStateName = App.get('router.currentState.name'),
       parentStateName = App.get('router.parentState.name'),
       mainAdminStackAndUpgradeController = App.get('router.mainAdminStackAndUpgradeController');
-    if (!(currentStateName === 'versions' && parentStateName === 'stackAndUpgrade') && currentStateName !== 'stackUpgrade' && App.get('upgradeIsNotFinished') && !mainAdminStackAndUpgradeController.get('isLoadUpgradeDataPending')) {
+    if (!(currentStateName === 'versions' && parentStateName === 'stackAndUpgrade') && currentStateName !== 'stackUpgrade' && App.get('wizardIsNotFinished') && !mainAdminStackAndUpgradeController.get('isLoadUpgradeDataPending')) {
       mainAdminStackAndUpgradeController.loadUpgradeData(true).done(callback);
     } else {
       callback();
     }
+  },
+
+  updateWizardWatcher: function(callback) {
+    App.router.get('wizardWatcherController').getUser().complete(callback);
   }
 
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/controllers/global/wizard_watcher_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/wizard_watcher_controller.js b/ambari-web/app/controllers/global/wizard_watcher_controller.js
new file mode 100644
index 0000000..e9cd958
--- /dev/null
+++ b/ambari-web/app/controllers/global/wizard_watcher_controller.js
@@ -0,0 +1,107 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.WizardWatcherController = Em.Controller.extend(App.UserPref, {
+  name: 'wizardWatcherController',
+
+  /**
+   * @const
+   */
+  PREF_KEY: 'wizard-data',
+
+  /**
+   * name of user who working with wizard
+   * @type {string|null}
+   */
+  wizardUser: null,
+
+  /**
+   * @type {string|null}
+   */
+  controllerName: null,
+
+  /**
+   * @type {Function}
+   */
+  mock: Em.K,
+
+  /**
+   * define whether Wizard is running
+   * @type {boolean}
+   */
+  isWizardRunning: function() {
+    return !Em.isNone(this.get('wizardUser'));
+  }.property('wizardUser'),
+
+  /**
+   * @type {string}
+   */
+  wizardDisplayName: function() {
+    if (this.get('controllerName')) {
+      return Em.I18n.t('wizard.inProgress').format(App.router.get(this.get('controllerName')).get('displayName'));
+    }
+    return "";
+  }.property('controllerName'),
+
+  /**
+   * define whether logged in user is the one who started wizard
+   * @type {boolean}
+   */
+  isNonWizardUser: function() {
+    return this.get('isWizardRunning') && this.get('wizardUser') !== App.router.get('loginName');
+  }.property('App.router.loginName', 'wizardUser').volatile(),
+
+  /**
+   * set user who launched wizard
+   * @returns {$.ajax}
+   */
+  setUser: function(controllerName) {
+    return this.postUserPref(this.get('PREF_KEY'), {
+      userName: App.router.get('loginName'),
+      controllerName: controllerName
+    });
+  },
+
+  /**
+   * reset user who launched wizard
+   * @returns {$.ajax}
+   */
+  resetUser: function() {
+    return this.postUserPref(this.get('PREF_KEY'), null);
+  },
+
+  /**
+   * get user who launched wizard
+   * @returns {$.ajax}
+   */
+  getUser: function() {
+    return this.getUserPref(this.get('PREF_KEY'));
+  },
+
+  getUserPrefSuccessCallback: function(data) {
+    if (Em.isNone(data)) {
+      this.set('wizardUser', null);
+      this.set('controllerName', null);
+    } else {
+      this.set('wizardUser', data.userName);
+      this.set('controllerName', data.controllerName);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/controllers/main/admin/highAvailability/nameNode/wizard_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/highAvailability/nameNode/wizard_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/nameNode/wizard_controller.js
index 134cb64..255e781 100644
--- a/ambari-web/app/controllers/main/admin/highAvailability/nameNode/wizard_controller.js
+++ b/ambari-web/app/controllers/main/admin/highAvailability/nameNode/wizard_controller.js
@@ -26,6 +26,11 @@ App.HighAvailabilityWizardController = App.WizardController.extend({
   totalSteps: 9,
 
   /**
+   * @type {string}
+   */
+  displayName: Em.I18n.t('admin.highAvailability.wizard.header'),
+
+  /**
    * Used for hiding back button in wizard
    */
   hideBackButton: true,

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/wizard_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/wizard_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/wizard_controller.js
index a8768b6..4e31569 100644
--- a/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/wizard_controller.js
+++ b/ambari-web/app/controllers/main/admin/highAvailability/rangerAdmin/wizard_controller.js
@@ -25,6 +25,11 @@ App.RAHighAvailabilityWizardController = App.WizardController.extend({
 
   totalSteps: 4,
 
+  /**
+   * @type {string}
+   */
+  displayName: Em.I18n.t('admin.ra_highAvailability.wizard.header'),
+
   isFinished: false,
 
   content: Em.Object.create({

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/controllers/main/admin/highAvailability/resourceManager/wizard_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/highAvailability/resourceManager/wizard_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/resourceManager/wizard_controller.js
index efa5119..963d65e 100644
--- a/ambari-web/app/controllers/main/admin/highAvailability/resourceManager/wizard_controller.js
+++ b/ambari-web/app/controllers/main/admin/highAvailability/resourceManager/wizard_controller.js
@@ -25,6 +25,11 @@ App.RMHighAvailabilityWizardController = App.WizardController.extend({
 
   totalSteps: 4,
 
+  /**
+   * @type {string}
+   */
+  displayName: Em.I18n.t('admin.rm_highAvailability.wizard.header'),
+
   isFinished: false,
 
   content: Em.Object.create({

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/controllers/main/admin/kerberos/wizard_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/kerberos/wizard_controller.js b/ambari-web/app/controllers/main/admin/kerberos/wizard_controller.js
index ed723cc..3476b2b 100644
--- a/ambari-web/app/controllers/main/admin/kerberos/wizard_controller.js
+++ b/ambari-web/app/controllers/main/admin/kerberos/wizard_controller.js
@@ -28,6 +28,11 @@ App.KerberosWizardController = App.WizardController.extend({
 
   totalSteps: 8,
 
+  /**
+   * @type {string}
+   */
+  displayName: Em.I18n.t('admin.kerberos.wizard.header'),
+
   isKerberosWizard: true,
 
   stackConfigsLoaded: false,

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/controllers/main/host/add_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/host/add_controller.js b/ambari-web/app/controllers/main/host/add_controller.js
index 7ad62af..de0dd30 100644
--- a/ambari-web/app/controllers/main/host/add_controller.js
+++ b/ambari-web/app/controllers/main/host/add_controller.js
@@ -26,6 +26,11 @@ App.AddHostController = App.WizardController.extend({
   totalSteps: 7,
 
   /**
+   * @type {string}
+   */
+  displayName: Em.I18n.t('hosts.add.header'),
+
+  /**
    * Used for hiding back button in wizard
    */
   hideBackButton: true,

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/controllers/main/service/add_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/add_controller.js b/ambari-web/app/controllers/main/service/add_controller.js
index a9bfa4e..5a5366e 100644
--- a/ambari-web/app/controllers/main/service/add_controller.js
+++ b/ambari-web/app/controllers/main/service/add_controller.js
@@ -25,6 +25,11 @@ App.AddServiceController = App.WizardController.extend(App.AddSecurityConfigs, {
   totalSteps: 8,
 
   /**
+   * @type {string}
+   */
+  displayName: Em.I18n.t('services.add.header'),
+
+  /**
    * Used for hiding back button in wizard
    */
   hideBackButton: true,

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/controllers/main/service/reassign_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/reassign_controller.js b/ambari-web/app/controllers/main/service/reassign_controller.js
index ee146e1..2c2f15a 100644
--- a/ambari-web/app/controllers/main/service/reassign_controller.js
+++ b/ambari-web/app/controllers/main/service/reassign_controller.js
@@ -26,6 +26,11 @@ App.ReassignMasterController = App.WizardController.extend({
   totalSteps: 7,
 
   /**
+   * @type {string}
+   */
+  displayName: Em.I18n.t('services.reassign.header'),
+
+  /**
    * Used for hiding back button in wizard
    */
   hideBackButton: true,

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index a017d97..05563c9 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -2706,5 +2706,7 @@ Em.I18n.translations = {
 
   'utils.ajax.errorMessage': 'Error message',
   'utils.ajax.defaultErrorPopupBody.message': 'received on {0} method for API: {1}',
-  'utils.ajax.defaultErrorPopupBody.statusCode': '{0} status code'
+  'utils.ajax.defaultErrorPopupBody.statusCode': '{0} status code',
+
+  'wizard.inProgress': '{0} in Progress'
 };

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/router.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/router.js b/ambari-web/app/router.js
index 9c248f1..85de1da 100644
--- a/ambari-web/app/router.js
+++ b/ambari-web/app/router.js
@@ -399,26 +399,28 @@ App.Router = Em.Router.extend({
       }
     } else {
       if (this.get('clusterInstallCompleted')) {
-        App.clusterStatus.updateFromServer(false).complete(function () {
-          var route = 'main.dashboard.index';
-          var clusterStatusOnServer = App.clusterStatus.get('value');
-          if (clusterStatusOnServer) {
-            var wizardControllerRoutes = require('data/controller_route');
-            var wizardControllerRoute =  wizardControllerRoutes.findProperty('wizardControllerName', clusterStatusOnServer.wizardControllerName);
-            if (wizardControllerRoute) {
-              route =  wizardControllerRoute.route;
+        App.router.get('wizardWatcherController').getUser().complete(function() {
+          App.clusterStatus.updateFromServer(false).complete(function () {
+            var route = 'main.dashboard.index';
+            var clusterStatusOnServer = App.clusterStatus.get('value');
+            if (clusterStatusOnServer) {
+              var wizardControllerRoutes = require('data/controller_route');
+              var wizardControllerRoute =  wizardControllerRoutes.findProperty('wizardControllerName', clusterStatusOnServer.wizardControllerName);
+              if (wizardControllerRoute && !App.router.get('wizardWatcherController').get('isNonWizardUser')) {
+                route = wizardControllerRoute.route;
+              }
             }
-          }
-          if (wizardControllerRoute && wizardControllerRoute.wizardControllerName === 'mainAdminStackAndUpgradeController')  {
-            var clusterController =   App.router.get('clusterController');
-            clusterController.loadClusterName().done(function(){
-              clusterController.restoreUpgradeState().done(function(){
-                callback(route);
+            if (wizardControllerRoute && wizardControllerRoute.wizardControllerName === 'mainAdminStackAndUpgradeController')  {
+              var clusterController =   App.router.get('clusterController');
+              clusterController.loadClusterName().done(function(){
+                clusterController.restoreUpgradeState().done(function(){
+                  callback(route);
+                });
               });
-            });
-          } else {
-            callback(route);
-          }
+            } else {
+              callback(route);
+            }
+          });
         });
       } else {
         callback('installer');

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/routes/add_host_routes.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/add_host_routes.js b/ambari-web/app/routes/add_host_routes.js
index 5487bce..50db9cc 100644
--- a/ambari-web/app/routes/add_host_routes.js
+++ b/ambari-web/app/routes/add_host_routes.js
@@ -25,6 +25,7 @@ module.exports = App.WizardRoute.extend({
     var addHostController = router.get('addHostController');
     App.router.get('updateController').set('isWorking', true);
     addHostController.finish();
+    App.router.get('wizardWatcherController').resetUser();
     App.clusterStatus.setClusterStatus({
       clusterName: App.router.get('content.cluster.name'),
       clusterState: 'DEFAULT',
@@ -97,6 +98,7 @@ module.exports = App.WizardRoute.extend({
         }
       }
 
+      App.router.get('wizardWatcherController').setUser(addHostController.get('name'));
       router.transitionTo('step' + addHostController.get('currentStep'));
     });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/routes/add_kerberos_routes.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/add_kerberos_routes.js b/ambari-web/app/routes/add_kerberos_routes.js
index 9e10465..5ac287b 100644
--- a/ambari-web/app/routes/add_kerberos_routes.js
+++ b/ambari-web/app/routes/add_kerberos_routes.js
@@ -78,6 +78,7 @@ module.exports = App.WizardRoute.extend({
             App.get('router').transitionTo('adminKerberos.index');
             location.reload();
           }
+          App.router.get('wizardWatcherController').resetUser();
           App.clusterStatus.setClusterStatus({
             clusterName: App.router.getClusterName(),
             clusterState: 'DEFAULT',
@@ -110,6 +111,7 @@ module.exports = App.WizardRoute.extend({
 
       }
       Em.run.next(function(){
+        App.router.get('wizardWatcherController').setUser(kerberosWizardController.get('name'));
         router.transitionTo('step' + kerberosWizardController.get('currentStep'));
       });
     });

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/routes/add_service_routes.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/add_service_routes.js b/ambari-web/app/routes/add_service_routes.js
index 96937f9..030eb90 100644
--- a/ambari-web/app/routes/add_service_routes.js
+++ b/ambari-web/app/routes/add_service_routes.js
@@ -54,6 +54,7 @@ module.exports = App.WizardRoute.extend({
                 });
                 var exitPath = addServiceController.getDBProperty('onClosePath') || 'main.services.index';
                 addServiceController.finish();
+                App.router.get('wizardWatcherController').resetUser();
                 // We need to do recovery based on whether we are in Add Host or Installer wizard
                 App.clusterStatus.setClusterStatus({
                   clusterName: App.router.get('content.cluster.name'),
@@ -90,6 +91,7 @@ module.exports = App.WizardRoute.extend({
               }
             }
 
+            App.router.get('wizardWatcherController').setUser(addServiceController.get('name'));
             router.transitionTo('step' + addServiceController.get('currentStep'));
           });
         });

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/routes/high_availability_routes.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/high_availability_routes.js b/ambari-web/app/routes/high_availability_routes.js
index 381d285..3302305 100644
--- a/ambari-web/app/routes/high_availability_routes.js
+++ b/ambari-web/app/routes/high_availability_routes.js
@@ -68,6 +68,7 @@ module.exports = App.WizardRoute.extend({
               controller.clearTasksData();
               controller.finish();
               App.router.get('updateController').set('isWorking', true);
+              App.router.get('wizardWatcherController').resetUser();
               App.clusterStatus.setClusterStatus({
                 clusterName: controller.get('content.cluster.name'),
                 clusterState: 'DEFAULT',
@@ -99,6 +100,7 @@ module.exports = App.WizardRoute.extend({
           }
         }
       Em.run.next(function () {
+        App.router.get('wizardWatcherController').setUser(highAvailabilityWizardController.get('name'));
         router.transitionTo('step' + highAvailabilityWizardController.get('currentStep'));
       });
     });

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/routes/ra_high_availability_routes.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/ra_high_availability_routes.js b/ambari-web/app/routes/ra_high_availability_routes.js
index 8be1f50..5700b17 100644
--- a/ambari-web/app/routes/ra_high_availability_routes.js
+++ b/ambari-web/app/routes/ra_high_availability_routes.js
@@ -63,6 +63,7 @@ module.exports = App.WizardRoute.extend({
           } else {
             router.get('updateController').set('isWorking', true);
             rAHighAvailabilityWizardController.finish();
+            App.router.get('wizardWatcherController').resetUser();
             App.clusterStatus.setClusterStatus({
               clusterName: App.router.getClusterName(),
               clusterState: 'DEFAULT',
@@ -93,6 +94,7 @@ module.exports = App.WizardRoute.extend({
             break;
         }
       }
+      App.router.get('wizardWatcherController').setUser(rAHighAvailabilityWizardController.get('name'));
       router.transitionTo('step' + rAHighAvailabilityWizardController.get('currentStep'));
     });
   },

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/routes/reassign_master_routes.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/reassign_master_routes.js b/ambari-web/app/routes/reassign_master_routes.js
index 4bec84a..4b79991 100644
--- a/ambari-web/app/routes/reassign_master_routes.js
+++ b/ambari-web/app/routes/reassign_master_routes.js
@@ -25,6 +25,7 @@ module.exports = App.WizardRoute.extend({
     var reassignMasterController = router.get('reassignMasterController');
     App.router.get('updateController').set('isWorking', true);
     reassignMasterController.finish();
+    App.router.get('wizardWatcherController').resetUser();
     App.clusterStatus.setClusterStatus({
       clusterName: App.router.get('content.cluster.name'),
       clusterState: 'DEFAULT',
@@ -102,6 +103,7 @@ module.exports = App.WizardRoute.extend({
                 break;
             }
           }
+          App.router.get('wizardWatcherController').setUser(reassignMasterController.get('name'));
           router.transitionTo('step' + currStep);
         });
       } else {

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/routes/rm_high_availability_routes.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/rm_high_availability_routes.js b/ambari-web/app/routes/rm_high_availability_routes.js
index 6d58c62..51cb2c7 100644
--- a/ambari-web/app/routes/rm_high_availability_routes.js
+++ b/ambari-web/app/routes/rm_high_availability_routes.js
@@ -61,6 +61,7 @@ module.exports = App.WizardRoute.extend({
           } else {
             router.get('updateController').set('isWorking', true);
             rMHighAvailabilityWizardController.finish();
+            App.router.get('wizardWatcherController').resetUser();
             App.clusterStatus.setClusterStatus({
               clusterName: App.router.getClusterName(),
               clusterState: 'DEFAULT',
@@ -92,6 +93,7 @@ module.exports = App.WizardRoute.extend({
         }
       }
       Em.run.next(function () {
+        App.router.get('wizardWatcherController').setUser(rMHighAvailabilityWizardController.get('name'));
         router.transitionTo('step' + rMHighAvailabilityWizardController.get('currentStep'));
       });
     });

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/templates/application.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/application.hbs b/ambari-web/app/templates/application.hbs
index e636e97..aca75a7 100644
--- a/ambari-web/app/templates/application.hbs
+++ b/ambari-web/app/templates/application.hbs
@@ -99,13 +99,18 @@
   </div>
   <div class="container main-container">
     <div id="content">
-      {{#if App.upgradeIsNotFinished}}
+      {{#if App.wizardIsNotFinished}}
         <div class="ru-badge span12">
           <div class="navbar navbar-static-top clearfix">
             <div class="span11">
               {{#if isExistingClusterDataLoaded}}
                 <p class="span4 offset4">
                 <a class="brand cluster-name" href="#">
+                  {{#if App.router.wizardWatcherController.isNonWizardUser}}
+                      <span class="label upgrade-in-progress" {{action "mock" target="App.router.wizardWatcherController"}}>
+                        <i class="icon-cog"></i>&nbsp;{{App.router.wizardWatcherController.wizardDisplayName}}
+                      </span>
+                  {{/if}}
                   {{#if App.upgradeInProgress}}
                     {{#if App.router.mainAdminStackAndUpgradeController.isDowngrade}}
                       <span

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/utils/helper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/helper.js b/ambari-web/app/utils/helper.js
index f777ee6..c54e78b 100644
--- a/ambari-web/app/utils/helper.js
+++ b/ambari-web/app/utils/helper.js
@@ -270,10 +270,16 @@ Em.Handlebars.registerHelper('highlight', function (property, words, fn) {
   return new Em.Handlebars.SafeString(property);
 });
 
-Em.Handlebars.registerHelper('isAccessible', function (context, options) {
-  if (App.isAccessible(context)) {
-    return options.fn(this);
-  }
+Em.Handlebars.registerHelper('isAccessible', function (property, options) {
+  var permission = Ember.Object.create({
+    isAccessible: function() {
+      return App.isAccessible(property);
+    }.property('App.router.wizardWatcherController.isWizardRunning')
+  });
+
+  // wipe out contexts so boundIf uses `this` (the permission) as the context
+  options.contexts = null;
+  return Ember.Handlebars.helpers.boundIf.call(permission, "isAccessible", options);
 });
 
 /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/app/views/main/menu.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/menu.js b/ambari-web/app/views/main/menu.js
index 40f9781..115d839 100644
--- a/ambari-web/app/views/main/menu.js
+++ b/ambari-web/app/views/main/menu.js
@@ -49,8 +49,13 @@ App.MainMenuView = Em.CollectionView.extend({
       result.push({ label: Em.I18n.t('menu.item.views'), routing: 'views.index', isView: true, views: this.get('views').filterProperty('visible')});
     }
     return result;
-  }.property('App.router.loggedIn', 'views.length',
-    'App.router.clusterController.isLoaded', 'App.router.clusterInstallCompleted'),
+  }.property(
+    'App.router.loggedIn',
+    'views.length',
+    'App.router.clusterController.isLoaded',
+    'App.router.clusterInstallCompleted',
+    'App.router.wizardWatcherController.isWizardRunning'
+  ),
 
   itemViewClass: Em.View.extend({
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/test/app_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/app_test.js b/ambari-web/test/app_test.js
index 416f3af..1723821 100644
--- a/ambari-web/test/app_test.js
+++ b/ambari-web/test/app_test.js
@@ -578,35 +578,35 @@ describe('App', function () {
 
   });
 
-  describe('#upgradeIsNotFinished', function () {
+  describe('#wizardIsNotFinished', function () {
 
     var cases = [
       {
         upgradeState: 'INIT',
-        upgradeIsNotFinished: false
+        wizardIsNotFinished: false
       },
       {
         upgradeState: 'IN_PROGRESS',
-        upgradeIsNotFinished: true
+        wizardIsNotFinished: true
       },
       {
         upgradeState: 'HOLDING',
-        upgradeIsNotFinished: true
+        wizardIsNotFinished: true
       },
       {
         upgradeState: 'HOLDING_TIMEDOUT',
-        upgradeIsNotFinished: true
+        wizardIsNotFinished: true
       },
       {
         upgradeState: 'ABORTED',
-        upgradeIsNotFinished: true
+        wizardIsNotFinished: true
       }
     ];
 
     cases.forEach(function (item) {
       it(item.upgradeState, function () {
         App.set('upgradeState', item.upgradeState);
-        expect(App.get('upgradeIsNotFinished')).to.equal(item.upgradeIsNotFinished);
+        expect(App.get('wizardIsNotFinished')).to.equal(item.wizardIsNotFinished);
       });
     });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/test/controllers/global/update_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/update_controller_test.js b/ambari-web/test/controllers/global/update_controller_test.js
index e380b86..83f0630 100644
--- a/ambari-web/test/controllers/global/update_controller_test.js
+++ b/ambari-web/test/controllers/global/update_controller_test.js
@@ -62,7 +62,7 @@ describe('App.UpdateController', function () {
 
     it('isWorking = true', function () {
       controller.set('isWorking', true);
-      expect(App.updater.run.callCount).to.equal(11);
+      expect(App.updater.run.callCount).to.equal(12);
     });
   });
 
@@ -283,7 +283,7 @@ describe('App.UpdateController', function () {
         {
           currentStateName: 'versions',
           parentStateName: 'stackAndUpgrade',
-          upgradeIsNotFinished: true,
+          wizardIsNotFinished: true,
           isLoadUpgradeDataPending: true,
           loadUpgradeDataCallCount: 0,
           callbackCallCount: 1,
@@ -292,7 +292,7 @@ describe('App.UpdateController', function () {
         {
           currentStateName: 'stackUpgrade',
           parentStateName: null,
-          upgradeIsNotFinished: true,
+          wizardIsNotFinished: true,
           isLoadUpgradeDataPending: true,
           loadUpgradeDataCallCount: 0,
           callbackCallCount: 1,
@@ -301,7 +301,7 @@ describe('App.UpdateController', function () {
         {
           currentStateName: 'versions',
           parentStateName: null,
-          upgradeIsNotFinished: true,
+          wizardIsNotFinished: true,
           isLoadUpgradeDataPending: false,
           loadUpgradeDataCallCount: 1,
           callbackCallCount: 0,
@@ -310,7 +310,7 @@ describe('App.UpdateController', function () {
         {
           currentStateName: 'versions',
           parentStateName: null,
-          upgradeIsNotFinished: false,
+          wizardIsNotFinished: false,
           isLoadUpgradeDataPending: false,
           loadUpgradeDataCallCount: 0,
           callbackCallCount: 1,
@@ -319,7 +319,7 @@ describe('App.UpdateController', function () {
         {
           currentStateName: 'versions',
           parentStateName: null,
-          upgradeIsNotFinished: true,
+          wizardIsNotFinished: true,
           isLoadUpgradeDataPending: true,
           loadUpgradeDataCallCount: 0,
           callbackCallCount: 1,
@@ -328,7 +328,7 @@ describe('App.UpdateController', function () {
         {
           currentStateName: 'services',
           parentStateName: 'stackAndUpgrade',
-          upgradeIsNotFinished: true,
+          wizardIsNotFinished: true,
           isLoadUpgradeDataPending: false,
           loadUpgradeDataCallCount: 1,
           callbackCallCount: 0,
@@ -337,7 +337,7 @@ describe('App.UpdateController', function () {
         {
           currentStateName: 'services',
           parentStateName: 'stackAndUpgrade',
-          upgradeIsNotFinished: false,
+          wizardIsNotFinished: false,
           isLoadUpgradeDataPending: false,
           loadUpgradeDataCallCount: 0,
           callbackCallCount: 1,
@@ -346,7 +346,7 @@ describe('App.UpdateController', function () {
         {
           currentStateName: 'services',
           parentStateName: 'stackAndUpgrade',
-          upgradeIsNotFinished: true,
+          wizardIsNotFinished: true,
           isLoadUpgradeDataPending: true,
           loadUpgradeDataCallCount: 0,
           callbackCallCount: 1,
@@ -355,7 +355,7 @@ describe('App.UpdateController', function () {
         {
           currentStateName: 'widgets',
           parentStateName: 'dashboard',
-          upgradeIsNotFinished: true,
+          wizardIsNotFinished: true,
           isLoadUpgradeDataPending: false,
           loadUpgradeDataCallCount: 1,
           callbackCallCount: 0,
@@ -364,7 +364,7 @@ describe('App.UpdateController', function () {
         {
           currentStateName: 'widgets',
           parentStateName: 'dashboard',
-          upgradeIsNotFinished: false,
+          wizardIsNotFinished: false,
           isLoadUpgradeDataPending: false,
           loadUpgradeDataCallCount: 0,
           callbackCallCount: 1,
@@ -373,7 +373,7 @@ describe('App.UpdateController', function () {
         {
           currentStateName: 'widgets',
           parentStateName: 'dashboard',
-          upgradeIsNotFinished: true,
+          wizardIsNotFinished: true,
           isLoadUpgradeDataPending: true,
           loadUpgradeDataCallCount: 0,
           callbackCallCount: 1,
@@ -409,7 +409,7 @@ describe('App.UpdateController', function () {
         appGetMock.withArgs('router.mainAdminStackAndUpgradeController').returns(Em.Object.create({
           loadUpgradeData: mock.loadUpgradeData,
           isLoadUpgradeDataPending: item.isLoadUpgradeDataPending
-        })).withArgs('upgradeIsNotFinished').returns(item.upgradeIsNotFinished);
+        })).withArgs('wizardIsNotFinished').returns(item.wizardIsNotFinished);
         controller.updateUpgradeState(mock.callback);
         expect(mock.loadUpgradeData.callCount).to.equal(item.loadUpgradeDataCallCount);
         expect(mock.callback.callCount).to.equal(item.callbackCallCount);

http://git-wip-us.apache.org/repos/asf/ambari/blob/9763e644/ambari-web/test/controllers/global/wizard_watcher_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/wizard_watcher_controller_test.js b/ambari-web/test/controllers/global/wizard_watcher_controller_test.js
new file mode 100644
index 0000000..4afc70f
--- /dev/null
+++ b/ambari-web/test/controllers/global/wizard_watcher_controller_test.js
@@ -0,0 +1,151 @@
+/**
+ * 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.
+ */
+
+
+var App = require('app');
+require('controllers/global/wizard_watcher_controller');
+
+var controller;
+
+describe('App.wizardWatcherController', function () {
+  beforeEach(function() {
+    controller = App.WizardWatcherController.create();
+  });
+
+  describe("#isWizardRunning", function() {
+    it("wizardUser is null", function() {
+      controller.set('wizardUser', null);
+      controller.propertyDidChange('isWizardRunning');
+      expect(controller.get('isWizardRunning')).to.be.false;
+    });
+    it("wizardUser is correct", function() {
+      controller.set('wizardUser', 'admin');
+      controller.propertyDidChange('isWizardRunning');
+      expect(controller.get('isWizardRunning')).to.be.true;
+    });
+  });
+
+  describe("#wizardDisplayName", function() {
+    beforeEach(function () {
+      sinon.stub(App.router, 'get').returns(Em.Object.create({displayName: 'Wizard'}));
+    });
+    afterEach(function () {
+      App.router.get.restore();
+    });
+    it("controllerName is null", function() {
+      controller.set('controllerName', null);
+      controller.propertyDidChange('wizardDisplayName');
+      expect(controller.get('wizardDisplayName')).to.be.empty;
+    });
+    it("controllerName is correct", function() {
+      controller.set('controllerName', 'ctrl1');
+      controller.propertyDidChange('wizardDisplayName');
+      expect(controller.get('wizardDisplayName')).to.equal(Em.I18n.t('wizard.inProgress').format('Wizard'));
+    });
+  });
+
+
+  describe("#isNonWizardUser", function() {
+    beforeEach(function () {
+      sinon.stub(App.router, 'get').returns('admin');
+    });
+    afterEach(function () {
+      App.router.get.restore();
+    });
+    it("isWizardRunning is false", function() {
+      controller.reopen({
+        isWizardRunning: false
+      });
+      controller.propertyDidChange('isNonWizardUser');
+      expect(controller.get('isNonWizardUser')).to.be.false;
+    });
+    it("isWizardRunning is true, wizardUser is admin", function() {
+      controller.setProperties({
+        isWizardRunning: true,
+        wizardUser: 'admin'
+      });
+      controller.propertyDidChange('isNonWizardUser');
+      expect(controller.get('isNonWizardUser')).to.be.false;
+    });
+    it("isWizardRunning is true, wizardUser is admin2", function() {
+      controller.setProperties({
+        isWizardRunning: true,
+        wizardUser: 'admin2'
+      });
+      controller.propertyDidChange('isNonWizardUser');
+      expect(controller.get('isNonWizardUser')).to.be.true;
+    });
+  });
+
+  describe("#setUser()", function() {
+    beforeEach(function () {
+      sinon.stub(controller, 'postUserPref', Em.K);
+      sinon.stub(App.router, 'get').returns('admin');
+    });
+    afterEach(function () {
+      controller.postUserPref.restore();
+      App.router.get.restore();
+    });
+    it("post user pref", function() {
+      controller.setUser('ctrl1');
+      expect(controller.postUserPref.calledWith(controller.get('PREF_KEY'), {
+        userName: 'admin',
+        controllerName: 'ctrl1'
+      })).to.be.true;
+    });
+  });
+
+  describe("#resetUser()", function() {
+    beforeEach(function () {
+      sinon.stub(controller, 'postUserPref', Em.K);
+    });
+    afterEach(function () {
+      controller.postUserPref.restore();
+    });
+    it("post user pref", function() {
+      controller.resetUser('ctrl1');
+      expect(controller.postUserPref.calledWith(controller.get('PREF_KEY'), null)).to.be.true;
+    });
+  });
+
+  describe("#getUser()", function() {
+    beforeEach(function () {
+      sinon.stub(controller, 'getUserPref', Em.K);
+    });
+    afterEach(function () {
+      controller.getUserPref.restore();
+    });
+    it("get user pref", function() {
+      controller.getUser('ctrl1');
+      expect(controller.getUserPref.calledWith(controller.get('PREF_KEY'))).to.be.true;
+    });
+  });
+
+  describe("#getUserPrefSuccessCallback()", function() {
+    it("data is null", function() {
+      controller.getUserPrefSuccessCallback(null);
+      expect(controller.get('wizardUser')).to.be.null;
+      expect(controller.get('controllerName')).to.be.null;
+    });
+    it("data is correct", function() {
+      controller.getUserPrefSuccessCallback({userName: 'admin', controllerName: 'ctrl1'});
+      expect(controller.get('wizardUser')).to.equal('admin');
+      expect(controller.get('controllerName')).to.equal('ctrl1');
+    });
+  });
+});