fixed ec2 to create a new keypair on each time runNodesWithTag; added a test to ensure we can add nodes to a set in a different context than it was created in

This commit is contained in:
Adrian Cole 2010-04-17 00:03:55 -07:00
parent 8ce9f1565a
commit 31d2b08b71
16 changed files with 314 additions and 271 deletions

View File

@ -30,9 +30,9 @@ import org.jclouds.Constants;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.compute.config.EC2ComputeServiceContextModule.GetRegionFromNodeOrDefault;
import org.jclouds.aws.ec2.compute.domain.KeyPairCredentials;
import org.jclouds.aws.ec2.compute.domain.PortsRegionTag;
import org.jclouds.aws.ec2.compute.domain.RegionTag;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.Image;
@ -59,7 +59,7 @@ import com.google.common.collect.Iterables;
public class EC2ComputeService extends BaseComputeService {
protected final EC2Client ec2Client;
protected final GetRegionFromNodeOrDefault getRegionFromNodeOrDefault;
protected final Map<RegionTag, KeyPairCredentials> credentialsMap;
protected final Map<RegionTag, KeyPair> credentialsMap;
protected final Map<PortsRegionTag, String> securityGroupMap;
protected final Predicate<RunningInstance> instanceStateTerminated;
@ -74,8 +74,7 @@ public class EC2ComputeService extends BaseComputeService {
Provider<TemplateBuilder> templateBuilderProvider, ComputeUtils utils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
GetRegionFromNodeOrDefault getRegionFromNodeOrDefault,
Map<RegionTag, KeyPairCredentials> credentialsMap,
Map<PortsRegionTag, String> securityGroupMap,
Map<RegionTag, KeyPair> credentialsMap, Map<PortsRegionTag, String> securityGroupMap,
@Named("TERMINATED") Predicate<RunningInstance> instanceStateTerminated) {
super(context, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy,
@ -98,11 +97,14 @@ public class EC2ComputeService extends BaseComputeService {
}
private void deleteKeyPair(Region region, String tag) {
if (ec2Client.getKeyPairServices().describeKeyPairsInRegion(region, tag).size() > 0) {
logger.debug(">> deleting keyPair(%s)", tag);
ec2Client.getKeyPairServices().deleteKeyPairInRegion(region, tag);
credentialsMap.remove(new RegionTag(region, tag)); // TODO: test this clear happens
logger.debug("<< deleted keyPair(%s)", tag);
for (KeyPair keyPair : ec2Client.getKeyPairServices().describeKeyPairsInRegion(region)) {
if (keyPair.getKeyName().matches(tag + "-[0-9]+")) {
logger.debug(">> deleting keyPair(%s)", tag);
ec2Client.getKeyPairServices().deleteKeyPairInRegion(region, keyPair.getKeyName());
credentialsMap.remove(new RegionTag(region, keyPair.getKeyName())); // TODO: test this
// clear happens
logger.debug("<< deleted keyPair(%s)", keyPair.getKeyName());
}
}
}

View File

@ -40,10 +40,9 @@ import org.jclouds.aws.ec2.EC2AsyncClient;
import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.compute.EC2ComputeService;
import org.jclouds.aws.ec2.compute.domain.EC2Size;
import org.jclouds.aws.ec2.compute.domain.KeyPairCredentials;
import org.jclouds.aws.ec2.compute.domain.PortsRegionTag;
import org.jclouds.aws.ec2.compute.domain.RegionTag;
import org.jclouds.aws.ec2.compute.functions.CreateKeyPairIfNeeded;
import org.jclouds.aws.ec2.compute.functions.CreateNewKeyPair;
import org.jclouds.aws.ec2.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.aws.ec2.compute.functions.ImageParser;
import org.jclouds.aws.ec2.compute.functions.RunningInstanceToNodeMetadata;
@ -51,6 +50,7 @@ import org.jclouds.aws.ec2.compute.strategy.EC2DestroyNodeStrategy;
import org.jclouds.aws.ec2.compute.strategy.EC2RunNodesAndAddToSetStrategy;
import org.jclouds.aws.ec2.config.EC2ContextModule;
import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.services.InstanceClient;
import org.jclouds.compute.ComputeService;
@ -214,7 +214,7 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
@Provides
@Singleton
protected final Map<RegionTag, KeyPairCredentials> credentialsMap(CreateKeyPairIfNeeded in) {
protected final Map<RegionTag, KeyPair> credentialsMap(CreateNewKeyPair in) {
// doesn't seem to clear when someone issues remove(key)
// return new MapMaker().makeComputingMap(in);
return Maps.newLinkedHashMap();

View File

@ -1,24 +1,19 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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
* Licensed 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
* 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.
* 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.aws.ec2.compute.domain;

View File

@ -1,39 +0,0 @@
package org.jclouds.aws.ec2.compute.domain;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.domain.Credentials;
public class KeyPairCredentials extends Credentials {
private final KeyPair keyPair;
public KeyPairCredentials(String account, KeyPair keyPair) {
super(account, keyPair.getKeyMaterial());
this.keyPair = keyPair;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((keyPair == null) ? 0 : keyPair.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
KeyPairCredentials other = (KeyPairCredentials) obj;
if (keyPair == null) {
if (other.keyPair != null)
return false;
} else if (!keyPair.equals(other.keyPair))
return false;
return true;
}
}

View File

@ -1,7 +1,30 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.compute.domain;
import org.jclouds.aws.domain.Region;
/**
*
* @author Adrian Cole
*/
public class PortsRegionTag extends RegionTag {
private final int[] ports;

View File

@ -1,8 +1,29 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.compute.domain;
import org.jclouds.aws.domain.Region;
/**
*
* @author Adrian Cole
*/
public class RegionTag {
protected final Region region;
protected final String tag;

View File

@ -1,54 +0,0 @@
package org.jclouds.aws.ec2.compute.functions;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.compute.domain.KeyPairCredentials;
import org.jclouds.aws.ec2.compute.domain.RegionTag;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
@Singleton
public class CreateKeyPairIfNeeded implements Function<RegionTag, KeyPairCredentials> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final EC2Client ec2Client;
@Inject
public CreateKeyPairIfNeeded(EC2Client ec2Client) {
this.ec2Client = ec2Client;
}
@Override
public KeyPairCredentials apply(RegionTag from) {
return new KeyPairCredentials("root", createKeyPairInRegion(from.getRegion(), from.getTag()));
}
private KeyPair createKeyPairInRegion(Region region, String name) {
logger.debug(">> creating keyPair region(%s) name(%s)", region, name);
KeyPair keyPair;
try {
keyPair = ec2Client.getKeyPairServices().createKeyPairInRegion(region, name);
logger.debug("<< created keyPair(%s)", keyPair.getKeyName());
} catch (AWSResponseException e) {
if (e.getError().getCode().equals("InvalidKeyPair.Duplicate")) {
keyPair = Iterables.getLast(ec2Client.getKeyPairServices().describeKeyPairsInRegion(
region, name));
logger.debug("<< reused keyPair(%s)", keyPair.getKeyName());
} else {
throw e;
}
}
return keyPair;
}
}

View File

@ -0,0 +1,76 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.compute.functions;
import java.security.SecureRandom;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.aws.AWSResponseException;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.compute.domain.RegionTag;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
@Singleton
public class CreateNewKeyPair implements Function<RegionTag, KeyPair> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final EC2Client ec2Client;
@Inject
public CreateNewKeyPair(EC2Client ec2Client) {
this.ec2Client = ec2Client;
}
@Override
public KeyPair apply(RegionTag from) {
return createNewKeyPairInRegion(from.getRegion(), from.getTag());
}
private KeyPair createNewKeyPairInRegion(Region region, String tag) {
logger.debug(">> creating keyPair region(%s) tag(%s)", region, tag);
KeyPair keyPair = null;
while (keyPair == null) {
try {
keyPair = ec2Client.getKeyPairServices().createKeyPairInRegion(region,
tag + "-" + new SecureRandom().nextInt(100));
logger.debug("<< created keyPair(%s)", keyPair.getKeyName());
} catch (AWSResponseException e) {
if (!e.getError().getCode().equals("InvalidKeyPair.Duplicate")) {
throw e;
}
}
}
return keyPair;
}
}

View File

@ -57,14 +57,14 @@ public class ImageParser implements Function<org.jclouds.aws.ec2.domain.Image, I
"9.04").put("karmic", "9.10").put("lucid", "10.04").put("maverick", "10.10")
.build();
@Inject
private PopulateDefaultLoginCredentialsForImageStrategy authenticator;
private final PopulateDefaultLoginCredentialsForImageStrategy credentialProvider;
public void setAuthenticator(PopulateDefaultLoginCredentialsForImageStrategy authenticator) {
this.authenticator = authenticator;
@Inject
ImageParser(PopulateDefaultLoginCredentialsForImageStrategy credentialProvider) {
this.credentialProvider = credentialProvider;
}
@Override
@Override
public Image apply(org.jclouds.aws.ec2.domain.Image from) {
if (from.getImageLocation().indexOf("test") != -1) {
logger.trace("skipping test image(%s)", from.getId());
@ -93,7 +93,7 @@ public class ImageParser implements Function<org.jclouds.aws.ec2.domain.Image, I
logger.debug("<< didn't match os(%s)", matcher.group(1));
}
}
Credentials defaultCredentials = authenticator.execute(from);
Credentials defaultCredentials = credentialProvider.execute(from);
return new ImageImpl(
from.getId(),
@ -106,7 +106,6 @@ public class ImageParser implements Function<org.jclouds.aws.ec2.domain.Image, I
os,
osDescription,
from.getArchitecture() == org.jclouds.aws.ec2.domain.Image.Architecture.I386 ? Architecture.X86_32
: Architecture.X86_64,
defaultCredentials);
: Architecture.X86_64, defaultCredentials);
}
}

View File

@ -1,5 +1,25 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.aws.ec2.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.InetAddress;
import java.net.URI;
import java.util.Map;
@ -8,23 +28,28 @@ import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.aws.ec2.compute.domain.KeyPairCredentials;
import org.jclouds.aws.ec2.compute.domain.RegionTag;
import org.jclouds.aws.ec2.domain.Image;
import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.options.DescribeImagesOptions;
import org.jclouds.aws.ec2.services.AMIClient;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy;
import org.jclouds.domain.Credentials;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
@Singleton
public class RunningInstanceToNodeMetadata implements Function<RunningInstance, NodeMetadata> {
private static final Map<InstanceState, NodeState> instanceToNodeState = ImmutableMap
@ -33,47 +58,56 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
NodeState.PENDING).put(InstanceState.TERMINATED, NodeState.TERMINATED).build();
private final AMIClient amiClient;
private final Map<RegionTag, KeyPairCredentials> credentialsMap;
private final ImageParser imageParser;
private final Map<RegionTag, KeyPair> credentialsMap;
private final PopulateDefaultLoginCredentialsForImageStrategy credentialProvider;
@Inject
public RunningInstanceToNodeMetadata(AMIClient amiClient,
Map<RegionTag, KeyPairCredentials> credentialsMap,
ImageParser imageParser) {
this.amiClient = amiClient;
this.credentialsMap = credentialsMap;
this.imageParser = imageParser;
RunningInstanceToNodeMetadata(AMIClient amiClient, Map<RegionTag, KeyPair> credentialsMap,
PopulateDefaultLoginCredentialsForImageStrategy credentialProvider) {
this.amiClient = checkNotNull(amiClient, "amiClient");
this.credentialsMap = checkNotNull(credentialsMap, "credentialsMap");
this.credentialProvider = checkNotNull(credentialProvider, "credentialProvider");
}
@Override
public NodeMetadata apply(RunningInstance from) {
String id = from.getId();
public NodeMetadata apply(RunningInstance instance) {
String id = checkNotNull(instance, "instance").getId();
String name = null; // user doesn't determine a node name;
URI uri = null; // no uri to get rest access to host info
Map<String, String> userMetadata = ImmutableMap.<String, String> of();
String tag = from.getKeyName();
NodeState state = instanceToNodeState.get(from.getInstanceState());
Set<InetAddress> publicAddresses = nullSafeSet(from.getIpAddress());
Set<InetAddress> privateAddresses = nullSafeSet(from.getPrivateIpAddress());
Credentials credentials = credentialsMap.containsKey(new RegionTag(from.getRegion(), tag)) ? credentialsMap
.get(new RegionTag(from.getRegion(), tag))
: null;
Image image = Iterables.getOnlyElement(amiClient.describeImagesInRegion(from.getRegion(),
DescribeImagesOptions.Builder.imageIds(from.getImageId())));
String tag = instance.getKeyName().replaceAll("-[0-9]+", "");
NodeState state = instanceToNodeState.get(instance.getInstanceState());
// canonical/alestic images use the ubuntu user to login
// TODO: add this as a property of image
if (credentials != null && image.getImageOwnerId().matches("063491364108|099720109477"))
credentials = new Credentials("ubuntu", credentials.key);
Set<InetAddress> publicAddresses = nullSafeSet(instance.getIpAddress());
Set<InetAddress> privateAddresses = nullSafeSet(instance.getPrivateIpAddress());
if(credentials == null) credentials = imageParser.apply(image).getDefaultCredentials();
Credentials credentials = new Credentials(getLoginAccountFor(instance), getPrivateKeyOrNull(
instance, tag));
String locationId = instance.getAvailabilityZone().toString();
String locationId = from.getAvailabilityZone().toString();
Map<String, String> extra = ImmutableMap.<String, String> of();
return new NodeMetadataImpl(id, name, locationId, uri, userMetadata, tag, state,
publicAddresses, privateAddresses, extra, credentials);
}
@VisibleForTesting
String getPrivateKeyOrNull(RunningInstance instance, String tag) {
KeyPair keyPair = credentialsMap.get(new RegionTag(instance.getRegion(), instance
.getKeyName()));
String privateKey = keyPair != null ? keyPair.getKeyMaterial() : null;
return privateKey;
}
@VisibleForTesting
String getLoginAccountFor(RunningInstance from) {
Image image = Iterables.getOnlyElement(amiClient.describeImagesInRegion(from.getRegion(),
DescribeImagesOptions.Builder.imageIds(from.getImageId())));
return checkNotNull(credentialProvider.execute(image), "login from image: "
+ from.getImageId()).account;
}
Set<InetAddress> nullSafeSet(InetAddress in) {
if (in == null) {
return ImmutableSet.<InetAddress> of();

View File

@ -37,13 +37,13 @@ import org.jclouds.Constants;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.ec2.EC2Client;
import org.jclouds.aws.ec2.compute.domain.EC2Size;
import org.jclouds.aws.ec2.compute.domain.KeyPairCredentials;
import org.jclouds.aws.ec2.compute.domain.PortsRegionTag;
import org.jclouds.aws.ec2.compute.domain.RegionTag;
import org.jclouds.aws.ec2.compute.functions.CreateKeyPairIfNeeded;
import org.jclouds.aws.ec2.compute.functions.CreateNewKeyPair;
import org.jclouds.aws.ec2.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.aws.ec2.compute.functions.RunningInstanceToNodeMetadata;
import org.jclouds.aws.ec2.domain.AvailabilityZone;
import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.options.RunInstancesOptions;
@ -84,9 +84,9 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate
};
protected final ComputeService computeService;
protected final EC2Client ec2Client;
protected final Map<RegionTag, KeyPairCredentials> credentialsMap;
protected final Map<RegionTag, KeyPair> credentialsMap;
protected final Map<PortsRegionTag, String> securityGroupMap;
protected final CreateKeyPairIfNeeded createKeyPairIfNeeded;
protected final CreateNewKeyPair createNewKeyPair;
protected final CreateSecurityGroupIfNeeded createSecurityGroupIfNeeded;
protected final Predicate<RunningInstance> instanceStateRunning;
protected final RunningInstanceToNodeMetadata runningInstanceToNodeMetadata;
@ -94,9 +94,8 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate
@Inject
protected EC2RunNodesAndAddToSetStrategy(ComputeService computeService, EC2Client ec2Client,
Map<RegionTag, KeyPairCredentials> credentialsMap,
Map<PortsRegionTag, String> securityGroupMap,
CreateKeyPairIfNeeded createKeyPairIfNeeded,
Map<RegionTag, KeyPair> credentialsMap, Map<PortsRegionTag, String> securityGroupMap,
CreateNewKeyPair createKeyPairIfNeeded,
CreateSecurityGroupIfNeeded createSecurityGroupIfNeeded,
@Named("RUNNING") Predicate<RunningInstance> instanceStateRunning,
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata, ComputeUtils utils,
@ -105,7 +104,7 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate
this.ec2Client = ec2Client;
this.credentialsMap = credentialsMap;
this.securityGroupMap = securityGroupMap;
this.createKeyPairIfNeeded = createKeyPairIfNeeded;
this.createNewKeyPair = createKeyPairIfNeeded;
this.createSecurityGroupIfNeeded = createSecurityGroupIfNeeded;
this.instanceStateRunning = instanceStateRunning;
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
@ -136,9 +135,11 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate
// another thread
// deletes a key
RegionTag regionTag = new RegionTag(region, tag);
if (!credentialsMap.containsKey(regionTag)) {
credentialsMap.put(regionTag, createKeyPairIfNeeded.apply(regionTag));
}
KeyPair keyPair = createNewKeyPair.apply(regionTag);
credentialsMap.put(new RegionTag(region, keyPair.getKeyName()), keyPair);
TemplateOptions options = template.getOptions();
PortsRegionTag portsRegionTag = new PortsRegionTag(region, tag, options.getInboundPorts());
if (!securityGroupMap.containsKey(portsRegionTag)) {
@ -150,7 +151,7 @@ public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrate
">> running %d instance region(%s) zone(%s) ami(%s) type(%s) keyPair(%s) securityGroup(%s)",
count, region, zone, template.getImage().getId(),
ec2Size.getInstanceType(), tag, tag);
RunInstancesOptions instanceOptions = withKeyName(tag)// key
RunInstancesOptions instanceOptions = withKeyName(keyPair.getKeyName())// key
.asType(ec2Size.getInstanceType())// instance size
.withSecurityGroup(tag)// group I created above
.withAdditionalInfo(tag);

View File

@ -21,16 +21,15 @@ package org.jclouds.aws.ec2.compute;
import static org.testng.Assert.assertEquals;
import org.jclouds.compute.BaseComputeServiceLiveTest;
import org.jclouds.compute.domain.*;
import org.jclouds.domain.Credentials;
import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Template;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.collect.Iterables;
import java.util.Map;
/**
*
* @author Adrian Cole
@ -63,17 +62,6 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest {
Architecture.X86_32).imageId("ami-bb709dd2").build();
}
@Test
public void testScriptExecution() throws Exception {
Template simpleTemplate = client.templateBuilder().smallest().build();
client.runNodesWithTag("ec2", 1, simpleTemplate);
Map<String, ? extends NodeMetadata> map = client.getNodesWithTag("ec2");
map.values().iterator().next();
Credentials creds = new Credentials("ubuntu", keyPair.get("public"));
client.runScriptOnNodesWithTag("ec2", "mkdir ~/ahha; sleep 3".getBytes());
client.destroyNodesWithTag("ec2");
}
@Override
protected JschSshClientModule getSshModule() {
return new JschSshClientModule();

View File

@ -16,7 +16,7 @@
* limitations under the License.
* ====================================================================
*/
package org.jclouds.aws.ec2.functions;
package org.jclouds.aws.ec2.compute.functions;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
@ -27,7 +27,6 @@ import java.io.InputStream;
import java.util.Set;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.ec2.compute.functions.ImageParser;
import org.jclouds.aws.ec2.compute.strategy.EC2PopulateDefaultLoginCredentialsForImageStrategy;
import org.jclouds.aws.ec2.domain.Image;
import org.jclouds.aws.ec2.xml.DescribeImagesResponseHandler;
@ -52,8 +51,7 @@ public class ImageParserTest extends BaseHandlerTest {
Set<Image> result = parseImages(is);
assertEquals(result.size(), 6);
ImageParser parser = new ImageParser();
parser.setAuthenticator(new EC2PopulateDefaultLoginCredentialsForImageStrategy());
ImageParser parser = new ImageParser(new EC2PopulateDefaultLoginCredentialsForImageStrategy());
org.jclouds.compute.domain.Image ubuntuHardy = parser.apply(Iterables.get(result, 0));
assertEquals(ubuntuHardy.getArchitecture(), org.jclouds.compute.domain.Architecture.X86_32);
@ -116,7 +114,7 @@ public class ImageParserTest extends BaseHandlerTest {
assertEquals(alesticHardy.getUserMetadata(), ImmutableMap.<String, String> of("owner",
"063491364108"));
assertEquals(alesticHardy.getVersion(), "20080905");
// should skip kernel
assert parser.apply(Iterables.get(result, 5)) == null;
}
@ -126,8 +124,7 @@ public class ImageParserTest extends BaseHandlerTest {
Set<Image> result = parseImages(is);
ImageParser parser = new ImageParser();
parser.setAuthenticator(new EC2PopulateDefaultLoginCredentialsForImageStrategy());
ImageParser parser = new ImageParser(new EC2PopulateDefaultLoginCredentialsForImageStrategy());
org.jclouds.compute.domain.Image image = parser.apply(Iterables.get(result, 0));

View File

@ -44,6 +44,8 @@ import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
@ -60,6 +62,7 @@ import org.testng.annotations.Test;
import com.google.common.base.Charsets;
import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@ -109,20 +112,26 @@ public abstract class BaseComputeServiceLiveTest {
String secret = Files.toString(new File(secretKeyFile), Charsets.UTF_8);
assert secret.startsWith("-----BEGIN RSA PRIVATE KEY-----") : "invalid key:\n" + secret;
context = new ComputeServiceContextFactory().createContext(service, user, password,
ImmutableSet.of(new Log4JLoggingModule(), getSshModule()));
initializeContextAndClient();
Injector injector = Guice.createInjector(getSshModule());
sshFactory = injector.getInstance(SshClient.Factory.class);
SocketOpen socketOpen = injector.getInstance(SocketOpen.class);
socketTester = new RetryablePredicate<InetSocketAddress>(socketOpen, 60, 1, TimeUnit.SECONDS);
injector.injectMembers(socketOpen); // add logger
client = context.getComputeService();
// keyPair = sshFactory.generateRSAKeyPair("", "");
keyPair = ImmutableMap.<String, String> of("private", secret, "public", Files.toString(
new File(secretKeyFile + ".pub"), Charsets.UTF_8));
}
private void initializeContextAndClient() throws IOException {
if (context != null)
context.close();
context = new ComputeServiceContextFactory().createContext(service, user, password,
ImmutableSet.of(new Log4JLoggingModule(), getSshModule()));
client = context.getComputeService();
}
private void checkSecretKeyFile(String secretKeyFile) throws FileNotFoundException {
Utils.checkNotEmpty(secretKeyFile,
"System property: [jclouds.test.ssh.keyfile] set to an empty string");
@ -140,7 +149,7 @@ public abstract class BaseComputeServiceLiveTest {
}
@Test(dependsOnMethods = "testTemplateMatch")
public void testCreate() throws Exception {
public void testCreateTwoNodesWithRunScript() throws Exception {
try {
client.destroyNodesWithTag(tag);
} catch (HttpResponseException e) {
@ -155,20 +164,56 @@ public abstract class BaseComputeServiceLiveTest {
buildScript(template.getImage().getOsFamily()).getBytes());
nodes = Sets.newTreeSet(client.runNodesWithTag(tag, 2, template).values());
assertEquals(nodes.size(), 2);
checkNodes();
checkNodes(nodes, tag);
NodeMetadata node1 = nodes.first();
NodeMetadata node2 = nodes.last();
// credentials aren't always the same
// assertEquals(node1.getCredentials(), node2.getCredentials());
assert !node1.getId().equals(node2.getId());
// run one more
nodes.addAll(client.runNodesWithTag(tag, 1, template).values());
assertEquals(nodes.size(), 3);
checkNodes();
}
private void checkNodes() throws IOException {
@Test(dependsOnMethods = "testCreateTwoNodesWithRunScript")
public void testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired() throws Exception {
initializeContextAndClient();
checkNodes(client.runNodesWithTag(tag, 1, template).values(), tag);
}
@Test
public void testScriptExecutionAfterBootWithBasicTemplate() throws Exception {
String tag = this.tag + "script";
Template simpleTemplate = buildTemplate(client.templateBuilder());
simpleTemplate.getOptions().blockOnPort(22, 60);
try {
Map<String, ? extends NodeMetadata> nodes = client.runNodesWithTag(tag, 1, simpleTemplate);
Credentials good = nodes.values().iterator().next().getCredentials();
assert good.account != null;
try {
runScriptWithCreds(tag, simpleTemplate.getImage().getOsFamily(), new Credentials(
good.account, "romeo"));
assert false : "shouldn't pass with a bad password";
} catch (SshException e) {
assert Throwables.getRootCause(e).getMessage().contains("Auth fail") : e;
}
runScriptWithCreds(tag, simpleTemplate.getImage().getOsFamily(), good);
checkNodes(nodes.values(), tag);
} finally {
client.destroyNodesWithTag(tag);
}
}
private Map<String, ExecResponse> runScriptWithCreds(String tag, OsFamily osFamily,
Credentials creds) {
return client.runScriptOnNodesWithTag(tag, buildScript(osFamily).getBytes(),
RunScriptOptions.Builder.overrideCredentialsWith(creds));
}
private void checkNodes(Iterable<? extends NodeMetadata> nodes, String tag) throws IOException {
for (NodeMetadata node : nodes) {
assertNotNull(node.getId());
assertNotNull(node.getTag());
@ -191,7 +236,6 @@ public abstract class BaseComputeServiceLiveTest {
protected String buildScript(OsFamily osFamily) {
switch (osFamily) {
case JEOS:
case UBUNTU:
return new StringBuilder()//
.append("echo nameserver 208.67.222.222 >> /etc/resolv.conf\n")//
@ -221,7 +265,7 @@ public abstract class BaseComputeServiceLiveTest {
}
}
@Test(enabled = true, dependsOnMethods = "testCreate")
@Test(enabled = true, dependsOnMethods = "testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired")
public void testGet() throws Exception {
Set<? extends NodeMetadata> metadataSet = Sets.newHashSet(client.getNodesWithTag(tag)
.values());
@ -291,7 +335,7 @@ public abstract class BaseComputeServiceLiveTest {
private void sshPing(NodeMetadata node) throws IOException {
for (int i = 0; i < 5; i++) {// retry loop TODO replace with predicate.
try {
doCheckKey(node);
doCheckJavaIsInstalledViaSsh(node);
return;
} catch (SshException e) {
try {
@ -303,7 +347,7 @@ public abstract class BaseComputeServiceLiveTest {
}
}
protected void doCheckKey(NodeMetadata node) throws IOException {
protected void doCheckJavaIsInstalledViaSsh(NodeMetadata node) throws IOException {
InetSocketAddress socket = new InetSocketAddress(Iterables.get(node.getPublicAddresses(), 0),
22);
socketTester.apply(socket); // TODO add transitionTo option that accepts a socket conection

View File

@ -19,90 +19,46 @@
package org.jclouds.gogrid;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Map;
import org.jclouds.compute.BaseComputeServiceLiveTest;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.domain.Credentials;
import org.jclouds.rest.RestContext;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
/**
* @author Oleksiy Yarmula
*/
@Test(groups = "live", enabled = true, sequential = true, testName = "gogrid.GoGridComputeServiceLiveTest")
public class GoGridComputeServiceLiveTest extends BaseComputeServiceLiveTest {
@BeforeClass
@Override
public void setServiceDefaults() {
service = "gogrid";
}
@BeforeClass
@Override
public void setServiceDefaults() {
service = "gogrid";
}
@Test
public void testTemplateBuilder() {
Template defaultTemplate = client.templateBuilder().build();
assertEquals(defaultTemplate.getImage().getArchitecture(), Architecture.X86_64);
assertEquals(defaultTemplate.getImage().getOsFamily(), OsFamily.CENTOS);
assertEquals(defaultTemplate.getLocation().getId(), "SANFRANCISCO");
assertEquals(defaultTemplate.getSize().getCores(), 1.0d);
}
@Test
public void testTemplateBuilder() {
Template defaultTemplate = client.templateBuilder().build();
assertEquals(defaultTemplate.getImage().getArchitecture(), Architecture.X86_64);
assertEquals(defaultTemplate.getImage().getOsFamily(), OsFamily.CENTOS);
assertEquals(defaultTemplate.getLocation().getId(), "SANFRANCISCO");
assertEquals(defaultTemplate.getSize().getCores(), 1.0d);
}
@Override
protected JschSshClientModule getSshModule() {
return new JschSshClientModule();
}
@Override
protected JschSshClientModule getSshModule() {
return new JschSshClientModule();
}
public void testAssignability() throws Exception {
@SuppressWarnings("unused")
RestContext<GoGridAsyncClient, GoGridClient> goGridContext = new ComputeServiceContextFactory()
.createContext(service, user, password).getProviderSpecificContext();
}
@Test(enabled = true)
public void endToEndComputeServiceTest() {
ComputeService service = context.getComputeService();
Template t = service.templateBuilder().minRam(1024).imageId("1532").build();
assertEquals(t.getImage().getId(), "1532");
service.runNodesWithTag(this.service, 3, t);
Map<String, ? extends ComputeMetadata> nodes = service.getNodes();
ComputeMetadata node = Iterables.find(nodes.values(), new Predicate<ComputeMetadata>() {
@Override
public boolean apply(ComputeMetadata computeMetadata) {
return computeMetadata.getName().startsWith(GoGridComputeServiceLiveTest.this.service);
}
});
NodeMetadata nodeMetadata = service.getNodeMetadata(node);
assertEquals(nodeMetadata.getPublicAddresses().size(), 1,
"There must be 1 public address for the node");
assertTrue(nodeMetadata.getName().startsWith(this.service));
service.rebootNode(nodeMetadata); // blocks until finished
assertEquals(service.getNodeMetadata(nodeMetadata).getState(), NodeState.RUNNING);
client.runScriptOnNodesWithTag("gogrid",
"mkdir ~/ahha; sleep 3".getBytes(),
new RunScriptOptions.Builder().overrideCredentials(new Credentials("root", null)).build());
service.destroyNodesWithTag("gogrid");
}
public void testAssignability() throws Exception {
@SuppressWarnings("unused")
RestContext<GoGridAsyncClient, GoGridClient> goGridContext = new ComputeServiceContextFactory()
.createContext(service, user, password).getProviderSpecificContext();
}
}

View File

@ -53,8 +53,8 @@ public class HostingDotComVCloudComputeServiceLiveTest extends VCloudComputeServ
// Takes too long
@Override
@Test(enabled = false)
public void testCreate() throws Exception {
super.testCreate();
public void testCreateTwoNodesWithRunScript() throws Exception {
super.testCreateTwoNodesWithRunScript();
}
@Override