YARN-4990. Re-direction of a particular log file within in a container in NM UI does not redirect properly. Contributed by Xuan Gong.

(cherry picked from commit 736f54b727)
This commit is contained in:
Junping Du 2016-12-21 14:14:42 -08:00 committed by Jason Lowe
parent 2adce1b361
commit 689d19575f
2 changed files with 184 additions and 0 deletions

View File

@ -79,6 +79,10 @@ public class NMWebAppFilter extends GuiceContainer{
String[] parts = uri.split("/"); String[] parts = uri.split("/");
String containerIdStr = parts[3]; String containerIdStr = parts[3];
String appOwner = parts[4]; String appOwner = parts[4];
String logType = null;
if (parts.length > 5) {
logType = parts[5];
}
if (containerIdStr != null && !containerIdStr.isEmpty()) { if (containerIdStr != null && !containerIdStr.isEmpty()) {
ContainerId containerId = null; ContainerId containerId = null;
try { try {
@ -106,6 +110,10 @@ public class NMWebAppFilter extends GuiceContainer{
sb.append(containerIdStr); sb.append(containerIdStr);
sb.append("/"); sb.append("/");
sb.append(appOwner); sb.append(appOwner);
if (logType != null && !logType.isEmpty()) {
sb.append("/");
sb.append(logType);
}
redirectPath = redirectPath =
WebAppUtils.appendQueryParams(request, sb.toString()); WebAppUtils.appendQueryParams(request, sb.toString());
} else { } else {

View File

@ -0,0 +1,176 @@
/**
* 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.google.inject.Injector;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.api.records.ContainerId;
import org.apache.hadoop.yarn.api.records.NodeId;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.server.nodemanager.LocalDirsHandlerService;
import org.apache.hadoop.yarn.server.nodemanager.NodeManager.NMContext;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.application.Application;
import org.glassfish.grizzly.servlet.HttpServletResponseImpl;
import org.junit.Test;
/**
* Basic sanity Tests for NMWebFilter.
*
*/
public class TestNMWebFilter {
private static final String LOG_SERVER_URI = "log-server:1999/logs";
private static final String USER = "testUser";
@Test(timeout = 5000)
public void testRedirection() throws Exception {
ApplicationId appId = ApplicationId.newInstance(
System.currentTimeMillis(), 1);
ApplicationAttemptId attemptId = ApplicationAttemptId.newInstance(
appId, 1);
ContainerId containerId = ContainerId.newContainerId(attemptId, 1);
NMContext mockNMContext = mock(NMContext.class);
ConcurrentMap<ApplicationId, Application> applications
= new ConcurrentHashMap<>();
when(mockNMContext.getApplications()).thenReturn(applications);
LocalDirsHandlerService mockLocalDirsHandlerService = mock(
LocalDirsHandlerService.class);
Configuration conf = new Configuration();
conf.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
conf.set(YarnConfiguration.YARN_LOG_SERVER_URL,
"http://" + LOG_SERVER_URI);
when(mockLocalDirsHandlerService.getConfig()).thenReturn(conf);
when(mockNMContext.getLocalDirsHandler()).thenReturn(
mockLocalDirsHandlerService);
NodeId nodeId = NodeId.newInstance("testNM", 9999);
when(mockNMContext.getNodeId()).thenReturn(nodeId);
Injector mockInjector = mock(Injector.class);
NMWebAppFilter testFilter = new NMWebAppFilter(
mockInjector, mockNMContext);
HttpServletResponseForTest response = new HttpServletResponseForTest();
// dummy filter
FilterChain chain = new FilterChain() {
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse) throws IOException,
ServletException {
// Do Nothing
}
};
String uri = "testNM:8042/node/containerlogs/"
+ containerId.toString() + "/" + USER;
HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getRequestURI()).thenReturn(uri);
testFilter.doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_TEMPORARY_REDIRECT, response.status);
String redirect = response.getHeader("Location");
assertTrue(redirect.contains(LOG_SERVER_URI));
assertTrue(redirect.contains(nodeId.toString()));
assertTrue(redirect.contains(containerId.toString()));
assertTrue(redirect.contains(USER));
String logType = "syslog";
uri = "testNM:8042/node/containerlogs/" + containerId.toString()
+ "/" + USER + "/" + logType + "/?start=10";
HttpServletRequest request2 = mock(HttpServletRequest.class);
when(request2.getRequestURI()).thenReturn(uri);
when(request2.getQueryString()).thenReturn("start=10");
testFilter.doFilter(request2, response, chain);
assertEquals(HttpServletResponse.SC_TEMPORARY_REDIRECT, response.status);
redirect = response.getHeader("Location");
assertTrue(redirect.contains(LOG_SERVER_URI));
assertTrue(redirect.contains(nodeId.toString()));
assertTrue(redirect.contains(containerId.toString()));
assertTrue(redirect.contains(USER));
assertTrue(redirect.contains(logType));
assertTrue(redirect.contains("start=10"));
}
private class HttpServletResponseForTest extends HttpServletResponseImpl {
String redirectLocation = "";
int status;
private String contentType;
private final Map<String, String> headers = new HashMap<>(1);
private StringWriter body;
public String getRedirect() {
return redirectLocation;
}
@Override
public void sendRedirect(String location) throws IOException {
redirectLocation = location;
}
@Override
public String encodeRedirectURL(String url) {
return url;
}
@Override
public void setStatus(int status) {
this.status = status;
}
@Override
public void setContentType(String type) {
this.contentType = type;
}
@Override
public void setHeader(String name, String value) {
headers.put(name, value);
}
public String getHeader(String name) {
return headers.get(name);
}
@Override
public PrintWriter getWriter() throws IOException {
body = new StringWriter();
return new PrintWriter(body);
}
}
}