/** * Copyright 2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package datameer.awstasks.util; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; import awstasks.com.amazonaws.AmazonServiceException; import awstasks.com.amazonaws.services.ec2.AmazonEC2; import awstasks.com.amazonaws.services.ec2.model.DescribeInstancesRequest; import awstasks.com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest; import awstasks.com.amazonaws.services.ec2.model.DescribeSecurityGroupsResult; import awstasks.com.amazonaws.services.ec2.model.Filter; import awstasks.com.amazonaws.services.ec2.model.GroupIdentifier; import awstasks.com.amazonaws.services.ec2.model.Instance; import awstasks.com.amazonaws.services.ec2.model.InstanceStateName; import awstasks.com.amazonaws.services.ec2.model.IpPermission; import awstasks.com.amazonaws.services.ec2.model.Reservation; import awstasks.com.amazonaws.services.ec2.model.SecurityGroup; import datameer.com.google.common.base.Preconditions; import datameer.com.google.common.collect.Lists; public class Ec2Util { private static final Logger LOG = Logger.getLogger(Ec2Util.class); public static List<Instance> findByGroup(AmazonEC2 ec2, String securityGroup, boolean includeMultipleReservations, InstanceStateName... instanceStates) { List<Reservation> reservations = ec2.describeInstances(new DescribeInstancesRequest().withFilters(Filters.groupName(securityGroup), Filters.instanceStates(instanceStates))).getReservations(); if (reservations.size() > 1 && !includeMultipleReservations) { throw new IllegalArgumentException("found more then one (" + reservations.size() + ") running instance groups (/reservations) for the given security group '" + securityGroup + "' with instances in '" + Arrays.asList(instanceStates) + "' mode"); } else if (reservations.isEmpty()) { return null; } List<Instance> instances = new ArrayList<Instance>(); for (Reservation reservation : reservations) { instances.addAll(reservation.getInstances()); } return instances; } public static Collection<String> getSecurityGroups(List<Instance> instances) { Set<String> groups = new HashSet<String>(); for (Instance instance : instances) { List<GroupIdentifier> securityGroups = instance.getSecurityGroups(); for (GroupIdentifier groupIdentifier : securityGroups) { groups.add(groupIdentifier.getGroupName()); } } return groups; } public static List<IpPermission> getPermissions(AmazonEC2 ec2, Collection<String> securityGroupNames, Filter... filters) { List<SecurityGroup> securityGroups = ec2.describeSecurityGroups(new DescribeSecurityGroupsRequest().withGroupNames(securityGroupNames).withFilters(filters)).getSecurityGroups(); List<IpPermission> ipPermissions = new ArrayList<IpPermission>(3); for (SecurityGroup groupDescription : securityGroups) { ipPermissions.addAll(groupDescription.getIpPermissions()); } return ipPermissions; } public static String[] toStrings(Enum<?>... enumInstances) { String[] names = new String[enumInstances.length]; for (int i = 0; i < names.length; i++) { names[i] = enumInstances[i].toString(); } return names; } public static List<String> toIds(List<Instance> instances) { List<String> ids = new ArrayList<String>(instances.size()); for (Instance instance : instances) { ids.add(instance.getInstanceId()); } return ids; } public static List<String> toStates(List<Instance> instances) { List<String> states = Lists.newArrayList(); for (Instance instance : instances) { states.add(instance.getState().getName()); } return states; } public static List<String> toPublicDns(List<Instance> instances) { List<String> dns = new ArrayList<String>(instances.size()); for (Instance instance : instances) { dns.add(instance.getPublicDnsName()); } return dns; } public static List<String> toPrivateDns(List<Instance> instances) { List<String> dns = new ArrayList<String>(instances.size()); for (Instance instance : instances) { dns.add(instance.getPrivateDnsName()); } return dns; } public static List<Instance> reloadInstanceDescriptions(AmazonEC2 ec2, List<Instance> instances) { List<Reservation> reservations = ec2.describeInstances(new DescribeInstancesRequest().withInstanceIds(toIds(instances))).getReservations(); List<Instance> updatedInstanceDescriptioins = new ArrayList<Instance>(); for (Reservation reservation : reservations) { updatedInstanceDescriptioins.addAll(reservation.getInstances()); } return updatedInstanceDescriptioins; } public static Reservation reloadReservation(AmazonEC2 ec2, Reservation reservation) { List<Reservation> reservations = ec2.describeInstances(new DescribeInstancesRequest().withFilters(Filters.reservationId(reservation.getReservationId()))).getReservations(); if (reservations.size() != 1) { throw new IllegalStateException("do not found resevervation with id '" + reservation.getReservationId() + "': " + reservations); } return reservations.get(0); } public static Reservation getReservation(AmazonEC2 ec2, List<String> instanceIds) { List<Reservation> reservations = ec2.describeInstances(new DescribeInstancesRequest().withInstanceIds(instanceIds)).getReservations(); if (reservations.size() != 1) { throw new IllegalStateException("do not found resevervation for instances '" + instanceIds + "': " + reservations); } return reservations.get(0); } public static List<String> getInstanceIds(Reservation reservationDescription) { List<Instance> instances = reservationDescription.getInstances(); List<String> instanceIds = new ArrayList<String>(instances.size()); for (Instance instance : instances) { instanceIds.add(instance.getInstanceId()); } return instanceIds; } public static boolean groupExists(AmazonEC2 ec2, String groupName) { try { DescribeSecurityGroupsResult groups = ec2.describeSecurityGroups(new DescribeSecurityGroupsRequest().withGroupNames(groupName)); return !groups.getSecurityGroups().isEmpty(); } catch (AmazonServiceException e) { if (e.getErrorCode().equals("InvalidGroup.NotFound")) { return false; } throw e; } } public static boolean isAlive(Instance instance) { switch (InstanceStateName.fromValue(instance.getState().getName())) { case Pending: case Running: return true; case ShuttingDown: case Stopping: case Terminated: case Stopped: return false; default: throw new UnsupportedOperationException(instance.getState().getName()); } } public static List<Instance> waitUntil(AmazonEC2 ec2, List<Instance> instances, EnumSet<InstanceStateName> allowedPreTargetStates, InstanceStateName targetState) { return waitUntil(ec2, instances, allowedPreTargetStates, targetState, TimeUnit.MINUTES, 10); } public static List<Instance> waitUntil(AmazonEC2 ec2, List<Instance> instances, EnumSet<InstanceStateName> allowedPreTargetStates, InstanceStateName targetState, TimeUnit timeUnit, long waitTime) { long end = System.currentTimeMillis() + timeUnit.toMillis(waitTime); List<InstanceStateName> undesiredStates = new ArrayList<InstanceStateName>(); do { try { long sleepTime = 10000; LOG.info(String.format("wait on instances %s to enter '" + targetState + "' mode. Sleeping %d ms. zzz...", Ec2Util.getSecurityGroups(instances), sleepTime)); Thread.sleep(sleepTime); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } instances = Ec2Util.reloadInstanceDescriptions(ec2, instances); undesiredStates.clear(); for (Instance instance : instances) { InstanceStateName state = InstanceStateName.fromValue(instance.getState().getName()); boolean instanceInTargetState = state.equals(targetState); Preconditions.checkState(instanceInTargetState || allowedPreTargetStates.contains(state), "Unexpected instance state '%s' for instance %s", state, instance.getInstanceId()); if (!instanceInTargetState) { undesiredStates.add(state); } } } while (!undesiredStates.isEmpty() && System.currentTimeMillis() < end); Preconditions.checkState(undesiredStates.isEmpty(), "not all instance of group '" + Ec2Util.getSecurityGroups(instances) + "' are in state 'running', some are in: " + undesiredStates); return instances; } }