package dk.kaspergsm.stormdeploy; import dk.kaspergsm.stormdeploy.configurations.Zookeeper; import dk.kaspergsm.stormdeploy.userprovided.Configuration; import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions; import org.jclouds.compute.ComputeService; import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.StatementList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import static org.jclouds.scriptbuilder.domain.Statements.exec; /** * Used to launch a new nodes * * @author Kasper Grud Skat Madsen */ public class LaunchNodeThread extends Thread { private static Logger log = LoggerFactory.getLogger(LaunchNodeThread.class); private String _instanceType, _clustername, _region, _image, _username, _sshkeyname, _subnetId, _securityGroupId, _installDir;; private Set<NodeMetadata> _newNodes = null; private List<Statement> _initScript; private ComputeService _compute; private List<Integer> _nodeids; private List<String> _daemons; /** * @param compute * ComputeService from JClouds * @param config * User configuration from configuration.yaml * @param instanceType * Supported instanceType (e.g. m1.medium on aws-ec2) * @param clustername * Name of cluster to deploy * @param nodeids * Set of nodeids being launched * @param daemons * Set of daemons to launch on this set of nodes * @param zkMyId * If contain(daemons, zk) then write this zkMyId on init */ public LaunchNodeThread(ComputeService compute, Configuration config, String instanceType, String clustername, List<Integer> nodeids, List<String> daemons, Integer zkMyId) { _region = config.getDeploymentLocation(); _username = config.getImageUsername(); _image = config.getDeploymentImage(); _subnetId = config.getSubnet(); _securityGroupId = config.getSecurityGroup(); _instanceType = instanceType; _clustername = clustername; _daemons = daemons; _compute = compute; _nodeids = nodeids; _sshkeyname = config.getSSHKeyName(); _installDir = config.getInstallDir(); // Create initScript _initScript = new ArrayList<Statement>(); _initScript.add(exec("mkdir -p " + _installDir)); if (!"~/".equals(_installDir)) { _initScript.add(exec("chown " + _username + " " + _installDir)); } _initScript.add(exec("echo \"" + daemons.toString() + "\" > " + _installDir + "daemons")); _initScript.add(exec("echo \"" + instanceType + "\" > " + _installDir + ".instance-type")); if (zkMyId != null) _initScript.addAll(Zookeeper.writeZKMyIds(_username, zkMyId)); // Run thread now this.start(); } @SuppressWarnings("unchecked") @Override public void run() { try { TemplateOptions options = _compute.templateOptions(); options.runAsRoot(false) .wrapInInitScript(true) .overrideLoginUser(_username) .inboundPorts(Tools.getPortsToOpen()) .userMetadata("daemons", _daemons.toString()) .runScript(new StatementList(_initScript)) .overrideLoginCredentials(Tools.getPrivateKeyCredentials(_username, _sshkeyname)) .authorizePublicKey(Tools.getPublicKey(_sshkeyname)); if(_subnetId != null){ if(_securityGroupId != null){ options.as(AWSEC2TemplateOptions.class).subnetId(_subnetId).securityGroupIds(_securityGroupId); } else{ options.as(AWSEC2TemplateOptions.class).subnetId(_subnetId); } } _newNodes = (Set<NodeMetadata>) _compute.createNodesInGroup( _clustername, _nodeids.size(), _compute.templateBuilder() .hardwareId(_instanceType) .locationId(_region) .imageId(_image) .options(options).build()); } catch (NoSuchElementException ex) { // happens often when hardwareId is not found. List all possible hardware types if (ex.getMessage().toLowerCase().contains("hardwareid") && ex.getMessage().toLowerCase().contains("not found")) { log.error("You have specified unknown hardware profile. Here follows a list of supported profiles: "); Set<? extends Hardware> availableHardware = _compute.listHardwareProfiles(); for (Hardware h : availableHardware) { log.info(h.toString()); } } else { log.error("Problem: ", ex); } } catch (Exception ex) { log.error("Problem launching instance", ex); } } public List<Integer> getNodeIds() { return _nodeids; } public Set<NodeMetadata> getNewNodes() { return _newNodes; } }