From 9892fb1d1b44f44667b4c44ac6f59b715281910e Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 6 Mar 2011 09:22:37 -0500 Subject: [PATCH] Issue 499: added ssh key import to AWSKeyPairClient --- providers/aws-ec2/pom.xml | 2 +- .../jclouds/aws/ec2/AWSEC2AsyncClient.java | 9 +- .../org/jclouds/aws/ec2/AWSEC2Client.java | 7 + .../ec2/config/AWSEC2RestClientModule.java | 6 +- .../EncodedRSAPublicKeyToBase64.java | 73 +++++++ .../ec2/services/AWSKeyPairAsyncClient.java | 66 ++++++ .../aws/ec2/services/AWSKeyPairClient.java | 71 +++++++ .../ec2/services/MonitoringAsyncClient.java | 4 +- .../services/PlacementGroupAsyncClient.java | 4 +- .../EncodedRSAPublicKeyToBase64Test.java | 28 +++ .../ec2/services/AWSAMIAsyncClientTest.java | 162 ++++++++------- .../services/AWSInstanceAsyncClientTest.java | 192 +++++++++--------- .../services/AWSKeyPairAsyncClientTest.java | 135 ++++++++++++ .../services/AWSKeyPairClientLiveTest.java | 178 ++++++++++++++++ .../services/MonitoringAsyncClientTest.java | 4 +- .../PlacementGroupAsyncClientTest.java | 10 +- 16 files changed, 763 insertions(+), 188 deletions(-) create mode 100644 providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/functions/EncodedRSAPublicKeyToBase64.java create mode 100644 providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/AWSKeyPairAsyncClient.java create mode 100644 providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/AWSKeyPairClient.java create mode 100644 providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/functions/EncodedRSAPublicKeyToBase64Test.java create mode 100644 providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSKeyPairAsyncClientTest.java create mode 100644 providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSKeyPairClientLiveTest.java diff --git a/providers/aws-ec2/pom.xml b/providers/aws-ec2/pom.xml index e66781ffe5..d566f55547 100644 --- a/providers/aws-ec2/pom.xml +++ b/providers/aws-ec2/pom.xml @@ -36,7 +36,7 @@ https://ec2.us-east-1.amazonaws.com - 2010-06-15 + 2010-11-15 ${test.aws.identity} ${test.aws.credential} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2AsyncClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2AsyncClient.java index c556e487f7..dc856615b3 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2AsyncClient.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2AsyncClient.java @@ -21,6 +21,7 @@ package org.jclouds.aws.ec2; import org.jclouds.aws.ec2.services.AWSAMIAsyncClient; import org.jclouds.aws.ec2.services.AWSInstanceAsyncClient; +import org.jclouds.aws.ec2.services.AWSKeyPairAsyncClient; import org.jclouds.aws.ec2.services.MonitoringAsyncClient; import org.jclouds.aws.ec2.services.PlacementGroupAsyncClient; import org.jclouds.ec2.EC2AsyncClient; @@ -32,7 +33,7 @@ import org.jclouds.rest.annotations.Delegate; * @author Adrian Cole */ public interface AWSEC2AsyncClient extends EC2AsyncClient { - public final static String VERSION = "2010-06-15"; + public final static String VERSION = "2010-11-15"; /** * {@inheritDoc} @@ -60,4 +61,10 @@ public interface AWSEC2AsyncClient extends EC2AsyncClient { @Delegate MonitoringAsyncClient getMonitoringServices(); + /** + * {@inheritDoc} + */ + @Delegate + @Override + AWSKeyPairAsyncClient getKeyPairServices(); } diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Client.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Client.java index 8bd8ea53f7..9a6f9087b6 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Client.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Client.java @@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit; import org.jclouds.aws.ec2.services.AWSAMIClient; import org.jclouds.aws.ec2.services.AWSInstanceClient; +import org.jclouds.aws.ec2.services.AWSKeyPairClient; import org.jclouds.aws.ec2.services.MonitoringClient; import org.jclouds.aws.ec2.services.PlacementGroupClient; import org.jclouds.concurrent.Timeout; @@ -63,4 +64,10 @@ public interface AWSEC2Client extends EC2Client { @Delegate MonitoringClient getMonitoringServices(); + /** + * {@inheritDoc} + */ + @Delegate + @Override + AWSKeyPairClient getKeyPairServices(); } diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/config/AWSEC2RestClientModule.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/config/AWSEC2RestClientModule.java index ad0866e6d2..719b3eb411 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/config/AWSEC2RestClientModule.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/config/AWSEC2RestClientModule.java @@ -31,6 +31,8 @@ import org.jclouds.aws.ec2.services.AWSAMIAsyncClient; import org.jclouds.aws.ec2.services.AWSAMIClient; import org.jclouds.aws.ec2.services.AWSInstanceAsyncClient; import org.jclouds.aws.ec2.services.AWSInstanceClient; +import org.jclouds.aws.ec2.services.AWSKeyPairAsyncClient; +import org.jclouds.aws.ec2.services.AWSKeyPairClient; import org.jclouds.aws.ec2.services.MonitoringAsyncClient; import org.jclouds.aws.ec2.services.MonitoringClient; import org.jclouds.aws.ec2.services.PlacementGroupAsyncClient; @@ -50,8 +52,6 @@ import org.jclouds.ec2.services.ElasticIPAddressAsyncClient; import org.jclouds.ec2.services.ElasticIPAddressClient; import org.jclouds.ec2.services.InstanceAsyncClient; import org.jclouds.ec2.services.InstanceClient; -import org.jclouds.ec2.services.KeyPairAsyncClient; -import org.jclouds.ec2.services.KeyPairClient; import org.jclouds.ec2.services.SecurityGroupAsyncClient; import org.jclouds.ec2.services.SecurityGroupClient; import org.jclouds.ec2.services.WindowsAsyncClient; @@ -75,7 +75,7 @@ public class AWSEC2RestClientModule extends EC2RestClientModule + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.jclouds.aws.ec2.functions; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Singleton; + +import org.jclouds.crypto.CryptoStreams; + +import com.google.common.base.Charsets; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; + +/** + * @see + * @author Adrian Cole + */ +@Singleton +public class EncodedRSAPublicKeyToBase64 implements Function { + private static Predicate startsWith(String value) { + return new ToStringStartsWith(value); + } + + private static final class ToStringStartsWith implements Predicate { + private final String value; + + private ToStringStartsWith(String value) { + this.value = value; + } + + @Override + public boolean apply(Object input) { + return input.toString().startsWith(value); + } + + public String toString() { + return "toStringStartsWith(" + value + ")"; + } + } + + @SuppressWarnings("unchecked") + private static final Predicate ALLOWED_MARKERS = Predicates.or(startsWith("ssh-rsa"), + startsWith("-----BEGIN CERTIFICATE-----"), startsWith("---- BEGIN SSH2 PUBLIC KEY ----")); + + @Override + public String apply(Object from) { + checkNotNull(from, "input"); + checkArgument(ALLOWED_MARKERS.apply(from), "must be a ssh public key, conforming to %s ", ALLOWED_MARKERS); + return CryptoStreams.base64(from.toString().getBytes(Charsets.UTF_8)); + } +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/AWSKeyPairAsyncClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/AWSKeyPairAsyncClient.java new file mode 100644 index 0000000000..c6a9d2b7c4 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/AWSKeyPairAsyncClient.java @@ -0,0 +1,66 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.jclouds.aws.ec2.services; + +import static org.jclouds.aws.reference.FormParameters.ACTION; +import static org.jclouds.aws.reference.FormParameters.VERSION; + +import javax.annotation.Nullable; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; + +import org.jclouds.aws.ec2.AWSEC2AsyncClient; +import org.jclouds.aws.ec2.functions.EncodedRSAPublicKeyToBase64; +import org.jclouds.aws.filters.FormSigner; +import org.jclouds.ec2.domain.KeyPair; +import org.jclouds.ec2.services.KeyPairAsyncClient; +import org.jclouds.ec2.services.KeyPairClient; +import org.jclouds.ec2.xml.KeyPairResponseHandler; +import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; +import org.jclouds.rest.annotations.EndpointParam; +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; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * @author Adrian Cole + */ +@RequestFilters(FormSigner.class) +@FormParams(keys = VERSION, values = AWSEC2AsyncClient.VERSION) +@VirtualHost +public interface AWSKeyPairAsyncClient extends KeyPairAsyncClient { + + /** + * @see KeyPairClient#importKeyPairInRegion + */ + @POST + @Path("/") + @FormParams(keys = ACTION, values = "ImportKeyPair") + @XMLResponseParser(KeyPairResponseHandler.class) + ListenableFuture importKeyPairInRegion( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("KeyName") String keyName, + @FormParam("PublicKeyMaterial") @ParamParser(EncodedRSAPublicKeyToBase64.class) String publicKeyMaterial); +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/AWSKeyPairClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/AWSKeyPairClient.java new file mode 100644 index 0000000000..b21ca6ab3a --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/AWSKeyPairClient.java @@ -0,0 +1,71 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.jclouds.aws.ec2.services; + +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nullable; + +import org.jclouds.concurrent.Timeout; +import org.jclouds.ec2.domain.KeyPair; +import org.jclouds.ec2.services.KeyPairClient; + +/** + * + * @author Adrian Cole + */ +@Timeout(duration = 90, timeUnit = TimeUnit.SECONDS) +public interface AWSKeyPairClient extends KeyPairClient { + + /** + * Imports the public key from an RSA key pair that you created with a third-party tool. Compare + * this with CreateKeyPair, in which AWS creates the key pair and gives the keys to you (AWS + * keeps a copy of the public key). With ImportKeyPair, you create the key pair and give AWS just + * the public key. The private key is never transferred between you and AWS. + * + *

+ * You can easily create an RSA key pair on Windows and Linux using the ssh-keygen command line + * tool (provided with the standard OpenSSH installation). Standard library support for RSA key + * pair creation is also available in Java, Ruby, Python, and many other programming languages. + * + *

+ *

Supported Formats

+ *
    + *
  • OpenSSH public key format (e.g., the format in ~/.ssh/authorized_keys)
  • + *
  • Base64 encoded DER format
  • + *
  • SSH public key file format as specified in RFC4716
  • + *
+ * DSA keys are not supported. Make sure your key generator is set up to create RSA keys. + *

+ * Supported lengths: 1024, 2048, and 4096. + *

+ * + * @param region + * region to import the key into + * @param keyName + * A unique name for the key pair. Accepts alphanumeric characters, spaces, dashes, and + * underscores. + * @param publicKeyMaterial + * The public key + * @return imported key including fingerprint + */ + KeyPair importKeyPairInRegion(@Nullable String region, String keyName, String publicKeyMaterial); + +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/MonitoringAsyncClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/MonitoringAsyncClient.java index 0c42604f61..088bfcb8ee 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/MonitoringAsyncClient.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/MonitoringAsyncClient.java @@ -29,10 +29,10 @@ import javax.ws.rs.FormParam; import javax.ws.rs.POST; import javax.ws.rs.Path; +import org.jclouds.aws.ec2.AWSEC2AsyncClient; import org.jclouds.aws.ec2.domain.MonitoringState; import org.jclouds.aws.ec2.xml.MonitoringStateHandler; import org.jclouds.aws.filters.FormSigner; -import org.jclouds.ec2.EC2AsyncClient; import org.jclouds.ec2.binders.BindInstanceIdsToIndexedFormParams; import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; import org.jclouds.rest.annotations.BinderParam; @@ -51,7 +51,7 @@ import com.google.common.util.concurrent.ListenableFuture; * @author Adrian Cole */ @RequestFilters(FormSigner.class) -@FormParams(keys = VERSION, values = EC2AsyncClient.VERSION) +@FormParams(keys = VERSION, values = AWSEC2AsyncClient.VERSION) @VirtualHost public interface MonitoringAsyncClient { diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/PlacementGroupAsyncClient.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/PlacementGroupAsyncClient.java index 45adce9236..d44c637a38 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/PlacementGroupAsyncClient.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/services/PlacementGroupAsyncClient.java @@ -29,10 +29,10 @@ import javax.ws.rs.FormParam; import javax.ws.rs.POST; import javax.ws.rs.Path; +import org.jclouds.aws.ec2.AWSEC2AsyncClient; import org.jclouds.aws.ec2.domain.PlacementGroup; import org.jclouds.aws.ec2.xml.DescribePlacementGroupsResponseHandler; import org.jclouds.aws.filters.FormSigner; -import org.jclouds.ec2.EC2AsyncClient; import org.jclouds.ec2.binders.BindGroupNamesToIndexedFormParams; import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; import org.jclouds.rest.annotations.BinderParam; @@ -54,7 +54,7 @@ import com.google.common.util.concurrent.ListenableFuture; * @author Adrian Cole */ @RequestFilters(FormSigner.class) -@FormParams(keys = VERSION, values = EC2AsyncClient.VERSION) +@FormParams(keys = VERSION, values = AWSEC2AsyncClient.VERSION) @VirtualHost public interface PlacementGroupAsyncClient { diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/functions/EncodedRSAPublicKeyToBase64Test.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/functions/EncodedRSAPublicKeyToBase64Test.java new file mode 100644 index 0000000000..9c235ee8c3 --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/functions/EncodedRSAPublicKeyToBase64Test.java @@ -0,0 +1,28 @@ +package org.jclouds.aws.ec2.functions; + +import static org.testng.Assert.assertEquals; + +import java.io.IOException; + +import org.testng.annotations.Test; + +/** + * Tests behavior of {@code EncodedRSAPublicKeyToBase64} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class EncodedRSAPublicKeyToBase64Test { + EncodedRSAPublicKeyToBase64 function = new EncodedRSAPublicKeyToBase64(); + + public void testAllowedMarkers() throws IOException { + assertEquals(function.apply("-----BEGIN CERTIFICATE-----"), "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t"); + assertEquals(function.apply("ssh-rsa"), "c3NoLXJzYQ=="); + assertEquals(function.apply("---- BEGIN SSH2 PUBLIC KEY ----"), "LS0tLSBCRUdJTiBTU0gyIFBVQkxJQyBLRVkgLS0tLQ=="); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testDisallowedMarkersIllegalArgument() throws IOException { + function.apply("ssh-dsa"); + } +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIAsyncClientTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIAsyncClientTest.java index 55e59271ab..8fb246c94d 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIAsyncClientTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIAsyncClientTest.java @@ -58,13 +58,13 @@ public class AWSAMIAsyncClientTest extends BaseAWSEC2AsyncClientTest mapping = Maps.newLinkedHashMap(); mapping.put("/dev/sda1", new BlockDevice("vol-test1", true)); @@ -479,14 +485,14 @@ public class AWSInstanceAsyncClientTest extends BaseAWSEC2AsyncClientTest + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.jclouds.aws.ec2.services; + +import java.io.IOException; +import java.lang.reflect.Array; +import java.lang.reflect.Method; + +import org.jclouds.ec2.xml.DescribeKeyPairsResponseHandler; +import org.jclouds.ec2.xml.KeyPairResponseHandler; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.functions.ParseSax; +import org.jclouds.http.functions.ReleasePayloadAndReturn; +import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; +import org.jclouds.rest.internal.RestAnnotationProcessor; +import org.testng.annotations.Test; + +import com.google.inject.TypeLiteral; + +/** + * Tests behavior of {@code AWSKeyPairAsyncClient} + * + * @author Adrian Cole + */ +// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire +@Test(groups = "unit", testName = "AWSKeyPairAsyncClientTest") +public class AWSKeyPairAsyncClientTest extends BaseAWSEC2AsyncClientTest { + + public void testCreateKeyPair() throws SecurityException, NoSuchMethodException, IOException { + Method method = AWSKeyPairAsyncClient.class.getMethod("createKeyPairInRegion", String.class, String.class); + HttpRequest request = processor.createRequest(method, null, "mykey"); + + assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1"); + assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n"); + assertPayloadEquals(request, "Version=2010-11-15&Action=CreateKeyPair&KeyName=mykey", + "application/x-www-form-urlencoded", false); + + assertResponseParserClassEquals(method, request, ParseSax.class); + assertSaxResponseParserClassEquals(method, KeyPairResponseHandler.class); + assertExceptionParserClassEquals(method, null); + + checkFilters(request); + } + + public void testImportKeyPair() throws SecurityException, NoSuchMethodException, IOException { + Method method = AWSKeyPairAsyncClient.class.getMethod("importKeyPairInRegion", String.class, String.class, + String.class); + HttpRequest request = processor.createRequest(method, null, "mykey", "ssh-rsa AA"); + + assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1"); + assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n"); + assertPayloadEquals(request, "Version=2010-11-15&Action=ImportKeyPair&PublicKeyMaterial=c3NoLXJzYSBBQQ%3D%3D&KeyName=mykey", + "application/x-www-form-urlencoded", false); + + assertResponseParserClassEquals(method, request, ParseSax.class); + assertSaxResponseParserClassEquals(method, KeyPairResponseHandler.class); + assertExceptionParserClassEquals(method, null); + + checkFilters(request); + } + + public void testDeleteKeyPair() throws SecurityException, NoSuchMethodException, IOException { + Method method = AWSKeyPairAsyncClient.class.getMethod("deleteKeyPairInRegion", String.class, String.class); + HttpRequest request = processor.createRequest(method, null, "mykey"); + + assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1"); + assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n"); + assertPayloadEquals(request, "Version=2010-11-15&Action=DeleteKeyPair&KeyName=mykey", + "application/x-www-form-urlencoded", false); + + assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, null); + + checkFilters(request); + } + + public void testDescribeKeyPairs() throws SecurityException, NoSuchMethodException, IOException { + Method method = AWSKeyPairAsyncClient.class.getMethod("describeKeyPairsInRegion", String.class, Array + .newInstance(String.class, 0).getClass()); + HttpRequest request = processor.createRequest(method, (String) null); + + assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1"); + assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n"); + assertPayloadEquals(request, "Version=2010-11-15&Action=DescribeKeyPairs", "application/x-www-form-urlencoded", + false); + + assertResponseParserClassEquals(method, request, ParseSax.class); + assertSaxResponseParserClassEquals(method, DescribeKeyPairsResponseHandler.class); + assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class); + + checkFilters(request); + } + + public void testDescribeKeyPairsArgs() throws SecurityException, NoSuchMethodException, IOException { + Method method = AWSKeyPairAsyncClient.class.getMethod("describeKeyPairsInRegion", String.class, Array + .newInstance(String.class, 0).getClass()); + HttpRequest request = processor.createRequest(method, null, "1", "2"); + + assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1"); + assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n"); + assertPayloadEquals(request, "Version=2010-11-15&Action=DescribeKeyPairs&KeyName.1=1&KeyName.2=2", + "application/x-www-form-urlencoded", false); + + assertResponseParserClassEquals(method, request, ParseSax.class); + assertSaxResponseParserClassEquals(method, DescribeKeyPairsResponseHandler.class); + assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class); + + checkFilters(request); + } + + @Override + protected TypeLiteral> createTypeLiteral() { + return new TypeLiteral>() { + }; + } + +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSKeyPairClientLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSKeyPairClientLiveTest.java new file mode 100644 index 0000000000..aabfe33cff --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSKeyPairClientLiveTest.java @@ -0,0 +1,178 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.jclouds.aws.ec2.services; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.SortedSet; + +import org.jclouds.Constants; +import org.jclouds.aws.domain.Region; +import org.jclouds.aws.ec2.AWSEC2AsyncClient; +import org.jclouds.aws.ec2.AWSEC2Client; +import org.jclouds.compute.ComputeServiceContextFactory; +import org.jclouds.compute.ComputeTestUtils; +import org.jclouds.ec2.domain.KeyPair; +import org.jclouds.logging.log4j.config.Log4JLoggingModule; +import org.jclouds.rest.RestContext; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import com.google.inject.Module; + +/** + * Tests behavior of {@code AWSKeyPairClient} + * + * @author Adrian Cole + */ +@Test(groups = "live", sequential = true) +public class AWSKeyPairClientLiveTest { + + private AWSKeyPairClient client; + private RestContext context; + + protected String provider = "aws-ec2"; + protected String identity; + protected String credential; + protected String endpoint; + protected String apiversion; + + protected void setupCredentials() { + identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity"); + credential = checkNotNull(System.getProperty("test." + provider + ".credential"), "test." + provider + + ".credential"); + endpoint = System.getProperty("test." + provider + ".endpoint", null); + apiversion = System.getProperty("test." + provider + ".apiversion", null); + } + + protected Properties setupProperties() { + Properties overrides = new Properties(); + overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "true"); + overrides.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true"); + overrides.setProperty(provider + ".identity", identity); + overrides.setProperty(provider + ".credential", credential); + if (endpoint != null) + overrides.setProperty(provider + ".endpoint", endpoint); + if (apiversion != null) + overrides.setProperty(provider + ".apiversion", apiversion); + return overrides; + } + + @BeforeGroups(groups = { "live" }) + public void setupClient() { + setupCredentials(); + Properties overrides = setupProperties(); + context = new ComputeServiceContextFactory().createContext(provider, + ImmutableSet. of(new Log4JLoggingModule()), overrides).getProviderSpecificContext(); + client = context.getApi().getKeyPairServices(); + } + + @Test + void testDescribeAWSKeyPairs() { + for (String region : Region.DEFAULT_REGIONS) { + + SortedSet allResults = Sets.newTreeSet(client.describeKeyPairsInRegion(region)); + assertNotNull(allResults); + if (allResults.size() >= 1) { + KeyPair pair = allResults.last(); + SortedSet result = Sets.newTreeSet(client.describeKeyPairsInRegion(region, pair.getKeyName())); + assertNotNull(result); + KeyPair compare = result.last(); + assertEquals(compare, pair); + } + } + } + + public static final String PREFIX = System.getProperty("user.name") + "-ec2"; + + @Test + void testCreateKeyPair() { + String keyName = PREFIX + "1"; + cleanupKeyPair(keyName); + try { + KeyPair keyPair = client.createKeyPairInRegion(null, keyName); + checkKeyPair(keyName, keyPair); + assertNotNull(keyPair.getKeyMaterial()); + } finally { + cleanupKeyPair(keyName); + } + } + + protected void cleanupKeyPair(String keyName) { + try { + client.deleteKeyPairInRegion(null, keyName); + } catch (Exception e) { + + } + client.deleteKeyPairInRegion(null, keyName); + } + + @Test + void testImportKeyPair() throws FileNotFoundException, IOException { + String keyName = PREFIX + "2"; + cleanupKeyPair(keyName); + Map myKey = ComputeTestUtils.setupKeyPair(); + try { + KeyPair keyPair = client.importKeyPairInRegion(null, keyName, myKey.get("public")); + checkKeyPair(keyName, keyPair); + // TODO generate correct fingerprint and check + // assertEquals(keyPair.getKeyFingerprint(), + // CryptoStreams.hex(CryptoStreams.md5(myKey.get("public").getBytes()))); + + // try again to see if there's an error + try { + client.importKeyPairInRegion(null, keyName, myKey.get("public")); + assert false; + } catch (IllegalStateException e) { + + } + } finally { + cleanupKeyPair(keyName); + } + } + + protected void checkKeyPair(String keyName, KeyPair keyPair) { + assertNotNull(keyPair); + assertNotNull(keyPair.getKeyFingerprint()); + assertEquals(keyPair.getKeyName(), keyName); + + Set twoResults = Sets.newLinkedHashSet(client.describeKeyPairsInRegion(null, keyName)); + assertNotNull(twoResults); + assertEquals(twoResults.size(), 1); + KeyPair listPair = twoResults.iterator().next(); + assertEquals(listPair.getKeyName(), keyPair.getKeyName()); + assertEquals(listPair.getKeyFingerprint(), keyPair.getKeyFingerprint()); + } + + @AfterTest + public void shutdown() { + context.close(); + } +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/MonitoringAsyncClientTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/MonitoringAsyncClientTest.java index 1a576a4e1c..0e7ccbf3e9 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/MonitoringAsyncClientTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/MonitoringAsyncClientTest.java @@ -46,7 +46,7 @@ public class MonitoringAsyncClientTest extends BaseAWSEC2AsyncClientTest