package org.codehaus.mojo.ec2;
/*
* Copyright 2008 Exist Global, Inc.
*
* 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.
*/
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.xerox.amazonws.ec2.EC2Exception;
import com.xerox.amazonws.ec2.Jec2;
import com.xerox.amazonws.ec2.ReservationDescription;
import com.xerox.amazonws.ec2.ReservationDescription.Instance;
/**
* Mojo to start Amazon EC2 instances
*
* @goal start
* @author Carlos Sanchez <carlos@apache.org>
*/
public class Ec2StartMojo
extends AbstractEc2Mojo
{
final Logger logger = LoggerFactory.getLogger( Ec2StartMojo.class );
/**
* @parameter
*/
private List<LaunchConfiguration> launchConfigurations;
public void doExecute( Jec2 ec2 )
throws MojoExecutionException, MojoFailureException
{
try
{
List<Instance> instancesStarted = new ArrayList<Instance>( launchConfigurations.size() );
List<Instance> instancesToWaitFor = new ArrayList<Instance>( launchConfigurations.size() );
List<Instance> instancesToTerminate = new ArrayList<Instance>( launchConfigurations.size() );
Map<Instance, String> instanceIp = new HashMap<Instance, String>();
for ( LaunchConfiguration lc : launchConfigurations )
{
if ( lc.getImageId() == null )
{
throw new MojoFailureException( "You must specify the imageId in the <launchConfiguration>" );
}
ReservationDescription reservation = ec2.runInstances( lc );
instancesStarted.addAll( reservation.getInstances() );
if ( lc.isWait() )
{
instancesToWaitFor.addAll( reservation.getInstances() );
}
if ( lc.isTerminate() )
{
instancesToTerminate.addAll( reservation.getInstances() );
}
if ( lc.getElasticIp() != null )
{
int s = reservation.getInstances().size();
if ( s != 1 )
{
logger.warn( "Tried to assign elatic IP to " + ( s > 1 ? "more than one image" : "zero images" ) );
}
else
{
instanceIp.put( reservation.getInstances().get( 0 ), lc.getElasticIp() );
}
}
}
if ( logger.isInfoEnabled() )
{
for ( Instance instance : instancesStarted )
{
logger.info( "Starting AMI {}", instance.getImageId() );
}
}
if ( !instancesToTerminate.isEmpty() )
{
TerminateInstancesThread.addShutdownHook( ec2, instancesToTerminate );
}
waitForInstancesToStart( ec2, instancesToWaitFor );
associateElasticIps( ec2, instanceIp );
}
catch ( EC2Exception e )
{
throw new MojoExecutionException( "Exception in EC2: " + e.getMessage(), e );
}
}
/**
* wait for instances to be started
*
* @throws MojoExecutionException
*/
private void waitForInstancesToStart( Jec2 ec2, List<Instance> instances )
throws MojoExecutionException
{
List<String> instanceIds = new ArrayList<String>( instances.size() );
for ( Instance instance : instances )
{
instanceIds.add( instance.getInstanceId() );
}
while ( !instanceIds.isEmpty() )
{
try
{
for ( ReservationDescription description : ec2.describeInstances( instanceIds ) )
{
for ( Instance currentInstance : description.getInstances() )
{
if ( currentInstance.isRunning() )
{
instanceIds.remove( currentInstance.getInstanceId() );
}
}
}
}
catch ( EC2Exception e )
{
throw new MojoExecutionException( "Error describing instances " + instanceIds, e );
}
if ( instanceIds.isEmpty() )
{
return;
}
try
{
logger.info( "Waiting for instances to start: {}", instanceIds );
Thread.sleep( 10 * 1000 ); // 10 sec
}
catch ( InterruptedException e )
{
throw new MojoExecutionException( "Poll for available interrupted : " + e.getMessage(), e );
}
}
}
private void associateElasticIps( Jec2 ec2, Map<Instance, String> instanceIp )
throws MojoExecutionException
{
for ( Map.Entry<Instance, String> entry : instanceIp.entrySet() )
{
String ip = entry.getValue();
String instanceId = entry.getKey().getInstanceId();
try
{
ec2.associateAddress( instanceId, ip );
}
catch ( EC2Exception e )
{
throw new MojoExecutionException( "Exception trying to associate ip " + ip + " to instance "
+ instanceId, e );
}
}
}
private void waitForPort( Instance instance, int port )
{
InetSocketAddress address = new InetSocketAddress( instance.getDnsName(), port );
Socket s = null;
try
{
s = new Socket();
s.connect( address, 5 * 1000 );
return;
}
catch ( IOException e )
{
// wait
}
finally
{
try
{
if ( s != null )
{
s.close();
}
}
catch ( IOException e )
{
}
}
}
}