Issue 387: revised terremark to use the password in the vAppTemplate description to use as adminPassword during sudo

This commit is contained in:
Adrian Cole 2010-10-26 20:20:36 -07:00
parent b4ad8fed1f
commit faa57c71bb
8 changed files with 97 additions and 23 deletions

View File

@ -79,7 +79,7 @@ public class TerremarkVCloudComputeServiceContextModule extends VCloudExpressCom
bind(ComputeService.class).to(TerremarkVCloudComputeService.class); bind(ComputeService.class).to(TerremarkVCloudComputeService.class);
bind(VCloudExpressComputeClient.class).to(TerremarkVCloudComputeClient.class); bind(VCloudExpressComputeClient.class).to(TerremarkVCloudComputeClient.class);
bind(PopulateDefaultLoginCredentialsForImageStrategy.class).to( bind(PopulateDefaultLoginCredentialsForImageStrategy.class).to(
ParseVAppTemplateDescriptionToGetDefaultLoginCredentials.class); ParseVAppTemplateDescriptionToGetDefaultLoginCredentials.class);
bind(SecureRandom.class).toInstance(new SecureRandom()); bind(SecureRandom.class).toInstance(new SecureRandom());
} }

View File

@ -80,6 +80,14 @@ public class TerremarkVCloudExpressVAppToNodeMetadata extends VCloudExpressVAppT
if (credentialsMap.containsKey(orgAndName)) { if (credentialsMap.containsKey(orgAndName)) {
Credentials creds = credentialsMap.get(orgAndName); Credentials creds = credentialsMap.get(orgAndName);
node = NodeMetadataBuilder.fromNodeMetadata(node).credentials(creds).build(); 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; return node;
} }

View File

@ -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.parentLocationId;
import static org.jclouds.compute.predicates.NodePredicates.withTag; import static org.jclouds.compute.predicates.NodePredicates.withTag;
import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.strategy.ListNodesStrategy; 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.domain.OrgAndName;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -47,20 +50,28 @@ public class CleanupOrphanKeys {
final Function<NodeMetadata, OrgAndName> nodeToOrgAndName; final Function<NodeMetadata, OrgAndName> nodeToOrgAndName;
final DeleteKeyPair deleteKeyPair; final DeleteKeyPair deleteKeyPair;
final ListNodesStrategy listNodes; final ListNodesStrategy listNodes;
final Map<String, Credentials> credentialStore;
@Inject @Inject
CleanupOrphanKeys(Function<NodeMetadata, OrgAndName> nodeToOrgAndName, DeleteKeyPair deleteKeyPair, CleanupOrphanKeys(Function<NodeMetadata, OrgAndName> nodeToOrgAndName, DeleteKeyPair deleteKeyPair,
ListNodesStrategy listNodes) { Map<String, Credentials> credentialStore, ListNodesStrategy listNodes) {
this.nodeToOrgAndName = nodeToOrgAndName; this.nodeToOrgAndName = nodeToOrgAndName;
this.deleteKeyPair = deleteKeyPair; this.deleteKeyPair = deleteKeyPair;
this.listNodes = listNodes; this.listNodes = listNodes;
this.credentialStore = credentialStore;
} }
public void execute(Iterable<? extends NodeMetadata> deadOnes) { public void execute(Iterable<? extends NodeMetadata> 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<OrgAndName> orgTags = filter(transform(deadOnes, nodeToOrgAndName), notNull()); Iterable<OrgAndName> orgTags = filter(transform(deadOnes, nodeToOrgAndName), notNull());
for (OrgAndName orgTag : orgTags) { for (OrgAndName orgTag : orgTags) {
Iterable<? extends NodeMetadata> nodesInOrg = listNodes.listDetailsOnNodesMatching(parentLocationId(orgTag Iterable<? extends NodeMetadata> nodesInOrg = listNodes.listDetailsOnNodesMatching(parentLocationId(orgTag
.getOrg().toASCIIString())); .getOrg().toASCIIString()));
Iterable<? extends NodeMetadata> nodesWithTag = filter(nodesInOrg, withTag(orgTag.getName())); Iterable<? extends NodeMetadata> nodesWithTag = filter(nodesInOrg, withTag(orgTag.getName()));
if (size(nodesWithTag) == 0 || all(nodesWithTag, TERMINATED)) if (size(nodesWithTag) == 0 || all(nodesWithTag, TERMINATED))
deleteKeyPair.execute(orgTag); deleteKeyPair.execute(orgTag);

View File

@ -22,13 +22,16 @@ package org.jclouds.vcloud.terremark.compute.strategy;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI; import java.net.URI;
import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
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.AddNodeWithTagStrategy; import org.jclouds.compute.strategy.AddNodeWithTagStrategy;
import org.jclouds.domain.Credentials;
import org.jclouds.vcloud.domain.VCloudExpressVApp; import org.jclouds.vcloud.domain.VCloudExpressVApp;
import org.jclouds.vcloud.terremark.compute.TerremarkVCloudComputeClient; import org.jclouds.vcloud.terremark.compute.TerremarkVCloudComputeClient;
import org.jclouds.vcloud.terremark.compute.functions.TemplateToInstantiateOptions; import org.jclouds.vcloud.terremark.compute.functions.TemplateToInstantiateOptions;
@ -44,21 +47,35 @@ public class TerremarkVCloudAddNodeWithTagStrategy implements AddNodeWithTagStra
protected final TerremarkVCloudComputeClient computeClient; protected final TerremarkVCloudComputeClient computeClient;
protected final TemplateToInstantiateOptions getOptions; protected final TemplateToInstantiateOptions getOptions;
protected final Function<VCloudExpressVApp, NodeMetadata> vAppToNodeMetadata; protected final Function<VCloudExpressVApp, NodeMetadata> vAppToNodeMetadata;
private final Map<String, Credentials> credentialStore;
@Inject @Inject
protected TerremarkVCloudAddNodeWithTagStrategy(TerremarkVCloudComputeClient computeClient, protected TerremarkVCloudAddNodeWithTagStrategy(TerremarkVCloudComputeClient computeClient,
Function<VCloudExpressVApp, NodeMetadata> vAppToNodeMetadata, TemplateToInstantiateOptions getOptions) { Function<VCloudExpressVApp, NodeMetadata> vAppToNodeMetadata, TemplateToInstantiateOptions getOptions,
Map<String, Credentials> credentialStore) {
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");
} }
@Override @Override
public NodeMetadata addNodeWithTag(String tag, String name, Template template) { public NodeMetadata addNodeWithTag(String tag, String name, Template template) {
TerremarkInstantiateVAppTemplateOptions options = getOptions.apply(template); TerremarkInstantiateVAppTemplateOptions options = getOptions.apply(template);
VCloudExpressVApp vApp = computeClient.start(URI.create(template.getLocation().getId()), VCloudExpressVApp vApp = computeClient.start(URI.create(template.getLocation().getId()), URI.create(template
URI.create(template.getImage().getId()), name, options, template.getOptions().getInboundPorts()); .getImage().getId()), name, options, template.getOptions().getInboundPorts());
return vAppToNodeMetadata.apply(vApp); 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();
} }
} }

View File

@ -19,6 +19,8 @@
package org.jclouds.vcloud.terremark.compute.suppliers; 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 static com.google.common.collect.Sets.newLinkedHashSet;
import java.util.Set; import java.util.Set;
@ -30,6 +32,7 @@ import javax.inject.Singleton;
import org.jclouds.collect.Memoized; import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageBuilder;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.logging.Logger; 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.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
/** /**
* @author Adrian Cole * @author Adrian Cole
@ -70,7 +72,23 @@ public class VAppTemplatesInOrgs implements Supplier<Set<? extends Image>> {
@Override @Override
public Set<? extends Image> get() { public Set<? extends Image> get() {
logger.debug(">> providing vAppTemplates"); logger.debug(">> providing vAppTemplates");
return newLinkedHashSet(Iterables.concat(Iterables.transform(organizatonsForLocations.apply(locations.get()), return newLinkedHashSet(transform(
imagesInOrg))); concat(transform(organizatonsForLocations.apply(locations.get()), imagesInOrg)),
new Function<Image, Image>() {
@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();
}
}));
} }
} }

View File

@ -436,11 +436,9 @@ public abstract class TerremarkClientLiveTest extends VCloudExpressClientLiveTes
protected void setupCredentials() { protected void setupCredentials() {
identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity"); identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity");
credential = checkNotNull(System.getProperty("test." + provider + ".credential"), "test." + provider credential = System.getProperty("test." + provider + ".credential");
+ ".credential"); endpoint = System.getProperty("test." + provider + ".endpoint");
endpoint = checkNotNull(System.getProperty("test." + provider + ".endpoint"), "test." + provider + ".endpoint"); apiversion = System.getProperty("test." + provider + ".apiversion");
apiversion = checkNotNull(System.getProperty("test." + provider + ".apiversion"), "test." + provider
+ ".apiversion");
} }
protected Properties setupProperties() { 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_TRUST_ALL_CERTS, "true");
overrides.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true"); overrides.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true");
overrides.setProperty(provider + ".identity", identity); overrides.setProperty(provider + ".identity", identity);
overrides.setProperty(provider + ".credential", credential); if (credential != null)
overrides.setProperty(provider + ".endpoint", endpoint); overrides.setProperty(provider + ".credential", credential);
overrides.setProperty(provider + ".apiversion", apiversion); if (endpoint != null)
overrides.setProperty(provider + ".endpoint", endpoint);
if (apiversion != null)
overrides.setProperty(provider + ".apiversion", apiversion);
return overrides; return overrides;
} }

View File

@ -33,6 +33,7 @@ import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
import org.jclouds.ssh.jsch.config.JschSshClientModule; import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.jclouds.vcloud.domain.VCloudExpressVApp;
import org.jclouds.vcloud.terremark.TerremarkVCloudExpressAsyncClient; import org.jclouds.vcloud.terremark.TerremarkVCloudExpressAsyncClient;
import org.jclouds.vcloud.terremark.TerremarkVCloudExpressClient; import org.jclouds.vcloud.terremark.TerremarkVCloudExpressClient;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -104,6 +105,10 @@ public class TerremarkVCloudExpressComputeServiceLiveTest extends BaseComputeSer
assertEquals(node.getType(), ComputeType.NODE); assertEquals(node.getType(), ComputeType.NODE);
NodeMetadata allData = client.getNodeMetadata(node.getId()); NodeMetadata allData = client.getNodeMetadata(node.getId());
System.out.println(allData.getHardware()); System.out.println(allData.getHardware());
RestContext<TerremarkVCloudExpressClient, TerremarkVCloudExpressAsyncClient> tmContext = new ComputeServiceContextFactory()
.createContext(provider, identity, credential).getProviderSpecificContext();
VCloudExpressVApp vApp = tmContext.getApi().findVAppInOrgVDCNamed(null, null, allData.getName());
assertEquals(vApp.getName(), allData.getName());
} }
} }

View File

@ -26,10 +26,12 @@ import static org.easymock.classextension.EasyMock.verify;
import static org.jclouds.compute.predicates.NodePredicates.parentLocationId; import static org.jclouds.compute.predicates.NodePredicates.parentLocationId;
import java.net.URI; import java.net.URI;
import java.util.Map;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.strategy.ListNodesStrategy; 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.domain.OrgAndName;
import org.jclouds.vcloud.terremark.compute.functions.NodeMetadataToOrgAndName; import org.jclouds.vcloud.terremark.compute.functions.NodeMetadataToOrgAndName;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -67,6 +69,7 @@ public class CleanupOrphanKeysTest {
// setup expectations // setup expectations
expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(null).atLeastOnce(); expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(null).atLeastOnce();
expectCleanupCredentialStore(strategy, nodeMetadata);
// replay mocks // replay mocks
replay(nodeMetadata); replay(nodeMetadata);
@ -90,9 +93,10 @@ public class CleanupOrphanKeysTest {
// setup expectations // setup expectations
expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(orgTag).atLeastOnce(); expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(orgTag).atLeastOnce();
expect((Object) strategy.listNodes.listDetailsOnNodesMatching(parentLocationId(orgTag.getOrg().toASCIIString()))) 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.getTag()).andReturn(orgTag.getName()).atLeastOnce();
expect(nodeMetadata.getState()).andReturn(NodeState.RUNNING).atLeastOnce(); expect(nodeMetadata.getState()).andReturn(NodeState.RUNNING).atLeastOnce();
expectCleanupCredentialStore(strategy, nodeMetadata);
// replay mocks // replay mocks
replay(nodeMetadata); replay(nodeMetadata);
@ -116,10 +120,11 @@ public class CleanupOrphanKeysTest {
// setup expectations // setup expectations
expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(orgTag).atLeastOnce(); expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(orgTag).atLeastOnce();
expect((Object) strategy.listNodes.listDetailsOnNodesMatching(parentLocationId(orgTag.getOrg().toASCIIString()))) 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.getTag()).andReturn(orgTag.getName()).atLeastOnce();
expect(nodeMetadata.getState()).andReturn(NodeState.TERMINATED).atLeastOnce(); expect(nodeMetadata.getState()).andReturn(NodeState.TERMINATED).atLeastOnce();
strategy.deleteKeyPair.execute(orgTag); strategy.deleteKeyPair.execute(orgTag);
expectCleanupCredentialStore(strategy, nodeMetadata);
// replay mocks // replay mocks
replay(nodeMetadata); replay(nodeMetadata);
@ -133,6 +138,12 @@ public class CleanupOrphanKeysTest {
verifyStrategy(strategy); 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() { public void testWhenNoneLeftWithTag() {
// create mocks // create mocks
CleanupOrphanKeys strategy = setupStrategy(); CleanupOrphanKeys strategy = setupStrategy();
@ -143,8 +154,9 @@ public class CleanupOrphanKeysTest {
// setup expectations // setup expectations
expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(orgTag).atLeastOnce(); expect(strategy.nodeToOrgAndName.apply(nodeMetadata)).andReturn(orgTag).atLeastOnce();
expect((Object) strategy.listNodes.listDetailsOnNodesMatching(parentLocationId(orgTag.getOrg().toASCIIString()))) expect((Object) strategy.listNodes.listDetailsOnNodesMatching(parentLocationId(orgTag.getOrg().toASCIIString())))
.andReturn(ImmutableSet.of()); .andReturn(ImmutableSet.of());
strategy.deleteKeyPair.execute(orgTag); strategy.deleteKeyPair.execute(orgTag);
expectCleanupCredentialStore(strategy, nodeMetadata);
// replay mocks // replay mocks
replay(nodeMetadata); replay(nodeMetadata);
@ -162,20 +174,22 @@ public class CleanupOrphanKeysTest {
verify(strategy.nodeToOrgAndName); verify(strategy.nodeToOrgAndName);
verify(strategy.deleteKeyPair); verify(strategy.deleteKeyPair);
verify(strategy.listNodes); verify(strategy.listNodes);
verify(strategy.credentialStore);
} }
private CleanupOrphanKeys setupStrategy() { private CleanupOrphanKeys setupStrategy() {
NodeMetadataToOrgAndName nodeToOrgAndName = createMock(NodeMetadataToOrgAndName.class); NodeMetadataToOrgAndName nodeToOrgAndName = createMock(NodeMetadataToOrgAndName.class);
DeleteKeyPair deleteKeyPair = createMock(DeleteKeyPair.class); DeleteKeyPair deleteKeyPair = createMock(DeleteKeyPair.class);
ListNodesStrategy listNodes = createMock(ListNodesStrategy.class); ListNodesStrategy listNodes = createMock(ListNodesStrategy.class);
return new CleanupOrphanKeys(nodeToOrgAndName, deleteKeyPair, listNodes); Map<String, Credentials> credentialStore = createMock(Map.class);
return new CleanupOrphanKeys(nodeToOrgAndName, deleteKeyPair, credentialStore, listNodes);
} }
private void replayStrategy(CleanupOrphanKeys strategy) { private void replayStrategy(CleanupOrphanKeys strategy) {
replay(strategy.nodeToOrgAndName); replay(strategy.nodeToOrgAndName);
replay(strategy.deleteKeyPair); replay(strategy.deleteKeyPair);
replay(strategy.listNodes); replay(strategy.listNodes);
replay(strategy.credentialStore);
} }
} }