Work in progress on fixing registerSSHKeyPair and implementing getPasswordForVirtualMachine

This commit is contained in:
Andrei Savu 2012-02-09 01:12:37 +02:00
parent b6f6be3eb4
commit 8524022e50
11 changed files with 322 additions and 73 deletions

View File

@ -18,29 +18,14 @@
*/ */
package org.jclouds.cloudstack.compute.strategy; package org.jclouds.cloudstack.compute.strategy;
import static com.google.common.base.Preconditions.checkArgument; import com.google.common.base.Predicate;
import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Supplier;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.and;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.getOnlyElement;
import static org.jclouds.cloudstack.options.DeployVirtualMachineOptions.Builder.displayName;
import static org.jclouds.cloudstack.predicates.NetworkPredicates.defaultNetworkInZone;
import static org.jclouds.cloudstack.predicates.NetworkPredicates.supportsStaticNAT;
import static org.jclouds.cloudstack.predicates.TemplatePredicates.isReady;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.Iterables; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Sets;
import com.google.common.primitives.Ints;
import org.jclouds.cloudstack.CloudStackClient; import org.jclouds.cloudstack.CloudStackClient;
import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions; import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions;
import org.jclouds.cloudstack.domain.AsyncCreateResponse; import org.jclouds.cloudstack.domain.AsyncCreateResponse;
@ -65,13 +50,20 @@ import org.jclouds.domain.Credentials;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import com.google.common.base.Predicate; import javax.annotation.Resource;
import com.google.common.base.Supplier; import javax.inject.Inject;
import com.google.common.cache.LoadingCache; import javax.inject.Named;
import com.google.common.collect.ImmutableSet; import javax.inject.Singleton;
import com.google.common.collect.ImmutableSet.Builder; import java.util.List;
import com.google.common.collect.Sets; import java.util.Map;
import com.google.common.primitives.Ints; import java.util.Set;
import java.util.concurrent.ExecutionException;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.filter;
import static org.jclouds.cloudstack.predicates.TemplatePredicates.isReady;
/** /**
* defines the connection between the {@link CloudStackClient} implementation * defines the connection between the {@link CloudStackClient} implementation

View File

@ -18,12 +18,6 @@
*/ */
package org.jclouds.cloudstack.features; package org.jclouds.cloudstack.features;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.Set;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import org.jclouds.cloudstack.domain.SshKeyPair; import org.jclouds.cloudstack.domain.SshKeyPair;
import org.jclouds.cloudstack.filters.AuthenticationFilter; import org.jclouds.cloudstack.filters.AuthenticationFilter;
@ -37,6 +31,12 @@ import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.Set;
/** /**
* Provides asynchronous access to CloudStack SSHKeyPair features. * Provides asynchronous access to CloudStack SSHKeyPair features.
* *

View File

@ -18,13 +18,7 @@
*/ */
package org.jclouds.cloudstack.features; package org.jclouds.cloudstack.features;
import java.util.Set; import com.google.common.util.concurrent.ListenableFuture;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.cloudstack.domain.AsyncCreateResponse; import org.jclouds.cloudstack.domain.AsyncCreateResponse;
import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.filters.AuthenticationFilter; import org.jclouds.cloudstack.filters.AuthenticationFilter;
@ -39,7 +33,11 @@ import org.jclouds.rest.annotations.Unwrap;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture; import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.Set;
/** /**
* Provides asynchronous access to cloudstack via their REST API. * Provides asynchronous access to cloudstack via their REST API.
@ -121,6 +119,15 @@ public interface VirtualMachineAsyncClient {
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<Long> resetPasswordForVirtualMachine(@QueryParam("id") long id); ListenableFuture<Long> resetPasswordForVirtualMachine(@QueryParam("id") long id);
/**
* @see VirtualMachineClient#getPasswordForVirtualMachine
*/
@GET
@QueryParams(keys = "command", values = "getVMPassword")
@SelectJson("jobid")
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<Long> getPasswordForVirtualMachine(@QueryParam("id") long id);
/** /**
* @see VirtualMachineClient#changeServiceForVirtualMachine * @see VirtualMachineClient#changeServiceForVirtualMachine
*/ */

View File

@ -18,15 +18,15 @@
*/ */
package org.jclouds.cloudstack.features; package org.jclouds.cloudstack.features;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.cloudstack.domain.AsyncCreateResponse; import org.jclouds.cloudstack.domain.AsyncCreateResponse;
import org.jclouds.cloudstack.domain.VirtualMachine; import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.cloudstack.options.DeployVirtualMachineOptions; import org.jclouds.cloudstack.options.DeployVirtualMachineOptions;
import org.jclouds.cloudstack.options.ListVirtualMachinesOptions; import org.jclouds.cloudstack.options.ListVirtualMachinesOptions;
import org.jclouds.concurrent.Timeout; import org.jclouds.concurrent.Timeout;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/** /**
* Provides synchronous access to CloudStack VirtualMachine features. * Provides synchronous access to CloudStack VirtualMachine features.
* <p/> * <p/>
@ -110,6 +110,17 @@ public interface VirtualMachineClient {
*/ */
Long resetPasswordForVirtualMachine(long id); Long resetPasswordForVirtualMachine(long id);
/**
* Return an encrypted password for the virtual machine. The command
* is asynchronous.
*
* @param id
* the ID of the virtual machine
* @return job id related to getting the encrypted password
*/
Long getPasswordForVirtualMachine(long id);
/** /**
* Changes the service offering for a virtual machine. The virtual machine * Changes the service offering for a virtual machine. The virtual machine
* must be in a "Stopped" state for this command to take effect. * must be in a "Stopped" state for this command to take effect.

View File

@ -18,17 +18,6 @@
*/ */
package org.jclouds.cloudstack.compute; package org.jclouds.cloudstack.compute;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.get;
import static com.google.common.collect.Sets.newTreeSet;
import static org.jclouds.cloudstack.options.CreateNetworkOptions.Builder.vlan;
import static org.jclouds.cloudstack.options.ListNetworkOfferingsOptions.Builder.specifyVLAN;
import java.net.URI;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions; import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions;
import org.jclouds.cloudstack.domain.Network; import org.jclouds.cloudstack.domain.Network;
import org.jclouds.cloudstack.domain.TrafficType; import org.jclouds.cloudstack.domain.TrafficType;
@ -38,8 +27,23 @@ import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.predicates.NodePredicates; import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.crypto.SshKeys;
import org.testng.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.get;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.collect.Sets.newTreeSet;
import static org.jclouds.cloudstack.options.CreateNetworkOptions.Builder.vlan;
import static org.jclouds.cloudstack.options.ListNetworkOfferingsOptions.Builder.specifyVLAN;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
@ -122,4 +126,40 @@ public class CloudStackExperimentLiveTest extends BaseCloudStackClientLiveTest {
} }
} }
@Test
public void testCreateWindowsMachineWithKeyPairAndCheckIfTheGeneratedPasswordIsEncrypted() throws RunNodesException {
final Map<String, String> sshKey = SshKeys.generate();
final String publicKey = sshKey.get("public");
String keyPairName = prefix + "-windows-keypair";
client.getSSHKeyPairClient().deleteSSHKeyPair(keyPairName);
// client.getSSHKeyPairClient().registerSSHKeyPair(keyPairName, publicKey);
client.getSSHKeyPairClient().createSSHKeyPair(keyPairName);
String group = prefix + "-windows-test";
Template template = computeContext.getComputeService().templateBuilder()
.imageId("290").locationId("1")
.options(new CloudStackTemplateOptions().setupStaticNat(false).keyPair(keyPairName))
.build();
NodeMetadata node = null;
try {
node = getOnlyElement(computeContext.getComputeService()
.createNodesInGroup(group, 1, template));
long jobId = client.getVirtualMachineClient()
.getPasswordForVirtualMachine(Long.parseLong(node.getId()));
// TODO: extrect the password from the async response
Assert.fail("Password: ...");
} finally {
if (node != null) {
computeContext.getComputeService().destroyNode(node.getId());
}
}
}
} }

View File

@ -0,0 +1,192 @@
/**
* 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.cloudstack.features;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import org.jclouds.cloudstack.CloudStackContext;
import org.jclouds.cloudstack.domain.SshKeyPair;
import org.jclouds.crypto.SshKeys;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.testng.annotations.Test;
import java.net.URI;
import java.net.URLEncoder;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
/**
* Test the CloudStack SSHKeyPairClient
*
* @author Andrei Savu
*/
@Test(groups = "unit", testName = "SSHKeyPairClientExpectTest")
public class SSHKeyPairClientExpectTest extends BaseCloudStackRestClientExpectTest<SSHKeyPairClient> {
@Test
public void testListAndGetSSHKeyPairsWhenResponseIs2xx() {
HttpResponse response = HttpResponse.builder()
.statusCode(200)
.payload(payloadFromResource("/listsshkeypairsresponse.json"))
.build();
SSHKeyPairClient client = requestSendsResponse(HttpRequest.builder()
.method("GET")
.endpoint(
URI.create("http://localhost:8080/client/api?response=json&" +
"command=listSSHKeyPairs&apiKey=identity&signature=9Mz1e7xf3vdH3QrDrvWm5eiRsjc%3D"))
.headers(
ImmutableMultimap.<String, String>builder()
.put("Accept", "application/json")
.build())
.build(), response);
assertEquals(client.listSSHKeyPairs(), ImmutableSet.of(
SshKeyPair.builder().name("jclouds-keypair")
.fingerprint("1c:06:74:52:3b:99:1c:95:5c:04:c2:f4:ba:77:6e:7b").build()));
client = requestSendsResponse(HttpRequest.builder()
.method("GET")
.endpoint(
URI.create("http://localhost:8080/client/api?response=json&command=listSSHKeyPairs&" +
"name=jclouds-keypair&apiKey=identity&signature=vYFm%2BwYIxwpjyk3xLjjGBzSkLRc%3D"))
.headers(
ImmutableMultimap.<String, String>builder()
.put("Accept", "application/json")
.build())
.build(), response);
assertEquals(client.getSSHKeyPair("jclouds-keypair"),
SshKeyPair.builder().name("jclouds-keypair")
.fingerprint("1c:06:74:52:3b:99:1c:95:5c:04:c2:f4:ba:77:6e:7b").build());
}
@Test
public void testCreateSSHKeyPairsWhenResponseIs2xx() {
SSHKeyPairClient client = requestSendsResponse(
HttpRequest.builder()
.method("GET")
.endpoint(
URI.create("http://localhost:8080/client/api?response=json&command=createSSHKeyPair&" +
"name=jclouds-keypair&apiKey=identity&signature=8wk32PZF44jrBLH2HLel22%2BqMC4%3D"))
.headers(
ImmutableMultimap.<String, String>builder()
.put("Accept", "application/json")
.build())
.build(),
HttpResponse.builder()
.statusCode(200)
.payload(payloadFromResource("/createsshkeypairresponse.json"))
.build());
SshKeyPair actual = client.createSSHKeyPair("jclouds-keypair");
SshKeyPair expected = SshKeyPair.builder().name("jclouds-keypair")
.fingerprint("1c:06:74:52:3b:99:1c:95:5c:04:c2:f4:ba:77:6e:7b")
.privateKey("-----BEGIN RSA PRIVATE KEY-----\n" +
"MIICXgIBAAKBgQDZo/EF4Ew1uEW0raz7vCs28lBwy0UKV2Xr606gaEgxO7h9mSXZ\n" +
"4x2K/KQ1NMnrbjppxGycLh9EKPWAO3ezFULAyuOZW4Fy+xRS8+3MAijxBJY/KBgl\n" +
"x5rJm2ILumRkTNkMlLGCSBb9SOqYRN1VpOy7kn3StzU9LdJ/snKVE2JLHQIDAQAB\n" +
"AoGBAMnL5okKRd9xcsBqYIAxIuiZmNhcwTErhEdRMOAukPGFbDSYsa3rldLvGdpz\n" +
"jd2LoQG8rO/LHBZ429kASqZzyiV+NvcgH+tFNJSVAigjSICfhEKF9PY2TiAkrg7S\n" +
"GyJgAjpPWQc2sQh0dE8EPEtBiq4ibXfMTDmbs1d/vnfdwtQJAkEA+AX5Y+xgWj74\n" +
"dYETmNLyLhNZpftLizEfIYj7lCVhsbFwVb8jbM1m8n8bxwGjls1w/ico1CWcQna+\n" +
"UnAfA8kJvwJBAOCj0YgDKpYd0OLQhvI3212J9QcQpJEkDOTYiMwXNHCNMKRpoF47\n" +
"MPPX+GG8YzUiQAi9/OG4pDKCjzQWE/ebiiMCQQCssnQ5WICqtggIwYykr9VDseON\n" +
"SFIMpHJ5xkjumazRrqx6eDGxc8BH/6uWwRRoT7pqrVeniFyqhsX03u8pkpU/AkBj\n" +
"WfCcwBHArNUqy2EzlWKuvwogosq16oTNXbs60HR/5uIBhTnJE1K2NemDiGc0I77A\n" +
"Xw6N4jS0piuhtLYGB8OTAkEA50abdbduXWcr62Z6E8G/6LNFaNg0uBuVgwSHtJMd\n" +
"dNeUtVDHQCHSf3tvxXTAtaB9PCnGOfgm/dyYWEMf3rMoHQ==\n" +
"-----END RSA PRIVATE KEY-----\n")
.build();
assertEquals(actual, expected);
assertEquals(SshKeys.fingerprintPrivateKey(actual.getPrivateKey()), expected.getFingerprint());
}
@Test
public void testRegisterSSHKeyPairWhenResponseIs2xx() {
String publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCc903twxU2zcQnIJdXv61RwZNZW94uId9qz08fgsBJsCOnHNIC4+L9kDOA2IHV9cUfEDBm1Be5TbpadWwSbS/05E+FARH2/MCO932UgcKUq5PGymS0249fLCBPci5zoLiG5vIym+1ij1hL/nHvkK99NIwe7io+Lmp9OcF3PTsm3Rgh5T09cRHGX9horp0VoAVa9vKJx6C1/IEHVnG8p0YPPa1lmemvx5kNBEiyoNQNYa34EiFkcJfP6rqNgvY8h/j4nE9SXoUCC/g6frhMFMOL0tzYqvz0Lczqm1Oh4RnSn3O9X4R934p28qqAobe337hmlLUdb6H5zuf+NwCh0HdZ";
String privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" +
"MIIEpQIBAAKCAQEAnPdN7cMVNs3EJyCXV7+tUcGTWVveLiHfas9PH4LASbAjpxzS\n" +
"AuPi/ZAzgNiB1fXFHxAwZtQXuU26WnVsEm0v9ORPhQER9vzAjvd9lIHClKuTxspk\n" +
"tNuPXywgT3Iuc6C4hubyMpvtYo9YS/5x75CvfTSMHu4qPi5qfTnBdz07Jt0YIeU9\n" +
"PXERxl/YaK6dFaAFWvbyicegtfyBB1ZxvKdGDz2tZZnpr8eZDQRIsqDUDWGt+BIh\n" +
"ZHCXz+q6jYL2PIf4+JxPUl6FAgv4On64TBTDi9Lc2Kr89C3M6ptToeEZ0p9zvV+E\n" +
"fd+KdvKqgKG3t9+4ZpS1HW+h+c7n/jcAodB3WQIDAQABAoIBAQCX+iKr2LzLiUMo\n" +
"lzexsFbB1+kxFe/zPryxD/QOEGzZa/+5KAB25+q5k0sqr3ZWkVXAk84pYaVut0F9\n" +
"oD95P9q1A/GyV6zrNSHDywD+Lv0VMWMtkH0dV5Bjl7fY9DbhoXXIuAc81Rhs21mk\n" +
"isIKME6Zra0VrYedGRfmE2usZc7F+rrnJeWs2edk1Q/lBLIe/v+NfRrO0fpHPu8S\n" +
"9/kbVM3fUwHXxVTbvzZjjerQcLyEr4nT53DcSQJcm3e2DGsdRr5FBxkOXlcWElew\n" +
"pbGM+RiF7RJvPW8lrmGj4y7Eo7TmfW8Yc5MM5A/PcvvxuRTRurmqOA5Wl1Bsp8/o\n" +
"PEU/p9G5AoGBANcBOz0vSj+NOFip9gbc2WPVFpaoCT51DBQsT9R4kxe34Ltbwqaj\n" +
"QXMiBjgereSM/KXTriA/Lhkj09YI5OAgk64PXcmDc2urMiFlewqxld79GDLAFwqn\n" +
"nsEm1YTjY8wujw2J5Fbp7BZFHCrfld5L8xhgSb135YEa1/4LGOg+o6FDAoGBALrl\n" +
"GL/v8ZDc2l/GpGsOA7360s9lRUhCTlQ86am8Lw/AdMSdpi9Is3yCdZx1NWDpUEKz\n" +
"MBQTfiEEzpYlujvdUQNyQ4JGuhU/J7JEqEP2rfXaXjn0PIThkWFuNRkyK6Pz0rsT\n" +
"4YJQouI7PCDE3BZxY4WYZ4uBZpCf3YC5SZiwtl0zAoGBAJGNnNwD+sDhSscDcLIe\n" +
"qvDh3iPp6DAnLyEtCnItmm7RJcvRCAqltPZLj2hIpLJ4G8XrcxMTkpKkZZGdfcyZ\n" +
"YUDR2E1Gt0mpoQto1w5bQLmwH8SjtDWbWmcqchw/kF03G9MviaypOhGtga8opB3U\n" +
"zuKutN0WoQFw+c5bFuaLGV1fAoGABdFLy+20H0ZApeqRA6QUCb3dAges+GrX9VdQ\n" +
"DrCE5oCfId+mZKJms+F7t7sORk386ZaaUIWqz2xO4e2atnJVKz5LS6rX8AFfQvVQ\n" +
"J41uLND3TeaEW76Jv/amQHqHUTstvBUKV/waleAyJvL5xtkQt//eeUE16BqR0ofx\n" +
"+obFpnECgYEAuDT1vH9JcGhD/iX4qLhS1xS1fXJh4IYvt8bg8oLRyRBqF6x9uhx3\n" +
"6v+WQaKHyGvebWRN+SKAsKQHsh8a7Iy7xZdZmQ8v9j4DcYwJMb7ksV//R2kXAPGL\n" +
"BTfRj1MSI+6AsuVY/YF1O2AfGneP+Zn5bQwYzQkxOYjzF9bhZz3IniE=\n" +
"-----END RSA PRIVATE KEY-----\n";
// Compute the fingerprint by using the following command: ssh-keygen -lf key.pub
String expectedFingerprint = "8f:f1:91:2d:b1:a8:51:f1:79:cf:c4:31:c4:14:9d:81";
assertTrue(SshKeys.privateKeyMatchesPublicKey(privateKey, publicKey));
assertEquals(SshKeys.fingerprintPublicKey(publicKey), expectedFingerprint);
assertEquals(SshKeys.fingerprintPrivateKey(privateKey), expectedFingerprint);
SSHKeyPairClient client = requestSendsResponse(
HttpRequest.builder()
.method("GET")
.endpoint(
URI.create("http://localhost:8080/client/api?response=json&command=registerSSHKeyPair&" +
"name=jclouds-keypair&publickey=" + URLEncoder.encode(publicKey) +
"&apiKey=identity&signature=x6kHcaqhJW%2B7iMV4nLCRkm05AQ4%3D"))
.headers(
ImmutableMultimap.<String, String>builder()
.put("Accept", "application/json")
.build())
.build(),
HttpResponse.builder()
.statusCode(200)
.payload(payloadFromResource("/registersshkeypairresponse.json"))
.build());
SshKeyPair actual = client.registerSSHKeyPair("jclouds-keypair", publicKey);
SshKeyPair expected = SshKeyPair.builder().name("jclouds-keypair")
.fingerprint(expectedFingerprint).build();
assertEquals(actual, expected);
assertEquals(expectedFingerprint, expected.getFingerprint());
}
@Override
protected SSHKeyPairClient clientFrom(CloudStackContext context) {
return context.getProviderSpecificContext().getApi().getSSHKeyPairClient();
}
}

View File

@ -18,17 +18,17 @@
*/ */
package org.jclouds.cloudstack.features; package org.jclouds.cloudstack.features;
import static org.testng.Assert.assertEquals;
import java.util.Map;
import java.util.Set;
import org.jclouds.cloudstack.domain.SshKeyPair; import org.jclouds.cloudstack.domain.SshKeyPair;
import org.jclouds.crypto.SshKeys; import org.jclouds.crypto.SshKeys;
import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.util.Map;
import java.util.Set;
import static org.testng.Assert.assertEquals;
/** /**
* Tests behavior of {@code SSHKeyPairClient} * Tests behavior of {@code SSHKeyPairClient}
* *
@ -47,6 +47,7 @@ public class SSHKeyPairClientLiveTest extends BaseCloudStackClientLiveTest {
client.getSSHKeyPairClient().deleteSSHKeyPair(keyPairName); client.getSSHKeyPairClient().deleteSSHKeyPair(keyPairName);
} }
@Test
public void testListSSHKeyPairs() { public void testListSSHKeyPairs() {
final Set<SshKeyPair> sshKeyPairs = client.getSSHKeyPairClient().listSSHKeyPairs(); final Set<SshKeyPair> sshKeyPairs = client.getSSHKeyPairClient().listSSHKeyPairs();
for (SshKeyPair sshKeyPair : sshKeyPairs) { for (SshKeyPair sshKeyPair : sshKeyPairs) {
@ -54,6 +55,7 @@ public class SSHKeyPairClientLiveTest extends BaseCloudStackClientLiveTest {
} }
} }
@Test
public void testCreateDeleteSSHKeyPair() { public void testCreateDeleteSSHKeyPair() {
sshKeyPair = client.getSSHKeyPairClient().createSSHKeyPair(keyPairName); sshKeyPair = client.getSSHKeyPairClient().createSSHKeyPair(keyPairName);
checkSSHKeyPair(sshKeyPair); checkSSHKeyPair(sshKeyPair);
@ -65,6 +67,7 @@ public class SSHKeyPairClientLiveTest extends BaseCloudStackClientLiveTest {
sshKeyPair = null; sshKeyPair = null;
} }
@Test
public void testRegisterDeleteSSHKeyPair() { public void testRegisterDeleteSSHKeyPair() {
final Map<String, String> sshKey = SshKeys.generate(); final Map<String, String> sshKey = SshKeys.generate();
final String publicKey = sshKey.get("public"); final String publicKey = sshKey.get("public");
@ -74,9 +77,7 @@ public class SSHKeyPairClientLiveTest extends BaseCloudStackClientLiveTest {
client.getSSHKeyPairClient().deleteSSHKeyPair(keyPairName); client.getSSHKeyPairClient().deleteSSHKeyPair(keyPairName);
assertEquals(client.getSSHKeyPairClient().getSSHKeyPair(sshKeyPair.getName()), null); assertEquals(client.getSSHKeyPairClient().getSSHKeyPair(sshKeyPair.getName()), null);
assertEquals(SshKeys.fingerprintPublicKey(publicKey), sshKeyPair.getFingerprint());
//FIXME: somehow the fingerprints aren't matching, so leaving this commented out for now
// assertEquals(SshKeys.fingerprintPublicKey(publicKey), sshKeyPair.getFingerprint());
sshKeyPair = null; sshKeyPair = null;
} }

View File

@ -18,8 +18,9 @@
*/ */
package org.jclouds.cloudstack.parse; package org.jclouds.cloudstack.parse;
import java.util.Set; import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.jclouds.cloudstack.config.CloudStackParserModule; import org.jclouds.cloudstack.config.CloudStackParserModule;
import org.jclouds.cloudstack.domain.SshKeyPair; import org.jclouds.cloudstack.domain.SshKeyPair;
import org.jclouds.json.BaseSetParserTest; import org.jclouds.json.BaseSetParserTest;
@ -27,9 +28,7 @@ import org.jclouds.json.config.GsonModule;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet; import java.util.Set;
import com.google.inject.Guice;
import com.google.inject.Injector;
/** /**
* @author Adrian Cole * @author Adrian Cole
@ -57,10 +56,10 @@ public class ListSSHKeyPairsResponseTest extends BaseSetParserTest<SshKeyPair> {
} }
@Override @Override
@SelectJson("keypair") @SelectJson("sshkeypair")
public Set<SshKeyPair> expected() { public Set<SshKeyPair> expected() {
return ImmutableSet.<SshKeyPair> of(SshKeyPair.builder().name("jclouds-keypair") return ImmutableSet.<SshKeyPair> of(SshKeyPair.builder().name("jclouds-keypair")
.fingerprint("43:6a:bd:46:e0:3d:3a:8d:ab:69:25:bb:b9:ca:9d:17").build()); .fingerprint("1c:06:74:52:3b:99:1c:95:5c:04:c2:f4:ba:77:6e:7b").build());
} }
} }

View File

@ -0,0 +1,4 @@
{ "createsshkeypairresponse" : { "keypair" : {
"name":"jclouds-keypair",
"fingerprint":"1c:06:74:52:3b:99:1c:95:5c:04:c2:f4:ba:77:6e:7b",
"privatekey":"-----BEGIN RSA PRIVATE KEY-----\nMIICXgIBAAKBgQDZo/EF4Ew1uEW0raz7vCs28lBwy0UKV2Xr606gaEgxO7h9mSXZ\n4x2K/KQ1NMnrbjppxGycLh9EKPWAO3ezFULAyuOZW4Fy+xRS8+3MAijxBJY/KBgl\nx5rJm2ILumRkTNkMlLGCSBb9SOqYRN1VpOy7kn3StzU9LdJ/snKVE2JLHQIDAQAB\nAoGBAMnL5okKRd9xcsBqYIAxIuiZmNhcwTErhEdRMOAukPGFbDSYsa3rldLvGdpz\njd2LoQG8rO/LHBZ429kASqZzyiV+NvcgH+tFNJSVAigjSICfhEKF9PY2TiAkrg7S\nGyJgAjpPWQc2sQh0dE8EPEtBiq4ibXfMTDmbs1d/vnfdwtQJAkEA+AX5Y+xgWj74\ndYETmNLyLhNZpftLizEfIYj7lCVhsbFwVb8jbM1m8n8bxwGjls1w/ico1CWcQna+\nUnAfA8kJvwJBAOCj0YgDKpYd0OLQhvI3212J9QcQpJEkDOTYiMwXNHCNMKRpoF47\nMPPX+GG8YzUiQAi9/OG4pDKCjzQWE/ebiiMCQQCssnQ5WICqtggIwYykr9VDseON\nSFIMpHJ5xkjumazRrqx6eDGxc8BH/6uWwRRoT7pqrVeniFyqhsX03u8pkpU/AkBj\nWfCcwBHArNUqy2EzlWKuvwogosq16oTNXbs60HR/5uIBhTnJE1K2NemDiGc0I77A\nXw6N4jS0piuhtLYGB8OTAkEA50abdbduXWcr62Z6E8G/6LNFaNg0uBuVgwSHtJMd\ndNeUtVDHQCHSf3tvxXTAtaB9PCnGOfgm/dyYWEMf3rMoHQ==\n-----END RSA PRIVATE KEY-----\n"} } }

View File

@ -1 +1,2 @@
{ "listsshkeypairsresponse" : { "count":1 ,"keypair" : [ {"name":"jclouds-keypair","fingerprint":"43:6a:bd:46:e0:3d:3a:8d:ab:69:25:bb:b9:ca:9d:17"} ] } } { "listsshkeypairsresponse" : { "count":1 ,"sshkeypair" : [
{"name":"jclouds-keypair","fingerprint":"1c:06:74:52:3b:99:1c:95:5c:04:c2:f4:ba:77:6e:7b"} ] } }

View File

@ -0,0 +1,2 @@
{ "registersshkeypairresponse" : { "keypair" :
{"name":"jclouds-keypair","fingerprint":"2f:4e:95:2f:f3:80:ee:21:72:a8:b4:9c:57:01:0b:3a"} } }