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 121e5344fdb..bcc339889f3 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 @@ -29,6 +29,7 @@ import org.apache.hadoop.yarn.YarnUncaughtExceptionHandler; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; +import org.apache.hadoop.yarn.server.federation.utils.FederationStateStoreFacade; import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWebAppUtil; import org.apache.hadoop.yarn.server.router.clientrm.RouterClientRMService; import org.apache.hadoop.yarn.server.router.rmadmin.RouterRMAdminService; @@ -65,6 +66,7 @@ private AtomicBoolean isStopping = new AtomicBoolean(false); private RouterClientRMService clientRMProxyService; private RouterRMAdminService rmAdminProxyService; + private RouterContext routerContext; private WebApp webApp; @VisibleForTesting protected String webAppAddress; @@ -76,6 +78,7 @@ public Router() { super(Router.class.getName()); + routerContext = new RouterContextImpl(); } protected void doSecureLogin() throws IOException { @@ -85,6 +88,7 @@ protected void doSecureLogin() throws IOException { @Override protected void serviceInit(Configuration config) throws Exception { this.conf = config; + routerContext.setFacade(FederationStateStoreFacade.getInstance()); // ClientRM Proxy clientRMProxyService = createClientRMProxyService(); addService(clientRMProxyService); @@ -142,6 +146,10 @@ public WebApp getWebapp() { return this.webApp; } + public FederationStateStoreFacade getFederationFacade() { + return routerContext.getFacade(); + } + @VisibleForTesting public void startWepApp() { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/RouterContext.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/RouterContext.java new file mode 100644 index 00000000000..23ed3a7cb77 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/RouterContext.java @@ -0,0 +1,28 @@ +/** + * 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; + +import org.apache.hadoop.yarn.server.federation.utils.FederationStateStoreFacade; + +public interface RouterContext { + + FederationStateStoreFacade getFacade(); + + void setFacade(FederationStateStoreFacade facade); +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/RouterContextImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/RouterContextImpl.java new file mode 100644 index 00000000000..6f155c6ec69 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/RouterContextImpl.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; + +import org.apache.hadoop.yarn.server.federation.utils.FederationStateStoreFacade; + +public class RouterContextImpl implements RouterContext { + + private FederationStateStoreFacade facade; + + @Override + public FederationStateStoreFacade getFacade() { + return facade; + } + + @Override + public void setFacade(FederationStateStoreFacade facade) { + this.facade = facade; + } +} \ 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/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..394848fdc50 --- /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,40 @@ +/** +* 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; + +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..7ca87da0330 --- /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,34 @@ +/** +* 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; + +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..dbfdfc191db --- /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,188 @@ +/** + * 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.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; + +class AppsBlock extends HtmlBlock { + final Router router; + + /** Application id -> SubClusters */ + private Map> appsToSubcluster; + 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 + Map infos = + router.getFederationFacade().getSubClusters(true); + for (SubClusterInfo info : infos.values()) { + try { + // Get the applications for this SubCluster + AppsInfo rmApps = RouterUtil.invokeRMWebService(router.getConfig(), + info.getRMWebServiceAddress(), "apps", AppsInfo.class); + if (rmApps != null) { + for (AppInfo rmApp : rmApps.getApps()) { + apps.add(rmApp); + } + } + + // Get link to the SubCluster + StringBuilder sb = new StringBuilder(); + sb.append("").append(info.getSubClusterId()).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..9524800bfc0 --- /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,42 @@ +/** +* 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; + +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..9bad2127d95 --- /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,144 @@ +/** + * 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.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; + +class NodesBlock extends HtmlBlock { + 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 { + Map infos = + router.getFederationFacade().getSubClusters(true); + for (SubClusterInfo info : infos.values()) { + try { + NodesInfo rmNodes = (NodesInfo) RouterUtil.invokeRMWebService( + router.getConfig(), info.getRMWebServiceAddress(), "nodes", + NodesInfo.class); + 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 {}: {}", + info.getRMWebServiceAddress(), 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..b288322084a --- /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,96 @@ +/** + * 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 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 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(); + + Map subClustersInfo; + + try { + subClustersInfo = router.getFederationFacade().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 + tbody.tr().td() + .a("//" + webAppAddress, subClusterState.getSubClusterId()).__() + .td("" + scm.getAppsSubmitted()).td("" + scm.getAppsRunning()) + .td("" + scm.getAppsCompleted()).td("" + scm.getAppsFailed()) + .td("" + scm.getAppsKilled()).td("" + scm.getContainersAllocated()) + .td("" + scm.getActiveNodes()) + .__(); + } + + } catch (Exception e) { + LOG.error("Cannot render resource managers", 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..8e548b36b4f --- /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,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 org.apache.hadoop.yarn.webapp.Controller; + +import com.google.inject.Inject; + +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/RouterUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterUtil.java new file mode 100644 index 00000000000..de92c9c26ed --- /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/RouterUtil.java @@ -0,0 +1,79 @@ +/** + * 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 javax.ws.rs.core.MediaType; + +import org.apache.hadoop.classification.InterfaceAudience.Public; +import org.apache.hadoop.classification.InterfaceStability.Unstable; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.yarn.webapp.util.WebAppUtils; +import org.slf4j.*; + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; + +@Public +@Unstable +public class RouterUtil { + + public static final Logger LOG = LoggerFactory.getLogger(RouterUtil.class); + + /** + * Performs an invocation of the the remote RMWebService. It does not throw in + * case of any communication failure. + * @param conf + * @param webApp + * @param path + * @param returnType + * @return + */ + public static T invokeRMWebServiceNoThrow(Configuration conf, + String webApp, String path, final Class returnType) { + try { + return invokeRMWebService(conf, webApp, path, returnType); + } catch (Exception e) { + LOG.error("Cannot invoke RM web request", e); + return null; + } + } + + /** + * Performs an invocation of the the remote RMWebService. + * @param conf + * @param webApp + * @param path + * @param returnType + * @return + */ + public static T invokeRMWebService(Configuration conf, String webApp, + String path, final Class returnType) { + Client client = Client.create(); + T obj = null; + + // It is needed for the new HTTP_POLICY because we enable 2 listeners + WebResource webResource = client.resource(WebAppUtils.HTTP_PREFIX + webApp); + ClientResponse response = webResource.path("ws/v1/cluster").path(path) + .accept(MediaType.APPLICATION_XML).get(ClientResponse.class); + if (response.getStatus() == 200) { + obj = response.getEntity(returnType); + } + return obj; + } +} 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..60569f66382 --- /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,51 @@ +/** +* 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.*; + +public class RouterView extends TwoColumnLayout { + static final int MAX_DISPLAY_ROWS = 100; // direct table rendering + static final int MAX_FAST_ROWS = 1000; // inline js array + + @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/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..b5589f63d34 --- /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,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.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; + +@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); + } + +} 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..13c36271eb9 --- /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,91 @@ +/** + * 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.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; + +@XmlRootElement(name = "subClusterState") +@XmlAccessorType(XmlAccessType.FIELD) +public class SubClusterState { + + protected String subClusterId; + protected String clientRMAddress; + protected String state; + protected ClusterMetricsInfo clusterMetrics; + protected String webAppAddress; + + public SubClusterState() { + } // JAXB needs this + + public SubClusterState(String subClusterId, String clientRMAddress, + String webAppAddress, String state, ClusterMetricsInfo clusterMetrics) { + + this.subClusterId = subClusterId; + this.clientRMAddress = clientRMAddress; + this.state = state; + this.clusterMetrics = clusterMetrics; + this.webAppAddress = webAppAddress; + } + + public SubClusterState(SubClusterInfo subClusterInfo) throws JAXBException { + this.subClusterId = subClusterInfo.getSubClusterId().toString(); + this.clientRMAddress = subClusterInfo.getClientRMServiceAddress(); + this.state = subClusterInfo.getState().toString(); + 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); + this.webAppAddress = subClusterInfo.getRMWebServiceAddress(); + } + + public String getSubClusterId() { + return subClusterId; + } + + 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..c7bf88fca4c --- /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,59 @@ +/** + * 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; + +@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; + } + +}