diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebAppFilter.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebAppFilter.java index d2f5849f32..797349980b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebAppFilter.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebAppFilter.java @@ -76,9 +76,14 @@ private String containerLogPageRedirectPath(HttpServletRequest request) { String uri = HtmlQuoting.quoteHtmlChars(request.getRequestURI()); String redirectPath = null; if (!uri.contains("/ws/v1/node") && uri.contains("/containerlogs")) { - String[] parts = uri.split("/"); + String[] parts = uri.split("/", 6); String containerIdStr = parts[3]; String appOwner = parts[4]; + StringBuilder uriEnd = new StringBuilder(); + // Append the rest of the string + if(parts.length > 5 && parts[5] != null) { + uriEnd.append(parts[5]); + } if (containerIdStr != null && !containerIdStr.isEmpty()) { ContainerId containerId = null; try { @@ -106,6 +111,8 @@ private String containerLogPageRedirectPath(HttpServletRequest request) { sb.append(containerIdStr); sb.append("/"); sb.append(appOwner); + sb.append("/"); + sb.append(uriEnd); redirectPath = WebAppUtils.appendQueryParams(request, sb.toString()); } else { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/webapp/TestNMWebAppFilter.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/webapp/TestNMWebAppFilter.java new file mode 100644 index 0000000000..f7c7a02ad4 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/webapp/TestNMWebAppFilter.java @@ -0,0 +1,108 @@ +/** + * 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.nodemanager.webapp; + +import com.google.inject.Injector; +import org.apache.hadoop.yarn.api.records.ApplicationId; +import org.apache.hadoop.yarn.api.records.NodeId; +import org.apache.hadoop.yarn.api.records.impl.pb.NodeIdPBImpl; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.server.nodemanager.Context; +import org.apache.hadoop.yarn.server.nodemanager.LocalDirsHandlerService; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.application.Application; +import org.glassfish.grizzly.servlet.HttpServletRequestImpl; +import org.glassfish.grizzly.servlet.HttpServletResponseImpl; +import org.junit.Test; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Tests the NMWebAppFilter's ability to do correct URL redirection. + */ +public class TestNMWebAppFilter { + private static final String URL = "foo.bar.com:1234/node/containerlogs/" + + "container_e01_1234567891011_1234567_01_000000/hadoop/" + + "syslog_attempt_1234567891011_1234567_1_00_000000_0/" + + "hadoop?user.name=hadoop"; + private static final String LOG_SERVER = "a.b.c.com:5678"; + private static final String NODE_STRING = "node123"; + + /** + * Mocked out test to verify that the redirected URL is constructed correctly. + * + * @throws IOException + * @throws ServletException + */ + @Test + public void testContainerLogPageRedirectPath() throws IOException, + ServletException { + YarnConfiguration nmConf = new YarnConfiguration(); + nmConf.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true); + nmConf.set(YarnConfiguration.YARN_LOG_SERVER_URL, LOG_SERVER); + + HttpServletResponseImpl response = mock(HttpServletResponseImpl.class); + HttpServletRequestImpl request = mock(HttpServletRequestImpl.class); + Injector injector = mock(Injector.class); + Context nmContext = mock(Context.class); + FilterChain chain = mock(FilterChain.class); + PrintWriter pw = mock(PrintWriter.class); + LocalDirsHandlerService handler = mock(LocalDirsHandlerService.class); + NodeId nodeId = mock(NodeIdPBImpl.class); + + ConcurrentMap apps = new + ConcurrentHashMap(); + StringBuffer sb = new StringBuffer(URL); + + when(response.getWriter()).thenReturn(pw); + when(request.getRequestURI()).thenReturn(URL); + when(request.getRequestURL()).thenReturn(sb); + when(nmContext.getApplications()).thenReturn(apps); + when(nmContext.getLocalDirsHandler()).thenReturn(handler); + when(nmContext.getNodeId()).thenReturn(nodeId); + when(handler.getConfig()).thenReturn(nmConf); + when(nodeId.toString()).thenReturn(NODE_STRING); + + NMWebAppFilter nmWebAppFilter = new NMWebAppFilter(injector, nmContext); + nmWebAppFilter.doFilter(request, response, chain); + + String[] parts = URL.split("/", 6); + String containerIdStr = parts[3]; + String appOwner = parts[4]; + String uriEnd = parts[5]; + String path = LOG_SERVER + "/" + NODE_STRING + "/" + + containerIdStr + "/" + containerIdStr + "/" + appOwner + "/" + uriEnd; + + verify(response).setHeader(eq("Location"), eq(path)); + verify(response).setStatus(eq(HttpServletResponse.SC_TEMPORARY_REDIRECT)); + } + +} \ No newline at end of file