/***************************************************************************** * Copyright (c) 2008 g-Eclipse Consortium * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Initial development of the original code was made for the * g-Eclipse project founded by European Union * project number: FP6-IST-034327 http://www.geclipse.eu/ * * Contributors: * Moritz Post - initial API and implementation *****************************************************************************/ package eu.geclipse.aws.ec2.service; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import com.xerox.amazonws.ec2.AddressInfo; import com.xerox.amazonws.ec2.GroupDescription; import com.xerox.amazonws.ec2.ImageDescription; import com.xerox.amazonws.ec2.KeyPairInfo; import com.xerox.amazonws.ec2.ReservationDescription; import com.xerox.amazonws.ec2.ReservationDescription.Instance; import eu.geclipse.aws.AWSInfoService; import eu.geclipse.aws.IAWSCategories; import eu.geclipse.aws.auth.AWSAuthTokenDescription; import eu.geclipse.aws.ec2.EC2AMIImage; import eu.geclipse.aws.ec2.EC2ElasticIPAddress; import eu.geclipse.aws.ec2.EC2Instance; import eu.geclipse.aws.ec2.EC2Keypair; import eu.geclipse.aws.ec2.EC2Registry; import eu.geclipse.aws.ec2.EC2SecurityGroup; import eu.geclipse.aws.ec2.IEC2; import eu.geclipse.aws.ec2.IEC2Categories; import eu.geclipse.aws.ec2.internal.Activator; import eu.geclipse.aws.ec2.internal.Messages; import eu.geclipse.aws.ec2.op.AbstractEC2OpDescribeImages; import eu.geclipse.aws.ec2.op.EC2OpDescribeAddresses; import eu.geclipse.aws.ec2.op.EC2OpDescribeImagesByExec; import eu.geclipse.aws.ec2.op.EC2OpDescribeImagesByOwner; import eu.geclipse.aws.ec2.op.EC2OpDescribeInstances; import eu.geclipse.aws.ec2.op.EC2OpDescribeKeypairs; import eu.geclipse.aws.ec2.op.EC2OpDescribeSecurityGroups; import eu.geclipse.aws.ec2.op.OperationExecuter; import eu.geclipse.aws.vo.AWSVirtualOrganization; import eu.geclipse.core.model.IGridContainer; import eu.geclipse.core.model.IGridInfoService; import eu.geclipse.core.model.IGridResource; import eu.geclipse.core.model.IGridResourceCategory; import eu.geclipse.core.model.IVirtualOrganization; import eu.geclipse.core.model.impl.AbstractGridInfoService; import eu.geclipse.core.model.impl.GridResourceCategoryFactory; import eu.geclipse.core.reporting.ProblemException; /** * The {@link EC2InfoService}is used to provide EC2 specific input to the * underlying {@link AWSInfoService}. The elements presented in the VO tree are * <ul> * <li>Available Images</li> * <li>Running Instances</li> * <li>Security Groups</li> * <li>Keypairs</li> * <li>Elastic IPs</li> * </ul> * * @author Moritz Post * @see AWSInfoService */ public class EC2InfoService extends AbstractGridInfoService implements IGridInfoService { /** The identifier of "amazon" as an AMI owner. */ private static final String AMI_OWNER_ALL = "all"; //$NON-NLS-1$ /** The identifier "self" as an AMI owner. */ private static final String AMI_OWNER_SELF = "self"; //$NON-NLS-1$ /** The name of the file to save this grid element in. */ public static String STORAGE_NAME = ".ec2InfoService"; //$NON-NLS-1$ /** * The Vo housing the {@link EC2Service} and thereby this * {@link EC2InfoService}. It is also used to create * {@link AWSAuthTokenDescription}s. */ private AWSVirtualOrganization awsVo; /** * The parent {@link EC2Service} providing connection details for this info * service. */ private EC2Service ec2Service; /** * Creates a new {@link EC2InfoService} by directly setting the various fields * described in the parameter list. * * @param awsVo the vo to use for authentication services * @param ec2Service the parent element to obtain various information from */ public EC2InfoService( final AWSVirtualOrganization awsVo, final EC2Service ec2Service ) { this.awsVo = awsVo; this.ec2Service = ec2Service; } public IGridResource[] fetchResources( final IGridContainer parent, final IVirtualOrganization vo, final IGridResourceCategory category, final boolean exclusive, final Class<? extends IGridResource> typeFilter, final IProgressMonitor monitor ) { IGridResource[] result = null; if( category.equals( GridResourceCategoryFactory.getCategory( IAWSCategories.CATEGORY_AWS_COMPUTING ) ) || category.equals( GridResourceCategoryFactory.getCategory( GridResourceCategoryFactory.ID_COMPUTING ) ) ) { result = fetchInstances( parent, vo, monitor ); } else if( category.equals( GridResourceCategoryFactory.getCategory( IEC2Categories.CATEGORY_EC2_IMAGES_ALL ) ) ) { String[] owner = { EC2InfoService.AMI_OWNER_ALL, EC2InfoService.AMI_OWNER_SELF }; result = fetchImages( parent, vo, monitor, new EC2OpDescribeImagesByExec( getEc2(), owner ) ); } else if( category.equals( GridResourceCategoryFactory.getCategory( IEC2Categories.CATEGORY_EC2_IMAGES_MY_OWNED ) ) ) { String[] owner = { EC2InfoService.AMI_OWNER_SELF }; result = fetchImages( parent, vo, monitor, new EC2OpDescribeImagesByOwner( getEc2(), owner ) ); } else if( category.equals( GridResourceCategoryFactory.getCategory( IEC2Categories.CATEGORY_EC2_IMAGES_MY_ACCESSIBLE ) ) ) { String[] owner = { EC2InfoService.AMI_OWNER_SELF }; result = fetchImages( parent, vo, monitor, new EC2OpDescribeImagesByExec( getEc2(), owner ) ); } else if( category.equals( GridResourceCategoryFactory.getCategory( IEC2Categories.CATEGORY_EC2_SECURITY_GROUPS ) ) ) { result = fetchSecurityGroups( parent, vo, monitor ); } else if( category.equals( GridResourceCategoryFactory.getCategory( IEC2Categories.CATEGORY_EC2_KEYPAIRS ) ) ) { result = fetchKeypairs( parent, vo, monitor ); } else if( category.equals( GridResourceCategoryFactory.getCategory( IEC2Categories.CATEGORY_EC2_ELASTIC_IP ) ) ) { result = fetchElasticIPs( parent, vo, monitor ); } if (result == null) result = new IGridResource[0]; return result; } /** * Fetches the list of remotely existing EC2 security groups and transforms * them into {@link EC2SecurityGroup}s. * * @param parent the parent housing this {@link EC2InfoService} * @param vo the vo providing the {@link EC2InfoService} * @param monitor the monitor to be informed of progress * @return the resulting array of {@link EC2SecurityGroup}s */ private EC2SecurityGroup[] fetchSecurityGroups( final IGridContainer parent, final IVirtualOrganization vo, IProgressMonitor monitor ) { if( monitor == null ) { monitor = new NullProgressMonitor(); } // fetch existing security groups from EC2 service monitor.beginTask( Messages.getString( "EC2InfoService.monitor_task_description" ), //$NON-NLS-1$ 2 ); EC2OpDescribeSecurityGroups opDescSecurityGroups = new EC2OpDescribeSecurityGroups( getEc2() ); new OperationExecuter().execOp( opDescSecurityGroups ); monitor.worked( 1 ); if( opDescSecurityGroups.getException() == null ) { // transform answer into gEclipse format ArrayList<EC2SecurityGroup> resultSecurityGroups = new ArrayList<EC2SecurityGroup>( opDescSecurityGroups.getResult() .size() ); for( GroupDescription groupDesc : opDescSecurityGroups.getResult() ) { resultSecurityGroups.add( new EC2SecurityGroup( parent, this.ec2Service, groupDesc ) ); } monitor.worked( 2 ); monitor.done(); return resultSecurityGroups.toArray( new EC2SecurityGroup[ resultSecurityGroups.size() ] ); } return null; } /** * Fetches the list of remotely existing EC2 keypairs and transforms them into * {@link EC2Keypair}s. * * @param parent the parent housing this {@link EC2InfoService} * @param vo the vo providing the {@link EC2InfoService} * @param monitor the monitor to be informed of progress * @return the resulting array of {@link EC2Keypair}s */ private EC2Keypair[] fetchKeypairs( final IGridContainer parent, final IVirtualOrganization vo, IProgressMonitor monitor ) { if( monitor == null ) { monitor = new NullProgressMonitor(); } // fetch existing security groups from EC2 service monitor.beginTask( Messages.getString( "EC2InfoService.monitor_task_description" ), //$NON-NLS-1$ 2 ); EC2OpDescribeKeypairs opDescKeypairs = new EC2OpDescribeKeypairs( getEc2() ); new OperationExecuter().execOp( opDescKeypairs ); monitor.worked( 1 ); if( opDescKeypairs.getException() == null ) { // transform answer into gEclipse format ArrayList<EC2Keypair> resultKeypairs = new ArrayList<EC2Keypair>( opDescKeypairs.getResult() .size() ); for( KeyPairInfo keyPairInfo : opDescKeypairs.getResult() ) { resultKeypairs.add( new EC2Keypair( parent, this.ec2Service, keyPairInfo ) ); } monitor.worked( 2 ); monitor.done(); return resultKeypairs.toArray( new EC2Keypair[ resultKeypairs.size() ] ); } return null; } /** * Fetches the list of remotely existing Elastic IP addresses and transforms * them into {@link EC2ElasticIPAddress}s. * * @param parent the parent housing this {@link EC2InfoService} * @param vo the vo providing the {@link EC2InfoService} * @param monitor the monitor to be informed of progress * @return the resulting array of {@link EC2ElasticIPAddress}s */ private EC2ElasticIPAddress[] fetchElasticIPs( final IGridContainer parent, final IVirtualOrganization vo, IProgressMonitor monitor ) { if( monitor == null ) { monitor = new NullProgressMonitor(); } // fetch existing addresses from EC2 service monitor.beginTask( Messages.getString( "EC2InfoService.monitor_task_description" ), //$NON-NLS-1$ 2 ); EC2OpDescribeAddresses opDescAddresses = new EC2OpDescribeAddresses( getEc2() ); new OperationExecuter().execOp( opDescAddresses ); monitor.worked( 1 ); if( opDescAddresses.getException() == null ) { // transform answer into gEclipse format ArrayList<EC2ElasticIPAddress> resultAddresses = new ArrayList<EC2ElasticIPAddress>( opDescAddresses.getResult() .size() ); for( AddressInfo addressInfo : opDescAddresses.getResult() ) { resultAddresses.add( new EC2ElasticIPAddress( parent, this.ec2Service, addressInfo ) ); } monitor.worked( 2 ); monitor.done(); return resultAddresses.toArray( new EC2ElasticIPAddress[ resultAddresses.size() ] ); } return null; } /** * Fetches an IEC2 instance from the {@link EC2Registry}. The initiator of * the fetch process is the {@link AWSVirtualOrganization} with its contained * aws access id, which is used for the mapping from the user to an instance * of an {@link IEC2}. * * @return the obtained {@link IEC2} instance */ private IEC2 getEc2() { IEC2 ec2 = null; try { EC2Registry ec2Registry = EC2Registry.getRegistry(); ec2 = ec2Registry.getEC2( this.awsVo ); } catch( ProblemException problemEx ) { Activator.log( "Could not obtain EC2 instance", problemEx ); //$NON-NLS-1$ } return ec2; } /** * Fetches all running instances from the EC2 service. * * @param parent the parent in the grid model * @param vo the VO to use for accessing the services * @param monitor a monitor to track progress * @return an array of fetched {@link EC2Instance} */ public IGridResource[] fetchInstances( final IGridContainer parent, final IVirtualOrganization vo, IProgressMonitor monitor ) { if( monitor == null ) { monitor = new NullProgressMonitor(); } // fetch existing instances from EC2 service monitor.beginTask( Messages.getString( "EC2InfoService.monitor_task_description" ), //$NON-NLS-1$ 2 ); EC2OpDescribeInstances opDescInstances = new EC2OpDescribeInstances( getEc2() ); new OperationExecuter().execOp( opDescInstances ); monitor.worked( 1 ); if( opDescInstances.getException() == null ) { // transform answer into gEclipse format ArrayList<EC2Instance> resultComputingElements = new ArrayList<EC2Instance>( opDescInstances.getResult() .size() ); for( ReservationDescription reservationDesc : opDescInstances.getResult() ) { for( Instance instance : reservationDesc.getInstances() ) { resultComputingElements.add( new EC2Instance( parent, this.ec2Service, instance ) ); } } monitor.worked( 2 ); monitor.done(); return resultComputingElements.toArray( new IGridResource[ resultComputingElements.size() ] ); } return null; } /** * Fetches the available AMIs of the EC2 service using the owner as a filter. * * @param parent the parent of this {@link IGridInfoService} * @param vo the vo initiating the query * @param monitor the monitor to notify of progress * @param operation the operation to execute * @return an array of {@link EC2AMIImage}s. */ public IGridResource[] fetchImages( final IGridContainer parent, final IVirtualOrganization vo, IProgressMonitor monitor, final AbstractEC2OpDescribeImages operation ) { if( monitor == null ) { monitor = new NullProgressMonitor(); } // fetch existing AMI images from EC2 service monitor.beginTask( Messages.getString( "EC2InfoService.monitor_task_description" ), //$NON-NLS-1$ 2 ); new OperationExecuter().execOp( operation ); monitor.worked( 1 ); if( operation.getException() == null ) { // transform answer into gEclipse format ArrayList<IGridResource> resultGridService = new ArrayList<IGridResource>( operation.getResult() .size() ); for( ImageDescription imageDescription : operation.getResult() ) { resultGridService.add( new EC2AMIImage( parent, this.ec2Service, imageDescription ) ); } monitor.worked( 2 ); monitor.done(); return resultGridService.toArray( new IGridResource[ resultGridService.size() ] ); } return null; } public String getHostName() { try { EC2ServiceProperties properties = this.ec2Service.getProperties(); if( properties != null ) { return properties.getEc2Url(); } } catch( ProblemException problemEx ) { Activator.log( "Could not load properties from ec2Service", problemEx ); //$NON-NLS-1$ } return null; } public URI getURI() { String hostName = getHostName(); try { if( hostName != null ) { return new URI( hostName ); } } catch( URISyntaxException uriEx ) { Activator.log( "Could not creat URI from " + hostName, uriEx ); //$NON-NLS-1$ } return null; } public IFileStore getFileStore() { return getParent().getFileStore().getChild( EC2InfoService.STORAGE_NAME ); } public String getName() { return EC2InfoService.STORAGE_NAME; } public IGridContainer getParent() { return this.ec2Service; } public IPath getPath() { return getParent().getPath().append( EC2InfoService.STORAGE_NAME ); } public IResource getResource() { return null; } public boolean isLocal() { return false; } }