blob: 6a947a159fcf9d95171b59c44d04872f58ba93fa [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.jclouds.examples.ec2.createlamp;
import static org.jclouds.ec2.options.RunInstancesOptions.Builder.asType;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.ContextBuilder;
import org.jclouds.ec2.EC2AsyncClient;
import org.jclouds.ec2.EC2Client;
import org.jclouds.ec2.domain.InstanceState;
import org.jclouds.ec2.domain.InstanceType;
import org.jclouds.ec2.domain.IpProtocol;
import org.jclouds.ec2.domain.KeyPair;
import org.jclouds.ec2.domain.Reservation;
import org.jclouds.ec2.domain.RunningInstance;
import org.jclouds.ec2.predicates.InstanceStateRunning;
import org.jclouds.predicates.InetSocketAddressConnect;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.RestContext;
import org.jclouds.scriptbuilder.ScriptBuilder;
import org.jclouds.scriptbuilder.domain.OsFamily;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.net.HostAndPort;
/**
* This the Main class of an Application that demonstrates the use of the EC2Client by creating a
* small lamp server.
*
* Usage is: java MainApp accesskeyid secretkey command name where command in create destroy
*/
public class MainApp {
public static int PARAMETERS = 4;
public static String INVALID_SYNTAX = "Invalid number of parameters. Syntax is: accesskeyid secretkey command name\nwhere command in create destroy";
public static void main(String[] args) throws TimeoutException {
if (args.length < PARAMETERS)
throw new IllegalArgumentException(INVALID_SYNTAX);
// Args
String accesskeyid = args[0];
String secretkey = args[1];
String command = args[2];
String name = args[3];
// Init
RestContext<EC2Client, EC2AsyncClient> context = ContextBuilder
.newBuilder("aws-ec2").credentials(accesskeyid, secretkey)
.build();
// Get a synchronous client
EC2Client client = context.getApi();
try {
if (command.equals("create")) {
KeyPair pair = createKeyPair(client, name);
RunningInstance instance = createSecurityGroupKeyPairAndInstance(client, name);
System.out.printf("instance %s ready%n", instance.getId());
System.out.printf("ip address: %s%n", instance.getIpAddress());
System.out.printf("dns name: %s%n", instance.getDnsName());
System.out.printf("login identity:%n%s%n", pair.getKeyMaterial());
} else if (command.equals("destroy")) {
destroySecurityGroupKeyPairAndInstance(client, name);
} else {
throw new IllegalArgumentException(INVALID_SYNTAX);
}
} finally {
// Close connecton
context.close();
System.exit(0);
}
}
private static void destroySecurityGroupKeyPairAndInstance(EC2Client client, String name) {
try {
String id = findInstanceByKeyName(client, name).getId();
System.out.printf("%d: %s terminating instance%n", System.currentTimeMillis(), id);
client.getInstanceServices().terminateInstancesInRegion(null, findInstanceByKeyName(client, name).getId());
} catch (NoSuchElementException e) {
} catch (Exception e) {
e.printStackTrace();
}
try {
System.out.printf("%d: %s deleting keypair%n", System.currentTimeMillis(), name);
client.getKeyPairServices().deleteKeyPairInRegion(null, name);
} catch (Exception e) {
e.printStackTrace();
}
try {
System.out.printf("%d: %s deleting group%n", System.currentTimeMillis(), name);
client.getSecurityGroupServices().deleteSecurityGroupInRegion(null, name);
} catch (Exception e) {
e.printStackTrace();
}
}
private static RunningInstance createSecurityGroupKeyPairAndInstance(EC2Client client, String name)
throws TimeoutException {
// create a new security group
createSecurityGroupAndAuthorizePorts(client, name);
// create a new instance
RunningInstance instance = runInstance(client, name, name);
// await for the instance to start
return blockUntilInstanceRunning(client, instance);
}
static void createSecurityGroupAndAuthorizePorts(EC2Client client, String name) {
System.out.printf("%d: creating security group: %s%n", System.currentTimeMillis(), name);
client.getSecurityGroupServices().createSecurityGroupInRegion(null, name, name);
for (int port : new int[] { 80, 8080, 443, 22 }) {
client.getSecurityGroupServices().authorizeSecurityGroupIngressInRegion(null, name, IpProtocol.TCP, port,
port, "0.0.0.0/0");
}
}
static KeyPair createKeyPair(EC2Client client, String name) {
System.out.printf("%d: creating keypair: %s%n", System.currentTimeMillis(), name);
return client.getKeyPairServices().createKeyPairInRegion(null, name);
}
static RunningInstance runInstance(EC2Client client, String securityGroupName, String keyPairName) {
String script = new ScriptBuilder() // lamp install script
.addStatement(exec("runurl run.alestic.com/apt/upgrade"))//
.addStatement(exec("runurl run.alestic.com/install/lamp"))//
.addStatement(exec("apt-get -y install openjdk-6-jdk"))// no license agreement!
.render(OsFamily.UNIX);
System.out.printf("%d: running instance%n", System.currentTimeMillis());
Reservation<? extends RunningInstance> reservation = client.getInstanceServices().runInstancesInRegion(null,
null, // allow ec2 to chose an availability zone
"ami-ccf615a5", // alestic ami allows auto-invoke of user data scripts
1, // minimum instances
1, // maximum instances
asType(InstanceType.M1_SMALL) // smallest instance size
.withKeyName(keyPairName) // key I created above
.withSecurityGroup(securityGroupName) // group I created above
.withUserData(script.getBytes())); // script to run as root
return Iterables.getOnlyElement(reservation);
}
static RunningInstance blockUntilInstanceRunning(EC2Client client, RunningInstance instance) throws TimeoutException {
// create utilities that wait for the instance to finish
RetryablePredicate<RunningInstance> runningTester = new RetryablePredicate<RunningInstance>(
new InstanceStateRunning(client), 180, 5, TimeUnit.SECONDS);
System.out.printf("%d: %s awaiting instance to run %n", System.currentTimeMillis(), instance.getId());
if (!runningTester.apply(instance))
throw new TimeoutException("timeout waiting for instance to run: " + instance.getId());
instance = findInstanceById(client, instance.getId());
RetryablePredicate<HostAndPort> socketTester = new RetryablePredicate<HostAndPort>(new InetSocketAddressConnect(), 300,
1, TimeUnit.SECONDS);
System.out.printf("%d: %s awaiting ssh service to start%n", System.currentTimeMillis(), instance.getIpAddress());
if (!socketTester.apply(HostAndPort.fromParts(instance.getIpAddress(), 22)))
throw new TimeoutException("timeout waiting for ssh to start: " + instance.getIpAddress());
System.out.printf("%d: %s ssh service started%n", System.currentTimeMillis(), instance.getIpAddress());
System.out.printf("%d: %s awaiting http service to start%n", System.currentTimeMillis(), instance.getIpAddress());
if (!socketTester.apply(HostAndPort.fromParts(instance.getIpAddress(), 80)))
throw new TimeoutException("timeout waiting for http to start: " + instance.getIpAddress());
System.out.printf("%d: %s http service started%n", System.currentTimeMillis(), instance.getIpAddress());
return instance;
}
private static RunningInstance findInstanceById(EC2Client client, String instanceId) {
// search my account for the instance I just created
Set<? extends Reservation<? extends RunningInstance>> reservations = client.getInstanceServices()
.describeInstancesInRegion(null, instanceId); // last parameter (ids) narrows the
// search
// since we refined by instanceId there should only be one instance
return Iterables.getOnlyElement(Iterables.getOnlyElement(reservations));
}
private static RunningInstance findInstanceByKeyName(EC2Client client, final String keyName) {
// search my account for the instance I just created
Set<? extends Reservation<? extends RunningInstance>> reservations = client.getInstanceServices()
.describeInstancesInRegion(null);
// extract all the instances from all reservations
Set<RunningInstance> allInstances = Sets.newHashSet();
for (Reservation<? extends RunningInstance> reservation : reservations) {
allInstances.addAll(reservation);
}
// get the first one that has a keyname matching what I just created
return Iterables.find(allInstances, new Predicate<RunningInstance>() {
public boolean apply(RunningInstance input) {
return input.getKeyName().equals(keyName) && input.getInstanceState() != InstanceState.TERMINATED;
}
});
}
}