From ba60357f213baa88eff2619753f43b56364ebd3d Mon Sep 17 00:00:00 2001 From: "adrian.f.cole" Date: Thu, 12 Nov 2009 18:49:38 +0000 Subject: [PATCH] Issue 29: elastic ip support git-svn-id: http://jclouds.googlecode.com/svn/trunk@2269 3d8758e0-26b5-11de-8745-db77d3ebf521 --- .../java/org/jclouds/aws/ec2/EC2Client.java | 103 +++++++++++++++++- .../BindInetAddressesToIndexedFormParams.java | 36 ++++++ .../ec2/domain/PublicIpInstanceIdPair.java | 78 +++++++++++++ .../functions/InetAddressToHostAddress.java | 49 +++++++++ .../xml/AllocateAddressResponseHandler.java | 77 +++++++++++++ .../xml/DescribeAddressesResponseHandler.java | 94 ++++++++++++++++ .../aws/s3/domain/ListBucketResponse.java | 2 +- .../jclouds/aws/ec2/EC2ClientLiveTest.java | 20 +++- .../org/jclouds/aws/ec2/EC2ClientTest.java | 93 ++++++++++++++++ .../aws/ec2/ExpensiveEC2ClientLiveTest.java | 68 ++++++++++-- .../AllocateAddressResponseHandlerTest.java | 51 +++++++++ .../DescribeAddressesResponseHandlerTest.java | 57 ++++++++++ .../test/resources/ec2/allocate_address.xml | 3 + .../test/resources/ec2/describe_addresses.xml | 11 ++ aws/core/src/test/resources/ec2/log4j.xml | 4 +- 15 files changed, 730 insertions(+), 16 deletions(-) create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/binders/BindInetAddressesToIndexedFormParams.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/domain/PublicIpInstanceIdPair.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/functions/InetAddressToHostAddress.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/xml/AllocateAddressResponseHandler.java create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeAddressesResponseHandler.java create mode 100644 aws/core/src/test/java/org/jclouds/aws/ec2/xml/AllocateAddressResponseHandlerTest.java create mode 100644 aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeAddressesResponseHandlerTest.java create mode 100644 aws/core/src/test/resources/ec2/allocate_address.xml create mode 100644 aws/core/src/test/resources/ec2/describe_addresses.xml diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/EC2Client.java b/aws/core/src/main/java/org/jclouds/aws/ec2/EC2Client.java index 556c9ac358..382d937f63 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/EC2Client.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/EC2Client.java @@ -26,6 +26,7 @@ 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.net.InetAddress; import java.util.SortedSet; import java.util.concurrent.Future; @@ -34,6 +35,7 @@ import javax.ws.rs.POST; import javax.ws.rs.Path; import org.jclouds.aws.ec2.binders.BindGroupNameToIndexedFormParams; +import org.jclouds.aws.ec2.binders.BindInetAddressesToIndexedFormParams; import org.jclouds.aws.ec2.binders.BindInstanceIdsToIndexedFormParams; import org.jclouds.aws.ec2.binders.BindKeyNameToIndexedFormParams; import org.jclouds.aws.ec2.binders.BindUserIdGroupPairToSourceSecurityGroupFormParams; @@ -41,14 +43,18 @@ import org.jclouds.aws.ec2.domain.Image; import org.jclouds.aws.ec2.domain.ImageAttribute; import org.jclouds.aws.ec2.domain.IpProtocol; import org.jclouds.aws.ec2.domain.KeyPair; +import org.jclouds.aws.ec2.domain.PublicIpInstanceIdPair; 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.InetAddressToHostAddress; 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.AllocateAddressResponseHandler; +import org.jclouds.aws.ec2.xml.DescribeAddressesResponseHandler; import org.jclouds.aws.ec2.xml.DescribeImagesResponseHandler; import org.jclouds.aws.ec2.xml.DescribeInstancesResponseHandler; import org.jclouds.aws.ec2.xml.DescribeKeyPairsResponseHandler; @@ -60,6 +66,7 @@ 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.ParamParser; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.VirtualHost; import org.jclouds.rest.annotations.XMLResponseParser; @@ -115,6 +122,101 @@ public interface EC2Client { String describeImageAttribute(@FormParam("ImageId") String imageId, @FormParam("Attribute") ImageAttribute attribute); + /** + * Acquires an elastic IP address for use with your account. + * + * @see #describeAddresses + * @see #releaseAddress + * @see #associateAddress + * @see #disassociateAddress + * @see allocateAddress(); + + /** + * Associates an elastic IP address with an instance. If the IP address is currently assigned to + * another instance, the IP address is assigned to the new instance. This is an idempotent + * operation. If you enter it more than once, Amazon EC2 does not return an error. + * + * @param publicIp + * IP address that you are assigning to the instance. + * @param instanceId + * The instance to associate with the IP address. + * + * @see #allocateAddress + * @see #describeAddresses + * @see #releaseAddress + * @see #disassociateAddress + * @see associateAddress( + @FormParam("PublicIp") @ParamParser(InetAddressToHostAddress.class) InetAddress publicIp, + @FormParam("InstanceId") String instanceId); + + /** + * Disassociates the specified elastic IP address from the instance to which it is assigned. This + * is an idempotent operation. If you enter it more than once, Amazon EC2 does not return an + * error. + * + * @param publicIp + * IP address that you are assigning to the instance. + * + * @see #allocateAddress + * @see #describeAddresses + * @see #releaseAddress + * @see #associateAddress + * @see disassociateAddress( + @FormParam("PublicIp") @ParamParser(InetAddressToHostAddress.class) InetAddress publicIp); + + /** + * Releases an elastic IP address associated with your account. + * + * @param publicIp + * The IP address that you are releasing from your account. + * @see #allocateAddress + * @see #describeAddresses + * @see #associateAddress + * @see #disassociateAddress + * @see releaseAddress( + @FormParam("PublicIp") @ParamParser(InetAddressToHostAddress.class) InetAddress publicIp); + + /** + * Lists elastic IP addresses assigned to your account or provides information about a specific + * address. + * + * @param publicIps + * Elastic IP address to describe. + * @throws AWSResponseException + * if the requested publicIp is not found + * @see #allocateAddress + * @see #releaseAddress + * @see + */ + @POST + @Path("/") + @FormParams(keys = ACTION, values = "DescribeAddresses") + @XMLResponseParser(DescribeAddressesResponseHandler.class) + Future> describeAddresses( + @BinderParam(BindInetAddressesToIndexedFormParams.class) InetAddress... publicIps); + /** * Returns information about instances that you own. *

@@ -131,7 +233,6 @@ public interface EC2Client { * @see #terminateInstances * @see - * @see DescribeInstancesOptions */ @POST @Path("/") diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/binders/BindInetAddressesToIndexedFormParams.java b/aws/core/src/main/java/org/jclouds/aws/ec2/binders/BindInetAddressesToIndexedFormParams.java new file mode 100644 index 0000000000..b3d6df696a --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/binders/BindInetAddressesToIndexedFormParams.java @@ -0,0 +1,36 @@ +package org.jclouds.aws.ec2.binders; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.InetAddress; + +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 BindInetAddressesToIndexedFormParams implements Binder { + + @SuppressWarnings("unchecked") + public void bindToRequest(HttpRequest request, Object input) { + checkArgument(checkNotNull(request, "input") instanceof GeneratedHttpRequest, + "this binder is only valid for GeneratedHttpRequests!"); + checkArgument(checkNotNull(input, "input") instanceof InetAddress[], + "this binder is only valid for InetAddress[] : " + input.getClass()); + InetAddress[] addresses = (InetAddress[]) input; + String[] addressStrings = new String[addresses.length]; + for (int i = 0; i < addresses.length; i++) { + addressStrings[i] = addresses[i].getHostAddress(); + } + EC2Utils.indexFormValuesWithPrefix((GeneratedHttpRequest) request, "PublicIp", + addressStrings); + } + +} \ No newline at end of file diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/domain/PublicIpInstanceIdPair.java b/aws/core/src/main/java/org/jclouds/aws/ec2/domain/PublicIpInstanceIdPair.java new file mode 100644 index 0000000000..f1866b10e2 --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/domain/PublicIpInstanceIdPair.java @@ -0,0 +1,78 @@ +package org.jclouds.aws.ec2.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.InetAddress; + +import com.google.inject.internal.Nullable; + +/** + * + * @see + * @author Adrian Cole + */ +public class PublicIpInstanceIdPair implements Comparable { + @Nullable + private final String instanceId; + private final InetAddress publicIp; + + public PublicIpInstanceIdPair(InetAddress publicIp, @Nullable String instanceId) { + this.instanceId = instanceId; + this.publicIp = checkNotNull(publicIp, "publicIp"); + } + + /** + * {@inheritDoc} + */ + public int compareTo(PublicIpInstanceIdPair o) { + return (this == o) ? 0 : getPublicIp().getHostAddress().compareTo( + o.getPublicIp().getHostAddress()); + } + + /** + * The ID of the instance. + */ + public String getInstanceId() { + return instanceId; + } + + /** + * The public IP address. + */ + public InetAddress getPublicIp() { + return publicIp; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((instanceId == null) ? 0 : instanceId.hashCode()); + result = prime * result + ((publicIp == null) ? 0 : publicIp.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; + PublicIpInstanceIdPair other = (PublicIpInstanceIdPair) obj; + if (instanceId == null) { + if (other.instanceId != null) + return false; + } else if (!instanceId.equals(other.instanceId)) + return false; + if (publicIp == null) { + if (other.publicIp != null) + return false; + } else if (!publicIp.equals(other.publicIp)) + return false; + return true; + } + +} \ No newline at end of file diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/functions/InetAddressToHostAddress.java b/aws/core/src/main/java/org/jclouds/aws/ec2/functions/InetAddressToHostAddress.java new file mode 100644 index 0000000000..5311f229c0 --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/functions/InetAddressToHostAddress.java @@ -0,0 +1,49 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.functions; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.InetAddress; + +import javax.inject.Singleton; + +import com.google.common.base.Function; + +/** + * @author Adrian Cole + */ +@Singleton +public class InetAddressToHostAddress implements Function { + + @Override + public String apply(Object from) { + checkArgument(checkNotNull(from, "from") instanceof InetAddress, + "this binder is only valid for InetAddress!"); + return ((InetAddress) from).getHostAddress(); + } + +} \ No newline at end of file diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/xml/AllocateAddressResponseHandler.java b/aws/core/src/main/java/org/jclouds/aws/ec2/xml/AllocateAddressResponseHandler.java new file mode 100644 index 0000000000..e137f9c4a3 --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/xml/AllocateAddressResponseHandler.java @@ -0,0 +1,77 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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 javax.annotation.Resource; + +import org.jclouds.http.functions.ParseSax.HandlerWithResult; +import org.jclouds.logging.Logger; + +public class AllocateAddressResponseHandler extends HandlerWithResult { + + @Resource + protected Logger logger = Logger.NULL; + + private InetAddress ipAddress; + private StringBuilder currentText = new StringBuilder(); + + 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("publicIp")) { + ipAddress = parseInetAddress(currentOrNull()); + } + currentText = new StringBuilder(); + } + + 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); + throw new RuntimeException(e); + } + } + + public void characters(char ch[], int start, int length) { + currentText.append(ch, start, length); + } + + @Override + public InetAddress getResult() { + return ipAddress; + } + +} \ No newline at end of file diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeAddressesResponseHandler.java b/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeAddressesResponseHandler.java new file mode 100644 index 0000000000..fa54f4ed1f --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/xml/DescribeAddressesResponseHandler.java @@ -0,0 +1,94 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.SortedSet; + +import javax.annotation.Resource; + +import org.jclouds.aws.ec2.domain.PublicIpInstanceIdPair; +import org.jclouds.http.functions.ParseSax.HandlerWithResult; +import org.jclouds.logging.Logger; + +import com.google.common.collect.Sets; + +/** + * + * @author Adrian Cole + */ +public class DescribeAddressesResponseHandler extends + HandlerWithResult> { + + @Resource + protected Logger logger = Logger.NULL; + private SortedSet pairs = Sets.newTreeSet(); + private InetAddress ipAddress; + private StringBuilder currentText = new StringBuilder(); + + private String instanceId; + + 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("publicIp")) { + ipAddress = parseInetAddress(currentOrNull()); + } else if (qName.equals("instanceId")) { + instanceId = currentOrNull(); + } else if (qName.equals("item")) { + pairs.add(new PublicIpInstanceIdPair(ipAddress, instanceId)); + ipAddress = null; + instanceId = null; + } + currentText = new StringBuilder(); + } + + 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); + throw new RuntimeException(e); + } + } + + public void characters(char ch[], int start, int length) { + currentText.append(ch, start, length); + } + + @Override + public SortedSet getResult() { + return pairs; + } + +} \ No newline at end of file diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/domain/ListBucketResponse.java b/aws/core/src/main/java/org/jclouds/aws/s3/domain/ListBucketResponse.java index add8034aea..f2393649f1 100644 --- a/aws/core/src/main/java/org/jclouds/aws/s3/domain/ListBucketResponse.java +++ b/aws/core/src/main/java/org/jclouds/aws/s3/domain/ListBucketResponse.java @@ -39,7 +39,7 @@ import java.util.SortedSet; * any way you like and the bucket will remain yours for as long as you like and as long as you have * the Amazon S3 account. *

- * The similarities between buckets and domain names is not a coincidenceÑthere is a direct mapping + * The similarities between buckets and domain names is not a coincidence there is a direct mapping * between Amazon S3 buckets and subdomains of s3.amazonaws.com. Objects stored in Amazon S3 are * addressable using the REST API under the domain bucketname.s3.amazonaws.com. For example, if the * object homepage.html?is stored in the Amazon S3 bucket mybucket its address would be diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ClientLiveTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ClientLiveTest.java index 0010e3e145..aed96f9a6c 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ClientLiveTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ClientLiveTest.java @@ -39,6 +39,7 @@ import org.jclouds.aws.ec2.domain.ImageAttribute; 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.PublicIpInstanceIdPair; import org.jclouds.aws.ec2.domain.Reservation; import org.jclouds.aws.ec2.domain.SecurityGroup; import org.jclouds.aws.ec2.domain.UserIdGroupPair; @@ -71,7 +72,7 @@ public class EC2ClientLiveTest { @Test void testDescribeImages() throws InterruptedException, ExecutionException, TimeoutException { - SortedSet allResults = client.describeImages().get(30, TimeUnit.SECONDS); + SortedSet allResults = client.describeImages().get(120, TimeUnit.SECONDS); assertNotNull(allResults); assert allResults.size() >= 2 : allResults.size(); Iterator iterator = allResults.iterator(); @@ -86,7 +87,22 @@ public class EC2ClientLiveTest { assertEquals(iterator.next().getImageId(), id2); } - @Test(dependsOnMethods = "testDescribeImages", enabled=false) + @Test + void testDescribeAddresses() throws InterruptedException, ExecutionException, TimeoutException { + SortedSet allResults = client.describeAddresses().get(30, + TimeUnit.SECONDS); + assertNotNull(allResults); + if (allResults.size() >= 1) { + PublicIpInstanceIdPair pair = allResults.last(); + SortedSet result = client.describeAddresses(pair.getPublicIp()) + .get(30, TimeUnit.SECONDS); + assertNotNull(result); + PublicIpInstanceIdPair compare = result.last(); + assertEquals(compare, pair); + } + } + + @Test(dependsOnMethods = "testDescribeImages", enabled = false) void testDescribeImageAttribute() throws InterruptedException, ExecutionException, TimeoutException { SortedSet oneResult = client.describeImages(imageIds(imageId)).get(30, diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ClientTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ClientTest.java index f7dd052ac3..4b582c3272 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ClientTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/EC2ClientTest.java @@ -29,6 +29,7 @@ import static org.testng.Assert.assertEquals; import java.io.IOException; import java.lang.reflect.Array; import java.lang.reflect.Method; +import java.net.InetAddress; import java.net.URI; import org.jclouds.aws.ec2.domain.ImageAttribute; @@ -38,6 +39,8 @@ 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.AllocateAddressResponseHandler; +import org.jclouds.aws.ec2.xml.DescribeAddressesResponseHandler; import org.jclouds.aws.ec2.xml.DescribeImagesResponseHandler; import org.jclouds.aws.ec2.xml.DescribeInstancesResponseHandler; import org.jclouds.aws.ec2.xml.DescribeKeyPairsResponseHandler; @@ -248,6 +251,96 @@ public class EC2ClientTest extends RestClientTest { checkFilters(httpMethod); } + public void testDisassociateAddress() throws SecurityException, NoSuchMethodException, + IOException { + Method method = EC2Client.class.getMethod("disassociateAddress", InetAddress.class); + GeneratedHttpRequest httpMethod = processor.createRequest(method, InetAddress + .getByAddress(new byte[] { 127, 0, 0, 1 })); + + assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1"); + assertHeadersEqual(httpMethod, + "Content-Length: 64\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n"); + assertEntityEquals(httpMethod, + "Version=2009-08-15&Action=DisassociateAddress&PublicIp=127.0.0.1"); + + assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpMethod); + } + + public void testAssociateAddress() throws SecurityException, NoSuchMethodException, IOException { + Method method = EC2Client.class + .getMethod("associateAddress", InetAddress.class, String.class); + GeneratedHttpRequest httpMethod = processor.createRequest(method, InetAddress + .getByAddress(new byte[] { 127, 0, 0, 1 }), "me"); + + assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1"); + assertHeadersEqual(httpMethod, + "Content-Length: 75\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n"); + assertEntityEquals(httpMethod, + "Version=2009-08-15&Action=AssociateAddress&PublicIp=127.0.0.1&InstanceId=me"); + + assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpMethod); + } + + public void testReleaseAddress() throws SecurityException, NoSuchMethodException, IOException { + Method method = EC2Client.class.getMethod("releaseAddress", InetAddress.class); + GeneratedHttpRequest httpMethod = processor.createRequest(method, InetAddress + .getByAddress(new byte[] { 127, 0, 0, 1 })); + + 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=ReleaseAddress&PublicIp=127.0.0.1"); + + assertResponseParserClassEquals(method, httpMethod, ReturnVoidIf2xx.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpMethod); + } + + public void testDescribeAddresses() throws SecurityException, NoSuchMethodException, IOException { + Method method = EC2Client.class.getMethod("describeAddresses", Array.newInstance( + InetAddress.class, 0).getClass()); + GeneratedHttpRequest httpMethod = processor.createRequest(method, InetAddress + .getByAddress(new byte[] { 127, 0, 0, 1 })); + + 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=DescribeAddresses&PublicIp.1=127.0.0.1"); + + assertResponseParserClassEquals(method, httpMethod, ParseSax.class); + assertSaxResponseParserClassEquals(method, DescribeAddressesResponseHandler.class); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpMethod); + } + + public void testAllocateAddress() throws SecurityException, NoSuchMethodException, IOException { + Method method = EC2Client.class.getMethod("allocateAddress"); + GeneratedHttpRequest httpMethod = processor.createRequest(method); + + assertRequestLineEquals(httpMethod, "POST https://ec2.amazonaws.com/ HTTP/1.1"); + assertHeadersEqual(httpMethod, + "Content-Length: 41\nContent-Type: application/x-www-form-urlencoded\nHost: ec2.amazonaws.com\n"); + assertEntityEquals(httpMethod, "Version=2009-08-15&Action=AllocateAddress"); + + assertResponseParserClassEquals(method, httpMethod, ParseSax.class); + assertSaxResponseParserClassEquals(method, AllocateAddressResponseHandler.class); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpMethod); + } + public void testDeleteKeyPair() throws SecurityException, NoSuchMethodException, IOException { Method method = EC2Client.class.getMethod("deleteKeyPair", String.class); GeneratedHttpRequest httpMethod = processor.createRequest(method, "mykey"); diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/ExpensiveEC2ClientLiveTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/ExpensiveEC2ClientLiveTest.java index 350cb24885..82bb805535 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/ExpensiveEC2ClientLiveTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/ExpensiveEC2ClientLiveTest.java @@ -26,11 +26,13 @@ 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.assertFalse; import static org.testng.Assert.assertNotNull; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.UndeclaredThrowableException; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -40,6 +42,8 @@ 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.PublicIpInstanceIdPair; +import org.jclouds.aws.ec2.domain.Reservation; import org.jclouds.aws.ec2.domain.RunningInstance; import org.jclouds.concurrent.WithinThreadExecutorService; import org.jclouds.concurrent.config.ExecutorServiceModule; @@ -72,6 +76,7 @@ public class ExpensiveEC2ClientLiveTest { private KeyPair keyPair; private String securityGroupName; private String serverId; + private InetAddress address; @BeforeGroups(groups = { "live" }) public void setupClient() throws InterruptedException, ExecutionException, TimeoutException { @@ -87,7 +92,7 @@ public class ExpensiveEC2ClientLiveTest { sshFactory = injector.getInstance(SshClient.Factory.class); } - @Test(enabled=false) + @Test(enabled = false) void testCreateSecurityGroupIngressCidr() throws InterruptedException, ExecutionException, TimeoutException { securityGroupName = serverPrefix + "ingress"; @@ -107,7 +112,7 @@ public class ExpensiveEC2ClientLiveTest { .get(30, TimeUnit.SECONDS); } - @Test(enabled=false) + @Test(enabled = false) void testCreateKeyPair() throws InterruptedException, ExecutionException, TimeoutException { String keyName = serverPrefix + "1"; try { @@ -122,10 +127,10 @@ public class ExpensiveEC2ClientLiveTest { assertNotNull(keyPair.getKeyMaterial()); assertNotNull(keyPair.getKeyFingerprint()); assertEquals(keyPair.getKeyName(), keyName); - } - @Test(enabled = false, dependsOnMethods = { "testCreateKeyPair", "testCreateSecurityGroupIngressCidr" }) + @Test(enabled = false, dependsOnMethods = { "testCreateKeyPair", + "testCreateSecurityGroupIngressCidr" }) public void testCreateRunningInstance() throws Exception { String imageId = "ami-1fd73376"; RunningInstance server = null; @@ -153,6 +158,43 @@ public class ExpensiveEC2ClientLiveTest { sshPing(server); } + @Test(enabled = false, dependsOnMethods = "testCreateRunningInstance") + void testElasticIpAddress() throws InterruptedException, ExecutionException, TimeoutException, + IOException { + address = client.allocateAddress().get(30, TimeUnit.SECONDS); + assertNotNull(address); + + PublicIpInstanceIdPair compare = client.describeAddresses(address).get(30, TimeUnit.SECONDS) + .last(); + + assertEquals(compare.getPublicIp(), address); + assert compare.getInstanceId() == null; + + client.associateAddress(address, serverId).get(30, TimeUnit.SECONDS); + + compare = client.describeAddresses(address).get(30, TimeUnit.SECONDS).last(); + + assertEquals(compare.getPublicIp(), address); + assertEquals(compare.getInstanceId(), serverId); + + Reservation reservation = client.describeInstances(serverId).get(30, TimeUnit.SECONDS).last(); + + assertNotNull(reservation.getRunningInstances().last().getIpAddress()); + assertFalse(reservation.getRunningInstances().last().getIpAddress().equals(address)); + + doCheckKey(address); + + client.disassociateAddress(address).get(30, TimeUnit.SECONDS); + + compare = client.describeAddresses(address).get(30, TimeUnit.SECONDS).last(); + + assertEquals(compare.getPublicIp(), address); + assert compare.getInstanceId() == null; + + reservation = client.describeInstances(serverId).get(30, TimeUnit.SECONDS).last(); + assert reservation.getRunningInstances().last().getIpAddress() == null; + } + /** * this tests "personality" as the file looked up was sent during server creation */ @@ -169,8 +211,12 @@ public class ExpensiveEC2ClientLiveTest { } private void doCheckKey(RunningInstance newDetails) throws IOException { - SshClient connection = sshFactory.create(new InetSocketAddress(newDetails.getDnsName(), 22), - "root", keyPair.getKeyMaterial().getBytes()); + doCheckKey(InetAddress.getByName(newDetails.getDnsName())); + } + + private void doCheckKey(InetAddress address) throws IOException { + SshClient connection = sshFactory.create(new InetSocketAddress(address, 22), "root", keyPair + .getKeyMaterial().getBytes()); try { connection.connect(); InputStream etcPasswd = connection.get("/etc/passwd"); @@ -195,13 +241,15 @@ public class ExpensiveEC2ClientLiveTest { } @AfterTest - void cleanup() { + void cleanup() throws InterruptedException, ExecutionException, TimeoutException { + if (address != null) + client.releaseAddress(address).get(30, TimeUnit.SECONDS); if (serverId != null) - client.terminateInstances(serverId); + client.terminateInstances(serverId).get(30, TimeUnit.SECONDS); if (keyPair != null) - client.deleteKeyPair(keyPair.getKeyName()); + client.deleteKeyPair(keyPair.getKeyName()).get(30, TimeUnit.SECONDS); if (securityGroupName != null) - client.deleteSecurityGroup(securityGroupName); + client.deleteSecurityGroup(securityGroupName).get(30, TimeUnit.SECONDS); } private RunningInstance getRunningInstance(String serverId) throws InterruptedException, diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/xml/AllocateAddressResponseHandlerTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/xml/AllocateAddressResponseHandlerTest.java new file mode 100644 index 0000000000..6211b5397e --- /dev/null +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/xml/AllocateAddressResponseHandlerTest.java @@ -0,0 +1,51 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 org.jclouds.http.functions.BaseHandlerTest; +import org.testng.annotations.Test; + +/** + * Tests behavior of {@code AllocateAddressResponseHandler} + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "ec2.AllocateAddressResponseHandlerTest") +public class AllocateAddressResponseHandlerTest extends BaseHandlerTest { + public void testApplyInputStream() throws UnknownHostException { + + InputStream is = getClass().getResourceAsStream("/ec2/allocate_address.xml"); + + InetAddress result = factory.create( + injector.getInstance(AllocateAddressResponseHandler.class)).parse(is); + + assertEquals(result, InetAddress.getByName("67.202.55.255")); + } +} diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeAddressesResponseHandlerTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeAddressesResponseHandlerTest.java new file mode 100644 index 0000000000..d9c2bf6597 --- /dev/null +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/xml/DescribeAddressesResponseHandlerTest.java @@ -0,0 +1,57 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.PublicIpInstanceIdPair; +import org.jclouds.http.functions.BaseHandlerTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSortedSet; + +/** + * Tests behavior of {@code DescribeAddressesResponseHandler} + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "ec2.DescribeAddressesResponseHandlerTest") +public class DescribeAddressesResponseHandlerTest extends BaseHandlerTest { + public void testApplyInputStream() throws UnknownHostException { + + InputStream is = getClass().getResourceAsStream("/ec2/describe_addresses.xml"); + + SortedSet result = factory.create( + injector.getInstance(DescribeAddressesResponseHandler.class)).parse(is); + + assertEquals(result, ImmutableSortedSet.of(new PublicIpInstanceIdPair(InetAddress + .getByName("67.202.55.233"), null), new PublicIpInstanceIdPair(InetAddress + .getByName("67.202.55.255"), "i-f15ebb98"))); + } +} diff --git a/aws/core/src/test/resources/ec2/allocate_address.xml b/aws/core/src/test/resources/ec2/allocate_address.xml new file mode 100644 index 0000000000..7dfea10314 --- /dev/null +++ b/aws/core/src/test/resources/ec2/allocate_address.xml @@ -0,0 +1,3 @@ + + 67.202.55.255 + \ No newline at end of file diff --git a/aws/core/src/test/resources/ec2/describe_addresses.xml b/aws/core/src/test/resources/ec2/describe_addresses.xml new file mode 100644 index 0000000000..b229702a4d --- /dev/null +++ b/aws/core/src/test/resources/ec2/describe_addresses.xml @@ -0,0 +1,11 @@ + + + + i-f15ebb98 + 67.202.55.255 + + + 67.202.55.233 + + + \ No newline at end of file diff --git a/aws/core/src/test/resources/ec2/log4j.xml b/aws/core/src/test/resources/ec2/log4j.xml index d712a5bd47..00892d8958 100755 --- a/aws/core/src/test/resources/ec2/log4j.xml +++ b/aws/core/src/test/resources/ec2/log4j.xml @@ -97,13 +97,13 @@ - + + -->