From faa57c71bbde6a6161de4219bcc013d593292fb9 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Tue, 26 Oct 2010 20:20:36 -0700 Subject: [PATCH] Issue 387: revised terremark to use the password in the vAppTemplate description to use as adminPassword during sudo --- ...markVCloudComputeServiceContextModule.java | 2 +- ...remarkVCloudExpressVAppToNodeMetadata.java | 8 ++++++ .../compute/strategy/CleanupOrphanKeys.java | 15 +++++++++-- ...TerremarkVCloudAddNodeWithTagStrategy.java | 25 ++++++++++++++++--- .../suppliers/VAppTemplatesInOrgs.java | 24 +++++++++++++++--- .../terremark/TerremarkClientLiveTest.java | 17 +++++++------ ...rkVCloudExpressComputeServiceLiveTest.java | 5 ++++ .../strategy/CleanupOrphanKeysTest.java | 24 ++++++++++++++---- 8 files changed, 97 insertions(+), 23 deletions(-) diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java index bf4a97843c..0d84ab905c 100755 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java @@ -79,7 +79,7 @@ public class TerremarkVCloudComputeServiceContextModule extends VCloudExpressCom bind(ComputeService.class).to(TerremarkVCloudComputeService.class); bind(VCloudExpressComputeClient.class).to(TerremarkVCloudComputeClient.class); bind(PopulateDefaultLoginCredentialsForImageStrategy.class).to( - ParseVAppTemplateDescriptionToGetDefaultLoginCredentials.class); + ParseVAppTemplateDescriptionToGetDefaultLoginCredentials.class); bind(SecureRandom.class).toInstance(new SecureRandom()); } diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/functions/TerremarkVCloudExpressVAppToNodeMetadata.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/functions/TerremarkVCloudExpressVAppToNodeMetadata.java index 517dfda86a..d4f7a6d268 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/functions/TerremarkVCloudExpressVAppToNodeMetadata.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/functions/TerremarkVCloudExpressVAppToNodeMetadata.java @@ -80,6 +80,14 @@ public class TerremarkVCloudExpressVAppToNodeMetadata extends VCloudExpressVAppT if (credentialsMap.containsKey(orgAndName)) { Credentials creds = credentialsMap.get(orgAndName); node = NodeMetadataBuilder.fromNodeMetadata(node).credentials(creds).build(); + credentialStore.put(node.getId(), creds); + } + // this is going to need refactoring.. we really need a credential list in the store per + // node. + String adminPasswordKey = node.getId() + "/adminPassword"; + if (credentialStore.containsKey(adminPasswordKey)) { + node = NodeMetadataBuilder.fromNodeMetadata(node).adminPassword( + credentialStore.get(adminPasswordKey).credential).build(); } return node; } diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/CleanupOrphanKeys.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/CleanupOrphanKeys.java index d9a5ccf4ac..8e21f5f95a 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/CleanupOrphanKeys.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/CleanupOrphanKeys.java @@ -28,11 +28,14 @@ import static org.jclouds.compute.predicates.NodePredicates.TERMINATED; import static org.jclouds.compute.predicates.NodePredicates.parentLocationId; import static org.jclouds.compute.predicates.NodePredicates.withTag; +import java.util.Map; + import javax.inject.Inject; import javax.inject.Singleton; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.strategy.ListNodesStrategy; +import org.jclouds.domain.Credentials; import org.jclouds.vcloud.terremark.compute.domain.OrgAndName; import com.google.common.base.Function; @@ -47,20 +50,28 @@ public class CleanupOrphanKeys { final Function nodeToOrgAndName; final DeleteKeyPair deleteKeyPair; final ListNodesStrategy listNodes; + final Map credentialStore; @Inject CleanupOrphanKeys(Function nodeToOrgAndName, DeleteKeyPair deleteKeyPair, - ListNodesStrategy listNodes) { + Map credentialStore, ListNodesStrategy listNodes) { this.nodeToOrgAndName = nodeToOrgAndName; this.deleteKeyPair = deleteKeyPair; this.listNodes = listNodes; + this.credentialStore = credentialStore; } public void execute(Iterable deadOnes) { + // TODO refactor so that admin passwords are cached properly, probably as a list value in the + // credentialStore + for (NodeMetadata node : deadOnes){ + credentialStore.remove(node.getId()); + credentialStore.remove(node.getId() + "/adminPassword"); + } Iterable orgTags = filter(transform(deadOnes, nodeToOrgAndName), notNull()); for (OrgAndName orgTag : orgTags) { Iterable nodesInOrg = listNodes.listDetailsOnNodesMatching(parentLocationId(orgTag - .getOrg().toASCIIString())); + .getOrg().toASCIIString())); Iterable nodesWithTag = filter(nodesInOrg, withTag(orgTag.getName())); if (size(nodesWithTag) == 0 || all(nodesWithTag, TERMINATED)) deleteKeyPair.execute(orgTag); diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/TerremarkVCloudAddNodeWithTagStrategy.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/TerremarkVCloudAddNodeWithTagStrategy.java index 5ca330f099..3d103a28f9 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/TerremarkVCloudAddNodeWithTagStrategy.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/TerremarkVCloudAddNodeWithTagStrategy.java @@ -22,13 +22,16 @@ package org.jclouds.vcloud.terremark.compute.strategy; import static com.google.common.base.Preconditions.checkNotNull; import java.net.URI; +import java.util.Map; import javax.inject.Inject; import javax.inject.Singleton; import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.domain.Template; import org.jclouds.compute.strategy.AddNodeWithTagStrategy; +import org.jclouds.domain.Credentials; import org.jclouds.vcloud.domain.VCloudExpressVApp; import org.jclouds.vcloud.terremark.compute.TerremarkVCloudComputeClient; import org.jclouds.vcloud.terremark.compute.functions.TemplateToInstantiateOptions; @@ -44,21 +47,35 @@ public class TerremarkVCloudAddNodeWithTagStrategy implements AddNodeWithTagStra protected final TerremarkVCloudComputeClient computeClient; protected final TemplateToInstantiateOptions getOptions; protected final Function vAppToNodeMetadata; + private final Map credentialStore; @Inject protected TerremarkVCloudAddNodeWithTagStrategy(TerremarkVCloudComputeClient computeClient, - Function vAppToNodeMetadata, TemplateToInstantiateOptions getOptions) { + Function vAppToNodeMetadata, TemplateToInstantiateOptions getOptions, + Map credentialStore) { this.computeClient = computeClient; this.vAppToNodeMetadata = vAppToNodeMetadata; this.getOptions = checkNotNull(getOptions, "getOptions"); + this.credentialStore = checkNotNull(credentialStore, "credentialStore"); } @Override public NodeMetadata addNodeWithTag(String tag, String name, Template template) { TerremarkInstantiateVAppTemplateOptions options = getOptions.apply(template); - VCloudExpressVApp vApp = computeClient.start(URI.create(template.getLocation().getId()), - URI.create(template.getImage().getId()), name, options, template.getOptions().getInboundPorts()); - return vAppToNodeMetadata.apply(vApp); + VCloudExpressVApp vApp = computeClient.start(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); + // TODO refactor this so that it is automatic in any provider + if (template.getImage().getAdminPassword() != null) { + builder.adminPassword(template.getImage().getAdminPassword()); + // this is going to need refactoring.. we really need a credential list in the store per + // node. we need to store the credential here explicitly, as there's no connection from a node + // in vcloud to the image it was created with. + credentialStore.put(node.getId() + "/adminPassword", new Credentials("root", template.getImage() + .getAdminPassword())); + } + return builder.build(); } } \ No newline at end of file diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/suppliers/VAppTemplatesInOrgs.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/suppliers/VAppTemplatesInOrgs.java index fb439c8a2a..8a5c46e3b3 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/suppliers/VAppTemplatesInOrgs.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/suppliers/VAppTemplatesInOrgs.java @@ -19,6 +19,8 @@ package org.jclouds.vcloud.terremark.compute.suppliers; +import static com.google.common.collect.Iterables.concat; +import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Sets.newLinkedHashSet; import java.util.Set; @@ -30,6 +32,7 @@ import javax.inject.Singleton; import org.jclouds.collect.Memoized; import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.ImageBuilder; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.Location; import org.jclouds.logging.Logger; @@ -38,7 +41,6 @@ import org.jclouds.vcloud.domain.Org; import com.google.common.base.Function; import com.google.common.base.Supplier; -import com.google.common.collect.Iterables; /** * @author Adrian Cole @@ -70,7 +72,23 @@ public class VAppTemplatesInOrgs implements Supplier> { @Override public Set get() { logger.debug(">> providing vAppTemplates"); - return newLinkedHashSet(Iterables.concat(Iterables.transform(organizatonsForLocations.apply(locations.get()), - imagesInOrg))); + return newLinkedHashSet(transform( + concat(transform(organizatonsForLocations.apply(locations.get()), imagesInOrg)), + new Function() { + + @Override + public Image apply(Image from) { + ImageBuilder builder = ImageBuilder.fromImage(from); + // the password in the image is the sudo password + // TODO refactor authenticate image logic so that it can populate the + // adminPassword + // value + // independently + if (from.getDefaultCredentials() != null) + builder.adminPassword(from.getDefaultCredentials().credential); + return builder.build(); + } + + })); } } \ No newline at end of file diff --git a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkClientLiveTest.java b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkClientLiveTest.java index dff0af2ce3..87b66edba2 100644 --- a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkClientLiveTest.java +++ b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkClientLiveTest.java @@ -436,11 +436,9 @@ public abstract class TerremarkClientLiveTest extends VCloudExpressClientLiveTes protected void setupCredentials() { identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity"); - credential = checkNotNull(System.getProperty("test." + provider + ".credential"), "test." + provider - + ".credential"); - endpoint = checkNotNull(System.getProperty("test." + provider + ".endpoint"), "test." + provider + ".endpoint"); - apiversion = checkNotNull(System.getProperty("test." + provider + ".apiversion"), "test." + provider - + ".apiversion"); + credential = System.getProperty("test." + provider + ".credential"); + endpoint = System.getProperty("test." + provider + ".endpoint"); + apiversion = System.getProperty("test." + provider + ".apiversion"); } protected Properties setupProperties() { @@ -448,9 +446,12 @@ public abstract class TerremarkClientLiveTest extends VCloudExpressClientLiveTes overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "true"); overrides.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true"); overrides.setProperty(provider + ".identity", identity); - overrides.setProperty(provider + ".credential", credential); - overrides.setProperty(provider + ".endpoint", endpoint); - overrides.setProperty(provider + ".apiversion", apiversion); + if (credential != null) + overrides.setProperty(provider + ".credential", credential); + if (endpoint != null) + overrides.setProperty(provider + ".endpoint", endpoint); + if (apiversion != null) + overrides.setProperty(provider + ".apiversion", apiversion); return overrides; } diff --git a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudExpressComputeServiceLiveTest.java b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudExpressComputeServiceLiveTest.java index e650ffd4b8..1bbdcc0777 100644 --- a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudExpressComputeServiceLiveTest.java +++ b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudExpressComputeServiceLiveTest.java @@ -33,6 +33,7 @@ import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.rest.RestContext; import org.jclouds.ssh.jsch.config.JschSshClientModule; +import org.jclouds.vcloud.domain.VCloudExpressVApp; import org.jclouds.vcloud.terremark.TerremarkVCloudExpressAsyncClient; import org.jclouds.vcloud.terremark.TerremarkVCloudExpressClient; import org.testng.annotations.Test; @@ -104,6 +105,10 @@ public class TerremarkVCloudExpressComputeServiceLiveTest extends BaseComputeSer assertEquals(node.getType(), ComputeType.NODE); NodeMetadata allData = client.getNodeMetadata(node.getId()); System.out.println(allData.getHardware()); + RestContext tmContext = new ComputeServiceContextFactory() + .createContext(provider, identity, credential).getProviderSpecificContext(); + VCloudExpressVApp vApp = tmContext.getApi().findVAppInOrgVDCNamed(null, null, allData.getName()); + assertEquals(vApp.getName(), allData.getName()); } } diff --git a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/strategy/CleanupOrphanKeysTest.java b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/strategy/CleanupOrphanKeysTest.java index 5c632ee5ce..e972b61747 100644 --- a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/strategy/CleanupOrphanKeysTest.java +++ b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/strategy/CleanupOrphanKeysTest.java @@ -26,10 +26,12 @@ import static org.easymock.classextension.EasyMock.verify; import static org.jclouds.compute.predicates.NodePredicates.parentLocationId; import java.net.URI; +import java.util.Map; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.strategy.ListNodesStrategy; +import org.jclouds.domain.Credentials; import org.jclouds.vcloud.terremark.compute.domain.OrgAndName; import org.jclouds.vcloud.terremark.compute.functions.NodeMetadataToOrgAndName; import org.testng.annotations.Test; @@ -67,6 +69,7 @@ public class CleanupOrphanKeysTest { // setup expectations expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(null).atLeastOnce(); + expectCleanupCredentialStore(strategy, nodeMetadata); // replay mocks replay(nodeMetadata); @@ -90,9 +93,10 @@ public class CleanupOrphanKeysTest { // setup expectations expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(orgTag).atLeastOnce(); expect((Object) strategy.listNodes.listDetailsOnNodesMatching(parentLocationId(orgTag.getOrg().toASCIIString()))) - .andReturn(ImmutableSet.of(nodeMetadata)); + .andReturn(ImmutableSet.of(nodeMetadata)); expect(nodeMetadata.getTag()).andReturn(orgTag.getName()).atLeastOnce(); expect(nodeMetadata.getState()).andReturn(NodeState.RUNNING).atLeastOnce(); + expectCleanupCredentialStore(strategy, nodeMetadata); // replay mocks replay(nodeMetadata); @@ -116,10 +120,11 @@ public class CleanupOrphanKeysTest { // setup expectations expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(orgTag).atLeastOnce(); expect((Object) strategy.listNodes.listDetailsOnNodesMatching(parentLocationId(orgTag.getOrg().toASCIIString()))) - .andReturn(ImmutableSet.of(nodeMetadata)); + .andReturn(ImmutableSet.of(nodeMetadata)); expect(nodeMetadata.getTag()).andReturn(orgTag.getName()).atLeastOnce(); expect(nodeMetadata.getState()).andReturn(NodeState.TERMINATED).atLeastOnce(); strategy.deleteKeyPair.execute(orgTag); + expectCleanupCredentialStore(strategy, nodeMetadata); // replay mocks replay(nodeMetadata); @@ -133,6 +138,12 @@ public class CleanupOrphanKeysTest { verifyStrategy(strategy); } + private void expectCleanupCredentialStore(CleanupOrphanKeys strategy, NodeMetadata nodeMetadata) { + expect(nodeMetadata.getId()).andReturn("1").times(2); + expect(strategy.credentialStore.remove("1")).andReturn(null); + expect(strategy.credentialStore.remove("1/adminPassword")).andReturn(null); + } + public void testWhenNoneLeftWithTag() { // create mocks CleanupOrphanKeys strategy = setupStrategy(); @@ -143,8 +154,9 @@ public class CleanupOrphanKeysTest { // setup expectations expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(orgTag).atLeastOnce(); expect((Object) strategy.listNodes.listDetailsOnNodesMatching(parentLocationId(orgTag.getOrg().toASCIIString()))) - .andReturn(ImmutableSet.of()); + .andReturn(ImmutableSet.of()); strategy.deleteKeyPair.execute(orgTag); + expectCleanupCredentialStore(strategy, nodeMetadata); // replay mocks replay(nodeMetadata); @@ -162,20 +174,22 @@ public class CleanupOrphanKeysTest { verify(strategy.nodeToOrgAndName); verify(strategy.deleteKeyPair); verify(strategy.listNodes); - + verify(strategy.credentialStore); } private CleanupOrphanKeys setupStrategy() { NodeMetadataToOrgAndName nodeToOrgAndName = createMock(NodeMetadataToOrgAndName.class); DeleteKeyPair deleteKeyPair = createMock(DeleteKeyPair.class); ListNodesStrategy listNodes = createMock(ListNodesStrategy.class); - return new CleanupOrphanKeys(nodeToOrgAndName, deleteKeyPair, listNodes); + Map credentialStore = createMock(Map.class); + return new CleanupOrphanKeys(nodeToOrgAndName, deleteKeyPair, credentialStore, listNodes); } private void replayStrategy(CleanupOrphanKeys strategy) { replay(strategy.nodeToOrgAndName); replay(strategy.deleteKeyPair); replay(strategy.listNodes); + replay(strategy.credentialStore); } }