package com.urbancode.terraform.tasks.rackspace; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.log4j.Logger; import com.urbancode.terraform.tasks.common.EnvironmentTask; import com.urbancode.terraform.tasks.common.TerraformContext; import com.urbancode.x2o.tasks.MultiThreadTask; public class EnvironmentTaskRackspace extends EnvironmentTask { //********************************************************************************************** // CLASS //********************************************************************************************** static private final Logger log = Logger.getLogger(EnvironmentTaskRackspace.class); static final private int MAX_THREADS = 30; //********************************************************************************************** // INSTANCE //********************************************************************************************** private List<ServerTask> serverTasks = new ArrayList<ServerTask>(); private List<LoadBalancerTask> loadBalancerTasks = new ArrayList<LoadBalancerTask>(); private List<DatabaseInstanceTask> dbInstanceTasks = new ArrayList<DatabaseInstanceTask>(); //---------------------------------------------------------------------------------------------- public EnvironmentTaskRackspace(TerraformContext context) { super(context); } //---------------------------------------------------------------------------------------------- public List<ServerTask> getServerTasks() { return serverTasks; } //---------------------------------------------------------------------------------------------- public List<LoadBalancerTask> getLoadBalancerTasks() { return loadBalancerTasks; } //---------------------------------------------------------------------------------------------- public List<DatabaseInstanceTask> getDatabaseInstanceTasks() { return dbInstanceTasks; } //---------------------------------------------------------------------------------------------- public ContextRackspace fetchContext() { return (ContextRackspace) this.context; } //---------------------------------------------------------------------------------------------- public ServerTask createServer() { ServerTask server = new ServerTask(this); serverTasks.add(server); return server; } //---------------------------------------------------------------------------------------------- public LoadBalancerTask createLoadBalancer() { LoadBalancerTask lb = new LoadBalancerTask(this); loadBalancerTasks.add(lb); return lb; } //---------------------------------------------------------------------------------------------- public DatabaseInstanceTask createDatabaseInstance() { DatabaseInstanceTask db = new DatabaseInstanceTask(this); dbInstanceTasks.add(db); return db; } //---------------------------------------------------------------------------------------------- /** * Spins off a new thread for each clone in this "chunk" to be created in parallel. * @param serverTaskList * @throws RemoteException * @throws InterruptedException * @throws Exception */ private void createOrDestroyServersInParallel(List<ServerTask> serverTaskList, List<DatabaseInstanceTask> databaseTaskList, boolean doCreate) throws RemoteException, InterruptedException, Exception { long pollInterval = 3000L; long timeoutInterval = 10L * 60L * 1000L; long start; if (serverTaskList != null && !serverTaskList.isEmpty() || (databaseTaskList != null && !databaseTaskList.isEmpty())) { int threadPoolSize = serverTaskList.size() + databaseTaskList.size(); if (threadPoolSize > MAX_THREADS) { threadPoolSize = MAX_THREADS; } // create instances - launch thread for each one List<MultiThreadTask> threadList = new ArrayList<MultiThreadTask>(); ExecutorService service = Executors.newFixedThreadPool(threadPoolSize); start = System.currentTimeMillis(); for (ServerTask instance : serverTaskList) { MultiThreadTask mThread = new MultiThreadTask(instance, doCreate, context); threadList.add(mThread); service.execute(mThread); } for (DatabaseInstanceTask instance : databaseTaskList) { MultiThreadTask mThread = new MultiThreadTask(instance, doCreate, context); threadList.add(mThread); service.execute(mThread); } service.shutdown(); // accept no more threads while (!service.isTerminated()) { if (System.currentTimeMillis() - start > timeoutInterval) { throw new RemoteException( "Timeout waiting for creation Instance threads to finish"); } // wait until all threads are done Thread.sleep(pollInterval); } // check for Exceptions caught in threads for (MultiThreadTask task : threadList) { if (task.getExceptions().size() != 0) { for (Exception e : task.getExceptions()) { log.error("Exception caught!", e); throw e; } } } } else { log.error("List of servers to launch was null!"); } } //---------------------------------------------------------------------------------------------- @Override public void create() { try { createOrDestroyServersInParallel(serverTasks, dbInstanceTasks, true); for (LoadBalancerTask lb : loadBalancerTasks) { lb.create(); } } catch (RemoteException e) { log.warn("RemoteException while creating Rackspace servers", e); } catch (InterruptedException e) { log.warn("InterruptedException while creating Rackspace servers", e); } catch (Exception e) { log.warn("Exception while creating Rackspace servers", e); } } //---------------------------------------------------------------------------------------------- @Override public void restore() { } //---------------------------------------------------------------------------------------------- @Override public void destroy() { try { createOrDestroyServersInParallel(serverTasks, dbInstanceTasks, false); for (LoadBalancerTask lb : loadBalancerTasks) { lb.destroy(); } } catch (RemoteException e) { log.warn("RemoteException while creating Rackspace servers", e); } catch (InterruptedException e) { log.warn("InterruptedException while creating Rackspace servers", e); } catch (Exception e) { log.warn("Exception while creating Rackspace servers", e); } } }