diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/functions/EncodedRSAPublicKeyToBase64.java b/apis/ec2/src/main/java/org/jclouds/ec2/functions/EncodedRSAPublicKeyToBase64.java similarity index 98% rename from providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/functions/EncodedRSAPublicKeyToBase64.java rename to apis/ec2/src/main/java/org/jclouds/ec2/functions/EncodedRSAPublicKeyToBase64.java index de9d32374c..0d877d6343 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/functions/EncodedRSAPublicKeyToBase64.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/functions/EncodedRSAPublicKeyToBase64.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.aws.ec2.functions; +package org.jclouds.ec2.functions; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/functions/EncodedRSAPublicKeyToBase64Test.java b/apis/ec2/src/test/java/org/jclouds/ec2/functions/EncodedRSAPublicKeyToBase64Test.java similarity index 97% rename from providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/functions/EncodedRSAPublicKeyToBase64Test.java rename to apis/ec2/src/test/java/org/jclouds/ec2/functions/EncodedRSAPublicKeyToBase64Test.java index fa4616a0e9..05ba97ab45 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/functions/EncodedRSAPublicKeyToBase64Test.java +++ b/apis/ec2/src/test/java/org/jclouds/ec2/functions/EncodedRSAPublicKeyToBase64Test.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.aws.ec2.functions; +package org.jclouds.ec2.functions; import static org.testng.Assert.assertEquals; diff --git a/apis/openstack-nova-ec2/pom.xml b/apis/openstack-nova-ec2/pom.xml index d7c2abd444..e8ef79dbf7 100644 --- a/apis/openstack-nova-ec2/pom.xml +++ b/apis/openstack-nova-ec2/pom.xml @@ -78,7 +78,7 @@ org.jclouds.driver - jclouds-slf4j + jclouds-log4j ${project.version} test diff --git a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/NovaEC2ApiMetadata.java b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/NovaEC2ApiMetadata.java index e0c53d8051..904c26f829 100644 --- a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/NovaEC2ApiMetadata.java +++ b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/NovaEC2ApiMetadata.java @@ -29,8 +29,6 @@ import java.util.Properties; import org.jclouds.apis.ApiMetadata; import org.jclouds.ec2.EC2ApiMetadata; -import org.jclouds.ec2.EC2AsyncClient; -import org.jclouds.ec2.EC2Client; import org.jclouds.ec2.compute.config.EC2ResolveImagesModule; import org.jclouds.openstack.nova.ec2.config.NovaEC2ComputeServiceContextModule; import org.jclouds.openstack.nova.ec2.config.NovaEC2RestClientModule; @@ -48,12 +46,12 @@ import com.google.inject.Module; public class NovaEC2ApiMetadata extends EC2ApiMetadata { /** The serialVersionUID */ - private static final long serialVersionUID = -1492951757032303845L; - - public static final TypeToken> CONTEXT_TOKEN = new TypeToken>() { - private static final long serialVersionUID = -5070937833892503232L; + private static final long serialVersionUID = -8539835226183747429L; + + public static final TypeToken> CONTEXT_TOKEN = new TypeToken>() { + private static final long serialVersionUID = -6449920293625658712L; }; - + private static Builder builder() { return new Builder(); } @@ -90,12 +88,13 @@ public class NovaEC2ApiMetadata extends EC2ApiMetadata { public static class Builder extends EC2ApiMetadata.Builder { protected Builder(){ - super(EC2Client.class, EC2AsyncClient.class); + super(NovaEC2Client.class, NovaEC2AsyncClient.class); id("openstack-nova-ec2") .name("OpenStack Nova's EC2-clone API") .version("2009-04-04") .defaultEndpoint("http://localhost:8773/services/Cloud") .defaultProperties(NovaEC2ApiMetadata.defaultProperties()) + .context(CONTEXT_TOKEN) .defaultModules(ImmutableSet.>of(NovaEC2RestClientModule.class, EC2ResolveImagesModule.class, NovaEC2ComputeServiceContextModule.class)); } diff --git a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/NovaEC2AsyncClient.java b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/NovaEC2AsyncClient.java new file mode 100644 index 0000000000..7d09a25f04 --- /dev/null +++ b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/NovaEC2AsyncClient.java @@ -0,0 +1,37 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.openstack.nova.ec2; + +import org.jclouds.ec2.EC2AsyncClient; +import org.jclouds.openstack.nova.ec2.services.NovaEC2KeyPairAsyncClient; +import org.jclouds.rest.annotations.Delegate; + +/** + * Provides asynchronous access to EC2 services. + * + * @author Adam Lowe + */ +public interface NovaEC2AsyncClient extends EC2AsyncClient { + /** + * {@inheritDoc} + */ + @Delegate + @Override + NovaEC2KeyPairAsyncClient getKeyPairServices(); +} diff --git a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/NovaEC2Client.java b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/NovaEC2Client.java new file mode 100644 index 0000000000..ab9bab86b0 --- /dev/null +++ b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/NovaEC2Client.java @@ -0,0 +1,42 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.openstack.nova.ec2; + +import java.util.concurrent.TimeUnit; + +import org.jclouds.concurrent.Timeout; +import org.jclouds.ec2.EC2Client; +import org.jclouds.openstack.nova.ec2.services.NovaEC2KeyPairClient; +import org.jclouds.rest.annotations.Delegate; + +/** + * Provides synchronous access to EC2 services. + * + * @author Adam Lowe + */ +@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS) +public interface NovaEC2Client extends EC2Client { + + /** + * {@inheritDoc} + */ + @Delegate + @Override + NovaEC2KeyPairClient getKeyPairServices(); +} diff --git a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java index da18c3733f..311c9589a0 100644 --- a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java +++ b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/config/NovaEC2RestClientModule.java @@ -18,9 +18,14 @@ */ package org.jclouds.openstack.nova.ec2.config; +import java.util.Map; + +import javax.inject.Singleton; + import org.jclouds.ec2.EC2AsyncClient; import org.jclouds.ec2.EC2Client; import org.jclouds.ec2.config.EC2RestClientModule; +import org.jclouds.ec2.services.*; import org.jclouds.ec2.suppliers.DescribeAvailabilityZonesInRegion; import org.jclouds.ec2.xml.CreateVolumeResponseHandler; import org.jclouds.ec2.xml.DescribeImagesResponseHandler; @@ -28,10 +33,17 @@ import org.jclouds.location.config.LocationModule; import org.jclouds.location.suppliers.RegionIdToZoneIdsSupplier; import org.jclouds.location.suppliers.ZoneIdsSupplier; import org.jclouds.location.suppliers.derived.ZoneIdsFromRegionIdToZoneIdsValues; +import org.jclouds.openstack.nova.ec2.NovaEC2AsyncClient; +import org.jclouds.openstack.nova.ec2.NovaEC2Client; +import org.jclouds.openstack.nova.ec2.services.NovaEC2KeyPairAsyncClient; +import org.jclouds.openstack.nova.ec2.services.NovaEC2KeyPairClient; import org.jclouds.openstack.nova.ec2.xml.NovaCreateVolumeResponseHandler; import org.jclouds.openstack.nova.ec2.xml.NovaDescribeImagesResponseHandler; import org.jclouds.rest.ConfiguresRestClient; +import com.google.common.collect.ImmutableMap; +import com.google.common.reflect.TypeToken; +import com.google.inject.Provides; import com.google.inject.Scopes; /** @@ -40,8 +52,22 @@ import com.google.inject.Scopes; * @author Adam Lowe */ @ConfiguresRestClient -public class NovaEC2RestClientModule extends EC2RestClientModule { +public class NovaEC2RestClientModule extends EC2RestClientModule { + public static final Map, Class> DELEGATE_MAP = ImmutableMap., Class> builder()// + .put(AMIClient.class, AMIAsyncClient.class)// + .put(ElasticIPAddressClient.class, ElasticIPAddressAsyncClient.class)// + .put(InstanceClient.class, InstanceAsyncClient.class)// + .put(NovaEC2KeyPairClient.class, NovaEC2KeyPairAsyncClient.class)// + .put(SecurityGroupClient.class, SecurityGroupAsyncClient.class)// + .put(WindowsClient.class, WindowsAsyncClient.class)// + .put(AvailabilityZoneAndRegionClient.class, AvailabilityZoneAndRegionAsyncClient.class)// + .put(ElasticBlockStoreClient.class, ElasticBlockStoreAsyncClient.class)// + .build(); + public NovaEC2RestClientModule() { + super(TypeToken.of(NovaEC2Client.class), TypeToken.of(NovaEC2AsyncClient.class), DELEGATE_MAP); + } + @Override protected void configure() { install(new NovaEC2ParserModule()); @@ -57,4 +83,16 @@ public class NovaEC2RestClientModule extends EC2RestClientModule importKeyPairInRegion( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("KeyName") String keyName, + @FormParam("PublicKeyMaterial") @ParamParser(EncodedRSAPublicKeyToBase64.class) String publicKeyMaterial); +} diff --git a/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/services/NovaEC2KeyPairClient.java b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/services/NovaEC2KeyPairClient.java new file mode 100644 index 0000000000..ef4e88b714 --- /dev/null +++ b/apis/openstack-nova-ec2/src/main/java/org/jclouds/openstack/nova/ec2/services/NovaEC2KeyPairClient.java @@ -0,0 +1,69 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.openstack.nova.ec2.services; + +import java.util.concurrent.TimeUnit; + +import org.jclouds.concurrent.Timeout; +import org.jclouds.ec2.domain.KeyPair; +import org.jclouds.ec2.services.KeyPairClient; +import org.jclouds.javax.annotation.Nullable; + +/** + * + * @author Adrian Cole + */ +@Timeout(duration = 90, timeUnit = TimeUnit.SECONDS) +public interface NovaEC2KeyPairClient 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 (Nova + * keeps a copy of the public key). With ImportKeyPair, you create the key pair and give Nova just + * the public key. The private key is never transferred between you and Nova. + * + *

+ * 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/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/internal/BaseNovaEC2RestClientExpectTest.java b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/internal/BaseNovaEC2RestClientExpectTest.java index 5f34f76241..5947fd1388 100644 --- a/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/internal/BaseNovaEC2RestClientExpectTest.java +++ b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/internal/BaseNovaEC2RestClientExpectTest.java @@ -8,9 +8,9 @@ import javax.ws.rs.core.MediaType; import org.jclouds.Constants; import org.jclouds.date.DateService; import org.jclouds.date.internal.SimpleDateFormatDateService; -import org.jclouds.ec2.EC2Client; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; +import org.jclouds.openstack.nova.ec2.NovaEC2Client; import org.jclouds.openstack.nova.ec2.config.NovaEC2RestClientModule; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.internal.BaseRestClientExpectTest; @@ -19,7 +19,7 @@ import com.google.common.collect.ImmutableMultimap; import com.google.inject.Module; import com.google.inject.Provides; -public abstract class BaseNovaEC2RestClientExpectTest extends BaseRestClientExpectTest { +public abstract class BaseNovaEC2RestClientExpectTest extends BaseRestClientExpectTest { protected static final String CONSTANT_DATE = "2012-04-16T15:54:08.897Z"; protected DateService dateService = new SimpleDateFormatDateService(); protected URI endpoint = URI.create("http://localhost:8773/services/Cloud/"); diff --git a/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2KeyPairClientExpectTest.java b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2KeyPairClientExpectTest.java new file mode 100644 index 0000000000..43df5d0de4 --- /dev/null +++ b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2KeyPairClientExpectTest.java @@ -0,0 +1,84 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.openstack.nova.ec2.services; + +import static org.testng.Assert.assertEquals; + +import java.net.URI; + +import org.jclouds.ec2.domain.KeyPair; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.openstack.nova.ec2.internal.BaseNovaEC2RestClientExpectTest; +import org.jclouds.rest.ResourceNotFoundException; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMultimap; + +/** + * @author Adam Lowe + */ +public class NovaEC2KeyPairClientExpectTest extends BaseNovaEC2RestClientExpectTest { + + public void testImportKeyPair() { + NovaEC2KeyPairClient client = requestsSendResponses( + describeAvailabilityZonesRequest, + describeAvailabilityZonesResponse, + HttpRequest.builder().method("POST") + .endpoint(URI.create("http://localhost:8773/services/Cloud/")) + .headers(ImmutableMultimap.of("Host", "localhost:8773")) + .payload(payloadFromStringWithContentType("Action=ImportKeyPair&KeyName=mykey&PublicKeyMaterial=c3NoLXJzYSBBQQ%3D%3D&Signature=wOOKOlDfJezRkx7NKcyOyaBQuY7PoVE3HFa9495RL7s%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-04-16T15%3A54%3A08.897Z&Version=2009-04-04&AWSAccessKeyId=identity", "application/x-www-form-urlencoded")).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/nova_ec2_import_keypair_response.xml")).build() + ).getKeyPairServices(); + + KeyPair result = client.importKeyPairInRegion(null, "mykey", "ssh-rsa AA"); + assertEquals(result.getKeyName(), "aplowe-nova-ec22"); + assertEquals(result.getSha1OfPrivateKey(), "e3:fd:de:f6:4c:36:7d:9b:8f:2f:4c:20:f8:ae:b0:ea"); + } + + @Test(expectedExceptions = ResourceNotFoundException.class) + public void testImportKeyPairFailsNotFound() { + NovaEC2KeyPairClient client = requestsSendResponses( + describeAvailabilityZonesRequest, + describeAvailabilityZonesResponse, + HttpRequest.builder().method("POST") + .endpoint(URI.create("http://localhost:8773/services/Cloud/")) + .headers(ImmutableMultimap.of("Host", "localhost:8773")) + .payload(payloadFromStringWithContentType("Action=ImportKeyPair&KeyName=mykey&PublicKeyMaterial=c3NoLXJzYSBBQQ%3D%3D&Signature=wOOKOlDfJezRkx7NKcyOyaBQuY7PoVE3HFa9495RL7s%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-04-16T15%3A54%3A08.897Z&Version=2009-04-04&AWSAccessKeyId=identity", "application/x-www-form-urlencoded")).build(), + HttpResponse.builder().statusCode(404).build() + ).getKeyPairServices(); + + client.importKeyPairInRegion(null, "mykey", "ssh-rsa AA"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testImportKeyPairFailsAlreadyExists() { + NovaEC2KeyPairClient client = requestsSendResponses( + describeAvailabilityZonesRequest, + describeAvailabilityZonesResponse, + HttpRequest.builder().method("POST") + .endpoint(URI.create("http://localhost:8773/services/Cloud/")) + .headers(ImmutableMultimap.of("Host", "localhost:8773")) + .payload(payloadFromStringWithContentType("Action=ImportKeyPair&KeyName=mykey&PublicKeyMaterial=c3NoLXJzYSBBQQ%3D%3D&Signature=wOOKOlDfJezRkx7NKcyOyaBQuY7PoVE3HFa9495RL7s%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-04-16T15%3A54%3A08.897Z&Version=2009-04-04&AWSAccessKeyId=identity", "application/x-www-form-urlencoded")).build(), + HttpResponse.builder().statusCode(409).build() + ).getKeyPairServices(); + + client.importKeyPairInRegion(null, "mykey", "ssh-rsa AA"); + } +} \ No newline at end of file diff --git a/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2KeyPairClientLiveTest.java b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2KeyPairClientLiveTest.java new file mode 100644 index 0000000000..58630dbfbc --- /dev/null +++ b/apis/openstack-nova-ec2/src/test/java/org/jclouds/openstack/nova/ec2/services/NovaEC2KeyPairClientLiveTest.java @@ -0,0 +1,136 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.openstack.nova.ec2.services; + +import static com.google.common.collect.Sets.newTreeSet; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; + +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; + +import org.jclouds.compute.ComputeTestUtils; +import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; +import org.jclouds.crypto.SshKeys; +import org.jclouds.ec2.domain.KeyPair; +import org.jclouds.openstack.nova.ec2.NovaEC2ApiMetadata; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * Tests behavior of {@code NovaKeyPairClient} + * + * @author Adam Lowe + */ +@Test(groups = "live", singleThreaded = true) +public class NovaEC2KeyPairClientLiveTest extends BaseComputeServiceContextLiveTest { + + public static final String PREFIX = System.getProperty("user.name") + "-nova-ec2"; + + public NovaEC2KeyPairClientLiveTest() { + provider = "openstack-nova-ec2"; + } + + private NovaEC2KeyPairClient client; + private Set regions; + + @Override + @BeforeClass(groups = { "integration", "live" }) + public void setupContext() { + super.setupContext(); + client = view.unwrap(NovaEC2ApiMetadata.CONTEXT_TOKEN).getApi().getKeyPairServices(); + regions = view.unwrap(NovaEC2ApiMetadata.CONTEXT_TOKEN).getApi().getAvailabilityZoneAndRegionServices().describeRegions().keySet(); + } + + @Test + void testDescribeKeyPairs() { + for (String region : regions) { + SortedSet allResults = newTreeSet(client.describeKeyPairsInRegion(region)); + assertNotNull(allResults); + if (allResults.size() >= 1) { + KeyPair pair = allResults.last(); + SortedSet result = newTreeSet(client.describeKeyPairsInRegion(region, pair.getKeyName())); + assertNotNull(result); + KeyPair compare = result.last(); + assertEquals(compare, pair); + } + } + } + + @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 IOException { + String keyName = PREFIX + "2"; + cleanupKeyPair(keyName); + Map myKey = ComputeTestUtils.setupKeyPair(); + try { + KeyPair keyPair = client.importKeyPairInRegion(null, keyName, myKey.get("public")); + checkKeyPair(keyName, keyPair); + + // check the fingerprint of public key (in the sha10OfPrivateKey field) + assertEquals(keyPair.getSha1OfPrivateKey(), SshKeys.fingerprintPublicKey(myKey.get("public"))); + + // try again to see if there's an error + try { + client.importKeyPairInRegion(null, keyName, myKey.get("public")); + fail("Duplicate call importKeyPairInRegion should have failed!"); + } catch (IllegalStateException e) { + } + } finally { + cleanupKeyPair(keyName); + } + } + + protected void checkKeyPair(String keyName, KeyPair keyPair) { + assertNotNull(keyPair); + assertNotNull(keyPair.getSha1OfPrivateKey()); + assertEquals(keyPair.getKeyName(), keyName); + + Set twoResults = client.describeKeyPairsInRegion(null, keyName); + assertNotNull(twoResults); + assertEquals(twoResults.size(), 1); + KeyPair listPair = twoResults.iterator().next(); + assertEquals(listPair.getKeyName(), keyPair.getKeyName()); + assertEquals(listPair.getSha1OfPrivateKey(), keyPair.getSha1OfPrivateKey()); + } +} diff --git a/apis/openstack-nova-ec2/src/test/resources/nova_ec2_import_keypair_response.xml b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_import_keypair_response.xml new file mode 100644 index 0000000000..24707220ec --- /dev/null +++ b/apis/openstack-nova-ec2/src/test/resources/nova_ec2_import_keypair_response.xml @@ -0,0 +1,6 @@ + + + req-dd54edc5-4beb-4b40-9694-0209fcf50459 + aplowe-nova-ec22 + e3:fd:de:f6:4c:36:7d:9b:8f:2f:4c:20:f8:ae:b0:ea + 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 index cec98084a3..98b6ff4705 100644 --- 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 @@ -24,11 +24,10 @@ import javax.ws.rs.FormParam; import javax.ws.rs.POST; import javax.ws.rs.Path; -import org.jclouds.aws.ec2.functions.EncodedRSAPublicKeyToBase64; import org.jclouds.aws.filters.FormSigner; import org.jclouds.ec2.domain.KeyPair; +import org.jclouds.ec2.functions.EncodedRSAPublicKeyToBase64; import org.jclouds.ec2.services.KeyPairAsyncClient; -import org.jclouds.ec2.services.KeyPairClient; import org.jclouds.ec2.xml.KeyPairResponseHandler; import org.jclouds.javax.annotation.Nullable; import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; @@ -49,7 +48,7 @@ import com.google.common.util.concurrent.ListenableFuture; public interface AWSKeyPairAsyncClient extends KeyPairAsyncClient { /** - * @see KeyPairClient#importKeyPairInRegion + * @see AWSKeyPairClient#importKeyPairInRegion */ @POST @Path("/")