All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.remoting.Launcher Maven / Gradle / Ivy

Go to download

Contains the bootstrap code to bridge separate JVMs into a single semi-shared space. Reusable outside Hudson.

There is a newer version: 3.0.3
Show newest version
/*******************************************************************************
 *
 * Copyright (c) 2004-2010 Oracle Corporation.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors: 
 *
 *    Kohsuke Kawaguchi
 *     
 *
 *******************************************************************************/ 

package hudson.remoting;

import hudson.remoting.Channel.Mode;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.CmdLineException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.TrustManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.File;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLClassLoader;
import java.net.InetSocketAddress;
import java.net.HttpURLConnection;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.NoSuchAlgorithmException;
import java.security.KeyManagementException;
import java.security.SecureRandom;
import java.util.Properties;
import org.apache.commons.codec.binary.Base64;

/**
 * Entry point for running a {@link Channel}. This is the main method of the slave JVM.
 *
 * 

* This class also defines several methods for * starting a channel on a fresh JVM. * * @author Kohsuke Kawaguchi */ public class Launcher { public Mode mode = Mode.BINARY; // no-op, but left for backward compatibility @Option(name="-ping") public boolean ping = true; @Option(name="-text",usage="encode communication with the master with base64. " + "Useful for running slave over 8-bit unsafe protocol like telnet") public void setTextMode(boolean b) { mode = b?Mode.TEXT:Mode.BINARY; System.out.println("Running in "+mode.name().toLowerCase(Locale.ENGLISH)+" mode"); } @Option(name="-jnlpUrl",usage="instead of talking to the master via stdin/stdout, " + "emulate a JNLP client by making a TCP connection to the master. " + "Connection parameters are obtained by parsing the JNLP file.") public URL slaveJnlpURL = null; @Option(name="-jnlpCredentials",metaVar="USER:PASSWORD",usage="HTTP BASIC AUTH header to pass in for making HTTP requests.") public String slaveJnlpCredentials = null; @Option(name="-cp",aliases="-classpath",metaVar="PATH", usage="add the given classpath elements to the system classloader.") public void addClasspath(String pathList) throws Exception { Method $addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); $addURL.setAccessible(true); for(String token : pathList.split(File.pathSeparator)) $addURL.invoke(ClassLoader.getSystemClassLoader(),new File(token).toURI().toURL()); // fix up the system.class.path to pretend that those jar files // are given through CLASSPATH or something. // some tools like JAX-WS RI and Hadoop relies on this. System.setProperty("java.class.path",System.getProperty("java.class.path")+File.pathSeparatorChar+pathList); } @Option(name="-tcp",usage="instead of talking to the master via stdin/stdout, " + "listens to a random local port, write that port number to the given file, " + "then wait for the master to connect to that port.") public File tcpPortFile=null; @Option(name="-auth",metaVar="user:pass",usage="If your Hudson is security-enabeld, specify a valid user name and password.") public String auth = null; public InetSocketAddress connectionTarget = null; @Option(name="-connectTo",usage="make a TCP connection to the given host and port, then start communication.",metaVar="HOST:PORT") public void setConnectTo(String target) { String[] tokens = target.split(":"); if(tokens.length!=2) { System.err.println("Illegal parameter: "+target); System.exit(1); } connectionTarget = new InetSocketAddress(tokens[0],Integer.valueOf(tokens[1])); } /** * Bypass HTTPS security check by using free-for-all trust manager. * * @param _ * This is ignored. */ @Option(name="-noCertificateCheck") public void setNoCertificateCheck(boolean _) throws NoSuchAlgorithmException, KeyManagementException { System.out.println("Skipping HTTPS certificate checks altoghether. Note that this is not secure at all."); SSLContext context = SSLContext.getInstance("TLS"); context.init(null, new TrustManager[]{new NoCheckTrustManager()}, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); // bypass host name check, too. HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { public boolean verify(String s, SSLSession sslSession) { return true; } }); } public static void main(String... args) throws Exception { Launcher launcher = new Launcher(); CmdLineParser parser = new CmdLineParser(launcher); try { parser.parseArgument(args); launcher.run(); } catch (CmdLineException e) { System.err.println(e.getMessage()); System.err.println("java -jar slave.jar [options...]"); parser.printUsage(System.err); System.err.println(); } } public void run() throws Exception { if(auth!=null) { final int idx = auth.indexOf(':'); if(idx<0) throw new CmdLineException(null, "No ':' in the -auth option"); Authenticator.setDefault(new Authenticator() { @Override public PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(auth.substring(0,idx), auth.substring(idx+1).toCharArray()); } }); } if(connectionTarget!=null) { runAsTcpClient(); System.exit(0); } else if(slaveJnlpURL!=null) { List jnlpArgs = parseJnlpArguments(); try { hudson.remoting.jnlp.Main._main(jnlpArgs.toArray(new String[jnlpArgs.size()])); } catch (CmdLineException e) { System.err.println("JNLP file "+slaveJnlpURL+" has invalid arguments: "+jnlpArgs); System.err.println("Most likely a configuration error in the master"); System.err.println(e.getMessage()); System.exit(1); } } else if(tcpPortFile!=null) { runAsTcpServer(); System.exit(0); } else { runWithStdinStdout(); System.exit(0); } } /** * Parses the connection arguments from JNLP file given in the URL. */ public List parseJnlpArguments() throws ParserConfigurationException, SAXException, IOException, InterruptedException { while (true) { try { URLConnection con = slaveJnlpURL.openConnection(); if (con instanceof HttpURLConnection && slaveJnlpCredentials != null) { HttpURLConnection http = (HttpURLConnection) con; String userPassword = slaveJnlpCredentials; String encoding = new String(Base64.encodeBase64(userPassword.getBytes())); http.setRequestProperty("Authorization", "Basic " + encoding); } con.connect(); if (con instanceof HttpURLConnection) { HttpURLConnection http = (HttpURLConnection) con; if(http.getResponseCode()>=400) // got the error code. report that (such as 401) throw new IOException("Failed to load "+slaveJnlpURL+": "+http.getResponseCode()+" "+http.getResponseMessage()); } Document dom; // check if this URL points to a .jnlp file String contentType = con.getHeaderField("Content-Type"); if(contentType==null || !contentType.startsWith("application/x-java-jnlp-file")) { // load DOM anyway, but if it fails to parse, that's probably because this is not an XML file to begin with. try { dom = loadDom(slaveJnlpURL, con); } catch (SAXException e) { throw new IOException(slaveJnlpURL+" doesn't look like a JNLP file; content type was "+contentType); } catch (IOException e) { throw new IOException(slaveJnlpURL+" doesn't look like a JNLP file; content type was "+contentType); } } else { dom = loadDom(slaveJnlpURL, con); } // exec into the JNLP launcher, to fetch the connection parameter through JNLP. NodeList argElements = dom.getElementsByTagName("argument"); List jnlpArgs = new ArrayList(); for( int i=0; i 0 && interval > 0) { new PingThread(channel, timeout, interval) { @Override protected void onDead() { System.err.println("Ping failed. Terminating"); System.exit(-1); } }.start(); } channel.join(); System.err.println("channel stopped"); } /** * {@link X509TrustManager} that performs no check at all. */ private static class NoCheckTrustManager implements X509TrustManager { public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { } public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } } public static boolean isWindows() { return File.pathSeparatorChar==';'; } private static String computeVersion() { Properties props = new Properties(); try { InputStream is = Launcher.class.getResourceAsStream("hudson-version.properties"); if(is!=null) props.load(is); } catch (IOException e) { e.printStackTrace(); } return props.getProperty("version", "?"); } /** * Version number of Hudson this slave.jar is from. */ public static final String VERSION = computeVersion(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy