package com.intuit.tank.jenkins.proxy;
/*
* #%L
* Intuit Tank Jenkins Plugin
* %%
* Copyright (C) 2011 - 2015 Intuit Inc.
* %%
* 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
* #L%
*/
import hudson.FilePath;
import java.io.PrintStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.intuit.tank.jenkins.callables.ProxyRequest;
import com.intuit.tank.jenkins.exceptions.TankJenkinsPluginException;
import com.intuit.tank.jenkins.printer.LogPrinter;
import com.intuit.tank.jenkins.publisher.ProxyPlugin.ProxyPluginDescriptor;
/**
* Jobs are sent to remote machines which have their own classloader. Generally
* because our proxy uses Streams and anonymous inner classes to function, we
* can't serialize the proxy and send it by wire to our remote machines. This
* singleton factory resides on each slave and exists solely to instantiate
* proxies, and ensure uniqueness by mapping a proxy to the port that it's being
* assigned to.
*
* However, on the same machine, we need to also keep track of which build 'owns' which proxy
*
* @author bfiola
*
*/
public class ProxyWrapperFactory implements Serializable {
private static final long serialVersionUID = 1L;
private static ProxyWrapperFactory instance;
private final Map<Integer, ProxyWrapper> proxies;
protected ProxyWrapperFactory() {
proxies = new HashMap<Integer, ProxyWrapper>();
}
private static ProxyWrapperFactory getInstance() {
if (instance == null) {
instance = new ProxyWrapperFactory();
}
return instance;
}
private void _startProxy(ProxyRequest request) {
Integer port = request.getProxyPort();
ProxyPluginDescriptor descriptor = request.getDescriptor();
PrintStream logger = request.getLogger();
String buildId = request.getBuildId();
// we use the plugin descriptor to validate the port number when
// it's initially configured - we can reuse this here to make sure
// that the port is still valid. if not, it will throw an exception.
try {
descriptor.testPort(port);
} catch(TankJenkinsPluginException e) {
throw new RuntimeException(e);
}
// if a proxy doesn't already exist at this port, create it.
// otherwise, throw an exception.
if (proxies.get(port) == null) {
LogPrinter.print("Proxy at port " + port
+ " wasn't found, creating a new one for build " + buildId + ".", logger);
ProxyWrapper proxy = new ProxyWrapper(request);
proxies.put(port, proxy);
proxy.startProxy();
} else {
ProxyWrapper proxy = proxies.get(port);
throw new RuntimeException("Port " + port + " already in use by build " + proxy.getOwnerId());
}
}
private void _stopProxy(ProxyRequest request) {
Integer port = request.getProxyPort();
PrintStream logger = request.getLogger();
String buildId = request.getBuildId();
if(proxies.get(port) != null) {
ProxyWrapper proxy = proxies.get(port);
if(buildId.equals(proxy.getOwnerId())) {
LogPrinter.print("Found proxy at port " + port + ", belonging to build " + buildId + " - stopping it.",
logger);
proxy.stopProxy();
proxies.remove(port);
} else {
throw new RuntimeException("Proxy exists at port " + port + " but belongs to build " + proxy.getOwnerId() + ", not build " + buildId + ". ");
}
} else {
throw new RuntimeException("No proxy at " + port + ".");
}
}
public static void startProxy(ProxyRequest request) {
getInstance()._startProxy(request);
}
public static void stopProxy(ProxyRequest request) {
getInstance()._stopProxy(request);
}
}