[SPARK-27180][BUILD][YARN] Fix testing issues with yarn module in Hadoop-3

## What changes were proposed in this pull request?

Fix testing issues with `yarn` module in Hadoop-3:

1. Upgrade jersey-1 to `1.19` to fix ```Cause: java.lang.NoClassDefFoundError: com/sun/jersey/spi/container/servlet/ServletContainer```.
2. Copy `ServerSocketUtil` from hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/ServerSocketUtil.java to fix ```java.lang.NoClassDefFoundError: org/apache/hadoop/net/ServerSocketUtil```.
3. Adapte `SessionHandler` from jetty-9.3.25.v20180904/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java  to fix ```java.lang.NoSuchMethodError: org.eclipse.jetty.server.session.SessionHandler.getSessionManager()Lorg/eclipse/jetty/server/SessionManager```.

## How was this patch tested?

manual tests:
```shell
build/sbt yarn/test -Pyarn
build/sbt yarn/test -Phadoop-3.2 -Pyarn

build/mvn -Dtest=none -DwildcardSuites=org.apache.spark.deploy.yarn.YarnClusterSuite -pl resource-managers/yarn test -Pyarn
build/mvn -Dtest=none -DwildcardSuites=org.apache.spark.deploy.yarn.YarnClusterSuite -pl resource-managers/yarn test -Pyarn -Phadoop-3.2
```

Closes #24115 from wangyum/hadoop3-yarn.

Authored-by: Yuming Wang <yumwang@ebay.com>
Signed-off-by: Sean Owen <sean.owen@databricks.com>
This commit is contained in:
Yuming Wang 2019-04-02 15:38:26 -05:00 committed by Sean Owen
parent 57aff93886
commit 13c5c1fb4b
5 changed files with 521 additions and 1 deletions

View file

@ -115,3 +115,5 @@ structured-streaming/*
kafka-source-initial-offset-version-2.1.0.bin
kafka-source-initial-offset-future-version.bin
vote.tmpl
SessionManager.java
SessionHandler.java

View file

@ -29,7 +29,7 @@
<name>Spark Project YARN</name>
<properties>
<sbt.project.name>yarn</sbt.project.name>
<jersey-1.version>1.9</jersey-1.version>
<jersey-1.version>1.19</jersey-1.version>
</properties>
<dependencies>
@ -166,6 +166,12 @@
<scope>test</scope>
<version>${jersey-1.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<scope>test</scope>
<version>${jersey-1.version}</version>
</dependency>
<!-- These dependencies are duplicated from core, because dependencies in the "provided"
scope are not transitive.-->

View file

@ -0,0 +1,132 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.net;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.Random;
/**
* Copied from
* hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/ServerSocketUtil.java
* for Hadoop-3.x testing
*/
public class ServerSocketUtil {
private static final Logger LOG = LoggerFactory.getLogger(ServerSocketUtil.class);
private static Random rand = new Random();
/**
* Port scan & allocate is how most other apps find ports
*
* @param port given port
* @param retries number of retries
* @return
* @throws IOException
*/
public static int getPort(int port, int retries) throws IOException {
int tryPort = port;
int tries = 0;
while (true) {
if (tries > 0 || tryPort == 0) {
tryPort = port + rand.nextInt(65535 - port);
}
if (tryPort == 0) {
continue;
}
try (ServerSocket s = new ServerSocket(tryPort)) {
LOG.info("Using port " + tryPort);
return tryPort;
} catch (IOException e) {
tries++;
if (tries >= retries) {
LOG.info("Port is already in use; giving up");
throw e;
} else {
LOG.info("Port is already in use; trying again");
}
}
}
}
/**
* Check whether port is available or not.
*
* @param port given port
* @return
*/
private static boolean isPortAvailable(int port) {
try (ServerSocket s = new ServerSocket(port)) {
return true;
} catch (IOException e) {
return false;
}
}
/**
* Wait till the port available.
*
* @param port given port
* @param retries number of retries for given port
* @return
* @throws InterruptedException
* @throws IOException
*/
public static int waitForPort(int port, int retries)
throws InterruptedException, IOException {
int tries = 0;
while (true) {
if (isPortAvailable(port)) {
return port;
} else {
tries++;
if (tries >= retries) {
throw new IOException(
"Port is already in use; giving up after " + tries + " times.");
}
Thread.sleep(1000);
}
}
}
/**
* Find the specified number of unique ports available.
* The ports are all closed afterwards,
* so other network services started may grab those same ports.
*
* @param numPorts number of required port nubmers
* @return array of available port numbers
* @throws IOException
*/
public static int[] getPorts(int numPorts) throws IOException {
ServerSocket[] sockets = new ServerSocket[numPorts];
int[] ports = new int[numPorts];
for (int i = 0; i < numPorts; i++) {
ServerSocket sock = new ServerSocket(0);
sockets[i] = sock;
ports[i] = sock.getLocalPort();
}
for (ServerSocket sock : sockets) {
sock.close();
}
return ports;
}
}

View file

@ -0,0 +1,290 @@
//
// ========================================================================
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.server;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.EventListener;
import java.util.Set;
import org.eclipse.jetty.http.HttpCookie;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.util.component.LifeCycle;
/**
* Adapted from https://github.com/eclipse/jetty.project/blob/jetty-9.3.25.v20180904/
* jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java
*/
public interface SessionManager extends LifeCycle {
/**
* Session cookie name.
* Defaults to <code>JSESSIONID</code>, but can be set with the
* <code>org.eclipse.jetty.servlet.SessionCookie</code> context init parameter.
*/
String __SessionCookieProperty = "org.eclipse.jetty.servlet.SessionCookie";
String __DefaultSessionCookie = "JSESSIONID";
/**
* Session id path parameter name.
* Defaults to <code>jsessionid</code>, but can be set with the
* <code>org.eclipse.jetty.servlet.SessionIdPathParameterName</code> context init parameter.
* If set to null or "none" no URL rewriting will be done.
*/
String __SessionIdPathParameterNameProperty =
"org.eclipse.jetty.servlet.SessionIdPathParameterName";
String __DefaultSessionIdPathParameterName = "jsessionid";
String __CheckRemoteSessionEncoding = "org.eclipse.jetty.servlet.CheckingRemoteSessionIdEncoding";
/**
* Session Domain.
* If this property is set as a ServletContext InitParam, then it is
* used as the domain for session cookies. If it is not set, then
* no domain is specified for the session cookie.
*/
String __SessionDomainProperty = "org.eclipse.jetty.servlet.SessionDomain";
String __DefaultSessionDomain = null;
/**
* Session Path.
* If this property is set as a ServletContext InitParam, then it is
* used as the path for the session cookie. If it is not set, then
* the context path is used as the path for the cookie.
*/
String __SessionPathProperty = "org.eclipse.jetty.servlet.SessionPath";
/**
* Session Max Age.
* If this property is set as a ServletContext InitParam, then it is
* used as the max age for the session cookie. If it is not set, then
* a max age of -1 is used.
*/
String __MaxAgeProperty = "org.eclipse.jetty.servlet.MaxAge";
/**
* Returns the <code>HttpSession</code> with the given session id
*
* @param id the session id
* @return the <code>HttpSession</code> with the corresponding id
* or null if no session with the given id exists
*/
HttpSession getHttpSession(String id);
/**
* Creates a new <code>HttpSession</code>.
*
* @param request the HttpServletRequest containing the requested session id
* @return the new <code>HttpSession</code>
*/
HttpSession newHttpSession(HttpServletRequest request);
/**
* @return true if session cookies should be HTTP-only (Microsoft extension)
* @see HttpCookie#isHttpOnly()
*/
boolean getHttpOnly();
/**
* @return the max period of inactivity, after which the session is invalidated, in seconds.
* @see #setMaxInactiveInterval(int)
*/
int getMaxInactiveInterval();
/**
* Sets the max period of inactivity, after which the session is invalidated, in seconds.
*
* @param seconds the max inactivity period, in seconds.
* @see #getMaxInactiveInterval()
*/
void setMaxInactiveInterval(int seconds);
/**
* Sets the {@link SessionHandler}.
*
* @param handler the <code>SessionHandler</code> object
*/
void setSessionHandler(SessionHandler handler);
/**
* Adds an event listener for session-related events.
*
* @param listener the session event listener to add
* Individual SessionManagers implementations may accept arbitrary listener types,
* but they are expected to at least handle HttpSessionActivationListener,
* HttpSessionAttributeListener,
* HttpSessionBindingListener and HttpSessionListener.
* @see #removeEventListener(EventListener)
*/
void addEventListener(EventListener listener);
/**
* Removes an event listener for for session-related events.
*
* @param listener the session event listener to remove
* @see #addEventListener(EventListener)
*/
void removeEventListener(EventListener listener);
/**
* Removes all event listeners for session-related events.
*
* @see #removeEventListener(EventListener)
*/
void clearEventListeners();
/**
* Gets a Cookie for a session.
*
* @param session the session to which the cookie should refer.
* @param contextPath the context to which the cookie should be linked.
* The client will only send the cookie value when
* requesting resources under this path.
* @param requestIsSecure whether the client is accessing the server over
* a secure protocol (i.e. HTTPS).
* @return if this <code>SessionManager</code> uses cookies, then this method will return a new
* {@link Cookie cookie object} that should be set on the client
* in order to link future HTTP requests
* with the <code>session</code>. If cookies are not in use,
* this method returns <code>null</code>.
*/
HttpCookie getSessionCookie(HttpSession session, String contextPath, boolean requestIsSecure);
/**
* @return the cross context session id manager.
* @see #setSessionIdManager(SessionIdManager)
*/
SessionIdManager getSessionIdManager();
/**
* @return the cross context session id manager.
* @deprecated use {@link #getSessionIdManager()}
*/
@Deprecated
SessionIdManager getMetaManager();
/**
* Sets the cross context session id manager
*
* @param idManager the cross context session id manager.
* @see #getSessionIdManager()
*/
void setSessionIdManager(SessionIdManager idManager);
/**
* @param session the session to test for validity
* @return whether the given session is valid, that is, it has not been invalidated.
*/
boolean isValid(HttpSession session);
/**
* @param session the session object
* @return the unique id of the session within the cluster, extended with an optional node id.
* @see #getClusterId(HttpSession)
*/
String getNodeId(HttpSession session);
/**
* @param session the session object
* @return the unique id of the session within the cluster (without a node id extension)
* @see #getNodeId(HttpSession)
*/
String getClusterId(HttpSession session);
/**
* Called by the {@link SessionHandler} when a session is first accessed by a request.
*
* @param session the session object
* @param secure whether the request is secure or not
* @return the session cookie. If not null,
* this cookie should be set on the response to either migrate
* the session or to refresh a session cookie that may expire.
* @see #complete(HttpSession)
*/
HttpCookie access(HttpSession session, boolean secure);
/**
* Called by the {@link SessionHandler} when a session is last accessed by a request.
*
* @param session the session object
* @see #access(HttpSession, boolean)
*/
void complete(HttpSession session);
/**
* Sets the session id URL path parameter name.
*
* @param parameterName the URL path parameter name
* for session id URL rewriting (null or "none" for no rewriting).
* @see #getSessionIdPathParameterName()
* @see #getSessionIdPathParameterNamePrefix()
*/
void setSessionIdPathParameterName(String parameterName);
/**
* @return the URL path parameter name for session id URL rewriting, by default "jsessionid".
* @see #setSessionIdPathParameterName(String)
*/
String getSessionIdPathParameterName();
/**
* @return a formatted version of {@link #getSessionIdPathParameterName()}, by default
* ";" + sessionIdParameterName + "=", for easier lookup in URL strings.
* @see #getSessionIdPathParameterName()
*/
String getSessionIdPathParameterNamePrefix();
/**
* @return whether the session management is handled via cookies.
*/
boolean isUsingCookies();
/**
* @return whether the session management is handled via URLs.
*/
boolean isUsingURLs();
Set<SessionTrackingMode> getDefaultSessionTrackingModes();
Set<SessionTrackingMode> getEffectiveSessionTrackingModes();
void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes);
SessionCookieConfig getSessionCookieConfig();
/**
* @return True if absolute URLs are check for remoteness before being session encoded.
*/
boolean isCheckingRemoteSessionIdEncoding();
/**
* @param remote True if absolute URLs are check for remoteness before being session encoded.
*/
void setCheckingRemoteSessionIdEncoding(boolean remote);
/** Change the existing session id.
*
* @param oldClusterId the old cluster id
* @param oldNodeId the old node id
* @param newClusterId the new cluster id
* @param newNodeId the new node id
*/
void renewSessionId(String oldClusterId, String oldNodeId, String newClusterId, String newNodeId);
}

View file

@ -0,0 +1,90 @@
//
// ========================================================================
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.server.session;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.handler.ScopedHandler;
/**
* Adapted from https://github.com/eclipse/jetty.project/blob/jetty-9.3.25.v20180904/
* jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java
*/
public class SessionHandler extends ScopedHandler {
private SessionManager _sessionManager;
public SessionHandler() {
}
/**
* @param manager
* The session manager
*/
public SessionHandler(SessionManager manager) {
setSessionManager(manager);
}
/**
* @return Returns the sessionManager.
*/
public SessionManager getSessionManager() {
return _sessionManager;
}
/**
* @param sessionManager
* The sessionManager to set.
*/
public void setSessionManager(SessionManager sessionManager) {
if (isStarted()) {
throw new IllegalStateException();
}
if (sessionManager != null) {
updateBean(_sessionManager,sessionManager);
_sessionManager=sessionManager;
}
}
/*
* @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse, int)
*/
@Override
public void doHandle(String target, Request baseRequest, HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
// start manual inline of nextHandle(target,baseRequest,request,response);
if (_nextScope != null && _nextScope == _handler) {
_nextScope.doHandle(target,baseRequest,request,response);
} else if (_handler != null) {
_handler.handle(target,baseRequest,request,response);
// end manual inline
}
}
public void clearEventListeners() {
if (_sessionManager != null) {
_sessionManager.clearEventListeners();
}
}
}