[ 
https://issues.apache.org/jira/browse/YARN-11310?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17608927#comment-17608927
 ] 

ASF GitHub Bot commented on YARN-11310:
---------------------------------------

slfan1989 commented on code in PR #4924:
URL: https://github.com/apache/hadoop/pull/4924#discussion_r979133698


##########
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/FederationBlock.java:
##########
@@ -58,119 +58,232 @@ class FederationBlock extends HtmlBlock {
 
   @Override
   public void render(Block html) {
+
     Configuration conf = this.router.getConfig();
     boolean isEnabled = conf.getBoolean(
         YarnConfiguration.FEDERATION_ENABLED,
         YarnConfiguration.DEFAULT_FEDERATION_ENABLED);
+
+    // If Yarn Federation is enabled.
     if (isEnabled) {
-      setTitle("Federation");
-
-      // Table header
-      TBODY<TABLE<Hamlet>> tbody = html.table("#rms").thead().tr()
-          .th(".id", "SubCluster")
-          .th(".submittedA", "Applications Submitted*")
-          .th(".pendingA", "Applications Pending*")
-          .th(".runningA", "Applications Running*")
-          .th(".failedA", "Applications Failed*")
-          .th(".killedA", "Applications Killed*")
-          .th(".completedA", "Applications Completed*")
-          .th(".contAllocated", "Containers Allocated")
-          .th(".contReserved", "Containers Reserved")
-          .th(".contPending", "Containers Pending")
-          .th(".availableM", "Available Memory")
-          .th(".allocatedM", "Allocated Memory")
-          .th(".reservedM", "Reserved Memory")
-          .th(".totalM", "Total Memory")
-          .th(".availableVC", "Available VirtualCores")
-          .th(".allocatedVC", "Allocated VirtualCores")
-          .th(".reservedVC", "Reserved VirtualCores")
-          .th(".totalVC", "Total VirtualCores")
-          .th(".activeN", "Active Nodes")
-          .th(".lostN", "Lost Nodes")
-          .th(".availableN", "Available Nodes")
-          .th(".unhealtyN", "Unhealthy Nodes")
-          .th(".rebootedN", "Rebooted Nodes")
-          .th(".totalN", "Total Nodes")
-          .__().__().tbody();
-
-      try {
-        // Binding to the FederationStateStore
-        FederationStateStoreFacade facade =
-            FederationStateStoreFacade.getInstance();
-        Map<SubClusterId, SubClusterInfo> subClustersInfo =
-            facade.getSubClusters(true);
-
-        // Sort the SubClusters
-        List<SubClusterInfo> subclusters = new ArrayList<>();
-        subclusters.addAll(subClustersInfo.values());
-        Comparator<? super SubClusterInfo> cmp =
-            new Comparator<SubClusterInfo>() {
-              @Override
-              public int compare(SubClusterInfo o1, SubClusterInfo o2) {
-                return o1.getSubClusterId().compareTo(o2.getSubClusterId());
-              }
-            };
-        Collections.sort(subclusters, cmp);
-
-        for (SubClusterInfo subcluster : subclusters) {
-          SubClusterId subClusterId = subcluster.getSubClusterId();
-          String webAppAddress = subcluster.getRMWebServiceAddress();
-          String capability = subcluster.getCapability();
-          ClusterMetricsInfo subClusterInfo = 
getClusterMetricsInfo(capability);
-
-          // Building row per SubCluster
-          tbody.tr().td().a("//" + webAppAddress, subClusterId.toString()).__()
-              .td(Integer.toString(subClusterInfo.getAppsSubmitted()))
-              .td(Integer.toString(subClusterInfo.getAppsPending()))
-              .td(Integer.toString(subClusterInfo.getAppsRunning()))
-              .td(Integer.toString(subClusterInfo.getAppsFailed()))
-              .td(Integer.toString(subClusterInfo.getAppsKilled()))
-              .td(Integer.toString(subClusterInfo.getAppsCompleted()))
-              .td(Integer.toString(subClusterInfo.getContainersAllocated()))
-              .td(Integer.toString(subClusterInfo.getReservedContainers()))
-              .td(Integer.toString(subClusterInfo.getPendingContainers()))
-              .td(StringUtils.byteDesc(
-                  subClusterInfo.getAvailableMB() * BYTES_IN_MB))
-              .td(StringUtils.byteDesc(
-                  subClusterInfo.getAllocatedMB() * BYTES_IN_MB))
-              .td(StringUtils.byteDesc(
-                  subClusterInfo.getReservedMB() * BYTES_IN_MB))
-              .td(StringUtils.byteDesc(
-                  subClusterInfo.getTotalMB() * BYTES_IN_MB))
-              .td(Long.toString(subClusterInfo.getAvailableVirtualCores()))
-              .td(Long.toString(subClusterInfo.getAllocatedVirtualCores()))
-              .td(Long.toString(subClusterInfo.getReservedVirtualCores()))
-              .td(Long.toString(subClusterInfo.getTotalVirtualCores()))
-              .td(Integer.toString(subClusterInfo.getActiveNodes()))
-              .td(Integer.toString(subClusterInfo.getLostNodes()))
-              .td(Integer.toString(subClusterInfo.getDecommissionedNodes()))
-              .td(Integer.toString(subClusterInfo.getUnhealthyNodes()))
-              .td(Integer.toString(subClusterInfo.getRebootedNodes()))
-              .td(Integer.toString(subClusterInfo.getTotalNodes())).__();
-        }
-      } catch (YarnException e) {
-        LOG.error("Cannot render ResourceManager", e);
-      }
+      initHtmlPageFederationEnabled(html);
+    }
 
-      tbody.__().__().div()
-          .p().__("*The application counts are local per 
subcluster").__().__();
-    } else {
-      setTitle("Federation is not Enabled!");
+    // If Yarn Federation is not enabled.
+    if(!isEnabled) {
+      initHtmlPageFederationNotEnabled(html);
     }
   }
 
-  private static ClusterMetricsInfo getClusterMetricsInfo(String capability) {
-    ClusterMetricsInfo clusterMetrics = null;
+  /**
+   * Parse the capability and obtain the metric information of the cluster.
+   *
+   * @param capability metric json obtained from RM.
+   * @return ClusterMetricsInfo Object
+   */
+  private ClusterMetricsInfo getClusterMetricsInfo(String capability) {
     try {
-      JSONJAXBContext jc = new JSONJAXBContext(
-          JSONConfiguration.mapped().rootUnwrapping(false).build(),
-          ClusterMetricsInfo.class);
-      JSONUnmarshaller unmarshaller = jc.createJSONUnmarshaller();
-      clusterMetrics = unmarshaller.unmarshalFromJSON(
-          new StringReader(capability), ClusterMetricsInfo.class);
+      if (capability != null && !capability.isEmpty()) {
+        JSONJAXBContext jc = new JSONJAXBContext(
+            JSONConfiguration.mapped().rootUnwrapping(false).build(), 
ClusterMetricsInfo.class);
+        JSONUnmarshaller unmarShaller = jc.createJSONUnmarshaller();
+        StringReader stringReader = new StringReader(capability);
+        ClusterMetricsInfo clusterMetrics =
+            unmarShaller.unmarshalFromJSON(stringReader, 
ClusterMetricsInfo.class);
+        return clusterMetrics;
+      }
     } catch (Exception e) {
       LOG.error("Cannot parse SubCluster info", e);
     }
-    return clusterMetrics;
+    return null;
+  }
+
+  /**
+   * Initialize the subCluster details JavaScript of the Federation page.
+   *
+   * This part of the js script will control to display or hide the detailed 
information
+   * of the subCluster when the user clicks on the subClusterId.
+   *
+   * We will obtain the specific information of a SubCluster,
+   * including the information of Applications, Resources, and Nodes.
+   *
+   * @param html html object
+   * @param subClusterDetailMap subCluster Detail Map
+   */
+  private void initFederationSubClusterDetailTableJs(Block html,
+      List<Map<String, String>> subClusterDetailMap) {
+    Gson gson = new Gson();
+    html.script().$type("text/javascript").
+         __("$(document).ready(function() { " +
+          " var scTableData = " + gson.toJson(subClusterDetailMap) + "; " +
+          " var table = $('#rms').DataTable(); " +
+          " $('#rms tbody').on('click', 'td.details-control', function () { " +
+          " var tr = $(this).closest('tr');  " +
+          " var row = table.row(tr); " +
+          " if (row.child.isShown()) {  " +
+          "  row.child.hide(); " +
+          "  tr.removeClass('shown'); " +
+          " } else { " +
+          "  var capabilityArr = scTableData.filter(item => (item.subcluster 
=== row.id())); " +
+          "  var capabilityObj = 
JSON.parse(capabilityArr[0].capability).clusterMetrics; " +
+          "  row.child(" +
+          "     '<table>" +
+          "          <tr>" +
+          "              <td>" +
+          "                  <h3>Application Metrics</h3>" +
+          "                  ApplicationSubmitted* : '+ 
capabilityObj.appsSubmitted +' </p>" +
+          "                  ApplicationCompleted* : '+ 
capabilityObj.appsCompleted +' </p>" +
+          "                  ApplicationPending*   : '+ 
capabilityObj.appsPending +' </p>" +
+          "                  ApplicationRunning*   : '+ 
capabilityObj.appsRunning +' </p>" +
+          "                  ApplicationFailed*    : '+ 
capabilityObj.appsFailed +' </p> " +
+          "                  ApplicationKilled*    : '+ 
capabilityObj.appsKilled +' </p>" +
+          "              </td>" +
+          "              <td>" +
+          "                 <h3>Resource Metrics</h3>" +
+          "                 <h4>Memory</h4>" +
+          "                 TotalMB : '+ capabilityObj.totalMB +' </p>" +
+          "                 ReservedMB : '+ capabilityObj.reservedMB +' </p>" +
+          "                 AvailableMB : '+ capabilityObj.availableMB +' 
</p>" +
+          "                 AllocatedMB : '+ capabilityObj.allocatedMB +' 
</p>" +
+          "                 PendingMB : '+ capabilityObj.pendingMB +' </p>" +
+          "                 <h4>VirtualCores</h4>" +
+          "                 TotalVirtualCores : 
'+capabilityObj.totalVirtualCores+' </p>" +
+          "                 ReservedVirtualCores : 
'+capabilityObj.reservedVirtualCores+' </p>" +
+          "                 AvailableVirtualCore : 
'+capabilityObj.availableVirtualCores+' </p>" +
+          "                 AllocatedVirtualCores : 
'+capabilityObj.allocatedVirtualCores+' </p>" +
+          "                 PendingVirtualCores : 
'+capabilityObj.pendingVirtualCores+' </p>" +
+          "                 <h4>Containers</h4>" +
+          "                 ContainersAllocated : 
'+capabilityObj.containersAllocated+' </p>" +
+          "                 ContainersReserved : 
'+capabilityObj.containersReserved+' </p>" +
+          "                 ContainersPending : 
'+capabilityObj.containersPending+' </p>" +
+          "             </td>" +
+          "             <td>" +
+          "                <h3>Node Metrics</h3>" +
+          "                TotalNodes : '+capabilityObj.totalNodes+' </p>" +
+          "                LostNodes : '+capabilityObj.lostNodes+' </p>" +
+          "                UnhealthyNodes : '+capabilityObj.unhealthyNodes+' 
</p>" +
+          "                DecommissioningNodes : 
'+capabilityObj.decommissioningNodes+' </p>" +
+          "                DecommissionedNodes : 
'+capabilityObj.decommissionedNodes+' </p>" +
+          "                RebootedNodes : '+capabilityObj.rebootedNodes+' 
</p>" +
+          "                ActiveNodes : '+capabilityObj.activeNodes+' </p>" +
+          "                ShutdownNodes : '+capabilityObj.shutdownNodes+' " +
+          "             </td>" +
+          "          </tr>" +
+          "     </table>').show(); "+
+          "   tr.addClass('shown'); " +
+          " } " +
+          " }); });").__();
+  }
+
+  /**
+   * Initialize the Html page when Federation is enabled.
+   *
+   * @param html html object
+   */
+  private void initHtmlPageFederationEnabled(Block html) {
+    List<Map<String, String>> lists = new ArrayList<>();
+
+    // Table header
+    TBODY<TABLE<Hamlet>> tbody =
+        
html.table("#rms").$class("cell-border").$style("width:100%").thead().tr()
+        .th(".id", "SubCluster")
+        .th(".state", "State")
+        .th(".lastStartTime", "LastStartTime")
+        .th(".lastHeartBeat", "LastHeartBeat")
+        .th(".resources", "Resources")
+        .th(".nodes", "Nodes")
+        .__().__().tbody();
+
+    try {
+      // Binding to the FederationStateStore
+      FederationStateStoreFacade facade = 
FederationStateStoreFacade.getInstance();
+
+      Map<SubClusterId, SubClusterInfo> subClustersInfo =

Review Comment:
   I will fix it.





> [Yarn Federation] Refactoring Router's Federation Web Page
> ----------------------------------------------------------
>
>                 Key: YARN-11310
>                 URL: https://issues.apache.org/jira/browse/YARN-11310
>             Project: Hadoop YARN
>          Issue Type: Improvement
>          Components: federation
>    Affects Versions: 3.4.0
>            Reporter: fanshilun
>            Assignee: fanshilun
>            Priority: Major
>              Labels: pull-request-available
>         Attachments: Federation_Web_Page.gif, 
> image-2022-09-22-11-43-27-954.png, image-2022-09-22-11-49-10-974.png, 
> image-2022-09-22-11-52-50-188.png, image-2022-09-22-11-55-08-113.png
>
>
> The Yarn Federation page before modification is as follows:
> enable federation:
> !image-2022-09-22-11-43-27-954.png|width=952,height=232!
> federation is not enabled
> !image-2022-09-22-11-49-10-974.png|width=958,height=209!
>  
> The page needs to be optimized as follows:
> 1. Title is inaccurate, should be "About The Federation"
> 2.If the user does not configure federation.enable, the page should prompt 
> information instead of showing blank.
> 3.For cluster information, we care more about the current sub-cluster status, 
> registration time, heartbeat time, etc., rather than capacity information.
>  
> enable federation:
> !image-2022-09-22-11-52-50-188.png|width=736,height=320!
> federation is not enabled
> !image-2022-09-22-11-55-08-113.png|width=733,height=211!
>  
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: yarn-issues-unsubscr...@hadoop.apache.org
For additional commands, e-mail: yarn-issues-h...@hadoop.apache.org

Reply via email to