simplified terremark credential handling

This commit is contained in:
Adrian Cole 2011-12-21 02:16:14 -08:00
parent 298e6fa3e4
commit 95753e5695
12 changed files with 144 additions and 228 deletions

View File

@ -25,9 +25,9 @@ import static org.jclouds.trmk.vcloud_0_8.options.AddInternetServiceOptions.Buil
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -35,9 +35,9 @@ import javax.inject.Named;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
@ -70,23 +70,18 @@ public class TerremarkVCloudComputeClient {
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
protected final TerremarkVCloudClient client; protected final TerremarkVCloudClient client;
protected final PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider;
protected final Provider<String> passwordGenerator; protected final Provider<String> passwordGenerator;
protected final Map<String, Credentials> credentialStore;
protected final InternetServiceAndPublicIpAddressSupplier internetServiceAndPublicIpAddressSupplier; protected final InternetServiceAndPublicIpAddressSupplier internetServiceAndPublicIpAddressSupplier;
protected final Map<Status, NodeState> vAppStatusToNodeState; protected final Map<Status, NodeState> vAppStatusToNodeState;
protected final Predicate<URI> taskTester; protected final Predicate<URI> taskTester;
@Inject @Inject
protected TerremarkVCloudComputeClient(TerremarkVCloudClient client, protected TerremarkVCloudComputeClient(TerremarkVCloudClient client,
PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider,
@Named("PASSWORD") Provider<String> passwordGenerator, Predicate<URI> successTester, @Named("PASSWORD") Provider<String> passwordGenerator, Predicate<URI> successTester,
Map<Status, NodeState> vAppStatusToNodeState, Map<String, Credentials> credentialStore, Map<Status, NodeState> vAppStatusToNodeState, Map<String, Credentials> credentialStore,
InternetServiceAndPublicIpAddressSupplier internetServiceAndPublicIpAddressSupplier) { InternetServiceAndPublicIpAddressSupplier internetServiceAndPublicIpAddressSupplier) {
this.client = client; this.client = client;
this.credentialsProvider = credentialsProvider;
this.passwordGenerator = passwordGenerator; this.passwordGenerator = passwordGenerator;
this.credentialStore = credentialStore;
this.internetServiceAndPublicIpAddressSupplier = internetServiceAndPublicIpAddressSupplier; this.internetServiceAndPublicIpAddressSupplier = internetServiceAndPublicIpAddressSupplier;
this.vAppStatusToNodeState = vAppStatusToNodeState; this.vAppStatusToNodeState = vAppStatusToNodeState;
this.taskTester = successTester; this.taskTester = successTester;
@ -95,7 +90,48 @@ public class TerremarkVCloudComputeClient {
protected Status getStatus(VApp vApp) { protected Status getStatus(VApp vApp) {
return vApp.getStatus(); return vApp.getStatus();
} }
public ComputeServiceAdapter.NodeAndInitialCredentials<VApp> startAndReturnCredentials(@Nullable URI VDC, URI templateId, String name, InstantiateVAppTemplateOptions options,
int... portsToOpen) {
// we only get IP addresses after "deploy"
if (portsToOpen.length > 0 && !options.shouldBlock())
throw new IllegalArgumentException("We cannot open ports on terremark unless we can deploy the vapp");
String password = null;
VAppTemplate template = client.getVAppTemplate(templateId);
if (template.getDescription().indexOf("Windows") != -1) {
password = passwordGenerator.get();
options.getProperties().put("password", password);
}
checkNotNull(options, "options");
logger.debug(">> instantiating vApp vDC(%s) template(%s) name(%s) options(%s) ", VDC, templateId, name, options);
VApp vAppResponse = client.instantiateVAppTemplateInVDC(VDC, templateId, name, options);
logger.debug("<< instantiated VApp(%s)", vAppResponse.getName());
if (options.shouldDeploy()) {
logger.debug(">> deploying vApp(%s)", vAppResponse.getName());
Task task = client.deployVApp(vAppResponse.getHref());
if (options.shouldBlock()) {
if (!taskTester.apply(task.getHref())) {
throw new RuntimeException(String.format("failed to %s %s: %s", "deploy", vAppResponse.getName(), task));
}
logger.debug("<< deployed vApp(%s)", vAppResponse.getName());
if (options.shouldPowerOn()) {
logger.debug(">> powering vApp(%s)", vAppResponse.getName());
task = client.powerOnVApp(vAppResponse.getHref());
if (!taskTester.apply(task.getHref())) {
throw new RuntimeException(String.format("failed to %s %s: %s", "powerOn", vAppResponse.getName(),
task));
}
logger.debug("<< on vApp(%s)", vAppResponse.getName());
}
}
}
if (portsToOpen.length > 0)
createPublicAddressMappedToPorts(vAppResponse.getHref(), portsToOpen);
return new ComputeServiceAdapter.NodeAndInitialCredentials<VApp>(vAppResponse, vAppResponse.getHref().toASCIIString(), password!= null?LoginCredentials.builder().password(password).build():null);
}
/** /**
* Runs through all commands necessary to startup a vApp, opening at least * Runs through all commands necessary to startup a vApp, opening at least
* one ip address to the public network. These are the steps: * one ip address to the public network. These are the steps:
@ -125,49 +161,8 @@ public class TerremarkVCloudComputeClient {
* </ol> * </ol>
*/ */
public VApp start(@Nullable URI VDC, URI templateId, String name, InstantiateVAppTemplateOptions options, public VApp start(@Nullable URI VDC, URI templateId, String name, InstantiateVAppTemplateOptions options,
int... portsToOpen) { int... portsToOpen) {
// we only get IP addresses after "deploy" return startAndReturnCredentials(VDC, templateId, name, options, portsToOpen).getNode();
if (portsToOpen.length > 0 && !options.shouldBlock())
throw new IllegalArgumentException("We cannot open ports on terremark unless we can deploy the vapp");
String password = null;
VAppTemplate template = client.getVAppTemplate(templateId);
if (template.getDescription().indexOf("Windows") != -1) {
password = passwordGenerator.get();
options.getProperties().put("password", password);
}
LoginCredentials defaultCredentials = credentialsProvider.apply(template);
checkNotNull(options, "options");
logger.debug(">> instantiating vApp vDC(%s) template(%s) name(%s) options(%s) ", VDC, templateId, name, options);
VApp vAppResponse = client.instantiateVAppTemplateInVDC(VDC, templateId, name, options);
logger.debug("<< instantiated VApp(%s)", vAppResponse.getName());
if (options.shouldDeploy()) {
logger.debug(">> deploying vApp(%s)", vAppResponse.getName());
Task task = client.deployVApp(vAppResponse.getHref());
if (options.shouldBlock()) {
if (!taskTester.apply(task.getHref())) {
throw new RuntimeException(String.format("failed to %s %s: %s", "deploy", vAppResponse.getName(), task));
}
logger.debug("<< deployed vApp(%s)", vAppResponse.getName());
if (options.shouldPowerOn()) {
logger.debug(">> powering vApp(%s)", vAppResponse.getName());
task = client.powerOnVApp(vAppResponse.getHref());
if (!taskTester.apply(task.getHref())) {
throw new RuntimeException(String.format("failed to %s %s: %s", "powerOn", vAppResponse.getName(),
task));
}
logger.debug("<< on vApp(%s)", vAppResponse.getName());
}
}
}
if (password != null) {
credentialStore.put("node#" + vAppResponse.getHref().toASCIIString(), new Credentials(
defaultCredentials.identity, password));
}
if (portsToOpen.length > 0)
createPublicAddressMappedToPorts(vAppResponse.getHref(), portsToOpen);
return vAppResponse;
} }
public String createPublicAddressMappedToPorts(URI vAppId, int... ports) { public String createPublicAddressMappedToPorts(URI vAppId, int... ports) {

View File

@ -20,8 +20,6 @@ package org.jclouds.trmk.vcloud_0_8.compute.config;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -41,7 +39,6 @@ import org.jclouds.rest.internal.RestContextImpl;
import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudAsyncClient; import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudAsyncClient;
import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudClient; import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudClient;
import org.jclouds.trmk.vcloud_0_8.compute.TerremarkVCloudComputeService; import org.jclouds.trmk.vcloud_0_8.compute.TerremarkVCloudComputeService;
import org.jclouds.trmk.vcloud_0_8.compute.domain.KeyPairCredentials;
import org.jclouds.trmk.vcloud_0_8.compute.domain.OrgAndName; import org.jclouds.trmk.vcloud_0_8.compute.domain.OrgAndName;
import org.jclouds.trmk.vcloud_0_8.compute.functions.ImagesInVCloudExpressOrg; import org.jclouds.trmk.vcloud_0_8.compute.functions.ImagesInVCloudExpressOrg;
import org.jclouds.trmk.vcloud_0_8.compute.functions.NodeMetadataToOrgAndName; import org.jclouds.trmk.vcloud_0_8.compute.functions.NodeMetadataToOrgAndName;
@ -126,12 +123,6 @@ public class TerremarkVCloudComputeServiceContextModule extends BaseComputeServi
} }
@Provides
@Singleton
ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap() {
return new ConcurrentHashMap<OrgAndName, KeyPairCredentials>();
}
@Named("PASSWORD") @Named("PASSWORD")
@Provides @Provides
String providePassword(SecureRandom random) { String providePassword(SecureRandom random) {

View File

@ -1,64 +0,0 @@
/**
* 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.trmk.vcloud_0_8.compute.domain;
import org.jclouds.domain.Credentials;
import org.jclouds.trmk.vcloud_0_8.domain.KeyPair;
/**
* @author Adrian Cole
*/
public class KeyPairCredentials extends Credentials {
public static class Builder<T extends KeyPairCredentials> extends Credentials.Builder<T> {
private String identity;
private KeyPair keyPair;
public Builder<T> identity(String identity) {
this.identity = identity;
return this;
}
public Builder<T> keyPair(KeyPair keyPair) {
this.keyPair = keyPair;
return this;
}
@SuppressWarnings("unchecked")
public T build() {
return (T) new KeyPairCredentials(identity, keyPair);
}
}
public KeyPair getKeyPair() {
return keyPair;
}
private final KeyPair keyPair;
public KeyPairCredentials(String identity, KeyPair keyPair) {
super(identity, keyPair.getPrivateKey());
this.keyPair = keyPair;
}
public Builder<? extends KeyPairCredentials> toBuilder() {
return new Builder<KeyPairCredentials>().identity(identity).keyPair(keyPair);
}
}

View File

@ -21,10 +21,8 @@ package org.jclouds.trmk.vcloud_0_8.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName; import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName;
import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -42,8 +40,6 @@ import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.trmk.vcloud_0_8.compute.TerremarkVCloudComputeClient; import org.jclouds.trmk.vcloud_0_8.compute.TerremarkVCloudComputeClient;
import org.jclouds.trmk.vcloud_0_8.compute.domain.KeyPairCredentials;
import org.jclouds.trmk.vcloud_0_8.compute.domain.OrgAndName;
import org.jclouds.trmk.vcloud_0_8.domain.Status; import org.jclouds.trmk.vcloud_0_8.domain.Status;
import org.jclouds.trmk.vcloud_0_8.domain.VApp; import org.jclouds.trmk.vcloud_0_8.domain.VApp;
@ -62,20 +58,17 @@ public class VAppToNodeMetadata implements Function<VApp, NodeMetadata> {
protected final FindLocationForResource findLocationForResourceInVDC; protected final FindLocationForResource findLocationForResourceInVDC;
protected final HardwareForVCloudExpressVApp hardwareForVCloudExpressVApp; protected final HardwareForVCloudExpressVApp hardwareForVCloudExpressVApp;
protected final Map<Status, NodeState> vAppStatusToNodeState; protected final Map<Status, NodeState> vAppStatusToNodeState;
protected final ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap;
@Inject @Inject
protected VAppToNodeMetadata(TerremarkVCloudComputeClient computeClient, Map<String, Credentials> credentialStore, protected VAppToNodeMetadata(TerremarkVCloudComputeClient computeClient, Map<String, Credentials> credentialStore,
Map<Status, NodeState> vAppStatusToNodeState, HardwareForVCloudExpressVApp hardwareForVCloudExpressVApp, Map<Status, NodeState> vAppStatusToNodeState, HardwareForVCloudExpressVApp hardwareForVCloudExpressVApp,
FindLocationForResource findLocationForResourceInVDC, @Memoized Supplier<Set<? extends Image>> images, FindLocationForResource findLocationForResourceInVDC, @Memoized Supplier<Set<? extends Image>> images) {
ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap) {
this.images = checkNotNull(images, "images"); this.images = checkNotNull(images, "images");
this.hardwareForVCloudExpressVApp = checkNotNull(hardwareForVCloudExpressVApp, "hardwareForVCloudExpressVApp"); this.hardwareForVCloudExpressVApp = checkNotNull(hardwareForVCloudExpressVApp, "hardwareForVCloudExpressVApp");
this.findLocationForResourceInVDC = checkNotNull(findLocationForResourceInVDC, "findLocationForResourceInVDC"); this.findLocationForResourceInVDC = checkNotNull(findLocationForResourceInVDC, "findLocationForResourceInVDC");
this.credentialStore = checkNotNull(credentialStore, "credentialStore"); this.credentialStore = checkNotNull(credentialStore, "credentialStore");
this.computeClient = checkNotNull(computeClient, "computeClient"); this.computeClient = checkNotNull(computeClient, "computeClient");
this.vAppStatusToNodeState = checkNotNull(vAppStatusToNodeState, "vAppStatusToNodeState"); this.vAppStatusToNodeState = checkNotNull(vAppStatusToNodeState, "vAppStatusToNodeState");
this.credentialsMap = checkNotNull(credentialsMap, "credentialsMap");
} }
@Override @Override
@ -106,18 +99,8 @@ public class VAppToNodeMetadata implements Function<VApp, NodeMetadata> {
builder.privateAddresses(computeClient.getPrivateAddresses(from.getHref())); builder.privateAddresses(computeClient.getPrivateAddresses(from.getHref()));
String group = parseGroupFromName(from.getName()); String group = parseGroupFromName(from.getName());
builder.group(group); builder.group(group);
builder.credentials(LoginCredentials.fromCredentials(credentialStore
// node-specific credentials override those from cache based on group .get("node#" + from.getHref().toASCIIString())));
if (group != null && !credentialStore.containsKey("node#" + from.getHref().toASCIIString())) {
OrgAndName orgAndName = new OrgAndName(URI.create(vdcLocation.getParent().getId()), group);
if (credentialsMap.containsKey(orgAndName)) {
builder.credentials(LoginCredentials.builder(credentialsMap.get(orgAndName)).build());
}
} else {
builder.credentials(LoginCredentials.builder(credentialStore.get("node#" + from.getHref().toASCIIString()))
.build());
}
return builder.build(); return builder.build();
} }
} }

View File

@ -69,8 +69,9 @@ public class CleanupOrphanKeys {
Iterable<? extends NodeMetadata> nodesInOrg = listNodes.listDetailsOnNodesMatching(parentLocationId(orgGroup Iterable<? extends NodeMetadata> nodesInOrg = listNodes.listDetailsOnNodesMatching(parentLocationId(orgGroup
.getOrg().toASCIIString())); .getOrg().toASCIIString()));
Iterable<? extends NodeMetadata> nodesInGroup = filter(nodesInOrg, inGroup(orgGroup.getName())); Iterable<? extends NodeMetadata> nodesInGroup = filter(nodesInOrg, inGroup(orgGroup.getName()));
if (size(nodesInGroup) == 0 || all(nodesInGroup, TERMINATED)) if (size(nodesInGroup) == 0 || all(nodesInGroup, TERMINATED)){
deleteKeyPair.execute(orgGroup); deleteKeyPair.execute(orgGroup);
}
} }
} }

View File

@ -18,13 +18,17 @@
*/ */
package org.jclouds.trmk.vcloud_0_8.compute.strategy; package org.jclouds.trmk.vcloud_0_8.compute.strategy;
import static com.google.common.base.Preconditions.checkState;
import java.net.URI; import java.net.URI;
import java.util.concurrent.ConcurrentMap; import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.trmk.vcloud_0_8.compute.domain.KeyPairCredentials; import org.jclouds.crypto.SshKeys;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.trmk.vcloud_0_8.compute.domain.OrgAndName; import org.jclouds.trmk.vcloud_0_8.compute.domain.OrgAndName;
import org.jclouds.trmk.vcloud_0_8.compute.functions.CreateUniqueKeyPair; import org.jclouds.trmk.vcloud_0_8.compute.functions.CreateUniqueKeyPair;
import org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplateOptions; import org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplateOptions;
@ -39,30 +43,41 @@ import com.google.common.annotations.VisibleForTesting;
*/ */
@Singleton @Singleton
public class CreateNewKeyPairUnlessUserSpecifiedOtherwise { public class CreateNewKeyPairUnlessUserSpecifiedOtherwise {
final ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap; final Map<String, Credentials> credentialStore;
@VisibleForTesting @VisibleForTesting
final CreateUniqueKeyPair createUniqueKeyPair; final CreateUniqueKeyPair createUniqueKeyPair;
@Inject @Inject
CreateNewKeyPairUnlessUserSpecifiedOtherwise(ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap, CreateNewKeyPairUnlessUserSpecifiedOtherwise(Map<String, Credentials> credentialStore,
CreateUniqueKeyPair createUniqueKeyPair) { CreateUniqueKeyPair createUniqueKeyPair) {
this.credentialsMap = credentialsMap; this.credentialStore = credentialStore;
this.createUniqueKeyPair = createUniqueKeyPair; this.createUniqueKeyPair = createUniqueKeyPair;
} }
@VisibleForTesting @VisibleForTesting
public void execute(URI org, String tag, String identity, TerremarkVCloudTemplateOptions options) { public void execute(URI org, String group, String identity, TerremarkVCloudTemplateOptions options) {
String sshKeyFingerprint = options.getSshKeyFingerprint(); String sshKeyFingerprint = options.getSshKeyFingerprint();
boolean shouldAutomaticallyCreateKeyPair = options.shouldAutomaticallyCreateKeyPair(); boolean shouldAutomaticallyCreateKeyPair = options.shouldAutomaticallyCreateKeyPair();
if (sshKeyFingerprint == null && shouldAutomaticallyCreateKeyPair) { if (sshKeyFingerprint == null && shouldAutomaticallyCreateKeyPair) {
OrgAndName orgAndName = new OrgAndName(org, tag);
if (credentialsMap.containsKey(orgAndName)) { // make sure that we don't request multiple keys simultaneously
options.sshKeyFingerprint(credentialsMap.get(orgAndName).getKeyPair().getFingerPrint()); synchronized (credentialStore) {
} else { // if there is already a keypair for the group specified, use it
KeyPair keyPair = createUniqueKeyPair.apply(orgAndName); if (credentialStore.containsKey("group#" + group)) {
credentialsMap.put(orgAndName, new KeyPairCredentials(identity, keyPair)); LoginCredentials creds = LoginCredentials.fromCredentials(credentialStore.get("group#" + group));
options.sshKeyFingerprint(keyPair.getFingerPrint()); checkState(creds.getOptionalPrivateKey().isPresent(),
"incorrect state: should have private key for: %s", creds);
options.sshKeyFingerprint(SshKeys.fingerprintPrivateKey(creds.getPrivateKey()));
} else {
// otherwise create a new keypair and key it under the group
KeyPair keyPair = createUniqueKeyPair.apply(new OrgAndName(org, group));
credentialStore.put("group#" + group, LoginCredentials.builder().user(identity).privateKey(
keyPair.getPrivateKey()).build());
options.sshKeyFingerprint(keyPair.getFingerPrint());
}
} }
} }
} }
} }

View File

@ -18,7 +18,7 @@
*/ */
package org.jclouds.trmk.vcloud_0_8.compute.strategy; package org.jclouds.trmk.vcloud_0_8.compute.strategy;
import java.util.concurrent.ConcurrentMap; import java.util.Map;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -26,9 +26,9 @@ import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Credentials;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudClient; import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudClient;
import org.jclouds.trmk.vcloud_0_8.compute.domain.KeyPairCredentials;
import org.jclouds.trmk.vcloud_0_8.compute.domain.OrgAndName; import org.jclouds.trmk.vcloud_0_8.compute.domain.OrgAndName;
import org.jclouds.trmk.vcloud_0_8.domain.KeyPair; import org.jclouds.trmk.vcloud_0_8.domain.KeyPair;
@ -44,12 +44,12 @@ public class DeleteKeyPair {
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
final TerremarkVCloudClient terremarkClient; final TerremarkVCloudClient terremarkClient;
final ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap; final Map<String, Credentials> credentialStore;
@Inject @Inject
DeleteKeyPair(TerremarkVCloudClient terremarkClient, ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap) { DeleteKeyPair(TerremarkVCloudClient terremarkClient, Map<String, Credentials> credentialStore) {
this.terremarkClient = terremarkClient; this.terremarkClient = terremarkClient;
this.credentialsMap = credentialsMap; this.credentialStore = credentialStore;
} }
public void execute(OrgAndName orgTag) { public void execute(OrgAndName orgTag) {
@ -57,9 +57,8 @@ public class DeleteKeyPair {
if (keyPair.getName().matches("jclouds_" + orgTag.getName().replaceAll("-", "_") + "_[0-9a-f]+")) { if (keyPair.getName().matches("jclouds_" + orgTag.getName().replaceAll("-", "_") + "_[0-9a-f]+")) {
logger.debug(">> deleting keyPair(%s)", keyPair.getName()); logger.debug(">> deleting keyPair(%s)", keyPair.getName());
terremarkClient.deleteKeyPair(keyPair.getId()); terremarkClient.deleteKeyPair(keyPair.getId());
// TODO: test this clear happens
credentialsMap.remove(orgTag);
logger.debug("<< deleted keyPair(%s)", keyPair.getName()); logger.debug("<< deleted keyPair(%s)", keyPair.getName());
credentialStore.remove("group#" + orgTag.getName());
} }
} }
} }

View File

@ -26,11 +26,13 @@ import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName; import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.trmk.vcloud_0_8.compute.TerremarkVCloudComputeClient; import org.jclouds.trmk.vcloud_0_8.compute.TerremarkVCloudComputeClient;
import org.jclouds.trmk.vcloud_0_8.compute.functions.TemplateToInstantiateOptions; import org.jclouds.trmk.vcloud_0_8.compute.functions.TemplateToInstantiateOptions;
import org.jclouds.trmk.vcloud_0_8.domain.VApp; import org.jclouds.trmk.vcloud_0_8.domain.VApp;
@ -46,28 +48,34 @@ public class StartVAppWithGroupEncodedIntoName implements CreateNodeWithGroupEnc
protected final TerremarkVCloudComputeClient computeClient; protected final TerremarkVCloudComputeClient computeClient;
protected final TemplateToInstantiateOptions getOptions; protected final TemplateToInstantiateOptions getOptions;
protected final Function<VApp, NodeMetadata> vAppToNodeMetadata; protected final Function<VApp, NodeMetadata> vAppToNodeMetadata;
private final Map<String, Credentials> credentialStore; protected final Map<String, Credentials> credentialStore;
protected final PrioritizeCredentialsFromTemplate prioritizeCredentialsFromTemplate;
@Inject @Inject
protected StartVAppWithGroupEncodedIntoName(TerremarkVCloudComputeClient computeClient, protected StartVAppWithGroupEncodedIntoName(TerremarkVCloudComputeClient computeClient,
Function<VApp, NodeMetadata> vAppToNodeMetadata, TemplateToInstantiateOptions getOptions, Function<VApp, NodeMetadata> vAppToNodeMetadata, TemplateToInstantiateOptions getOptions,
Map<String, Credentials> credentialStore) { Map<String, Credentials> credentialStore, PrioritizeCredentialsFromTemplate prioritizeCredentialsFromTemplate) {
this.computeClient = computeClient; this.computeClient = computeClient;
this.vAppToNodeMetadata = vAppToNodeMetadata; this.vAppToNodeMetadata = vAppToNodeMetadata;
this.getOptions = checkNotNull(getOptions, "getOptions"); this.getOptions = checkNotNull(getOptions, "getOptions");
this.credentialStore = checkNotNull(credentialStore, "credentialStore"); this.credentialStore = checkNotNull(credentialStore, "credentialStore");
this.prioritizeCredentialsFromTemplate = checkNotNull(prioritizeCredentialsFromTemplate, "prioritizeCredentialsFromTemplate");
} }
@Override @Override
public NodeMetadata createNodeWithGroupEncodedIntoName(String group, String name, Template template) { public NodeMetadata createNodeWithGroupEncodedIntoName(String group, String name, Template template) {
InstantiateVAppTemplateOptions options = getOptions.apply(template); InstantiateVAppTemplateOptions options = getOptions.apply(template);
VApp vApp = computeClient.start(URI.create(template.getLocation().getId()), URI.create(template NodeAndInitialCredentials<VApp> from = computeClient.startAndReturnCredentials(URI.create(template.getLocation().getId()), URI.create(template
.getImage().getId()), name, options, template.getOptions().getInboundPorts()); .getImage().getId()), name, options, template.getOptions().getInboundPorts());
NodeMetadata node = vAppToNodeMetadata.apply(vApp); LoginCredentials fromNode = from.getCredentials();
NodeMetadataBuilder builder = NodeMetadataBuilder.fromNodeMetadata(node); if (credentialStore.containsKey("group#" + group)) {
if (template.getImage().getDefaultCredentials() != null) fromNode = fromNode == null ? LoginCredentials.fromCredentials(credentialStore.get("group#" + group))
credentialStore.put("node#" + node.getId(), template.getImage().getDefaultCredentials()); : fromNode.toBuilder().privateKey(credentialStore.get("group#" + group).credential).build();
return builder.build(); }
LoginCredentials creds = prioritizeCredentialsFromTemplate.apply(template, fromNode);
if (creds != null)
credentialStore.put("node#" + from.getNodeId(), creds);
return vAppToNodeMetadata.apply(from.getNode());
} }
} }

View File

@ -31,10 +31,11 @@ import java.util.Map;
import javax.inject.Provider; import javax.inject.Provider;
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudClient; import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudClient;
import org.jclouds.trmk.vcloud_0_8.compute.strategy.ParseVAppTemplateDescriptionToGetDefaultLoginCredentials;
import org.jclouds.trmk.vcloud_0_8.domain.Status; import org.jclouds.trmk.vcloud_0_8.domain.Status;
import org.jclouds.trmk.vcloud_0_8.domain.Task; import org.jclouds.trmk.vcloud_0_8.domain.Task;
import org.jclouds.trmk.vcloud_0_8.domain.VApp; import org.jclouds.trmk.vcloud_0_8.domain.VApp;
@ -88,7 +89,7 @@ public class TerremarkVCloudComputeClientTest {
Map<Status, NodeState> vAppStatusToNodeState = createMock(Map.class); Map<Status, NodeState> vAppStatusToNodeState = createMock(Map.class);
TerremarkVCloudComputeClient computeClient = new TerremarkVCloudComputeClient(client, TerremarkVCloudComputeClient computeClient = new TerremarkVCloudComputeClient(client,
new ParseVAppTemplateDescriptionToGetDefaultLoginCredentials(null), new Provider<String>() { new Provider<String>() {
@Override @Override
public String get() { public String get() {
@ -106,10 +107,11 @@ public class TerremarkVCloudComputeClientTest {
replay(notFoundTester); replay(notFoundTester);
replay(vAppStatusToNodeState); replay(vAppStatusToNodeState);
VApp response = computeClient.start(vdcURI, templateURI, "name", new InstantiateVAppTemplateOptions()); NodeAndInitialCredentials<VApp> response = computeClient.startAndReturnCredentials(vdcURI, templateURI, "name", new InstantiateVAppTemplateOptions());
assertEquals(response.getHref().toASCIIString(), "vapp"); assertEquals(response.getNodeId(), "vapp");
assertEquals(credentialStore.get("node#vapp"), new Credentials("Administrator", "password")); assertEquals(response.getNode(),vApp);
assertEquals(response.getCredentials(), LoginCredentials.builder().password("password").build());
verify(vdc); verify(vdc);
verify(template); verify(template);

View File

@ -140,9 +140,8 @@ public class CleanupOrphanKeysTest {
} }
private void expectCleanupCredentialStore(CleanupOrphanKeys strategy, NodeMetadata nodeMetadata) { private void expectCleanupCredentialStore(CleanupOrphanKeys strategy, NodeMetadata nodeMetadata) {
expect("node#" + nodeMetadata.getId()).andReturn("1").times(2); expect("node#" + nodeMetadata.getId()).andReturn("1");
expect(strategy.credentialStore.remove("node#1")).andReturn(null); expect(strategy.credentialStore.remove("node#1")).andReturn(null);
expect(strategy.credentialStore.remove("node#1#adminPassword")).andReturn(null);
} }
public void testWhenNoneLeftWithTag() { public void testWhenNoneLeftWithTag() {

View File

@ -27,14 +27,16 @@ import static org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplat
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.net.URI; import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import org.jclouds.trmk.vcloud_0_8.compute.domain.KeyPairCredentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.trmk.vcloud_0_8.compute.domain.OrgAndName; import org.jclouds.trmk.vcloud_0_8.compute.domain.OrgAndName;
import org.jclouds.trmk.vcloud_0_8.compute.functions.CreateUniqueKeyPair; import org.jclouds.trmk.vcloud_0_8.compute.functions.CreateUniqueKeyPair;
import org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplateOptions; import org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplateOptions;
import org.jclouds.trmk.vcloud_0_8.compute.strategy.CreateNewKeyPairUnlessUserSpecifiedOtherwise;
import org.jclouds.trmk.vcloud_0_8.domain.KeyPair; import org.jclouds.trmk.vcloud_0_8.domain.KeyPair;
import org.jclouds.trmk.vcloud_0_8.xml.KeyPairHandlerTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
@ -47,34 +49,25 @@ public class CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest {
// setup constants // setup constants
URI org = URI.create("org1"); URI org = URI.create("org1");
String identity = "identity"; String identity = "identity";
String tag = "tag"; String group = "group";
OrgAndName orgAndName = new OrgAndName(org, "tag");
String systemGeneratedFingerprint = "systemGeneratedKeyPairfinger";
TerremarkVCloudTemplateOptions options = new TerremarkVCloudTemplateOptions(); TerremarkVCloudTemplateOptions options = new TerremarkVCloudTemplateOptions();
// create mocks // create mocks
CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy = setupStrategy(); CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy = setupStrategy();
KeyPairCredentials keyPairCredentials = createMock(KeyPairCredentials.class); LoginCredentials keyPairCredentials = LoginCredentials.builder().privateKey(KeyPairHandlerTest.keyPair.getPrivateKey()).build();
KeyPair keyPair = createMock(KeyPair.class);
// setup expectations // setup expectations
expect(strategy.credentialsMap.containsKey(orgAndName)).andReturn(true); expect(strategy.credentialStore.containsKey("group#group")).andReturn(true);
expect(strategy.credentialsMap.get(orgAndName)).andReturn(keyPairCredentials); expect(strategy.credentialStore.get("group#group")).andReturn(keyPairCredentials);
expect(keyPairCredentials.getKeyPair()).andReturn(keyPair);
expect(keyPair.getFingerPrint()).andReturn(systemGeneratedFingerprint).atLeastOnce();
// replay mocks // replay mocks
replay(keyPair);
replay(keyPairCredentials);
replayStrategy(strategy); replayStrategy(strategy);
// run // run
strategy.execute(org, tag, identity, options); strategy.execute(org, group, identity, options);
assertEquals(options.getSshKeyFingerprint(), "systemGeneratedKeyPairfinger"); assertEquals(options.getSshKeyFingerprint(), KeyPairHandlerTest.keyPair.getFingerPrint());
// verify mocks // verify mocks
verify(keyPair);
verify(keyPairCredentials);
verifyStrategy(strategy); verifyStrategy(strategy);
} }
@ -82,7 +75,7 @@ public class CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest {
// setup constants // setup constants
URI org = URI.create("org1"); URI org = URI.create("org1");
String identity = "identity"; String identity = "identity";
String tag = "tag"; String group = "group";
TerremarkVCloudTemplateOptions options = sshKeyFingerprint("fingerprintFromUser"); TerremarkVCloudTemplateOptions options = sshKeyFingerprint("fingerprintFromUser");
// create mocks // create mocks
@ -94,7 +87,7 @@ public class CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest {
replayStrategy(strategy); replayStrategy(strategy);
// run // run
strategy.execute(org, tag, identity, options); strategy.execute(org, group, identity, options);
assertEquals(options.getSshKeyFingerprint(), "fingerprintFromUser"); assertEquals(options.getSshKeyFingerprint(), "fingerprintFromUser");
// verify mocks // verify mocks
@ -108,30 +101,27 @@ public class CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest {
// setup constants // setup constants
URI org = URI.create("org1"); URI org = URI.create("org1");
String identity = "identity"; String identity = "identity";
String tag = "tag"; String group = "group";
String systemGeneratedFingerprint = "systemGeneratedKeyPairfinger"; String systemGeneratedFingerprint = "systemGeneratedKeyPairfinger";
String privateKey = "privateKey";
TerremarkVCloudTemplateOptions options = new TerremarkVCloudTemplateOptions(); TerremarkVCloudTemplateOptions options = new TerremarkVCloudTemplateOptions();
OrgAndName orgAndName = new OrgAndName(org, "tag");
// create mocks // create mocks
CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy = setupStrategy(); CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy = setupStrategy();
KeyPairCredentials keyPairCredentials = createMock(KeyPairCredentials.class); LoginCredentials keyPairCredentials = LoginCredentials.builder().privateKey(KeyPairHandlerTest.keyPair.getPrivateKey()).build();
KeyPair keyPair = createMock(KeyPair.class); KeyPair keyPair = createMock(KeyPair.class);
// setup expectations // setup expectations
expect(strategy.credentialsMap.containsKey(orgAndName)).andReturn(false); expect(strategy.credentialStore.containsKey("group#group")).andReturn(false);
expect(strategy.createUniqueKeyPair.apply(orgAndName)).andReturn(keyPair); expect(strategy.createUniqueKeyPair.apply(new OrgAndName(org, "group"))).andReturn(keyPair);
expect(keyPair.getFingerPrint()).andReturn(systemGeneratedFingerprint).atLeastOnce(); expect(keyPair.getFingerPrint()).andReturn(KeyPairHandlerTest.keyPair.getFingerPrint()).atLeastOnce();
expect(keyPair.getPrivateKey()).andReturn(privateKey).atLeastOnce(); expect(strategy.credentialStore.put("group#group", keyPairCredentials)).andReturn(null);
expect(strategy.credentialsMap.put(orgAndName, keyPairCredentials)).andReturn(null);
// replay mocks // replay mocks
replay(keyPair); replay(keyPair);
replayStrategy(strategy); replayStrategy(strategy);
// run // run
strategy.execute(org, tag, identity, options); strategy.execute(org, group, identity, options);
assertEquals(options.getSshKeyFingerprint(), systemGeneratedFingerprint); assertEquals(options.getSshKeyFingerprint(), systemGeneratedFingerprint);
// verify mocks // verify mocks
@ -143,43 +133,40 @@ public class CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest {
// setup constants // setup constants
URI org = URI.create("org1"); URI org = URI.create("org1");
String identity = "identity"; String identity = "identity";
String tag = "tag"; String group = "group";
TerremarkVCloudTemplateOptions options = noKeyPair(); TerremarkVCloudTemplateOptions options = noKeyPair();
// create mocks // create mocks
CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy = setupStrategy(); CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy = setupStrategy();
KeyPair keyPair = createMock(KeyPair.class);
// setup expectations // setup expectations
// replay mocks // replay mocks
replay(keyPair);
replayStrategy(strategy); replayStrategy(strategy);
// run // run
strategy.execute(org, tag, identity, options); strategy.execute(org, group, identity, options);
assertEquals(options.getSshKeyFingerprint(), null); assertEquals(options.getSshKeyFingerprint(), null);
// verify mocks // verify mocks
verify(keyPair);
verifyStrategy(strategy); verifyStrategy(strategy);
} }
private void verifyStrategy(CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy) { private void verifyStrategy(CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy) {
verify(strategy.credentialsMap); verify(strategy.credentialStore);
verify(strategy.createUniqueKeyPair); verify(strategy.createUniqueKeyPair);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private CreateNewKeyPairUnlessUserSpecifiedOtherwise setupStrategy() { private CreateNewKeyPairUnlessUserSpecifiedOtherwise setupStrategy() {
ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap = createMock(ConcurrentMap.class); Map<String, Credentials> credentialStore = createMock(ConcurrentMap.class);
CreateUniqueKeyPair createUniqueKeyPair = createMock(CreateUniqueKeyPair.class); CreateUniqueKeyPair createUniqueKeyPair = createMock(CreateUniqueKeyPair.class);
return new CreateNewKeyPairUnlessUserSpecifiedOtherwise(credentialsMap, createUniqueKeyPair); return new CreateNewKeyPairUnlessUserSpecifiedOtherwise(credentialStore, createUniqueKeyPair);
} }
private void replayStrategy(CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy) { private void replayStrategy(CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy) {
replay(strategy.credentialsMap); replay(strategy.credentialStore);
replay(strategy.createUniqueKeyPair); replay(strategy.createUniqueKeyPair);
} }

View File

@ -24,12 +24,12 @@ import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify; import static org.easymock.classextension.EasyMock.verify;
import java.net.URI; import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import org.jclouds.domain.Credentials;
import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudClient; import org.jclouds.trmk.vcloud_0_8.TerremarkVCloudClient;
import org.jclouds.trmk.vcloud_0_8.compute.domain.KeyPairCredentials;
import org.jclouds.trmk.vcloud_0_8.compute.domain.OrgAndName; import org.jclouds.trmk.vcloud_0_8.compute.domain.OrgAndName;
import org.jclouds.trmk.vcloud_0_8.compute.strategy.DeleteKeyPair;
import org.jclouds.trmk.vcloud_0_8.domain.KeyPair; import org.jclouds.trmk.vcloud_0_8.domain.KeyPair;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -78,7 +78,7 @@ public class DeleteKeyPairTest {
expect(keyPair.getName()).andReturn("jclouds_" + orgTag.getName() + "_123").atLeastOnce(); expect(keyPair.getName()).andReturn("jclouds_" + orgTag.getName() + "_123").atLeastOnce();
expect(keyPair.getId()).andReturn(URI.create("1245")); expect(keyPair.getId()).andReturn(URI.create("1245"));
strategy.terremarkClient.deleteKeyPair(URI.create("1245")); strategy.terremarkClient.deleteKeyPair(URI.create("1245"));
expect(strategy.credentialsMap.remove(orgTag)).andReturn(null); expect(strategy.credentialStore.remove("group#tag")).andReturn(null);
// replay mocks // replay mocks
replay(keyPair); replay(keyPair);
@ -119,20 +119,20 @@ public class DeleteKeyPairTest {
} }
private void verifyStrategy(DeleteKeyPair strategy) { private void verifyStrategy(DeleteKeyPair strategy) {
verify(strategy.credentialsMap); verify(strategy.credentialStore);
verify(strategy.terremarkClient); verify(strategy.terremarkClient);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private DeleteKeyPair setupStrategy() { private DeleteKeyPair setupStrategy() {
ConcurrentMap<OrgAndName, KeyPairCredentials> credentialsMap = createMock(ConcurrentMap.class); Map<String, Credentials> credentialStore = createMock(ConcurrentMap.class);
TerremarkVCloudClient terremarkClient = createMock(TerremarkVCloudClient.class); TerremarkVCloudClient terremarkClient = createMock(TerremarkVCloudClient.class);
return new DeleteKeyPair(terremarkClient, credentialsMap); return new DeleteKeyPair(terremarkClient, credentialStore);
} }
private void replayStrategy(DeleteKeyPair strategy) { private void replayStrategy(DeleteKeyPair strategy) {
replay(strategy.credentialsMap); replay(strategy.credentialStore);
replay(strategy.terremarkClient); replay(strategy.terremarkClient);
} }