Ver Fonte

AMBARI-15443:Make Host bulk command menu item list stack driven instead of a hardcoded list in UI code (dili)

Di Li há 9 anos atrás
pai
commit
2410929485
21 ficheiros alterados com 329 adições e 37 exclusões
  1. 67 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceComponentResponse.java
  2. 18 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceComponentResourceProvider.java
  3. 4 0
      ambari-server/src/main/java/org/apache/ambari/server/stack/ComponentModule.java
  4. 72 0
      ambari-server/src/main/java/org/apache/ambari/server/state/BulkCommandDefinition.java
  5. 18 0
      ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java
  6. 3 0
      ambari-server/src/main/resources/common-services/HAWQ/2.0.0/metainfo.xml
  7. 5 0
      ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/metainfo.xml
  8. 5 0
      ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml
  9. 3 0
      ambari-server/src/main/resources/common-services/PXF/3.0.0/metainfo.xml
  10. 4 0
      ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/metainfo.xml
  11. 5 0
      ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/metainfo.xml
  12. 4 0
      ambari-server/src/main/resources/properties.json
  13. 36 0
      ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
  14. 23 0
      ambari-server/src/test/java/org/apache/ambari/server/stack/ComponentModuleTest.java
  15. 5 0
      ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HBASE/metainfo.xml
  16. 5 0
      ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/metainfo.xml
  17. 5 0
      ambari-server/src/test/resources/stacks/HDP/2.0.6/services/HBASE/metainfo.xml
  18. 3 0
      ambari-web/app/mappers/stack_service_mapper.js
  19. 3 0
      ambari-web/app/models/stack_service_component.js
  20. 17 36
      ambari-web/app/views/main/host/hosts_table_menu_view.js
  21. 24 1
      ambari-web/test/mappers/stack_service_mapper_test.js

+ 67 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/StackServiceComponentResponse.java

@@ -19,6 +19,7 @@
 package org.apache.ambari.server.controller;
 
 import org.apache.ambari.server.state.AutoDeployInfo;
+import org.apache.ambari.server.state.BulkCommandDefinition;
 import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.CustomCommandDefinition;
 
@@ -95,6 +96,9 @@ public class StackServiceComponentResponse {
    */
   private boolean recoveryEnabled;
 
+  private String bulkCommandsDisplayName;
+  private String bulkCommandMasterComponentName;
+  private boolean hasBulkCommands;
 
   /**
    * Constructor.
@@ -112,6 +116,9 @@ public class StackServiceComponentResponse {
     versionAdvertised = component.isVersionAdvertised();
     autoDeploy = component.getAutoDeploy();
     recoveryEnabled = component.isRecoveryEnabled();
+    hasBulkCommands = componentHasBulkCommands(component);
+    bulkCommandsDisplayName = getBulkCommandsDisplayName(component);
+    bulkCommandMasterComponentName = getBulkCommandsMasterComponentName(component);
 
     // the custom command names defined for this component
     List<CustomCommandDefinition> definitions = component.getCustomCommands();
@@ -125,6 +132,54 @@ public class StackServiceComponentResponse {
     }
   }
 
+  /**
+   * Get bulk command master component name
+   *
+   * @param component
+   *          the component to generate the response from (not {@code null}).
+   * @return master component name
+   */
+  private String getBulkCommandsMasterComponentName(ComponentInfo component) {
+    BulkCommandDefinition o = component.getBulkCommandDefinition();
+    if (o == null) {
+      return "";
+    } else {
+      return o.getMasterComponent();
+    }
+  }
+
+  /**
+   * Get the display name shown on the user interface which bulk commands are grouped under
+   *
+   * @param component
+   *          the component to generate the response from (not {@code null}).
+   * @return display name of the bulk command group
+   */
+  private String getBulkCommandsDisplayName(ComponentInfo component) {
+    BulkCommandDefinition o = component.getBulkCommandDefinition();
+    if (o == null) {
+      return "";
+    } else {
+      return o.getDisplayName();
+    }
+  }
+
+  /**
+   * Determine if the component has bulk commands
+   *
+   * @param component
+   *          the component to generate the response from (not {@code null}).
+   * @return boolean
+   */
+  private boolean componentHasBulkCommands(ComponentInfo component) {
+    BulkCommandDefinition o = component.getBulkCommandDefinition();
+    if (o == null) {
+      return false;
+    } else {
+      return o.getDisplayName() != null && !o.getDisplayName().trim().isEmpty();
+    }
+  }
+
   /**
    * Get stack name.
    *
@@ -352,4 +407,16 @@ public class StackServiceComponentResponse {
   public List<String> getCustomCommands() {
     return customCommands;
   }
+
+  public boolean hasBulkCommands(){
+    return hasBulkCommands;
+  }
+
+  public String getBulkCommandsDisplayName(){
+    return bulkCommandsDisplayName == null ? "":bulkCommandsDisplayName;
+  }
+
+  public String getBulkCommandsMasterComponentName(){
+    return bulkCommandMasterComponentName == null ? "":bulkCommandMasterComponentName;
+  }
 }

+ 18 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackServiceComponentResourceProvider.java

@@ -65,6 +65,15 @@ public class StackServiceComponentResourceProvider extends
   private static final String CUSTOM_COMMANDS_PROPERTY_ID = PropertyHelper.getPropertyId(
       "StackServiceComponents", "custom_commands");
 
+  private static final String HAS_BULK_COMMANDS_PROPERTY_ID = PropertyHelper.getPropertyId(
+        "StackServiceComponents", "has_bulk_commands_definition");
+
+  private static final String BULK_COMMANDS_DISPLAY_NAME_PROPERTY_ID = PropertyHelper.getPropertyId(
+      "StackServiceComponents", "bulk_commands_display_name");
+
+  private static final String BULK_COMMANDS_MASTER_COMPONENT_NAME_PROPERTY_ID = PropertyHelper.getPropertyId(
+      "StackServiceComponents", "bulk_commands_master_component_name");
+
   private static final String RECOVERY_ENABLED = PropertyHelper.getPropertyId(
       "StackServiceComponents", "recovery_enabled");
 
@@ -150,6 +159,15 @@ public class StackServiceComponentResourceProvider extends
       setResourceProperty(resource, CUSTOM_COMMANDS_PROPERTY_ID,
           response.getCustomCommands(), requestedIds);
 
+      setResourceProperty(resource, BULK_COMMANDS_DISPLAY_NAME_PROPERTY_ID,
+          response.getBulkCommandsDisplayName(), requestedIds);
+
+      setResourceProperty(resource, BULK_COMMANDS_MASTER_COMPONENT_NAME_PROPERTY_ID,
+          response.getBulkCommandsMasterComponentName(), requestedIds);
+
+      setResourceProperty(resource, HAS_BULK_COMMANDS_PROPERTY_ID,
+          response.hasBulkCommands(), requestedIds);
+
       AutoDeployInfo autoDeployInfo = response.getAutoDeploy();
       if (autoDeployInfo != null) {
         setResourceProperty(resource, AUTO_DEPLOY_ENABLED_ID,

+ 4 - 0
ambari-server/src/main/java/org/apache/ambari/server/stack/ComponentModule.java

@@ -90,6 +90,10 @@ public class ComponentModule extends BaseModule<ComponentModule, ComponentInfo>
 
       componentInfo.setRecoveryEnabled(parentInfo.isRecoveryEnabled());
 
+      if(componentInfo.getBulkCommandDefinition() == null){
+        componentInfo.setBulkCommands(parentInfo.getBulkCommandDefinition());
+      }
+
       mergeComponentDependencies(parentInfo.getDependencies(),
               componentInfo.getDependencies());
 

+ 72 - 0
ambari-server/src/main/java/org/apache/ambari/server/state/BulkCommandDefinition.java

@@ -0,0 +1,72 @@
+/**
+ * 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.
+ */
+package org.apache.ambari.server.state;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+import javax.xml.bind.annotation.*;
+
+/**
+ * Represents the customCommand tag at service/component metainfo
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+public class BulkCommandDefinition {
+
+  private String displayName;
+  private String masterComponent;
+
+  public String getDisplayName() {
+    return displayName;
+  }
+
+  public void setDisplayName(String displayName){
+    this.displayName = displayName;
+  }
+
+  public String getMasterComponent() {
+    return masterComponent;
+  }
+
+  public void setMasterComponent(String masterComponent){
+    this.masterComponent = masterComponent;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj == null) {
+      return false;
+    }
+    if (obj == this) {
+      return true;
+    }
+    if (! (obj instanceof BulkCommandDefinition)) {
+      return false;
+    }
+
+    BulkCommandDefinition rhs = (BulkCommandDefinition) obj;
+    return new EqualsBuilder()
+        .append(masterComponent, rhs.masterComponent)
+        .append(displayName, rhs.displayName).isEquals();
+  }
+
+  @Override
+  public int hashCode() {
+    return new HashCodeBuilder(17, 31).append(displayName).append(masterComponent).toHashCode();
+  }
+}

+ 18 - 0
ambari-server/src/main/java/org/apache/ambari/server/state/ComponentInfo.java

@@ -86,6 +86,12 @@ public class ComponentInfo {
   @XmlElements(@XmlElement(name="customCommand"))
   private List<CustomCommandDefinition> customCommands;
 
+  /**
+   * bulk commands shown in the Hosts actions
+   * */
+  @XmlElement(name="bulkCommands")
+  private BulkCommandDefinition bulkCommandDefinition;
+
   /**
    * Component dependencies to other components.
    */
@@ -127,6 +133,7 @@ public class ComponentInfo {
     commandScript = prototype.commandScript;
     logs = prototype.logs;
     customCommands = prototype.customCommands;
+    bulkCommandDefinition = prototype.bulkCommandDefinition;
     dependencies = prototype.dependencies;
     autoDeploy = prototype.autoDeploy;
     configDependencies = prototype.configDependencies;
@@ -232,6 +239,14 @@ public class ComponentInfo {
     return null;
   }
 
+  public BulkCommandDefinition getBulkCommandDefinition() {
+    return bulkCommandDefinition;
+  }
+
+  public void setBulkCommands(BulkCommandDefinition bulkCommandDefinition) {
+    this.bulkCommandDefinition = bulkCommandDefinition;
+  }
+
   public List<DependencyInfo> getDependencies() {
     return dependencies;
   }
@@ -319,6 +334,8 @@ public class ComponentInfo {
       return false;
     if (customCommands != null ? !customCommands.equals(that.customCommands) : that.customCommands != null)
       return false;
+    if (bulkCommandDefinition != null ? !bulkCommandDefinition.equals(that.bulkCommandDefinition) : that.bulkCommandDefinition != null)
+      return false;
     if (dependencies != null ? !dependencies.equals(that.dependencies) : that.dependencies != null) return false;
     if (displayName != null ? !displayName.equals(that.displayName) : that.displayName != null) return false;
     if (name != null ? !name.equals(that.name) : that.name != null) return false;
@@ -340,6 +357,7 @@ public class ComponentInfo {
     result = 31 * result + (logs != null ? logs.hashCode() : 0);
     result = 31 * result + (clientConfigFiles != null ? clientConfigFiles.hashCode() : 0);
     result = 31 * result + (customCommands != null ? customCommands.hashCode() : 0);
+    result = 31 * result + (bulkCommandDefinition != null ? bulkCommandDefinition.hashCode(): 0);
     result = 31 * result + (dependencies != null ? dependencies.hashCode() : 0);
     result = 31 * result + (autoDeploy != null ? autoDeploy.hashCode() : 0);
     result = 31 * result + (configDependencies != null ? configDependencies.hashCode() : 0);

+ 3 - 0
ambari-server/src/main/resources/common-services/HAWQ/2.0.0/metainfo.xml

@@ -151,6 +151,9 @@
               </commandScript>
             </customCommand>
           </customCommands>
+          <bulkCommands>
+            <displayName>HAWQ Segments</displayName>
+          </bulkCommands>
         </component>
       </components>
 

+ 5 - 0
ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/metainfo.xml

@@ -83,6 +83,11 @@
             <script>scripts/hbase_regionserver.py</script>
             <scriptType>PYTHON</scriptType>
           </commandScript>
+          <bulkCommands>
+            <displayName>RegionServers</displayName>
+            <!-- Used by decommission and recommission -->
+            <masterComponent>HBASE_MASTER</masterComponent>
+          </bulkCommands>
           <logs>
             <log>
               <logId>hbase_regionserver</logId>

+ 5 - 0
ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/metainfo.xml

@@ -75,6 +75,11 @@
             <scriptType>PYTHON</scriptType>
             <timeout>1200</timeout>
           </commandScript>
+          <bulkCommands>
+            <displayName>DataNodes</displayName>
+            <!-- Used by decommission and recommission -->
+            <masterComponent>NAMENODE</masterComponent>
+          </bulkCommands>
           <logs>
             <log>
               <logId>hdfs_datanode</logId>

+ 3 - 0
ambari-server/src/main/resources/common-services/PXF/3.0.0/metainfo.xml

@@ -36,6 +36,9 @@
             <scriptType>PYTHON</scriptType>
             <timeout>600</timeout>
           </commandScript>
+          <bulkCommands>
+            <displayName>PXF</displayName>
+          </bulkCommands>
         </component>
       </components>
 

+ 4 - 0
ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/metainfo.xml

@@ -85,6 +85,10 @@
             <scriptType>PYTHON</scriptType>
             <timeout>1200</timeout>
           </commandScript>
+          <bulkCommands>
+            <displayName>Supervisors</displayName>
+            <masterComponent>SUPERVISOR</masterComponent>
+          </bulkCommands>
           <logs>
             <log>
               <logId>storm_supervisor</logId>

+ 5 - 0
ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/metainfo.xml

@@ -216,6 +216,11 @@
             <scriptType>PYTHON</scriptType>
             <timeout>1200</timeout>
           </commandScript>
+          <bulkCommands>
+            <displayName>NodeManagers</displayName>
+            <!-- Used by decommission and recommission -->
+            <masterComponent>RESOURCEMANAGER</masterComponent>
+          </bulkCommands>
         </component>
 
         <component>

+ 4 - 0
ambari-server/src/main/resources/properties.json

@@ -244,6 +244,10 @@
         "StackServiceComponents/cardinality",
         "StackServiceComponents/custom_commands",
         "StackServiceComponents/recovery_enabled",
+        "StackServiceComponents/advertise_version",
+        "StackServiceComponents/has_bulk_commands_definition",
+        "StackServiceComponents/bulk_commands_display_name",
+        "StackServiceComponents/bulk_commands_master_component_name",
         "auto_deploy/enabled",
         "auto_deploy/location",
         "_"

+ 36 - 0
ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java

@@ -172,6 +172,9 @@ public class AmbariManagementControllerTest {
 
   private static final String STACK_NAME = "HDP";
 
+  private static final String SERVICE_NAME_HBASE = "HBASE";
+  private static final String COMPONENT_NAME_REGIONSERVER = "HBASE_REGIONSERVER";
+  private static final String COMPONENT_NAME_DATANODE = "DATANODE";
   private static final String STACK_VERSION = "0.2";
   private static final String NEW_STACK_VERSION = "2.0.6";
   private static final String OS_TYPE = "centos5";
@@ -7384,6 +7387,39 @@ public class AmbariManagementControllerTest {
     assertEquals(0, response.getCustomCommands().size());
   }
 
+  @Test
+  public void testBulkCommandsInheritence() throws Exception{
+    //HDP 2.0.6 inherit HDFS configurations from HDP 2.0.5
+    StackServiceComponentRequest requestWithParams = new StackServiceComponentRequest(STACK_NAME, NEW_STACK_VERSION, SERVICE_NAME, COMPONENT_NAME_DATANODE);
+    Set<StackServiceComponentResponse> responsesWithParams = controller.getStackComponents(Collections.singleton(requestWithParams));
+    Assert.assertEquals(1, responsesWithParams.size());
+    for (StackServiceComponentResponse responseWithParams: responsesWithParams) {
+      Assert.assertEquals(responseWithParams.getComponentName(), COMPONENT_NAME_DATANODE);
+      Assert.assertEquals(responseWithParams.getBulkCommandsDisplayName(), "DataNodes");
+      Assert.assertEquals(responseWithParams.getBulkCommandsMasterComponentName(), "NAMENODE");
+    }
+  }
+
+  @Test
+  public void testBulkCommandsChildStackOverride() throws Exception{
+    //Both HDP 2.0.6 and HDP 2.0.5 has HBase configurations
+    StackServiceComponentRequest requestWithParams = new StackServiceComponentRequest(STACK_NAME, "2.0.5", SERVICE_NAME_HBASE, COMPONENT_NAME_REGIONSERVER);
+    Set<StackServiceComponentResponse> responsesWithParams = controller.getStackComponents(Collections.singleton(requestWithParams));
+    Assert.assertEquals(1, responsesWithParams.size());
+    for (StackServiceComponentResponse responseWithParams: responsesWithParams) {
+      Assert.assertEquals(responseWithParams.getBulkCommandsDisplayName(), "Region Servers");
+      Assert.assertEquals(responseWithParams.getBulkCommandsMasterComponentName(), "HBASE_MASTER");
+    }
+
+    requestWithParams = new StackServiceComponentRequest(STACK_NAME, NEW_STACK_VERSION, SERVICE_NAME_HBASE, COMPONENT_NAME_REGIONSERVER);
+    responsesWithParams = controller.getStackComponents(Collections.singleton(requestWithParams));
+    Assert.assertEquals(1, responsesWithParams.size());
+    for (StackServiceComponentResponse responseWithParams: responsesWithParams) {
+      Assert.assertEquals(responseWithParams.getBulkCommandsDisplayName(), "HBase Region Servers");
+      Assert.assertEquals(responseWithParams.getBulkCommandsMasterComponentName(), "HBASE_MASTER");
+    }
+  }
+
   // disabled as upgrade feature is disabled
   @Ignore
   @Test

+ 23 - 0
ambari-server/src/test/java/org/apache/ambari/server/stack/ComponentModuleTest.java

@@ -19,6 +19,7 @@
 package org.apache.ambari.server.stack;
 
 import org.apache.ambari.server.state.AutoDeployInfo;
+import org.apache.ambari.server.state.BulkCommandDefinition;
 import org.apache.ambari.server.state.ClientConfigFileDefinition;
 import org.apache.ambari.server.state.CommandScriptDefinition;
 import org.apache.ambari.server.state.ComponentInfo;
@@ -387,6 +388,28 @@ public class ComponentModuleTest {
     assertTrue(component.isDeleted());
   }
 
+  @Test
+  public void testResolve_BulkCommandsDefinition(){
+    BulkCommandDefinition bulkCommandsDefinition = new BulkCommandDefinition();
+    ComponentInfo info = new ComponentInfo();
+    ComponentInfo parentInfo = new ComponentInfo();
+
+    // parent has value set, child value is null
+    parentInfo.setBulkCommands(bulkCommandsDefinition);
+    assertSame(bulkCommandsDefinition, resolveComponent(info, parentInfo).getModuleInfo().getBulkCommandDefinition());
+
+    // child has value set, parent value is null
+    info.setBulkCommands(bulkCommandsDefinition);
+    parentInfo.setBulkCommands(null);
+    assertSame(bulkCommandsDefinition, resolveComponent(info, parentInfo).getModuleInfo().getBulkCommandDefinition());
+
+    // value set in both parent and child; child overwrites
+    BulkCommandDefinition bulkCommandsDefinition2 = createNiceMock(BulkCommandDefinition.class);
+    info.setBulkCommands(bulkCommandsDefinition);
+    parentInfo.setBulkCommands(bulkCommandsDefinition2);
+    assertSame(bulkCommandsDefinition, resolveComponent(info, parentInfo).getModuleInfo().getBulkCommandDefinition());
+  }
+
   private ComponentModule resolveComponent(ComponentInfo info, ComponentInfo parentInfo) {
     info.setName("FOO");
     parentInfo.setName("FOO");

+ 5 - 0
ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HBASE/metainfo.xml

@@ -70,6 +70,11 @@
             <script>scripts/hbase_regionserver.py</script>
             <scriptType>PYTHON</scriptType>
           </commandScript>
+          <bulkCommands>
+            <displayName>Region Servers</displayName>
+            <!-- Used by decommission and recommission -->
+            <masterComponent>HBASE_MASTER</masterComponent>
+          </bulkCommands>
         </component>
 
         <component>

+ 5 - 0
ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/metainfo.xml

@@ -65,6 +65,11 @@
             <scriptType>PYTHON</scriptType>
             <timeout>600</timeout>
           </commandScript>
+          <bulkCommands>
+            <displayName>DataNodes</displayName>
+            <!-- Used by decommission and recommission -->
+            <masterComponent>NAMENODE</masterComponent>
+          </bulkCommands>
         </component>
 
         <component>

+ 5 - 0
ambari-server/src/test/resources/stacks/HDP/2.0.6/services/HBASE/metainfo.xml

@@ -70,6 +70,11 @@
             <script>scripts/hbase_regionserver.py</script>
             <scriptType>PYTHON</scriptType>
           </commandScript>
+          <bulkCommands>
+            <displayName>HBase Region Servers</displayName>
+            <!-- Used by decommission and recommission -->
+            <masterComponent>HBASE_MASTER</masterComponent>
+          </bulkCommands>
         </component>
 
         <component>

+ 3 - 0
ambari-web/app/mappers/stack_service_mapper.js

@@ -51,6 +51,9 @@ App.stackServiceMapper = App.QuickDataMapper.create({
     display_name: 'display_name',
     cardinality: 'cardinality',
     custom_commands: 'custom_commands',
+    has_bulk_commands_definition: 'has_bulk_commands_definition',
+    bulk_commands_display_name: 'bulk_commands_display_name',
+    bulk_commands_master_component_name: 'bulk_commands_master_component_name',
     service_name: 'service_name',
     component_category: 'component_category',
     is_master: 'is_master',

+ 3 - 0
ambari-web/app/models/stack_service_component.js

@@ -27,6 +27,9 @@ App.StackServiceComponent = DS.Model.extend({
   displayName: DS.attr('string'),
   cardinality: DS.attr('string'),
   customCommands: DS.attr('array'),
+  hasBulkCommandsDefinition: DS.attr('boolean'),
+  bulkCommandsDisplayName: DS.attr('string'),
+  bulkCommandsMasterComponentName: DS.attr('string'),
   dependencies: DS.attr('array'),
   serviceName: DS.attr('string'),
   componentCategory: DS.attr('string'),

+ 17 - 36
ambari-web/app/views/main/host/hosts_table_menu_view.js

@@ -38,47 +38,28 @@ App.HostTableMenuView = Em.View.extend({
 
   components: function () {
     var serviceNames = App.Service.find().mapProperty('serviceName');
-    var menuItems = [
-      O.create({
-        serviceName: 'HDFS',
-        componentName: 'DATANODE',
-        masterComponentName: 'NAMENODE',
-        componentNameFormatted: Em.I18n.t('dashboard.services.hdfs.datanodes')
-      }),
-      O.create({
-        serviceName: 'YARN',
-        componentName: 'NODEMANAGER',
-        masterComponentName: 'RESOURCEMANAGER',
-        componentNameFormatted: Em.I18n.t('dashboard.services.yarn.nodeManagers')
-      }),
-      O.create({
-        serviceName: 'HBASE',
-        componentName: 'HBASE_REGIONSERVER',
-        masterComponentName: 'HBASE_MASTER',
-        componentNameFormatted: Em.I18n.t('dashboard.services.hbase.regionServers')
-      }),
-      O.create({
-        serviceName: 'HAWQ',
-        componentName: 'HAWQSEGMENT',
-        componentNameFormatted: Em.I18n.t('dashboard.services.hawq.hawqSegments')
-      }),
-      O.create({
-        serviceName: 'PXF',
-        componentName: 'PXF',
-        componentNameFormatted: Em.I18n.t('dashboard.services.pxf.pxfHosts')
-      }),
-      O.create({
-        serviceName: 'STORM',
-        componentName: 'SUPERVISOR',
-        masterComponentName: 'SUPERVISOR',
-        componentNameFormatted: Em.I18n.t('dashboard.services.storm.supervisors')
-      })];
-
+    var menuItems = this.getBulkMenuItemsPerServiceComponent();
     return menuItems.filter(function (item) {
       return serviceNames.contains(item.serviceName);
     });
   }.property(),
 
+  getBulkMenuItemsPerServiceComponent: function(){
+    var menuItems = [];
+    App.StackServiceComponent.find().forEach(function (stackComponent) {
+      if(stackComponent.get('hasBulkCommandsDefinition')){
+        var menuItem = O.create({
+          serviceName: stackComponent.get('serviceName'),
+          componentName: stackComponent.get('componentName'),
+          masterComponentName: stackComponent.get('bulkCommandsMasterComponentName'),
+          componentNameFormatted: stackComponent.get('bulkCommandsDisplayName')
+        });
+        menuItems.push(menuItem);
+      }
+    }, this);
+    return menuItems;
+  },
+
   /**
    * slaveItemView build second-level menu
    * for slave component

+ 24 - 1
ambari-web/test/mappers/stack_service_mapper_test.js

@@ -118,7 +118,26 @@ describe('App.stackServiceMapper', function () {
             "StackServices" : {
               "service_name" : "HDFS"
             },
-            "components" : [ ],
+            "components" : [
+              {
+                "StackServiceComponents" : {
+                  "cardinality" : "1+",
+                  "component_category" : "SLAVE",
+                  "component_name" : "DATANODE",
+                  "custom_commands" : [ ],
+                  "bulk_commands_display_name" : "DataNodes",
+                  "bulk_commands_master_component_name" : "NAMENODE",
+                  "has_bulk_commands_definition" : true,
+                  "cardinality" : "1+",
+                  "display_name" : "DataNode",
+                  "is_client" : false,
+                  "is_master" : true,
+                  "service_name" : "HDFS",
+                  "stack_name" : "HDP"
+                },
+                "dependencies" : []
+              }
+            ],
             "artifacts" : [ ]
           },
           {
@@ -227,6 +246,10 @@ describe('App.stackServiceMapper', function () {
       expect(services.findProperty('serviceName', 'KERBEROS').get('isInstallable')).to.be.false;
       expect(services.findProperty('serviceName', 'KERBEROS').get('isSelected')).to.be.false;
       expect(components.findProperty('componentName', 'MYSQL_SERVER').get('customCommands')).to.be.empty;
+
+      expect(components.findProperty('componentName', 'DATANODE').get('hasBulkCommandsDefinition')).to.be.true;
+      expect(components.findProperty('componentName', 'DATANODE').get('bulkCommandsDisplayName')).to.eql("DataNodes");
+      expect(components.findProperty('componentName', 'DATANODE').get('bulkCommandsMasterComponentName')).to.eql("NAMENODE");
     });
 
   });