Skip to content

Commit

Permalink
Merge pull request #51 from ndeloof/JENKINS-21746
Browse files Browse the repository at this point in the history
introduce TcpSocketHostLocator extension point
  • Loading branch information
ndeloof committed Aug 18, 2015
2 parents a598af0 + fde3de7 commit 1439cda
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 12 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -43,7 +43,7 @@ THE SOFTWARE.
<url>http://wiki.jenkins-ci.org/display/JENKINS/Maven+Project+Plugin</url>

<properties>
<mavenInterceptorsVersion>1.6</mavenInterceptorsVersion>
<mavenInterceptorsVersion>1.7</mavenInterceptorsVersion>
<mavenVersion>3.1.0</mavenVersion>
<maven.version>${mavenVersion}</maven.version>
<aetherVersion>0.9.0.M3</aetherVersion>
Expand Down
49 changes: 38 additions & 11 deletions src/main/java/hudson/maven/AbstractMavenProcessFactory.java
Expand Up @@ -4,6 +4,7 @@

import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.Platform;
Expand Down Expand Up @@ -36,9 +37,11 @@
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Arrays;
Expand Down Expand Up @@ -138,7 +141,7 @@ public abstract class AbstractMavenProcessFactory
* and buffer data on the master. What we need to avoid here is to have channel input stream be a
* {@link RemoteInputStream}, as it'll turn every read into a remote read that has a large latency.
*/
private static final class Connection implements Serializable {
static final class Connection implements Serializable {
// these two fields are non-null when Connection is in memory
public InputStream in;
public OutputStream out;
Expand Down Expand Up @@ -180,7 +183,8 @@ private Object readResolve() {

interface Acceptor {
Connection accept() throws IOException;
int getPort();

int getPort() throws UnknownHostException;
}

/**
Expand Down Expand Up @@ -216,6 +220,7 @@ public Connection accept() throws IOException {
return new Connection(socket);
}

@Override
public int getPort() {
return serverSocket.getLocalPort();
}
Expand Down Expand Up @@ -255,14 +260,23 @@ public ProcessCache.NewProcess newProcess(BuildListener listener, OutputStream o

MavenConsoleAnnotator mca = new MavenConsoleAnnotator(out,charset);

if ( mavenRemoteUseInet ) {
envVars.put(MAVEN_REMOTE_USEINET_ENV_VAR_NAME , "true" );
}
JDK jdk = getJava(listener);
JDK originalJdk = null;
JDK: while (true) {
final Acceptor acceptor = launcher.getChannel().call(new SocketHandler());
final ArgumentListBuilder cmdLine = buildMavenAgentCmdLine(listener, acceptor.getPort(), jdk);

String hostName = null;
for (TcpSocketHostLocator locator : TcpSocketHostLocator.all()) {
hostName = locator.getTcpSocketHost();
if (hostName != null) break;
}

final String socket = hostName != null ?
hostName + ":" + acceptor.getPort() :
String.valueOf(acceptor.getPort());
listener.getLogger().println("Established TCP socket on "+ socket);

final ArgumentListBuilder cmdLine = buildMavenAgentCmdLine(listener, socket, jdk);
String[] cmds = cmdLine.toCommandArray();
final Proc proc = launcher.launch().cmds(cmds).envs(envVars).stdout(mca).pwd(workDir).start();

Expand Down Expand Up @@ -356,11 +370,11 @@ private static final class FindJavaHome extends MasterToSlaveCallable<JDK,Error>
/**
* Builds the command line argument list to launch the maven process.
*/
protected ArgumentListBuilder buildMavenAgentCmdLine(BuildListener listener,int tcpPort) throws IOException, InterruptedException {
return buildMavenAgentCmdLine(listener, tcpPort, getJava(listener));
protected ArgumentListBuilder buildMavenAgentCmdLine(BuildListener listener, String tcpSocket) throws IOException, InterruptedException {
return buildMavenAgentCmdLine(listener, tcpSocket, getJava(listener));
}

private ArgumentListBuilder buildMavenAgentCmdLine(BuildListener listener, int tcpPort, JDK jdk) throws IOException, InterruptedException {
private ArgumentListBuilder buildMavenAgentCmdLine(BuildListener listener, String tcpSocket, JDK jdk) throws IOException, InterruptedException {
MavenInstallation mvn = getMavenInstallation(listener);
if(mvn==null) {
listener.error("Maven version is not configured for this project. Can't determine which Maven to run");
Expand Down Expand Up @@ -416,8 +430,8 @@ private ArgumentListBuilder buildMavenAgentCmdLine(BuildListener listener, int t
args.add( mavenInterceptorCommonClasspath );
}

// TCP/IP port to establish the remoting infrastructure
args.add(tcpPort);
// TCP/IP socket to establish the remoting infrastructure
args.add(tcpSocket);

String interceptorOverride = getMavenInterceptorOverride(mvn, slaveRoot, listener);
if (interceptorOverride!=null) {
Expand Down Expand Up @@ -601,6 +615,19 @@ protected EnvVars getEnvVars() {
public static boolean mavenRemoteUseInet = Boolean.getBoolean("maven.remote.useinet");

public static final String MAVEN_REMOTE_USEINET_ENV_VAR_NAME = "MAVEN_REMOTE_USEINET";

@Extension(ordinal=0)
public static class UserInetTcpSocketHostLocator extends TcpSocketHostLocator {

@Override
public String getTcpSocketHost() throws IOException {
if (mavenRemoteUseInet) {
InetAddress host = InetAddress.getLocalHost();
return host.getHostName();
}
return null;
}
}

/**
* If true, launch Maven with YJP offline profiler agent.
Expand Down
34 changes: 34 additions & 0 deletions src/main/java/hudson/maven/TcpSocketHostLocator.java
@@ -0,0 +1,34 @@
package hudson.maven;

import hudson.ExtensionList;
import hudson.ExtensionPoint;
import jenkins.model.Jenkins;

import javax.annotation.CheckForNull;
import java.io.IOException;
import java.util.List;

/**
* Identify the Host name to use from maven-agent to connect to to jenkins slave agent TCP socket.
* <p>
* In simple scenarios both slave agent and maven process do live on same host without specific network
* constraints, but for some virtualization usages maven process just can't bind a socket on wildcard
* host network. This extension give infrastructure plugins a chance to configure the adequate hostname.
* to handle such network constraints
*
* @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
*/
public abstract class TcpSocketHostLocator implements ExtensionPoint {

/**
* Try to identify the slave agent TCP socket host name or IP.
* @return <code>null</code> if not found or does not apply to this specific implementation
* @throws IOException
*/
public abstract @CheckForNull String getTcpSocketHost() throws IOException;

public static List<TcpSocketHostLocator> all() {
return ExtensionList.lookup(TcpSocketHostLocator.class);
}

}

0 comments on commit 1439cda

Please sign in to comment.