diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeClient.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeClient.java index 7a229b37f1..e17206d096 100644 --- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeClient.java +++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeClient.java @@ -25,9 +25,9 @@ import static org.jclouds.trmk.vcloud_0_8.options.AddInternetServiceOptions.Buil import java.net.URI; import java.util.Map; -import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Set; +import java.util.Map.Entry; import javax.annotation.Resource; import javax.inject.Inject; @@ -35,9 +35,9 @@ import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; +import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.reference.ComputeServiceConstants; -import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy; import org.jclouds.domain.Credentials; import org.jclouds.domain.LoginCredentials; import org.jclouds.javax.annotation.Nullable; @@ -70,23 +70,18 @@ public class TerremarkVCloudComputeClient { protected Logger logger = Logger.NULL; protected final TerremarkVCloudClient client; - protected final PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider; protected final Provider passwordGenerator; - protected final Map credentialStore; protected final InternetServiceAndPublicIpAddressSupplier internetServiceAndPublicIpAddressSupplier; protected final Map vAppStatusToNodeState; protected final Predicate taskTester; @Inject protected TerremarkVCloudComputeClient(TerremarkVCloudClient client, - PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider, @Named("PASSWORD") Provider passwordGenerator, Predicate successTester, Map vAppStatusToNodeState, Map credentialStore, InternetServiceAndPublicIpAddressSupplier internetServiceAndPublicIpAddressSupplier) { this.client = client; - this.credentialsProvider = credentialsProvider; this.passwordGenerator = passwordGenerator; - this.credentialStore = credentialStore; this.internetServiceAndPublicIpAddressSupplier = internetServiceAndPublicIpAddressSupplier; this.vAppStatusToNodeState = vAppStatusToNodeState; this.taskTester = successTester; @@ -95,7 +90,48 @@ public class TerremarkVCloudComputeClient { protected Status getStatus(VApp vApp) { return vApp.getStatus(); } + + public ComputeServiceAdapter.NodeAndInitialCredentials 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(vAppResponse, vAppResponse.getHref().toASCIIString(), password!= null?LoginCredentials.builder().password(password).build():null); + } + /** * Runs through all commands necessary to startup a vApp, opening at least * one ip address to the public network. These are the steps: @@ -125,49 +161,8 @@ public class TerremarkVCloudComputeClient { * */ public VApp start(@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); - } - 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; + int... portsToOpen) { + return startAndReturnCredentials(VDC, templateId, name, options, portsToOpen).getNode(); } public String createPublicAddressMappedToPorts(URI vAppId, int... ports) { diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/config/TerremarkVCloudComputeServiceContextModule.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/config/TerremarkVCloudComputeServiceContextModule.java index 77b35b18a9..441b64779c 100644 --- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/config/TerremarkVCloudComputeServiceContextModule.java +++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/config/TerremarkVCloudComputeServiceContextModule.java @@ -20,8 +20,6 @@ package org.jclouds.trmk.vcloud_0_8.compute.config; import java.security.SecureRandom; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import javax.inject.Named; 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.TerremarkVCloudClient; 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.functions.ImagesInVCloudExpressOrg; import org.jclouds.trmk.vcloud_0_8.compute.functions.NodeMetadataToOrgAndName; @@ -126,12 +123,6 @@ public class TerremarkVCloudComputeServiceContextModule extends BaseComputeServi } - @Provides - @Singleton - ConcurrentMap credentialsMap() { - return new ConcurrentHashMap(); - } - @Named("PASSWORD") @Provides String providePassword(SecureRandom random) { diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/domain/KeyPairCredentials.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/domain/KeyPairCredentials.java deleted file mode 100644 index d25d2197ea..0000000000 --- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/domain/KeyPairCredentials.java +++ /dev/null @@ -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 extends Credentials.Builder { - private String identity; - private KeyPair keyPair; - - public Builder identity(String identity) { - this.identity = identity; - return this; - } - - public Builder 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 toBuilder() { - return new Builder().identity(identity).keyPair(keyPair); - } - -} \ No newline at end of file diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/functions/VAppToNodeMetadata.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/functions/VAppToNodeMetadata.java index 4f8b499491..a49924e044 100644 --- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/functions/VAppToNodeMetadata.java +++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/functions/VAppToNodeMetadata.java @@ -21,10 +21,8 @@ package org.jclouds.trmk.vcloud_0_8.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName; -import java.net.URI; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentMap; import javax.inject.Inject; import javax.inject.Singleton; @@ -42,8 +40,6 @@ import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; import org.jclouds.domain.LoginCredentials; 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.VApp; @@ -62,20 +58,17 @@ public class VAppToNodeMetadata implements Function { protected final FindLocationForResource findLocationForResourceInVDC; protected final HardwareForVCloudExpressVApp hardwareForVCloudExpressVApp; protected final Map vAppStatusToNodeState; - protected final ConcurrentMap credentialsMap; @Inject protected VAppToNodeMetadata(TerremarkVCloudComputeClient computeClient, Map credentialStore, Map vAppStatusToNodeState, HardwareForVCloudExpressVApp hardwareForVCloudExpressVApp, - FindLocationForResource findLocationForResourceInVDC, @Memoized Supplier> images, - ConcurrentMap credentialsMap) { + FindLocationForResource findLocationForResourceInVDC, @Memoized Supplier> images) { this.images = checkNotNull(images, "images"); this.hardwareForVCloudExpressVApp = checkNotNull(hardwareForVCloudExpressVApp, "hardwareForVCloudExpressVApp"); this.findLocationForResourceInVDC = checkNotNull(findLocationForResourceInVDC, "findLocationForResourceInVDC"); this.credentialStore = checkNotNull(credentialStore, "credentialStore"); this.computeClient = checkNotNull(computeClient, "computeClient"); this.vAppStatusToNodeState = checkNotNull(vAppStatusToNodeState, "vAppStatusToNodeState"); - this.credentialsMap = checkNotNull(credentialsMap, "credentialsMap"); } @Override @@ -106,18 +99,8 @@ public class VAppToNodeMetadata implements Function { builder.privateAddresses(computeClient.getPrivateAddresses(from.getHref())); String group = parseGroupFromName(from.getName()); builder.group(group); - - // node-specific credentials override those from cache based on group - 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()); - } - + builder.credentials(LoginCredentials.fromCredentials(credentialStore + .get("node#" + from.getHref().toASCIIString()))); return builder.build(); } } \ No newline at end of file diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CleanupOrphanKeys.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CleanupOrphanKeys.java index b3797f9bdd..b1605fb61a 100644 --- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CleanupOrphanKeys.java +++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CleanupOrphanKeys.java @@ -69,8 +69,9 @@ public class CleanupOrphanKeys { Iterable nodesInOrg = listNodes.listDetailsOnNodesMatching(parentLocationId(orgGroup .getOrg().toASCIIString())); Iterable nodesInGroup = filter(nodesInOrg, inGroup(orgGroup.getName())); - if (size(nodesInGroup) == 0 || all(nodesInGroup, TERMINATED)) + if (size(nodesInGroup) == 0 || all(nodesInGroup, TERMINATED)){ deleteKeyPair.execute(orgGroup); + } } } diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CreateNewKeyPairUnlessUserSpecifiedOtherwise.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CreateNewKeyPairUnlessUserSpecifiedOtherwise.java index f3fc506994..1ef94f9bd0 100644 --- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CreateNewKeyPairUnlessUserSpecifiedOtherwise.java +++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CreateNewKeyPairUnlessUserSpecifiedOtherwise.java @@ -18,13 +18,17 @@ */ package org.jclouds.trmk.vcloud_0_8.compute.strategy; +import static com.google.common.base.Preconditions.checkState; + import java.net.URI; -import java.util.concurrent.ConcurrentMap; +import java.util.Map; import javax.inject.Inject; 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.functions.CreateUniqueKeyPair; import org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplateOptions; @@ -39,30 +43,41 @@ import com.google.common.annotations.VisibleForTesting; */ @Singleton public class CreateNewKeyPairUnlessUserSpecifiedOtherwise { - final ConcurrentMap credentialsMap; + final Map credentialStore; @VisibleForTesting final CreateUniqueKeyPair createUniqueKeyPair; @Inject - CreateNewKeyPairUnlessUserSpecifiedOtherwise(ConcurrentMap credentialsMap, - CreateUniqueKeyPair createUniqueKeyPair) { - this.credentialsMap = credentialsMap; + CreateNewKeyPairUnlessUserSpecifiedOtherwise(Map credentialStore, + CreateUniqueKeyPair createUniqueKeyPair) { + this.credentialStore = credentialStore; this.createUniqueKeyPair = createUniqueKeyPair; } @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(); boolean shouldAutomaticallyCreateKeyPair = options.shouldAutomaticallyCreateKeyPair(); if (sshKeyFingerprint == null && shouldAutomaticallyCreateKeyPair) { - OrgAndName orgAndName = new OrgAndName(org, tag); - if (credentialsMap.containsKey(orgAndName)) { - options.sshKeyFingerprint(credentialsMap.get(orgAndName).getKeyPair().getFingerPrint()); - } else { - KeyPair keyPair = createUniqueKeyPair.apply(orgAndName); - credentialsMap.put(orgAndName, new KeyPairCredentials(identity, keyPair)); - options.sshKeyFingerprint(keyPair.getFingerPrint()); + + // make sure that we don't request multiple keys simultaneously + synchronized (credentialStore) { + // if there is already a keypair for the group specified, use it + if (credentialStore.containsKey("group#" + group)) { + LoginCredentials creds = LoginCredentials.fromCredentials(credentialStore.get("group#" + group)); + 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()); + } } + } + } -} \ No newline at end of file +} diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/DeleteKeyPair.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/DeleteKeyPair.java index c6c9e710cf..f3af6d25fd 100644 --- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/DeleteKeyPair.java +++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/DeleteKeyPair.java @@ -18,7 +18,7 @@ */ package org.jclouds.trmk.vcloud_0_8.compute.strategy; -import java.util.concurrent.ConcurrentMap; +import java.util.Map; import javax.annotation.Resource; import javax.inject.Inject; @@ -26,9 +26,9 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.domain.Credentials; import org.jclouds.logging.Logger; 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.domain.KeyPair; @@ -44,12 +44,12 @@ public class DeleteKeyPair { protected Logger logger = Logger.NULL; final TerremarkVCloudClient terremarkClient; - final ConcurrentMap credentialsMap; + final Map credentialStore; @Inject - DeleteKeyPair(TerremarkVCloudClient terremarkClient, ConcurrentMap credentialsMap) { + DeleteKeyPair(TerremarkVCloudClient terremarkClient, Map credentialStore) { this.terremarkClient = terremarkClient; - this.credentialsMap = credentialsMap; + this.credentialStore = credentialStore; } public void execute(OrgAndName orgTag) { @@ -57,9 +57,8 @@ public class DeleteKeyPair { if (keyPair.getName().matches("jclouds_" + orgTag.getName().replaceAll("-", "_") + "_[0-9a-f]+")) { logger.debug(">> deleting keyPair(%s)", keyPair.getName()); terremarkClient.deleteKeyPair(keyPair.getId()); - // TODO: test this clear happens - credentialsMap.remove(orgTag); logger.debug("<< deleted keyPair(%s)", keyPair.getName()); + credentialStore.remove("group#" + orgTag.getName()); } } } diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/StartVAppWithGroupEncodedIntoName.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/StartVAppWithGroupEncodedIntoName.java index cae27a6664..4625f50c34 100644 --- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/StartVAppWithGroupEncodedIntoName.java +++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/StartVAppWithGroupEncodedIntoName.java @@ -26,11 +26,13 @@ import java.util.Map; import javax.inject.Inject; import javax.inject.Singleton; +import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials; import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.domain.Template; import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName; +import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate; 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.functions.TemplateToInstantiateOptions; import org.jclouds.trmk.vcloud_0_8.domain.VApp; @@ -46,28 +48,34 @@ public class StartVAppWithGroupEncodedIntoName implements CreateNodeWithGroupEnc protected final TerremarkVCloudComputeClient computeClient; protected final TemplateToInstantiateOptions getOptions; protected final Function vAppToNodeMetadata; - private final Map credentialStore; + protected final Map credentialStore; + protected final PrioritizeCredentialsFromTemplate prioritizeCredentialsFromTemplate; + @Inject protected StartVAppWithGroupEncodedIntoName(TerremarkVCloudComputeClient computeClient, Function vAppToNodeMetadata, TemplateToInstantiateOptions getOptions, - Map credentialStore) { + Map credentialStore, PrioritizeCredentialsFromTemplate prioritizeCredentialsFromTemplate) { this.computeClient = computeClient; this.vAppToNodeMetadata = vAppToNodeMetadata; this.getOptions = checkNotNull(getOptions, "getOptions"); this.credentialStore = checkNotNull(credentialStore, "credentialStore"); + this.prioritizeCredentialsFromTemplate = checkNotNull(prioritizeCredentialsFromTemplate, "prioritizeCredentialsFromTemplate"); } - @Override public NodeMetadata createNodeWithGroupEncodedIntoName(String group, String name, Template template) { InstantiateVAppTemplateOptions options = getOptions.apply(template); - VApp vApp = computeClient.start(URI.create(template.getLocation().getId()), URI.create(template + NodeAndInitialCredentials from = computeClient.startAndReturnCredentials(URI.create(template.getLocation().getId()), URI.create(template .getImage().getId()), name, options, template.getOptions().getInboundPorts()); - NodeMetadata node = vAppToNodeMetadata.apply(vApp); - NodeMetadataBuilder builder = NodeMetadataBuilder.fromNodeMetadata(node); - if (template.getImage().getDefaultCredentials() != null) - credentialStore.put("node#" + node.getId(), template.getImage().getDefaultCredentials()); - return builder.build(); + LoginCredentials fromNode = from.getCredentials(); + if (credentialStore.containsKey("group#" + group)) { + fromNode = fromNode == null ? LoginCredentials.fromCredentials(credentialStore.get("group#" + group)) + : fromNode.toBuilder().privateKey(credentialStore.get("group#" + group).credential).build(); + } + LoginCredentials creds = prioritizeCredentialsFromTemplate.apply(template, fromNode); + if (creds != null) + credentialStore.put("node#" + from.getNodeId(), creds); + return vAppToNodeMetadata.apply(from.getNode()); } } \ No newline at end of file diff --git a/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeClientTest.java b/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeClientTest.java index 00a06cbe0b..10027a7bc2 100644 --- a/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeClientTest.java +++ b/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/TerremarkVCloudComputeClientTest.java @@ -31,10 +31,11 @@ import java.util.Map; import javax.inject.Provider; +import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials; import org.jclouds.compute.domain.NodeState; 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.compute.strategy.ParseVAppTemplateDescriptionToGetDefaultLoginCredentials; 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.VApp; @@ -88,7 +89,7 @@ public class TerremarkVCloudComputeClientTest { Map vAppStatusToNodeState = createMock(Map.class); TerremarkVCloudComputeClient computeClient = new TerremarkVCloudComputeClient(client, - new ParseVAppTemplateDescriptionToGetDefaultLoginCredentials(null), new Provider() { + new Provider() { @Override public String get() { @@ -106,10 +107,11 @@ public class TerremarkVCloudComputeClientTest { replay(notFoundTester); replay(vAppStatusToNodeState); - VApp response = computeClient.start(vdcURI, templateURI, "name", new InstantiateVAppTemplateOptions()); + NodeAndInitialCredentials response = computeClient.startAndReturnCredentials(vdcURI, templateURI, "name", new InstantiateVAppTemplateOptions()); - assertEquals(response.getHref().toASCIIString(), "vapp"); - assertEquals(credentialStore.get("node#vapp"), new Credentials("Administrator", "password")); + assertEquals(response.getNodeId(), "vapp"); + assertEquals(response.getNode(),vApp); + assertEquals(response.getCredentials(), LoginCredentials.builder().password("password").build()); verify(vdc); verify(template); diff --git a/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CleanupOrphanKeysTest.java b/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CleanupOrphanKeysTest.java index 42501d3931..01d2e9d3fc 100644 --- a/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CleanupOrphanKeysTest.java +++ b/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CleanupOrphanKeysTest.java @@ -140,9 +140,8 @@ public class CleanupOrphanKeysTest { } 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#adminPassword")).andReturn(null); } public void testWhenNoneLeftWithTag() { diff --git a/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest.java b/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest.java index f2dc30e9ab..4a89da2078 100644 --- a/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest.java +++ b/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest.java @@ -27,14 +27,16 @@ import static org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplat import static org.testng.Assert.assertEquals; import java.net.URI; +import java.util.Map; 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.functions.CreateUniqueKeyPair; 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.xml.KeyPairHandlerTest; import org.testng.annotations.Test; /** @@ -47,34 +49,25 @@ public class CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest { // setup constants URI org = URI.create("org1"); String identity = "identity"; - String tag = "tag"; - OrgAndName orgAndName = new OrgAndName(org, "tag"); - String systemGeneratedFingerprint = "systemGeneratedKeyPairfinger"; + String group = "group"; TerremarkVCloudTemplateOptions options = new TerremarkVCloudTemplateOptions(); // create mocks CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy = setupStrategy(); - KeyPairCredentials keyPairCredentials = createMock(KeyPairCredentials.class); - KeyPair keyPair = createMock(KeyPair.class); + LoginCredentials keyPairCredentials = LoginCredentials.builder().privateKey(KeyPairHandlerTest.keyPair.getPrivateKey()).build(); // setup expectations - expect(strategy.credentialsMap.containsKey(orgAndName)).andReturn(true); - expect(strategy.credentialsMap.get(orgAndName)).andReturn(keyPairCredentials); - expect(keyPairCredentials.getKeyPair()).andReturn(keyPair); - expect(keyPair.getFingerPrint()).andReturn(systemGeneratedFingerprint).atLeastOnce(); + expect(strategy.credentialStore.containsKey("group#group")).andReturn(true); + expect(strategy.credentialStore.get("group#group")).andReturn(keyPairCredentials); // replay mocks - replay(keyPair); - replay(keyPairCredentials); replayStrategy(strategy); // run - strategy.execute(org, tag, identity, options); - assertEquals(options.getSshKeyFingerprint(), "systemGeneratedKeyPairfinger"); + strategy.execute(org, group, identity, options); + assertEquals(options.getSshKeyFingerprint(), KeyPairHandlerTest.keyPair.getFingerPrint()); // verify mocks - verify(keyPair); - verify(keyPairCredentials); verifyStrategy(strategy); } @@ -82,7 +75,7 @@ public class CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest { // setup constants URI org = URI.create("org1"); String identity = "identity"; - String tag = "tag"; + String group = "group"; TerremarkVCloudTemplateOptions options = sshKeyFingerprint("fingerprintFromUser"); // create mocks @@ -94,7 +87,7 @@ public class CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest { replayStrategy(strategy); // run - strategy.execute(org, tag, identity, options); + strategy.execute(org, group, identity, options); assertEquals(options.getSshKeyFingerprint(), "fingerprintFromUser"); // verify mocks @@ -108,30 +101,27 @@ public class CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest { // setup constants URI org = URI.create("org1"); String identity = "identity"; - String tag = "tag"; + String group = "group"; String systemGeneratedFingerprint = "systemGeneratedKeyPairfinger"; - String privateKey = "privateKey"; TerremarkVCloudTemplateOptions options = new TerremarkVCloudTemplateOptions(); - OrgAndName orgAndName = new OrgAndName(org, "tag"); // create mocks CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy = setupStrategy(); - KeyPairCredentials keyPairCredentials = createMock(KeyPairCredentials.class); + LoginCredentials keyPairCredentials = LoginCredentials.builder().privateKey(KeyPairHandlerTest.keyPair.getPrivateKey()).build(); KeyPair keyPair = createMock(KeyPair.class); // setup expectations - expect(strategy.credentialsMap.containsKey(orgAndName)).andReturn(false); - expect(strategy.createUniqueKeyPair.apply(orgAndName)).andReturn(keyPair); - expect(keyPair.getFingerPrint()).andReturn(systemGeneratedFingerprint).atLeastOnce(); - expect(keyPair.getPrivateKey()).andReturn(privateKey).atLeastOnce(); - expect(strategy.credentialsMap.put(orgAndName, keyPairCredentials)).andReturn(null); + expect(strategy.credentialStore.containsKey("group#group")).andReturn(false); + expect(strategy.createUniqueKeyPair.apply(new OrgAndName(org, "group"))).andReturn(keyPair); + expect(keyPair.getFingerPrint()).andReturn(KeyPairHandlerTest.keyPair.getFingerPrint()).atLeastOnce(); + expect(strategy.credentialStore.put("group#group", keyPairCredentials)).andReturn(null); // replay mocks replay(keyPair); replayStrategy(strategy); // run - strategy.execute(org, tag, identity, options); + strategy.execute(org, group, identity, options); assertEquals(options.getSshKeyFingerprint(), systemGeneratedFingerprint); // verify mocks @@ -143,43 +133,40 @@ public class CreateNewKeyPairUnlessUserSpecifiedOtherwiseTest { // setup constants URI org = URI.create("org1"); String identity = "identity"; - String tag = "tag"; + String group = "group"; TerremarkVCloudTemplateOptions options = noKeyPair(); // create mocks CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy = setupStrategy(); - KeyPair keyPair = createMock(KeyPair.class); // setup expectations // replay mocks - replay(keyPair); replayStrategy(strategy); // run - strategy.execute(org, tag, identity, options); + strategy.execute(org, group, identity, options); assertEquals(options.getSshKeyFingerprint(), null); // verify mocks - verify(keyPair); verifyStrategy(strategy); } private void verifyStrategy(CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy) { - verify(strategy.credentialsMap); + verify(strategy.credentialStore); verify(strategy.createUniqueKeyPair); } @SuppressWarnings("unchecked") private CreateNewKeyPairUnlessUserSpecifiedOtherwise setupStrategy() { - ConcurrentMap credentialsMap = createMock(ConcurrentMap.class); + Map credentialStore = createMock(ConcurrentMap.class); CreateUniqueKeyPair createUniqueKeyPair = createMock(CreateUniqueKeyPair.class); - return new CreateNewKeyPairUnlessUserSpecifiedOtherwise(credentialsMap, createUniqueKeyPair); + return new CreateNewKeyPairUnlessUserSpecifiedOtherwise(credentialStore, createUniqueKeyPair); } private void replayStrategy(CreateNewKeyPairUnlessUserSpecifiedOtherwise strategy) { - replay(strategy.credentialsMap); + replay(strategy.credentialStore); replay(strategy.createUniqueKeyPair); } diff --git a/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/DeleteKeyPairTest.java b/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/DeleteKeyPairTest.java index dbe5836072..f207e14135 100644 --- a/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/DeleteKeyPairTest.java +++ b/common/trmk/src/test/java/org/jclouds/trmk/vcloud_0_8/compute/strategy/DeleteKeyPairTest.java @@ -24,12 +24,12 @@ import static org.easymock.classextension.EasyMock.replay; import static org.easymock.classextension.EasyMock.verify; import java.net.URI; +import java.util.Map; 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.compute.domain.KeyPairCredentials; 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.testng.annotations.Test; @@ -78,7 +78,7 @@ public class DeleteKeyPairTest { expect(keyPair.getName()).andReturn("jclouds_" + orgTag.getName() + "_123").atLeastOnce(); expect(keyPair.getId()).andReturn(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(keyPair); @@ -119,20 +119,20 @@ public class DeleteKeyPairTest { } private void verifyStrategy(DeleteKeyPair strategy) { - verify(strategy.credentialsMap); + verify(strategy.credentialStore); verify(strategy.terremarkClient); } @SuppressWarnings("unchecked") private DeleteKeyPair setupStrategy() { - ConcurrentMap credentialsMap = createMock(ConcurrentMap.class); + Map credentialStore = createMock(ConcurrentMap.class); TerremarkVCloudClient terremarkClient = createMock(TerremarkVCloudClient.class); - return new DeleteKeyPair(terremarkClient, credentialsMap); + return new DeleteKeyPair(terremarkClient, credentialStore); } private void replayStrategy(DeleteKeyPair strategy) { - replay(strategy.credentialsMap); + replay(strategy.credentialStore); replay(strategy.terremarkClient); }