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
new file mode 100644
index 00000000000..723cbd68174
--- /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/AboutBlock.java
@@ -0,0 +1,77 @@
+/**
+* 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.router.webapp;
+
+import org.apache.hadoop.conf.Configuration;
+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.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.webapp.view.InfoBlock;
+
+import com.google.inject.Inject;
+
+/**
+ * About block for the Router Web UI.
+ */
+public class AboutBlock extends HtmlBlock {
+ private final Router router;
+
+ @Inject
+ AboutBlock(Router router, ViewContext ctx) {
+ super(ctx);
+ this.router = router;
+ }
+
+ @Override
+ protected void render(Block html) {
+ Configuration conf = this.router.getConfig();
+ String webAppAddress = WebAppUtils.getRouterWebAppURLWithScheme(conf);
+ ClusterMetricsInfo metrics = RouterWebServiceUtil.genericForward(
+ webAppAddress, null, ClusterMetricsInfo.class, HTTPMethods.GET,
+ RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.METRICS, null, null);
+ boolean isEnabled = conf.getBoolean(
+ YarnConfiguration.FEDERATION_ENABLED,
+ YarnConfiguration.DEFAULT_FEDERATION_ENABLED);
+ info("Federation status").
+ __("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()).
+ __("Virtual codes available", metrics.getAvailableVirtualCores()).
+ __("Virtual codes allocated", metrics.getAllocatedVirtualCores()).
+ __("Virtual codes total", metrics.getTotalVirtualCores()).
+ __("Memory available", metrics.getAvailableMB()).
+ __("Memory allocated", metrics.getAllocatedMB()).
+ __("Memory total", metrics.getTotalMB()).
+ __("Nodes active", metrics.getActiveNodes()).
+ __("Nodes lost", metrics.getLostNodes()).
+ __("Nodes decommissioned", metrics.getDecommissionedNodes()).
+ __("Nodes decommissioning", metrics.getDecommissioningNodes()).
+ __("Nodes total", metrics.getTotalNodes());
+
+ html.__(InfoBlock.class);
+ }
+}
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/AboutPage.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/AboutPage.java
new file mode 100644
index 00000000000..3c9f00dbfc6
--- /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/AboutPage.java
@@ -0,0 +1,37 @@
+/**
+* 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.router.webapp;
+
+import org.apache.hadoop.yarn.webapp.SubView;
+
+/**
+ * About page for the Router Web UI.
+ */
+public class AboutPage extends RouterView {
+
+ @Override
+ protected void preHead(Page.HTML<__> html) {
+ commonPreHead(html);
+ }
+
+ @Override
+ protected Class extends SubView> content() {
+ return AboutBlock.class;
+ }
+}
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/AppsBlock.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/AppsBlock.java
new file mode 100644
index 00000000000..ddad460361a
--- /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/AppsBlock.java
@@ -0,0 +1,132 @@
+/**
+ * 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.router.webapp;
+
+import static org.apache.hadoop.yarn.util.StringHelper.join;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.C_PROGRESSBAR;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.C_PROGRESSBAR_VALUE;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.util.StringUtils;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWSConsts;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo;
+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;
+
+/**
+ * Applications block for the Router Web UI.
+ */
+public class AppsBlock extends HtmlBlock {
+ private final Router router;
+
+ @Inject
+ AppsBlock(Router router, ViewContext ctx) {
+ super(ctx);
+ this.router = router;
+ }
+
+ @Override
+ protected void render(Block html) {
+ // Get the applications from the Resource Managers
+ Configuration conf = this.router.getConfig();
+ String webAppAddress = WebAppUtils.getRouterWebAppURLWithScheme(conf);
+ AppsInfo apps = RouterWebServiceUtil.genericForward(webAppAddress, null,
+ AppsInfo.class, HTTPMethods.GET,
+ RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.APPS, null, null);
+
+ setTitle("Applications");
+
+ TBODY
> tbody =
+ html.table("#apps").thead().tr().th(".id", "ID").th(".user", "User")
+ .th(".name", "Name")
+ .th(".type", "Application Type")
+ .th(".queue", "Queue")
+ .th(".starttime", "StartTime")
+ .th(".finishtime", "FinishTime")
+ .th(".state", "State")
+ .th(".finalstatus", "FinalStatus")
+ .th(".progress", "Progress")
+ .th(".ui", "Tracking UI")
+ .__().__().tbody();
+
+ // Render the applications
+ StringBuilder appsTableData = new StringBuilder("[\n");
+ for (AppInfo app : apps.getApps()) {
+ try {
+
+ String percent = String.format("%.1f", app.getProgress() * 100.0F);
+ // AppID numerical value parsed by parseHadoopID in yarn.dt.plugins.js
+ appsTableData.append("[\"").append(app.getAppId()).append("\",\"")
+ .append(StringEscapeUtils
+ .escapeJavaScript(StringEscapeUtils.escapeHtml(app.getUser())))
+ .append("\",\"")
+ .append(StringEscapeUtils
+ .escapeJavaScript(StringEscapeUtils.escapeHtml(app.getName())))
+ .append("\",\"")
+ .append(StringEscapeUtils.escapeJavaScript(
+ StringEscapeUtils.escapeHtml(app.getApplicationType())))
+ .append("\",\"")
+ .append(StringEscapeUtils
+ .escapeJavaScript(StringEscapeUtils.escapeHtml(app.getQueue())))
+ .append("\",\"").append(app.getStartTime()).append("\",\"")
+ .append(app.getFinishTime()).append("\",\"").append(app.getState())
+ .append("\",\"").append(app.getFinalStatus()).append("\",\"")
+ // Progress bar
+ .append("
")
+ .append("\",\"").append("History")
+ .append("");
+ appsTableData.append("\"],\n");
+
+ } catch (Exception e) {
+ LOG.info(
+ "Cannot add application " + app.getAppId() + ": " + e.getMessage());
+ }
+ }
+ if (appsTableData.charAt(appsTableData.length() - 2) == ',') {
+ appsTableData.delete(appsTableData.length() - 2,
+ appsTableData.length() - 1);
+ }
+ appsTableData.append("]");
+ html.script().$type("text/javascript")
+ .__("var appsTableData=" + appsTableData).__();
+
+ tbody.__().__();
+ }
+}
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/AppsPage.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/AppsPage.java
new file mode 100644
index 00000000000..12d0b5b4ede
--- /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/AppsPage.java
@@ -0,0 +1,77 @@
+/**
+ * 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.router.webapp;
+
+import static org.apache.hadoop.yarn.util.StringHelper.sjoin;
+import static org.apache.hadoop.yarn.webapp.YarnWebParams.APP_STATE;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.DATATABLES;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.DATATABLES_ID;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.initID;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.tableInit;
+
+import org.apache.hadoop.yarn.webapp.SubView;
+
+class AppsPage extends RouterView {
+
+ @Override
+ protected void preHead(Page.HTML<__> html) {
+ commonPreHead(html);
+ set(DATATABLES_ID, "apps");
+ set(initID(DATATABLES, "apps"), appsTableInit());
+ setTableStyles(html, "apps", ".queue {width:6em}", ".ui {width:8em}");
+
+ // Set the correct title.
+ String reqState = $(APP_STATE);
+ reqState = (reqState == null || reqState.isEmpty() ? "All" : reqState);
+ setTitle(sjoin(reqState, "Applications"));
+ }
+
+ private String appsTableInit() {
+ // id, user, name, queue, starttime, finishtime, state, status, progress, ui
+ return tableInit()
+ .append(", 'aaData': appsTableData")
+ .append(", bDeferRender: true")
+ .append(", bProcessing: true")
+
+ .append("\n, aoColumnDefs: ")
+ .append(getAppsTableColumnDefs())
+
+ // Sort by id upon page load
+ .append(", aaSorting: [[0, 'desc']]}").toString();
+ }
+
+ protected String getAppsTableColumnDefs() {
+ StringBuilder sb = new StringBuilder();
+ return sb
+ .append("[\n")
+ .append("{'sType':'string', 'aTargets': [0]")
+ .append(", 'mRender': parseHadoopID }")
+
+ .append("\n, {'sType':'numeric', 'aTargets': [6, 7]")
+ .append(", 'mRender': renderHadoopDate }")
+
+ .append("\n, {'sType':'numeric', bSearchable:false, 'aTargets': [10]")
+ .append(", 'mRender': parseHadoopProgress }]").toString();
+ }
+
+ @Override
+ protected Class extends SubView> content() {
+ return AppsBlock.class;
+ }
+}
\ 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
new file mode 100644
index 00000000000..e3171c4a607
--- /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/FederationBlock.java
@@ -0,0 +1,129 @@
+/**
+ * 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.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 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.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.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 {
+
+ @Inject
+ FederationBlock(ViewContext ctx, Router router) {
+ super(ctx);
+ }
+
+ @Override
+ public void render(Block html) {
+ setTitle("Federation");
+
+ // Table header
+ TBODY> tbody = html.table("#rms")
+ .thead()
+ .tr()
+ .th(".id", "Subcluster")
+ .th(".submitted", "Apps Submitted")
+ .th(".running", "Apps Running")
+ .th(".completed", "Apps Completed")
+ .th(".failed", "Apps Failed")
+ .th(".killed", "Apps Killed")
+ .th(".containers", "Containers Running")
+ .th(".nodes", "Active Nodes")
+ .th(".maintenance", "Maintenance Nodes")
+ .__().__().tbody();
+
+ try {
+ // Binding to the State Store
+ FederationStateStoreFacade facade =
+ FederationStateStoreFacade.getInstance();
+ Map subClustersInfo =
+ facade.getSubClusters(true);
+
+ // Sort the subclusters
+ List subclusters = new ArrayList<>();
+ subclusters.addAll(subClustersInfo.values());
+ Comparator super SubClusterInfo> cmp =
+ new Comparator() {
+ @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.getClientRMServiceAddress();
+ 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.getAppsRunning()))
+ .td(Integer.toString(subClusterInfo.getAppsCompleted()))
+ .td(Integer.toString(subClusterInfo.getAppsFailed()))
+ .td(Integer.toString(subClusterInfo.getAppsKilled()))
+ .td(Integer.toString(subClusterInfo.getContainersAllocated()))
+ .td(Integer.toString(subClusterInfo.getActiveNodes()))
+ .__();
+ }
+ } catch (YarnException e) {
+ LOG.error("Cannot render resource managers", e);
+ }
+
+ tbody.__().__();
+ }
+
+ private static ClusterMetricsInfo getClusterMetricsInfo(String capability) {
+ ClusterMetricsInfo clusterMetrics = null;
+ try {
+ JSONJAXBContext jc = new JSONJAXBContext(
+ JSONConfiguration.mapped().rootUnwrapping(false).build(),
+ ClusterMetricsInfo.class);
+ JSONUnmarshaller unmarshaller = jc.createJSONUnmarshaller();
+ clusterMetrics = unmarshaller.unmarshalFromJSON(
+ new StringReader(capability),
+ ClusterMetricsInfo.class);
+ } catch (Exception e) {
+ LOG.error("Cannot parse subcluster info", e);
+ }
+ return clusterMetrics;
+ }
+}
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/FederationPage.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/FederationPage.java
new file mode 100644
index 00000000000..ddd2866e3b1
--- /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/FederationPage.java
@@ -0,0 +1,57 @@
+/**
+* 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.router.webapp;
+
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.DATATABLES;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.DATATABLES_ID;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.initID;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.tableInit;
+
+import org.apache.hadoop.yarn.webapp.SubView;
+
+/**
+ * Renders a block for the applications with metrics information.
+ */
+class FederationPage extends RouterView {
+
+ @Override
+ protected void preHead(Page.HTML<__> html) {
+ commonPreHead(html);
+ setTitle("Federation");
+ set(DATATABLES_ID, "rms");
+ set(initID(DATATABLES, "rms"), rmsTableInit());
+ setTableStyles(html, "rms", ".healthStatus {width:10em}",
+ ".healthReport {width:10em}");
+ }
+
+ @Override
+ protected Class extends SubView> content() {
+ return FederationBlock.class;
+ }
+
+ private String rmsTableInit() {
+ StringBuilder b = tableInit().append(", aoColumnDefs: [");
+ b.append("{'bSearchable': false, 'aTargets': [ 7 ]}");
+ b.append(", {'sType': 'title-numeric', 'bSearchable': false, "
+ + "'aTargets': [ 8, 9 ] }");
+ b.append(", {'sType': 'title-numeric', 'aTargets': [ 5 ]}");
+ b.append("]}");
+ return b.toString();
+ }
+}
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/NavBlock.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/NavBlock.java
new file mode 100644
index 00000000000..c33170cbcbf
--- /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/NavBlock.java
@@ -0,0 +1,46 @@
+/**
+* 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.router.webapp;
+
+import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
+
+/**
+ * Navigation block for the Router Web UI.
+ */
+public class NavBlock extends HtmlBlock {
+
+ @Override
+ public void render(Block html) {
+ html.
+ div("#nav").
+ h3("Cluster").
+ ul().
+ li().a(url("cluster"), "About").__().
+ li().a(url(""), "Federation").__().
+ li().a(url("nodes"), "Nodes").__().
+ li().a(url("apps"), "Applications").__().
+ __().
+ h3("Tools").
+ ul().
+ li().a("/conf", "Configuration").__().
+ li().a("/logs", "Local logs").__().
+ li().a("/stacks", "Server stacks").__().
+ li().a("/jmx?qry=Hadoop:*", "Server metrics").__().__().__();
+ }
+}
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/NodesBlock.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/NodesBlock.java
new file mode 100644
index 00000000000..bc569f70bbf
--- /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/NodesBlock.java
@@ -0,0 +1,124 @@
+/**
+ * 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.router.webapp;
+
+import java.util.Map;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.util.StringUtils;
+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.NodeInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
+import org.apache.hadoop.yarn.server.router.Router;
+import org.apache.hadoop.yarn.util.Times;
+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.hamlet2.Hamlet.TR;
+import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
+import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
+
+import com.google.inject.Inject;
+
+/**
+ * Nodes block for the Router Web UI.
+ */
+public class NodesBlock extends HtmlBlock {
+
+ private static final long BYTES_IN_MB = 1024 * 1024;
+
+ private final Router router;
+
+ private Map nodesToSubcluster;
+
+ @Inject
+ NodesBlock(Router router, ViewContext ctx) {
+ super(ctx);
+ this.router = router;
+ }
+
+ @Override
+ protected void render(Block html) {
+ // Get the node info from the federation
+ Configuration conf = this.router.getConfig();
+ String webAppAddress = WebAppUtils.getRouterWebAppURLWithScheme(conf);
+ NodesInfo nodes = RouterWebServiceUtil.genericForward(
+ webAppAddress, null, NodesInfo.class, HTTPMethods.GET,
+ RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.NODES,
+ null, null);
+
+ setTitle("Nodes");
+
+ TBODY> tbody = html.table("#nodes").thead().tr()
+ .th(".subcluster", "Subcluster")
+ .th(".nodelabels", "Node Labels")
+ .th(".rack", "Rack")
+ .th(".state", "Node State")
+ .th(".nodeaddress", "Node Address")
+ .th(".nodehttpaddress", "Node HTTP Address")
+ .th(".lastHealthUpdate", "Last health-update")
+ .th(".healthReport", "Health-report")
+ .th(".containers", "Containers")
+ .th(".mem", "Mem Used")
+ .th(".mem", "Mem Avail")
+ .th(".vcores", "VCores Used")
+ .th(".vcores", "VCores Avail")
+ .th(".nodeManagerVersion", "Version")
+ .__().__().tbody();
+
+
+ // Add nodes to the web UI
+ for (NodeInfo info : nodes.getNodes()) {
+ String nodeId = info.getNodeId();
+ int usedMemory = (int) info.getUsedMemory();
+ int availableMemory = (int) info.getAvailableMemory();
+ TR>> row = tbody.tr();
+ if (nodesToSubcluster.containsKey(nodeId)) {
+ SubClusterInfo subcluster = nodesToSubcluster.get(info.getNodeId());
+ row.td().a("//" + subcluster.getRMWebServiceAddress(),
+ subcluster.getSubClusterId().toString()).__();
+ } else {
+ row.td("N/A");
+ }
+ row.td(StringUtils.join(",", info.getNodeLabels())).td(info.getRack())
+ .td(info.getState()).td(info.getNodeId());
+ // TODO
+ boolean isInactive = false;
+ if (isInactive) {
+ row.td().__("N/A").__();
+ } else {
+ String httpAddress = info.getNodeHTTPAddress();
+ row.td().a("//" + httpAddress, httpAddress).__();
+ }
+ row.td().br().$title(String.valueOf(info.getLastHealthUpdate())).__()
+ .__(Times.format(info.getLastHealthUpdate())).__()
+ .td(info.getHealthReport())
+ .td(String.valueOf(info.getNumContainers())).td().br()
+ .$title(String.valueOf(usedMemory)).__()
+ .__(StringUtils.byteDesc(usedMemory * BYTES_IN_MB)).__().td().br()
+ .$title(String.valueOf(availableMemory)).__()
+ .__(StringUtils.byteDesc(availableMemory * BYTES_IN_MB)).__()
+ .td(String.valueOf(info.getUsedVirtualCores()))
+ .td(String.valueOf(info.getAvailableVirtualCores()))
+ .td(info.getVersion()).__();
+ }
+ tbody.__().__();
+ }
+}
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/NodesPage.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/NodesPage.java
new file mode 100644
index 00000000000..0351cbac3a3
--- /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/NodesPage.java
@@ -0,0 +1,60 @@
+/**
+ * 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.router.webapp;
+
+import static org.apache.hadoop.yarn.webapp.YarnWebParams.NODE_STATE;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.DATATABLES;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.DATATABLES_ID;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.initID;
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.tableInit;
+
+import org.apache.hadoop.yarn.webapp.SubView;
+
+class NodesPage extends RouterView {
+
+ @Override
+ protected void preHead(Page.HTML<__> html) {
+ commonPreHead(html);
+ String type = $(NODE_STATE);
+ String title = "Nodes of the cluster";
+ if (type != null && !type.isEmpty()) {
+ title = title + " (" + type + ")";
+ }
+ setTitle(title);
+ set(DATATABLES_ID, "nodes");
+ set(initID(DATATABLES, "nodes"), nodesTableInit());
+ setTableStyles(html, "nodes", ".healthStatus {width:10em}",
+ ".healthReport {width:10em}");
+ }
+
+ @Override
+ protected Class extends SubView> content() {
+ return NodesBlock.class;
+ }
+
+ private String nodesTableInit() {
+ StringBuilder b = tableInit().append(", aoColumnDefs: [");
+ b.append("{'bSearchable': false, 'aTargets': [ 7 ]}");
+ b.append(", {'sType': 'title-numeric', 'bSearchable': false, "
+ + "'aTargets': [ 2, 3, 4, 5, 6 ] }");
+ b.append(", {'sType': 'title-numeric', 'aTargets': [ 5 ]}");
+ b.append("]}");
+ return b.toString();
+ }
+}
\ 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/RouterController.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterController.java
new file mode 100644
index 00000000000..bf377d46427
--- /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/RouterController.java
@@ -0,0 +1,60 @@
+/**
+* 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.router.webapp;
+
+import org.apache.hadoop.yarn.webapp.Controller;
+
+import com.google.inject.Inject;
+
+/**
+ * Controller for the Router Web UI.
+ */
+public class RouterController extends Controller {
+
+ @Inject
+ RouterController(RequestContext ctx) {
+ super(ctx);
+ }
+
+ @Override
+ public void index() {
+ setTitle("Router");
+ render(FederationPage.class);
+ }
+
+ public void about() {
+ setTitle("About the Cluster");
+ render(AboutPage.class);
+ }
+
+ public void federation() {
+ setTitle("Federation");
+ render(FederationPage.class);
+ }
+
+ public void apps() {
+ setTitle("Applications");
+ render(AppsPage.class);
+ }
+
+ public void nodes() {
+ setTitle("Nodes");
+ render(NodesPage.class);
+ }
+}
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/RouterView.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterView.java
new file mode 100644
index 00000000000..b377f7dc1dd
--- /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/RouterView.java
@@ -0,0 +1,52 @@
+/**
+* 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.router.webapp;
+
+import org.apache.hadoop.yarn.webapp.SubView;
+import org.apache.hadoop.yarn.webapp.view.TwoColumnLayout;
+
+import static org.apache.hadoop.yarn.webapp.view.JQueryUI.*;
+
+/**
+ * View for the Router Web UI.
+ */
+public class RouterView extends TwoColumnLayout {
+
+ @Override
+ protected void preHead(Page.HTML<__> html) {
+ commonPreHead(html);
+
+ setTitle("Router");
+ }
+
+ protected void commonPreHead(Page.HTML<__> html) {
+ set(ACCORDION_ID, "nav");
+ set(initID(ACCORDION, "nav"), "{autoHeight:false, active:0}");
+ }
+
+ @Override
+ protected Class extends SubView> nav() {
+ return NavBlock.class;
+ }
+
+ @Override
+ protected Class extends SubView> content() {
+ return AboutBlock.class;
+ }
+}
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/TestAppsPage.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestAppsPage.java
new file mode 100644
index 00000000000..655f1c5f146
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestAppsPage.java
@@ -0,0 +1,36 @@
+/**
+ * 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.router.webapp;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test the Router applications page.
+ */
+public class TestAppsPage {
+
+ @Before
+ public void setup() {
+ }
+
+ @Test
+ public void test() {
+ }
+}
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/TestNodesPage.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestNodesPage.java
new file mode 100644
index 00000000000..53ddd1bb2e8
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestNodesPage.java
@@ -0,0 +1,36 @@
+/**
+ * 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.router.webapp;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test the Router nodes page.
+ */
+public class TestNodesPage {
+
+ @Before
+ public void setup() {
+ }
+
+ @Test
+ public void test() {
+ }
+}
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/TestResourceManagersPage.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestResourceManagersPage.java
new file mode 100644
index 00000000000..50f97219b98
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/TestResourceManagersPage.java
@@ -0,0 +1,36 @@
+/**
+ * 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.router.webapp;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test the Router federation page.
+ */
+public class TestResourceManagersPage {
+
+ @Before
+ public void setup() {
+ }
+
+ @Test
+ public void test() {
+ }
+}