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..6f4c685cdf3 --- /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,43 @@ +/** +* 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.server.router.Router; +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 { + final Router router; + + @Inject + AboutBlock(Router router, ViewContext ctx) { + super(ctx); + this.router = router; + } + + @Override + protected void render(Block html) { + 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 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..e3edf7794fe --- /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,197 @@ +/** + * 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.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.hadoop.util.StringUtils; +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.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.view.HtmlBlock; + +import com.google.inject.Inject; + +/** + * Applications block for the Router Web UI. + */ +public class AppsBlock extends HtmlBlock { + private final Router router; + + /** Application id -> SubClusters. */ + private Map> appsToSubcluster; + /** Applications in the system. */ + private AppsInfo apps; + + @Inject + AppsBlock(Router router, ViewContext ctx) { + super(ctx); + this.router = router; + } + + @Override + protected void render(Block html) { + // Get the applications from the Resource Managers + initAppsInfo(); + + 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(".reservationid", "ReservationId") + .th(".starttime", "StartTime").th(".finishtime", "FinishTime") + .th(".state", "State").th(".finalstatus", "FinalStatus") + .th(".progress", "Progress").th(".ui", "Tracking UI") + .th(".subcluster", "Subcluster").__().__().tbody(); + + // Render the applications + StringBuilder appsTableData = new StringBuilder("[\n"); + for (AppInfo app : apps.getApps()) { + try { + + String percent = String.format("%.1f", app.getProgress() * 100.0F); + String subclusters = "N/A"; + if (appsToSubcluster.containsKey(app.getAppId())) { + subclusters = + StringUtils.join(",", appsToSubcluster.get(app.getAppId())); + } + + // 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("(best effort)") // TODO + .append("\",\"").append(app.getStartTime()).append("\",\"") + .append(app.getFinishTime()).append("\",\"").append(app.getState()) + .append("\",\"").append(app.getFinalStatus()).append("\",\"") + // Progress bar + .append("
").append("
") + .append("\",\"").append("History") + .append(""); + appsTableData.append("\",\"").append(subclusters); + 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.__().__(); + } + + /** + * Get the applications from the Resource Managers. + * + * @return Information of all the applications in the federation. + */ + private void initAppsInfo() { + // Application to SubClusters + appsToSubcluster = new HashMap<>(); + + // Get the applications from the Resource Managers + apps = new AppsInfo(); + try { + // Check each SubCluster + FederationStateStoreFacade facade = + FederationStateStoreFacade.getInstance(); + Map infos = facade.getSubClusters(true); + for (SubClusterInfo info : infos.values()) { + try { + // Get the applications for this SubCluster + String rmWebAddress = info.getRMWebServiceAddress(); + AppsInfo rmApps = RouterWebServiceUtil.genericForward( + rmWebAddress, null, AppsInfo.class, HTTPMethods.GET, "apps", + null, null); + if (rmApps != null) { + for (AppInfo rmApp : rmApps.getApps()) { + apps.add(rmApp); + } + + // Get link to the SubCluster + StringBuilder sb = new StringBuilder(); + sb.append(""); + sb.append(info.getSubClusterId()); + sb.append(""); + String subclusterLink = sb.toString(); + + // Generate mapping to SubCluster + for (AppInfo rmApp : rmApps.getApps()) { + String appId = rmApp.getAppId(); + if (!appsToSubcluster.containsKey(appId)) { + appsToSubcluster.put(appId, new TreeSet<>()); + } + appsToSubcluster.get(appId).add(subclusterLink); + } + } + } catch (Exception e) { + LOG.error("Cannot get the subcluster information for {}: {}", + info.getRMWebServiceAddress(), e.getMessage()); + } + } + // Aggregate the applications per SubCluster + // TODO + //apps.mergeAppsInfo(); + } catch (YarnException e) { + LOG.error("Cannot get the subcluster information", 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/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 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/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..2d5873bb8d1 --- /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,150 @@ +/** + * 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.HashMap; +import java.util.Map; + +import org.apache.hadoop.util.StringUtils; +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.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.view.HtmlBlock; + +import com.google.inject.Inject; + +/** + * Nodes block for the Router Web UI. + */ +public class NodesBlock extends HtmlBlock { + private final Router router; + private static final long BYTES_IN_MB = 1024 * 1024; + + private Map nodesToSubcluster; + private NodesInfo nodes; + + @Inject + NodesBlock(Router router, ViewContext ctx) { + super(ctx); + this.router = router; + } + + @Override + protected void render(Block html) { + // Get the node info from the federation + initNodesInfo(); + + 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.__().__(); + } + + /** + * Get the node information from the federation + */ + private void initNodesInfo() { + // Node -> SubCluster + nodesToSubcluster = new HashMap(); + + // Get the nodes from the Resource Managers + nodes = new NodesInfo(); + try { + FederationStateStoreFacade facade = + FederationStateStoreFacade.getInstance(); + Map infos = facade.getSubClusters(true); + for (SubClusterInfo info : infos.values()) { + String webAddr = info.getRMWebServiceAddress(); + try { + NodesInfo rmNodes = RouterWebServiceUtil.genericForward( + webAddr, null, NodesInfo.class, HTTPMethods.GET, "nodes", + null, null); + if (rmNodes != null) { + for (NodeInfo rmNode : rmNodes.getNodes()) { + nodes.add(rmNode); + } + + // Assign the node to its SubCluster + for (NodeInfo rmNode : rmNodes.getNodes()) { + nodesToSubcluster.put(rmNode.getNodeId(), info); + } + } + } catch (Exception e) { + LOG.error("Cannot get the SubCluster information for {}: {}", + webAddr, e.getMessage()); + } + } + } catch (Exception e) { + LOG.error("Cannot get the SubCluster information", 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/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 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/ResourceManagersBlock.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/ResourceManagersBlock.java new file mode 100644 index 00000000000..424a334336d --- /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/ResourceManagersBlock.java @@ -0,0 +1,112 @@ +/** + * 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.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBException; + +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.server.router.webapp.dao.SubClusterState; +import org.apache.hadoop.yarn.server.router.webapp.dao.SubClustersMetricsInfo; +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; + +class ResourceManagersBlock extends HtmlBlock { + private Router router; + + @Inject + ResourceManagersBlock(ViewContext ctx, Router router) { + super(ctx); + this.router = router; + } + + @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 { + FederationStateStoreFacade facade = + FederationStateStoreFacade.getInstance(); + Map subClustersInfo = + facade.getSubClusters(true); + + SubClustersMetricsInfo fsi = new SubClustersMetricsInfo(subClustersInfo); + List subclusters = fsi.getSubClusterMetrics(); + Comparator cmp = + new Comparator() { + @Override + public int compare(SubClusterState o1, SubClusterState o2) { + return o1.getSubClusterId().compareTo(o2.getSubClusterId()); + } + }; + Collections.sort(subclusters, cmp); + + for (SubClusterState subClusterState : subclusters) { + String webAppAddress = subClusterState.getWebAppAddress(); + ClusterMetricsInfo scm = subClusterState.getClusterMetrics(); + + // Building row per subcluster + tbody.tr().td() + .a("//" + webAppAddress, subClusterState.getSubClusterId()).__() + .td(Integer.toString(scm.getAppsSubmitted())) + .td(Integer.toString(scm.getAppsRunning())) + .td(Integer.toString(scm.getAppsCompleted())) + .td(Integer.toString(scm.getAppsFailed())) + .td(Integer.toString(scm.getAppsKilled())) + .td(Integer.toString(scm.getContainersAllocated())) + .td(Integer.toString(scm.getActiveNodes())) + .__(); + } + } catch (YarnException e) { + LOG.error("Cannot render resource managers", e); + } catch (JAXBException e) { + LOG.error("Cannot parse subcluster info", e); + } + + 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/ResourceManagersPage.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/ResourceManagersPage.java new file mode 100644 index 00000000000..65ad7463164 --- /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/ResourceManagersPage.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 ResourceManagersPage 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 content() { + return ResourceManagersBlock.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/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..819f0a23ffb --- /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(ResourceManagersPage.class); + } + + public void about() { + setTitle("About the Cluster"); + render(AboutPage.class); + } + + public void federation() { + setTitle("Federation"); + render(ResourceManagersPage.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 nav() { + return NavBlock.class; + } + + @Override + protected Class 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/RouterWebServiceUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebServiceUtil.java index 18618eeac1b..a018a2bfb43 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebServiceUtil.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebServiceUtil.java @@ -223,5 +223,4 @@ public static void retrieveException(ClientResponse response) { } } - } \ 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/dao/SubClusterMetricsInfo.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/SubClusterMetricsInfo.java new file mode 100644 index 00000000000..66c261a7877 --- /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/SubClusterMetricsInfo.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.dao; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterMetricsInfo; + +/** + * Metrics for each subcluster for the Router Web UI. + */ +@XmlRootElement(name = "federationSubClusterMetrics") +@XmlAccessorType(XmlAccessType.FIELD) +public class SubClusterMetricsInfo { + + protected List subClusterMetrics = + new ArrayList<>(); + + public SubClusterMetricsInfo() { + // JAXB needs this + } + + public void add(ClusterMetricsInfo info) { + subClusterMetrics.add(info); + } +} \ 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/dao/SubClusterState.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/SubClusterState.java new file mode 100644 index 00000000000..32cb9d9c7e0 --- /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/SubClusterState.java @@ -0,0 +1,87 @@ +/** + * 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.dao; + +import java.io.StringReader; + +import javax.xml.bind.JAXBException; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +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.resourcemanager.webapp.dao.ClusterMetricsInfo; + +import com.sun.jersey.api.json.JSONConfiguration; +import com.sun.jersey.api.json.JSONJAXBContext; +import com.sun.jersey.api.json.JSONUnmarshaller; + +/** + * State for each cluster for the Router Web UI. + */ +@XmlRootElement(name = "subClusterState") +@XmlAccessorType(XmlAccessType.FIELD) +public class SubClusterState { + + private SubClusterId subClusterId; + private String clientRMAddress; + private String state; + private ClusterMetricsInfo clusterMetrics; + private String webAppAddress; + + public SubClusterState() { + // JAXB needs this + } + + public SubClusterState(SubClusterInfo subClusterInfo) throws JAXBException { + this.subClusterId = subClusterInfo.getSubClusterId(); + this.clientRMAddress = subClusterInfo.getClientRMServiceAddress(); + this.state = subClusterInfo.getState().toString(); + this.webAppAddress = subClusterInfo.getRMWebServiceAddress(); + + // Parse metrics + JSONJAXBContext jc = new JSONJAXBContext( + JSONConfiguration.mapped().rootUnwrapping(false).build(), + ClusterMetricsInfo.class); + JSONUnmarshaller unmarshaller = jc.createJSONUnmarshaller(); + this.clusterMetrics = unmarshaller.unmarshalFromJSON( + new StringReader(subClusterInfo.getCapability()), + ClusterMetricsInfo.class); + } + + public String getSubClusterId() { + return subClusterId.toString(); + } + + public String getClientRMAddress() { + return clientRMAddress; + } + + public String getSubClusterState() { + return state; + } + + public ClusterMetricsInfo getClusterMetrics() { + return clusterMetrics; + } + + public String getWebAppAddress() { + return webAppAddress; + } +} 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/SubClustersMetricsInfo.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/SubClustersMetricsInfo.java new file mode 100644 index 00000000000..bb8e4d99799 --- /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/SubClustersMetricsInfo.java @@ -0,0 +1,62 @@ +/** + * 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.dao; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBException; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.hadoop.yarn.server.federation.store.records.SubClusterId; +import org.apache.hadoop.yarn.server.federation.store.records.SubClusterInfo; + +/** + * Metrics of multiple subclusters for the Router Web UI. + */ +@XmlRootElement(name = "subClustersMetricsInfo") +@XmlAccessorType(XmlAccessType.FIELD) +public class SubClustersMetricsInfo { + + protected List subClusterMetrics; + + public SubClustersMetricsInfo() { + // JAXB needs this + } + + public SubClustersMetricsInfo(List subClusterMetrics) { + this.subClusterMetrics = subClusterMetrics; + } + + public SubClustersMetricsInfo( + Map federationState) throws JAXBException { + + subClusterMetrics = new ArrayList<>(); + for (SubClusterInfo subClusterInfo : federationState.values()) { + subClusterMetrics.add(new SubClusterState(subClusterInfo)); + } + } + + public List getSubClusterMetrics() { + return subClusterMetrics; + } + +} 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..3a838ea58e3 --- /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,33 @@ +/** + * 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; + +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..e3857caf51a --- /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,33 @@ +/** + * 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; + +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..ff0366d1307 --- /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,33 @@ +/** + * 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; + +public class TestResourceManagersPage { + + @Before + public void setup() { + } + + @Test + public void test() { + } +}