/*
* Copyright 2008-2010 Xebia and 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 fr.xebia.demo.amazon.aws;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
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.DescribeSnapshotsRequest;
import com.amazonaws.services.ec2.model.Image;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.Snapshot;
import com.amazonaws.services.ec2.model.StopInstancesRequest;
import com.amazonaws.services.ec2.model.TagDescription;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;
import com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancing;
import com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingClient;
import com.amazonaws.services.rds.AmazonRDS;
import com.amazonaws.services.rds.AmazonRDSClient;
import com.amazonaws.services.rds.model.DBInstance;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
public class AmazonAwsShutdowner {
private static final String TAG_DO_NOT_DEREGISTER = "do-not-deregister";
public static final Function<Instance, String> TO_INSTANCE_ID_FUNCTION = new Function<Instance, String>() {
@Override
public String apply(Instance instance) {
return instance.getInstanceId();
}
};
public static final Function<Image, String> TO_IMAGE_ID_FUNCTION = new Function<Image, String>() {
@Override
public String apply(Image image) {
return image.getImageId();
}
};
private static final String TAG_DO_NOT_TERMINATE = "do-not-terminate";
private static final String TAG_DO_NOT_STOP = "do-not-stop";
public static void main(String[] args) throws Exception {
AmazonAwsShutdowner amazonAwsShutdowner = new AmazonAwsShutdowner();
amazonAwsShutdowner.test();
}
protected final Logger logger = LoggerFactory.getLogger(getClass());
private AmazonEC2 ec2;
private AmazonRDS rds;
private AmazonElasticLoadBalancing elb;
public AmazonAwsShutdowner() throws IOException {
InputStream credentialsAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("AwsCredentials.properties");
Preconditions.checkNotNull(credentialsAsStream, "File 'AwsCredentials.properties' NOT found in the classpath");
AWSCredentials credentials = new PropertiesCredentials(credentialsAsStream);
ec2 = new AmazonEC2Client(credentials);
ec2.setEndpoint("ec2.eu-west-1.amazonaws.com");
rds = new AmazonRDSClient(credentials);
rds.setEndpoint("rds.eu-west-1.amazonaws.com");
elb = new AmazonElasticLoadBalancingClient(credentials);
elb.setEndpoint("elasticloadbalancing.eu-west-1.amazonaws.com");
}
public void test() {
String ownerId = "self";
boolean dryRun = true;
// RETRIEVE TAGS
Map<String, Map<String, String>> tagsByResourceId = new MapMaker().makeComputingMap(new Function<String, Map<String, String>>() {
@Override
public Map<String, String> apply(String input) {
return Maps.newHashMap();
}
});
for (TagDescription tagDescription : ec2.describeTags().getTags()) {
tagsByResourceId.get(tagDescription.getResourceId()).put(tagDescription.getKey(), tagDescription.getValue());
}
// RDS INSTANCEs
for (DBInstance dbInstance : rds.describeDBInstances().getDBInstances()) {
Map<String, String> instanceTags = tagsByResourceId.get(dbInstance.getDBInstanceIdentifier());
logger.debug("Tags for " + dbInstance + ": " + instanceTags);
}
// EC2 INSTANCES
List<Instance> instancesAlreadyNotStarted = Lists.newArrayList();
List<Instance> instancesToStop = Lists.newArrayList();
List<Instance> instancesToTerminate = Lists.newArrayList();
List<Instance> instancesToKeepUnchanged = Lists.newArrayList();
for (Reservation reservation : ec2.describeInstances().getReservations()) {
for (Instance instance : reservation.getInstances()) {
Map<String, String> instanceTags = tagsByResourceId.get(instance.getInstanceId());
logger.debug("Tags for {}: {}", instance, instanceTags);
if("terminated".equals(instance.getState().getName())) {
instancesToKeepUnchanged.add(instance);
} else if (instanceTags.containsKey(TAG_DO_NOT_STOP)) {
instancesToKeepUnchanged.add(instance);
} else if (instanceTags.containsKey(TAG_DO_NOT_TERMINATE)) {
if ("started".equals(instance.getState().getName())) {
instancesToStop.add(instance);
} else {
instancesAlreadyNotStarted.add(instance);
}
} else {
instancesToTerminate.add(instance);
}
}
}
System.out.println("EC2 INSTANCES");
if (dryRun) {
System.out.println("DRY RUN Terminate:" + instancesToTerminate);
System.out.println("DRY RUN Stop:" + instancesToStop);
System.out.println("DRY RUN No need to stop:" + instancesAlreadyNotStarted);
System.out.println("DRY RUN Keep unchanged:" + instancesToKeepUnchanged);
} else {
System.out.println("Terminate:" + instancesToTerminate);
if (!instancesToTerminate.isEmpty()) {
ec2.terminateInstances(new TerminateInstancesRequest(Lists.transform(instancesToTerminate, TO_INSTANCE_ID_FUNCTION)));
}
System.out.println("Stop:" + instancesToStop);
if (!instancesToStop.isEmpty()) {
ec2.stopInstances(new StopInstancesRequest(Lists.transform(instancesToStop, TO_INSTANCE_ID_FUNCTION)));
}
System.out.println("No need to stop:" + instancesAlreadyNotStarted);
System.out.println("Keep unchanged:" + instancesToKeepUnchanged);
}
// AMIs
System.out.println("AMIs");
List<Image> imagesToDeRegister = Lists.newArrayList();
List<Image> imagesToKeep = Lists.newArrayList();
for (Image image : ec2.describeImages(new DescribeImagesRequest().withOwners(ownerId)).getImages()) {
Map<String, String> imageTags = tagsByResourceId.get(image.getImageId());
logger.debug("Tags for {}: {}", image, imageTags);
if (imageTags.containsKey(TAG_DO_NOT_DEREGISTER)) {
imagesToKeep.add(image);
} else {
imagesToDeRegister.add(image);
}
}
if (dryRun) {
System.out.println("DRY RUN Deregister:" + imagesToDeRegister);
System.out.println("DRY RUN Keep:" + imagesToKeep);
} else {
System.out.println("Deregister:" + imagesToDeRegister);
for (Image image : imagesToDeRegister) {
ec2.deregisterImage(new DeregisterImageRequest(image.getImageId()));
}
System.out.println("Keep:" + imagesToKeep);
}
List<String> imageIdsToKeep = Lists.transform(imagesToKeep, TO_IMAGE_ID_FUNCTION);
// SNAPSHOTS
System.out.println("SNAPSHOTs");
for (Snapshot snapshot : ec2.describeSnapshots(new DescribeSnapshotsRequest().withOwnerIds(ownerId)).getSnapshots()) {
if (snapshot.getDescription().contains("Created by CreateImage")) {
boolean associatedWithAnImageToKeep = false;
for (String imageIdToKeep : imageIdsToKeep) {
if (snapshot.getDescription().contains(imageIdToKeep)) {
associatedWithAnImageToKeep = true;
break;
}
}
if (associatedWithAnImageToKeep) {
System.out.println("Keep: " + snapshot);
} else {
if (dryRun) {
System.out.println("DRY RUN delete: " + snapshot);
} else {
System.out.println("Delete: " + snapshot);
ec2.deleteSnapshot(new DeleteSnapshotRequest(snapshot.getSnapshotId()));
}
}
}
}
// ELASTIC LOAD BALANCERs
// no tags on elb
}
}