You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by in...@apache.org on 2022/10/11 20:31:09 UTC

[hadoop] branch trunk updated: YARN-11317. [Federation] Refactoring Yarn Router's About Web Page. (#4946)

This is an automated email from the ASF dual-hosted git repository.

inigoiri pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/hadoop.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 9e16f1f883a YARN-11317. [Federation] Refactoring Yarn Router's About Web Page. (#4946)
9e16f1f883a is described below

commit 9e16f1f883a053addb786f9642518cf9ecbda068
Author: slfan1989 <55...@users.noreply.github.com>
AuthorDate: Wed Oct 12 04:30:48 2022 +0800

    YARN-11317. [Federation] Refactoring Yarn Router's About Web Page. (#4946)
---
 .../apache/hadoop/yarn/webapp/view/HtmlBlock.java  |  24 ++
 .../server/resourcemanager/webapp/RMWSConsts.java  |   3 +
 .../resourcemanager/webapp/RMWebServices.java      |  11 +
 .../webapp/dao/SchedulerOverviewInfo.java          | 118 ++++++++
 .../resourcemanager/webapp/TestRMWebServices.java  |  57 ++++
 .../webapp/TestRMWebServicesCapacitySched.java     |  13 +
 .../TestRMWebServicesFairScheduler.java            |  12 +
 .../apache/hadoop/yarn/server/router/Router.java   |   5 +
 .../yarn/server/router/webapp/AboutBlock.java      |  95 +++----
 .../yarn/server/router/webapp/FederationBlock.java |  40 +--
 .../server/router/webapp/MetricsOverviewTable.java | 239 ++++++++++++++++
 .../yarn/server/router/webapp/RouterBlock.java     |  99 +++++++
 .../router/webapp/dao/RouterClusterMetrics.java    | 310 +++++++++++++++++++++
 .../yarn/server/router/webapp/dao/RouterInfo.java  | 104 +++++++
 .../router/webapp/dao/RouterSchedulerMetrics.java  | 109 ++++++++
 .../server/router/webapp/dao/package-info.java     |  20 ++
 .../server/router/webapp/TestFederationWebApp.java |  20 +-
 17 files changed, 1191 insertions(+), 88 deletions(-)

diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/view/HtmlBlock.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/view/HtmlBlock.java
index 6c14b7532f5..c07a76617ee 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/view/HtmlBlock.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/view/HtmlBlock.java
@@ -97,4 +97,28 @@ public abstract class HtmlBlock extends TextView implements SubView {
     return callerUGI;
   }
 
+  /**
+   * Initialize User Help Information Div.
+   * When the user does not configure the Yarn Federation function, prompt the user.
+   *
+   * @param html HTML page.
+   * @param isEnabled If federation is enabled.
+   */
+  protected void initUserHelpInformationDiv(Block html, boolean isEnabled) {
+    if (!isEnabled) {
+      html.style(".alert {padding: 15px; margin-bottom: 20px; " +
+          " border: 1px solid transparent; border-radius: 4px;}");
+      html.style(".alert-dismissable {padding-right: 35px;}");
+      html.style(".alert-info {color: #856404;background-color: #fff3cd;border-color: #ffeeba;}");
+
+      Hamlet.DIV<Hamlet> div = html.div("#div_id").$class("alert alert-dismissable alert-info");
+      div.p().$style("color:red").__("Federation is not Enabled.").__()
+          .p().__()
+          .p().__("We can refer to the following documents to configure Yarn Federation. ").__()
+          .p().__()
+          .a("https://hadoop.apache.org/docs/stable/hadoop-yarn/hadoop-yarn-site/Federation.html",
+          "Hadoop: YARN Federation").
+          __();
+    }
+  }
 }
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java
index 791e34ad3d1..5c7787ce023 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java
@@ -57,6 +57,9 @@ public final class RMWSConsts {
   /** Path for {@code RMWebServiceProtocol#dumpSchedulerLogs}. */
   public static final String SCHEDULER_LOGS = "/scheduler/logs";
 
+  /** Path for {@code RMWebServiceProtocol#getSchedulerOverview}. */
+  public static final String SCHEDULER_OVERVIEW = "/scheduler-overview";
+
   /**
    * Path for {@code RMWebServiceProtocol#validateAndGetSchedulerConfiguration}.
    */
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java
index 6a6a2e1de1e..0803af5e76d 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java
@@ -202,6 +202,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.BulkActivitiesIn
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerTypeInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.StatisticsItemInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ConfigVersionInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerOverviewInfo;
 import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
 import org.apache.hadoop.yarn.server.utils.BuilderUtils;
 import org.apache.hadoop.yarn.server.webapp.WebServices;
@@ -2942,4 +2943,14 @@ public class RMWebServices extends WebServices implements RMWebServiceProtocol {
     }
     return Response.status(Status.OK).build();
   }
+
+  @GET
+  @Path(RMWSConsts.SCHEDULER_OVERVIEW)
+  @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
+      MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
+  public SchedulerOverviewInfo getSchedulerOverview() {
+    initForReadableEndpoints();
+    ResourceScheduler rs = rm.getResourceScheduler();
+    return new SchedulerOverviewInfo(rs);
+  }
 }
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/SchedulerOverviewInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/SchedulerOverviewInfo.java
new file mode 100644
index 00000000000..06df27dc4c4
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/SchedulerOverviewInfo.java
@@ -0,0 +1,118 @@
+/**
+ * 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.hadoop.yarn.server.resourcemanager.webapp.dao;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.yarn.api.records.ResourceTypeInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler;
+import org.apache.hadoop.yarn.util.resource.ResourceUtils;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+@XmlRootElement(name = "scheduler")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class SchedulerOverviewInfo {
+
+  private String schedulerType;
+  private String schedulingResourceType;
+  private ResourceInfo minimumAllocation;
+  private ResourceInfo maximumAllocation;
+  private int applicationPriority;
+  private int schedulerBusy;
+  private int rmDispatcherEventQueueSize;
+  private int schedulerDispatcherEventQueueSize;
+
+  // JAXB needs this
+  public SchedulerOverviewInfo() {
+
+  }
+
+  public SchedulerOverviewInfo(ResourceScheduler rs) {
+    // Parse the schedule type
+    this.schedulerType = getSchedulerName(rs);
+
+    // Parse and allocate resource information
+    this.minimumAllocation = new ResourceInfo(rs.getMinimumResourceCapability());
+    this.maximumAllocation = new ResourceInfo(rs.getMaximumResourceCapability());
+
+    // Parse App Priority
+    this.applicationPriority = rs.getMaxClusterLevelAppPriority().getPriority();
+
+    // Resolving resource types
+    List<ResourceTypeInfo> resourceTypeInfos = ResourceUtils.getResourcesTypeInfo();
+    resourceTypeInfos.sort((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName()));
+    this.schedulingResourceType = StringUtils.join(resourceTypeInfos, ",");
+
+    // clusterMetrics
+    ClusterMetricsInfo clusterMetrics = new ClusterMetricsInfo(rs);
+    this.schedulerBusy = clusterMetrics.getRmSchedulerBusyPercent();
+    this.rmDispatcherEventQueueSize = clusterMetrics.getRmEventQueueSize();
+    this.schedulerDispatcherEventQueueSize = clusterMetrics.getSchedulerEventQueueSize();
+  }
+
+  private static String getSchedulerName(ResourceScheduler rs) {
+    if (rs instanceof CapacityScheduler) {
+      return "Capacity Scheduler";
+    }
+    if (rs instanceof FairScheduler) {
+      return "Fair Scheduler";
+    }
+    if (rs instanceof FifoScheduler) {
+      return "Fifo Scheduler";
+    }
+    return rs.getClass().getSimpleName();
+  }
+
+  public String getSchedulerType() {
+    return schedulerType;
+  }
+
+  public String getSchedulingResourceType() {
+    return schedulingResourceType;
+  }
+
+  public ResourceInfo getMinimumAllocation() {
+    return minimumAllocation;
+  }
+
+  public ResourceInfo getMaximumAllocation() {
+    return maximumAllocation;
+  }
+
+  public int getApplicationPriority() {
+    return applicationPriority;
+  }
+
+  public int getSchedulerBusy() {
+    return schedulerBusy;
+  }
+
+  public int getRmDispatcherEventQueueSize() {
+    return rmDispatcherEventQueueSize;
+  }
+
+  public int getSchedulerDispatcherEventQueueSize() {
+    return schedulerDispatcherEventQueueSize;
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServices.java
index ce9de643744..9cf0dda7c39 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServices.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServices.java
@@ -1099,4 +1099,61 @@ public class TestRMWebServices extends JerseyTestBase {
     return  webService;
   }
 
+  @Test
+  public void testClusterSchedulerOverviewFifo() throws JSONException, Exception {
+    WebResource r = resource();
+    ClientResponse response = r.path("ws").path("v1").path("cluster")
+        .path("scheduler-overview").accept(MediaType.APPLICATION_JSON)
+        .get(ClientResponse.class);
+
+    assertEquals(MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
+        response.getType().toString());
+    JSONObject json = response.getEntity(JSONObject.class);
+    verifyClusterSchedulerOverView(json, "Fifo Scheduler");
+  }
+
+  public static void verifyClusterSchedulerOverView(
+      JSONObject json, String expectedSchedulerType) throws Exception {
+
+    // why json contains 8 elements because we defined 8 fields
+    assertEquals("incorrect number of elements in: " + json, 8, json.length());
+
+    // 1.Verify that the schedulerType is as expected
+    String schedulerType = json.getString("schedulerType");
+    assertEquals(expectedSchedulerType, schedulerType);
+
+    // 2.Verify that schedulingResourceType is as expected
+    String schedulingResourceType = json.getString("schedulingResourceType");
+    assertEquals("memory-mb (unit=Mi),vcores", schedulingResourceType);
+
+    // 3.Verify that minimumAllocation is as expected
+    JSONObject minimumAllocation = json.getJSONObject("minimumAllocation");
+    String minMemory = minimumAllocation.getString("memory");
+    String minVCores = minimumAllocation.getString("vCores");
+    assertEquals("1024", minMemory);
+    assertEquals("1", minVCores);
+
+    // 4.Verify that maximumAllocation is as expected
+    JSONObject maximumAllocation = json.getJSONObject("maximumAllocation");
+    String maxMemory = maximumAllocation.getString("memory");
+    String maxVCores = maximumAllocation.getString("vCores");
+    assertEquals("8192", maxMemory);
+    assertEquals("4", maxVCores);
+
+    // 5.Verify that schedulerBusy is as expected
+    int schedulerBusy = json.getInt("schedulerBusy");
+    assertEquals(-1, schedulerBusy);
+
+    // 6.Verify that rmDispatcherEventQueueSize is as expected
+    int rmDispatcherEventQueueSize = json.getInt("rmDispatcherEventQueueSize");
+    assertEquals(0, rmDispatcherEventQueueSize);
+
+    // 7.Verify that schedulerDispatcherEventQueueSize is as expected
+    int schedulerDispatcherEventQueueSize = json.getInt("schedulerDispatcherEventQueueSize");
+    assertEquals(0, schedulerDispatcherEventQueueSize);
+
+    // 8.Verify that applicationPriority is as expected
+    int applicationPriority = json.getInt("applicationPriority");
+    assertEquals(0, applicationPriority);
+  }
 }
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesCapacitySched.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesCapacitySched.java
index 258947af4ef..4454442bf22 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesCapacitySched.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesCapacitySched.java
@@ -23,6 +23,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.inject.Guice;
 import com.google.inject.servlet.ServletModule;
 import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
 import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
 import com.sun.jersey.test.framework.WebAppDescriptor;
 
@@ -413,4 +414,16 @@ public class TestRMWebServicesCapacitySched extends JerseyTestBase {
         YarnConfiguration.SCHEDULER_RM_PLACEMENT_CONSTRAINTS_HANDLER);
     return new MockRM(conf);
   }
+
+  @Test
+  public void testClusterSchedulerOverviewCapacity() throws Exception {
+    WebResource r = resource();
+    ClientResponse response = r.path("ws").path("v1").path("cluster")
+        .path("scheduler-overview").accept(MediaType.APPLICATION_JSON)
+        .get(ClientResponse.class);
+    assertEquals(MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
+        response.getType().toString());
+    JSONObject json = response.getEntity(JSONObject.class);
+    TestRMWebServices.verifyClusterSchedulerOverView(json, "Capacity Scheduler");
+  }
 }
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/fairscheduler/TestRMWebServicesFairScheduler.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/fairscheduler/TestRMWebServicesFairScheduler.java
index bf605e9f5f6..cbc6c417859 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/fairscheduler/TestRMWebServicesFairScheduler.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/fairscheduler/TestRMWebServicesFairScheduler.java
@@ -34,6 +34,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.QueueManager
 
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.JAXBContextResolver;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWebServices;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.TestRMWebServices;
 import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
 import org.apache.hadoop.yarn.webapp.GuiceServletConfig;
 import org.apache.hadoop.yarn.webapp.JerseyTestBase;
@@ -157,4 +158,15 @@ public class TestRMWebServicesFairScheduler extends JerseyTestBase {
     assertEquals("root", rootQueue.getString("queueName"));
   }
 
+  @Test
+  public void testClusterSchedulerOverviewFair() throws Exception {
+    WebResource r = resource();
+    ClientResponse response = r.path("ws").path("v1").path("cluster")
+        .path("scheduler-overview").accept(MediaType.APPLICATION_JSON)
+        .get(ClientResponse.class);
+    assertEquals(MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
+        response.getType().toString());
+    JSONObject json = response.getEntity(JSONObject.class);
+    TestRMWebServices.verifyClusterSchedulerOverView(json, "Fair Scheduler");
+  }
 }
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/Router.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/Router.java
index 82a1e1ea6f9..24e9ad23c93 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/Router.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/Router.java
@@ -79,6 +79,7 @@ public class Router extends CompositeService {
   private WebApp webApp;
   @VisibleForTesting
   protected String webAppAddress;
+  private static long clusterTimeStamp = System.currentTimeMillis();
 
   /**
    * Priority of the Router shutdown hook.
@@ -237,4 +238,8 @@ public class Router extends CompositeService {
     }
     return name;
   }
+
+  public static long getClusterTimeStamp() {
+    return clusterTimeStamp;
+  }
 }
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/AboutBlock.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/AboutBlock.java
index a8a6e6bbac9..878ac75d1c7 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/AboutBlock.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/AboutBlock.java
@@ -18,15 +18,11 @@
 
 package org.apache.hadoop.yarn.server.router.webapp;
 
-import com.sun.jersey.api.client.Client;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.util.StringUtils;
-import org.apache.hadoop.yarn.conf.YarnConfiguration;
-import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWSConsts;
-import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterMetricsInfo;
+import org.apache.commons.lang3.time.DateFormatUtils;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.federation.utils.FederationStateStoreFacade;
 import org.apache.hadoop.yarn.server.router.Router;
-import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
-import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
+import org.apache.hadoop.yarn.server.router.webapp.dao.RouterInfo;
 import org.apache.hadoop.yarn.webapp.view.InfoBlock;
 
 import com.google.inject.Inject;
@@ -34,62 +30,57 @@ import com.google.inject.Inject;
 /**
  * About block for the Router Web UI.
  */
-public class AboutBlock extends HtmlBlock {
-
-  private static final long BYTES_IN_MB = 1024 * 1024;
+public class AboutBlock extends RouterBlock {
 
   private final Router router;
 
   @Inject
   AboutBlock(Router router, ViewContext ctx) {
-    super(ctx);
+    super(router, ctx);
     this.router = router;
   }
 
   @Override
   protected void render(Block html) {
-    Configuration conf = this.router.getConfig();
-    String webAppAddress = WebAppUtils.getRouterWebAppURLWithScheme(conf);
-    Client client = RouterWebServiceUtil.createJerseyClient(conf);
 
-    ClusterMetricsInfo metrics = RouterWebServiceUtil
-        .genericForward(webAppAddress, null, ClusterMetricsInfo.class,
-            HTTPMethods.GET,
-            RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.METRICS, null, null,
-            conf, client);
-    boolean isEnabled = conf.getBoolean(
-        YarnConfiguration.FEDERATION_ENABLED,
-        YarnConfiguration.DEFAULT_FEDERATION_ENABLED);
-    info("Cluster Status").
-        __("Federation Enabled", isEnabled).
-        __("Applications Submitted", metrics.getAppsSubmitted()).
-        __("Applications Pending", metrics.getAppsPending()).
-        __("Applications Running", metrics.getAppsRunning()).
-        __("Applications Failed", metrics.getAppsFailed()).
-        __("Applications Killed", metrics.getAppsKilled()).
-        __("Applications Completed", metrics.getAppsCompleted()).
-        __("Containers Allocated", metrics.getContainersAllocated()).
-        __("Containers Reserved", metrics.getReservedContainers()).
-        __("Containers Pending", metrics.getPendingContainers()).
-        __("Available Memory",
-            StringUtils.byteDesc(metrics.getAvailableMB() * BYTES_IN_MB)).
-        __("Allocated Memory",
-            StringUtils.byteDesc(metrics.getAllocatedMB() * BYTES_IN_MB)).
-        __("Reserved Memory",
-            StringUtils.byteDesc(metrics.getReservedMB() * BYTES_IN_MB)).
-        __("Total Memory",
-            StringUtils.byteDesc(metrics.getTotalMB() * BYTES_IN_MB)).
-        __("Available VirtualCores", metrics.getAvailableVirtualCores()).
-        __("Allocated VirtualCores", metrics.getAllocatedVirtualCores()).
-        __("Reserved VirtualCores", metrics.getReservedVirtualCores()).
-        __("Total VirtualCores", metrics.getTotalVirtualCores()).
-        __("Active Nodes", metrics.getActiveNodes()).
-        __("Lost Nodes", metrics.getLostNodes()).
-        __("Available Nodes", metrics.getDecommissionedNodes()).
-        __("Unhealthy Nodes", metrics.getUnhealthyNodes()).
-        __("Rebooted Nodes", metrics.getRebootedNodes()).
-        __("Total Nodes", metrics.getTotalNodes());
+    boolean isEnabled = isYarnFederationEnabled();
+
+    // If Yarn Federation is not enabled, the user needs to be prompted.
+    initUserHelpInformationDiv(html, isEnabled);
+
+    // Metrics Overview Table
+    html.__(MetricsOverviewTable.class);
 
+    // Init Yarn Router Basic Information
+    initYarnRouterBasicInformation(isEnabled);
+
+    // InfoBlock
     html.__(InfoBlock.class);
   }
+
+  /**
+   * Init Yarn Router Basic Infomation.
+   * @param isEnabled true, federation is enabled; false, federation is not enabled.
+   */
+  private void initYarnRouterBasicInformation(boolean isEnabled) {
+    FederationStateStoreFacade facade = FederationStateStoreFacade.getInstance();
+    RouterInfo routerInfo = new RouterInfo(router);
+    String lastStartTime =
+        DateFormatUtils.format(routerInfo.getStartedOn(), DATE_PATTERN);
+    try {
+      info("Yarn Router Overview").
+          __("Federation Enabled:", String.valueOf(isEnabled)).
+          __("Router ID:", routerInfo.getClusterId()).
+          __("Router state:", routerInfo.getState()).
+          __("Router SubCluster Count:", facade.getSubClusters(true).size()).
+          __("Router RMStateStore:", routerInfo.getRouterStateStore()).
+          __("Router started on:", lastStartTime).
+          __("Router version:", routerInfo.getRouterBuildVersion() +
+             " on " + routerInfo.getRouterVersionBuiltOn()).
+          __("Hadoop version:", routerInfo.getHadoopBuildVersion() +
+             " on " + routerInfo.getHadoopVersionBuiltOn());
+    } catch (YarnException e) {
+      LOG.error("initYarnRouterBasicInformation error.", e);
+    }
+  }
 }
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/FederationBlock.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/FederationBlock.java
index 70976d6221d..9e449a46e29 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/FederationBlock.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/FederationBlock.java
@@ -20,50 +20,41 @@ package org.apache.hadoop.yarn.server.router.webapp;
 
 import java.io.StringReader;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.HashMap;
 
 import com.google.gson.Gson;
-import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.util.StringUtils;
 import org.apache.commons.lang3.time.DateFormatUtils;
-import org.apache.hadoop.yarn.conf.YarnConfiguration;
 import org.apache.hadoop.yarn.server.federation.store.records.SubClusterId;
 import org.apache.hadoop.yarn.server.federation.store.records.SubClusterInfo;
-import org.apache.hadoop.yarn.server.federation.utils.FederationStateStoreFacade;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterMetricsInfo;
 import org.apache.hadoop.yarn.server.router.Router;
 import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet;
 import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet.TABLE;
 import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet.TBODY;
 import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
-import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
 
 import com.google.inject.Inject;
 import com.sun.jersey.api.json.JSONConfiguration;
 import com.sun.jersey.api.json.JSONJAXBContext;
 import com.sun.jersey.api.json.JSONUnmarshaller;
 
-class FederationBlock extends HtmlBlock {
+class FederationBlock extends RouterBlock {
 
   private final Router router;
 
   @Inject
   FederationBlock(ViewContext ctx, Router router) {
-    super(ctx);
+    super(router, ctx);
     this.router = router;
   }
 
   @Override
   public void render(Block html) {
 
-    Configuration conf = this.router.getConfig();
-    boolean isEnabled = conf.getBoolean(
-        YarnConfiguration.FEDERATION_ENABLED,
-        YarnConfiguration.DEFAULT_FEDERATION_ENABLED);
+    boolean isEnabled = isYarnFederationEnabled();
 
     // init Html Page Federation
     initHtmlPageFederation(html, isEnabled);
@@ -122,21 +113,7 @@ class FederationBlock extends HtmlBlock {
     List<Map<String, String>> lists = new ArrayList<>();
 
     // If Yarn Federation is not enabled, the user needs to be prompted.
-    if (!isEnabled) {
-      html.style(".alert {padding: 15px; margin-bottom: 20px; " +
-          " border: 1px solid transparent; border-radius: 4px;}");
-      html.style(".alert-dismissable {padding-right: 35px;}");
-      html.style(".alert-info {color: #856404;background-color: #fff3cd;border-color: #ffeeba;}");
-
-      Hamlet.DIV<Hamlet> div = html.div("#div_id").$class("alert alert-dismissable alert-info");
-      div.p().$style("color:red").__("Federation is not Enabled.").__()
-          .p().__()
-          .p().__("We can refer to the following documents to configure Yarn Federation. ").__()
-          .p().__()
-          .a("https://hadoop.apache.org/docs/stable/hadoop-yarn/hadoop-yarn-site/Federation.html",
-          "Hadoop: YARN Federation").
-          __();
-    }
+    initUserHelpInformationDiv(html, isEnabled);
 
     // Table header
     TBODY<TABLE<Hamlet>> tbody =
@@ -150,16 +127,9 @@ class FederationBlock extends HtmlBlock {
         .__().__().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 = Comparator.comparing(o -> o.getSubClusterId());
-      Collections.sort(subclusters, cmp);
+      List<SubClusterInfo> subclusters = getSubClusterInfoList();
 
       for (SubClusterInfo subcluster : subclusters) {
 
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/MetricsOverviewTable.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/MetricsOverviewTable.java
new file mode 100644
index 00000000000..ba17fa27ff4
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/MetricsOverviewTable.java
@@ -0,0 +1,239 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.router.webapp;
+
+import com.google.inject.Inject;
+import com.sun.jersey.api.client.Client;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.federation.store.records.SubClusterInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWSConsts;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterMetricsInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerOverviewInfo;
+import org.apache.hadoop.yarn.server.router.Router;
+import org.apache.hadoop.yarn.server.router.webapp.dao.RouterClusterMetrics;
+import org.apache.hadoop.yarn.server.router.webapp.dao.RouterSchedulerMetrics;
+import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet;
+import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
+
+import java.io.IOException;
+import java.util.List;
+
+public class MetricsOverviewTable extends RouterBlock {
+
+  private final Router router;
+
+  @Inject
+  MetricsOverviewTable(Router router, ViewContext ctx) {
+    super(router, ctx);
+    this.router = router;
+  }
+
+  @Override
+  protected void render(Block html) {
+    // Initialize page styles
+    html.style(".metrics {margin-bottom:5px}");
+
+    // get routerClusterMetrics Info
+    ClusterMetricsInfo routerClusterMetricsInfo = getRouterClusterMetricsInfo();
+    RouterClusterMetrics routerClusterMetrics = new RouterClusterMetrics(routerClusterMetricsInfo);
+
+    // metrics div
+    Hamlet.DIV<Hamlet> div = html.div().$class("metrics");
+    try {
+      initFederationClusterAppsMetrics(div, routerClusterMetrics);
+      initFederationClusterNodesMetrics(div, routerClusterMetrics);
+      initFederationClusterSchedulersMetrics(div, routerClusterMetrics);
+    } catch (Exception e) {
+      LOG.error("MetricsOverviewTable init error.", e);
+    }
+    div.__();
+  }
+
+  /**
+   * Init Federation Cluster Apps Metrics.
+   * Contains App information, resource usage information.
+   *
+   * @param div data display div.
+   * @param metrics data metric information.
+   */
+  private void initFederationClusterAppsMetrics(Hamlet.DIV<Hamlet> div,
+      RouterClusterMetrics metrics) {
+    div.h3("Federation Cluster Metrics").
+        table("#metricsoverview").
+        thead().$class("ui-widget-header").
+        // Initialize table header information
+        tr().
+        th().$class("ui-state-default").__("Apps Submitted").__().
+        th().$class("ui-state-default").__("Apps Pending").__().
+        th().$class("ui-state-default").__("Apps Running").__().
+        th().$class("ui-state-default").__("Apps Completed").__().
+        th().$class("ui-state-default").__("Containers Running").__().
+        th().$class("ui-state-default").__("Used Resources").__().
+        th().$class("ui-state-default").__("Total Resources").__().
+        th().$class("ui-state-default").__("Reserved Resources").__().
+        th().$class("ui-state-default").__("Physical Mem Used %").__().
+        th().$class("ui-state-default").__("Physical VCores Used %").__().
+        __().
+        __().
+        // Initialize table data information
+        tbody().$class("ui-widget-content").
+        tr().
+        td(metrics.getAppsSubmitted()).
+        td(metrics.getAppsPending()).
+        td(String.valueOf(metrics.getAppsRunning())).
+        td(metrics.getAppsCompleted()).
+        td(metrics.getAllocatedContainers()).
+        td(metrics.getUsedResources()).
+        td(metrics.getTotalResources()).
+        td(metrics.getReservedResources()).
+        td(metrics.getUtilizedMBPercent()).
+        td(metrics.getUtilizedVirtualCoresPercent()).
+        __().
+        __().__();
+  }
+
+  /**
+   * Init Federation Cluster Nodes Metrics.
+   *
+   * @param div data display div.
+   * @param metrics data metric information.
+   */
+  private void initFederationClusterNodesMetrics(Hamlet.DIV<Hamlet> div,
+      RouterClusterMetrics metrics) {
+    div.h3("Federation Cluster Nodes Metrics").
+        table("#nodemetricsoverview").
+        thead().$class("ui-widget-header").
+        // Initialize table header information
+        tr().
+        th().$class("ui-state-default").__("Active Nodes").__().
+        th().$class("ui-state-default").__("Decommissioning Nodes").__().
+        th().$class("ui-state-default").__("Decommissioned Nodes").__().
+        th().$class("ui-state-default").__("Lost Nodes").__().
+        th().$class("ui-state-default").__("Unhealthy Nodes").__().
+        th().$class("ui-state-default").__("Rebooted Nodes").__().
+        th().$class("ui-state-default").__("Shutdown Nodes").__().
+        __().
+        __().
+        // Initialize table data information
+        tbody().$class("ui-widget-content").
+        tr().
+        td(String.valueOf(metrics.getActiveNodes())).
+        td(String.valueOf(metrics.getDecommissioningNodes())).
+        td(String.valueOf(metrics.getDecommissionedNodes())).
+        td(String.valueOf(metrics.getLostNodes())).
+        td(String.valueOf(metrics.getUnhealthyNodes())).
+        td(String.valueOf(metrics.getRebootedNodes())).
+        td(String.valueOf(metrics.getShutdownNodes())).
+        __().
+        __().__();
+  }
+
+  /**
+   * Init Federation Cluster SchedulersMetrics.
+   *
+   * @param div data display div.
+   * @param metrics data metric information.
+   * @throws YarnException yarn error.
+   * @throws IOException io error.
+   * @throws InterruptedException interrupt error.
+   */
+  private void initFederationClusterSchedulersMetrics(Hamlet.DIV<Hamlet> div,
+      RouterClusterMetrics metrics) throws YarnException, IOException, InterruptedException {
+    // Sort the SubClusters.
+    List<SubClusterInfo> subclusters = getSubClusterInfoList();
+
+    Hamlet.TBODY<Hamlet.TABLE<Hamlet.DIV<Hamlet>>> fsMetricsScheduleTr =
+        div.h3("Federation Scheduler Metrics").
+        table("#schedulermetricsoverview").
+        thead().$class("ui-widget-header").
+        tr().
+        th().$class("ui-state-default").__("SubCluster").__().
+        th().$class("ui-state-default").__("Scheduler Type").__().
+        th().$class("ui-state-default").__("Scheduling Resource Type").__().
+        th().$class("ui-state-default").__("Minimum Allocation").__().
+        th().$class("ui-state-default").__("Maximum Allocation").__().
+        th().$class("ui-state-default").__("Maximum Cluster Application Priority").__().
+        th().$class("ui-state-default").__("Scheduler Busy %").__().
+        th().$class("ui-state-default").__("RM Dispatcher EventQueue Size").__().
+        th().$class("ui-state-default")
+        .__("Scheduler Dispatcher EventQueue Size").__().
+        __().
+        __().
+        tbody().$class("ui-widget-content");
+
+    boolean isEnabled = isYarnFederationEnabled();
+
+    // If Federation mode is not enabled or there is currently no SubCluster available,
+    // each column in the list should be displayed as N/A
+    if (!isEnabled || subclusters == null || subclusters.isEmpty()) {
+      fsMetricsScheduleTr.tr().
+          td(UNAVAILABLE).
+          td(UNAVAILABLE).
+          td(UNAVAILABLE).
+          td(UNAVAILABLE).
+          td(UNAVAILABLE).
+          td(UNAVAILABLE).
+          td(UNAVAILABLE).
+          td(UNAVAILABLE).
+          td(UNAVAILABLE)
+          .__();
+    } else {
+      initSubClusterOverViewTable(metrics, fsMetricsScheduleTr, subclusters);
+    }
+
+    fsMetricsScheduleTr.__().__();
+  }
+
+  private void initSubClusterOverViewTable(RouterClusterMetrics metrics,
+      Hamlet.TBODY<Hamlet.TABLE<Hamlet.DIV<Hamlet>>> fsMetricsScheduleTr,
+      List<SubClusterInfo> subclusters) {
+
+    // configuration
+    Configuration config = this.router.getConfig();
+
+    Client client = RouterWebServiceUtil.createJerseyClient(config);
+
+    // Traverse all SubClusters to get cluster information.
+    for (SubClusterInfo subcluster : subclusters) {
+
+      // Call the RM interface to obtain schedule information
+      String webAppAddress =  WebAppUtils.getHttpSchemePrefix(config) +
+          subcluster.getRMWebServiceAddress();
+
+      SchedulerOverviewInfo typeInfo = RouterWebServiceUtil
+          .genericForward(webAppAddress, null, SchedulerOverviewInfo.class, HTTPMethods.GET,
+          RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.SCHEDULER_OVERVIEW, null, null,
+          config, client);
+      RouterSchedulerMetrics rsMetrics = new RouterSchedulerMetrics(subcluster, metrics, typeInfo);
+
+      // Basic information
+      fsMetricsScheduleTr.tr().
+          td(rsMetrics.getSubCluster()).
+          td(rsMetrics.getSchedulerType()).
+          td(rsMetrics.getSchedulingResourceType()).
+          td(rsMetrics.getMinimumAllocation()).
+          td(rsMetrics.getMaximumAllocation()).
+          td(rsMetrics.getApplicationPriority()).
+          td(rsMetrics.getSchedulerBusy()).
+          td(rsMetrics.getRmDispatcherEventQueueSize()).
+          td(rsMetrics.getSchedulerDispatcherEventQueueSize()).
+          __();
+    }
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterBlock.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterBlock.java
new file mode 100644
index 00000000000..de5d62edf1f
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterBlock.java
@@ -0,0 +1,99 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.router.webapp;
+
+import com.sun.jersey.api.client.Client;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.federation.store.records.SubClusterId;
+import org.apache.hadoop.yarn.server.federation.store.records.SubClusterInfo;
+import org.apache.hadoop.yarn.server.federation.utils.FederationStateStoreFacade;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWSConsts;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterMetricsInfo;
+import org.apache.hadoop.yarn.server.router.Router;
+import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
+import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Collections;
+import java.util.Comparator;
+
+public abstract class RouterBlock extends HtmlBlock {
+
+  private final Router router;
+
+  public RouterBlock(Router router, ViewContext ctx) {
+    super(ctx);
+    this.router = router;
+  }
+
+  /**
+   * Get RouterClusterMetrics Info.
+   *
+   * @return Router ClusterMetricsInfo.
+   */
+  protected ClusterMetricsInfo getRouterClusterMetricsInfo() {
+    Configuration conf = this.router.getConfig();
+    boolean isEnabled = isYarnFederationEnabled();
+    if(isEnabled) {
+      String webAppAddress = WebAppUtils.getRouterWebAppURLWithScheme(conf);
+      Client client = RouterWebServiceUtil.createJerseyClient(conf);
+      ClusterMetricsInfo metrics = RouterWebServiceUtil
+          .genericForward(webAppAddress, null, ClusterMetricsInfo.class, HTTPMethods.GET,
+          RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.METRICS, null, null,
+          conf, client);
+      return metrics;
+    }
+    return null;
+  }
+
+  /**
+   * Get a list of subclusters.
+   *
+   * @return subcluster List.
+   * @throws YarnException if the call to the getSubClusters is unsuccessful.
+   */
+  protected List<SubClusterInfo> getSubClusterInfoList() throws YarnException {
+    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 = Comparator.comparing(o -> o.getSubClusterId());
+    Collections.sort(subclusters, cmp);
+
+    return subclusters;
+  }
+
+  /**
+   * Whether Yarn Federation is enabled.
+   *
+   * @return true, enable yarn federation; false, not enable yarn federation;
+   */
+  protected boolean isYarnFederationEnabled() {
+    Configuration conf = this.router.getConfig();
+    boolean isEnabled = conf.getBoolean(
+        YarnConfiguration.FEDERATION_ENABLED,
+        YarnConfiguration.DEFAULT_FEDERATION_ENABLED);
+    return isEnabled;
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/RouterClusterMetrics.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/RouterClusterMetrics.java
new file mode 100644
index 00000000000..46e9e89ac18
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/RouterClusterMetrics.java
@@ -0,0 +1,310 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.router.webapp.dao;
+
+import org.apache.hadoop.util.StringUtils;
+import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterMetricsInfo;
+import org.apache.hadoop.yarn.util.resource.Resources;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RouterClusterMetrics {
+
+  protected static final long BYTES_IN_MB = 1024 * 1024;
+  private static final Logger LOG = LoggerFactory.getLogger(RouterClusterMetrics.class);
+
+  // Application Information.
+  private String appsSubmitted = "N/A";
+  private String appsCompleted = "N/A";
+  private String appsPending = "N/A";
+  private String appsRunning = "N/A";
+  private String appsFailed = "N/A";
+  private String appsKilled = "N/A";
+
+  // Memory Information.
+  private String totalMemory = "N/A";
+  private String reservedMemory = "N/A";
+  private String availableMemory = "N/A";
+  private String allocatedMemory = "N/A";
+  private String pendingMemory = "N/A";
+
+  // VirtualCores Information.
+  private String reservedVirtualCores = "N/A";
+  private String availableVirtualCores = "N/A";
+  private String allocatedVirtualCores = "N/A";
+  private String pendingVirtualCores = "N/A";
+  private String totalVirtualCores = "N/A";
+
+  // Resources Information.
+  private String usedResources = "N/A";
+  private String totalResources = "N/A";
+  private String reservedResources = "N/A";
+  private String allocatedContainers = "N/A";
+
+  // Resource Percent Information.
+  private String utilizedMBPercent = "N/A";
+  private String utilizedVirtualCoresPercent = "N/A";
+
+  // Node Information.
+  private String activeNodes = "N/A";
+  private String decommissioningNodes = "N/A";
+  private String decommissionedNodes = "N/A";
+  private String lostNodes = "N/A";
+  private String unhealthyNodes = "N/A";
+  private String rebootedNodes = "N/A";
+  private String shutdownNodes = "N/A";
+
+  public RouterClusterMetrics() {
+
+  }
+
+  public RouterClusterMetrics(ClusterMetricsInfo metrics) {
+    if (metrics != null) {
+      // Application Information Conversion.
+      conversionApplicationInformation(metrics);
+
+      // Memory Information Conversion.
+      conversionMemoryInformation(metrics);
+
+      // Resources Information Conversion.
+      conversionResourcesInformation(metrics);
+
+      // Percent Information Conversion.
+      conversionResourcesPercent(metrics);
+
+      // Node Information Conversion.
+      conversionNodeInformation(metrics);
+    }
+  }
+
+  // Get Key Metric Information
+  public String getAppsSubmitted() {
+    return appsSubmitted;
+  }
+
+  public String getAppsCompleted() {
+    return appsCompleted;
+  }
+
+  public String getAppsPending() {
+    return appsPending;
+  }
+
+  public String getAppsRunning() {
+    return appsRunning;
+  }
+
+  public String getAppsFailed() {
+    return appsFailed;
+  }
+
+  public String getAppsKilled() {
+    return appsKilled;
+  }
+
+  public String getTotalMemory() {
+    return totalMemory;
+  }
+
+  public String getReservedMemory() {
+    return reservedMemory;
+  }
+
+  public String getAvailableMemory() {
+    return availableMemory;
+  }
+
+  public String getAllocatedMemory() {
+    return allocatedMemory;
+  }
+
+  public String getPendingMemory() {
+    return pendingMemory;
+  }
+
+  public String getReservedVirtualCores() {
+    return reservedVirtualCores;
+  }
+
+  public String getAvailableVirtualCores() {
+    return availableVirtualCores;
+  }
+
+  public String getAllocatedVirtualCores() {
+    return allocatedVirtualCores;
+  }
+
+  public String getPendingVirtualCores() {
+    return pendingVirtualCores;
+  }
+
+  public String getTotalVirtualCores() {
+    return totalVirtualCores;
+  }
+
+  public String getUsedResources() {
+    return usedResources;
+  }
+
+  public String getTotalResources() {
+    return totalResources;
+  }
+
+  public String getReservedResources() {
+    return reservedResources;
+  }
+
+  public String getAllocatedContainers() {
+    return allocatedContainers;
+  }
+
+  public String getUtilizedMBPercent() {
+    return utilizedMBPercent;
+  }
+
+  public String getUtilizedVirtualCoresPercent() {
+    return utilizedVirtualCoresPercent;
+  }
+
+  public String getActiveNodes() {
+    return activeNodes;
+  }
+
+  public String getDecommissioningNodes() {
+    return decommissioningNodes;
+  }
+
+  public String getDecommissionedNodes() {
+    return decommissionedNodes;
+  }
+
+  public String getLostNodes() {
+    return lostNodes;
+  }
+
+  public String getUnhealthyNodes() {
+    return unhealthyNodes;
+  }
+
+  public String getRebootedNodes() {
+    return rebootedNodes;
+  }
+
+  public String getShutdownNodes() {
+    return shutdownNodes;
+  }
+
+  // Metric Information Conversion
+  public void conversionApplicationInformation(ClusterMetricsInfo metrics) {
+    try {
+      // Application Information.
+      this.appsSubmitted = String.valueOf(metrics.getAppsSubmitted());
+      this.appsCompleted = String.valueOf(metrics.getAppsCompleted() +
+           metrics.getAppsFailed() + metrics.getAppsKilled());
+      this.appsPending = String.valueOf(metrics.getAppsPending());
+      this.appsRunning = String.valueOf(metrics.getAppsRunning());
+      this.appsFailed = String.valueOf(metrics.getAppsFailed());
+      this.appsKilled = String.valueOf(metrics.getAppsKilled());
+    } catch (Exception e) {
+      LOG.error("conversionApplicationInformation error.", e);
+    }
+  }
+
+  // Metric Memory Information
+  public void conversionMemoryInformation(ClusterMetricsInfo metrics) {
+    try {
+      // Memory Information.
+      this.totalMemory = StringUtils.byteDesc(metrics.getTotalMB() * BYTES_IN_MB);
+      this.reservedMemory = StringUtils.byteDesc(metrics.getReservedMB() * BYTES_IN_MB);
+      this.availableMemory = StringUtils.byteDesc(metrics.getAvailableMB() * BYTES_IN_MB);
+      this.allocatedMemory = StringUtils.byteDesc(metrics.getAllocatedMB() * BYTES_IN_MB);
+      this.pendingMemory = StringUtils.byteDesc(metrics.getPendingMB() * BYTES_IN_MB);
+    } catch (Exception e) {
+      LOG.error("conversionMemoryInformation error.", e);
+    }
+  }
+
+  // ResourcesInformation Conversion
+  public void conversionResourcesInformation(ClusterMetricsInfo metrics) {
+    try {
+      // Parse resource information from metrics.
+      Resource metricUsedResources;
+      Resource metricTotalResources;
+      Resource metricReservedResources;
+
+      int metricAllocatedContainers;
+      if (metrics.getCrossPartitionMetricsAvailable()) {
+        metricAllocatedContainers = metrics.getTotalAllocatedContainersAcrossPartition();
+        metricUsedResources = metrics.getTotalUsedResourcesAcrossPartition().getResource();
+        metricTotalResources = metrics.getTotalClusterResourcesAcrossPartition().getResource();
+        metricReservedResources = metrics.getTotalReservedResourcesAcrossPartition().getResource();
+        // getTotalUsedResourcesAcrossPartition includes reserved resources.
+        Resources.subtractFrom(metricUsedResources, metricReservedResources);
+      } else {
+        metricAllocatedContainers = metrics.getContainersAllocated();
+        metricUsedResources = Resource.newInstance(metrics.getAllocatedMB(),
+            (int) metrics.getAllocatedVirtualCores());
+        metricTotalResources = Resource.newInstance(metrics.getTotalMB(),
+            (int) metrics.getTotalVirtualCores());
+        metricReservedResources = Resource.newInstance(metrics.getReservedMB(),
+            (int) metrics.getReservedVirtualCores());
+      }
+
+      // Convert to standard format.
+      usedResources = metricUsedResources.getFormattedString();
+      totalResources = metricTotalResources.getFormattedString();
+      reservedResources = metricReservedResources.getFormattedString();
+      allocatedContainers =  String.valueOf(metricAllocatedContainers);
+
+    } catch (Exception e) {
+      LOG.error("conversionResourcesInformation error.", e);
+    }
+  }
+
+  // ResourcesPercent Conversion
+  public void conversionResourcesPercent(ClusterMetricsInfo metrics) {
+    try {
+      this.utilizedMBPercent = String.valueOf(metrics.getUtilizedMBPercent());
+      this.utilizedVirtualCoresPercent = String.valueOf(metrics.getUtilizedVirtualCoresPercent());
+    } catch (Exception e) {
+      LOG.error("conversionResourcesPercent error.", e);
+    }
+  }
+
+  // NodeInformation Conversion
+  public void conversionNodeInformation(ClusterMetricsInfo metrics) {
+    try {
+      this.activeNodes = String.valueOf(metrics.getActiveNodes());
+      this.decommissioningNodes = String.valueOf(metrics.getDecommissioningNodes());
+      this.decommissionedNodes = String.valueOf(metrics.getDecommissionedNodes());
+      this.lostNodes = String.valueOf(metrics.getLostNodes());
+      this.unhealthyNodes = String.valueOf(metrics.getUnhealthyNodes());
+      this.rebootedNodes = String.valueOf(metrics.getRebootedNodes());
+      this.shutdownNodes = String.valueOf(metrics.getShutdownNodes());
+    } catch (Exception e) {
+      LOG.error("conversionNodeInformation error.", e);
+    }
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/RouterInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/RouterInfo.java
new file mode 100644
index 00000000000..7cedd0c8e1f
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/RouterInfo.java
@@ -0,0 +1,104 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.router.webapp.dao;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.service.Service;
+import org.apache.hadoop.util.VersionInfo;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.server.router.Router;
+import org.apache.hadoop.yarn.util.YarnVersionInfo;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RouterInfo {
+  private long id;
+  private long startedOn;
+  private Service.STATE state;
+  private String routerStateStoreName;
+  private String routerVersion;
+  private String routerBuildVersion;
+  private String routerVersionBuiltOn;
+  private String hadoopVersion;
+  private String hadoopBuildVersion;
+  private String hadoopVersionBuiltOn;
+
+  public RouterInfo() {
+  } // JAXB needs this
+
+  public RouterInfo(Router router) {
+    long ts = Router.getClusterTimeStamp();
+    this.id = ts;
+    this.state = router.getServiceState();
+    Configuration configuration = router.getConfig();
+    this.routerStateStoreName = configuration.get(
+        YarnConfiguration.FEDERATION_STATESTORE_CLIENT_CLASS,
+        YarnConfiguration.DEFAULT_FEDERATION_STATESTORE_CLIENT_CLASS);
+    this.routerVersion = YarnVersionInfo.getVersion();
+    this.routerBuildVersion = YarnVersionInfo.getBuildVersion();
+    this.routerVersionBuiltOn = YarnVersionInfo.getDate();
+    this.hadoopVersion = VersionInfo.getVersion();
+    this.hadoopBuildVersion = VersionInfo.getBuildVersion();
+    this.hadoopVersionBuiltOn = VersionInfo.getDate();
+    this.startedOn = ts;
+  }
+
+  public String getState() {
+    return this.state.toString();
+  }
+
+  public String getRouterStateStore() {
+    return this.routerStateStoreName;
+  }
+
+  public String getRouterVersion() {
+    return this.routerVersion;
+  }
+
+  public String getRouterBuildVersion() {
+    return this.routerBuildVersion;
+  }
+
+  public String getRouterVersionBuiltOn() {
+    return this.routerVersionBuiltOn;
+  }
+
+  public String getHadoopVersion() {
+    return this.hadoopVersion;
+  }
+
+  public String getHadoopBuildVersion() {
+    return this.hadoopBuildVersion;
+  }
+
+  public String getHadoopVersionBuiltOn() {
+    return this.hadoopVersionBuiltOn;
+  }
+
+  public long getClusterId() {
+    return this.id;
+  }
+
+  public long getStartedOn() {
+    return this.startedOn;
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/RouterSchedulerMetrics.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/RouterSchedulerMetrics.java
new file mode 100644
index 00000000000..4a3af1ba43d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/RouterSchedulerMetrics.java
@@ -0,0 +1,109 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.router.webapp.dao;
+
+
+import org.apache.hadoop.yarn.server.federation.store.records.SubClusterInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerOverviewInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RouterSchedulerMetrics {
+
+  // Metrics Log.
+  private static final Logger LOG = LoggerFactory.getLogger(RouterSchedulerMetrics.class);
+
+  // Scheduler Information.
+  private String subCluster = "N/A";
+  private String schedulerType = "N/A";
+  private String schedulingResourceType = "N/A";
+  private String minimumAllocation = "N/A";
+  private String maximumAllocation = "N/A";
+  private String applicationPriority = "N/A";
+  private String schedulerBusy = "N/A";
+  private String rmDispatcherEventQueueSize = "N/A";
+  private String schedulerDispatcherEventQueueSize = "N/A";
+
+  public RouterSchedulerMetrics() {
+
+  }
+
+  public RouterSchedulerMetrics(SubClusterInfo subClusterInfo, RouterClusterMetrics metrics,
+      SchedulerOverviewInfo overview) {
+    try {
+      // Parse Scheduler Information.
+      this.subCluster = subClusterInfo.getSubClusterId().getId();
+      this.schedulerType = overview.getSchedulerType();
+      this.schedulingResourceType = overview.getSchedulingResourceType();
+      this.minimumAllocation = overview.getMinimumAllocation().toString();
+      this.maximumAllocation = overview.getMaximumAllocation().toString();
+      this.applicationPriority = String.valueOf(overview.getApplicationPriority());
+      if (overview.getSchedulerBusy() != -1) {
+        this.schedulerBusy = String.valueOf(overview.getSchedulerBusy());
+      }
+      this.rmDispatcherEventQueueSize =
+          String.valueOf(overview.getRmDispatcherEventQueueSize());
+      this.schedulerDispatcherEventQueueSize =
+          String.valueOf(overview.getSchedulerDispatcherEventQueueSize());
+    } catch (Exception ex) {
+      LOG.error("RouterSchedulerMetrics Error.", ex);
+    }
+  }
+
+  public String getSubCluster() {
+    return subCluster;
+  }
+
+  public String getSchedulerType() {
+    return schedulerType;
+  }
+
+  public String getSchedulingResourceType() {
+    return schedulingResourceType;
+  }
+
+  public String getMinimumAllocation() {
+    return minimumAllocation;
+  }
+
+  public String getMaximumAllocation() {
+    return maximumAllocation;
+  }
+
+  public String getApplicationPriority() {
+    return applicationPriority;
+  }
+
+  public String getRmDispatcherEventQueueSize() {
+    return rmDispatcherEventQueueSize;
+  }
+
+  public String getSchedulerDispatcherEventQueueSize() {
+    return schedulerDispatcherEventQueueSize;
+  }
+
+  public String getSchedulerBusy() {
+    return schedulerBusy;
+  }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/package-info.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/package-info.java
new file mode 100644
index 00000000000..27f43ad1ff4
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/dao/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/** Router Web Dao package. **/
+package org.apache.hadoop.yarn.server.router.webapp.dao;
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestFederationWebApp.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestFederationWebApp.java
index e0ea4ccdb39..55f23db72b2 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestFederationWebApp.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestFederationWebApp.java
@@ -26,7 +26,7 @@ import org.junit.Test;
 
 import java.io.IOException;
 
-public class TestFederationWebApp {
+public class TestFederationWebApp extends TestRouterWebServicesREST {
 
   @Test
   public void testFederationWebViewNotEnable()
@@ -45,4 +45,22 @@ public class TestFederationWebApp {
     config.setBoolean(YarnConfiguration.FEDERATION_ENABLED, true);
     WebAppTests.testPage(FederationPage.class, Router.class, new MockRouter(config));
   }
+
+  @Test
+  public void testFederationAboutViewEnable()
+      throws InterruptedException, YarnException, IOException {
+    // Test Federation Enabled
+    Configuration config = new YarnConfiguration();
+    config.setBoolean(YarnConfiguration.FEDERATION_ENABLED, true);
+    WebAppTests.testPage(AboutPage.class, Router.class, new MockRouter(config));
+  }
+
+  @Test
+  public void testFederationAboutViewNotEnable()
+      throws InterruptedException, YarnException, IOException {
+    // Test Federation Not Enabled
+    Configuration config = new YarnConfiguration();
+    config.setBoolean(YarnConfiguration.FEDERATION_ENABLED, false);
+    WebAppTests.testPage(AboutPage.class, Router.class, new MockRouter(config));
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org