package org.ukiuni.pacifista.virtual;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.NotImplementedException;
import org.ukiuni.pacifista.util.ScriptingUtil;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest;
import com.amazonaws.services.ec2.model.CreateKeyPairRequest;
import com.amazonaws.services.ec2.model.CreateKeyPairResult;
import com.amazonaws.services.ec2.model.CreateSecurityGroupRequest;
import com.amazonaws.services.ec2.model.CreateTagsRequest;
import com.amazonaws.services.ec2.model.DeleteKeyPairRequest;
import com.amazonaws.services.ec2.model.DeleteSecurityGroupRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.Filter;
import com.amazonaws.services.ec2.model.IamInstanceProfileSpecification;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.InstanceStateName;
import com.amazonaws.services.ec2.model.IpPermission;
import com.amazonaws.services.ec2.model.KeyPair;
import com.amazonaws.services.ec2.model.RunInstancesRequest;
import com.amazonaws.services.ec2.model.RunInstancesResult;
import com.amazonaws.services.ec2.model.StartInstancesRequest;
import com.amazonaws.services.ec2.model.StopInstancesRequest;
import com.amazonaws.services.ec2.model.Tag;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;
public class EC2VirtualHost implements VirtualHost {
private static final String SUFFIX_GROUP_NAME = "_s_Security_Group";
private static final String SUFFIX_KEY_NAME = "_s_Key_Name";
private Map<String, String> parameterMap = new HashMap<String, String>();
private String host;
private File baseDir;
private String instanceId;
public EC2VirtualHost(File baseDir, String host) {
this.baseDir = baseDir;
this.host = host;
}
@Override
public void setParameters(String parameters) {
ScriptingUtil.parseParameters(parameterMap, parameters);
}
@Override
public void boot() throws IOException, InterruptedException {
String instanceId = loadInstanceId();
StartInstancesRequest startInstancesRequest = new StartInstancesRequest(Arrays.asList(instanceId));
AmazonEC2Client client = createClient();
client.startInstances(startInstancesRequest);
}
@Override
public void shutdown() throws IOException, InterruptedException {
String instanceId = loadInstanceId();
StopInstancesRequest stopInstancesRequest = new StopInstancesRequest(Arrays.asList(instanceId));
AmazonEC2Client client = createClient();
client.stopInstances(stopInstancesRequest);
}
@Override
public boolean isRunning() {
return isStatus(InstanceStateName.Running);
}
private boolean isStatus(InstanceStateName status) {
loadInstanceId();
DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest();
describeInstancesRequest.setInstanceIds(Arrays.asList(this.instanceId));
DescribeInstancesResult describeInstancesResult = createClient().describeInstances(describeInstancesRequest);
if (describeInstancesResult.getReservations().isEmpty()) {
return false;
}
if (describeInstancesResult.getReservations().get(0).getInstances().isEmpty()) {
return false;
}
boolean result = status.toString().equals(describeInstancesResult.getReservations().get(0).getInstances().get(0).getState().getName());
return result;
}
@Override
public boolean isExist() throws IOException, InterruptedException {
return null != loadInstanceId();
}
@Override
public String downloadImage(String url) throws IOException {
throw new NotImplementedException();
}
@Override
public String downloadImage(String url, String proxyHost, int proxyPort) throws IOException {
throw new NotImplementedException();
}
@Override
public String downloadImage(String url, String proxyHost, int proxyPort, String proxyUser, String proxyPass) throws IOException {
throw new NotImplementedException();
}
public InstanceSSHAddress create() throws IOException, InterruptedException {
return create(null);
}
@Override
public InstanceSSHAddress create(String stragePath) throws IOException, InterruptedException {
AmazonEC2Client amazonEC2Client = createClient();
String securityGroupName;
if (parameterMap.containsKey("securityGroupName")) {
securityGroupName = parameterMap.get("securityGroupName");
} else {
securityGroupName = host + SUFFIX_GROUP_NAME;
CreateSecurityGroupRequest createSecurityGroupRequest = new CreateSecurityGroupRequest();
createSecurityGroupRequest.withGroupName(securityGroupName).withDescription(host + " s Security Group");
amazonEC2Client.createSecurityGroup(createSecurityGroupRequest);
}
String ipRange = "0.0.0.0/0";
if (null != parameterMap.get("sshAccessibleIpRange")) {
ipRange = parameterMap.get("sshAccessibleIpRange");
}
try {
openPort("tcp", 22, ipRange);
} catch (Exception e) {
// when duplicate. ignore.
}
File keyFile = null;
String keyName;
if (parameterMap.containsKey("keyName")) {
keyName = parameterMap.get("keyName");
} else {
keyName = host + SUFFIX_KEY_NAME;
CreateKeyPairRequest createKeyPairRequest = new CreateKeyPairRequest();
createKeyPairRequest.withKeyName(keyName);
CreateKeyPairResult createKeyPairResult = amazonEC2Client.createKeyPair(createKeyPairRequest);
KeyPair keyPair = createKeyPairResult.getKeyPair();
String privateKey = keyPair.getKeyMaterial();
File virtualMachineDir = new File(new File(baseDir, "vmimages"), host);
virtualMachineDir.mkdirs();
keyFile = new File(virtualMachineDir, keyPair.getKeyName() + ".key");
FileOutputStream out = new FileOutputStream(keyFile);
out.write(privateKey.getBytes());
out.close();
}
String imageId = "ami-fb8e9292";
if (parameterMap.containsKey("imageId")) {
imageId = parameterMap.get("imageId");
}
String instanceType = "t1.micro";
if (parameterMap.containsKey("instanceType")) {
instanceType = parameterMap.get("instanceType");
}
RunInstancesRequest runInstancesRequest = new RunInstancesRequest();
runInstancesRequest.withImageId(imageId).withInstanceType(instanceType).withMinCount(1).withMaxCount(1).withKeyName(keyName).withSecurityGroups(securityGroupName);
if (parameterMap.containsKey("iamName")) {
runInstancesRequest.setIamInstanceProfile(new IamInstanceProfileSpecification().withName(parameterMap.get("iamName")));
}
if (parameterMap.containsKey("subnetId")) {
runInstancesRequest.setSubnetId(parameterMap.get("subnetId"));
}
RunInstancesResult runInstancesResult = amazonEC2Client.runInstances(runInstancesRequest);
this.instanceId = runInstancesResult.getReservation().getInstances().get(0).getInstanceId();
while (!isStatus(InstanceStateName.Running)) {
Thread.sleep(5000);
}
addTag("Name", host);
DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest();
describeInstancesRequest.setInstanceIds(Arrays.asList(this.instanceId));
DescribeInstancesResult describeInstancesResult = amazonEC2Client.describeInstances(describeInstancesRequest);
String keyPath = null;
if (null != keyFile) {
keyPath = keyFile.getAbsolutePath();
}
return new InstanceSSHAddress(describeInstancesResult.getReservations().get(0).getInstances().get(0).getPublicDnsName(), 22, keyPath);
}
@Override
public void openPort(String protocol, int port) throws IOException, InterruptedException {
openPort(protocol, port, "0.0.0.0/0");
}
public void openPort(String protocol, int port, String ipRange) {
String securityGroupName;
if (parameterMap.containsKey("securityGroupName")) {
securityGroupName = parameterMap.get("securityGroupName");
} else {
securityGroupName = host + SUFFIX_GROUP_NAME;
}
IpPermission ipPermission = new IpPermission();
ipPermission.withIpRanges(ipRange).withIpProtocol(protocol).withFromPort(port).withToPort(port);
AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest = new AuthorizeSecurityGroupIngressRequest();
authorizeSecurityGroupIngressRequest.withGroupName(securityGroupName).withIpPermissions(ipPermission);
AmazonEC2Client amazonEC2Client = createClient();
amazonEC2Client.authorizeSecurityGroupIngress(authorizeSecurityGroupIngressRequest);
}
public void addTag(String key, String value) {
ArrayList<Tag> requestTags = new ArrayList<Tag>();
requestTags.add(new Tag(key, value));
CreateTagsRequest createTagsRequest = new CreateTagsRequest();
createTagsRequest.withResources(this.instanceId);
createTagsRequest.setTags(requestTags);
AmazonEC2Client amazonEC2Client = createClient();
amazonEC2Client.createTags(createTagsRequest);
}
@Override
public InstanceSSHAddress create(String stragePath, String type, int memory, int port) throws IOException, InterruptedException {
return this.create(stragePath);
}
private Instance loadInstance() {
DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest();
Filter filter = new Filter("tag:Name", Arrays.asList(host));
describeInstancesRequest.withFilters(filter);
AmazonEC2Client client = createClient();
DescribeInstancesResult describeInstancesResult = client.describeInstances(describeInstancesRequest);
if (describeInstancesResult.getReservations().isEmpty() || describeInstancesResult.getReservations().get(0).getInstances().isEmpty()) {
return null;
} else {
return describeInstancesResult.getReservations().get(describeInstancesResult.getReservations().size() - 1).getInstances().get(describeInstancesResult.getReservations().get(describeInstancesResult.getReservations().size() - 1).getInstances().size() - 1);
}
}
private String loadInstanceId() {
if (null != this.instanceId) {
return this.instanceId;
}
Instance instance = loadInstance();
if (null == instance) {
return null;
}
this.instanceId = instance.getInstanceId();
return this.instanceId;
}
@Override
public void remove() throws IOException, InterruptedException {
AmazonEC2Client client = createClient();
String instanceId = loadInstanceId();
try {
addTag("Name", host + "_deleted");
TerminateInstancesRequest terminateInstancesRequest = new TerminateInstancesRequest(Arrays.asList(instanceId));
client.terminateInstances(terminateInstancesRequest);
while (!isStatus(InstanceStateName.Terminated)) {
Thread.sleep(5000);
}
} catch (Throwable e) {
// Do nothing
}
try {
DeleteKeyPairRequest deleteKeyPairRequest = new DeleteKeyPairRequest(host + SUFFIX_KEY_NAME);
client.deleteKeyPair(deleteKeyPairRequest);
} catch (Throwable e) {
// Do nothing.
}
try {
DeleteSecurityGroupRequest deleteSecurityGroupRequest = new DeleteSecurityGroupRequest(host + SUFFIX_GROUP_NAME);
client.deleteSecurityGroup(deleteSecurityGroupRequest);
} catch (Throwable e) {
// Do nothing.
}
}
private AmazonEC2Client createClient() {
BasicAWSCredentials credentials = new BasicAWSCredentials(parameterMap.get("accessKey"), parameterMap.get("secretKey"));
AmazonEC2Client amazonEC2Client = new AmazonEC2Client(credentials);
if (null != parameterMap.get("proxyHost")) {
ClientConfiguration configuration = new ClientConfiguration();
configuration.setProxyHost(parameterMap.get("proxyHost"));
configuration.setProxyPort(Integer.valueOf(parameterMap.get("proxyPort")));
if (null != parameterMap.get("proxyUser")) {
configuration.setProxyUsername(parameterMap.get("proxyUser"));
configuration.setProxyPassword(parameterMap.get("proxyPassword"));
}
amazonEC2Client.setConfiguration(configuration);
}
if (parameterMap.containsKey("endpoint")) {
amazonEC2Client.setEndpoint(parameterMap.get("endpoint"));
}
return amazonEC2Client;
}
}