
com.nitorcreations.willow.autoscaler.clouds.aws.AWSCloudAdapter Maven / Gradle / Ivy
package com.nitorcreations.willow.autoscaler.clouds.aws;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.commons.codec.binary.Base64;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.CreateTagsRequest;
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.InstanceStateChange;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.RunInstancesRequest;
import com.amazonaws.services.ec2.model.RunInstancesResult;
import com.amazonaws.services.ec2.model.Tag;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;
import com.amazonaws.services.ec2.model.TerminateInstancesResult;
import com.nitorcreations.willow.autoscaler.clouds.CloudAdapter;
import com.nitorcreations.willow.autoscaler.config.AutoScalingGroupConfig;
import com.nitorcreations.willow.autoscaler.deployment.AutoScalingGroupDeploymentStatus;
import com.nitorcreations.willow.autoscaler.metrics.AutoScalingGroupStatus;
import com.nitorcreations.willow.autoscaler.metrics.AutoScalingStatus;
@Named("AWS")
public class AWSCloudAdapter implements CloudAdapter {
private Logger logger = Logger.getLogger(this.getClass().getCanonicalName());
@Inject
private EC2ClientFactory ec2ClientFactory;
@Inject
private AutoScalingStatus autoScalingStatus;
@Inject
private Random random;
@Override
public String getCloudProviderId() {
return "AWS";
}
@Override
public AutoScalingGroupDeploymentStatus getGroupStatus(String regionId, String groupId) {
List instances = new LinkedList<>();
AmazonEC2Client client = ec2ClientFactory.getClient(regionId);
DescribeInstancesRequest request = new DescribeInstancesRequest();
request.withFilters(
new Filter()
.withName("tag:willow-group")
.withValues(groupId)
);
DescribeInstancesResult result;
try {
result = client.describeInstances(request);
} catch (Exception e) {
logger.log(Level.SEVERE, "Failed to query AWS instance(s)", e);
throw e;
}
for (Reservation r : result.getReservations()) {
addLiveInstancesToList(instances, r);
}
while (result.getNextToken() != null) {
DescribeInstancesRequest moreRequest = new DescribeInstancesRequest().withNextToken(result.getNextToken());
result = client.describeInstances(moreRequest);
for (Reservation r : result.getReservations()) {
addLiveInstancesToList(instances, r);
}
}
return new AutoScalingGroupDeploymentStatus(groupId, instances);
}
@Override
public List launchInstances(AutoScalingGroupConfig config, int count) {
List instanceIds = new ArrayList<>();
RunInstancesRequest runInstancesRequest = new RunInstancesRequest();
try {
logger.info(String.format("starting instance with authorization role %s", config.getAuthorizationRole()));
runInstancesRequest
.withImageId(config.getVirtualMachineImage())
.withInstanceType(config.getInstanceType())
.withMinCount(count)
.withMaxCount(count)
.withKeyName(config.getSshKey())
.withSecurityGroupIds(config.getSecurityGroups())
.withSubnetId(config.getSubnet())
.withUserData(Base64.encodeBase64String(config.getUserData().getBytes("UTF-8")))
.withIamInstanceProfile(new IamInstanceProfileSpecification().withArn(config.getAuthorizationRole()))
;
} catch (UnsupportedEncodingException e) {
logger.log(Level.SEVERE, "UTF-8 not supported, all bets are off!", e);
}
logger.info("Sending runInstances request to AWS");
AmazonEC2Client client = ec2ClientFactory.getClient(config.getRegion());
RunInstancesResult result = null;
try {
result = client.runInstances(runInstancesRequest);
} catch (Exception e) {
logger.log(Level.SEVERE, "Failed to launch AWS instance(s)", e);
return instanceIds;
}
logger.info("Sent runInstances request to AWS");
List instances = result.getReservation().getInstances();
for (Instance instance : instances) {
CreateTagsRequest createTagsRequest = new CreateTagsRequest();
createTagsRequest
.withResources(instance.getInstanceId())
.withTags(willowTagsToAWSTags(config.getTags()));
logger.info("Tagging instance " + instance.getInstanceId());
client.createTags(createTagsRequest);
instanceIds.add(instance.getInstanceId());
}
return instanceIds;
}
@Override
public List terminateInstances(AutoScalingGroupConfig config, int count) {
List instanceIds = new ArrayList<>();
List idsToTerminate = chooseInstancesToTerminate(config, count);
TerminateInstancesRequest request = new TerminateInstancesRequest();
request.withInstanceIds(idsToTerminate);
AmazonEC2Client client = ec2ClientFactory.getClient(config.getRegion());
TerminateInstancesResult result;
try {
result = client.terminateInstances(request);
} catch (Exception e) {
logger.log(Level.SEVERE, "Failed to terminate AWS instance(s)", e);
return instanceIds;
}
for (InstanceStateChange i : result.getTerminatingInstances()) {
instanceIds.add(i.getInstanceId());
}
return instanceIds;
}
private List chooseInstancesToTerminate(AutoScalingGroupConfig config, int count) {
Set idsToTerminate = new HashSet<>();
AutoScalingGroupStatus groupStatus = autoScalingStatus.getStatus(config.getName());
if (groupStatus != null && groupStatus.getDeploymentStatus() != null) {
List instances =
groupStatus.getDeploymentStatus().getInstances();
assert instances.size() >= count;
while (idsToTerminate.size() < count) {
int index = random.nextInt(instances.size());
String instanceId = instances.get(index).getInstanceId();
idsToTerminate.add(instanceId);
logger.info(String.format("Chose instance %s to terminate", instanceId));
}
}
return new ArrayList<>(idsToTerminate);
}
private List willowTagsToAWSTags(List wTags) {
List tags = new ArrayList<>();
for (com.nitorcreations.willow.autoscaler.config.Tag t : wTags) {
tags.add(new Tag(t.name, t.value));
}
return tags;
}
private void addLiveInstancesToList(List instances, Reservation r) {
for (Instance instance : r.getInstances()) {
String state = instance.getState().getName();
if ("running".equalsIgnoreCase(state) || "pending".equalsIgnoreCase(state)) {
instances.add(
new com.nitorcreations.willow.autoscaler.deployment.Instance(instance.getInstanceId())
.setInstanceType(instance.getInstanceType())
.setPrivateHostname(instance.getPrivateDnsName())
.setPrivateIp(instance.getPrivateIpAddress())
.setPublicHostname(instance.getPublicDnsName())
.setPublicIp(instance.getPublicIpAddress())
.setTags(convertToWillowTags(instance.getTags())));
}
}
}
private List convertToWillowTags(List awsTags) {
List willowTags = new ArrayList<>();
for (Tag tag : awsTags) {
willowTags.add(new com.nitorcreations.willow.autoscaler.config.Tag(tag.getKey(), tag.getValue()));
}
return willowTags;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy