You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by al...@apache.org on 2015/03/10 18:40:52 UTC

ambari git commit: AMBARI-9976. Host component action dropdown should show all supported custom commands for that service component (alexantonenko)

Repository: ambari
Updated Branches:
  refs/heads/trunk 57915556b -> 435f9a14b


AMBARI-9976. Host component action dropdown should show all supported custom commands for that service component (alexantonenko)


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

Branch: refs/heads/trunk
Commit: 435f9a14bfaf11f5eb0c35f9c141afea2dc36cbd
Parents: 5791555
Author: Alex Antonenko <hi...@gmail.com>
Authored: Tue Mar 10 18:08:35 2015 +0200
Committer: Alex Antonenko <hi...@gmail.com>
Committed: Tue Mar 10 19:40:48 2015 +0200

----------------------------------------------------------------------
 ambari-web/app/controllers/main/host/details.js |   2 +-
 ambari-web/app/models/host_component.js         | 105 +++++++++++++++
 ambari-web/app/models/quick_links.js            |   4 +-
 .../main/host/details/host_component_view.js    | 112 +++++++++++++---
 ambari-web/app/views/main/service/item.js       | 109 +---------------
 .../host/details/host_component_view_test.js    | 127 +++++++++++++++++++
 ambari-web/test/views/main/service/item_test.js |   8 +-
 7 files changed, 340 insertions(+), 127 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/435f9a14/ambari-web/app/controllers/main/host/details.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/host/details.js b/ambari-web/app/controllers/main/host/details.js
index 5eac7ca..5c035c4 100644
--- a/ambari-web/app/controllers/main/host/details.js
+++ b/ambari-web/app/controllers/main/host/details.js
@@ -1910,7 +1910,7 @@ App.MainHostDetailsController = Em.Controller.extend({
         sender: controller,
         data : {
           command : context.command,
-          context : Em.I18n.t('services.service.actions.run.executeCustomCommand.context').format(context.command),
+          context : context.context || Em.I18n.t('services.service.actions.run.executeCustomCommand.context').format(context.command),
           hosts : context.hosts,
           serviceName : context.service,
           componentName : context.component

http://git-wip-us.apache.org/repos/asf/ambari/blob/435f9a14/ambari-web/app/models/host_component.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/host_component.js b/ambari-web/app/models/host_component.js
index 8eb8dad..82ee85a 100644
--- a/ambari-web/app/models/host_component.js
+++ b/ambari-web/app/models/host_component.js
@@ -225,3 +225,108 @@ App.HostComponentStatus = {
   }
 };
 
+App.HostComponentActionMap = {
+  getMap: function(ctx) {
+    return {
+      RESTART_ALL: {
+        action: 'restartAllHostComponents',
+        context: ctx.get('serviceName'),
+        label: Em.I18n.t('restart.service.all'),
+        cssClass: 'icon-repeat',
+        disabled: false
+      },
+      RUN_SMOKE_TEST: {
+        action: 'runSmokeTest',
+        label: Em.I18n.t('services.service.actions.run.smoke'),
+        cssClass: 'icon-thumbs-up-alt'
+      },
+      REFRESH_CONFIGS: {
+        action: 'refreshConfigs',
+        label: Em.I18n.t('hosts.host.details.refreshConfigs'),
+        cssClass: 'icon-refresh',
+        disabled: !ctx.get('controller.content.isRestartRequired')
+      },
+      REFRESHQUEUES: {
+        action: 'refreshYarnQueues',
+        customCommand: 'REFRESHQUEUES',
+        context : Em.I18n.t('services.service.actions.run.yarnRefreshQueues.context'),
+        label: Em.I18n.t('services.service.actions.run.yarnRefreshQueues.menu'),
+        cssClass: 'icon-refresh',
+        disabled: false
+      },
+      ROLLING_RESTART: {
+        action: 'rollingRestart',
+        context: ctx.get('rollingRestartComponent'),
+        label: Em.I18n.t('rollingrestart.dialog.title'),
+        cssClass: 'icon-time',
+        disabled: false
+      },
+      TOGGLE_PASSIVE: {
+        action: 'turnOnOffPassive',
+        context: ctx.get('isPassive') ? Em.I18n.t('passiveState.turnOffFor').format(ctx.get('displayName')) : Em.I18n.t('passiveState.turnOnFor').format(ctx.get('displayName')),
+        label: ctx.get('isPassive') ? Em.I18n.t('passiveState.turnOff') : Em.I18n.t('passiveState.turnOn'),
+        cssClass: 'icon-medkit',
+        disabled: false
+      },
+      TOGGLE_NN_HA: {
+        action: App.get('isHaEnabled') ? 'disableHighAvailability' : 'enableHighAvailability',
+        label: App.get('isHaEnabled') ? Em.I18n.t('admin.highAvailability.button.disable') : Em.I18n.t('admin.highAvailability.button.enable'),
+        cssClass: App.get('isHaEnabled') ? 'icon-arrow-down' : 'icon-arrow-up',
+        isHidden: (App.get('isHaEnabled') || (/^1.3/.test(App.get('currentStackVersionNumber')))),
+        disabled: App.get('isSingleNode')
+      },
+      TOGGLE_RM_HA: {
+        action: 'enableRMHighAvailability',
+        label: Em.I18n.t('admin.rm_highAvailability.button.enable'),
+        cssClass: 'icon-arrow-up',
+        isHidden: App.get('isRMHaEnabled'),
+        disabled: App.get('isSingleNode')
+      },
+      MOVE_COMPONENT: {
+        action: 'reassignMaster',
+        context: '',
+        label: Em.I18n.t('services.service.actions.reassign.master'),
+        cssClass: 'icon-share-alt'
+      },
+      STARTDEMOLDAP: {
+        action: 'startLdapKnox',
+        customCommand: 'STARTDEMOLDAP',
+        context: Em.I18n.t('services.service.actions.run.startLdapKnox.context'),
+        label: Em.I18n.t('services.service.actions.run.startLdapKnox.context'),
+        cssClass: 'icon-play-sign',
+        disabled: false
+      },
+      STOPDEMOLDAP: {
+        action: 'stopLdapKnox',
+        customCommand: 'STOPDEMOLDAP',
+        context: Em.I18n.t('services.service.actions.run.stopLdapKnox.context'),
+        label: Em.I18n.t('services.service.actions.run.stopLdapKnox.context'),
+        cssClass: 'icon-stop',
+        disabled: false
+      },
+      REBALANCEHDFS: {
+        action: 'rebalanceHdfsNodes',
+        customCommand: 'REBALANCEHDFS',
+        context: Em.I18n.t('services.service.actions.run.rebalanceHdfsNodes.context'),
+        label: Em.I18n.t('services.service.actions.run.rebalanceHdfsNodes'),
+        cssClass: 'icon-refresh',
+        disabled: false
+      },
+      DOWNLOAD_CLIENT_CONFIGS: {
+        action: ctx.get('controller.isSeveralClients') ? '' : 'downloadClientConfigs',
+        label: Em.I18n.t('services.service.actions.downloadClientConfigs'),
+        cssClass: 'icon-download-alt',
+        isHidden: !!ctx.get('controller.content.clientComponents') ? ctx.get('controller.content.clientComponents').rejectProperty('totalCount', 0).length == 0 : false,
+        disabled: false,
+        hasSubmenu: ctx.get('controller.isSeveralClients'),
+        submenuOptions: ctx.get('controller.clientComponents')
+      },
+      MASTER_CUSTOM_COMMAND: {
+        action: 'executeCustomCommand',
+        cssClass: 'icon-play-circle',
+        isHidden: false,
+        disabled: false
+      }
+    }
+  }
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/435f9a14/ambari-web/app/models/quick_links.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/quick_links.js b/ambari-web/app/models/quick_links.js
index 57f912a..4d686d5 100644
--- a/ambari-web/app/models/quick_links.js
+++ b/ambari-web/app/models/quick_links.js
@@ -286,9 +286,9 @@ App.QuickLinks.FIXTURES = [
   {
     id:32,
     label:'Falcon Web UI',
-    url:'%@://%@:%@/index.html?user.name=%@',
+    url:'%@://%@:%@/',
     service_id: 'FALCON',
-    template:'%@://%@:%@/index.html?user.name=%@',
+    template:'%@://%@:%@/',
     http_config: 'falcon_port',
     site: 'falcon-env',
     regex: '^(\\d+)$',

http://git-wip-us.apache.org/repos/asf/ambari/blob/435f9a14/ambari-web/app/views/main/host/details/host_component_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/host/details/host_component_view.js b/ambari-web/app/views/main/host/details/host_component_view.js
index 8d7e102..758a2bd 100644
--- a/ambari-web/app/views/main/host/details/host_component_view.js
+++ b/ambari-web/app/views/main/host/details/host_component_view.js
@@ -27,7 +27,7 @@ App.HostComponentView = Em.View.extend({
    * @type {App.HostComponent}
    */
   content: null,
-
+  excludedMasterCommands: ['DECOMMISSION', 'RECOMMISSION'],
   /**
    * @type {App.HostComponent}
    */
@@ -222,6 +222,21 @@ App.HostComponentView = Em.View.extend({
   },
 
   /**
+   * Gets number of current running components that are applied to the cluster
+   * @returns {Number}
+   */
+  runningComponentCounter: function () {
+    var runningComponents;
+    var self = this;
+
+    runningComponents = App.HostComponent.find().filter(function (component) {
+      return (component.get('componentName') === self.get('content.componentName') && [App.HostComponentStatus.started, App.HostComponentStatus.starting].contains(component.get('workStatus')))
+    });
+
+    return runningComponents ? runningComponents.length : 0;
+  },
+
+  /**
    * Check if component may be reassinged to another host
    * @type {bool}
    */
@@ -290,25 +305,92 @@ App.HostComponentView = Em.View.extend({
    * Get custom commands for slave components
    */
   customCommands: function() {
+    var customCommands;
     var hostComponent = this.get('content');
     var component = App.StackServiceComponent.find(hostComponent.get('componentName'));
+
+    customCommands = this.getCustomCommands(component, hostComponent, component.get('isSlave'));
+
+    return customCommands;
+  }.property('content', 'workStatus'),
+
+  /**
+   * Get a list of custom commands
+   *
+   * @param component
+   * @param hostComponent
+   * @param isSlave
+   * @returns {Array}
+   */
+  getCustomCommands: function (component, hostComponent, isSlave) {
+    isSlave = isSlave || false;
+
+    if (!component || !hostComponent) {
+      return [];
+    }
+
+    var self = this;
+    var commands = component.get('customCommands');
     var customCommands = [];
-    var commands;
-
-    if (component.get('isSlave')) {
-      commands = component.get('customCommands');
-      commands.forEach(function(command) {
-        customCommands.push({
-          label: Em.I18n.t('services.service.actions.run.executeCustomCommand.menu').format(command),
-          service: component.get('serviceName'),
-          hosts: hostComponent.get('hostName'),
-          component: component.get('componentName'),
-          command: command
-        });
+
+    commands.forEach(function(command) {
+      if (!isSlave && !self.meetsCustomCommandReq(component, command)) {
+        return;
+      }
+      customCommands.push({
+        label: self.getCustomCommandLabel(command, isSlave),
+        service: component.get('serviceName'),
+        hosts: hostComponent.get('hostName'),
+        context: isSlave ? null : App.HostComponentActionMap.getMap(self)[command].context,
+        component: component.get('componentName'),
+        command: command
       });
-    }
+    });
 
     return customCommands;
-  }.property('content')
+  },
+
+  /**
+   * Get the Label of the custom command
+   *
+   * @param command
+   * @returns {String}
+   */
+  getCustomCommandLabel: function (command, isSlave) {
+    if (isSlave) {
+      return Em.I18n.t('services.service.actions.run.executeCustomCommand.menu').format(command)
+    }
+    return App.HostComponentActionMap.getMap(this)[command].label;
+  },
+
+  /**
+   * The custom command meets the requirements to be active on master
+   *
+   * @param component
+   * @param command
+   *
+   * @return {Boolean}
+   */
+  meetsCustomCommandReq: function (component, command) {
+    var excludedMasterCommands = this.get('excludedMasterCommands');
+
+    if (excludedMasterCommands.indexOf(command) >= 0) {
+      return false;
+    }
+
+    if (component.get('cardinality') !== '1') {
+      if (!this.get('isStart')) {
+        if (this.componentCounter() > 1) {
+          if (this.runningComponentCounter()) {
+            return false;
+          }
+        } else {
+          return false;
+        }
+      }
+    }
+
+    return true;
+  }
 
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/435f9a14/ambari-web/app/views/main/service/item.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/item.js b/ambari-web/app/views/main/service/item.js
index d6d9173..c4a27b3 100644
--- a/ambari-web/app/views/main/service/item.js
+++ b/ambari-web/app/views/main/service/item.js
@@ -44,107 +44,6 @@ App.MainServiceItemView = Em.View.extend({
     'KNOX_GATEWAY': ['STARTDEMOLDAP','STOPDEMOLDAP']
   },
 
-  actionMap: function() {
-    return {
-      RESTART_ALL: {
-        action: 'restartAllHostComponents',
-        context: this.get('serviceName'),
-        label: Em.I18n.t('restart.service.all'),
-        cssClass: 'icon-repeat',
-        disabled: false
-      },
-      RUN_SMOKE_TEST: {
-        action: 'runSmokeTest',
-        label: Em.I18n.t('services.service.actions.run.smoke'),
-        cssClass: 'icon-thumbs-up-alt'
-      },
-      REFRESH_CONFIGS: {
-        action: 'refreshConfigs',
-        label: Em.I18n.t('hosts.host.details.refreshConfigs'),
-        cssClass: 'icon-refresh',
-        disabled: !this.get('controller.content.isRestartRequired')
-      },
-      REFRESH_YARN_QUEUE: {
-        action: 'refreshYarnQueues',
-        customCommand: 'REFRESHQUEUES',
-        label: Em.I18n.t('services.service.actions.run.yarnRefreshQueues.menu'),
-        cssClass: 'icon-refresh',
-        disabled: false
-      },
-      ROLLING_RESTART: {
-        action: 'rollingRestart',
-        context: this.get('rollingRestartComponent'),
-        label: Em.I18n.t('rollingrestart.dialog.title'),
-        cssClass: 'icon-time',
-        disabled: false
-      },
-      TOGGLE_PASSIVE: {
-        action: 'turnOnOffPassive',
-        context: this.get('isPassive') ? Em.I18n.t('passiveState.turnOffFor').format(this.get('displayName')) : Em.I18n.t('passiveState.turnOnFor').format(this.get('displayName')),
-        label: this.get('isPassive') ? Em.I18n.t('passiveState.turnOff') : Em.I18n.t('passiveState.turnOn'),
-        cssClass: 'icon-medkit',
-        disabled: false
-      },
-      TOGGLE_NN_HA: {
-        action: App.get('isHaEnabled') ? 'disableHighAvailability' : 'enableHighAvailability',
-        label: App.get('isHaEnabled') ? Em.I18n.t('admin.highAvailability.button.disable') : Em.I18n.t('admin.highAvailability.button.enable'),
-        cssClass: App.get('isHaEnabled') ? 'icon-arrow-down' : 'icon-arrow-up',
-        isHidden: (App.get('isHaEnabled') || (/^1.3/.test(App.get('currentStackVersionNumber')))),
-        disabled: App.get('isSingleNode')
-      },
-      TOGGLE_RM_HA: {
-        action: 'enableRMHighAvailability',
-        label: Em.I18n.t('admin.rm_highAvailability.button.enable'),
-        cssClass: 'icon-arrow-up',
-        isHidden: App.get('isRMHaEnabled'),
-        disabled: App.get('isSingleNode')
-      },
-      MOVE_COMPONENT: {
-        action: 'reassignMaster',
-        context: '',
-        label: Em.I18n.t('services.service.actions.reassign.master'),
-        cssClass: 'icon-share-alt'
-      },
-      STARTDEMOLDAP: {
-        action: 'startLdapKnox',
-        customCommand: 'STARTDEMOLDAP',
-        label: Em.I18n.t('services.service.actions.run.startLdapKnox.context'),
-        cssClass: 'icon-play-sign',
-        disabled: false
-      },
-      STOPDEMOLDAP: {
-        action: 'stopLdapKnox',
-        customCommand: 'STOPDEMOLDAP',
-        label: Em.I18n.t('services.service.actions.run.stopLdapKnox.context'),
-        cssClass: 'icon-stop',
-        disabled: false
-      },
-      REBALANCE_HDFS: {
-        action: 'rebalanceHdfsNodes',
-        customCommand: 'REBALANCEHDFS',
-        context: Em.I18n.t('services.service.actions.run.rebalanceHdfsNodes.context'),
-        label: Em.I18n.t('services.service.actions.run.rebalanceHdfsNodes'),
-        cssClass: 'icon-refresh',
-        disabled: false
-      },
-      DOWNLOAD_CLIENT_CONFIGS: {
-        action: this.get('controller.isSeveralClients') ? '' : 'downloadClientConfigs',
-        label: Em.I18n.t('services.service.actions.downloadClientConfigs'),
-        cssClass: 'icon-download-alt',
-        isHidden: !!this.get('controller.content.clientComponents') ? this.get('controller.content.clientComponents').rejectProperty('totalCount', 0).length == 0 : false,
-        disabled: false,
-        hasSubmenu: this.get('controller.isSeveralClients'),
-        submenuOptions: this.get('controller.clientComponents')
-      },
-      MASTER_CUSTOM_COMMAND: {
-        action: 'executeCustomCommand',
-        cssClass: 'icon-play-circle',
-        isHidden: false,
-        disabled: false
-      }
-    }
-  },
-
    addActionMap: function() {
      return [
       {
@@ -184,7 +83,7 @@ App.MainServiceItemView = Em.View.extend({
   /**
    * Create option for MOVE_COMPONENT or ROLLING_RESTART task.
    *
-   * @param {Object} option - one of the options that return by <code>actionMap()</code>
+   * @param {Object} option - one of the options that return by <code>App.HostComponentActionMap.getMap()</code>
    * @param {Object} fields - option fields to add/rewrite
    * @return {Object}
    */
@@ -204,7 +103,7 @@ App.MainServiceItemView = Em.View.extend({
     var service = this.get('controller.content');
     var allMasters = service.get('hostComponents').filterProperty('isMaster').mapProperty('componentName').uniq();
     var allSlaves = service.get('slaveComponents').rejectProperty('totalCount', 0).mapProperty('componentName');
-    var actionMap = this.actionMap();
+    var actionMap = App.HostComponentActionMap.getMap(this);
     var serviceCheckSupported = App.get('services.supportsServiceCheck').contains(service.get('serviceName'));
     var hasConfigTab = this.get('hasConfigTab');
     var excludedCommands = this.get('mastersExcludedCommands');
@@ -221,7 +120,7 @@ App.MainServiceItemView = Em.View.extend({
         options.push(actionMap.REFRESH_CONFIGS);
       }
       if (this.get('serviceName') === 'YARN') {
-        options.push(actionMap.REFRESH_YARN_QUEUE);
+        options.push(actionMap.REFRESHQUEUES);
       }
       options.push(actionMap.RESTART_ALL);
       allSlaves.filter(function (slave) {
@@ -261,7 +160,7 @@ App.MainServiceItemView = Em.View.extend({
       if (serviceName === 'HDFS' && nnComponent) {
         var namenodeCustomCommands = nnComponent.get('customCommands');
         if (namenodeCustomCommands && namenodeCustomCommands.contains('REBALANCEHDFS'))
-        options.push(actionMap.REBALANCE_HDFS);
+        options.push(actionMap.REBALANCEHDFS);
       }
 
       if (serviceName === 'KNOX' && knoxGatewayComponent) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/435f9a14/ambari-web/test/views/main/host/details/host_component_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/host/details/host_component_view_test.js b/ambari-web/test/views/main/host/details/host_component_view_test.js
index 2cb5105..44cb5fa 100644
--- a/ambari-web/test/views/main/host/details/host_component_view_test.js
+++ b/ambari-web/test/views/main/host/details/host_component_view_test.js
@@ -455,4 +455,131 @@ describe('App.HostComponentView', function() {
     });
   });
 
+  describe('#masterCustomCommands', function() {
+    var content = [
+      {
+        componentName: 'MASTER_COMPONENT',
+        hostName: '01'
+      }
+    ];
+
+    beforeEach(function () {
+      sinon.stub(App.HostComponentActionMap, 'getMap', function () {
+        return {
+          REFRESHQUEUES: {
+            action: 'refreshYarnQueues',
+            customCommand: 'REFRESHQUEUES',
+            context : Em.I18n.t('services.service.actions.run.yarnRefreshQueues.context'),
+            label: Em.I18n.t('services.service.actions.run.yarnRefreshQueues.menu'),
+            cssClass: 'icon-refresh',
+            disabled: false
+          }
+        }
+      });
+    });
+
+
+    //two components, one running, active one is stopped
+    it('Should not get custom commands for master component if component not running', function() {
+      sinon.stub(App.StackServiceComponent, 'find', function() {
+        return Em.Object.create({
+          componentName: 'MASTER_COMPONENT',
+          isSlave: false,
+          isMaster: true,
+          isStart: false,
+          customCommands: ['DECOMMISSION', 'REFRESHQUEUES']
+        });
+      });
+
+      sinon.stub(hostComponentView, 'componentCounter', function() {
+        return 2;
+      });
+
+      sinon.stub(hostComponentView, 'runningComponentCounter', function () {
+        return 1;
+      });
+
+      hostComponentView.set('content', content);
+      expect(hostComponentView.get('customCommands')).to.have.length(0);
+    });
+
+    //two components, none running
+    it('Should get custom commands for master component when all components are stopped', function() {
+      sinon.stub(App.StackServiceComponent, 'find', function() {
+        return Em.Object.create({
+          componentName: 'MASTER_COMPONENT',
+          isSlave: false,
+          isMaster: true,
+          isStart: false,
+          customCommands: ['DECOMMISSION', 'REFRESHQUEUES']
+        });
+      });
+
+      sinon.stub(hostComponentView, 'componentCounter', function() {
+        return 2;
+      });
+
+      sinon.stub(hostComponentView, 'runningComponentCounter', function () {
+        return 0;
+      });
+
+      hostComponentView.set('content', content);
+      expect(hostComponentView.get('customCommands')).to.have.length(1);
+    });
+
+    //two components, two running, only commission and decommission custom commands
+    it('Should not show COMMISSION and DECOMMISSION on master', function() {
+      sinon.stub(App.StackServiceComponent, 'find', function() {
+        return Em.Object.create({
+          componentName: 'MASTER_COMPONENT',
+          isSlave: false,
+          isMaster: true,
+          isStart: false,
+          customCommands: ['DECOMMISSION', 'RECOMMISSION']
+        });
+      });
+
+      sinon.stub(hostComponentView, 'componentCounter', function() {
+        return 2;
+      });
+
+      sinon.stub(hostComponentView, 'runningComponentCounter', function () {
+        return 2;
+      });
+
+      hostComponentView.set('content', content);
+      expect(hostComponentView.get('customCommands')).to.have.length(0);
+    });
+
+    //one component, one running, cardinality 1
+    it('Should show custom command for cardinality 1', function() {
+      sinon.stub(App.StackServiceComponent, 'find', function() {
+        return Em.Object.create({
+          isSlave: false,
+          cardinality: '1',
+          isMaster: true,
+          isStart: true,
+          customCommands: ['DECOMMISSION', 'REFRESHQUEUES']
+        });
+      });
+
+      sinon.stub(hostComponentView, 'componentCounter', function() {
+        return 1;
+      });
+
+      sinon.stub(hostComponentView, 'runningComponentCounter', function () {
+        return 1;
+      });
+
+      hostComponentView.set('content', content);
+      expect(hostComponentView.get('customCommands')).to.have.length(1);
+    });
+
+    afterEach(function() {
+      App.HostComponentActionMap.getMap.restore();
+      App.StackServiceComponent.find.restore();
+      hostComponentView.componentCounter.restore();
+      hostComponentView.runningComponentCounter.restore();
+    });
+  });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/435f9a14/ambari-web/test/views/main/service/item_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/service/item_test.js b/ambari-web/test/views/main/service/item_test.js
index 81a9bf9..fb9227a 100644
--- a/ambari-web/test/views/main/service/item_test.js
+++ b/ambari-web/test/views/main/service/item_test.js
@@ -42,7 +42,7 @@ describe('App.MainServiceItemView', function () {
     var allMastersExcludedCommands = mastersExcludedCommands.reduce(function (previous, current) {
       return previous.concat(current);
     });
-    var actionMap = view.actionMap();
+    var actionMap = App.HostComponentActionMap.getMap(view);
 
     var customActionsArray = [];
     for (var iter in actionMap) {
@@ -174,7 +174,7 @@ describe('App.MainServiceItemView', function () {
             })
           ],
           result: [
-            {"action": "refreshYarnQueues", "customCommand": "REFRESHQUEUES", "label": "Refresh YARN Capacity Scheduler", "cssClass": "icon-refresh", "disabled": false},
+            {"action": "refreshYarnQueues", "customCommand": "REFRESHQUEUES", "context": "Refresh YARN Capacity Scheduler", "label": "Refresh YARN Capacity Scheduler", "cssClass": "icon-refresh", "disabled": false},
             {"action": "restartAllHostComponents", "context": "YARN", "label": "Restart All", "cssClass": "icon-repeat", "disabled": false},
             {"action": "rollingRestart", "label": "Restart NodeManagers", "cssClass": "icon-time", "disabled": false, "context": "NODEMANAGER"},
             {"action": "reassignMaster", "context": "APP_TIMELINE_SERVER", "label": "Move App Timeline Server", "cssClass": "icon-share-alt", "disabled": false},
@@ -336,8 +336,8 @@ describe('App.MainServiceItemView', function () {
             {"action": "restartAllHostComponents", "context": "KNOX", "label": "Restart All", "cssClass": "icon-repeat", "disabled": false},
             {"action": "runSmokeTest", "label": "Run Service Check", "cssClass": "icon-thumbs-up-alt"},
             {"action": "turnOnOffPassive", "context": "Turn On Maintenance Mode for Knox", "label": "Turn On Maintenance Mode", "cssClass": "icon-medkit", "disabled": false},
-            {"action": "startLdapKnox", "customCommand": "STARTDEMOLDAP", "label": "Start Demo LDAP", "cssClass": "icon-play-sign", "disabled": false},
-            {"action": "stopLdapKnox", "customCommand": "STOPDEMOLDAP", "label": "Stop Demo LDAP", "cssClass": "icon-stop", "disabled": false},
+            {"action": "startLdapKnox", "customCommand": "STARTDEMOLDAP", "context": "Start Demo LDAP",  "label": "Start Demo LDAP", "cssClass": "icon-play-sign", "disabled": false},
+            {"action": "stopLdapKnox", "customCommand": "STOPDEMOLDAP", "context": "Stop Demo LDAP", "label": "Stop Demo LDAP", "cssClass": "icon-stop", "disabled": false},
             {"action": "downloadClientConfigs", "label": "Download Client Configs", "cssClass": "icon-download-alt", "isHidden": true, "disabled": false, "hasSubmenu": false, "submenuOptions": []}
           ]
         }