All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kuali.maven.ec2.EC2Utils Maven / Gradle / Ivy

package org.kuali.maven.ec2;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import org.apache.commons.lang.StringUtils;
import org.kuali.maven.ec2.pojo.ImageComparator;
import org.kuali.maven.ec2.state.ImageStateRetriever;
import org.kuali.maven.ec2.state.InstanceStateRetriever;
import org.kuali.maven.ec2.state.SnapshotStateRetriever;
import org.kuali.maven.ec2.state.StateRetriever;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.BlockDeviceMapping;
import com.amazonaws.services.ec2.model.CreateSnapshotRequest;
import com.amazonaws.services.ec2.model.CreateSnapshotResult;
import com.amazonaws.services.ec2.model.CreateTagsRequest;
import com.amazonaws.services.ec2.model.DeleteSnapshotRequest;
import com.amazonaws.services.ec2.model.DeregisterImageRequest;
import com.amazonaws.services.ec2.model.DescribeImagesRequest;
import com.amazonaws.services.ec2.model.DescribeImagesResult;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.DescribeSnapshotsRequest;
import com.amazonaws.services.ec2.model.DescribeSnapshotsResult;
import com.amazonaws.services.ec2.model.EbsBlockDevice;
import com.amazonaws.services.ec2.model.Filter;
import com.amazonaws.services.ec2.model.Image;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.RegisterImageRequest;
import com.amazonaws.services.ec2.model.RegisterImageResult;
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.Snapshot;
import com.amazonaws.services.ec2.model.Tag;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;

public class EC2Utils {

    private static final Logger logger = LoggerFactory.getLogger(EC2Utils.class);

    AmazonEC2Client client;

    private EC2Utils(AWSCredentials credentials) {
        this.client = new AmazonEC2Client(credentials);
    }

    public static EC2Utils getInstance(String accessKey, String secretKey) {
        AWSCredentials credentials = getCredentials(accessKey, secretKey);
        return getInstance(credentials);
    }

    public static EC2Utils getInstance(AWSCredentials credentials) {
        return new EC2Utils(credentials);
    }

    public static EC2Utils getImage(String accessKey, String secretKey) {
        AWSCredentials credentials = getCredentials(accessKey, secretKey);
        return getImage(credentials);
    }

    public static EC2Utils getImage(AWSCredentials credentials) {
        return new EC2Utils(credentials);
    }

    public void cleanupSlaveImages(String key, String prefix, String device, int min) {
        // Just in case
        if (min < 1) {
            min = 1;
        }
        List images = getEC2ImagesOwnedByMe();
        Collections.sort(images, new ImageComparator());
        List slaveTags = new ArrayList();
        for (Image image : images) {
            if (containsTag(image.getTags(), key, prefix)) {
                Tag tag = getTag(image.getTags(), key, prefix);
                SlaveTag slaveTag = getSlaveTag(image, tag, device);
                slaveTags.add(slaveTag);
            }
        }
        int size = slaveTags.size();
        if (size <= min) {
            logger.info("Retaining all slave images since there are only " + size + " and " + min + " must be retained");
            return;
        }
        Collections.sort(slaveTags);
        Collections.reverse(slaveTags);
        List delete = new ArrayList();
        for (int i = min; i < size; i++) {
            delete.add(slaveTags.get(i));
        }
        logger.info("Retaining " + min + " slave images");
        logger.info("Deleting " + delete.size() + " slave images");
        for (SlaveTag st : delete) {
            logger.info("Deleting " + st.getSequence() + " - " + st.getImageId() + " - " + st.getSnapshotId());
            deRegisterImage(st.getImageId());
            deleteSnapshot(st.getSnapshotId());
        }
    }

    public boolean containsTag(List tags, String key, String prefix) {
        for (Tag tag : tags) {
            if (matches(tag, key, prefix)) {
                return true;
            }
        }
        return false;
    }

    public String getSnapshotId(Image image, String deviceName) {
        List mappings = image.getBlockDeviceMappings();
        for (BlockDeviceMapping mapping : mappings) {
            if (deviceName.equals(mapping.getDeviceName())) {
                EbsBlockDevice ebd = mapping.getEbs();
                return ebd.getSnapshotId();
            }
        }
        return null;
    }

    public SlaveTag getSlaveTag(Image image, Tag tag, String device) {
        String[] tokens = StringUtils.splitByWholeSeparator(tag.getValue(), " - ");
        String snapshotId = getSnapshotId(image, device);

        SlaveTag slaveTag = new SlaveTag();
        slaveTag.setImageId(image.getImageId());
        slaveTag.setKey(tag.getKey());
        slaveTag.setLabel(tokens[0]);
        slaveTag.setDate(tokens[1]);
        slaveTag.setSequence(new Integer(tokens[2]));
        slaveTag.setSnapshotId(snapshotId);
        return slaveTag;
    }

    public boolean matches(Tag tag, String key, String prefix) {
        return key.equals(tag.getKey()) && tag.getValue().startsWith(prefix);
    }

    public Tag getTag(List tags, String key, String prefix) {
        for (Tag tag : tags) {
            if (matches(tag, key, prefix)) {
                return tag;
            }
        }
        return null;
    }

    public Image getImage(String imageId) {
        DescribeImagesRequest request = new DescribeImagesRequest();
        request.setImageIds(Collections.singletonList(imageId));
        DescribeImagesResult result = client.describeImages(request);
        List images = result.getImages();
        if (isEmpty(images)) {
            throw new IllegalStateException("Unable to locate '" + imageId + "'");
        }
        if (images.size() > 1) {
            throw new IllegalStateException("Found " + images.size() + " matching '" + imageId + "'");
        }

        return images.get(0);
    }

    public RegisterImageResult registerImage(RegisterImageRequest request, WaitControl wc) {
        RegisterImageResult result = client.registerImage(request);
        if (wc.isWait()) {
            String id = result.getImageId();
            int timeout = wc.getTimeout();
            StateRetriever sr = new ImageStateRetriever(this, id);
            logger.info("Waiting up to " + timeout + " seconds for '" + id + "' to reach state '" + wc.getState() + "'");
            waitForState(sr, wc);
        } else {
            logger.info("Created image " + result.getImageId());
        }
        return result;
    }

    public void terminate(String instanceId, WaitControl wc) {
        TerminateInstancesRequest request = new TerminateInstancesRequest();
        request.setInstanceIds(Collections.singletonList(instanceId));
        client.terminateInstances(request);
        if (wc.isWait()) {
            StateRetriever sr = new InstanceStateRetriever(this, instanceId);
            logger.info("Waiting up to " + wc.getTimeout() + " seconds for " + instanceId + " to terminate");
            waitForState(sr, wc);
        } else {
            logger.info("Terminated " + instanceId);
        }
    }

    public Instance wait(Instance i, WaitControl wc, Properties props) {
        if (wc.isWait()) {
            StateRetriever sr = new InstanceStateRetriever(this, i.getInstanceId());
            logger.info("Waiting up to " + wc.getTimeout() + " seconds for " + i.getInstanceId() + " to start");
            waitForState(sr, wc);
            Instance running = getEC2Instance(i.getInstanceId());
            String id = i.getInstanceId();
            String dns = running.getPublicDnsName();
            String name = getTagValue(running, "Name");
            logger.info("EC2 Instance: " + name + " (" + id + ") " + dns);
            props.setProperty("ec2.instance.dns", running.getPublicDnsName());
            return running;
        } else {
            logger.info("Launched " + i.getInstanceId());
            return i;
        }
    }

    public void createTags(Instance instance, List tags) {
        if (isEmpty(tags)) {
            return;
        }
        CreateTagsRequest request = new CreateTagsRequest();
        request.setResources(Collections.singletonList(instance.getInstanceId()));
        request.setTags(tags);
        client.createTags(request);
    }

    public Instance getSingleEC2Instance(RunInstancesRequest request) {
        RunInstancesResult result = client.runInstances(request);
        Reservation r = result.getReservation();
        List instances = r.getInstances();
        return instances.get(0);
    }

    protected Filter getFilterFromTag(String tag, String value) {
        Filter filter = new Filter();
        filter.setName("tag:" + tag);
        filter.setValues(Collections.singletonList(value));
        return filter;
    }

    protected DescribeInstancesRequest getDescribeInstancesRequest(Tag tag) {
        DescribeInstancesRequest request = new DescribeInstancesRequest();
        Filter filter = getFilterFromTag(tag.getKey(), tag.getValue());
        request.setFilters(Collections.singletonList(filter));
        return request;
    }

    protected int validate(List instances, Tag tag, boolean failIfNotFound) {
        int size = instances.size();
        String msg = tag.getKey() + "=" + tag.getValue() + " matched " + size + " instances";
        if (size == 1) {
            return size;
        }
        if (size > 1) {
            throw new IllegalStateException(msg);
        }
        // size == 0
        if (failIfNotFound) {
            throw new IllegalStateException(msg);
        } else {
            logger.info(msg);
        }
        return size;
    }

    public Instance findInstanceFromTag(Tag tag, boolean failIfNotFound) {
        DescribeInstancesRequest request = getDescribeInstancesRequest(tag);
        DescribeInstancesResult result = client.describeInstances(request);
        List instances = getAllInstances(result.getReservations());
        int size = validate(instances, tag, failIfNotFound);
        if (size == 1) {
            return instances.get(0);
        } else {
            return null;
        }
    }

    public List getEC2Instances() {
        return getEC2Instances(Collections. emptyList());
    }

    public List getEC2Instances(List instanceIds) {
        DescribeInstancesRequest request = new DescribeInstancesRequest();
        request.setInstanceIds(instanceIds);
        DescribeInstancesResult result = client.describeInstances(request);
        return getAllInstances(result.getReservations());
    }

    public List getEC2Images(List imageIds) {
        DescribeImagesRequest request = new DescribeImagesRequest();
        request.setImageIds(imageIds);
        DescribeImagesResult result = client.describeImages(request);
        return result.getImages();
    }

    public List getEC2ImagesOwnedByMe() {
        DescribeImagesRequest request = new DescribeImagesRequest();
        request.withOwners("self");
        DescribeImagesResult result = client.describeImages(request);

        return result.getImages();
    }

    public void deleteSnapshot(String snapshotId) {
        DeleteSnapshotRequest request = new DeleteSnapshotRequest();
        request.setSnapshotId(snapshotId);
        client.deleteSnapshot(request);
    }

    public void deRegisterImage(String ImageId) {
        DeregisterImageRequest request = new DeregisterImageRequest();
        request.setImageId(ImageId);
        client.deregisterImage(request);
    }

    public List getEC2SnapshotsbyTag(Tag tag) {
        DescribeSnapshotsRequest request = new DescribeSnapshotsRequest();
        Filter filter = getFilterFromTag(tag.getKey(), tag.getValue());
        request.setFilters(Collections.singletonList(filter));
        DescribeSnapshotsResult result = client.describeSnapshots(request);
        return result.getSnapshots();
    }

    public Snapshot createSnapshot(String volumeId, String description, WaitControl wc) {
        CreateSnapshotRequest request = new CreateSnapshotRequest(volumeId, description);
        CreateSnapshotResult result = client.createSnapshot(request);
        String id = result.getSnapshot().getSnapshotId();
        if (wc.isWait()) {
            StateRetriever sr = new SnapshotStateRetriever(this, id);
            logger.info("Waiting up to " + wc.getTimeout() + " seconds for snapshot '" + id + "' to complete");
            waitForState(sr, wc);
        } else {
            logger.info("Completed " + id);
        }
        return result.getSnapshot();
    }

    public void tag(String id, String name, String value) {
        tag(id, new Tag(name, value));
    }

    public void tag(String id, Tag tag) {
        tag(id, Collections.singletonList(tag));
    }

    /**
     * Adds or overwrites tags for the specified resource. id can be an EC2 instance id, snapshot id,
     * volume id, etc. Each resource can have a maximum of 10 tags. Each tag consists of a key-value pair. Tag keys must
     * be unique per resource.
     */
    public void tag(String id, List tags) {
        if (isEmpty(tags)) {
            return;
        }
        CreateTagsRequest request = new CreateTagsRequest();
        request.setResources(Collections.singletonList(id));
        request.setTags(tags);
        client.createTags(request);
        logger.info("Tagged '" + id + "' with " + tags.size() + " tags");
    }

    public static AWSCredentials getCredentials(String accessKey, String secretKey) {
        return new BasicAWSCredentials(accessKey, secretKey);
    }

    public static AmazonEC2Client getEC2Client(String accessKey, String secretKey) {
        AWSCredentials credentials = getCredentials(accessKey, secretKey);
        return new AmazonEC2Client(credentials);
    }

    public String getTagValue(Instance i, String tag) {
        List tags = i.getTags();
        for (Tag t : tags) {
            if (t.getKey().equals(tag)) {
                return t.getValue();
            }
        }
        return "";
    }

    public String getTagValueImage(Image i, String tag) {
        List tags = i.getTags();
        for (Tag t : tags) {
            if (t.getKey().equals(tag)) {
                return t.getValue();
            }
        }
        return "";
    }

    public void waitForState(StateRetriever retriever, WaitControl wc) {
        long now = System.currentTimeMillis();
        long timeout = now + wc.getTimeout() * 1000;
        // Wait a little bit before we query AWS for state information
        // If you query immediately it can sometimes flake out
        sleep(wc.getInitialPause());
        while (true) {
            now = System.currentTimeMillis();
            if (now > timeout) {
                throw new IllegalStateException("Timed out waiting for state '" + wc.getState() + "'");
            }
            long remaining = (timeout - now) / 1000;
            String newState = retriever.getState();
            if (newState.equals(wc.getState())) {
                logger.info("Success!!!  state=" + newState);
                break;
            } else {
                logger.info(newState + " - " + remaining + "s");
                sleep(wc.getSleep());
            }
        }
    }

    protected void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }

    public List getAllInstances(List reservations) {
        List instances = new ArrayList();
        for (Reservation r : reservations) {
            instances.addAll(r.getInstances());
        }
        return instances;
    }

    public Snapshot getSnapshot(String snapshotId) {
        DescribeSnapshotsRequest request = new DescribeSnapshotsRequest();
        request.setSnapshotIds(Collections.singletonList(snapshotId));
        DescribeSnapshotsResult result = client.describeSnapshots(request);
        List snapshots = result.getSnapshots();
        return snapshots.get(0);
    }

    public Instance getEC2Instance(String instanceId) {
        DescribeInstancesRequest request = new DescribeInstancesRequest();
        request.setInstanceIds(Collections.singletonList(instanceId));
        DescribeInstancesResult result = client.describeInstances(request);
        List reservations = result.getReservations();
        Reservation r = reservations.get(0);
        List instances = r.getInstances();
        return instances.get(0);
    }

    public static final boolean isEmpty(Collection c) {
        return c == null || c.size() == 0;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy