Issue 29: supports basic operations

git-svn-id: http://jclouds.googlecode.com/svn/trunk@2236 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-11-09 03:39:28 +00:00
parent 870becd3f1
commit 78d72fae49
74 changed files with 6844 additions and 921 deletions

View File

@ -21,22 +21,24 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.ec2.config;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
package org.jclouds.aws.ec2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* designates the the module configures a {@link org.jclouds.aws.ec2.EC2Connection}
* Related to a EC2 resource.
*
* @author Adrian Cole
*
*/
@Retention(RUNTIME)
@Target(TYPE)
public @interface EC2ConnectionModule {
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Qualifier
public @interface EC2 {
}
}

View File

@ -0,0 +1,461 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2;
import static org.jclouds.aws.ec2.reference.EC2Parameters.ACTION;
import static org.jclouds.aws.ec2.reference.EC2Parameters.VERSION;
import java.util.SortedSet;
import java.util.concurrent.Future;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.jclouds.aws.ec2.binders.BindGroupNameToIndexedFormParams;
import org.jclouds.aws.ec2.binders.BindInstanceIdsToIndexedFormParams;
import org.jclouds.aws.ec2.binders.BindKeyNameToIndexedFormParams;
import org.jclouds.aws.ec2.binders.BindUserIdGroupPairToSourceSecurityGroupFormParams;
import org.jclouds.aws.ec2.domain.Image;
import org.jclouds.aws.ec2.domain.IpProtocol;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.SecurityGroup;
import org.jclouds.aws.ec2.domain.TerminatedInstance;
import org.jclouds.aws.ec2.domain.UserIdGroupPair;
import org.jclouds.aws.ec2.filters.FormSigner;
import org.jclouds.aws.ec2.functions.ReturnVoidOnGroupNotFound;
import org.jclouds.aws.ec2.options.DescribeImagesOptions;
import org.jclouds.aws.ec2.options.RunInstancesOptions;
import org.jclouds.aws.ec2.xml.DescribeImagesResponseHandler;
import org.jclouds.aws.ec2.xml.DescribeInstancesResponseHandler;
import org.jclouds.aws.ec2.xml.DescribeKeyPairsResponseHandler;
import org.jclouds.aws.ec2.xml.DescribeSecurityGroupsResponseHandler;
import org.jclouds.aws.ec2.xml.KeyPairResponseHandler;
import org.jclouds.aws.ec2.xml.RunInstancesResponseHandler;
import org.jclouds.aws.ec2.xml.TerminateInstancesResponseHandler;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
/**
* Provides access to EC2 via their REST API.
* <p/>
*
* @author Adrian Cole
*/
@Endpoint(EC2.class)
@RequestFilters(FormSigner.class)
@FormParams(keys = VERSION, values = "2009-08-15")
@VirtualHost
public interface EC2Client {
/**
* Returns information about AMIs, AKIs, and ARIs. This includes image type, product codes,
* architecture, and kernel and RAM disk IDs. Images available to you include p ublic images,
* private images that you own, and private images owned by other users for which you have
* explicit launch permissions.
*
* @see #describeInstances
* @see #describeImageAttribute
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeImages.html"
* />
* @see DescribeImagesOptions
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DescribeImages")
@XMLResponseParser(DescribeImagesResponseHandler.class)
Future<? extends SortedSet<Image>> describeImages(DescribeImagesOptions... options);
/**
* Returns information about instances that you own.
* <p/>
*
* If you specify one or more instance IDs, Amazon EC2 returns information for those instances.
* If you do not specify instance IDs, Amazon EC2 returns information for all relevant instances.
* If you specify an invalid instance ID, a fault is returned. If you specify an instance that
* you do not own, it will not be included in the returned results.
* <p/>
* Recently terminated instances might appear in the returned results.This interval is usually
* less than one hour.
*
* @see #runInstances
* @see #terminateInstances
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeInstances.html"
* />
* @see DescribeInstancesOptions
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DescribeInstances")
@XMLResponseParser(DescribeInstancesResponseHandler.class)
Future<? extends SortedSet<Reservation>> describeInstances(
@BinderParam(BindInstanceIdsToIndexedFormParams.class) String... instanceIds);
/**
* Launches a specified number of instances of an AMI for which you have permissions.
* <p/>
*
* If Amazon EC2 cannot launch the minimum number AMIs you request, no instances will be
* launched. If there is insufficient capacity to launch the maximum number of AMIs you request,
* Amazon EC2 launches the minimum number specified for each AMI and allocate the remaining
* available instances using round robin.
* <p/>
* <h4>Security Groups</h4>
* <b>Note:</b> Every instance is launched in a security group (created using the
* CreateSecurityGroup operation.
* <h4>Key Pair</h4>
* You can provide an optional key pair ID for each image in the launch request (created using
* the CreateKeyPair operation). All instances that are created from images that use this key
* pair will have access to the associated public key at boot. You can use this key to provide
* secure access to an instance of an image on a per-instance basis. Amazon EC2 public images use
* this feature to provide secure access without passwords.
* <p/>
* <b>Note:</b> Launching public images without a key pair ID will leave them inaccessible.
* <p/>
* The public key material is made available to the instance at boot time by placing it in the
* openssh_id.pub file on a logical device that is exposed to the instance as /dev/sda2 (the
* instance store). The format of this file is suitable for use as an entry within
* ~/.ssh/authorized_keys (the OpenSSH format). This can be done at boot (e.g., as part of
* rc.local) allowing for secure access without passwords.
* <h4>User Data</h4>
* Optional user data can be provided in the launch request. All instances that collectively
* comprise the launch request have access to this data. For more information, go the Amazon
* Elastic Compute Cloud Developer Guide.
* <h4>Product Codes</h4>
*
* <b>Note:</b> If any of the AMIs have a product code attached for which the user has not
* subscribed, the RunInstances call will fail.
* <h4>Kernel</h4>
*
* <b>Important:</b> We strongly recommend using the 2.6.18 Xen stock kernel with High-CPU and
* High-Memory instances. Although the default Amazon EC2 kernels will work, the new kernels
* provide greater stability and performance for these instance types. For more information about
* kernels, go the Amazon Elastic Compute Cloud Developer Guide.
*
* @param imageId
* Unique ID of a machine image, returned by a call to
* @param minCount
* Minimum number of instances to launch. If the value is more than Amazon EC2 can
* launch, no instances a re launched at all. Constraints: Between 1 and the maximum
* number allowed for your account (default: 20).
* @param maxCount
* Maximum number of instances to launch. If the value is more than Amazon EC2 can
* launch, the largest possible number above minCount will be launched instead.
* Constraints: Between 1 and the maximum number allowed for your account (default:
* 20).
* @see #describeInstances
* @see #terminateInstances
* @see #authorizeSecurityGroupIngress
* @see #revokeSecurityGroupIngress
* @see #describeSecurityGroups
* @see #createSecurityGroup
* @see #createKeyPair
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-RunInstances.html"
* />
* @see RunInstancesOptions
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "RunInstances")
@XMLResponseParser(RunInstancesResponseHandler.class)
Future<Reservation> runInstances(@FormParam("ImageId") String imageId,
@FormParam("MinCount") int minCount, @FormParam("MaxCount") int maxCount,
RunInstancesOptions... options);
/**
* Shuts down one or more instances. This operation is idempotent; if you terminate an instance
* more than once, each call will succeed.
* <p/>
* Terminated instances will remain visible after termination (approximately one hour).
*
* @param instanceIds
* Instance ID to terminate.
* @see #describeInstances
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-TerminateInstances.html"
* />
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "TerminateInstances")
@XMLResponseParser(TerminateInstancesResponseHandler.class)
Future<? extends SortedSet<TerminatedInstance>> terminateInstances(
@FormParam("InstanceId.0") String instanceId,
@BinderParam(BindInstanceIdsToIndexedFormParams.class) String... instanceIds);
/**
* Creates a new 2048-bit RSA key pair with the specified name. The public key is stored by
* Amazon EC2 and the private key is displayed on the console. The private key is returned as an
* unencrypted PEM encoded PKCS#8 private key. If a key with the specified name already exists,
* Amazon EC2 returns an error.
*
* @see #runInstances
* @see #describeKeyPairs
* @see #deleteKeyPair
*
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CreateKeyPair.html"
* />
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "CreateKeyPair")
@XMLResponseParser(KeyPairResponseHandler.class)
Future<KeyPair> createKeyPair(@FormParam("KeyName") String keyName);
/**
* Returns information about key pairs available to you. If you specify key pairs, information
* about those key pairs is returned. Otherwise, information for all registered key pairs is
* returned.
*
* @param keyPairNames
* Key pairs to describe.
* @see #runInstances
* @see #describeAvailabilityZones
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeKeyPairs.html"
* />
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DescribeKeyPairs")
@XMLResponseParser(DescribeKeyPairsResponseHandler.class)
Future<? extends SortedSet<KeyPair>> describeKeyPairs(
@BinderParam(BindKeyNameToIndexedFormParams.class) String... keyPairNames);
/**
* Deletes the specified key pair, by removing the public key from Amazon EC2. You must own the
* key pair
*
* @see #describeKeyPairs
* @see #createKeyPair
*
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DeleteKeyPair.html"
* />
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DeleteKeyPair")
Future<Void> deleteKeyPair(@FormParam("KeyName") String keyName);
/**
* Creates a new security group. Group names must be unique per account.
*
* @param name
* Name of the security group. Accepts alphanumeric characters, spaces, dashes, and
* underscores.
* @param description
* Description of the group. This is informational only. If the description contains
* spaces, you must enc lose it in single quotes (') or URL-encode it. Accepts
* alphanumeric characters, spaces, dashes, and underscores.
* @see #runInstances
* @see #describeSecurityGroups
* @see #authorizeSecurityGroupIngress
* @see #revokeSecurityGroupIngress
* @see #deleteSecurityGroup
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CreateSecurityGroup.html"
* />
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "CreateSecurityGroup")
Future<Void> createSecurityGroup(@FormParam("GroupName") String name,
@FormParam("GroupDescription") String description);
/**
* Deletes a security group that you own.
*
* @param name
* Name of the security group to delete.
*
* @see #describeSecurityGroups
* @see #authorizeSecurityGroupIngress
* @see #revokeSecurityGroupIngress
* @see #createSecurityGroup
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DeleteSecurityGroup.html"
* />
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DeleteSecurityGroup")
@ExceptionParser(ReturnVoidOnGroupNotFound.class)
Future<Void> deleteSecurityGroup(@FormParam("GroupName") String name);
/**
* Returns information about security groups that you own.
*
* @param securityGroupNames
* Name of the security groups
*
* @see #createSecurityGroup
* @see #authorizeSecurityGroupIngress
* @see #revokeSecurityGroupIngress
* @see #deleteSecurityGroup
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSecurityGroups.html"
* />
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DescribeSecurityGroups")
@XMLResponseParser(DescribeSecurityGroupsResponseHandler.class)
Future<? extends SortedSet<SecurityGroup>> describeSecurityGroups(
@BinderParam(BindGroupNameToIndexedFormParams.class) String... securityGroupNames);
/**
*
* Adds permissions to a security group based on another group.
*
* @param groupName
* Name of the group to modify. The name must be valid and belong to the account
* @param sourceSecurityGroup
* group to associate with this group.
*
* @see #createSecurityGroup
* @see #describeSecurityGroups
* @see #revokeSecurityGroupIngress
* @see #deleteSecurityGroup
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-AuthorizeSecurityGroupIngress.html"
*
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "AuthorizeSecurityGroupIngress")
Future<Void> authorizeSecurityGroupIngress(
@FormParam("GroupName") String groupName,
@BinderParam(BindUserIdGroupPairToSourceSecurityGroupFormParams.class) UserIdGroupPair sourceSecurityGroup);
/**
*
* Adds permissions to a security group.
* <p/>
* Permissions are specified by the IP protocol (TCP, UDP or ICMP), the source of the request (by
* IP range or an Amazon EC2 user-group pair), the source and destination port ranges (for TCP
* and UDP), and the ICMP codes and types (for ICMP). When authorizing ICMP, -1 can be used as a
* wildcard in the type and code fields. Permission changes are propagated to instances within
* the security group as quickly as possible. However, depending on the number of instances, a
* small delay might occur.
*
* @param groupName
* Name of the group to modify. The name must be valid and belong to the account
* @param ipProtocol
* IP protocol.
* @param fromPort
* Start of port range for the TCP and UDP protocols, or an ICMP type number. An ICMP
* type number of -1 indicates a wildcard (i.e., any ICMP type number).
* @param toPort
* End of port range for the TCP and UDP protocols, or an ICMP code. An ICMP code of -1
* indicates a wildcard (i.e., any ICMP code).
* @param cidrIp
* CIDR range.
*
* @see #createSecurityGroup
* @see #describeSecurityGroups
* @see #revokeSecurityGroupIngress
* @see #deleteSecurityGroup
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-AuthorizeSecurityGroupIngress.html"
*
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "AuthorizeSecurityGroupIngress")
Future<Void> authorizeSecurityGroupIngress(@FormParam("GroupName") String groupName,
@FormParam("IpProtocol") IpProtocol ipProtocol, @FormParam("FromPort") int fromPort,
@FormParam("ToPort") int toPort, @FormParam("CidrIp") String cidrIp);
/**
*
* Revokes permissions from a security group. The permissions used to revoke must be specified
* using the same values used to grant the permissions.
*
* @param groupName
* Name of the group to modify. The name must be valid and belong to the account
* @param sourceSecurityGroup
* group to associate with this group.
*
* @see #createSecurityGroup
* @see #describeSecurityGroups
* @see #authorizeSecurityGroupIngress
* @see #deleteSecurityGroup
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-RevokeSecurityGroupIngress.html"
*
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "RevokeSecurityGroupIngress")
Future<Void> revokeSecurityGroupIngress(
@FormParam("GroupName") String groupName,
@BinderParam(BindUserIdGroupPairToSourceSecurityGroupFormParams.class) UserIdGroupPair sourceSecurityGroup);
/**
*
* Revokes permissions from a security group. The permissions used to revoke must be specified
* using the same values used to grant the permissions.
* <p/>
* Permissions are specified by IP protocol (TCP, UDP, or ICMP), the source of the request (by IP
* range or an Amazon EC2 user-group pair), the source and destination port ranges (for TCP and
* UDP), and the ICMP codes and types (for ICMP).
*
* Permission changes are quickly propagated to instances within the security group. However,
* depending on the number of instances in the group, a small delay is might occur.
*
* @param groupName
* Name of the group to modify. The name must be valid and belong to the account
* @param ipProtocol
* IP protocol.
* @param fromPort
* Start of port range for the TCP and UDP protocols, or an ICMP type number. An ICMP
* type number of -1 indicates a wildcard (i.e., any ICMP type number).
* @param toPort
* End of port range for the TCP and UDP protocols, or an ICMP code. An ICMP code of -1
* indicates a wildcard (i.e., any ICMP code).
* @param cidrIp
* CIDR range.
*
* @see #createSecurityGroup
* @see #describeSecurityGroups
* @see #authorizeSecurityGroupIngress
* @see #deleteSecurityGroup
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-RevokeSecurityGroupIngress.html"
*
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "RevokeSecurityGroupIngress")
Future<Void> revokeSecurityGroupIngress(@FormParam("GroupName") String groupName,
@FormParam("IpProtocol") IpProtocol ipProtocol, @FormParam("FromPort") int fromPort,
@FormParam("ToPort") int toPort, @FormParam("CidrIp") String cidrIp);
}

View File

@ -0,0 +1,62 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_ACCESSKEYID;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_SECRETACCESSKEY;
import java.util.List;
import java.util.Properties;
import org.jclouds.aws.ec2.config.EC2ContextModule;
import org.jclouds.aws.ec2.config.EC2RestClientModule;
import org.jclouds.rest.RestContextBuilder;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
*
* @author Adrian Cole
*/
public class EC2ContextBuilder extends RestContextBuilder<EC2Client> {
public EC2ContextBuilder(Properties props) {
super(new TypeLiteral<EC2Client>() {
}, props);
checkNotNull(properties.getProperty(PROPERTY_AWS_ACCESSKEYID));
checkNotNull(properties.getProperty(PROPERTY_AWS_SECRETACCESSKEY));
}
protected void addClientModule(List<Module> modules) {
modules.add(new EC2RestClientModule());
}
@Override
protected void addContextModule(List<Module> modules) {
modules.add(new EC2ContextModule());
}
}

View File

@ -0,0 +1,66 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2;
import java.net.URI;
import java.util.Properties;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.rest.RestContext;
import com.google.inject.Module;
/**
* Creates {@link RestContext} instances bound with generic type {@link EC2Client} based on the most
* commonly requested arguments.
* <p/>
* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided.
* <p/>
* <p/>
* If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
* {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
*
* @author Adrian Cole
* @see RestContext
*/
public class EC2ContextFactory {
public static RestContext<EC2Client> createContext(Properties properties, Module... modules) {
return new EC2ContextBuilder(new EC2PropertiesBuilder(properties).build()).withModules(
modules).buildContext();
}
public static RestContext<EC2Client> createContext(String awsAccessKeyId,
String awsSecretAccessKey, Module... modules) {
return new EC2ContextBuilder(new EC2PropertiesBuilder(awsAccessKeyId, awsSecretAccessKey)
.build()).withModules(modules).buildContext();
}
public static RestContext<EC2Client> createContext(URI endpoint, String awsAccessKeyId,
String awsSecretAccessKey, Module... modules) {
return new EC2ContextBuilder(new EC2PropertiesBuilder(awsAccessKeyId, awsSecretAccessKey)
.withEndpoint(endpoint).build()).withModules(modules).buildContext();
}
}

View File

@ -0,0 +1,76 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_EC2_ENDPOINT;
import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_EC2_EXPIREINTERVAL;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_ACCESSKEYID;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_SECRETACCESSKEY;
import java.net.URI;
import java.util.Properties;
import org.jclouds.http.HttpPropertiesBuilder;
/**
* Builds properties used in EC2 Clients
*
* @author Adrian Cole
*/
public class EC2PropertiesBuilder extends HttpPropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_EC2_ENDPOINT, "http://ec2.amazonaws.com");
properties.setProperty(PROPERTY_EC2_EXPIREINTERVAL, "60");
return properties;
}
public EC2PropertiesBuilder(Properties properties) {
super(properties);
}
public EC2PropertiesBuilder(String id, String secret) {
super();
withCredentials(id, secret);
}
public EC2PropertiesBuilder withCredentials(String id, String secret) {
properties.setProperty(PROPERTY_AWS_ACCESSKEYID, checkNotNull(id, "awsAccessKeyId"));
properties.setProperty(PROPERTY_AWS_SECRETACCESSKEY, checkNotNull(secret,
"awsSecretAccessKey"));
return this;
}
public EC2PropertiesBuilder withEndpoint(URI endpoint) {
properties.setProperty(PROPERTY_EC2_ENDPOINT, checkNotNull(endpoint, "endpoint").toString());
return this;
}
public EC2PropertiesBuilder withRequestExpiration(long seconds) {
properties.setProperty(PROPERTY_EC2_EXPIREINTERVAL, seconds + "");
return this;
}
}

View File

@ -0,0 +1,26 @@
package org.jclouds.aws.ec2.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder;
import org.jclouds.rest.internal.GeneratedHttpRequest;
/**
* Binds the String [] to query parameters named with GroupName.index
*
* @author Adrian Cole
* @since 4.0
*/
public class BindGroupNameToIndexedFormParams implements Binder {
@SuppressWarnings("unchecked")
public void bindToRequest(HttpRequest request, Object input) {
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!");
EC2Utils.indexFormValuesWithPrefix((GeneratedHttpRequest<?>) request, "GroupName", input);
}
}

View File

@ -0,0 +1,26 @@
package org.jclouds.aws.ec2.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder;
import org.jclouds.rest.internal.GeneratedHttpRequest;
/**
* Binds the String [] to form parameters named with InstanceId.index
*
* @author Adrian Cole
* @since 4.0
*/
public class BindInstanceIdsToIndexedFormParams implements Binder {
@SuppressWarnings("unchecked")
public void bindToRequest(HttpRequest request, Object input) {
checkArgument(checkNotNull(request, "input") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!");
EC2Utils.indexFormValuesWithPrefix((GeneratedHttpRequest<?>) request, "InstanceId", input);
}
}

View File

@ -0,0 +1,26 @@
package org.jclouds.aws.ec2.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder;
import org.jclouds.rest.internal.GeneratedHttpRequest;
/**
* Binds the String [] to query parameters named with KeyName.index
*
* @author Adrian Cole
* @since 4.0
*/
public class BindKeyNameToIndexedFormParams implements Binder {
@SuppressWarnings("unchecked")
public void bindToRequest(HttpRequest request, Object input) {
checkArgument(checkNotNull(request, "input") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!");
EC2Utils.indexFormValuesWithPrefix((GeneratedHttpRequest<?>) request, "KeyName", input);
}
}

View File

@ -0,0 +1,30 @@
package org.jclouds.aws.ec2.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.aws.ec2.domain.UserIdGroupPair;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder;
import org.jclouds.rest.internal.GeneratedHttpRequest;
/**
* Binds the String [] to query parameters named with GroupName.index
*
* @author Adrian Cole
* @since 4.0
*/
public class BindUserIdGroupPairToSourceSecurityGroupFormParams implements Binder {
@SuppressWarnings("unchecked")
public void bindToRequest(HttpRequest request, Object input) {
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!");
checkArgument(checkNotNull(input, "input") instanceof UserIdGroupPair,
"this binder is only valid for UserIdGroupPair!");
UserIdGroupPair pair = (UserIdGroupPair) input;
GeneratedHttpRequest generatedRequest = (GeneratedHttpRequest) request;
generatedRequest.addFormParam("SourceSecurityGroupOwnerId", pair.getUserId());
generatedRequest.addFormParam("SourceSecurityGroupName", pair.getGroupName());
}
}

View File

@ -21,57 +21,41 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.ec2.internal;
package org.jclouds.aws.ec2.config;
import java.io.IOException;
import java.net.URI;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.EC2Connection;
import org.jclouds.aws.ec2.EC2Context;
import org.jclouds.aws.ec2.EC2;
import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.reference.AWSConstants;
import org.jclouds.http.functions.config.ParserModule.CDateTimeAdapter;
import org.jclouds.http.functions.config.ParserModule.DateTimeAdapter;
import org.jclouds.lifecycle.Closer;
import org.jclouds.logging.Logger;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.RestContextImpl;
import javax.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
/**
* Uses a Guice Injector to configure the objects served by EC2Context methods.
* Configures the EC2 connection, including logging and http transport.
*
* @author Adrian Cole
* @see Injector
*/
public class GuiceEC2Context implements EC2Context {
@Resource
private Logger logger = Logger.NULL;
private final Injector injector;
private final Closer closer;
@Inject
private GuiceEC2Context(Injector injector, Closer closer) {
this.injector = injector;
this.closer = closer;
public class EC2ContextModule extends AbstractModule {
@Override
protected void configure() {
bind(DateTimeAdapter.class).to(CDateTimeAdapter.class);
}
/**
* {@inheritDoc}
*/
public EC2Connection getConnection() {
return injector.getInstance(EC2Connection.class);
@Provides
@Singleton
RestContext<EC2Client> provideContext(Closer closer, EC2Client defaultApi, @EC2 URI endPoint,
@Named(AWSConstants.PROPERTY_AWS_ACCESSKEYID) String account) {
return new RestContextImpl<EC2Client>(closer, defaultApi, endPoint, account);
}
/**
* {@inheritDoc}
*
* @see Closer
*/
public void close() {
try {
closer.close();
} catch (IOException e) {
logger.error(e, "error closing content");
}
}
}
}

View File

@ -0,0 +1,110 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.config;
import java.net.URI;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.EC2;
import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.filters.FormSigner;
import org.jclouds.aws.ec2.reference.EC2Constants;
import org.jclouds.aws.handlers.AWSClientErrorRetryHandler;
import org.jclouds.aws.handlers.AWSRedirectionRetryHandler;
import org.jclouds.aws.handlers.ParseAWSErrorFromXmlContent;
import org.jclouds.aws.util.RequestSigner;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientFactory;
import org.jclouds.util.DateService;
import org.jclouds.util.TimeStamp;
import org.joda.time.DateTime;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
/**
* Configures the EC2 connection.
*
* @author Adrian Cole
*/
@RequiresHttp
@ConfiguresRestClient
public class EC2RestClientModule extends AbstractModule {
@Override
protected void configure() {
bindErrorHandlers();
bindRetryHandlers();
}
@Provides
@TimeStamp
protected String provideTimeStamp(final DateService dateService,
@Named(EC2Constants.PROPERTY_EC2_EXPIREINTERVAL) final int expiration) {
return dateService.iso8601DateFormat(new DateTime().plusSeconds(expiration));
}
@Provides
@Singleton
RequestSigner provideRequestSigner(FormSigner in) {
return in;
}
@Provides
@Singleton
protected EC2Client provideClient(RestClientFactory factory) {
return factory.create(EC2Client.class);
}
@Provides
@Singleton
@EC2
protected URI provideURI(@Named(EC2Constants.PROPERTY_EC2_ENDPOINT) String endpoint) {
return URI.create(endpoint);
}
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
ParseAWSErrorFromXmlContent.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(
ParseAWSErrorFromXmlContent.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(
ParseAWSErrorFromXmlContent.class);
}
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(Redirection.class).to(
AWSRedirectionRetryHandler.class);
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(
AWSClientErrorRetryHandler.class);
}
}

View File

@ -0,0 +1,262 @@
package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import com.google.inject.internal.Nullable;
/**
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-DescribeImagesResponseItemType.html"
* />
* @author Adrian Cole
*/
public class Image implements Comparable<Image> {
public Image(Architecture architecture, String imageId, String imageLocation,
String imageOwnerId, ImageState imageState, ImageType imageType, boolean isPublic,
@Nullable String kernelId, @Nullable String platform, Set<String> productCodes,
@Nullable String ramdiskId) {
this.architecture = checkNotNull(architecture, "architecture");
this.imageId = checkNotNull(imageId, "imageId");
this.imageLocation = checkNotNull(imageLocation, "imageLocation");
this.imageOwnerId = checkNotNull(imageOwnerId, "imageOwnerId");
this.imageState = checkNotNull(imageState, "imageState");
this.imageType = checkNotNull(imageType, "imageType");
this.isPublic = isPublic;
this.kernelId = kernelId;
this.platform = platform;
this.productCodes = checkNotNull(productCodes, "productCodes");
this.ramdiskId = ramdiskId;
}
/** The serialVersionUID */
private static final long serialVersionUID = -6965068835316857535L;
public enum ImageState {
/**
* the image is successfully registered and available for launching
*/
AVAILABLE,
/**
* the image is deregistered and no longer available for launching
*/
DEREGISTERED;
public String value() {
return name().toLowerCase();
}
public static ImageState fromValue(String v) {
return valueOf(v.toUpperCase());
}
}
public enum Architecture {
I386, X86_64;
public String value() {
return name().toLowerCase();
}
public static Architecture fromValue(String v) {
return valueOf(v.toUpperCase());
}
}
public enum ImageType {
MACHINE, KERNEL, RAMDISK;
public String value() {
return name().toLowerCase();
}
public static ImageType fromValue(String v) {
return valueOf(v.toUpperCase());
}
}
private final Architecture architecture;
private final String imageId;
private final String imageLocation;
private final String imageOwnerId;
private final ImageState imageState;
private final ImageType imageType;
private final boolean isPublic;
private final @Nullable
String kernelId;
private final @Nullable String platform;
private final Set<String> productCodes;
private final @Nullable
String ramdiskId;
/**
* The architecture of the image (i386 or x86_64).
*/
public Architecture getArchitecture() {
return architecture;
}
/**
* The ID of the AMI.
*/
public String getImageId() {
return imageId;
}
/**
* The location of the AMI.
*/
public String getImageLocation() {
return imageLocation;
}
/**
* AWS Access Key ID of the image owner.
*/
public String getImageOwnerId() {
return imageOwnerId;
}
/**
* Current state of the AMI. If the operation returns available, the image is successfully
* registered and avail able for launching. If the operation returns deregistered, the image is
* deregistered and no longer available for launching.
*/
public ImageState getImageState() {
return imageState;
}
/**
* The type of image (machine, kernel, or ramdisk).
*/
public ImageType getImageType() {
return imageType;
}
/**
* Returns true if this image has public launch permissions. Returns false if it only has
* implicit and explicit launch permissions.
*/
public boolean isPublic() {
return isPublic;
}
/**
* The kernel associated with the image, if any. Only applicable for machine images.
*/
public String getKernelId() {
return kernelId;
}
/**
* The operating platform of the instance.
*/
public String getPlatform() {
return platform;
}
/**
* Product codes of the AMI.
*/
public Set<String> getProductCodes() {
return productCodes;
}
/**
* The RAM disk associated with the image, if any. Only applicable for machine images.
*/
public String getRamdiskId() {
return ramdiskId;
}
/**
* {@inheritDoc}
*/
public int compareTo(Image o) {
return (this == o) ? 0 : getImageId().compareTo(o.getImageId());
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((architecture == null) ? 0 : architecture.hashCode());
result = prime * result + ((imageId == null) ? 0 : imageId.hashCode());
result = prime * result + ((imageLocation == null) ? 0 : imageLocation.hashCode());
result = prime * result + ((imageOwnerId == null) ? 0 : imageOwnerId.hashCode());
result = prime * result + ((imageState == null) ? 0 : imageState.hashCode());
result = prime * result + ((imageType == null) ? 0 : imageType.hashCode());
result = prime * result + (isPublic ? 1231 : 1237);
result = prime * result + ((kernelId == null) ? 0 : kernelId.hashCode());
result = prime * result + ((platform == null) ? 0 : platform.hashCode());
result = prime * result + ((productCodes == null) ? 0 : productCodes.hashCode());
result = prime * result + ((ramdiskId == null) ? 0 : ramdiskId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Image other = (Image) obj;
if (architecture == null) {
if (other.architecture != null)
return false;
} else if (!architecture.equals(other.architecture))
return false;
if (imageId == null) {
if (other.imageId != null)
return false;
} else if (!imageId.equals(other.imageId))
return false;
if (imageLocation == null) {
if (other.imageLocation != null)
return false;
} else if (!imageLocation.equals(other.imageLocation))
return false;
if (imageOwnerId == null) {
if (other.imageOwnerId != null)
return false;
} else if (!imageOwnerId.equals(other.imageOwnerId))
return false;
if (imageState == null) {
if (other.imageState != null)
return false;
} else if (!imageState.equals(other.imageState))
return false;
if (imageType == null) {
if (other.imageType != null)
return false;
} else if (!imageType.equals(other.imageType))
return false;
if (isPublic != other.isPublic)
return false;
if (kernelId == null) {
if (other.kernelId != null)
return false;
} else if (!kernelId.equals(other.kernelId))
return false;
if (platform == null) {
if (other.platform != null)
return false;
} else if (!platform.equals(other.platform))
return false;
if (productCodes == null) {
if (other.productCodes != null)
return false;
} else if (!productCodes.equals(other.productCodes))
return false;
if (ramdiskId == null) {
if (other.ramdiskId != null)
return false;
} else if (!ramdiskId.equals(other.ramdiskId))
return false;
return true;
}
}

View File

@ -0,0 +1,65 @@
package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.aws.ec2.EC2Client;
/**
*
* The current state of the instance..
*
* @author Adrian Cole
* @see EC2Client#describeInstances
* @see EC2Client#runInstances
* @see EC2Client#terminateInstances
*
*/
public enum InstanceState {
/**
* the instance is in the process of being launched
*/
PENDING,
/**
* the instance launched (although the boot process might not be completed)
*/
RUNNING,
/**
* the instance started shutting down
*/
SHUTTING_DOWN,
/**
* the instance terminated
*/
TERMINATED;
public String value() {
return name().toLowerCase().replaceAll("_", "-");
}
@Override
public String toString() {
return value();
}
public static InstanceState fromValue(String state) {
return valueOf(checkNotNull(state, "state").replaceAll("-", "_").toUpperCase());
}
public static InstanceState fromValue(int v) {
switch (v) {
case 0:
return PENDING;
case 16:
return RUNNING;
case 32:
return SHUTTING_DOWN;
case 48:
return TERMINATED;
default:
throw new IllegalArgumentException("invalid state:" + v);
}
}
}

View File

@ -0,0 +1,108 @@
package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.aws.ec2.EC2Client;
/**
*
* The type of the instance. Description accurate as of 8-15-2009 release.
*
* @author Adrian Cole
* @see EC2Client#describeInstances
* @see EC2Client#runInstances
* @see EC2Client#terminateInstances
*
*/
public enum InstanceType {
/**
* Small Instance
* <ul>
* <li>1.7 GB memory</li>
* <li>1 EC2 Compute Unit (1 virtual core with 1 EC2 Compute Unit)</li>
* <li>160 GB instance storage (150 GB plus 10 GB root partition)</li>
* <li>32-bit platform</li>
* <li>I/O Performance: Moderate</li>
* </ul>
*/
M1_SMALL,
/**
* Large Instance
* <ul>
* <li>7.5 GB memory</li>
* <li>4 EC2 Compute Units (2 virtual cores with 2 EC2 Compute Units each)</li>
* <li>850 GB instance storage (2x420 GB plus 10 GB root partition)</li>
* <li>64-bit platform</li>
* <li>I/O Performance: High</li>
* </ul>
*/
M1_LARGE,
/**
* Extra Large Instance
* <ul>
* <li>15 GB memory</li>
* <li>8 EC2 Compute Units (4 virtual cores with 2 EC2 Compute Units each)</li>
* <li>1690 GB instance storage (4x420 GB plus 10 GB root partition)</li>
* <li>64-bit platform</li>
* <li>I/O Performance: High</li>
* </ul>
*/
M1_XLARGE,
/**
* High-Memory Double Extra Large Instance
* <ul>
* <li>34.2 GB of memory</li>
* <li>13 EC2 Compute Units (4 virtual cores with 3.25 EC2 Compute Units each)</li>
* <li>850 GB of instance storage</li>
* <li>64-bit platform</li>
* <li>I/O Performance: High</li>
* </ul>
*/
M2_2XLARGE,
/**
* High-Memory Quadruple Extra Large Instance
* <ul>
* <li>68.4 GB of memory</li>
* <li>26 EC2 Compute Units (8 virtual cores with 3.25 EC2 Compute Units each)</li>
* <li>1690 GB of instance storage</li>
* <li>64-bit platform</li>
* <li>I/O Performance: High</li>
* </ul>
*/
M2_4XLARGE,
/**
* High-CPU Medium Instance
* <ul>
* <li>1.7 GB of memory</li>
* <li>5 EC2 Compute Units (2 virtual cores with 2.5 EC2 Compute Units each)</li>
* <li>350 GB of instance storage</li>
* <li>32-bit platform</li>
* <li>I/O Performance: Moderate</li>
* </ul>
*/
C1_MEDIUM,
/**
* High-CPU Extra Large Instance
* <ul>
* <li>7 GB of memory</li>
* <li>20 EC2 Compute Units (8 virtual cores with 2.5 EC2 Compute Units each)</li>
* <li>1690 GB of instance storage</li>
* <li>64-bit platform</li>
* <li>I/O Performance: High</li>
* </ul>
*/
C1_XLARGE;
public String value() {
return name().toLowerCase().replaceAll("_", ".");
}
@Override
public String toString() {
return value();
}
public static InstanceType fromValue(String type) {
return valueOf(checkNotNull(type, "type").replaceAll("\\.", "_").toUpperCase());
}
}

View File

@ -0,0 +1,114 @@
package org.jclouds.aws.ec2.domain;
import java.util.SortedSet;
/**
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-IpPermissionType.html"
* />
* @author Adrian Cole
*/
public class IpPermission implements Comparable<IpPermission> {
private final int fromPort;
private final int toPort;
private final SortedSet<UserIdGroupPair> groups;
private final IpProtocol ipProtocol;
private final SortedSet<String> ipRanges;
public IpPermission(int fromPort, int toPort, SortedSet<UserIdGroupPair> groups,
IpProtocol ipProtocol, SortedSet<String> ipRanges) {
this.fromPort = fromPort;
this.toPort = toPort;
this.groups = groups;
this.ipProtocol = ipProtocol;
this.ipRanges = ipRanges;
}
/**
* {@inheritDoc}
*/
public int compareTo(IpPermission o) {
return (this == o) ? 0 : getIpProtocol().compareTo(o.getIpProtocol());
}
/**
* Start of port range for the TCP and UDP protocols, or an ICMP type number. An ICMP type number
* of -1 indicates a wildcard (i.e., any ICMP type number).
*/
public int getFromPort() {
return fromPort;
}
/**
* End of port range for the TCP and UDP protocols, or an ICMP code. An ICMP code of -1 indicates
* a wildcard (i.e., any ICMP code).
*/
public int getToPort() {
return toPort;
}
/**
* List of security group and user ID pairs.
*/
public SortedSet<UserIdGroupPair> getGroups() {
return groups;
}
/**
* IP protocol
*/
public IpProtocol getIpProtocol() {
return ipProtocol;
}
/**
* IP ranges.
*/
public SortedSet<String> getIpRanges() {
return ipRanges;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + fromPort;
result = prime * result + ((groups == null) ? 0 : groups.hashCode());
result = prime * result + ((ipProtocol == null) ? 0 : ipProtocol.hashCode());
result = prime * result + ((ipRanges == null) ? 0 : ipRanges.hashCode());
result = prime * result + toPort;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
IpPermission other = (IpPermission) obj;
if (fromPort != other.fromPort)
return false;
if (groups == null) {
if (other.groups != null)
return false;
} else if (!groups.equals(other.groups))
return false;
if (ipProtocol == null) {
if (other.ipProtocol != null)
return false;
} else if (!ipProtocol.equals(other.ipProtocol))
return false;
if (ipRanges == null) {
if (other.ipRanges != null)
return false;
} else if (!ipRanges.equals(other.ipRanges))
return false;
if (toPort != other.toPort)
return false;
return true;
}
}

View File

@ -0,0 +1,26 @@
package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* @author Adrian Cole
*
*/
public enum IpProtocol {
TCP, UDP, ICMP;
public String value() {
return name().toLowerCase();
}
@Override
public String toString() {
return value();
}
public static IpProtocol fromValue(String protocol) {
return valueOf(checkNotNull(protocol, "protocol").toUpperCase());
}
}

View File

@ -0,0 +1,91 @@
package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.internal.Nullable;
/**
*
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CreateKeyPair.html"
* />
* @author Adrian Cole
*/
public class KeyPair implements Comparable<KeyPair> {
private final String keyName;
private final String keyFingerprint;
@Nullable
private final String keyMaterial;
public KeyPair(String keyName, String keyFingerprint, @Nullable String keyMaterial) {
this.keyName = checkNotNull(keyName, "keyName");
this.keyFingerprint = checkNotNull(keyFingerprint, "keyFingerprint");
this.keyMaterial = keyMaterial;// nullable on list
}
/**
* {@inheritDoc}
*/
public int compareTo(KeyPair o) {
return (this == o) ? 0 : getKeyName().compareTo(o.getKeyName());
}
/**
* A SHA-1 digest of the DER encoded private key.
*/
public String getKeyFingerprint() {
return keyFingerprint;
}
/**
* An unencrypted PEM encoded RSA private key.
*/
public String getKeyMaterial() {
return keyMaterial;
}
/**
* The key pair name provided in the original request.
*/
public String getKeyName() {
return keyName;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((keyFingerprint == null) ? 0 : keyFingerprint.hashCode());
result = prime * result + ((keyMaterial == null) ? 0 : keyMaterial.hashCode());
result = prime * result + ((keyName == null) ? 0 : keyName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
KeyPair other = (KeyPair) obj;
if (keyFingerprint == null) {
if (other.keyFingerprint != null)
return false;
} else if (!keyFingerprint.equals(other.keyFingerprint))
return false;
if (keyMaterial == null) {
if (other.keyMaterial != null)
return false;
} else if (!keyMaterial.equals(other.keyMaterial))
return false;
if (keyName == null) {
if (other.keyName != null)
return false;
} else if (!keyName.equals(other.keyName))
return false;
return true;
}
}

View File

@ -0,0 +1,119 @@
package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.SortedSet;
import com.google.inject.internal.Nullable;
/**
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-ReservationInfoType.html"
* />
* @author Adrian Cole
*/
public class Reservation implements Comparable<Reservation> {
public Reservation(SortedSet<String> groupIds, SortedSet<RunningInstance> instances,
@Nullable String ownerId, @Nullable String requesterId, @Nullable String reservationId) {
this.groupIds = checkNotNull(groupIds, "groupIds");
this.instances = checkNotNull(instances, "instances");
this.ownerId = ownerId;
this.requesterId = requesterId;
this.reservationId = reservationId;
}
private final SortedSet<String> groupIds;
private final SortedSet<RunningInstance> instances;
private final @Nullable
String ownerId;
private final @Nullable
String requesterId;
private final @Nullable
String reservationId;
public int compareTo(Reservation o) {
return (this == o) ? 0 : getReservationId().compareTo(o.getReservationId());
}
/**
* Names of the security groups.
*/
public SortedSet<String> getGroupIds() {
return groupIds;
}
public SortedSet<RunningInstance> getRunningInstances() {
return instances;
}
/**
* AWS Access Key ID of the user who owns the reservation.
*/
public String getOwnerId() {
return ownerId;
}
/**
* ID of the requester.
*/
public String getRequesterId() {
return requesterId;
}
/**
* Unique ID of the reservation.
*/
public String getReservationId() {
return reservationId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((groupIds == null) ? 0 : groupIds.hashCode());
result = prime * result + ((instances == null) ? 0 : instances.hashCode());
result = prime * result + ((ownerId == null) ? 0 : ownerId.hashCode());
result = prime * result + ((requesterId == null) ? 0 : requesterId.hashCode());
result = prime * result + ((reservationId == null) ? 0 : reservationId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Reservation other = (Reservation) obj;
if (groupIds == null) {
if (other.groupIds != null)
return false;
} else if (!groupIds.equals(other.groupIds))
return false;
if (instances == null) {
if (other.instances != null)
return false;
} else if (!instances.equals(other.instances))
return false;
if (ownerId == null) {
if (other.ownerId != null)
return false;
} else if (!ownerId.equals(other.ownerId))
return false;
if (requesterId == null) {
if (other.requesterId != null)
return false;
} else if (!requesterId.equals(other.requesterId))
return false;
if (reservationId == null) {
if (other.reservationId != null)
return false;
} else if (!reservationId.equals(other.reservationId))
return false;
return true;
}
}

View File

@ -0,0 +1,367 @@
package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.InetAddress;
import java.util.Set;
import org.joda.time.DateTime;
import com.google.inject.internal.Nullable;
/**
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-RunningInstancesItemType.html"
* />
* @author Adrian Cole
*/
public class RunningInstance implements Comparable<RunningInstance> {
private final String amiLaunchIndex;
private final @Nullable
String dnsName;
private final String imageId;
private final String instanceId;
private final InstanceState instanceState;
private final InstanceType instanceType;
private final @Nullable
InetAddress ipAddress;
private final @Nullable
String kernelId;
private final @Nullable
String keyName;
private final DateTime launchTime;
private final boolean monitoring;
private final String availabilityZone;
private final @Nullable
String platform;
private final @Nullable
String privateDnsName;
private final @Nullable
InetAddress privateIpAddress;
private final Set<String> productCodes;
private final @Nullable
String ramdiskId;
private final @Nullable
String reason;
private final @Nullable
String subnetId;
private final @Nullable
String vpcId;
public int compareTo(RunningInstance o) {
return (this == o) ? 0 : getInstanceId().compareTo(o.getInstanceId());
}
public RunningInstance(String amiLaunchIndex, @Nullable String dnsName, String imageId,
String instanceId, InstanceState instanceState, InstanceType instanceType,
@Nullable InetAddress ipAddress, @Nullable String kernelId, @Nullable String keyName,
DateTime launchTime, boolean monitoring, String availabilityZone,
@Nullable String platform, @Nullable String privateDnsName,
@Nullable InetAddress privateIpAddress, Set<String> productCodes,
@Nullable String ramdiskId, @Nullable String reason, @Nullable String subnetId,
@Nullable String vpcId) {
this.amiLaunchIndex = checkNotNull(amiLaunchIndex, "amiLaunchIndex");
this.dnsName = dnsName; // nullable on runinstances.
this.imageId = checkNotNull(imageId, "imageId");
this.instanceId = checkNotNull(instanceId, "instanceId");
this.instanceState = checkNotNull(instanceState, "instanceState");
this.instanceType = checkNotNull(instanceType, "instanceType");
this.ipAddress = ipAddress;
this.kernelId = kernelId;
this.keyName = keyName;
this.launchTime = checkNotNull(launchTime, "launchTime");
this.monitoring = checkNotNull(monitoring, "monitoring");
this.availabilityZone = checkNotNull(availabilityZone, "availabilityZone");
this.platform = platform;
this.privateDnsName = privateDnsName; // nullable on runinstances.
this.privateIpAddress = privateIpAddress;
this.productCodes = checkNotNull(productCodes, "productCodes");
this.ramdiskId = ramdiskId;
this.reason = reason;
this.subnetId = subnetId;
this.vpcId = vpcId;
}
/**
* The AMI launch index, which can be used to find this instance within the launch group. For
* more information, go to the Metadata section of the Amazon Elastic Compute Cloud Developer
* Guide.
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/2009-08-15/DeveloperGuide/" />
*/
public String getAmiLaunchIndex() {
return amiLaunchIndex;
}
/**
* The public DNS name assigned to the instance. This DNS name is contactable from outside the
* Amazon EC2 network. This element remains empty until the instance enters a running state.
*/
public String getDnsName() {
return dnsName;
}
/**
* Image ID of the AMI used to launch the instance.
*/
public String getImageId() {
return imageId;
}
/**
* Unique ID of the instance launched.
*/
public String getInstanceId() {
return instanceId;
}
/**
* The current state of the instance.
*/
public InstanceState getInstanceState() {
return instanceState;
}
/**
* The instance type.
*/
public InstanceType getInstanceType() {
return instanceType;
}
/**
* Specifies the IP address of the instance.
*/
public InetAddress getIpAddress() {
return ipAddress;
}
/**
* Optional. Kernel associated with this instance.
*/
public String getKernelId() {
return kernelId;
}
/**
* If this instance was launched with an associated key pair, this displays the key pair name.
*/
public String getKeyName() {
return keyName;
}
/**
* The time the instance launched.
*/
public DateTime getLaunchTime() {
return launchTime;
}
/**
* Specifies whether monitoring is enabled for the instance.
*/
public boolean isMonitoring() {
return monitoring;
}
/**
* The location where the instance launched.
*/
public String getAvailabilityZone() {
return availabilityZone;
}
/**
* Platform of the instance (e.g., Windows).
*/
public String getPlatform() {
return platform;
}
/**
* The private DNS name assigned to the instance. This DNS name can only be used inside the
* Amazon EC2 network. This element remains empty until the instance enters a running state.
*/
public String getPrivateDnsName() {
return privateDnsName;
}
/**
* Specifies the private IP address that is assigned to the instance (Amazon VPC).
*/
public InetAddress getPrivateIpAddress() {
return privateIpAddress;
}
/**
* Product codes attached to this instance.
*/
public Set<String> getProductCodes() {
return productCodes;
}
/**
* Optional. RAM disk associated with this instance.
*/
public String getRamdiskId() {
return ramdiskId;
}
/**
* Reason for the most recent state transition. This might be an empty string.
*/
public String getReason() {
return reason;
}
/**
* Specifies the subnet ID in which the instance is running (Amazon Virtual Private Cloud).
*/
public String getSubnetId() {
return subnetId;
}
/**
* Specifies the VPC in which the instance is running (Amazon Virtual Private Cloud).
*/
public String getVpcId() {
return vpcId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((amiLaunchIndex == null) ? 0 : amiLaunchIndex.hashCode());
result = prime * result + ((availabilityZone == null) ? 0 : availabilityZone.hashCode());
result = prime * result + ((dnsName == null) ? 0 : dnsName.hashCode());
result = prime * result + ((imageId == null) ? 0 : imageId.hashCode());
result = prime * result + ((instanceId == null) ? 0 : instanceId.hashCode());
result = prime * result + ((instanceState == null) ? 0 : instanceState.hashCode());
result = prime * result + ((instanceType == null) ? 0 : instanceType.hashCode());
result = prime * result + ((ipAddress == null) ? 0 : ipAddress.hashCode());
result = prime * result + ((kernelId == null) ? 0 : kernelId.hashCode());
result = prime * result + ((keyName == null) ? 0 : keyName.hashCode());
result = prime * result + ((launchTime == null) ? 0 : launchTime.hashCode());
result = prime * result + (monitoring ? 1231 : 1237);
result = prime * result + ((platform == null) ? 0 : platform.hashCode());
result = prime * result + ((privateDnsName == null) ? 0 : privateDnsName.hashCode());
result = prime * result + ((privateIpAddress == null) ? 0 : privateIpAddress.hashCode());
result = prime * result + ((productCodes == null) ? 0 : productCodes.hashCode());
result = prime * result + ((ramdiskId == null) ? 0 : ramdiskId.hashCode());
result = prime * result + ((reason == null) ? 0 : reason.hashCode());
result = prime * result + ((subnetId == null) ? 0 : subnetId.hashCode());
result = prime * result + ((vpcId == null) ? 0 : vpcId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
RunningInstance other = (RunningInstance) obj;
if (amiLaunchIndex == null) {
if (other.amiLaunchIndex != null)
return false;
} else if (!amiLaunchIndex.equals(other.amiLaunchIndex))
return false;
if (availabilityZone == null) {
if (other.availabilityZone != null)
return false;
} else if (!availabilityZone.equals(other.availabilityZone))
return false;
if (dnsName == null) {
if (other.dnsName != null)
return false;
} else if (!dnsName.equals(other.dnsName))
return false;
if (imageId == null) {
if (other.imageId != null)
return false;
} else if (!imageId.equals(other.imageId))
return false;
if (instanceId == null) {
if (other.instanceId != null)
return false;
} else if (!instanceId.equals(other.instanceId))
return false;
if (instanceState == null) {
if (other.instanceState != null)
return false;
} else if (!instanceState.equals(other.instanceState))
return false;
if (instanceType == null) {
if (other.instanceType != null)
return false;
} else if (!instanceType.equals(other.instanceType))
return false;
if (ipAddress == null) {
if (other.ipAddress != null)
return false;
} else if (!ipAddress.equals(other.ipAddress))
return false;
if (kernelId == null) {
if (other.kernelId != null)
return false;
} else if (!kernelId.equals(other.kernelId))
return false;
if (keyName == null) {
if (other.keyName != null)
return false;
} else if (!keyName.equals(other.keyName))
return false;
if (launchTime == null) {
if (other.launchTime != null)
return false;
} else if (!launchTime.equals(other.launchTime))
return false;
if (monitoring != other.monitoring)
return false;
if (platform == null) {
if (other.platform != null)
return false;
} else if (!platform.equals(other.platform))
return false;
if (privateDnsName == null) {
if (other.privateDnsName != null)
return false;
} else if (!privateDnsName.equals(other.privateDnsName))
return false;
if (privateIpAddress == null) {
if (other.privateIpAddress != null)
return false;
} else if (!privateIpAddress.equals(other.privateIpAddress))
return false;
if (productCodes == null) {
if (other.productCodes != null)
return false;
} else if (!productCodes.equals(other.productCodes))
return false;
if (ramdiskId == null) {
if (other.ramdiskId != null)
return false;
} else if (!ramdiskId.equals(other.ramdiskId))
return false;
if (reason == null) {
if (other.reason != null)
return false;
} else if (!reason.equals(other.reason))
return false;
if (subnetId == null) {
if (other.subnetId != null)
return false;
} else if (!subnetId.equals(other.subnetId))
return false;
if (vpcId == null) {
if (other.vpcId != null)
return false;
} else if (!vpcId.equals(other.vpcId))
return false;
return true;
}
}

View File

@ -0,0 +1,102 @@
package org.jclouds.aws.ec2.domain;
import java.util.SortedSet;
/**
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-SecurityGroupItemType.html"
* />
* @author Adrian Cole
*/
public class SecurityGroup implements Comparable<SecurityGroup> {
private final String name;
private final String ownerId;
private final String description;
private final SortedSet<IpPermission> ipPermissions;
public SecurityGroup(String name, String ownerId, String description,
SortedSet<IpPermission> ipPermissions) {
this.name = name;
this.ownerId = ownerId;
this.description = description;
this.ipPermissions = ipPermissions;
}
/**
* {@inheritDoc}
*/
public int compareTo(SecurityGroup o) {
return (this == o) ? 0 : getName().compareTo(o.getName());
}
/**
* Name of the security group.
*/
public String getName() {
return name;
}
/**
* AWS Access Key ID of the owner of the security group.
*/
public String getOwnerId() {
return ownerId;
}
/**
* Description of the security group.
*/
public String getDescription() {
return description;
}
/**
* Set of IP permissions associated with the security group.
*/
public SortedSet<IpPermission> getIpPermissions() {
return ipPermissions;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((ipPermissions == null) ? 0 : ipPermissions.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((ownerId == null) ? 0 : ownerId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SecurityGroup other = (SecurityGroup) obj;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (ipPermissions == null) {
if (other.ipPermissions != null)
return false;
} else if (!ipPermissions.equals(other.ipPermissions))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (ownerId == null) {
if (other.ownerId != null)
return false;
} else if (!ownerId.equals(other.ownerId))
return false;
return true;
}
}

View File

@ -0,0 +1,76 @@
package org.jclouds.aws.ec2.domain;
/**
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-TerminateInstancesResponseInfoType.html"
* />
* @author Adrian Cole
*/
public class TerminatedInstance implements Comparable<TerminatedInstance> {
private final String instanceId;
private final InstanceState shutdownState;
private final InstanceState previousState;
public int compareTo(TerminatedInstance o) {
return (this == o) ? 0 : getInstanceId().compareTo(o.getInstanceId());
}
public TerminatedInstance(String instanceId, InstanceState shutdownState,
InstanceState previousState) {
this.instanceId = instanceId;
this.shutdownState = shutdownState;
this.previousState = previousState;
}
public String getInstanceId() {
return instanceId;
}
public InstanceState getShutdownState() {
return shutdownState;
}
public InstanceState getPreviousState() {
return previousState;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((instanceId == null) ? 0 : instanceId.hashCode());
result = prime * result + ((previousState == null) ? 0 : previousState.hashCode());
result = prime * result + ((shutdownState == null) ? 0 : shutdownState.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TerminatedInstance other = (TerminatedInstance) obj;
if (instanceId == null) {
if (other.instanceId != null)
return false;
} else if (!instanceId.equals(other.instanceId))
return false;
if (previousState == null) {
if (other.previousState != null)
return false;
} else if (!previousState.equals(other.previousState))
return false;
if (shutdownState == null) {
if (other.shutdownState != null)
return false;
} else if (!shutdownState.equals(other.shutdownState))
return false;
return true;
}
}

View File

@ -0,0 +1,78 @@
package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
/**
*
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-UserIdGroupPairType.html"
* />
* @author Adrian Cole
*/
public class UserIdGroupPair implements Comparable<UserIdGroupPair> {
private final String userId;
private final String groupName;
public UserIdGroupPair(String userId, String groupName) {
this.userId = checkNotNull(userId,"userId");
this.groupName = checkNotNull(groupName,"groupName");
}
/**
* {@inheritDoc}
*/
public int compareTo(UserIdGroupPair o) {
return (this == o) ? 0 : getUserId().compareTo(o.getUserId());
}
/**
* AWS User ID of an account. Cannot be used when specifying a CIDR IP address.
*/
public String getUserId() {
return userId;
}
/**
* Name of the security group. Cannot be used when specifying a CIDR IP address.
*/
public String getGroupName() {
return groupName;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((groupName == null) ? 0 : groupName.hashCode());
result = prime * result + ((userId == null) ? 0 : userId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UserIdGroupPair other = (UserIdGroupPair) obj;
if (groupName == null) {
if (other.groupName != null)
return false;
} else if (!groupName.equals(other.groupName))
return false;
if (userId == null) {
if (other.userId != null)
return false;
} else if (!userId.equals(other.userId))
return false;
return true;
}
}

View File

@ -0,0 +1,213 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.filters;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.aws.ec2.reference.EC2Parameters.ACTION;
import static org.jclouds.aws.ec2.reference.EC2Parameters.AWS_ACCESS_KEY_ID;
import static org.jclouds.aws.ec2.reference.EC2Parameters.SIGNATURE;
import static org.jclouds.aws.ec2.reference.EC2Parameters.SIGNATURE_METHOD;
import static org.jclouds.aws.ec2.reference.EC2Parameters.SIGNATURE_VERSION;
import static org.jclouds.aws.ec2.reference.EC2Parameters.TIMESTAMP;
import static org.jclouds.aws.ec2.reference.EC2Parameters.VERSION;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.ws.rs.core.HttpHeaders;
import org.apache.commons.io.IOUtils;
import org.jclouds.aws.reference.AWSConstants;
import org.jclouds.aws.util.RequestSigner;
import org.jclouds.http.HttpConstants;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.internal.SignatureWire;
import org.jclouds.logging.Logger;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.TimeStamp;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
/**
*
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/Form-Common-Parameters.html"
* />
* @author Adrian Cole
*
*/
@Singleton
public class FormSigner implements HttpRequestFilter, RequestSigner {
public static String[] mandatoryParametersForSignature = new String[] { ACTION,
SIGNATURE_METHOD, SIGNATURE_VERSION, VERSION };
private final SignatureWire signatureWire;
private final String accessKey;
private final String secretKey;
private final Provider<String> dateService;
@Resource
@Named(HttpConstants.SIGNATURE_LOGGER)
private final Logger signatureLog = Logger.NULL;
@Inject
public FormSigner(SignatureWire signatureWire,
@Named(AWSConstants.PROPERTY_AWS_ACCESSKEYID) String accessKey,
@Named(AWSConstants.PROPERTY_AWS_SECRETACCESSKEY) String secretKey,
@TimeStamp Provider<String> dateService) {
this.signatureWire = signatureWire;
this.accessKey = accessKey;
this.secretKey = secretKey;
this.dateService = dateService;
}
public void filter(HttpRequest in) throws HttpException {
GeneratedHttpRequest<?> request = (GeneratedHttpRequest<?>) in;
checkNotNull(request.getFirstHeaderOrNull(HttpHeaders.HOST),
"request is not ready to sign; host not present");
Multimap<String, String> decodedParams = RestAnnotationProcessor.parseQueryToMap(request
.getEntity().toString());
addSigningParams(decodedParams);
validateParams(decodedParams);
String stringToSign = createStringToSign(request, decodedParams);
String signature = signString(stringToSign);
addSignature(decodedParams, signature);
setEntity(request, decodedParams);
HttpUtils.logRequest(signatureLog, request, "<<");
}
String[] sortForSigning(String queryLine) {
String[] parts = queryLine.split("&");
// 1. Sort the UTF-8 query string components by parameter name with natural byte ordering.
Arrays.sort(parts, new Comparator<String>() {
public int compare(String o1, String o2) {
if (o1.startsWith("AWSAccessKeyId"))
return -1;
return o1.compareTo(o2);
}
});
return parts;
}
void setEntity(GeneratedHttpRequest<?> request, Multimap<String, String> decodedParams) {
request.setEntity(RestAnnotationProcessor.makeQueryLine(decodedParams,
new Comparator<Map.Entry<String, String>>() {
public int compare(Entry<String, String> o1, Entry<String, String> o2) {
if (o1.getKey().startsWith("Action")
|| o2.getKey().startsWith("AWSAccessKeyId"))
return -1;
if (o1.getKey().startsWith("AWSAccessKeyId")
|| o2.getKey().startsWith("Action"))
return 1;
return o1.getKey().compareTo(o2.getKey());
}
}));
}
@VisibleForTesting
void validateParams(Multimap<String, String> params) {
for (String parameter : mandatoryParametersForSignature) {
checkState(params.containsKey(parameter), "parameter " + parameter
+ " is required for signature");
}
}
@VisibleForTesting
void addSignature(Multimap<String, String> params, String signature) {
params.replaceValues(SIGNATURE, ImmutableList.of(signature));
}
@VisibleForTesting
public String signString(String stringToSign) {
String signature;
try {
signature = HttpUtils.hmacSha256Base64(stringToSign, secretKey.getBytes());
if (signatureWire.enabled())
signatureWire.input(IOUtils.toInputStream(signature));
} catch (Exception e) {
throw new HttpException("error signing request", e);
}
return signature;
}
@VisibleForTesting
public String createStringToSign(HttpRequest request, Multimap<String, String> decodedParams) {
HttpUtils.logRequest(signatureLog, request, ">>");
StringBuilder stringToSign = new StringBuilder();
// StringToSign = HTTPVerb + "\n" +
stringToSign.append(request.getMethod()).append("\n");
// ValueOfHostHeaderInLowercase + "\n" +
stringToSign.append(request.getFirstHeaderOrNull(HttpHeaders.HOST).toLowerCase())
.append("\n");
// HTTPRequestURI + "\n" +
stringToSign.append(request.getEndpoint().getPath()).append("\n");
// CanonicalizedFormString <from the preceding step>
stringToSign.append(buildCanonicalizedString(decodedParams));
if (signatureWire.enabled())
signatureWire.output(stringToSign.toString());
return stringToSign.toString();
}
@VisibleForTesting
String buildCanonicalizedString(Multimap<String, String> decodedParams) {
return RestAnnotationProcessor.makeQueryLine(decodedParams,
new Comparator<Map.Entry<String, String>>() {
public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
if (o1.getKey().startsWith("AWSAccessKeyId"))
return -1;
return o1.getKey().compareTo(o2.getKey());
}
});
}
@VisibleForTesting
void addSigningParams(Multimap<String, String> params) {
params.replaceValues(SIGNATURE_METHOD, ImmutableList.of("HmacSHA256"));
params.replaceValues(SIGNATURE_VERSION, ImmutableList.of("2"));
params.replaceValues(TIMESTAMP, ImmutableList.of(dateService.get()));
params.replaceValues(AWS_ACCESS_KEY_ID, ImmutableList.of(accessKey));
params.removeAll(SIGNATURE);
}
public String createStringToSign(HttpRequest input) {
return createStringToSign(input, RestAnnotationProcessor.parseQueryToMap(input.getEntity()
.toString()));
}
}

View File

@ -0,0 +1,34 @@
package org.jclouds.aws.ec2.functions;
import java.lang.reflect.Constructor;
import javax.inject.Singleton;
import org.jclouds.aws.AWSResponseException;
import com.google.common.base.Function;
@Singleton
public class ReturnVoidOnGroupNotFound implements Function<Exception, Void> {
static final Void v;
static {
Constructor<Void> cv;
try {
cv = Void.class.getDeclaredConstructor();
cv.setAccessible(true);
v = cv.newInstance();
} catch (Exception e) {
throw new Error("Error setting up class", e);
}
}
public Void apply(Exception from) {
if (from instanceof AWSResponseException) {
if (((AWSResponseException) from).getError().getCode().equals("InvalidGroup.NotFound"))
return v;
}
return null;
}
}

View File

@ -0,0 +1,94 @@
package org.jclouds.aws.ec2.options;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import org.jclouds.aws.ec2.options.internal.BaseEC2RequestOptions;
/**
* Contains options supported in the Form API for the DescribeImages operation. <h2>
* Usage</h2> The recommended way to instantiate a DescribeImagesOptions object is to statically
* import DescribeImagesOptions.Builder.* and invoke a static creation method followed by an
* instance mutator (if needed):
* <p/>
* <code>
* import static org.jclouds.aws.ec2.options.DescribeImagesOptions.Builder.*
* <p/>
* EC2Client connection = // get connection
* Future<SortedSet<ImageMetadata>> images = connection.describeImages(executableBy("123125").imageIds(1000, 1004));
* <code>
*
* @author Adrian Cole
* @see <a
* href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-form-DescribeImages.html"
* />
*/
public class DescribeImagesOptions extends BaseEC2RequestOptions {
public static final DescribeImagesOptions NONE = new DescribeImagesOptions();
/**
* AMIs for which the specified user has explicit launch permissions.
*
*/
public DescribeImagesOptions executableBy(String accountId) {
formParameters.put("ExecutableBy", checkNotNull(accountId, "accountId"));
return this;
}
public String getExecutableBy() {
return getFirstFormOrNull("ExecutableBy");
}
/**
* AMI IDs to describe.
*/
public DescribeImagesOptions imageIds(String... imageIds) {
indexFormValuesWithPrefix("ImageId", imageIds);
return this;
}
public Set<String> getImageIds() {
return getFormValuesWithKeysPrefixedBy("ImageId.");
}
/**
* Returns AMIs owned by the specified owner. Multiple owners can be specified.
*/
public DescribeImagesOptions ownedBy(String... owners) {
indexFormValuesWithPrefix("Owner", owners);
return this;
}
public Set<String> getOwners() {
return getFormValuesWithKeysPrefixedBy("Owner.");
}
public static class Builder {
/**
* @see DescribeImagesOptions#executableBy(String )
*/
public static DescribeImagesOptions executableBy(String accountId) {
DescribeImagesOptions options = new DescribeImagesOptions();
return options.executableBy(accountId);
}
/**
* @see DescribeImagesOptions#imageIds(String[] )
*/
public static DescribeImagesOptions imageIds(String... imageIds) {
DescribeImagesOptions options = new DescribeImagesOptions();
return options.imageIds(imageIds);
}
/**
* @see DescribeImagesOptions#ownedBy(String[] )
*/
public static DescribeImagesOptions ownedBy(String... owners) {
DescribeImagesOptions options = new DescribeImagesOptions();
return options.ownedBy(owners);
}
}
}

View File

@ -0,0 +1,277 @@
package org.jclouds.aws.ec2.options;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.aws.ec2.domain.InstanceType;
import org.jclouds.aws.ec2.options.internal.BaseEC2RequestOptions;
/**
* Contains options supported in the Form API for the RunInstances operation. <h2>
* Usage</h2> The recommended way to instantiate a RunInstancesOptions object is to statically
* import RunInstancesOptions.Builder.* and invoke a static creation method followed by an instance
* mutator (if needed):
* <p/>
* <code>
* import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.*
* <p/>
* EC2Client connection = // get connection
* Future<ReservationInfo> instances = connection.runInstances(executableBy("123125").imageIds(1000, 1004));
* <code>
*
* @author Adrian Cole
* @see <a
* href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-form-RunInstances.html"
* />
*/
public class RunInstancesOptions extends BaseEC2RequestOptions {
public static final RunInstancesOptions NONE = new RunInstancesOptions();
/**
* The name of the key pair.
*/
public RunInstancesOptions withKeyName(String keyName) {
formParameters.put("KeyName", checkNotNull(keyName, "keyName"));
return this;
}
String getKeyName() {
return getFirstFormOrNull("KeyName");
}
/**
* Name of the security group.
*/
public RunInstancesOptions withSecurityGroup(String securityGroup) {
formParameters.put("SecurityGroup", checkNotNull(securityGroup, "securityGroup"));
return this;
}
String getSecurityGroup() {
return getFirstFormOrNull("SecurityGroup");
}
/**
* Specifies additional information to make available to the instance(s).
*/
public RunInstancesOptions withAdditionalInfo(String info) {
formParameters.put("AdditionalInfo", checkNotNull(info, "info"));
return this;
}
String getAdditionalInfo() {
return getFirstFormOrNull("AdditionalInfo");
}
/**
* MIME, Base64-encoded user data.
*/
public RunInstancesOptions withUserData(String info) {
formParameters.put("UserData", checkNotNull(info, "info"));
return this;
}
String getUserData() {
return getFirstFormOrNull("UserData");
}
/**
* Specifies the instance type. default small;
*/
public RunInstancesOptions asType(InstanceType type) {
formParameters.put("InstanceType", checkNotNull(type, "type").toString());
return this;
}
String getType() {
return getFirstFormOrNull("InstanceType");
}
/**
* Specifies the placement constraints (Availability Zones) for launching the instances.
*/
public RunInstancesOptions inAvailabilityZone(String availabilityZone) {
formParameters.put("Placement.AvailabilityZone", checkNotNull(availabilityZone,
"availabilityZone"));
return this;
}
String getAvailabilityZone() {
return getFirstFormOrNull("Placement.AvailabilityZone");
}
/**
* The ID of the kernel with which to launch the instance.
*/
public RunInstancesOptions withKernelId(String kernelId) {
formParameters.put("KernelId", checkNotNull(kernelId, "kernelId"));
return this;
}
String getKernelId() {
return getFirstFormOrNull("KernelId");
}
/**
* The ID of the RAM disk with which to launch the instance. Some kernels require additional
* drivers at l aunch. Check the kernel requirements for information on whether you need to
* specify a RAM disk. To find kernel requirements, go to th e Resource Center and search for the
* kernel ID.
*/
public RunInstancesOptions withRamdisk(String ramDiskId) {
formParameters.put("RamdiskId", checkNotNull(ramDiskId, "ramDiskId"));
return this;
}
String getRamdiskId() {
return getFirstFormOrNull("RamdiskId");
}
/**
* The virtual name.
*/
public RunInstancesOptions withVirtualName(String virtualName) {
formParameters
.put("BlockDeviceMapping.VirtualName", checkNotNull(virtualName, "virtualName"));
return this;
}
String getVirtualName() {
return getFirstFormOrNull("BlockDeviceMapping.VirtualName");
}
/**
* The device name (e.g., /dev/sdh).
*/
public RunInstancesOptions withDeviceName(String deviceName) {
formParameters.put("BlockDeviceMapping.DeviceName", checkNotNull(deviceName, "deviceName"));
return this;
}
String getDeviceName() {
return getFirstFormOrNull("BlockDeviceMapping.DeviceName");
}
/**
* Enables monitoring for the instance.
*/
public RunInstancesOptions enableMonitoring() {
formParameters.put("Monitoring.Enabled", "true");
return this;
}
String getMonitoringEnabled() {
return getFirstFormOrNull("Monitoring.Enabled");
}
/**
* Specifies the subnet ID within which to launch the instance(s) for Amazon Virtual Private
* Cloud.
*/
public RunInstancesOptions withSubnetId(String subnetId) {
formParameters.put("SubnetId", checkNotNull(subnetId, "subnetId"));
return this;
}
String getSubnetId() {
return getFirstFormOrNull("SubnetId");
}
public static class Builder {
/**
* @see RunInstancesOptions#withKeyName(String)
*/
public static RunInstancesOptions withKeyName(String keyName) {
RunInstancesOptions options = new RunInstancesOptions();
return options.withKeyName(keyName);
}
/**
* @see RunInstancesOptions#withSecurityGroup(String)
*/
public static RunInstancesOptions withSecurityGroup(String securityGroup) {
RunInstancesOptions options = new RunInstancesOptions();
return options.withSecurityGroup(securityGroup);
}
/**
* @see RunInstancesOptions#withAdditionalInfo(String)
*/
public static RunInstancesOptions withAdditionalInfo(String additionalInfo) {
RunInstancesOptions options = new RunInstancesOptions();
return options.withAdditionalInfo(additionalInfo);
}
/**
* @see RunInstancesOptions#withUserData(String)
*/
public static RunInstancesOptions withUserData(String userData) {
RunInstancesOptions options = new RunInstancesOptions();
return options.withUserData(userData);
}
/**
* @see RunInstancesOptions#asType(InstanceType)
*/
public static RunInstancesOptions asType(InstanceType instanceType) {
RunInstancesOptions options = new RunInstancesOptions();
return options.asType(instanceType);
}
/**
* @see RunInstancesOptions#inAvailabilityZone(String)
*/
public static RunInstancesOptions inAvailabilityZone(String availabilityZone) {
RunInstancesOptions options = new RunInstancesOptions();
return options.inAvailabilityZone(availabilityZone);
}
/**
* @see RunInstancesOptions#withKernelId(String)
*/
public static RunInstancesOptions withKernelId(String kernelId) {
RunInstancesOptions options = new RunInstancesOptions();
return options.withKernelId(kernelId);
}
/**
* @see RunInstancesOptions#withDeviceName(String)
*/
public static RunInstancesOptions withDeviceName(String deviceName) {
RunInstancesOptions options = new RunInstancesOptions();
return options.withDeviceName(deviceName);
}
/**
* @see RunInstancesOptions#enableMonitoring()
*/
public static RunInstancesOptions enableMonitoring() {
RunInstancesOptions options = new RunInstancesOptions();
return options.enableMonitoring();
}
/**
* @see RunInstancesOptions#withSubnetId(String)
*/
public static RunInstancesOptions withSubnetId(String subnetId) {
RunInstancesOptions options = new RunInstancesOptions();
return options.withSubnetId(subnetId);
}
/**
* @see RunInstancesOptions#withRamdisk(String)
*/
public static RunInstancesOptions withRamdisk(String ramdiskId) {
RunInstancesOptions options = new RunInstancesOptions();
return options.withRamdisk(ramdiskId);
}
/**
* @see RunInstancesOptions#withVirtualName(String)
*/
public static RunInstancesOptions withVirtualName(String virtualName) {
RunInstancesOptions options = new RunInstancesOptions();
return options.withVirtualName(virtualName);
}
}
}

View File

@ -0,0 +1,64 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.aws.ec2.options.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import org.jclouds.http.options.BaseHttpRequestOptions;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
/**
*
* @author Adrian Cole
*/
public class BaseEC2RequestOptions extends BaseHttpRequestOptions {
protected void indexFormValuesWithPrefix(String prefix, String... values) {
for (int i = 0; i < values.length; i++) {
formParameters.put(prefix + "." + (i + 1), checkNotNull(values[i], prefix.toLowerCase()
+ "s[" + i + "]"));
}
}
protected Set<String> getFormValuesWithKeysPrefixedBy(final String prefix) {
Set<String> values = Sets.newLinkedHashSet();
for (String key : Iterables.filter(formParameters.keySet(), new Predicate<String>() {
public boolean apply(String input) {
return input.startsWith(prefix);
}
})) {
values.add(formParameters.get(key).iterator().next());
}
return values;
}
}

View File

@ -31,4 +31,10 @@ import org.jclouds.aws.reference.AWSConstants;
* @author Adrian Cole
*/
public interface EC2Constants extends AWSConstants {
public static final String PROPERTY_EC2_ENDPOINT = "jclouds.ec2.endpoint";
/**
* how long do we wait before expiring requests.
*/
public static final String PROPERTY_EC2_EXPIREINTERVAL = "jclouds.ec2.expireinterval";
}

View File

@ -29,7 +29,7 @@ package org.jclouds.aws.ec2.reference;
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/Query-Common-Parameters.html"/>
* @author Adrian Cole
*/
public interface CommonEC2Parameters {
public interface EC2Parameters {
/**
* Indicates the action to perform. Example: RunInstances

View File

@ -0,0 +1,24 @@
package org.jclouds.aws.ec2.util;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.rest.internal.GeneratedHttpRequest;
/**
*
* @author Adrian Cole
*/
public class EC2Utils {
public static void indexFormValuesWithPrefix(GeneratedHttpRequest<?> request, String prefix,
Object input) {
checkArgument(checkNotNull(input, "input") instanceof String[],
"this binder is only valid for String[] : " + input.getClass());
String[] values = (String[]) input;
for (int i = 0; i < values.length; i++) {
request.addFormParam(prefix + "." + (i + 1), checkNotNull(values[i], prefix
.toLowerCase()
+ "s[" + i + "]"));
}
}
}

View File

@ -0,0 +1,218 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Set;
import java.util.SortedSet;
import javax.annotation.Resource;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.InstanceType;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.http.functions.ParseSax.HandlerWithResult;
import org.jclouds.logging.Logger;
import org.jclouds.util.DateService;
import org.joda.time.DateTime;
import org.xml.sax.Attributes;
import com.google.common.collect.Sets;
public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
protected final DateService dateService;
public BaseReservationHandler(DateService dateService) {
this.dateService = dateService;
}
@Resource
protected Logger logger = Logger.NULL;
private StringBuilder currentText = new StringBuilder();
private SortedSet<String> groupIds = Sets.newTreeSet();
private SortedSet<RunningInstance> instances = Sets.newTreeSet();
private String ownerId;
private String requesterId;
private String reservationId;
private String amiLaunchIndex;
private String dnsName;
private String imageId;
private String instanceId;
private InstanceState instanceState;
private InstanceType instanceType;
private InetAddress ipAddress;
private String kernelId;
private String keyName;
private DateTime launchTime;
private boolean monitoring;
private String availabilityZone;
private String platform;
private String privateDnsName;
private InetAddress privateIpAddress;
private Set<String> productCodes = Sets.newHashSet();
private String ramdiskId;
private String reason;
private String subnetId;
private String vpcId;
protected boolean inInstances;
protected boolean inProductCodes;
protected boolean inGroups;
public void startElement(String uri, String name, String qName, Attributes attrs) {
if (qName.equals("instancesSet")) {
inInstances = true;
} else if (qName.equals("productCodesSet")) {
inProductCodes = true;
} else if (qName.equals("groupSet")) {
inGroups = true;
}
}
protected String currentOrNull() {
String returnVal = currentText.toString().trim();
return returnVal.equals("") ? null : returnVal;
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("groupId")) {
groupIds.add(currentOrNull());
} else if (qName.equals("ownerId")) {
ownerId = currentOrNull();
} else if (qName.equals("requesterId")) {
requesterId = currentOrNull();
} else if (qName.equals("reservationId")) {
reservationId = currentOrNull();
} else if (qName.equals("amiLaunchIndex")) {
amiLaunchIndex = currentOrNull();
} else if (qName.equals("dnsName")) {
dnsName = currentOrNull();
} else if (qName.equals("imageId")) {
imageId = currentOrNull();
} else if (qName.equals("instanceId")) {
instanceId = currentOrNull();
} else if (qName.equals("name")) {
instanceState = InstanceState.fromValue(currentOrNull());
} else if (qName.equals("instanceType")) {
instanceType = InstanceType.fromValue(currentOrNull());
} else if (qName.equals("ipAddress")) {
ipAddress = parseInetAddress(currentOrNull());
} else if (qName.equals("kernelId")) {
kernelId = currentOrNull();
} else if (qName.equals("keyName")) {
keyName = currentOrNull();
} else if (qName.equals("launchTime")) {
launchTime = dateService.iso8601DateParse(currentOrNull());
} else if (qName.equals("enabled")) {
monitoring = Boolean.parseBoolean(currentOrNull());
} else if (qName.equals("availabilityZone")) {
availabilityZone = currentOrNull();
} else if (qName.equals("platform")) {
platform = currentOrNull();
} else if (qName.equals("privateDnsName")) {
privateDnsName = currentOrNull();
} else if (qName.equals("privateIpAddress")) {
privateIpAddress = parseInetAddress(currentOrNull());
} else if (qName.equals("ramdiskId")) {
ramdiskId = currentOrNull();
} else if (qName.equals("reason")) {
reason = currentOrNull();
} else if (qName.equals("subnetId")) {
subnetId = currentOrNull();
} else if (qName.equals("vpcId")) {
vpcId = currentOrNull();
} else if (qName.equals("productCode")) {
productCodes.add(currentOrNull());
} else if (qName.equals("productCodesSet")) {
inProductCodes = false;
} else if (qName.equals("instancesSet")) {
inInstances = false;
} else if (qName.equals("groupSet")) {
inGroups = false;
} else if (qName.equals("item")) {
inItem();
}
currentText = new StringBuilder();
}
protected void inItem() {
if (inInstances && !inProductCodes) {
instances.add(new RunningInstance(amiLaunchIndex, dnsName, imageId, instanceId,
instanceState, instanceType, ipAddress, kernelId, keyName, launchTime,
monitoring, availabilityZone, platform, privateDnsName, privateIpAddress,
productCodes, ramdiskId, reason, subnetId, vpcId));
this.amiLaunchIndex = null;
this.dnsName = null;
this.imageId = null;
this.instanceId = null;
this.instanceState = null;
this.instanceType = null;
this.ipAddress = null;
this.kernelId = null;
this.keyName = null;
this.launchTime = null;
this.monitoring = false;
this.availabilityZone = null;
this.platform = null;
this.privateDnsName = null;
this.privateIpAddress = null;
this.productCodes = Sets.newHashSet();
this.ramdiskId = null;
this.reason = null;
this.subnetId = null;
this.vpcId = null;
}
}
private InetAddress parseInetAddress(String string) {
String[] byteStrings = string.split("\\.");
byte[] bytes = new byte[4];
for (int i = 0; i < 4; i++) {
bytes[i] = (byte) Integer.parseInt(byteStrings[i]);
}
try {
return InetAddress.getByAddress(bytes);
} catch (UnknownHostException e) {
logger.warn(e, "error parsing ipAddress", currentText);
}
return null;
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
protected Reservation newReservation() {
Reservation info = new Reservation(groupIds, instances, ownerId, requesterId, reservationId);
this.groupIds = Sets.newTreeSet();
this.instances = Sets.newTreeSet();
this.ownerId = null;
this.requesterId = null;
this.reservationId = null;
return info;
}
}

View File

@ -0,0 +1,137 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import java.util.Set;
import java.util.SortedSet;
import javax.annotation.Resource;
import org.jclouds.aws.ec2.domain.Image;
import org.jclouds.aws.ec2.domain.Image.Architecture;
import org.jclouds.aws.ec2.domain.Image.ImageState;
import org.jclouds.aws.ec2.domain.Image.ImageType;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.logging.Logger;
import org.xml.sax.Attributes;
import com.google.common.collect.Sets;
import com.google.inject.internal.Nullable;
/**
* Parses the following XML document:
* <p/>
* DescribeImagesResponse xmlns="http://ec2.amazonaws.com/doc/2009-08-15/"
*
* @author Adrian Cole
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeImages.html"
* />
*/
public class DescribeImagesResponseHandler extends ParseSax.HandlerWithResult<SortedSet<Image>> {
@Resource
protected Logger logger = Logger.NULL;
private SortedSet<Image> contents = Sets.newTreeSet();
private StringBuilder currentText = new StringBuilder();
private Architecture architecture;
private String imageId;
private String imageLocation;
private String imageOwnerId;
private ImageState imageState;
private ImageType imageType;
private boolean isPublic;
private @Nullable
String kernelId;
private String platform;
private Set<String> productCodes = Sets.newHashSet();
private @Nullable
String ramdiskId;
private boolean inProductCodes;
public SortedSet<Image> getResult() {
return contents;
}
public void startElement(String uri, String name, String qName, Attributes attrs) {
if (qName.equals("productCodesSet")) {
inProductCodes = true;
}
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("architecture")) {
architecture = Architecture.fromValue(currentText.toString().trim());
} else if (qName.equals("imageId")) {
imageId = currentText.toString().trim();
} else if (qName.equals("imageLocation")) {
imageLocation = currentText.toString().trim();
} else if (qName.equals("imageOwnerId")) {
imageOwnerId = currentText.toString().trim();
} else if (qName.equals("imageState")) {
imageState = ImageState.fromValue(currentText.toString().trim());
} else if (qName.equals("imageType")) {
imageType = ImageType.fromValue(currentText.toString().trim());
} else if (qName.equals("isPublic")) {
isPublic = Boolean.parseBoolean(currentText.toString().trim());
} else if (qName.equals("kernelId")) {
kernelId = currentText.toString().trim();
} else if (qName.equals("platform")) {
platform = currentText.toString().trim();
} else if (qName.equals("productCode")) {
productCodes.add(currentText.toString().trim());
} else if (qName.equals("productCodesSet")) {
inProductCodes = false;
} else if (qName.equals("ramdiskId")) {
ramdiskId = currentText.toString().trim();
} else if (qName.equals("item")) {
if (!inProductCodes) {
try {
contents.add(new Image(architecture, imageId, imageLocation, imageOwnerId,
imageState, imageType, isPublic, kernelId, platform, productCodes,
ramdiskId));
} catch (NullPointerException e) {
logger.warn(e, "malformed image: %s", imageId);
}
this.architecture = null;
this.imageId = null;
this.imageLocation = null;
this.imageOwnerId = null;
this.imageState = null;
this.imageType = null;
this.isPublic = false;
this.kernelId = null;
this.platform = null;
this.productCodes = Sets.newHashSet();
this.ramdiskId = null;
}
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,66 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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:
*
* 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.aws.ec2.xml;
import java.util.SortedSet;
import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.util.DateService;
import com.google.common.collect.Sets;
/**
* Parses the following XML document:
* <p/>
* DescribeImagesResponse xmlns="http:
*
* @author Adrian Cole
* @see <a href="http: />
*/
public class DescribeInstancesResponseHandler extends
BaseReservationHandler<SortedSet<Reservation>> {
private SortedSet<Reservation> reservations = Sets.newTreeSet();
@Inject
DescribeInstancesResponseHandler(DateService dateService) {
super(dateService);
}
@Override
public SortedSet<Reservation> getResult() {
return reservations;
}
@Override
protected void inItem() {
if (!inInstances && !inProductCodes && !inGroups) {
reservations.add(super.newReservation());
} else {
super.inItem();
}
}
}

View File

@ -0,0 +1,67 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import java.util.SortedSet;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.http.functions.ParseSax;
import com.google.common.collect.Sets;
/**
* Parses: DescribeKeyPairsResponse xmlns="http://ec2.amazonaws.com/doc/2009-08-15/"
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeKeyPairs.html"
* />
* @author Adrian Cole
*/
public class DescribeKeyPairsResponseHandler extends ParseSax.HandlerWithResult<SortedSet<KeyPair>> {
private StringBuilder currentText = new StringBuilder();
private SortedSet<KeyPair> keyPairs = Sets.newTreeSet();
private String keyFingerprint;
private String keyName;
public SortedSet<KeyPair> getResult() {
return keyPairs;
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("keyFingerprint")) {
this.keyFingerprint = currentText.toString().trim();
} else if (qName.equals("item")) {
keyPairs.add(new KeyPair(keyName, keyFingerprint, null));
} else if (qName.equals("keyName")) {
this.keyName = currentText.toString().trim();
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,133 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import java.util.SortedSet;
import org.jclouds.aws.ec2.domain.IpPermission;
import org.jclouds.aws.ec2.domain.IpProtocol;
import org.jclouds.aws.ec2.domain.SecurityGroup;
import org.jclouds.aws.ec2.domain.UserIdGroupPair;
import org.jclouds.http.functions.ParseSax;
import org.xml.sax.Attributes;
import com.google.common.collect.Sets;
/**
* Parses: DescribeSecurityGroupsResponse xmlns="http://ec2.amazonaws.com/doc/2009-08-15/"
*
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-query-DescribeSecurityGroups.html"
* />
* @author Adrian Cole
*/
public class DescribeSecurityGroupsResponseHandler extends
ParseSax.HandlerWithResult<SortedSet<SecurityGroup>> {
private StringBuilder currentText = new StringBuilder();
private SortedSet<SecurityGroup> securtyGroups = Sets.newTreeSet();
private String groupName;
private String ownerId;
private String groupDescription;
private SortedSet<IpPermission> ipPermissions = Sets.newTreeSet();
private int fromPort;
private int toPort;
private SortedSet<UserIdGroupPair> groups = Sets.newTreeSet();
private String userId;
private String userIdGroupName;
private IpProtocol ipProtocol;
private SortedSet<String> ipRanges = Sets.newTreeSet();
private boolean inIpPermissions;
private boolean inIpRanges;
private boolean inGroups;
public SortedSet<SecurityGroup> getResult() {
return securtyGroups;
}
public void startElement(String uri, String name, String qName, Attributes attrs) {
if (qName.equals("ipPermissions")) {
inIpPermissions = true;
} else if (qName.equals("ipRanges")) {
inIpRanges = true;
} else if (qName.equals("groups")) {
inGroups = true;
}
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("groupName")) {
if (!inGroups)
this.groupName = currentText.toString().trim();
else
this.userIdGroupName = currentText.toString().trim();
} else if (qName.equals("ownerId")) {
this.ownerId = currentText.toString().trim();
} else if (qName.equals("userId")) {
this.userId = currentText.toString().trim();
} else if (qName.equals("groupDescription")) {
this.groupDescription = currentText.toString().trim();
} else if (qName.equals("ipProtocol")) {
this.ipProtocol = IpProtocol.fromValue(currentText.toString().trim());
} else if (qName.equals("fromPort")) {
this.fromPort = Integer.parseInt(currentText.toString().trim());
} else if (qName.equals("toPort")) {
this.toPort = Integer.parseInt(currentText.toString().trim());
} else if (qName.equals("cidrIp")) {
this.ipRanges.add(currentText.toString().trim());
} else if (qName.equals("ipPermissions")) {
inIpPermissions = false;
} else if (qName.equals("ipRanges")) {
inIpRanges = false;
} else if (qName.equals("groups")) {
inGroups = false;
} else if (qName.equals("item")) {
if (inIpPermissions && !inIpRanges && !inGroups) {
ipPermissions.add(new IpPermission(fromPort, toPort, groups, ipProtocol, ipRanges));
this.fromPort = -1;
this.toPort = -1;
this.groups = Sets.newTreeSet();
this.ipProtocol = null;
this.ipRanges = Sets.newTreeSet();
} else if (inIpPermissions && !inIpRanges && inGroups) {
this.groups.add(new UserIdGroupPair(userId, userIdGroupName));
this.userId = null;
this.userIdGroupName = null;
} else if (!inIpPermissions && !inIpRanges && !inGroups) {
securtyGroups
.add(new SecurityGroup(groupName, ownerId, groupDescription, ipPermissions));
this.groupName = null;
this.ownerId = null;
this.groupDescription = null;
this.ipPermissions = Sets.newTreeSet();
}
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,63 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.http.functions.ParseSax;
/**
*
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CreateKeyPair.html"
* />
* @author Adrian Cole
*/
public class KeyPairResponseHandler extends ParseSax.HandlerWithResult<KeyPair> {
private StringBuilder currentText = new StringBuilder();
private String keyFingerprint;
private String keyMaterial;
private String keyName;
public KeyPair getResult() {
return new KeyPair(keyName, keyFingerprint, keyMaterial);
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("keyFingerprint")) {
this.keyFingerprint = currentText.toString().trim();
} else if (qName.equals("keyMaterial")) {
this.keyMaterial = currentText.toString().trim();
} else if (qName.equals("keyName")) {
this.keyName = currentText.toString().trim();
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -11,7 +11,7 @@
* "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
* http:
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
@ -21,31 +21,31 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.ec2;
package org.jclouds.aws.ec2.xml;
import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.util.DateService;
/**
* Represents an authenticated context to EC2.
* Parses the following XML document:
* <p/>
* RunInstancesResponse xmlns="http:
*
* <h2>Note</h2> Please issue {@link #close()} when you are finished with this
* context in order to release resources.
*
*
* @see EC2Connection
* @author Adrian Cole
*
* @see <a href="http: />
*/
public interface EC2Context {
public class RunInstancesResponseHandler extends BaseReservationHandler<Reservation> {
/**
* low-level api to EC2. Threadsafe implementations will return a singleton.
*
* @return a connection to EC2
*/
EC2Connection getConnection();
@Inject
RunInstancesResponseHandler(DateService dateService) {
super(dateService);
}
/**
* Closes all connections to EC2.
*/
void close();
@Override
public Reservation getResult() {
return newReservation();
}
}

View File

@ -0,0 +1,102 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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:
*
* 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.aws.ec2.xml;
import java.util.SortedSet;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.TerminatedInstance;
import org.jclouds.http.functions.ParseSax.HandlerWithResult;
import org.xml.sax.Attributes;
import com.google.common.collect.Sets;
/**
* Parses the following XML document:
* <p/>
* TerminateInstancesResponse xmlns="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-TerminateInstancesResponseInfoType.html"
*
* @author Adrian Cole
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-TerminateInstancesResponseInfoType.html"
* />
*/
public class TerminateInstancesResponseHandler extends
HandlerWithResult<SortedSet<TerminatedInstance>> {
private StringBuilder currentText = new StringBuilder();
SortedSet<TerminatedInstance> instances = Sets.newTreeSet();
private InstanceState shutdownState;
private InstanceState previousState;
private String instanceId;
private boolean inShutdownState;
private boolean inPreviousState;
@Override
public SortedSet<TerminatedInstance> getResult() {
return instances;
}
public void startElement(String uri, String name, String qName, Attributes attrs) {
if (qName.equals("shutdownState")) {
inShutdownState = true;
} else if (qName.equals("previousState")) {
inPreviousState = true;
}
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("instanceId")) {
this.instanceId = currentOrNull();
} else if (qName.equals("shutdownState")) {
inShutdownState = false;
} else if (qName.equals("previousState")) {
inPreviousState = false;
} else if (qName.equals("name")) {
if (inShutdownState) {
shutdownState = InstanceState.fromValue(currentOrNull());
} else if (inPreviousState) {
previousState = InstanceState.fromValue(currentOrNull());
}
} else if (qName.equals("item")) {
instances.add(new TerminatedInstance(instanceId, shutdownState, previousState));
this.instanceId = null;
this.shutdownState = null;
this.previousState = null;
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
protected String currentOrNull() {
String returnVal = currentText.toString().trim();
return returnVal.equals("") ? null : returnVal;
}
}

View File

@ -0,0 +1,82 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.handlers;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpConstants;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.logging.Logger;
import org.jclouds.util.Utils;
/**
* Handles Retryable responses with error codes in the 3xx range
*
* @author Adrian Cole
*/
public class AWSClientErrorRetryHandler implements HttpRetryHandler {
@Inject(optional = true)
@Named(HttpConstants.PROPERTY_HTTP_MAX_RETRIES)
private int retryCountLimit = 5;
private final AWSUtils utils;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public AWSClientErrorRetryHandler(AWSUtils utils) {
this.utils = utils;
}
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
if (command.getFailureCount() > retryCountLimit)
return false;
if (response.getStatusCode() == 400 || response.getStatusCode() == 403
|| response.getStatusCode() == 409) {
byte[] content = Utils.closeClientButKeepContentStream(response);
command.incrementFailureCount();
try {
AWSError error = utils.parseAWSErrorFromContent(command, response, new String(content));
if ("RequestTimeout".equals(error.getCode())
|| "OperationAborted".equals(error.getCode())
|| "SignatureDoesNotMatch".equals(error.getCode())) {
return true;
}
} catch (HttpException e) {
logger.warn(e, "error parsing response: %s", new String(content));
}
}
return false;
}
}

View File

@ -0,0 +1,90 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.handlers;
import javax.inject.Inject;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.reference.AWSConstants;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.http.handlers.RedirectionRetryHandler;
import org.jclouds.util.Utils;
/**
* Handles Retryable responses with error codes in the 3xx range
*
* @author Adrian Cole
*/
public class AWSRedirectionRetryHandler extends RedirectionRetryHandler {
private final AWSUtils utils;
@Inject
public AWSRedirectionRetryHandler(BackoffLimitedRetryHandler backoffHandler, AWSUtils utils) {
super(backoffHandler);
this.utils = utils;
}
@Override
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
if (response.getFirstHeaderOrNull(HttpHeaders.LOCATION) == null
&& (response.getStatusCode() == 301 || response.getStatusCode() == 307)) {
byte[] content = Utils.closeClientButKeepContentStream(response);
if (command.getRequest().getMethod() == HttpMethod.HEAD) {
command.setMethod(HttpMethod.GET);
return true;
} else {
command.incrementRedirectCount();
try {
AWSError error = utils.parseAWSErrorFromContent(command, response, new String(
content));
String host = error.getDetails().get(AWSConstants.ENDPOINT);
if (host != null) {
if (host.equals(command.getRequest().getEndpoint().getHost())) {
// must be an amazon error related to
// http://developer.amazonwebservices.com/connect/thread.jspa?messageID=72287&#72287
return backoffHandler.shouldRetryRequest(command, response);
} else {
command.setHostAndPort(host, command.getRequest().getEndpoint().getPort());
}
return true;
} else {
return false;
}
} catch (HttpException e) {
logger.error(e, "error on redirect for command %s; response %s; retrying...",
command, response);
return false;
}
}
} else {
return super.shouldRetryRequest(command, response);
}
}
}

View File

@ -0,0 +1,83 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.handlers;
import javax.annotation.Resource;
import javax.inject.Inject;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.Logger;
import org.jclouds.util.Utils;
/**
* This will parse and set an appropriate exception on the command object.
*
* @see AWSError
* @author Adrian Cole
*
*/
public class ParseAWSErrorFromXmlContent implements HttpErrorHandler {
@Resource
protected Logger logger = Logger.NULL;
private final AWSUtils utils;
@Inject
public ParseAWSErrorFromXmlContent(AWSUtils utils) {
this.utils = utils;
}
public void handleError(HttpCommand command, HttpResponse response) {
String content;
try {
content = response.getContent() != null ? Utils.toStringAndClose(response.getContent())
: null;
if (content != null) {
try {
if (content.indexOf('<') >= 0) {
AWSError error = utils.parseAWSErrorFromContent(command, response, content);
command.setException(new AWSResponseException(command, response, error));
} else {
command.setException(new HttpResponseException(command, response, content));
}
} catch (Exception he) {
command.setException(new HttpResponseException(command, response, content));
Utils.rethrowIfRuntime(he);
}
} else {
command.setException(new HttpResponseException(command, response));
}
} catch (Exception e) {
command.setException(new HttpResponseException(command, response));
Utils.rethrowIfRuntime(e);
}
}
}

View File

@ -21,8 +21,9 @@
* under the License.
* ====================================================================
*/
package org.jclouds.aws.ec2;
public class EC2Connection {
}
/**
* This package contains HttpResponseHandlers needed to operate the REST api.
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/latest/RESTAuthentication.html" />
* @author Adrian Cole
*/
package org.jclouds.aws.handlers;

View File

@ -0,0 +1,357 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.aws.ec2.options.DescribeImagesOptions.Builder.imageIds;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.aws.ec2.domain.Image;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.domain.IpPermission;
import org.jclouds.aws.ec2.domain.IpProtocol;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.SecurityGroup;
import org.jclouds.aws.ec2.domain.UserIdGroupPair;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
/**
* Tests behavior of {@code EC2Client}
*
* @author Adrian Cole
*/
@Test(groups = "live", sequential = true, testName = "ec2.EC2ClientLiveTest")
public class EC2ClientLiveTest {
private EC2Client client;
private String user;
@BeforeGroups(groups = { "live" })
public void setupClient() throws InterruptedException, ExecutionException, TimeoutException {
user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
String password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
client = EC2ContextFactory.createContext(user, password, new Log4JLoggingModule()).getApi();
}
@Test
void testDescribeImages() throws InterruptedException, ExecutionException, TimeoutException {
SortedSet<Image> allResults = client.describeImages().get(30, TimeUnit.SECONDS);
assertNotNull(allResults);
assert allResults.size() >= 2 : allResults.size();
Iterator<Image> iterator = allResults.iterator();
String id1 = iterator.next().getImageId();
String id2 = iterator.next().getImageId();
SortedSet<Image> twoResults = client.describeImages(imageIds(id1, id2)).get(30,
TimeUnit.SECONDS);
assertNotNull(twoResults);
assertEquals(twoResults.size(), 2);
iterator = twoResults.iterator();
assertEquals(iterator.next().getImageId(), id1);
assertEquals(iterator.next().getImageId(), id2);
}
@Test
void testDescribeInstances() throws InterruptedException, ExecutionException, TimeoutException {
SortedSet<Reservation> allResults = client.describeInstances().get(30, TimeUnit.SECONDS);
assertNotNull(allResults);
assert allResults.size() >= 0 : allResults.size();
if (allResults.size() >= 2) {
Iterator<RunningInstance> iterator = allResults.iterator().next().getRunningInstances()
.iterator();
String id1 = iterator.next().getInstanceId();
String id2 = iterator.next().getInstanceId();
SortedSet<Reservation> twoResults = client.describeInstances(id1, id2).get(30,
TimeUnit.SECONDS);
assertNotNull(twoResults);
assertEquals(twoResults.size(), 2);
iterator = twoResults.iterator().next().getRunningInstances().iterator();
assertEquals(iterator.next().getInstanceId(), id1);
assertEquals(iterator.next().getInstanceId(), id2);
}
}
@Test
void testDescribeKeyPairs() throws InterruptedException, ExecutionException, TimeoutException {
SortedSet<KeyPair> allResults = client.describeKeyPairs().get(30, TimeUnit.SECONDS);
assertNotNull(allResults);
assert allResults.size() >= 0 : allResults.size();
if (allResults.size() >= 2) {
Iterator<KeyPair> iterator = allResults.iterator();
String id1 = iterator.next().getKeyName();
String id2 = iterator.next().getKeyName();
SortedSet<KeyPair> twoResults = client.describeKeyPairs(id1, id2)
.get(30, TimeUnit.SECONDS);
assertNotNull(twoResults);
assertEquals(twoResults.size(), 2);
iterator = twoResults.iterator();
assertEquals(iterator.next().getKeyName(), id1);
assertEquals(iterator.next().getKeyName(), id2);
}
}
@Test
void testDescribeSecurityGroups() throws InterruptedException, ExecutionException,
TimeoutException {
SortedSet<SecurityGroup> allResults = client.describeSecurityGroups().get(30,
TimeUnit.SECONDS);
assertNotNull(allResults);
assert allResults.size() >= 0 : allResults.size();
if (allResults.size() >= 2) {
Iterator<SecurityGroup> iterator = allResults.iterator();
String id1 = iterator.next().getName();
String id2 = iterator.next().getName();
SortedSet<SecurityGroup> twoResults = client.describeSecurityGroups(id1, id2).get(30,
TimeUnit.SECONDS);
assertNotNull(twoResults);
assertEquals(twoResults.size(), 2);
iterator = twoResults.iterator();
assertEquals(iterator.next().getName(), id1);
assertEquals(iterator.next().getName(), id2);
}
}
public static final String PREFIX = System.getProperty("user.name") + "-ec2";
@Test
void testCreateKeyPair() throws InterruptedException, ExecutionException, TimeoutException {
String keyName = PREFIX + "1";
try {
client.deleteKeyPair(keyName).get(30, TimeUnit.SECONDS);
} catch (Exception e) {
}
client.deleteKeyPair(keyName).get(30, TimeUnit.SECONDS);
KeyPair result = client.createKeyPair(keyName).get(30, TimeUnit.SECONDS);
assertNotNull(result);
assertNotNull(result.getKeyMaterial());
assertNotNull(result.getKeyFingerprint());
assertEquals(result.getKeyName(), keyName);
SortedSet<KeyPair> twoResults = client.describeKeyPairs(keyName).get(30, TimeUnit.SECONDS);
assertNotNull(twoResults);
assertEquals(twoResults.size(), 1);
KeyPair listPair = twoResults.iterator().next();
assertEquals(listPair.getKeyName(), result.getKeyName());
assertEquals(listPair.getKeyFingerprint(), result.getKeyFingerprint());
}
@Test
void testCreateSecurityGroup() throws InterruptedException, ExecutionException, TimeoutException {
String groupName = PREFIX + "1";
String groupDescription = PREFIX + "1 description";
try {
client.deleteSecurityGroup(groupName).get(30, TimeUnit.SECONDS);
} catch (Exception e) {
}
client.deleteSecurityGroup(groupName).get(30, TimeUnit.SECONDS);
client.createSecurityGroup(groupName, groupDescription).get(30, TimeUnit.SECONDS);
verifySecurityGroup(groupName, groupDescription);
}
@Test
void testAuthorizeSecurityGroupIngressCidr() throws InterruptedException, ExecutionException,
TimeoutException {
String groupName = PREFIX + "ingress";
try {
client.deleteSecurityGroup(groupName).get(30, TimeUnit.SECONDS);
} catch (Exception e) {
}
client.createSecurityGroup(groupName, groupName).get(30, TimeUnit.SECONDS);
client.authorizeSecurityGroupIngress(groupName, IpProtocol.TCP, 80, 80, "0.0.0.0/0").get(30,
TimeUnit.SECONDS);
assertEventually(new GroupHasPermission(client, groupName, new IpPermission(80, 80, Sets
.<UserIdGroupPair> newTreeSet(), IpProtocol.TCP, ImmutableSortedSet.of("0.0.0.0/0"))));
client.revokeSecurityGroupIngress(groupName, IpProtocol.TCP, 80, 80, "0.0.0.0/0").get(30,
TimeUnit.SECONDS);
assertEventually(new GroupHasNoPermissions(client, groupName));
}
private void verifySecurityGroup(String groupName, String description)
throws InterruptedException, ExecutionException, TimeoutException {
SortedSet<SecurityGroup> oneResult = client.describeSecurityGroups(groupName).get(30,
TimeUnit.SECONDS);
assertNotNull(oneResult);
assertEquals(oneResult.size(), 1);
SecurityGroup listPair = oneResult.iterator().next();
assertEquals(listPair.getName(), groupName);
assertEquals(listPair.getDescription(), description);
}
@Test(enabled = false)
// TODO
void testAuthorizeSecurityGroupIngressSourceGroup() throws InterruptedException,
ExecutionException, TimeoutException {
String group1Name = PREFIX + "ingress1";
String group2Name = PREFIX + "ingress2";
try {
client.deleteSecurityGroup(group1Name).get(30, TimeUnit.SECONDS);
} catch (Exception e) {
}
try {
client.deleteSecurityGroup(group2Name).get(30, TimeUnit.SECONDS);
} catch (Exception e) {
}
client.createSecurityGroup(group1Name, group1Name).get(30, TimeUnit.SECONDS);
client.createSecurityGroup(group2Name, group2Name).get(30, TimeUnit.SECONDS);
ensureGroupsExist(group1Name, group2Name);
client.authorizeSecurityGroupIngress(group1Name, IpProtocol.TCP, 80, 80, "0.0.0.0/0").get(30,
TimeUnit.SECONDS);
assertEventually(new GroupHasPermission(client, group2Name, new IpPermission(80, 80, Sets
.<UserIdGroupPair> newTreeSet(), IpProtocol.TCP, ImmutableSortedSet.of("0.0.0.0/0"))));
SortedSet<SecurityGroup> oneResult = client.describeSecurityGroups(group1Name).get(30,
TimeUnit.SECONDS);
assertNotNull(oneResult);
assertEquals(oneResult.size(), 1);
SecurityGroup group = oneResult.iterator().next();
assertEquals(group.getName(), group1Name);
client.authorizeSecurityGroupIngress(group2Name,
new UserIdGroupPair(group.getOwnerId(), group1Name)).get(30, TimeUnit.SECONDS);
assertEventually(new GroupHasPermission(client, group2Name, new IpPermission(80, 80, Sets
.<UserIdGroupPair> newTreeSet(), IpProtocol.TCP, ImmutableSortedSet.of("0.0.0.0/0"))));
client.revokeSecurityGroupIngress(group2Name,
new UserIdGroupPair(group.getOwnerId(), group1Name)).get(30, TimeUnit.SECONDS);
assertEventually(new GroupHasNoPermissions(client, group2Name));
}
private static final class GroupHasPermission implements Runnable {
private final EC2Client client;
private final String group;
private final IpPermission permission;
private GroupHasPermission(EC2Client client, String group, IpPermission permission) {
this.client = client;
this.group = group;
this.permission = permission;
}
public void run() {
try {
SortedSet<SecurityGroup> oneResult = client.describeSecurityGroups(group).get(30,
TimeUnit.SECONDS);
assertNotNull(oneResult);
assertEquals(oneResult.size(), 1);
SecurityGroup listPair = oneResult.iterator().next();
assert listPair.getIpPermissions().contains(permission);
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
private static final class GroupHasNoPermissions implements Runnable {
private final EC2Client client;
private final String group;
private GroupHasNoPermissions(EC2Client client, String group) {
this.client = client;
this.group = group;
}
public void run() {
try {
SortedSet<SecurityGroup> oneResult = client.describeSecurityGroups(group).get(30,
TimeUnit.SECONDS);
assertNotNull(oneResult);
assertEquals(oneResult.size(), 1);
SecurityGroup listPair = oneResult.iterator().next();
assertEquals(listPair.getIpPermissions().size(), 0);
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
private void ensureGroupsExist(String group1Name, String group2Name)
throws InterruptedException, ExecutionException, TimeoutException {
SortedSet<SecurityGroup> twoResults = client.describeSecurityGroups(group1Name, group2Name)
.get(30, TimeUnit.SECONDS);
assertNotNull(twoResults);
assertEquals(twoResults.size(), 2);
Iterator<SecurityGroup> iterator = twoResults.iterator();
SecurityGroup listPair1 = iterator.next();
assertEquals(listPair1.getName(), group1Name);
assertEquals(listPair1.getDescription(), group1Name);
SecurityGroup listPair2 = iterator.next();
assertEquals(listPair2.getName(), group2Name);
assertEquals(listPair2.getDescription(), group2Name);
}
private static final int INCONSISTENCY_WINDOW = 5000;
/**
* Due to eventual consistency, container commands may not return correctly immediately. Hence,
* we will try up to the inconsistency window to see if the assertion completes.
*/
protected static void assertEventually(Runnable assertion) throws InterruptedException {
long start = System.currentTimeMillis();
AssertionError error = null;
for (int i = 0; i < 30; i++) {
try {
assertion.run();
if (i > 0)
System.err.printf("%d attempts and %dms asserting %s%n", i + 1, System
.currentTimeMillis()
- start, assertion.getClass().getSimpleName());
return;
} catch (AssertionError e) {
error = e;
}
Thread.sleep(INCONSISTENCY_WINDOW / 30);
}
if (error != null)
throw error;
}
}

View File

@ -0,0 +1,481 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2;
import static org.jclouds.aws.ec2.options.DescribeImagesOptions.Builder.executableBy;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.net.URI;
import org.jclouds.aws.ec2.domain.IpProtocol;
import org.jclouds.aws.ec2.domain.UserIdGroupPair;
import org.jclouds.aws.ec2.filters.FormSigner;
import org.jclouds.aws.ec2.functions.ReturnVoidOnGroupNotFound;
import org.jclouds.aws.ec2.options.DescribeImagesOptions;
import org.jclouds.aws.ec2.options.RunInstancesOptions;
import org.jclouds.aws.ec2.xml.DescribeImagesResponseHandler;
import org.jclouds.aws.ec2.xml.DescribeInstancesResponseHandler;
import org.jclouds.aws.ec2.xml.DescribeKeyPairsResponseHandler;
import org.jclouds.aws.ec2.xml.DescribeSecurityGroupsResponseHandler;
import org.jclouds.aws.ec2.xml.KeyPairResponseHandler;
import org.jclouds.aws.ec2.xml.RunInstancesResponseHandler;
import org.jclouds.aws.ec2.xml.TerminateInstancesResponseHandler;
import org.jclouds.aws.reference.AWSConstants;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReturnVoidIf2xx;
import org.jclouds.logging.Logger;
import org.jclouds.logging.Logger.LoggerFactory;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.Jsr330;
import org.jclouds.util.TimeStamp;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code EC2Client}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.EC2ClientTest")
public class EC2ClientTest extends RestClientTest<EC2Client> {
public void testDescribeImages() throws SecurityException, NoSuchMethodException, IOException {
Method method = EC2Client.class.getMethod("describeImages", Array.newInstance(
DescribeImagesOptions.class, 0).getClass());
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method);
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 40\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod, "Version=2009-08-15&Action=DescribeImages");
filter.filter(httpMethod);
assertEntityEquals(
httpMethod,
"Action=DescribeImages&Signature=wJmKTnrx5v3PSECZJjm%2BE1s8I%2FqHkVs2K1hJ6yxbpC0%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2009-11-08T15%3A54%3A08.897Z&Version=2009-08-15&AWSAccessKeyId=user");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeImagesResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testDescribeImagesOptions() throws SecurityException, NoSuchMethodException,
IOException {
Method method = EC2Client.class.getMethod("describeImages", Array.newInstance(
DescribeImagesOptions.class, 0).getClass());
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, executableBy(
"me").ownedBy("fred", "nancy").imageIds("1", "2"));
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 107\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(
httpMethod,
"Version=2009-08-15&Action=DescribeImages&ExecutableBy=me&Owner.1=fred&Owner.2=nancy&ImageId.1=1&ImageId.2=2");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeImagesResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testDescribeInstances() throws SecurityException, NoSuchMethodException, IOException {
Method method = EC2Client.class.getMethod("describeInstances", Array.newInstance(
String.class, 0).getClass());
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method);
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 43\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod, "Version=2009-08-15&Action=DescribeInstances");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeInstancesResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testDescribeInstancesArgs() throws SecurityException, NoSuchMethodException,
IOException {
Method method = EC2Client.class.getMethod("describeInstances", Array.newInstance(
String.class, 0).getClass());
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "1", "2");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 43\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod,
"Version=2009-08-15&Action=DescribeInstances&InstanceId.1=1&InstanceId.2=2");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeInstancesResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testTerminateInstances() throws SecurityException, NoSuchMethodException,
IOException {
Method method = EC2Client.class.getMethod("terminateInstances", String.class, Array
.newInstance(String.class, 0).getClass());
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "1", "2");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 59\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod,
"Version=2009-08-15&Action=TerminateInstances&InstanceId.0=1&InstanceId.1=2");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, TerminateInstancesResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testRunInstances() throws SecurityException, NoSuchMethodException, IOException {
Method method = EC2Client.class.getMethod("runInstances", String.class, int.class, int.class,
Array.newInstance(RunInstancesOptions.class, 0).getClass());
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "ami-voo", 1, 1);
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 76\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod,
"Version=2009-08-15&Action=RunInstances&ImageId=ami-voo&MaxCount=1&MinCount=1");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, RunInstancesResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testRunInstancesOptions() throws SecurityException, NoSuchMethodException,
IOException {
Method method = EC2Client.class.getMethod("runInstances", String.class, int.class, int.class,
Array.newInstance(RunInstancesOptions.class, 0).getClass());
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "ami-voo", 1, 5,
new RunInstancesOptions().withKernelId("kernelId").enableMonitoring());
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 118\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(
httpMethod,
"Version=2009-08-15&Action=RunInstances&ImageId=ami-voo&MaxCount=5&MinCount=1&KernelId=kernelId&Monitoring.Enabled=true");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, RunInstancesResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testCreateKeyPair() throws SecurityException, NoSuchMethodException, IOException {
Method method = EC2Client.class.getMethod("createKeyPair", String.class);
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "mykey");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 53\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod, "Version=2009-08-15&Action=CreateKeyPair&KeyName=mykey");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, KeyPairResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testDeleteKeyPair() throws SecurityException, NoSuchMethodException, IOException {
Method method = EC2Client.class.getMethod("deleteKeyPair", String.class);
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "mykey");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 53\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod, "Version=2009-08-15&Action=DeleteKeyPair&KeyName=mykey");
assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testDescribeKeyPairs() throws SecurityException, NoSuchMethodException, IOException {
Method method = EC2Client.class.getMethod("describeKeyPairs", Array.newInstance(String.class,
0).getClass());
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method);
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 42\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod, "Version=2009-08-15&Action=DescribeKeyPairs");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeKeyPairsResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testDescribeKeyPairsArgs() throws SecurityException, NoSuchMethodException,
IOException {
Method method = EC2Client.class.getMethod("describeKeyPairs", Array.newInstance(String.class,
0).getClass());
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "1", "2");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 42\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod,
"Version=2009-08-15&Action=DescribeKeyPairs&KeyName.1=1&KeyName.2=2");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeKeyPairsResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testDeleteSecurityGroup() throws SecurityException, NoSuchMethodException,
IOException {
Method method = EC2Client.class.getMethod("deleteSecurityGroup", String.class);
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "name");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 60\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod, "Version=2009-08-15&Action=DeleteSecurityGroup&GroupName=name");
assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnVoidOnGroupNotFound.class);
checkFilters(httpMethod);
}
public void testCreateSecurityGroup() throws SecurityException, NoSuchMethodException,
IOException {
Method method = EC2Client.class.getMethod("createSecurityGroup", String.class, String.class);
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "name",
"description");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 89\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod,
"Version=2009-08-15&Action=CreateSecurityGroup&GroupName=name&GroupDescription=description");
assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testDescribeSecurityGroups() throws SecurityException, NoSuchMethodException,
IOException {
Method method = EC2Client.class.getMethod("describeSecurityGroups", Array.newInstance(
String.class, 0).getClass());
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method);
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 48\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod, "Version=2009-08-15&Action=DescribeSecurityGroups");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeSecurityGroupsResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testDescribeSecurityGroupsArgs() throws SecurityException, NoSuchMethodException,
IOException {
Method method = EC2Client.class.getMethod("describeSecurityGroups", Array.newInstance(
String.class, 0).getClass());
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "1", "2");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 48\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(httpMethod,
"Version=2009-08-15&Action=DescribeSecurityGroups&GroupName.1=1&GroupName.2=2");
assertResponseParserClassEquals(method, httpMethod, ParseSax.class);
assertSaxResponseParserClassEquals(method, DescribeSecurityGroupsResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testAuthorizeSecurityGroupIngressGroup() throws SecurityException,
NoSuchMethodException, IOException {
Method method = EC2Client.class.getMethod("authorizeSecurityGroupIngress", String.class,
UserIdGroupPair.class);
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "group",
new UserIdGroupPair("sourceUser", "sourceGroup"));
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 71\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(
httpMethod,
"Version=2009-08-15&Action=AuthorizeSecurityGroupIngress&GroupName=group&SourceSecurityGroupOwnerId=sourceUser&SourceSecurityGroupName=sourceGroup");
assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testAuthorizeSecurityGroupIngressCidr() throws SecurityException,
NoSuchMethodException, IOException {
Method method = EC2Client.class.getMethod("authorizeSecurityGroupIngress", String.class,
IpProtocol.class, int.class, int.class, String.class);
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "group",
IpProtocol.TCP, 6000, 7000, "0.0.0.0/0");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 131\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(
httpMethod,
"Version=2009-08-15&Action=AuthorizeSecurityGroupIngress&GroupName=group&FromPort=6000&IpProtocol=tcp&ToPort=7000&CidrIp=0.0.0.0%2F0");
assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testRevokeSecurityGroupIngressGroup() throws SecurityException,
NoSuchMethodException, IOException {
Method method = EC2Client.class.getMethod("revokeSecurityGroupIngress", String.class,
UserIdGroupPair.class);
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "group",
new UserIdGroupPair("sourceUser", "sourceGroup"));
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 68\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(
httpMethod,
"Version=2009-08-15&Action=RevokeSecurityGroupIngress&GroupName=group&SourceSecurityGroupOwnerId=sourceUser&SourceSecurityGroupName=sourceGroup");
assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
public void testRevokeSecurityGroupIngressCidr() throws SecurityException,
NoSuchMethodException, IOException {
Method method = EC2Client.class.getMethod("revokeSecurityGroupIngress", String.class,
IpProtocol.class, int.class, int.class, String.class);
GeneratedHttpRequest<EC2Client> httpMethod = processor.createRequest(method, "group",
IpProtocol.TCP, 6000, 7000, "0.0.0.0/0");
assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1");
assertHeadersEqual(httpMethod,
"Content-Length: 128\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n");
assertEntityEquals(
httpMethod,
"Version=2009-08-15&Action=RevokeSecurityGroupIngress&GroupName=group&FromPort=6000&IpProtocol=tcp&ToPort=7000&CidrIp=0.0.0.0%2F0");
assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
@Override
protected void checkFilters(GeneratedHttpRequest<EC2Client> httpMethod) {
assertEquals(httpMethod.getFilters().size(), 1);
assertEquals(httpMethod.getFilters().get(0).getClass(), FormSigner.class);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<EC2Client>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<EC2Client>>() {
};
}
private FormSigner filter;
@Override
@BeforeTest
protected void setupFactory() {
super.setupFactory();
this.filter = injector.getInstance(FormSigner.class);
}
@Override
protected Module createModule() {
return new AbstractModule() {
@Override
protected void configure() {
bind(URI.class).annotatedWith(EC2.class).toInstance(
URI.create("https://ec2.amazonaws.com"));
bindConstant().annotatedWith(Jsr330.named(AWSConstants.PROPERTY_AWS_ACCESSKEYID)).to(
"user");
bindConstant().annotatedWith(Jsr330.named(AWSConstants.PROPERTY_AWS_SECRETACCESSKEY))
.to("key");
bind(Logger.LoggerFactory.class).toInstance(new LoggerFactory() {
public Logger getLogger(String category) {
return Logger.NULL;
}
});
}
@SuppressWarnings("unused")
@Provides
@TimeStamp
String provide() {
return "2009-11-08T15:54:08.897Z";
}
};
}
}

View File

@ -0,0 +1,98 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_ACCESSKEYID;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_SECRETACCESSKEY;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.jclouds.aws.ec2.config.EC2RestClientModule;
import org.jclouds.aws.ec2.filters.FormSigner;
import org.jclouds.aws.ec2.reference.EC2Constants;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.RestContextImpl;
import org.testng.annotations.Test;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of modules configured in EC2ContextBuilderT
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.EC2ContextBuilderTest")
public class EC2ContextBuilderTest {
public void testNewBuilder() {
EC2ContextBuilder builder = newBuilder();
assertEquals(builder.getProperties().getProperty(EC2Constants.PROPERTY_EC2_ENDPOINT),
"http://ec2.amazonaws.com");
assertEquals(builder.getProperties().getProperty(PROPERTY_AWS_ACCESSKEYID), "id");
assertEquals(builder.getProperties().getProperty(PROPERTY_AWS_SECRETACCESSKEY), "secret");
}
public void testBuildContext() {
RestContext<EC2Client> context = newBuilder().buildContext();
assertEquals(context.getClass(), RestContextImpl.class);
assertEquals(context.getAccount(), "id");
assertEquals(context.getEndPoint(), URI.create("http://ec2.amazonaws.com"));
}
public void testBuildInjector() {
Injector i = newBuilder().buildInjector();
assert i.getInstance(Key.get(new TypeLiteral<RestContext<EC2Client>>() {
})) != null; // TODO: test all things taken from context
assert i.getInstance(FormSigner.class) != null;
}
protected void testAddContextModule() {
List<Module> modules = new ArrayList<Module>();
EC2ContextBuilder builder = newBuilder();
builder.addContextModule(modules);
assertEquals(modules.size(), 1);
assertEquals(modules.get(0).getClass(), EC2RestClientModule.class);
}
private EC2ContextBuilder newBuilder() {
EC2ContextBuilder builder = new EC2ContextBuilder(new EC2PropertiesBuilder("id", "secret")
.build());
return builder;
}
protected void addClientModule() {
List<Module> modules = new ArrayList<Module>();
EC2ContextBuilder builder = newBuilder();
builder.addClientModule(modules);
assertEquals(modules.size(), 1);
assertEquals(modules.get(0).getClass(), EC2RestClientModule.class);
}
}

View File

@ -0,0 +1,211 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withKeyName;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.InstanceType;
import org.jclouds.aws.ec2.domain.IpProtocol;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshException;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.jclouds.util.Utils;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Follows the book Cloud Application Architectures ISBN: 978-0-596-15636-7
*
* @author Adrian Cole
*/
@Test(groups = "live", sequential = true, testName = "ec2.ExpensiveEC2ClientLiveTest")
public class ExpensiveEC2ClientLiveTest {
private EC2Client client;
protected SshClient.Factory sshFactory;
private String serverPrefix = System.getProperty("user.name") + ".ec2";
private KeyPair keyPair;
private String securityGroupName;
private String serverId;
@BeforeGroups(groups = { "live" })
public void setupClient() throws InterruptedException, ExecutionException, TimeoutException {
String user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
String password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
client = new EC2ContextBuilder(new EC2PropertiesBuilder(user, password).build()).withModules(
new Log4JLoggingModule()).buildContext().getApi();
Injector injector = Guice.createInjector(new Log4JLoggingModule(), new JschSshClientModule(),
new ExecutorServiceModule(new WithinThreadExecutorService()));
client = EC2ContextFactory.createContext(user, password, new Log4JLoggingModule()).getApi();
sshFactory = injector.getInstance(SshClient.Factory.class);
}
@Test
void testCreateSecurityGroupIngressCidr() throws InterruptedException, ExecutionException,
TimeoutException {
securityGroupName = serverPrefix + "ingress";
try {
client.deleteSecurityGroup(securityGroupName).get(30, TimeUnit.SECONDS);
} catch (Exception e) {
}
client.createSecurityGroup(securityGroupName, securityGroupName).get(30, TimeUnit.SECONDS);
client.authorizeSecurityGroupIngress(securityGroupName, IpProtocol.TCP, 80, 80, "0.0.0.0/0")
.get(30, TimeUnit.SECONDS);
client
.authorizeSecurityGroupIngress(securityGroupName, IpProtocol.TCP, 443, 443,
"0.0.0.0/0").get(30, TimeUnit.SECONDS);
client.authorizeSecurityGroupIngress(securityGroupName, IpProtocol.TCP, 22, 22, "0.0.0.0/0")
.get(30, TimeUnit.SECONDS);
}
@Test
void testCreateKeyPair() throws InterruptedException, ExecutionException, TimeoutException {
String keyName = serverPrefix + "1";
try {
client.deleteKeyPair(keyName).get(30, TimeUnit.SECONDS);
} catch (Exception e) {
}
client.deleteKeyPair(keyName).get(30, TimeUnit.SECONDS);
keyPair = client.createKeyPair(keyName).get(30, TimeUnit.SECONDS);
assertNotNull(keyPair);
assertNotNull(keyPair.getKeyMaterial());
assertNotNull(keyPair.getKeyFingerprint());
assertEquals(keyPair.getKeyName(), keyName);
}
@Test(dependsOnMethods = { "testCreateKeyPair", "testCreateSecurityGroupIngressCidr" })
public void testCreateRunningInstance() throws Exception {
String imageId = "ami-1fd73376";
RunningInstance server = null;
while (server == null) {
try {
server = client.runInstances(
imageId,
1,
1,
withKeyName(keyPair.getKeyName()).asType(InstanceType.M1_SMALL)
.withSecurityGroup(securityGroupName)).get(30, TimeUnit.SECONDS)
.getRunningInstances().iterator().next();
} catch (UndeclaredThrowableException e) {
HttpResponseException htpe = (HttpResponseException) e.getCause().getCause();
if (htpe.getResponse().getStatusCode() == 400)
continue;
throw e;
}
}
assertNotNull(server.getInstanceId());
serverId = server.getInstanceId();
assertEquals(server.getInstanceState(), InstanceState.PENDING);
server = blockUntilRunningInstanceActive(serverId);
sshPing(server);
}
/**
* this tests "personality" as the file looked up was sent during server creation
*/
private void sshPing(RunningInstance newDetails) throws IOException {
try {
doCheckKey(newDetails);
} catch (SshException e) {// try twice in case there is a network timeout
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e1) {
}
doCheckKey(newDetails);
}
}
private void doCheckKey(RunningInstance newDetails) throws IOException {
SshClient connection = sshFactory.create(new InetSocketAddress(newDetails.getDnsName(), 22),
"root", keyPair.getKeyMaterial().getBytes());
try {
connection.connect();
InputStream etcPasswd = connection.get("/etc/passwd");
Utils.toStringAndClose(etcPasswd);
} finally {
if (connection != null)
connection.disconnect();
}
}
private RunningInstance blockUntilRunningInstanceActive(String serverId)
throws InterruptedException, ExecutionException, TimeoutException {
RunningInstance currentDetails = null;
for (currentDetails = getRunningInstance(serverId); currentDetails.getInstanceState() != InstanceState.RUNNING; currentDetails = getRunningInstance(serverId)) {
System.out.printf("%s blocking on status active: currently: %s%n", currentDetails
.getInstanceId(), currentDetails.getInstanceState());
Thread.sleep(5 * 1000);
}
System.out.printf("%s awaiting daemons to start%n", currentDetails.getInstanceId());
Thread.sleep(10 * 1000);
return currentDetails;
}
@AfterClass
void cleanup() {
if (serverId != null)
client.terminateInstances(serverId);
if (keyPair != null)
client.deleteKeyPair(keyPair.getKeyName());
if (securityGroupName != null)
client.deleteSecurityGroup(securityGroupName);
}
private RunningInstance getRunningInstance(String serverId) throws InterruptedException,
ExecutionException, TimeoutException {
return client.describeInstances(serverId).get(15, TimeUnit.SECONDS).first()
.getRunningInstances().first();
}
}

View File

@ -0,0 +1,79 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.config;
import static org.testng.Assert.assertEquals;
import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.reference.EC2Constants;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.config.RestModule;
import org.jclouds.rest.internal.RestContextImpl;
import org.jclouds.util.Jsr330;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.EC2ContextModuleTest")
public class EC2ContextModuleTest {
Injector createInjector() {
return Guice.createInjector(new ExecutorServiceModule(new WithinThreadExecutorService()),
new EC2RestClientModule(), new RestModule(),
new JavaUrlHttpCommandExecutorServiceModule(), new JDKLoggingModule(),
new EC2ContextModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(
Jsr330.named(EC2Constants.PROPERTY_AWS_ACCESSKEYID)).to("user");
bindConstant().annotatedWith(
Jsr330.named(EC2Constants.PROPERTY_AWS_SECRETACCESSKEY)).to("key");
bindConstant().annotatedWith(Jsr330.named(EC2Constants.PROPERTY_EC2_ENDPOINT))
.to("http://localhost");
bindConstant().annotatedWith(
Jsr330.named(EC2Constants.PROPERTY_EC2_EXPIREINTERVAL)).to(30);
super.configure();
}
});
}
@Test
void testContextImpl() {
RestContext<EC2Client> handler = createInjector().getInstance(
Key.get(new TypeLiteral<RestContext<EC2Client>>() {
}));
assertEquals(handler.getClass(), RestContextImpl.class);
}
}

View File

@ -0,0 +1,70 @@
package org.jclouds.aws.ec2.config;
import static org.testng.Assert.assertEquals;
import org.jclouds.aws.ec2.reference.EC2Constants;
import org.jclouds.aws.handlers.AWSClientErrorRetryHandler;
import org.jclouds.aws.handlers.AWSRedirectionRetryHandler;
import org.jclouds.aws.handlers.ParseAWSErrorFromXmlContent;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.http.handlers.DelegatingErrorHandler;
import org.jclouds.http.handlers.DelegatingRetryHandler;
import org.jclouds.util.Jsr330;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.EC2RestClientModuleTest")
public class EC2RestClientModuleTest {
Injector createInjector() {
return Guice.createInjector(new EC2RestClientModule(), new ExecutorServiceModule(
new WithinThreadExecutorService()), new ParserModule(), new AbstractModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Jsr330.named(EC2Constants.PROPERTY_AWS_ACCESSKEYID)).to(
"user");
bindConstant().annotatedWith(Jsr330.named(EC2Constants.PROPERTY_AWS_SECRETACCESSKEY))
.to("key");
bindConstant().annotatedWith(Jsr330.named(EC2Constants.PROPERTY_EC2_ENDPOINT)).to(
"http://localhost");
bindConstant().annotatedWith(Jsr330.named(EC2Constants.PROPERTY_EC2_EXPIREINTERVAL))
.to(30);
}
});
}
@Test
void testServerErrorHandler() {
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
assertEquals(handler.getServerErrorHandler().getClass(), ParseAWSErrorFromXmlContent.class);
}
@Test
void testClientErrorHandler() {
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
assertEquals(handler.getClientErrorHandler().getClass(), ParseAWSErrorFromXmlContent.class);
}
@Test
void testClientRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getClientErrorRetryHandler().getClass(),
AWSClientErrorRetryHandler.class);
}
@Test
void testRedirectionRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getRedirectionRetryHandler().getClass(),
AWSRedirectionRetryHandler.class);
}
}

View File

@ -0,0 +1,59 @@
package org.jclouds.aws.ec2.filters;
import static org.testng.Assert.assertEquals;
import org.jclouds.aws.ec2.config.EC2RestClientModule;
import org.jclouds.aws.ec2.reference.EC2Constants;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.util.Jsr330;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
@Test(groups = "unit", testName = "ec2.FormSignerTest")
public class FormSignerTest {
private Injector injector;
private FormSigner filter;
@Test
void testBuildCanonicalizedString() {
assertEquals(
filter.buildCanonicalizedString(new ImmutableMultimap.Builder<String, String>().put(
"AWSAccessKeyId", "foo").put( "Action","DescribeImages").put(
"Expires","2008-02-10T12:00:00Z").put("ImageId.1", "ami-2bb65342").put(
"SignatureMethod", "HmacSHA256").put("SignatureVersion", "2").put("Version",
"2009-08-15").build()),
"AWSAccessKeyId=foo&Action=DescribeImages&Expires=2008-02-10T12%3A00%3A00Z&ImageId.1=ami-2bb65342&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2009-08-15");
}
/**
* before class, as we need to ensure that the filter is threadsafe.
*
*/
@BeforeClass
protected void createFilter() {
injector = Guice.createInjector(new EC2RestClientModule(), new ExecutorServiceModule(
new WithinThreadExecutorService()), new ParserModule(), new AbstractModule() {
protected void configure() {
bindConstant().annotatedWith(Jsr330.named(EC2Constants.PROPERTY_AWS_ACCESSKEYID)).to(
"foo");
bindConstant().annotatedWith(Jsr330.named(EC2Constants.PROPERTY_AWS_SECRETACCESSKEY))
.to("bar");
bindConstant().annotatedWith(Jsr330.named(EC2Constants.PROPERTY_EC2_ENDPOINT)).to(
"https://ec2.amazonaws.com");
bindConstant().annotatedWith(Jsr330.named(EC2Constants.PROPERTY_EC2_EXPIREINTERVAL))
.to(30);
}
});
filter = injector.getInstance(FormSigner.class);
}
}

View File

@ -0,0 +1,118 @@
package org.jclouds.aws.ec2.options;
import static org.jclouds.aws.ec2.options.DescribeImagesOptions.Builder.executableBy;
import static org.jclouds.aws.ec2.options.DescribeImagesOptions.Builder.imageIds;
import static org.jclouds.aws.ec2.options.DescribeImagesOptions.Builder.ownedBy;
import static org.testng.Assert.assertEquals;
import java.util.Collections;
import org.jclouds.http.options.HttpRequestOptions;
import org.testng.annotations.Test;
/**
* Tests possible uses of DescribeImagesOptions and DescribeImagesOptions.Builder.*
*
* @author Adrian Cole
*/
public class DescribeImagesOptionsTest {
@Test
public void testAssignability() {
assert HttpRequestOptions.class.isAssignableFrom(DescribeImagesOptions.class);
assert !String.class.isAssignableFrom(DescribeImagesOptions.class);
}
@Test
public void testExecutableBy() {
DescribeImagesOptions options = new DescribeImagesOptions();
options.executableBy("test");
assertEquals(options.buildFormParameters().get("ExecutableBy"), Collections
.singletonList("test"));
}
@Test
public void testNullExecutableBy() {
DescribeImagesOptions options = new DescribeImagesOptions();
assertEquals(options.buildFormParameters().get("ExecutableBy"), Collections.EMPTY_LIST);
}
@Test
public void testExecutableByStatic() {
DescribeImagesOptions options = executableBy("test");
assertEquals(options.buildFormParameters().get("ExecutableBy"), Collections
.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testExecutableByNPE() {
executableBy(null);
}
@Test
public void testOwners() {
DescribeImagesOptions options = new DescribeImagesOptions();
options.ownedBy("test");
assertEquals(options.buildFormParameters().get("Owner.1"), Collections.singletonList("test"));
}
@Test
public void testMultipleOwners() {
DescribeImagesOptions options = new DescribeImagesOptions();
options.ownedBy("test", "trouble");
assertEquals(options.buildFormParameters().get("Owner.1"), Collections.singletonList("test"));
assertEquals(options.buildFormParameters().get("Owner.2"), Collections
.singletonList("trouble"));
}
@Test
public void testNullOwners() {
DescribeImagesOptions options = new DescribeImagesOptions();
assertEquals(options.buildFormParameters().get("Owner.1"), Collections.EMPTY_LIST);
}
@Test
public void testOwnersStatic() {
DescribeImagesOptions options = ownedBy("test");
assertEquals(options.buildFormParameters().get("Owner.1"), Collections.singletonList("test"));
}
public void testNoOwners() {
ownedBy();
}
@Test
public void testImageIds() {
DescribeImagesOptions options = new DescribeImagesOptions();
options.imageIds("test");
assertEquals(options.buildFormParameters().get("ImageId.1"), Collections
.singletonList("test"));
}
@Test
public void testMultipleImageIds() {
DescribeImagesOptions options = new DescribeImagesOptions();
options.imageIds("test", "trouble");
assertEquals(options.buildFormParameters().get("ImageId.1"), Collections
.singletonList("test"));
assertEquals(options.buildFormParameters().get("ImageId.2"), Collections
.singletonList("trouble"));
}
@Test
public void testNullImageIds() {
DescribeImagesOptions options = new DescribeImagesOptions();
assertEquals(options.buildFormParameters().get("ImageId.1"), Collections.EMPTY_LIST);
}
@Test
public void testImageIdsStatic() {
DescribeImagesOptions options = imageIds("test");
assertEquals(options.buildFormParameters().get("ImageId.1"), Collections
.singletonList("test"));
}
public void testNoImageIds() {
imageIds();
}
}

View File

@ -0,0 +1,344 @@
package org.jclouds.aws.ec2.options;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.asType;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.enableMonitoring;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.inAvailabilityZone;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withAdditionalInfo;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withDeviceName;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withKernelId;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withKeyName;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withRamdisk;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withSecurityGroup;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withSubnetId;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withUserData;
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withVirtualName;
import static org.testng.Assert.assertEquals;
import java.util.Collections;
import org.jclouds.aws.ec2.domain.InstanceType;
import org.jclouds.http.options.HttpRequestOptions;
import org.testng.annotations.Test;
/**
* Tests possible uses of RunInstancesOptions and RunInstancesOptions.Builder.*
*
* @author Adrian Cole
*/
public class RunInstancesOptionsTest {
@Test
public void testAssignability() {
assert HttpRequestOptions.class.isAssignableFrom(RunInstancesOptions.class);
assert !String.class.isAssignableFrom(RunInstancesOptions.class);
}
@Test
public void testWithKeyName() {
RunInstancesOptions options = new RunInstancesOptions();
options.withKeyName("test");
assertEquals(options.buildFormParameters().get("KeyName"), Collections.singletonList("test"));
}
@Test
public void testNullWithKeyName() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("KeyName"), Collections.EMPTY_LIST);
}
@Test
public void testWithKeyNameStatic() {
RunInstancesOptions options = withKeyName("test");
assertEquals(options.buildFormParameters().get("KeyName"), Collections.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithKeyNameNPE() {
withKeyName(null);
}
@Test
public void testWithSecurityGroup() {
RunInstancesOptions options = new RunInstancesOptions();
options.withSecurityGroup("test");
assertEquals(options.buildFormParameters().get("SecurityGroup"), Collections
.singletonList("test"));
}
@Test
public void testNullWithSecurityGroup() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("SecurityGroup"), Collections.EMPTY_LIST);
}
@Test
public void testWithSecurityGroupStatic() {
RunInstancesOptions options = withSecurityGroup("test");
assertEquals(options.buildFormParameters().get("SecurityGroup"), Collections
.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithSecurityGroupNPE() {
withSecurityGroup(null);
}
@Test
public void testWithAdditionalInfo() {
RunInstancesOptions options = new RunInstancesOptions();
options.withAdditionalInfo("test");
assertEquals(options.buildFormParameters().get("AdditionalInfo"), Collections
.singletonList("test"));
}
@Test
public void testNullWithAdditionalInfo() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("AdditionalInfo"), Collections.EMPTY_LIST);
}
@Test
public void testWithAdditionalInfoStatic() {
RunInstancesOptions options = withAdditionalInfo("test");
assertEquals(options.buildFormParameters().get("AdditionalInfo"), Collections
.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithAdditionalInfoNPE() {
withAdditionalInfo(null);
}
@Test
public void testWithUserData() {
RunInstancesOptions options = new RunInstancesOptions();
options.withUserData("test");
assertEquals(options.buildFormParameters().get("UserData"), Collections
.singletonList("test"));
}
@Test
public void testNullWithUserData() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("UserData"), Collections.EMPTY_LIST);
}
@Test
public void testWithUserDataStatic() {
RunInstancesOptions options = withUserData("test");
assertEquals(options.buildFormParameters().get("UserData"), Collections
.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithUserDataNPE() {
withUserData(null);
}
@Test
public void testWithInstanceType() {
RunInstancesOptions options = new RunInstancesOptions();
options.asType(InstanceType.C1_XLARGE);
assertEquals(options.buildFormParameters().get("InstanceType"), Collections
.singletonList("c1.xlarge"));
}
@Test
public void testNullWithInstanceType() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("InstanceType"), Collections.EMPTY_LIST);
}
@Test
public void testWithInstanceTypeStatic() {
RunInstancesOptions options = asType(InstanceType.C1_XLARGE);
assertEquals(options.buildFormParameters().get("InstanceType"), Collections
.singletonList("c1.xlarge"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithInstanceTypeNPE() {
asType(null);
}
@Test
public void testInAvailabilityZone() {
RunInstancesOptions options = new RunInstancesOptions();
options.inAvailabilityZone("test");
assertEquals(options.buildFormParameters().get("Placement.AvailabilityZone"), Collections
.singletonList("test"));
}
@Test
public void testNullAvailabilityZone() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("Placement.AvailabilityZone"),
Collections.EMPTY_LIST);
}
@Test
public void testInAvailabilityZoneStatic() {
RunInstancesOptions options = inAvailabilityZone("test");
assertEquals(options.buildFormParameters().get("Placement.AvailabilityZone"), Collections
.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testInAvailabilityZoneNPE() {
inAvailabilityZone(null);
}
@Test
public void testWithKernelId() {
RunInstancesOptions options = new RunInstancesOptions();
options.withKernelId("test");
assertEquals(options.buildFormParameters().get("KernelId"), Collections
.singletonList("test"));
}
@Test
public void testNullWithKernelId() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("KernelId"), Collections.EMPTY_LIST);
}
@Test
public void testWithKernelIdStatic() {
RunInstancesOptions options = withKernelId("test");
assertEquals(options.buildFormParameters().get("KernelId"), Collections
.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithKernelIdNPE() {
withKernelId(null);
}
@Test
public void testWithDeviceName() {
RunInstancesOptions options = new RunInstancesOptions();
options.withDeviceName("test");
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.DeviceName"), Collections
.singletonList("test"));
}
@Test
public void testNullWithDeviceName() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.DeviceName"),
Collections.EMPTY_LIST);
}
@Test
public void testWithDeviceNameStatic() {
RunInstancesOptions options = withDeviceName("test");
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.DeviceName"), Collections
.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithDeviceNameNPE() {
withDeviceName(null);
}
@Test
public void testWithMonitoringEnabled() {
RunInstancesOptions options = new RunInstancesOptions();
options.enableMonitoring();
assertEquals(options.buildFormParameters().get("Monitoring.Enabled"), Collections
.singletonList("true"));
}
@Test
public void testNullWithMonitoringEnabled() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("Monitoring.Enabled"), Collections.EMPTY_LIST);
}
@Test
public void testWithMonitoringEnabledStatic() {
RunInstancesOptions options = enableMonitoring();
assertEquals(options.buildFormParameters().get("Monitoring.Enabled"), Collections
.singletonList("true"));
}
@Test
public void testWithSubnetId() {
RunInstancesOptions options = new RunInstancesOptions();
options.withSubnetId("test");
assertEquals(options.buildFormParameters().get("SubnetId"), Collections
.singletonList("test"));
}
@Test
public void testNullWithSubnetId() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("SubnetId"), Collections.EMPTY_LIST);
}
@Test
public void testWithSubnetIdStatic() {
RunInstancesOptions options = withSubnetId("test");
assertEquals(options.buildFormParameters().get("SubnetId"), Collections
.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithSubnetIdNPE() {
withSubnetId(null);
}
@Test
public void testWithRamdisk() {
RunInstancesOptions options = new RunInstancesOptions();
options.withRamdisk("test");
assertEquals(options.buildFormParameters().get("RamdiskId"), Collections
.singletonList("test"));
}
@Test
public void testNullWithRamdisk() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("RamdiskId"), Collections.EMPTY_LIST);
}
@Test
public void testWithRamdiskStatic() {
RunInstancesOptions options = withRamdisk("test");
assertEquals(options.buildFormParameters().get("RamdiskId"), Collections
.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithRamdiskNPE() {
withRamdisk(null);
}
@Test
public void testWithVirtualName() {
RunInstancesOptions options = new RunInstancesOptions();
options.withVirtualName("test");
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.VirtualName"),
Collections.singletonList("test"));
}
@Test
public void testNullWithVirtualName() {
RunInstancesOptions options = new RunInstancesOptions();
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.VirtualName"),
Collections.EMPTY_LIST);
}
@Test
public void testWithVirtualNameStatic() {
RunInstancesOptions options = withVirtualName("test");
assertEquals(options.buildFormParameters().get("BlockDeviceMapping.VirtualName"),
Collections.singletonList("test"));
}
@Test(expectedExceptions = NullPointerException.class)
public void testWithVirtualNameNPE() {
withVirtualName(null);
}
}

View File

@ -0,0 +1,62 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.util.SortedSet;
import org.jclouds.aws.ec2.domain.Image;
import org.jclouds.aws.ec2.domain.Image.Architecture;
import org.jclouds.aws.ec2.domain.Image.ImageState;
import org.jclouds.aws.ec2.domain.Image.ImageType;
import org.jclouds.http.functions.BaseHandlerTest;
import org.testng.annotations.Test;
import com.google.common.collect.Sets;
/**
* Tests behavior of {@code DescribeImagesResponseHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.DescribeImagesResponseHandlerTest")
public class DescribeImagesResponseHandlerTest extends BaseHandlerTest {
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/ec2/describe_images.xml");
SortedSet<Image> contents = Sets.newTreeSet();
contents.add(new Image(Architecture.I386, "ami-be3adfd7",
"ec2-public-images/fedora-8-i386-base-v1.04.manifest.xml", "206029621532",
ImageState.AVAILABLE, ImageType.MACHINE, false, "aki-4438dd2d", null, Sets
.<String> newHashSet(), "ari-4538dd2c"));
SortedSet<Image> result = (SortedSet<Image>) factory.create(
injector.getInstance(DescribeImagesResponseHandler.class)).parse(is);
assertEquals(result, contents);
}
}

View File

@ -0,0 +1,111 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.SortedSet;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.InstanceType;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.util.DateService;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
/**
* Tests behavior of {@code DescribeInstancesResponseHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.DescribeInstancesResponseHandlerTest")
public class DescribeInstancesResponseHandlerTest extends BaseHandlerTest {
private DateService dateService;
@BeforeTest
@Override
protected void setUpInjector() {
super.setUpInjector();
dateService = injector.getInstance(DateService.class);
assert dateService != null;
}
public void testWhenRunning() throws UnknownHostException {
InputStream is = getClass().getResourceAsStream("/ec2/describe_instances_running.xml");
SortedSet<Reservation> contents = Sets.newTreeSet();
contents.add(new Reservation(ImmutableSortedSet.of("adriancole.ec2ingress"),
ImmutableSortedSet.of(new RunningInstance("0",
"ec2-174-129-81-68.compute-1.amazonaws.com", "ami-1fd73376", "i-0799056f",
InstanceState.RUNNING, InstanceType.M1_SMALL, InetAddress
.getByName("174.129.81.68"), "aki-a71cf9ce", "adriancole.ec21",
dateService.iso8601DateParse("2009-11-09T03:00:34.000Z"), false,
"us-east-1c", null, "ip-10-243-42-70.ec2.internal", InetAddress
.getByName("10.243.42.70"), ImmutableSet.<String> of(),
"ari-a51cf9cc", null, null, null)), "993194456877", null, "r-a3c508cb"));
SortedSet<Reservation> result = factory.create(
injector.getInstance(DescribeInstancesResponseHandler.class)).parse(is);
assertEquals(result, contents);
}
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/ec2/describe_instances.xml");
SortedSet<Reservation> contents = Sets.newTreeSet();
contents.add(new Reservation(ImmutableSortedSet.of("default"), ImmutableSortedSet.of(
new RunningInstance("23", "ec2-72-44-33-4.compute-1.amazonaws.com", "ami-6ea54007",
"i-28a64341", InstanceState.RUNNING, InstanceType.M1_LARGE,
(InetAddress) null, "aki-ba3adfd3", "example-key-name", dateService
.iso8601DateParse("2007-08-07T11:54:42.000Z"), false,
"us-east-1b", null, "10-251-50-132.ec2.internal", null, ImmutableSet
.of("774F4FF8"), "ari-badbad00", null, null, null),
new RunningInstance("23", "ec2-72-44-33-6.compute-1.amazonaws.com", "ami-6ea54007",
"i-28a64435", InstanceState.RUNNING, InstanceType.M1_LARGE,
(InetAddress) null, "aki-ba3adfd3", "example-key-name", dateService
.iso8601DateParse("2007-08-07T11:54:42.000Z"), false,
"us-east-1b", null, "10-251-50-134.ec2.internal", null, ImmutableSet
.of("774F4FF8"), "ari-badbad00", null, null, null)),
"UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM", null, "r-44a5402d"));
SortedSet<Reservation> result = factory.create(
injector.getInstance(DescribeInstancesResponseHandler.class)).parse(is);
assertEquals(result, contents);
}
}

View File

@ -0,0 +1,56 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.util.SortedSet;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.http.functions.BaseHandlerTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSortedSet;
/**
* Tests behavior of {@code DescribeKeyPairsHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.DescribeKeyPairsHandlerTest")
public class DescribeKeyPairsResponseHandlerTest extends BaseHandlerTest {
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/ec2/describe_keypairs.xml");
SortedSet<KeyPair> expected = ImmutableSortedSet.of(new KeyPair("gsg-keypair",
"1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f", null));
SortedSet<KeyPair> result = factory.create(
injector.getInstance(DescribeKeyPairsResponseHandler.class)).parse(is);
assertEquals(result, expected);
}
}

View File

@ -0,0 +1,65 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.util.SortedSet;
import org.jclouds.aws.ec2.domain.IpPermission;
import org.jclouds.aws.ec2.domain.IpProtocol;
import org.jclouds.aws.ec2.domain.SecurityGroup;
import org.jclouds.aws.ec2.domain.UserIdGroupPair;
import org.jclouds.http.functions.BaseHandlerTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSortedSet;
/**
* Tests behavior of {@code DescribeSecurityGroupsHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.DescribeSecurityGroupsHandlerTest")
public class DescribeSecurityGroupsResponseHandlerTest extends BaseHandlerTest {
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/ec2/describe_securitygroups.xml");
SortedSet<SecurityGroup> expected = ImmutableSortedSet.of(new SecurityGroup("WebServers",
"UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM", "Web Servers", ImmutableSortedSet
.of(new IpPermission(80, 80, ImmutableSortedSet.<UserIdGroupPair> of(),
IpProtocol.TCP, ImmutableSortedSet.of("0.0.0.0/0")))),
new SecurityGroup("RangedPortsBySource", "UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM",
"Group A", ImmutableSortedSet.of(new IpPermission(6000, 7000,
ImmutableSortedSet.<UserIdGroupPair> of(), IpProtocol.TCP,
ImmutableSortedSet.<String> of()))));
SortedSet<SecurityGroup> result = factory.create(
injector.getInstance(DescribeSecurityGroupsResponseHandler.class)).parse(is);
assertEquals(result, expected);
}
}

View File

@ -0,0 +1,76 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.http.functions.BaseHandlerTest;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code KeyPairResponseHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.KeyPairResponseHandlerTest")
public class KeyPairResponseHandlerTest extends BaseHandlerTest {
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/ec2/create_keypair.xml");
KeyPair expected = new KeyPair(
"gsg-keypair",
"1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f",
"-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIIEoQIBAAKCAQBuLFg5ujHrtm1jnutSuoO8Xe56LlT+HM8v/xkaa39EstM3/aFxTHgElQiJLChp\n"
+ "HungXQ29VTc8rc1bW0lkdi23OH5eqkMHGhvEwqa0HWASUMll4o3o/IX+0f2UcPoKCOVUR+jx71Sg\n"
+ "5AU52EQfanIn3ZQ8lFW7Edp5a3q4DhjGlUKToHVbicL5E+g45zfB95wIyywWZfeW/UUF3LpGZyq/\n"
+ "ebIUlq1qTbHkLbCC2r7RTn8vpQWp47BGVYGtGSBMpTRP5hnbzzuqj3itkiLHjU39S2sJCJ0TrJx5\n"
+ "i8BygR4s3mHKBj8l+ePQxG1kGbF6R4yg6sECmXn17MRQVXODNHZbAgMBAAECggEAY1tsiUsIwDl5\n"
+ "91CXirkYGuVfLyLflXenxfI50mDFms/mumTqloHO7tr0oriHDR5K7wMcY/YY5YkcXNo7mvUVD1pM\n"
+ "ZNUJs7rw9gZRTrf7LylaJ58kOcyajw8TsC4e4LPbFaHwS1d6K8rXh64o6WgW4SrsB6ICmr1kGQI7\n"
+ "3wcfgt5ecIu4TZf0OE9IHjn+2eRlsrjBdeORi7KiUNC/pAG23I6MdDOFEQRcCSigCj+4/mciFUSA\n"
+ "SWS4dMbrpb9FNSIcf9dcLxVM7/6KxgJNfZc9XWzUw77Jg8x92Zd0fVhHOux5IZC+UvSKWB4dyfcI\n"
+ "tE8C3p9bbU9VGyY5vLCAiIb4qQKBgQDLiO24GXrIkswF32YtBBMuVgLGCwU9h9HlO9mKAc2m8Cm1\n"
+ "jUE5IpzRjTedc9I2qiIMUTwtgnw42auSCzbUeYMURPtDqyQ7p6AjMujp9EPemcSVOK9vXYL0Ptco\n"
+ "xW9MC0dtV6iPkCN7gOqiZXPRKaFbWADp16p8UAIvS/a5XXk5jwKBgQCKkpHi2EISh1uRkhxljyWC\n"
+ "iDCiK6JBRsMvpLbc0v5dKwP5alo1fmdR5PJaV2qvZSj5CYNpMAy1/EDNTY5OSIJU+0KFmQbyhsbm\n"
+ "rdLNLDL4+TcnT7c62/aH01ohYaf/VCbRhtLlBfqGoQc7+sAc8vmKkesnF7CqCEKDyF/dhrxYdQKB\n"
+ "gC0iZzzNAapayz1+JcVTwwEid6j9JqNXbBc+Z2YwMi+T0Fv/P/hwkX/ypeOXnIUcw0Ih/YtGBVAC\n"
+ "DQbsz7LcY1HqXiHKYNWNvXgwwO+oiChjxvEkSdsTTIfnK4VSCvU9BxDbQHjdiNDJbL6oar92UN7V\n"
+ "rBYvChJZF7LvUH4YmVpHAoGAbZ2X7XvoeEO+uZ58/BGKOIGHByHBDiXtzMhdJr15HTYjxK7OgTZm\n"
+ "gK+8zp4L9IbvLGDMJO8vft32XPEWuvI8twCzFH+CsWLQADZMZKSsBasOZ/h1FwhdMgCMcY+Qlzd4\n"
+ "JZKjTSu3i7vhvx6RzdSedXEMNTZWN4qlIx3kR5aHcukCgYA9T+Zrvm1F0seQPbLknn7EqhXIjBaT\n"
+ "P8TTvW/6bdPi23ExzxZn7KOdrfclYRph1LHMpAONv/x2xALIf91UB+v5ohy1oDoasL0gij1houRe\n"
+ "2ERKKdwz0ZL9SWq6VTdhr/5G994CK72fy5WhyERbDjUIdHaK3M849JJuf8cSrvSb4g==\n"
+ "-----END RSA PRIVATE KEY-----");
KeyPair result = factory.create(injector.getInstance(KeyPairResponseHandler.class)).parse(is);
assertEquals(result, expected);
}
}

View File

@ -0,0 +1,91 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.InetAddress;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.InstanceType;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.util.DateService;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
/**
* Tests behavior of {@code RunInstancesResponseHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.RunInstancesResponseHandlerTest")
public class RunInstancesResponseHandlerTest extends BaseHandlerTest {
private DateService dateService;
@BeforeTest
@Override
protected void setUpInjector() {
super.setUpInjector();
dateService = injector.getInstance(DateService.class);
assert dateService != null;
}
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/ec2/run_instances.xml");
Reservation expected = new Reservation(ImmutableSortedSet.of("default"), ImmutableSortedSet
.of(
new RunningInstance("0", null, "ami-60a54009", "i-2ba64342",
InstanceState.PENDING, InstanceType.M1_SMALL, (InetAddress) null, null,
"example-key-name", dateService
.iso8601DateParse("2007-08-07T11:51:50.000Z"), true, "us-east-1b",
null, null, (InetAddress) null, Sets.<String> newTreeSet(), null, null,
null, null), new RunningInstance("0", null, "ami-60a54009",
"i-2bc64242", InstanceState.PENDING, InstanceType.M1_SMALL,
(InetAddress) null, null, "example-key-name", dateService
.iso8601DateParse("2007-08-07T11:51:50.000Z"), true, "us-east-1b",
null, null, (InetAddress) null, Sets.<String> newTreeSet(), null, null,
null, null), new RunningInstance("0", null, "ami-60a54009",
"i-2be64332", InstanceState.PENDING, InstanceType.M1_SMALL,
(InetAddress) null, null, "example-key-name", dateService
.iso8601DateParse("2007-08-07T11:51:50.000Z"), true, "us-east-1b",
null, null, (InetAddress) null, Sets.<String> newTreeSet(), null, null,
null, null)
), "AIDADH4IGTRXXKCD", null, "r-47a5402e");
Reservation result = factory.create(
injector.getInstance(RunInstancesResponseHandler.class)).parse(is);
assertEquals(result, expected);
}
}

View File

@ -0,0 +1,70 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.util.SortedSet;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.TerminatedInstance;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.util.DateService;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSortedSet;
/**
* Tests behavior of {@code TerminateInstancesResponseHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.TerminateInstancesResponseHandlerTest")
public class TerminateInstancesResponseHandlerTest extends BaseHandlerTest {
private DateService dateService;
@BeforeTest
@Override
protected void setUpInjector() {
super.setUpInjector();
dateService = injector.getInstance(DateService.class);
assert dateService != null;
}
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/ec2/terminate_instances.xml");
SortedSet<TerminatedInstance> expected = ImmutableSortedSet.of(new TerminatedInstance(
"i-3ea74257", InstanceState.SHUTTING_DOWN, InstanceState.RUNNING));
SortedSet<TerminatedInstance> result = factory.create(
injector.getInstance(TerminateInstancesResponseHandler.class)).parse(is);
assertEquals(result, expected);
}
}

View File

@ -0,0 +1,27 @@
<CreateKeyPairResponse xmlns="http://ec2.amazonaws.com/doc/2009-08-15/">
<keyName>gsg-keypair</keyName>
<keyFingerprint>1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f</keyFingerprint>
<keyMaterial>-----BEGIN RSA PRIVATE KEY-----
MIIEoQIBAAKCAQBuLFg5ujHrtm1jnutSuoO8Xe56LlT+HM8v/xkaa39EstM3/aFxTHgElQiJLChp
HungXQ29VTc8rc1bW0lkdi23OH5eqkMHGhvEwqa0HWASUMll4o3o/IX+0f2UcPoKCOVUR+jx71Sg
5AU52EQfanIn3ZQ8lFW7Edp5a3q4DhjGlUKToHVbicL5E+g45zfB95wIyywWZfeW/UUF3LpGZyq/
ebIUlq1qTbHkLbCC2r7RTn8vpQWp47BGVYGtGSBMpTRP5hnbzzuqj3itkiLHjU39S2sJCJ0TrJx5
i8BygR4s3mHKBj8l+ePQxG1kGbF6R4yg6sECmXn17MRQVXODNHZbAgMBAAECggEAY1tsiUsIwDl5
91CXirkYGuVfLyLflXenxfI50mDFms/mumTqloHO7tr0oriHDR5K7wMcY/YY5YkcXNo7mvUVD1pM
ZNUJs7rw9gZRTrf7LylaJ58kOcyajw8TsC4e4LPbFaHwS1d6K8rXh64o6WgW4SrsB6ICmr1kGQI7
3wcfgt5ecIu4TZf0OE9IHjn+2eRlsrjBdeORi7KiUNC/pAG23I6MdDOFEQRcCSigCj+4/mciFUSA
SWS4dMbrpb9FNSIcf9dcLxVM7/6KxgJNfZc9XWzUw77Jg8x92Zd0fVhHOux5IZC+UvSKWB4dyfcI
tE8C3p9bbU9VGyY5vLCAiIb4qQKBgQDLiO24GXrIkswF32YtBBMuVgLGCwU9h9HlO9mKAc2m8Cm1
jUE5IpzRjTedc9I2qiIMUTwtgnw42auSCzbUeYMURPtDqyQ7p6AjMujp9EPemcSVOK9vXYL0Ptco
xW9MC0dtV6iPkCN7gOqiZXPRKaFbWADp16p8UAIvS/a5XXk5jwKBgQCKkpHi2EISh1uRkhxljyWC
iDCiK6JBRsMvpLbc0v5dKwP5alo1fmdR5PJaV2qvZSj5CYNpMAy1/EDNTY5OSIJU+0KFmQbyhsbm
rdLNLDL4+TcnT7c62/aH01ohYaf/VCbRhtLlBfqGoQc7+sAc8vmKkesnF7CqCEKDyF/dhrxYdQKB
gC0iZzzNAapayz1+JcVTwwEid6j9JqNXbBc+Z2YwMi+T0Fv/P/hwkX/ypeOXnIUcw0Ih/YtGBVAC
DQbsz7LcY1HqXiHKYNWNvXgwwO+oiChjxvEkSdsTTIfnK4VSCvU9BxDbQHjdiNDJbL6oar92UN7V
rBYvChJZF7LvUH4YmVpHAoGAbZ2X7XvoeEO+uZ58/BGKOIGHByHBDiXtzMhdJr15HTYjxK7OgTZm
gK+8zp4L9IbvLGDMJO8vft32XPEWuvI8twCzFH+CsWLQADZMZKSsBasOZ/h1FwhdMgCMcY+Qlzd4
JZKjTSu3i7vhvx6RzdSedXEMNTZWN4qlIx3kR5aHcukCgYA9T+Zrvm1F0seQPbLknn7EqhXIjBaT
P8TTvW/6bdPi23ExzxZn7KOdrfclYRph1LHMpAONv/x2xALIf91UB+v5ohy1oDoasL0gij1houRe
2ERKKdwz0ZL9SWq6VTdhr/5G994CK72fy5WhyERbDjUIdHaK3M849JJuf8cSrvSb4g==
-----END RSA PRIVATE KEY-----</keyMaterial>
</CreateKeyPairResponse>

View File

@ -0,0 +1,16 @@
<DescribeImagesResponse xmlns="http://ec2.amazonaws.com/doc/2009-08-15/">
<imagesSet>
<item>
<imageId>ami-be3adfd7</imageId>
<imageLocation>ec2-public-images/fedora-8-i386-base-v1.04.manifest.xml
</imageLocation>
<imageState>available</imageState>
<imageOwnerId>206029621532</imageOwnerId>
<isPublic>false</isPublic>
<architecture>i386</architecture>
<imageType>machine</imageType>
<kernelId>aki-4438dd2d</kernelId>
<ramdiskId>ari-4538dd2c</ramdiskId>
</item>
</imagesSet>
</DescribeImagesResponse>

View File

@ -0,0 +1,59 @@
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2009-08-15/">
<reservationSet>
<item>
<reservationId>r-44a5402d</reservationId>
<ownerId>UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM</ownerId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instancesSet>
<item>
<instanceId>i-28a64341</instanceId>
<imageId>ami-6ea54007</imageId>
<instanceState>
<code>0</code>
<name>running</name>
</instanceState>
<privateDnsName>10-251-50-132.ec2.internal</privateDnsName>
<dnsName>ec2-72-44-33-4.compute-1.amazonaws.com</dnsName>
<keyName>example-key-name</keyName>
<amiLaunchIndex>23</amiLaunchIndex>
<productCodesSet>
<item><productCode>774F4FF8</productCode></item>
</productCodesSet>
<instanceType>m1.large</instanceType>
<launchTime>2007-08-07T11:54:42.000Z</launchTime>
<placement>
<availabilityZone>us-east-1b</availabilityZone>
</placement>
<kernelId>aki-ba3adfd3</kernelId>
<ramdiskId>ari-badbad00</ramdiskId>
</item>
<item>
<instanceId>i-28a64435</instanceId>
<imageId>ami-6ea54007</imageId>
<instanceState>
<code>0</code>
<name>running</name>
</instanceState>
<privateDnsName>10-251-50-134.ec2.internal</privateDnsName>
<dnsName>ec2-72-44-33-6.compute-1.amazonaws.com</dnsName>
<keyName>example-key-name</keyName>
<amiLaunchIndex>23</amiLaunchIndex>
<productCodesSet>
<item><productCode>774F4FF8</productCode></item>
</productCodesSet>
<instanceType>m1.large</instanceType>
<launchTime>2007-08-07T11:54:42.000Z</launchTime>
<placement>
<availabilityZone>us-east-1b</availabilityZone>
</placement>
<kernelId>aki-ba3adfd3</kernelId>
<ramdiskId>ari-badbad00</ramdiskId>
</item>
</instancesSet>
</item>
</reservationSet>
</DescribeInstancesResponse>

View File

@ -0,0 +1,44 @@
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2009-08-15/">
<requestId>ae75a8cc-b707-4a20-b130-61ad6f20de61</requestId>
<reservationSet>
<item>
<reservationId>r-a3c508cb</reservationId>
<ownerId>993194456877</ownerId>
<groupSet>
<item>
<groupId>adriancole.ec2ingress</groupId>
</item>
</groupSet>
<instancesSet>
<item>
<instanceId>i-0799056f</instanceId>
<imageId>ami-1fd73376</imageId>
<instanceState>
<code>16</code>
<name>running</name>
</instanceState>
<privateDnsName>ip-10-243-42-70.ec2.internal
</privateDnsName>
<dnsName>ec2-174-129-81-68.compute-1.amazonaws.com
</dnsName>
<reason />
<keyName>adriancole.ec21</keyName>
<amiLaunchIndex>0</amiLaunchIndex>
<productCodes />
<instanceType>m1.small</instanceType>
<launchTime>2009-11-09T03:00:34.000Z</launchTime>
<placement>
<availabilityZone>us-east-1c</availabilityZone>
</placement>
<kernelId>aki-a71cf9ce</kernelId>
<ramdiskId>ari-a51cf9cc</ramdiskId>
<monitoring>
<state>disabled</state>
</monitoring>
<privateIpAddress>10.243.42.70</privateIpAddress>
<ipAddress>174.129.81.68</ipAddress>
</item>
</instancesSet>
</item>
</reservationSet>
</DescribeInstancesResponse>

View File

@ -0,0 +1,8 @@
<DescribeKeyPairsResponse xmlns="http://ec2.amazonaws.com/doc/2009-08-15/">
<keySet>
<item>
<keyName>gsg-keypair</keyName>
<keyFingerprint>1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f</keyFingerprint>
</item>
</keySet>
</DescribeKeyPairsResponse>

View File

@ -0,0 +1,36 @@
<DescribeSecurityGroupsResponse xmlns="http://ec2.amazonaws.com/doc/2009-08-15/">
<securityGroupInfo>
<item>
<ownerId>UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM</ownerId>
<groupName>WebServers</groupName>
<groupDescription>Web Servers</groupDescription>
<ipPermissions>
<item>
<ipProtocol>tcp</ipProtocol>
<fromPort>80</fromPort>
<toPort>80</toPort>
<groups/>
<ipRanges>
<item>
<cidrIp>0.0.0.0/0</cidrIp>
</item>
</ipRanges>
</item>
</ipPermissions>
</item>
<item>
<ownerId>UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM</ownerId>
<groupName>RangedPortsBySource</groupName>
<groupDescription>Group A</groupDescription>
<ipPermissions>
<item>
<ipProtocol>tcp</ipProtocol>
<fromPort>6000</fromPort>
<toPort>7000</toPort>
<groups/>
<ipRanges/>
</item>
</ipPermissions>
</item>
</securityGroupInfo>
</DescribeSecurityGroupsResponse>

View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
====================================================================
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.
====================================================================
-->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--
For more configuration infromation and examples see the Apache Log4j
website: http://logging.apache.org/log4j/
-->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
debug="false">
<!-- A time/date based rolling appender -->
<appender name="WIREFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-wire.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
%m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
%m%n"/>
-->
</layout>
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<appender name="ASYNCWIRE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="WIREFILE" />
</appender>
<!-- ================ -->
<!-- Limit categories -->
<!-- ================ -->
<category name="org.jclouds">
<priority value="DEBUG" />
<appender-ref ref="ASYNC" />
</category>
<category name="jclouds.http.headers">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<category name="jclouds.http.wire">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN" />
</root>
</log4j:configuration>

View File

@ -0,0 +1,71 @@
<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2009-08-15/">
<reservationId>r-47a5402e</reservationId>
<ownerId>AIDADH4IGTRXXKCD</ownerId>
<groupSet>
<item>
<groupId>default</groupId>
</item>
</groupSet>
<instancesSet>
<item>
<instanceId>i-2ba64342</instanceId>
<imageId>ami-60a54009</imageId>
<instanceState>
<code>0</code>
<name>pending</name>
</instanceState>
<privateDnsName></privateDnsName>
<dnsName></dnsName>
<keyName>example-key-name</keyName>
<amiLaunchIndex>0</amiLaunchIndex>
<instanceType>m1.small</instanceType>
<launchTime>2007-08-07T11:51:50.000Z</launchTime>
<placement>
<availabilityZone>us-east-1b</availabilityZone>
</placement>
<monitoring>
<enabled>true</enabled>
</monitoring>
</item>
<item>
<instanceId>i-2bc64242</instanceId>
<imageId>ami-60a54009</imageId>
<instanceState>
<code>0</code>
<name>pending</name>
</instanceState>
<privateDnsName></privateDnsName>
<dnsName></dnsName>
<keyName>example-key-name</keyName>
<amiLaunchIndex>1</amiLaunchIndex>
<instanceType>m1.small</instanceType>
<launchTime>2007-08-07T11:51:50.000Z</launchTime>
<placement>
<availabilityZone>us-east-1b</availabilityZone>
</placement>
<monitoring>
<enabled>true</enabled>
</monitoring>
</item>
<item>
<instanceId>i-2be64332</instanceId>
<imageId>ami-60a54009</imageId>
<instanceState>
<code>0</code>
<name>pending</name>
</instanceState>
<privateDnsName></privateDnsName>
<dnsName></dnsName>
<keyName>example-key-name</keyName>
<amiLaunchIndex>2</amiLaunchIndex>
<instanceType>m1.small</instanceType>
<launchTime>2007-08-07T11:51:50.000Z</launchTime>
<placement>
<availabilityZone>us-east-1b</availabilityZone>
</placement>
<monitoring>
<enabled>true</enabled>
</monitoring>
</item>
</instancesSet>
</RunInstancesResponse>

View File

@ -0,0 +1,15 @@
<TerminateInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2009-08-15/">
<instancesSet>
<item>
<instanceId>i-3ea74257</instanceId>
<shutdownState>
<code>32</code>
<name>shutting-down</name>
</shutdownState>
<previousState>
<code>16</code>
<name>running</name>
</previousState>
</item>
</instancesSet>
</TerminateInstancesResponse>

View File

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
$HeadURL$
$Revision$
$Date$
Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
====================================================================
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.html
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.
====================================================================
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-ec2-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-ec2-core</artifactId>
<name>jclouds Amazon EC2 Components Core</name>
<packaging>jar</packaging>
<description>jclouds Core components to access Amazon EC2</description>
<scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/aws/ec2/core</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/aws/ec2/core</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk/aws/ec2/core</url>
</scm>
</project>

View File

@ -1,271 +0,0 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.commands.options;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.ACTION;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.AWS_ACCESS_KEY_ID;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.EXPIRES;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.SIGNATURE;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.SIGNATURE_METHOD;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.SIGNATURE_VERSION;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.TIMESTAMP;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.VERSION;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import org.jclouds.aws.ec2.reference.CommonEC2Parameters;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.aws.util.DateService;
import org.jclouds.http.HttpHeaders;
import org.jclouds.http.options.BaseHttpRequestOptions;
import org.joda.time.DateTime;
/**
* Contains the base options needed for all EC2 QUERY API operations.<h2>
* Extend this class in the following way to avoid massive boilerplate code: Usage:
* <p/>
*
* <pre>
* public static class MyRequestOptions extends BaseEC2RequestOptions&lt;MyRequestOptions&gt; {
* static {
* realClass = MyRequestOptions.class;
* }
*
* &#064;Override
* public String getAction() {
* return &quot;MyRequest&quot;;
* }
*
* public String getId() {
* return parameters.get(&quot;id&quot;);
* }
*
* public MyRequestOptions withId(String id) {
* encodeAndReplaceParameter(&quot;id&quot;, id);
* return this;
* }
*
* public static class Builder extends BaseEC2RequestOptions.Builder {
* public static MyRequestOptions withId(String id) {
* MyRequestOptions options = new MyRequestOptions();
* return options.withId(id);
* }
* }
* }
* </pre>
*
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/Query-Common-Parameters.html"
* />
* @see CommonEC2Parameters
* @author Adrian Cole
*
*/
public abstract class BaseEC2RequestOptions<T extends EC2RequestOptions> extends
BaseHttpRequestOptions implements EC2RequestOptions {
public static String[] mandatoryParametersForSignature = new String[] { ACTION,
SIGNATURE_METHOD, SIGNATURE_VERSION, VERSION };
static final DateService dateService = new DateService();
private String awsSecretAccessKey;
private String awsAccessKeyId;
/**
* {@inheritDoc}
*
* @see CommonEC2Parameters#ACTION
*/
public abstract String getAction();
protected static Class<? extends EC2RequestOptions> realClass = BaseEC2RequestOptions.class;
/**
* Sets the request property <code>Action</code> to the appropriate name
*
*/
public BaseEC2RequestOptions() {
try {
parameters.put(ACTION, URLEncoder.encode(getAction(), "UTF-8"));
parameters.put(SIGNATURE_METHOD, URLEncoder.encode("HmacSHA256", "UTF-8"));
parameters.put(SIGNATURE_VERSION, URLEncoder.encode("2", "UTF-8"));
parameters.put(VERSION, URLEncoder.encode("2009-04-04", "UTF-8"));
} catch (UnsupportedEncodingException e) {
assert false : e.toString();
// job of unit test to ensure this never happens
}
}
/**
* {@inheritDoc}
*
* @see CommonEC2Parameters#TIMESTAMP
*/
@SuppressWarnings("unchecked")
public T timeStamp() {
encodeAndReplaceParameter(TIMESTAMP, dateService.iso8601DateFormat());
return (T) this;
}
/**
* {@inheritDoc}
*
* @see CommonEC2Parameters#EXPIRES
*/
@SuppressWarnings("unchecked")
public T expireAt(DateTime time) {
try {
parameters.put(EXPIRES, URLEncoder.encode(dateService.iso8601DateFormat(checkNotNull(time,
"time")), "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("bad encoding on datetime: " + time, e);
}
return (T) this;
}
@Override
public String buildQueryString() {
checkState(awsSecretAccessKey != null,
"request is not ready to sign; awsSecretAccessKey not present");
checkState(awsAccessKeyId != null, "request is not ready to sign; awsAccessKeyId not present");
String host = getFirstHeaderOrNull(HttpHeaders.HOST);
checkState(host != null, "request is not ready to sign; host not present");
// timestamp is incompatible with expires
if (parameters.get(EXPIRES) == null) {
timeStamp();
}
for (String parameter : mandatoryParametersForSignature) {
checkState(parameters.get(parameter) != null, "parameter " + parameter
+ " is required for signature");
}
parameters.remove(SIGNATURE);
encodeAndReplaceParameter(AWS_ACCESS_KEY_ID, awsAccessKeyId);
// 1. Sort the UTF-8 query string components by parameter name with natural byte ordering.
// -- as parameters are a SortedSet, they are already sorted.
// 2. URL encode the parameter name and values according to the following rules...
// -- all parameters are URL encoded on the way in
// 3. Separate the encoded parameter names from their encoded values with the equals sign,
// even if the parameter value is empty.
// -- we do not allow null values.
// 4. Separate the name-value pairs with an ampersand.
// -- buildQueryString() does this.
StringBuilder toSign = new StringBuilder();
toSign.append(HttpMethod.GET).append("\n").append(host.toLowerCase()).append("\n").append("/").append(
"\n");
String canonicalizedQueryString = super.buildQueryString().replaceFirst("\\?", "");
toSign.append(canonicalizedQueryString);
String signature;
try {
signature = AWSUtils.hmacSha256Base64(toSign.toString(), awsSecretAccessKey.getBytes());
encodeAndReplaceParameter(SIGNATURE, signature);
return super.buildQueryString();
} catch (Exception e) {
throw new RuntimeException("error signing request [" + toSign.toString() + "]");
}
}
/**
* {@inheritDoc}
*
* @see CommonEC2Parameters#AWS_ACCESS_KEY_ID
*/
@SuppressWarnings("unchecked")
public T signWith(String awsAccessKeyId, String awsSecretAccessKey) {
this.awsAccessKeyId = checkNotNull(awsAccessKeyId, "awsAccessKeyId");
this.awsSecretAccessKey = checkNotNull(awsSecretAccessKey, "awsSecretAccessKey");
return (T) this;
}
/**
* {@inheritDoc}
*
* @see HttpHeaders#HOST
*/
@SuppressWarnings("unchecked")
public T usingHost(String hostname) {
this.replaceHeader(HttpHeaders.HOST, hostname);
return (T) this;
}
/**
* The types here are parameterized in effort to return the proper type of the subclass
*
* @author Adrian Cole
*/
public static abstract class Builder {
/**
* @see BaseEC2RequestOptions#expireAt(DateTime)
*/
@SuppressWarnings("unchecked")
public static <T extends EC2RequestOptions> T expireAt(DateTime time) {
T options;
try {
options = (T) realClass.newInstance();
} catch (Exception e) {
throw new Error("incorrect configuration, class: " + realClass
+ " should extend BaseEC2RequestOptions", e);
}
return (T) options.expireAt(time);
}
/**
* @see BaseEC2RequestOptions#usingHost(String)
*/
@SuppressWarnings("unchecked")
public static <T extends EC2RequestOptions> T usingHost(String hostname) {
T options;
try {
options = (T) realClass.newInstance();
} catch (Exception e) {
throw new Error("incorrect configuration, class: " + realClass
+ " should extend BaseEC2RequestOptions", e);
}
return (T) options.usingHost(hostname);
}
/**
* @see BaseEC2RequestOptions#signWith(String,String)
*/
@SuppressWarnings("unchecked")
public static <T extends EC2RequestOptions> T signWith(String awsAccessKeyId,
String awsSecretAccessKey) {
T options;
try {
options = (T) realClass.newInstance();
} catch (Exception e) {
throw new Error("incorrect configuration, class: " + realClass
+ " should extend BaseEC2RequestOptions", e);
}
return (T) options.signWith(awsAccessKeyId, awsSecretAccessKey);
}
}
}

View File

@ -1,176 +0,0 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.commands.options;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.ACTION;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.AWS_ACCESS_KEY_ID;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.EXPIRES;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.SIGNATURE;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.SIGNATURE_METHOD;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.SIGNATURE_VERSION;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.TIMESTAMP;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.VERSION;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.aws.ec2.reference.CommonEC2Parameters;
import org.jclouds.aws.reference.AWSConstants;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils;
import org.jclouds.util.DateService;
import javax.inject.Inject;
import javax.inject.Named;
/**
* Contains the base options needed for all EC2 QUERY API operations.<h2>
* Extend this class in the following way to avoid massive boilerplate code: Usage:
* <p/>
*
* <pre>
* public static class MyRequestOptions extends BaseEC2RequestOptions&lt;MyRequestOptions&gt; {
* static {
* realClass = MyRequestOptions.class;
* }
*
* &#064;Override
* public String getAction() {
* return &quot;MyRequest&quot;;
* }
*
* public String getId() {
* return queryParameters.get(&quot;id&quot;);
* }
*
* public MyRequestOptions withId(String id) {
* encodeAndReplaceParameter(&quot;id&quot;, id);
* return this;
* }
*
* public static class Builder extends BaseEC2RequestOptions.Builder {
* public static MyRequestOptions withId(String id) {
* MyRequestOptions options = new MyRequestOptions();
* return options.withId(id);
* }
* }
* }
* </pre>
*
* @see <a href=
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/Query-Common-Parameters.html"
* />
* @see CommonEC2Parameters
* @author Adrian Cole
*
*/
public class EC2QuerySigner implements HttpRequestFilter {
public static String[] mandatoryParametersForSignature = new String[] { ACTION,
SIGNATURE_METHOD, SIGNATURE_VERSION, VERSION };
private final String accessKey;
private final String secretKey;
private final DateService dateService;
@Inject
public EC2QuerySigner(@Named(AWSConstants.PROPERTY_AWS_ACCESSKEYID) String accessKey,
@Named(AWSConstants.PROPERTY_AWS_SECRETACCESSKEY) String secretKey,
DateService dateService) {
this.accessKey = accessKey;
this.secretKey = secretKey;
this.dateService = dateService;
}
public HttpRequest filter(HttpRequest request) throws HttpException {
validateRequest(request);
request = addSigningParamsToRequest(request);
String stringToSign = buildStringToSign(request);
String signature = sign(stringToSign);
return addSignatureToRequest(request, signature);
}
private void validateRequest(HttpRequest request) {
for (String parameter : mandatoryParametersForSignature) {
checkState(request.getEndpoint().getQuery().contains(parameter), "parameter " + parameter
+ " is required for signature");
}
checkState(request.getHeaders().get(HttpHeaders.HOST) != null,
"request is not ready to sign; host not present");
}
private HttpRequest addSignatureToRequest(HttpRequest request, String signature) {
UriBuilder builder = UriBuilder.fromUri(request.getEndpoint());
builder.queryParam(SIGNATURE, signature);
return new HttpRequest(request.getMethod(), builder.build(), request.getHeaders(), request
.getEntity());
}
private String sign(String stringToSign) {
String signature;
try {
signature = HttpUtils.hmacSha256Base64(stringToSign, secretKey.getBytes());
} catch (Exception e) {
throw new HttpException("error signing request", e);
}
return signature;
}
private String buildStringToSign(HttpRequest request) {
// 1. Sort the UTF-8 query string components by parameter name with natural byte ordering.
// -- as queryParameters are a SortedSet, they are already sorted.
// 2. URL encode the parameter name and values according to the following rules...
// -- all queryParameters are URL encoded on the way in
// 3. Separate the encoded parameter names from their encoded values with the equals sign,
// even if the parameter value is empty.
// -- we do not allow null values.
// 4. Separate the name-value pairs with an ampersand.
// -- buildQueryString() does this.
StringBuilder toSign = new StringBuilder();
toSign.append(request.getMethod()).append("\n").append(
request.getEndpoint().getHost().toLowerCase()).append("\n").append("/").append("\n");
toSign.append(request.getEndpoint().getQuery());
String stringToSign = toSign.toString();
return stringToSign;
}
private HttpRequest addSigningParamsToRequest(HttpRequest request) {
UriBuilder builder = UriBuilder.fromUri(request.getEndpoint());
builder.queryParam(SIGNATURE_METHOD, "HmacSHA256");
builder.queryParam(SIGNATURE_VERSION, "2");
builder.queryParam(VERSION, "2009-04-04");
// timestamp is incompatible with expires
if (request.getEndpoint().getQuery().contains(EXPIRES)) {
// TODO tune this if necessary
builder.queryParam(TIMESTAMP, dateService.iso8601DateFormat());
}
builder.queryParam(AWS_ACCESS_KEY_ID, accessKey);
return new HttpRequest(request.getMethod(), builder.build(), request.getHeaders(), request
.getEntity());
}
}

View File

@ -1,67 +0,0 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.commands.options;
import org.jclouds.aws.ec2.reference.EC2Constants;
import org.jclouds.http.options.HttpRequestOptions;
import org.joda.time.DateTime;
import javax.inject.Named;
/**
*
* defines the interface needed to properly sign EC2 QUERY requests.
*
* @author Adrian Cole
*/
public interface EC2RequestOptions extends HttpRequestOptions {
/**
* @see org.jclouds.aws.ec2.reference.CommonEC2Parameters#ACTION
*/
String getAction();
/**
* @see org.jclouds.aws.ec2.reference.CommonEC2Parameters#AWS_ACCESS_KEY_ID
* @see org.jclouds.aws.ec2.reference.CommonEC2Parameters#SIGNATURE
*/
EC2RequestOptions signWith(@Named(EC2Constants.PROPERTY_AWS_ACCESSKEYID) String accessKey,
@Named(EC2Constants.PROPERTY_AWS_SECRETACCESSKEY) String secretKey);
/**
* @see org.jclouds.aws.ec2.reference.CommonEC2Parameters#EXPIRES
*/
EC2RequestOptions expireAt(DateTime time);
/**
* @see org.jclouds.aws.ec2.reference.CommonEC2Parameters#TIMESTAMP
*/
EC2RequestOptions timeStamp();
/**
* @see org.jclouds.http.HttpHeaders#HOST
*/
EC2RequestOptions usingHost(String hostname);
}

View File

@ -1,124 +0,0 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.commands.options;
import static org.testng.Assert.assertEquals;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import org.jclouds.util.DateService;
import org.joda.time.DateTime;
import org.testng.annotations.Test;
/**
* Tests possible uses of BaseEC2RequestOptions and BaseEC2RequestOptions.Builder.*
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ec2.BaseEC2RequestOptionsTest")
public class BaseEC2RequestOptionsTest {
@Test
public void testGetAction() {
EC2RequestOptions options = new MyRequestOptions();
assertEquals(options.getAction(), "MyRequest");
}
public static class MyRequestOptions extends BaseEC2RequestOptions<MyRequestOptions> {
static {
realClass = MyRequestOptions.class;
}
@Override
public String getAction() {
return "MyRequest";
}
/**
* @see MyRequestOptions#withId(String)
*/
public String getId() {
return queryParameters.get("id");
}
/**
* add the 'id' parameter to the query string
*/
public MyRequestOptions withId(String id) {
encodeAndReplaceParameter("id", id);
return this;
}
public static class Builder extends BaseEC2RequestOptions.Builder {
/**
* @see MyRequestOptions#withId(String)
*/
public static MyRequestOptions withId(String id) {
MyRequestOptions options = new MyRequestOptions();
return options.withId(id);
}
}
}
@Test
public void testExpireAt() throws UnsupportedEncodingException {
DateTime date = new DateTime();
BaseEC2RequestOptions<EC2RequestOptions> options = MyRequestOptions.Builder.expireAt(date);
String dateString = URLEncoder.encode(new DateService().iso8601DateFormat(date), "UTF-8");
makeReady(options);
assert options.buildQueryString().contains("Expires=" + dateString) : String.format(
"%1s$ should have contained %2s$", options.buildQueryString(), dateString);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testBuildQueryWithNotEnoughArguments() {
EC2RequestOptions options = new MyRequestOptions();
options.buildQueryString();
}
@Test
public void testBuildQueryWithEnoughArguments() {
EC2RequestOptions options = new MyRequestOptions();
makeReady(options);
options.buildQueryString();
}
private void makeReady(EC2RequestOptions options) {
options.signWith("meow", "bark");
options.usingHost("localhost");
}
@Test
public void testExpireAtStatic() throws UnsupportedEncodingException {
DateTime date = new DateTime();
BaseEC2RequestOptions<EC2RequestOptions> options = MyRequestOptions.Builder.expireAt(date);
String dateString = URLEncoder.encode(new DateService().iso8601DateFormat(date), "UTF-8");
makeReady(options);
assert options.buildQueryString().contains("Expires=" + dateString) : String.format(
"%1s$ should have contained %2s$", options.buildQueryString(), dateString);
}
}

View File

@ -1,103 +0,0 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.aws.ec2.commands.options;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.ACTION;
import static org.jclouds.aws.ec2.reference.CommonEC2Parameters.EXPIRES;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.aws.reference.AWSConstants;
import org.jclouds.http.HttpRequest;
import org.jclouds.util.DateService;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import org.jclouds.util.Jsr330;
@Test(groups = "unit", testName = "s3.EC2QuerySignerTest")
public class EC2QuerySignerTest {
@Test
void testExpires() {
UriBuilder builder = UriBuilder.fromUri(URI.create("https://ec2.amazonaws.com/"));
builder.queryParam(ACTION,"DescribeImages");
builder.queryParam(EXPIRES,"2008-02-10T12%3A00%3A00Z");
builder.queryParam("ImageId.1","ami-2bb65342");
HttpRequest request = new HttpRequest(HttpMethod.GET,builder.build());
createFilter();
}
@Test
void testAclQueryString() {
URI host = URI.create("http://s3.amazonaws.com:80/?acl");
HttpRequest request = new HttpRequest(HttpMethod.GET, host);
StringBuilder builder = new StringBuilder();
createFilter().appendUriPath(request, builder);
assertEquals(builder.toString(), "/?acl");
}
// "?acl", "?location", "?logging", or "?torrent"
@Test
void testAppendBucketNameHostHeaderService() {
URI host = URI.create("http://s3.amazonaws.com:80");
HttpRequest request = new HttpRequest(HttpMethod.GET, host);
request.getHeaders().put(HttpHeaders.HOST, "s3.amazonaws.com");
StringBuilder builder = new StringBuilder();
createFilter().appendBucketName(request, builder);
assertEquals(builder.toString(), "");
}
@Test
void testAppendBucketNameURIHost() {
URI host = URI.create("http://adriancole.s3int5.s3-external-3.amazonaws.com:80");
HttpRequest request = new HttpRequest(HttpMethod.GET, host);
StringBuilder builder = new StringBuilder();
createFilter().appendBucketName(request, builder);
assertEquals(builder.toString(), "/adriancole.s3int5");
}
private EC2QuerySigner createFilter() {
return Guice.createInjector(new AbstractModule() {
protected void configure() {
bindConstant().annotatedWith(Jsr330.named(AWSConstants.PROPERTY_AWS_ACCESSKEYID)).to(
"foo");
bindConstant().annotatedWith(Jsr330.named(AWSConstants.PROPERTY_AWS_SECRETACCESSKEY)).to(
"bar");
bind(DateService.class);
}
}).getInstance(EC2QuerySigner.class);
}
}

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
$HeadURL$
$Revision$
$Date$
Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
====================================================================
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
d istributed 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.html
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.
====================================================================
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>jclouds-aws-project</artifactId>
<groupId>org.jclouds</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jclouds-ec2-project</artifactId>
<packaging>pom</packaging>
<name>jclouds ec2 aggregator</name>
<modules>
<module>core</module>
</modules>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-aws-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-aws-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
</project>