mirror of https://github.com/apache/jclouds.git
Issue 249: new extended options for ec2, including securityGroups, keyPair, and noKeyPair
This commit is contained in:
parent
25fd278ecf
commit
b6189457d5
|
@ -22,7 +22,7 @@ import java.util.List;
|
|||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.aws.ec2.compute.config.EC2ComputeServiceContextModule;
|
||||
import org.jclouds.aws.ec2.compute.config.internal.EC2ResolveImagesModule;
|
||||
import org.jclouds.aws.ec2.compute.config.EC2ResolveImagesModule;
|
||||
import org.jclouds.aws.ec2.config.EC2RestClientModule;
|
||||
import org.jclouds.compute.ComputeServiceContextBuilder;
|
||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.jclouds.aws.ec2.compute;
|
||||
|
||||
import static org.jclouds.util.Utils.checkNotEmpty;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
@ -31,10 +33,9 @@ import javax.inject.Singleton;
|
|||
import org.jclouds.Constants;
|
||||
import org.jclouds.aws.ec2.EC2Client;
|
||||
import org.jclouds.aws.ec2.compute.config.EC2ComputeServiceContextModule.GetRegionFromNodeOrDefault;
|
||||
import org.jclouds.aws.ec2.compute.domain.PortsRegionTag;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionTag;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionNameAndIngressRules;
|
||||
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;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
|
@ -48,10 +49,8 @@ import org.jclouds.compute.strategy.RebootNodeStrategy;
|
|||
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
|
||||
import org.jclouds.compute.util.ComputeUtils;
|
||||
import org.jclouds.domain.Location;
|
||||
import static org.jclouds.util.Utils.*;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
|
@ -60,11 +59,10 @@ import com.google.common.collect.Sets;
|
|||
*/
|
||||
@Singleton
|
||||
public class EC2ComputeService extends BaseComputeService {
|
||||
protected final EC2Client ec2Client;
|
||||
protected final GetRegionFromNodeOrDefault getRegionFromNodeOrDefault;
|
||||
protected final Map<RegionTag, KeyPair> credentialsMap;
|
||||
protected final Map<PortsRegionTag, String> securityGroupMap;
|
||||
protected final Predicate<RunningInstance> instanceStateTerminated;
|
||||
private final EC2Client ec2Client;
|
||||
private final GetRegionFromNodeOrDefault getRegionFromNodeOrDefault;
|
||||
private final Map<RegionAndName, KeyPair> credentialsMap;
|
||||
private final Map<RegionAndName, String> securityGroupMap;
|
||||
|
||||
@Inject
|
||||
protected EC2ComputeService(ComputeServiceContext context,
|
||||
|
@ -76,8 +74,8 @@ public class EC2ComputeService extends BaseComputeService {
|
|||
Provider<TemplateBuilder> templateBuilderProvider, ComputeUtils utils,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
|
||||
GetRegionFromNodeOrDefault getRegionFromNodeOrDefault,
|
||||
Map<RegionTag, KeyPair> credentialsMap, Map<PortsRegionTag, String> securityGroupMap,
|
||||
@Named("TERMINATED") Predicate<RunningInstance> instanceStateTerminated) {
|
||||
Map<RegionAndName, KeyPair> credentialsMap,
|
||||
Map<RegionAndName, String> securityGroupMap) {
|
||||
super(context, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
||||
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy,
|
||||
templateBuilderProvider, utils, executor);
|
||||
|
@ -85,7 +83,6 @@ public class EC2ComputeService extends BaseComputeService {
|
|||
this.getRegionFromNodeOrDefault = getRegionFromNodeOrDefault;
|
||||
this.credentialsMap = credentialsMap;
|
||||
this.securityGroupMap = securityGroupMap;
|
||||
this.instanceStateTerminated = instanceStateTerminated;
|
||||
}
|
||||
|
||||
private void deleteSecurityGroup(String region, String tag) {
|
||||
|
@ -94,8 +91,8 @@ public class EC2ComputeService extends BaseComputeService {
|
|||
if (ec2Client.getSecurityGroupServices().describeSecurityGroupsInRegion(region, group).size() > 0) {
|
||||
logger.debug(">> deleting securityGroup(%s)", group);
|
||||
ec2Client.getSecurityGroupServices().deleteSecurityGroupInRegion(region, group);
|
||||
securityGroupMap.remove(new PortsRegionTag(region, tag, null)); // TODO: test this clear
|
||||
// happens
|
||||
// TODO: test this clear happens
|
||||
securityGroupMap.remove(new RegionNameAndIngressRules(region, tag, null, false));
|
||||
logger.debug("<< deleted securityGroup(%s)", group);
|
||||
}
|
||||
}
|
||||
|
@ -105,8 +102,8 @@ public class EC2ComputeService extends BaseComputeService {
|
|||
if (keyPair.getKeyName().matches("jclouds#" + tag + "-[0-9]+")) {
|
||||
logger.debug(">> deleting keyPair(%s)", keyPair.getKeyName());
|
||||
ec2Client.getKeyPairServices().deleteKeyPairInRegion(region, keyPair.getKeyName());
|
||||
credentialsMap.remove(new RegionTag(region, keyPair.getKeyName())); // TODO: test this
|
||||
// clear happens
|
||||
// TODO: test this clear happens
|
||||
credentialsMap.remove(new RegionAndName(region, keyPair.getKeyName()));
|
||||
logger.debug("<< deleted keyPair(%s)", keyPair.getKeyName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS
|
|||
import static org.jclouds.compute.domain.OsFamily.UBUNTU;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
@ -40,12 +41,12 @@ 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.PortsRegionTag;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionTag;
|
||||
import org.jclouds.aws.ec2.compute.functions.CreateNewKeyPair;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.aws.ec2.compute.functions.CreateSecurityGroupIfNeeded;
|
||||
import org.jclouds.aws.ec2.compute.functions.CreateUniqueKeyPair;
|
||||
import org.jclouds.aws.ec2.compute.functions.ImageParser;
|
||||
import org.jclouds.aws.ec2.compute.functions.RunningInstanceToNodeMetadata;
|
||||
import org.jclouds.aws.ec2.compute.options.EC2TemplateOptions;
|
||||
import org.jclouds.aws.ec2.compute.strategy.EC2DestroyNodeStrategy;
|
||||
import org.jclouds.aws.ec2.compute.strategy.EC2RunNodesAndAddToSetStrategy;
|
||||
import org.jclouds.aws.ec2.config.EC2ContextModule;
|
||||
|
@ -64,6 +65,7 @@ import org.jclouds.compute.domain.TemplateBuilder;
|
|||
import org.jclouds.compute.internal.ComputeServiceContextImpl;
|
||||
import org.jclouds.compute.internal.TemplateBuilderImpl;
|
||||
import org.jclouds.compute.options.GetNodesOptions;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.predicates.ScriptStatusReturnsZero;
|
||||
import org.jclouds.compute.predicates.ScriptStatusReturnsZero.CommandUsingClient;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
|
@ -84,6 +86,7 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
|
@ -108,6 +111,7 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
|
|||
@Override
|
||||
protected void configure() {
|
||||
super.configure();
|
||||
bind(TemplateOptions.class).to(EC2TemplateOptions.class);
|
||||
bind(ComputeService.class).to(EC2ComputeService.class);
|
||||
bind(RunNodesAndAddToSetStrategy.class).to(EC2RunNodesAndAddToSetStrategy.class);
|
||||
bind(ListNodesStrategy.class).to(EC2ListNodesStrategy.class);
|
||||
|
@ -119,6 +123,20 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
|
|||
.in(Scopes.SINGLETON);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Supplier<String> provideSuffix() {
|
||||
return new Supplier<String>() {
|
||||
final SecureRandom random = new SecureRandom();
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
return random.nextInt(100) + "";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@Provides
|
||||
TemplateBuilder provideTemplate(TemplateBuilderImpl template) {
|
||||
return template.architecture(Architecture.X86_32).osFamily(UBUNTU);
|
||||
|
@ -220,7 +238,7 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected final Map<RegionTag, KeyPair> credentialsMap(CreateNewKeyPair in) {
|
||||
protected final Map<RegionAndName, KeyPair> credentialsMap(CreateUniqueKeyPair in) {
|
||||
// doesn't seem to clear when someone issues remove(key)
|
||||
// return new MapMaker().makeComputingMap(in);
|
||||
return Maps.newLinkedHashMap();
|
||||
|
@ -228,7 +246,7 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected final Map<PortsRegionTag, String> securityGroupMap(CreateSecurityGroupIfNeeded in) {
|
||||
protected final Map<RegionAndName, String> securityGroupMap(CreateSecurityGroupIfNeeded in) {
|
||||
// doesn't seem to clear when someone issues remove(key)
|
||||
// return new MapMaker().makeComputingMap(in);
|
||||
return Maps.newLinkedHashMap();
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.aws.ec2.compute.config.internal;
|
||||
package org.jclouds.aws.ec2.compute.config;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import org.jclouds.aws.ec2.compute.strategy.EC2PopulateDefaultLoginCredentialsForImageStrategy;
|
|
@ -22,13 +22,13 @@ package org.jclouds.aws.ec2.compute.domain;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class RegionTag {
|
||||
public class RegionAndName {
|
||||
protected final String region;
|
||||
protected final String tag;
|
||||
protected final String name;
|
||||
|
||||
public RegionTag(String region, String tag) {
|
||||
public RegionAndName(String region, String name) {
|
||||
this.region = region;
|
||||
this.tag = tag;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -36,7 +36,7 @@ public class RegionTag {
|
|||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((region == null) ? 0 : region.hashCode());
|
||||
result = prime * result + ((tag == null) ? 0 : tag.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -48,16 +48,16 @@ public class RegionTag {
|
|||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
RegionTag other = (RegionTag) obj;
|
||||
RegionAndName other = (RegionAndName) obj;
|
||||
if (region == null) {
|
||||
if (other.region != null)
|
||||
return false;
|
||||
} else if (!region.equals(other.region))
|
||||
return false;
|
||||
if (tag == null) {
|
||||
if (other.tag != null)
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!tag.equals(other.tag))
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -66,13 +66,13 @@ public class RegionTag {
|
|||
return region;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RegionTag [region=" + region + ", tag=" + tag + "]";
|
||||
return "RegionTag [region=" + region + ", name=" + name + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -23,12 +23,14 @@ package org.jclouds.aws.ec2.compute.domain;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class PortsRegionTag extends RegionTag {
|
||||
public class RegionNameAndIngressRules extends RegionAndName {
|
||||
private final int[] ports;
|
||||
private final boolean authorizeSelf;
|
||||
|
||||
public PortsRegionTag(String region, String tag, int[] ports) {
|
||||
public RegionNameAndIngressRules(String region, String tag, int[] ports, boolean authorizeSelf) {
|
||||
super(region, tag);
|
||||
this.ports = ports;
|
||||
this.authorizeSelf = authorizeSelf;
|
||||
}
|
||||
|
||||
// intentionally not overriding equals or hash-code so that we can search only by region/tag in a
|
||||
|
@ -38,4 +40,8 @@ public class PortsRegionTag extends RegionTag {
|
|||
return ports;
|
||||
}
|
||||
|
||||
public boolean shouldAuthorizeSelf() {
|
||||
return authorizeSelf;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,3 +1,21 @@
|
|||
/**
|
||||
*
|
||||
* 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;
|
||||
|
@ -9,7 +27,7 @@ import javax.inject.Singleton;
|
|||
|
||||
import org.jclouds.aws.AWSResponseException;
|
||||
import org.jclouds.aws.ec2.EC2Client;
|
||||
import org.jclouds.aws.ec2.compute.domain.PortsRegionTag;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionNameAndIngressRules;
|
||||
import org.jclouds.aws.ec2.domain.IpProtocol;
|
||||
import org.jclouds.aws.ec2.domain.UserIdGroupPair;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
|
@ -18,8 +36,12 @@ import org.jclouds.logging.Logger;
|
|||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class CreateSecurityGroupIfNeeded implements Function<PortsRegionTag, String> {
|
||||
public class CreateSecurityGroupIfNeeded implements Function<RegionNameAndIngressRules, String> {
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
@ -31,9 +53,9 @@ public class CreateSecurityGroupIfNeeded implements Function<PortsRegionTag, Str
|
|||
}
|
||||
|
||||
@Override
|
||||
public String apply(PortsRegionTag from) {
|
||||
createSecurityGroupInRegion(from.getRegion(), from.getTag(), from.getPorts());
|
||||
return from.getTag();
|
||||
public String apply(RegionNameAndIngressRules from) {
|
||||
createSecurityGroupInRegion(from.getRegion(), from.getName(), from.getPorts());
|
||||
return from.getName();
|
||||
}
|
||||
|
||||
private void createSecurityGroupInRegion(String region, String name, int... ports) {
|
||||
|
@ -44,21 +66,11 @@ public class CreateSecurityGroupIfNeeded implements Function<PortsRegionTag, Str
|
|||
ec2Client.getSecurityGroupServices().createSecurityGroupInRegion(region, name, name);
|
||||
logger.debug("<< created securityGroup(%s)", name);
|
||||
for (int port : ports) {
|
||||
logger.debug(">> authorizing securityGroup region(%s) name(%s) port(%s)", region, name,
|
||||
port);
|
||||
ec2Client.getSecurityGroupServices().authorizeSecurityGroupIngressInRegion(region,
|
||||
name, IpProtocol.TCP, port, port, "0.0.0.0/0");
|
||||
logger.debug("<< authorized securityGroup(%s)", name);
|
||||
createIngressRuleForTCPPort(region, name, port);
|
||||
}
|
||||
if (ports.length > 0) {
|
||||
authorizeGroupToItself(region, name);
|
||||
}
|
||||
logger.debug(">> authorizing securityGroup region(%s) name(%s) permission to itself",
|
||||
region, name);
|
||||
String myOwnerId = Iterables.get(
|
||||
ec2Client.getSecurityGroupServices().describeSecurityGroupsInRegion(region), 0)
|
||||
.getOwnerId();
|
||||
ec2Client.getSecurityGroupServices().authorizeSecurityGroupIngressInRegion(region, name,
|
||||
new UserIdGroupPair(myOwnerId, name));
|
||||
logger.debug("<< authorized securityGroup(%s)", name);
|
||||
|
||||
} catch (AWSResponseException e) {
|
||||
if (e.getError().getCode().equals("InvalidGroup.Duplicate")) {
|
||||
logger.debug("<< reused securityGroup(%s)", name);
|
||||
|
@ -68,4 +80,22 @@ public class CreateSecurityGroupIfNeeded implements Function<PortsRegionTag, Str
|
|||
}
|
||||
}
|
||||
|
||||
private void createIngressRuleForTCPPort(String region, String name, int port) {
|
||||
logger.debug(">> authorizing securityGroup region(%s) name(%s) port(%s)", region, name, port);
|
||||
ec2Client.getSecurityGroupServices().authorizeSecurityGroupIngressInRegion(region, name,
|
||||
IpProtocol.TCP, port, port, "0.0.0.0/0");
|
||||
logger.debug("<< authorized securityGroup(%s)", name);
|
||||
}
|
||||
|
||||
private void authorizeGroupToItself(String region, String name) {
|
||||
logger.debug(">> authorizing securityGroup region(%s) name(%s) permission to itself", region,
|
||||
name);
|
||||
String myOwnerId = Iterables.get(
|
||||
ec2Client.getSecurityGroupServices().describeSecurityGroupsInRegion(region), 0)
|
||||
.getOwnerId();
|
||||
ec2Client.getSecurityGroupServices().authorizeSecurityGroupIngressInRegion(region, name,
|
||||
new UserIdGroupPair(myOwnerId, name));
|
||||
logger.debug("<< authorized securityGroup(%s)", name);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@ package org.jclouds.aws.ec2.compute.functions;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
@ -30,43 +28,46 @@ import javax.inject.Singleton;
|
|||
|
||||
import org.jclouds.aws.AWSResponseException;
|
||||
import org.jclouds.aws.ec2.EC2Client;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionTag;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionAndName;
|
||||
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.base.Supplier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class CreateNewKeyPair implements Function<RegionTag, KeyPair> {
|
||||
public class CreateUniqueKeyPair implements Function<RegionAndName, KeyPair> {
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
protected final EC2Client ec2Client;
|
||||
protected Supplier<String> randomSuffix;
|
||||
|
||||
@Inject
|
||||
public CreateNewKeyPair(EC2Client ec2Client) {
|
||||
public CreateUniqueKeyPair(EC2Client ec2Client, Supplier<String> randomSuffix) {
|
||||
this.ec2Client = ec2Client;
|
||||
this.randomSuffix = randomSuffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyPair apply(RegionTag from) {
|
||||
return createNewKeyPairInRegion(from.getRegion(), from.getTag());
|
||||
public KeyPair apply(RegionAndName from) {
|
||||
return createNewKeyPairInRegion(from.getRegion(), from.getName());
|
||||
}
|
||||
|
||||
private KeyPair createNewKeyPairInRegion(String region, String tag) {
|
||||
private KeyPair createNewKeyPairInRegion(String region, String keyPairName) {
|
||||
checkNotNull(region, "region");
|
||||
checkNotNull(tag, "tag");
|
||||
logger.debug(">> creating keyPair region(%s) tag(%s)", region, tag);
|
||||
checkNotNull(keyPairName, "keyPairName");
|
||||
logger.debug(">> creating keyPair region(%s) keyPairName(%s)", region, keyPairName);
|
||||
KeyPair keyPair = null;
|
||||
while (keyPair == null) {
|
||||
try {
|
||||
keyPair = ec2Client.getKeyPairServices().createKeyPairInRegion(region,
|
||||
"jclouds#" + tag + "-" + new SecureRandom().nextInt(100));
|
||||
getNextName(keyPairName));
|
||||
logger.debug("<< created keyPair(%s)", keyPair.getKeyName());
|
||||
} catch (AWSResponseException e) {
|
||||
if (!e.getError().getCode().equals("InvalidKeyPair.Duplicate")) {
|
||||
|
@ -76,4 +77,8 @@ public class CreateNewKeyPair implements Function<RegionTag, KeyPair> {
|
|||
}
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
private String getNextName(String keyPairName) {
|
||||
return "jclouds#" + keyPairName + "-" + randomSuffix.get();
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ import javax.inject.Inject;
|
|||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionTag;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.aws.ec2.domain.InstanceState;
|
||||
import org.jclouds.aws.ec2.domain.KeyPair;
|
||||
import org.jclouds.aws.ec2.domain.RunningInstance;
|
||||
|
@ -86,7 +86,7 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
|
|||
NodeState.PENDING).put(InstanceState.TERMINATED, NodeState.TERMINATED).build();
|
||||
|
||||
private final AMIClient amiClient;
|
||||
private final Map<RegionTag, KeyPair> credentialsMap;
|
||||
private final Map<RegionAndName, KeyPair> credentialsMap;
|
||||
private final PopulateDefaultLoginCredentialsForImageStrategy credentialProvider;
|
||||
private final Set<? extends Image> images;
|
||||
private final Set<? extends Location> locations;
|
||||
|
@ -95,7 +95,7 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
|
|||
@Inject
|
||||
RunningInstanceToNodeMetadata(
|
||||
AMIClient amiClient,
|
||||
Map<RegionTag, KeyPair> credentialsMap,
|
||||
Map<RegionAndName, KeyPair> credentialsMap,
|
||||
PopulateDefaultLoginCredentialsForImageStrategy credentialProvider,
|
||||
Set<? extends Image> images,
|
||||
Set<? extends Location> locations,
|
||||
|
@ -194,7 +194,7 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
|
|||
|
||||
@VisibleForTesting
|
||||
String getPrivateKeyOrNull(RunningInstance instance, String tag) {
|
||||
KeyPair keyPair = credentialsMap.get(new RegionTag(instance.getRegion(), instance
|
||||
KeyPair keyPair = credentialsMap.get(new RegionAndName(instance.getRegion(), instance
|
||||
.getKeyName()));
|
||||
return keyPair != null ? keyPair.getKeyMaterial() : null;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,303 @@
|
|||
/**
|
||||
*
|
||||
* 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.options;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* Contains options supported in the {@code ComputeService#runNode} operation on the "ec2" provider.
|
||||
* <h2>
|
||||
* Usage</h2> The recommended way to instantiate a EC2TemplateOptions object is to statically import
|
||||
* EC2TemplateOptions.* and invoke a static creation method followed by an instance mutator (if
|
||||
* needed):
|
||||
* <p/>
|
||||
* <code>
|
||||
* import static org.jclouds.aws.ec2.compute.options.EC2TemplateOptions.Builder.*;
|
||||
* <p/>
|
||||
* ComputeService client = // get connection
|
||||
* templateBuilder.options(inboundPorts(22, 80, 8080, 443));
|
||||
* Set<? extends NodeMetadata> set = client.runNodesWithTag(tag, 2, templateBuilder.build());
|
||||
* <code>
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class EC2TemplateOptions extends TemplateOptions {
|
||||
|
||||
private Set<String> groupIds = ImmutableSet.of();
|
||||
private String keyPair = null;
|
||||
private boolean noKeyPair;
|
||||
|
||||
public static final EC2TemplateOptions NONE = new EC2TemplateOptions();
|
||||
|
||||
/**
|
||||
*
|
||||
* @see EC2TemplateOptions#securityGroups(Iterable<String>)
|
||||
*/
|
||||
public EC2TemplateOptions securityGroups(String... groupIds) {
|
||||
return securityGroups(ImmutableSet.copyOf(groupIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the security groups to be used for nodes with this template
|
||||
*/
|
||||
public EC2TemplateOptions securityGroups(Iterable<String> groupIds) {
|
||||
checkArgument(Iterables.size(groupIds) > 0, "you must specify at least one security group");
|
||||
for (String groupId : groupIds)
|
||||
Utils.checkNotEmpty(groupId, "all security groups must be non-empty");
|
||||
this.groupIds = ImmutableSet.copyOf(groupIds);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the keypair used to run instances with
|
||||
*/
|
||||
public EC2TemplateOptions keyPair(String keyPair) {
|
||||
checkNotNull(keyPair, "use noKeyPair option to request boot without a keypair");
|
||||
checkState(!noKeyPair, "you cannot specify both options keyPair and noKeyPair");
|
||||
Utils.checkNotEmpty(keyPair, "keypair must be non-empty");
|
||||
this.keyPair = keyPair;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not use a keypair on instances
|
||||
*/
|
||||
public EC2TemplateOptions noKeyPair() {
|
||||
checkState(keyPair == null, "you cannot specify both options keyPair and noKeyPair");
|
||||
this.noKeyPair = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
/**
|
||||
* @see EC2TemplateOptions#securityGroups(Iterable<String>)
|
||||
*/
|
||||
public static EC2TemplateOptions securityGroups(String... groupIds) {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
return EC2TemplateOptions.class.cast(options.securityGroups(groupIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EC2TemplateOptions#securityGroups(Iterable<String>)
|
||||
*/
|
||||
public static EC2TemplateOptions securityGroups(Iterable<String> groupIds) {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
return EC2TemplateOptions.class.cast(options.securityGroups(groupIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EC2TemplateOptions#keyPair
|
||||
*/
|
||||
public static EC2TemplateOptions keyPair(String keyPair) {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
return EC2TemplateOptions.class.cast(options.keyPair(keyPair));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EC2TemplateOptions#noKeyPair
|
||||
*/
|
||||
public static EC2TemplateOptions noKeyPair() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
return EC2TemplateOptions.class.cast(options.noKeyPair());
|
||||
}
|
||||
|
||||
// methods that only facilitate returning the correct object type
|
||||
/**
|
||||
* @see TemplateOptions#inboundPorts
|
||||
*/
|
||||
public static EC2TemplateOptions inboundPorts(int... ports) {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
return EC2TemplateOptions.class.cast(options.inboundPorts(ports));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TemplateOptions#port
|
||||
*/
|
||||
public static EC2TemplateOptions blockOnPort(int port, int seconds) {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
return EC2TemplateOptions.class.cast(options.blockOnPort(port, seconds));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TemplateOptions#runScript
|
||||
*/
|
||||
public static EC2TemplateOptions runScript(byte[] script) {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
return EC2TemplateOptions.class.cast(options.runScript(script));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TemplateOptions#installPrivateKey
|
||||
*/
|
||||
public static EC2TemplateOptions installPrivateKey(String rsaKey) {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
return EC2TemplateOptions.class.cast(options.installPrivateKey(rsaKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TemplateOptions#authorizePublicKey
|
||||
*/
|
||||
public static EC2TemplateOptions authorizePublicKey(String rsaKey) {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
return EC2TemplateOptions.class.cast(options.authorizePublicKey(rsaKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TemplateOptions#withDetails
|
||||
*/
|
||||
public static EC2TemplateOptions withDetails() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
return EC2TemplateOptions.class.cast(options.withMetadata());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// methods that only facilitate returning the correct object type
|
||||
|
||||
/**
|
||||
* @see TemplateOptions#authorizePublicKey
|
||||
*/
|
||||
@Override
|
||||
public EC2TemplateOptions authorizePublicKey(String publicKey) {
|
||||
return EC2TemplateOptions.class.cast(super.authorizePublicKey(publicKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TemplateOptions#blockOnPort
|
||||
*/
|
||||
@Override
|
||||
public EC2TemplateOptions blockOnPort(int port, int seconds) {
|
||||
return EC2TemplateOptions.class.cast(super.blockOnPort(port, seconds));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* special thing is that we do assume if you are passing groups that you have everything you need
|
||||
* already defined. for example, our option inboundPorts normally creates ingress rules
|
||||
* accordingly but if we notice you've specified securityGroups, we do not mess with rules at all
|
||||
*
|
||||
* @see TemplateOptions#inboundPorts
|
||||
*/
|
||||
@Override
|
||||
public EC2TemplateOptions inboundPorts(int... ports) {
|
||||
return EC2TemplateOptions.class.cast(super.inboundPorts(ports));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TemplateOptions#installPrivateKey
|
||||
*/
|
||||
@Override
|
||||
public EC2TemplateOptions installPrivateKey(String privateKey) {
|
||||
return EC2TemplateOptions.class.cast(super.installPrivateKey(privateKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TemplateOptions#runScript
|
||||
*/
|
||||
@Override
|
||||
public EC2TemplateOptions runScript(byte[] script) {
|
||||
return EC2TemplateOptions.class.cast(super.runScript(script));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TemplateOptions#withMetadata
|
||||
*/
|
||||
@Override
|
||||
public EC2TemplateOptions withMetadata() {
|
||||
return EC2TemplateOptions.class.cast(super.withMetadata());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return groupIds the user specified to run instances with, or zero length set to create an
|
||||
* implicit group
|
||||
*/
|
||||
public Set<String> getGroupIds() {
|
||||
return groupIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return keyPair to use when running the instance or null, to generate a keypair.
|
||||
*/
|
||||
public String getKeyPair() {
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true (default) if we are supposed to use a keypair
|
||||
*/
|
||||
public boolean shouldAutomaticallyCreateKeyPair() {
|
||||
return !noKeyPair;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((groupIds == null) ? 0 : groupIds.hashCode());
|
||||
result = prime * result + ((keyPair == null) ? 0 : keyPair.hashCode());
|
||||
result = prime * result + (noKeyPair ? 1231 : 1237);
|
||||
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;
|
||||
EC2TemplateOptions other = (EC2TemplateOptions) obj;
|
||||
if (groupIds == null) {
|
||||
if (other.groupIds != null)
|
||||
return false;
|
||||
} else if (!groupIds.equals(other.groupIds))
|
||||
return false;
|
||||
if (keyPair == null) {
|
||||
if (other.keyPair != null)
|
||||
return false;
|
||||
} else if (!keyPair.equals(other.keyPair))
|
||||
return false;
|
||||
if (noKeyPair != other.noKeyPair)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EC2TemplateOptions [groupIds=" + groupIds + ", keyPair=" + keyPair + ", noKeyPair="
|
||||
+ noKeyPair + ", inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey="
|
||||
+ (privateKey != null) + ", publicKey=" + (publicKey != null) + ", runScript="
|
||||
+ (script != null) + ", port:seconds=" + port + ":" + seconds
|
||||
+ ", metadata/details: " + includeMetadata + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
*
|
||||
* 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.strategy;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.aws.ec2.compute.domain.EC2Size;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionNameAndIngressRules;
|
||||
import org.jclouds.aws.ec2.compute.functions.CreateSecurityGroupIfNeeded;
|
||||
import org.jclouds.aws.ec2.compute.functions.CreateUniqueKeyPair;
|
||||
import org.jclouds.aws.ec2.compute.options.EC2TemplateOptions;
|
||||
import org.jclouds.aws.ec2.domain.KeyPair;
|
||||
import org.jclouds.aws.ec2.options.RunInstancesOptions;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions {
|
||||
@VisibleForTesting
|
||||
final Map<RegionAndName, KeyPair> credentialsMap;
|
||||
@VisibleForTesting
|
||||
final Map<RegionAndName, String> securityGroupMap;
|
||||
@VisibleForTesting
|
||||
final CreateUniqueKeyPair createUniqueKeyPair;
|
||||
@VisibleForTesting
|
||||
final CreateSecurityGroupIfNeeded createSecurityGroupIfNeeded;
|
||||
|
||||
@Inject
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions(
|
||||
Map<RegionAndName, KeyPair> credentialsMap,
|
||||
Map<RegionAndName, String> securityGroupMap, CreateUniqueKeyPair createUniqueKeyPair,
|
||||
CreateSecurityGroupIfNeeded createSecurityGroupIfNeeded) {
|
||||
this.credentialsMap = credentialsMap;
|
||||
this.securityGroupMap = securityGroupMap;
|
||||
this.createUniqueKeyPair = createUniqueKeyPair;
|
||||
this.createSecurityGroupIfNeeded = createSecurityGroupIfNeeded;
|
||||
}
|
||||
|
||||
public RunInstancesOptions execute(String region, String tag, Template template) {
|
||||
checkArgument(template.getSize() instanceof EC2Size,
|
||||
"unexpected image type. should be EC2Size, was: " + template.getSize().getClass());
|
||||
EC2Size ec2Size = EC2Size.class.cast(template.getSize());
|
||||
|
||||
checkArgument(template.getOptions() instanceof EC2TemplateOptions,
|
||||
"unexpected options type. should be EC2Options, was: "
|
||||
+ template.getOptions().getClass());
|
||||
EC2TemplateOptions options = EC2TemplateOptions.class.cast(template.getOptions());
|
||||
|
||||
String keyPairName = createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options);
|
||||
Set<String> groups = getSecurityGroupsForTagAndOptions(region, tag, options);
|
||||
|
||||
RunInstancesOptions instanceOptions = asType(ec2Size.getInstanceType())//
|
||||
.withSecurityGroups(groups)//
|
||||
.withAdditionalInfo(tag);
|
||||
|
||||
if (keyPairName != null)
|
||||
instanceOptions.withKeyName(keyPairName);
|
||||
|
||||
return instanceOptions;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String createNewKeyPairUnlessUserSpecifiedOtherwise(String region, String tag,
|
||||
EC2TemplateOptions options) {
|
||||
String keyPairName = options.getKeyPair();
|
||||
if (keyPairName == null && options.shouldAutomaticallyCreateKeyPair()) {
|
||||
RegionAndName regionAndName = new RegionAndName(region, tag);
|
||||
KeyPair keyPair = createUniqueKeyPair.apply(regionAndName);
|
||||
// get or create incidental resources
|
||||
// TODO race condition. we were using MapMaker, but it doesn't seem to refresh properly
|
||||
// when
|
||||
// another thread
|
||||
// deletes a key
|
||||
credentialsMap.put(new RegionAndName(region, keyPair.getKeyName()), keyPair);
|
||||
keyPairName = keyPair.getKeyName();
|
||||
}
|
||||
return keyPairName;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Set<String> getSecurityGroupsForTagAndOptions(String region, @Nullable String tag,
|
||||
EC2TemplateOptions options) {
|
||||
Set<String> groups = Sets.newLinkedHashSet();
|
||||
|
||||
if (tag != null) {
|
||||
String markerGroup = "jclouds#" + tag;
|
||||
groups.add(markerGroup);
|
||||
|
||||
RegionNameAndIngressRules regionNameAndIngessRulesForMarkerGroup;
|
||||
|
||||
if (options.getGroupIds().size() == 0) {
|
||||
regionNameAndIngessRulesForMarkerGroup = new RegionNameAndIngressRules(region,
|
||||
markerGroup, options.getInboundPorts(), true);
|
||||
} else {
|
||||
regionNameAndIngessRulesForMarkerGroup = new RegionNameAndIngressRules(region,
|
||||
markerGroup, new int[] {}, false);
|
||||
}
|
||||
|
||||
if (!securityGroupMap.containsKey(regionNameAndIngessRulesForMarkerGroup)) {
|
||||
securityGroupMap.put(regionNameAndIngessRulesForMarkerGroup,
|
||||
createSecurityGroupIfNeeded.apply(regionNameAndIngessRulesForMarkerGroup));
|
||||
}
|
||||
}
|
||||
groups.addAll(options.getGroupIds());
|
||||
return groups;
|
||||
}
|
||||
}
|
|
@ -19,48 +19,37 @@
|
|||
|
||||
package org.jclouds.aws.ec2.compute.strategy;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.jclouds.aws.ec2.options.RunInstancesOptions.Builder.withKeyName;
|
||||
import static org.jclouds.concurrent.ConcurrentUtils.makeListenable;
|
||||
import static com.google.common.collect.Iterables.all;
|
||||
import static com.google.common.collect.Iterables.concat;
|
||||
import static com.google.common.collect.Iterables.toArray;
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static org.jclouds.aws.ec2.compute.util.EC2ComputeUtils.getRegionFromLocationOrNull;
|
||||
import static org.jclouds.aws.ec2.compute.util.EC2ComputeUtils.getZoneFromLocationOrNull;
|
||||
import static org.jclouds.aws.ec2.compute.util.EC2ComputeUtils.instanceToId;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.aws.ec2.EC2Client;
|
||||
import org.jclouds.aws.ec2.compute.domain.EC2Size;
|
||||
import org.jclouds.aws.ec2.compute.domain.PortsRegionTag;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionTag;
|
||||
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.KeyPair;
|
||||
import org.jclouds.aws.ec2.domain.Reservation;
|
||||
import org.jclouds.aws.ec2.domain.RunningInstance;
|
||||
import org.jclouds.aws.ec2.options.RunInstancesOptions;
|
||||
import org.jclouds.compute.ComputeService;
|
||||
import org.jclouds.aws.ec2.services.InstanceClient;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
|
||||
import org.jclouds.compute.util.ComputeUtils;
|
||||
import org.jclouds.domain.LocationScope;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
|
@ -70,125 +59,84 @@ import com.google.common.util.concurrent.ListenableFuture;
|
|||
*/
|
||||
@Singleton
|
||||
public class EC2RunNodesAndAddToSetStrategy implements RunNodesAndAddToSetStrategy {
|
||||
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private static Function<RunningInstance, String> instanceToId = new Function<RunningInstance, String>() {
|
||||
@Override
|
||||
public String apply(RunningInstance from) {
|
||||
return from.getId();
|
||||
}
|
||||
};
|
||||
protected final ComputeService computeService;
|
||||
protected final EC2Client ec2Client;
|
||||
protected final Map<RegionTag, KeyPair> credentialsMap;
|
||||
protected final Map<PortsRegionTag, String> securityGroupMap;
|
||||
protected final CreateNewKeyPair createNewKeyPair;
|
||||
protected final CreateSecurityGroupIfNeeded createSecurityGroupIfNeeded;
|
||||
protected final Predicate<RunningInstance> instanceStateRunning;
|
||||
protected final RunningInstanceToNodeMetadata runningInstanceToNodeMetadata;
|
||||
protected final ComputeUtils utils;
|
||||
@VisibleForTesting
|
||||
final InstanceClient instanceClient;
|
||||
@VisibleForTesting
|
||||
final CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions;
|
||||
@VisibleForTesting
|
||||
final Predicate<RunningInstance> instanceStateRunning;
|
||||
@VisibleForTesting
|
||||
final RunningInstanceToNodeMetadata runningInstanceToNodeMetadata;
|
||||
@VisibleForTesting
|
||||
final ComputeUtils utils;
|
||||
|
||||
@Inject
|
||||
protected EC2RunNodesAndAddToSetStrategy(ComputeService computeService, EC2Client ec2Client,
|
||||
Map<RegionTag, KeyPair> credentialsMap, Map<PortsRegionTag, String> securityGroupMap,
|
||||
CreateNewKeyPair createKeyPairIfNeeded,
|
||||
CreateSecurityGroupIfNeeded createSecurityGroupIfNeeded,
|
||||
EC2RunNodesAndAddToSetStrategy(
|
||||
InstanceClient instanceClient,
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions,
|
||||
@Named("RUNNING") Predicate<RunningInstance> instanceStateRunning,
|
||||
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata, ComputeUtils utils,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
this.computeService = computeService;
|
||||
this.ec2Client = ec2Client;
|
||||
this.credentialsMap = credentialsMap;
|
||||
this.securityGroupMap = securityGroupMap;
|
||||
this.createNewKeyPair = createKeyPairIfNeeded;
|
||||
this.createSecurityGroupIfNeeded = createSecurityGroupIfNeeded;
|
||||
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata, ComputeUtils utils) {
|
||||
this.instanceClient = instanceClient;
|
||||
this.createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions = createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions;
|
||||
this.instanceStateRunning = instanceStateRunning;
|
||||
this.runningInstanceToNodeMetadata = runningInstanceToNodeMetadata;
|
||||
this.utils = utils;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
protected final ExecutorService executor;
|
||||
|
||||
@Override
|
||||
public Map<?, ListenableFuture<Void>> execute(final String tag, final int count,
|
||||
final Template template, final Set<NodeMetadata> nodes,
|
||||
final Map<NodeMetadata, Exception> badNodes) {
|
||||
checkArgument(template.getSize() instanceof EC2Size,
|
||||
"unexpected image type. should be EC2Size, was: " + template.getSize().getClass());
|
||||
EC2Size ec2Size = EC2Size.class.cast(template.getSize());
|
||||
public Map<?, ListenableFuture<Void>> execute(String tag, int count, Template template,
|
||||
Set<NodeMetadata> goodNodes, Map<NodeMetadata, Exception> badNodes) {
|
||||
|
||||
// parse the availability zone of the request
|
||||
String zone = template.getLocation().getScope() == LocationScope.ZONE ? template
|
||||
.getLocation().getId() : null;
|
||||
Reservation reservation = createKeyPairAndSecurityGroupsAsNeededThenRunInstances(tag, count,
|
||||
template);
|
||||
|
||||
// if the location has a parent, it must be an availability zone.
|
||||
String region = zone == null ? template.getLocation().getId() : template.getLocation()
|
||||
.getParent().getId();
|
||||
Iterable<NodeMetadata> runningNodes = blockUntilInstancesAreRunningAndConvertToNodes(reservation);
|
||||
|
||||
// get or create incidental resources
|
||||
// TODO race condition. we were using MapMaker, but it doesn't seem to refresh properly when
|
||||
// another thread
|
||||
// deletes a key
|
||||
RegionTag regionTag = new RegionTag(region, tag);
|
||||
|
||||
KeyPair keyPair = createNewKeyPair.apply(regionTag);
|
||||
|
||||
credentialsMap.put(new RegionTag(region, keyPair.getKeyName()), keyPair);
|
||||
|
||||
TemplateOptions options = template.getOptions();
|
||||
String group = "jclouds#" +tag;
|
||||
PortsRegionTag portsRegionTag = new PortsRegionTag(region, group, options.getInboundPorts());
|
||||
if (!securityGroupMap.containsKey(portsRegionTag)) {
|
||||
securityGroupMap.put(portsRegionTag, createSecurityGroupIfNeeded.apply(portsRegionTag));
|
||||
return utils.runOptionsOnNodesAndAddToGoodSetOrPutExceptionIntoBadMap(template.getOptions(),
|
||||
runningNodes, goodNodes, badNodes);
|
||||
}
|
||||
|
||||
logger
|
||||
.debug(
|
||||
">> running %d instance region(%s) zone(%s) ami(%s) type(%s) keyPair(%s) securityGroup(%s)",
|
||||
count, region, zone, template.getImage().getId(),
|
||||
ec2Size.getInstanceType(), keyPair.getKeyName(), group);
|
||||
RunInstancesOptions instanceOptions = withKeyName(keyPair.getKeyName())// key
|
||||
.asType(ec2Size.getInstanceType())// instance size
|
||||
.withSecurityGroup(group)// group I created above
|
||||
.withAdditionalInfo(tag);
|
||||
@VisibleForTesting
|
||||
Iterable<NodeMetadata> blockUntilInstancesAreRunningAndConvertToNodes(Reservation reservation) {
|
||||
return transform(blockUntilInstancesAreRunning(reservation), runningInstanceToNodeMetadata);
|
||||
}
|
||||
|
||||
Reservation reservation = ec2Client.getInstanceServices().runInstancesInRegion(region, zone,
|
||||
template.getImage().getId(), 1, count, instanceOptions);
|
||||
Iterable<String> ids = Iterables.transform(reservation, instanceToId);
|
||||
@VisibleForTesting
|
||||
Iterable<RunningInstance> blockUntilInstancesAreRunning(Reservation reservation) {
|
||||
Iterable<String> ids = transform(reservation, instanceToId);
|
||||
|
||||
String idsString = Joiner.on(',').join(ids);
|
||||
logger.debug("<< started instances(%s)", idsString);
|
||||
Iterables.all(reservation, instanceStateRunning);
|
||||
all(reservation, instanceStateRunning);
|
||||
logger.debug("<< running instances(%s)", idsString);
|
||||
Map<NodeMetadata, ListenableFuture<Void>> responses = Maps.newHashMap();
|
||||
for (final NodeMetadata node : Iterables.transform(getInstances(region, ids),
|
||||
runningInstanceToNodeMetadata)) {
|
||||
responses.put(node, makeListenable(executor.submit(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
try {
|
||||
utils.runOptionsOnNode(node, template.getOptions());
|
||||
logger.debug("<< options applied node(%s)", node.getId());
|
||||
nodes.add(computeService.getNodeMetadata(node));
|
||||
} catch (Exception e) {
|
||||
logger.error(e, "<< problem applying options to node(%s): ", node.getId(),
|
||||
Throwables.getRootCause(e).getMessage());
|
||||
badNodes.put(computeService.getNodeMetadata(node), e);
|
||||
}
|
||||
return null;
|
||||
|
||||
return getInstances(reservation.getRegion(), ids);
|
||||
}
|
||||
|
||||
}), executor));
|
||||
}
|
||||
return responses;
|
||||
@VisibleForTesting
|
||||
Reservation createKeyPairAndSecurityGroupsAsNeededThenRunInstances(String tag, int count,
|
||||
Template template) {
|
||||
String region = getRegionFromLocationOrNull(template.getLocation());
|
||||
String zone = getZoneFromLocationOrNull(template.getLocation());
|
||||
|
||||
RunInstancesOptions instanceOptions = createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions
|
||||
.execute(region, tag, template);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug(">> running %d instance region(%s) zone(%s) ami(%s) params(%s)", count,
|
||||
region, zone, template.getImage().getId(), instanceOptions.buildFormParameters());
|
||||
|
||||
return instanceClient.runInstancesInRegion(region, zone, template.getImage().getId(), 1,
|
||||
count, instanceOptions);
|
||||
}
|
||||
|
||||
private Iterable<RunningInstance> getInstances(String region, Iterable<String> ids) {
|
||||
return Iterables.concat(ec2Client.getInstanceServices().describeInstancesInRegion(region,
|
||||
Iterables.toArray(ids, String.class)));
|
||||
return concat(instanceClient.describeInstancesInRegion(region, toArray(ids, String.class)));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
*
|
||||
* 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.util;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.aws.ec2.domain.RunningInstance;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.LocationScope;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class EC2ComputeUtils {
|
||||
|
||||
public static Function<RunningInstance, String> instanceToId = new Function<RunningInstance, String>() {
|
||||
@Override
|
||||
public String apply(RunningInstance from) {
|
||||
return from.getId();
|
||||
}
|
||||
};
|
||||
|
||||
public static String getRegionFromLocationOrNull(Location location) {
|
||||
return location.getScope() == LocationScope.ZONE ? location.getParent().getId() : location
|
||||
.getId();
|
||||
}
|
||||
|
||||
public static String getZoneFromLocationOrNull(Location location) {
|
||||
return location.getScope() == LocationScope.ZONE ? location.getId() : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -129,4 +129,10 @@ public class IpPermission implements Comparable<IpPermission> {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IpPermission [fromPort=" + fromPort + ", groups=" + groups + ", ipProtocol="
|
||||
+ ipProtocol + ", ipRanges=" + ipRanges + ", toPort=" + toPort + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -137,4 +137,10 @@ public class SecurityGroup implements Comparable<SecurityGroup> {
|
|||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SecurityGroup [description=" + description + ", ipPermissions=" + ipPermissions
|
||||
+ ", name=" + name + ", ownerId=" + ownerId + ", region=" + region + "]";
|
||||
}
|
||||
}
|
|
@ -66,6 +66,14 @@ public class RunInstancesOptions extends BaseEC2RequestOptions {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach multiple security groups
|
||||
*/
|
||||
public RunInstancesOptions withSecurityGroups(Iterable<String> securityGroups) {
|
||||
indexFormValuesWithPrefix("SecurityGroup", securityGroups);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a single security group. Multiple calls to this method
|
||||
* won't add more groups.
|
||||
|
|
|
@ -41,6 +41,10 @@ public class BaseEC2RequestOptions extends BaseHttpRequestOptions {
|
|||
}
|
||||
}
|
||||
|
||||
protected void indexFormValuesWithPrefix(String prefix, Iterable<String> values) {
|
||||
indexFormValuesWithPrefix(prefix, Iterables.toArray(values, String.class));
|
||||
}
|
||||
|
||||
protected Set<String> getFormValuesWithKeysPrefixedBy(final String prefix) {
|
||||
Set<String> values = Sets.newLinkedHashSet();
|
||||
for (String key : Iterables.filter(formParameters.keySet(), new Predicate<String>() {
|
||||
|
|
|
@ -20,15 +20,29 @@ package org.jclouds.aws.ec2.compute;
|
|||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.aws.ec2.EC2Client;
|
||||
import org.jclouds.aws.ec2.compute.options.EC2TemplateOptions;
|
||||
import org.jclouds.aws.ec2.domain.IpProtocol;
|
||||
import org.jclouds.aws.ec2.domain.KeyPair;
|
||||
import org.jclouds.aws.ec2.domain.RunningInstance;
|
||||
import org.jclouds.aws.ec2.domain.SecurityGroup;
|
||||
import org.jclouds.aws.ec2.services.InstanceClient;
|
||||
import org.jclouds.aws.ec2.services.KeyPairClient;
|
||||
import org.jclouds.aws.ec2.services.SecurityGroupClient;
|
||||
import org.jclouds.compute.BaseComputeServiceLiveTest;
|
||||
import org.jclouds.compute.domain.Architecture;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.domain.OsFamily;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.jclouds.compute.domain.TemplateBuilder;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.ssh.jsch.config.JschSshClientModule;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
|
@ -73,4 +87,136 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest {
|
|||
return templateBuilder.imageId("ami-714ba518").build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtendedOptionsAndLogin() throws Exception {
|
||||
SecurityGroupClient securityGroupClient = EC2Client.class.cast(
|
||||
context.getProviderSpecificContext().getApi()).getSecurityGroupServices();
|
||||
|
||||
KeyPairClient keyPairClient = EC2Client.class.cast(
|
||||
context.getProviderSpecificContext().getApi()).getKeyPairServices();
|
||||
|
||||
InstanceClient instanceClient = EC2Client.class.cast(
|
||||
context.getProviderSpecificContext().getApi()).getInstanceServices();
|
||||
|
||||
String tag = this.tag + "optionsandlogin";
|
||||
|
||||
Template template = buildTemplate(client.templateBuilder());
|
||||
|
||||
template.getOptions().as(EC2TemplateOptions.class).securityGroups(tag);
|
||||
template.getOptions().as(EC2TemplateOptions.class).keyPair(tag);
|
||||
|
||||
String startedId = null;
|
||||
try {
|
||||
// create a security group that allows ssh in so that our scripts later will work
|
||||
securityGroupClient.createSecurityGroupInRegion(null, tag, tag);
|
||||
securityGroupClient.authorizeSecurityGroupIngressInRegion(null, tag, IpProtocol.TCP, 22,
|
||||
22, "0.0.0.0/0");
|
||||
|
||||
// create a keypair to pass in as well
|
||||
KeyPair result = keyPairClient.createKeyPairInRegion(null, tag);
|
||||
|
||||
Set<? extends NodeMetadata> nodes = client.runNodesWithTag(tag, 1, template);
|
||||
Credentials good = nodes.iterator().next().getCredentials();
|
||||
assert good.account != null;
|
||||
|
||||
startedId = Iterables.getOnlyElement(nodes).getId();
|
||||
|
||||
RunningInstance instance = getInstance(instanceClient, startedId);
|
||||
|
||||
assertEquals(instance.getKeyName(), tag);
|
||||
|
||||
// make sure we made our dummy group and also let in the user's group
|
||||
assertEquals(instance.getGroupIds(), ImmutableSet.<String> of(tag, "jclouds#" + tag));
|
||||
|
||||
// make sure our dummy group has no rules
|
||||
SecurityGroup group = Iterables.getOnlyElement(securityGroupClient
|
||||
.describeSecurityGroupsInRegion(null, "jclouds#" + tag));
|
||||
assert group.getIpPermissions().size() == 0 : group;
|
||||
|
||||
// try to run a script with the original keyPair
|
||||
runScriptWithCreds(tag, template.getImage().getOsFamily(), new Credentials(good.account,
|
||||
result.getKeyMaterial()));
|
||||
|
||||
} finally {
|
||||
client.destroyNodesWithTag(tag);
|
||||
if (startedId != null) {
|
||||
// ensure we didn't delete these resources!
|
||||
assertEquals(keyPairClient.describeKeyPairsInRegion(null, tag).size(), 1);
|
||||
assertEquals(securityGroupClient.describeSecurityGroupsInRegion(null, tag).size(), 1);
|
||||
}
|
||||
cleanupExtendedStuff(securityGroupClient, keyPairClient, tag);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtendedOptionsNoKeyPair() throws Exception {
|
||||
SecurityGroupClient securityGroupClient = EC2Client.class.cast(
|
||||
context.getProviderSpecificContext().getApi()).getSecurityGroupServices();
|
||||
|
||||
KeyPairClient keyPairClient = EC2Client.class.cast(
|
||||
context.getProviderSpecificContext().getApi()).getKeyPairServices();
|
||||
|
||||
InstanceClient instanceClient = EC2Client.class.cast(
|
||||
context.getProviderSpecificContext().getApi()).getInstanceServices();
|
||||
|
||||
String tag = this.tag + "optionsnokey";
|
||||
|
||||
Template template = buildTemplate(client.templateBuilder());
|
||||
|
||||
template.getOptions().as(EC2TemplateOptions.class).securityGroups(tag);
|
||||
template.getOptions().as(EC2TemplateOptions.class).noKeyPair();
|
||||
|
||||
String startedId = null;
|
||||
try {
|
||||
// create the security group
|
||||
securityGroupClient.createSecurityGroupInRegion(null, tag, tag);
|
||||
|
||||
Set<? extends NodeMetadata> nodes = client.runNodesWithTag(tag, 1, template);
|
||||
Credentials creds = nodes.iterator().next().getCredentials();
|
||||
assert creds == null;
|
||||
|
||||
startedId = Iterables.getOnlyElement(nodes).getId();
|
||||
|
||||
RunningInstance instance = getInstance(instanceClient, startedId);
|
||||
|
||||
assertEquals(instance.getKeyName(), null);
|
||||
|
||||
// make sure we made our dummy group and also let in the user's group
|
||||
assertEquals(instance.getGroupIds(), ImmutableSet.<String> of(tag, "jclouds#" + tag));
|
||||
|
||||
// make sure our dummy group has no rules
|
||||
SecurityGroup group = Iterables.getOnlyElement(securityGroupClient
|
||||
.describeSecurityGroupsInRegion(null, "jclouds#" + tag));
|
||||
assert group.getIpPermissions().size() == 0 : group;
|
||||
|
||||
} finally {
|
||||
client.destroyNodesWithTag(tag);
|
||||
if (startedId != null) {
|
||||
// ensure we didn't delete these resources!
|
||||
assertEquals(securityGroupClient.describeSecurityGroupsInRegion(null, tag).size(), 1);
|
||||
}
|
||||
cleanupExtendedStuff(securityGroupClient, keyPairClient, tag);
|
||||
}
|
||||
}
|
||||
|
||||
private RunningInstance getInstance(InstanceClient instanceClient, String id) {
|
||||
RunningInstance instance = Iterables.getOnlyElement(Iterables.getOnlyElement(instanceClient
|
||||
.describeInstancesInRegion(null, id)));
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void cleanupExtendedStuff(SecurityGroupClient securityGroupClient,
|
||||
KeyPairClient keyPairClient, String tag) {
|
||||
try {
|
||||
securityGroupClient.deleteSecurityGroupInRegion(null, tag);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
try {
|
||||
keyPairClient.deleteKeyPairInRegion(null, tag);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ package org.jclouds.aws.ec2.compute;
|
|||
import static java.lang.String.format;
|
||||
|
||||
import org.jclouds.aws.ec2.compute.domain.EC2Size;
|
||||
import org.jclouds.aws.ec2.compute.options.EC2TemplateOptions;
|
||||
import org.jclouds.compute.domain.Architecture;
|
||||
import org.jclouds.compute.domain.ComputeMetadata;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
|
@ -118,7 +119,7 @@ public class EC2ComputeServiceTest {
|
|||
return new TemplateBuilderImpl(ImmutableSet.of(location), ImmutableSet.of(image),
|
||||
ImmutableSet.of(EC2Size.C1_MEDIUM, EC2Size.C1_XLARGE, EC2Size.M1_LARGE,
|
||||
EC2Size.M1_SMALL, EC2Size.M1_XLARGE, EC2Size.M2_XLARGE, EC2Size.M2_2XLARGE,
|
||||
EC2Size.M2_4XLARGE), location) {
|
||||
EC2Size.M2_4XLARGE), location, new EC2TemplateOptions()) {
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
import org.jclouds.aws.domain.Region;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionTag;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.aws.ec2.domain.AvailabilityZone;
|
||||
import org.jclouds.aws.ec2.domain.Image;
|
||||
import org.jclouds.aws.ec2.domain.InstanceState;
|
||||
|
@ -60,7 +60,7 @@ public class RunningInstanceToNodeMetadataTest {
|
|||
public void testApplyWithNoSecurityGroupCreatesTagOfIdPrefixedByTagAndNullCredentials()
|
||||
throws UnknownHostException {
|
||||
AMIClient amiClient = createMock(AMIClient.class);
|
||||
Map<RegionTag, KeyPair> credentialsMap = createMock(Map.class);
|
||||
Map<RegionAndName, KeyPair> credentialsMap = createMock(Map.class);
|
||||
org.jclouds.compute.domain.Image jcImage = createMock(org.jclouds.compute.domain.Image.class);
|
||||
|
||||
Set<org.jclouds.compute.domain.Image> images = ImmutableSet
|
||||
|
@ -117,7 +117,7 @@ public class RunningInstanceToNodeMetadataTest {
|
|||
public void testApplyWithNoKeyPairCreatesTagOfParsedSecurityGroupAndNullCredentials()
|
||||
throws UnknownHostException {
|
||||
AMIClient amiClient = createMock(AMIClient.class);
|
||||
Map<RegionTag, KeyPair> credentialsMap = createMock(Map.class);
|
||||
Map<RegionAndName, KeyPair> credentialsMap = createMock(Map.class);
|
||||
org.jclouds.compute.domain.Image jcImage = createMock(org.jclouds.compute.domain.Image.class);
|
||||
|
||||
Set<org.jclouds.compute.domain.Image> images = ImmutableSet
|
||||
|
@ -174,7 +174,7 @@ public class RunningInstanceToNodeMetadataTest {
|
|||
public void testApplyWithKeyPairCreatesTagOfParsedSecurityGroupAndCredentialsBasedOnIt()
|
||||
throws UnknownHostException {
|
||||
AMIClient amiClient = createMock(AMIClient.class);
|
||||
Map<RegionTag, KeyPair> credentialsMap = createMock(Map.class);
|
||||
Map<RegionAndName, KeyPair> credentialsMap = createMock(Map.class);
|
||||
|
||||
PopulateDefaultLoginCredentialsForImageStrategy credentialProvider = createMock(PopulateDefaultLoginCredentialsForImageStrategy.class);
|
||||
RunningInstance instance = createMock(RunningInstance.class);
|
||||
|
@ -207,7 +207,7 @@ public class RunningInstanceToNodeMetadataTest {
|
|||
|
||||
expect(credentialProvider.execute(image)).andReturn(new Credentials("user", "pass"));
|
||||
|
||||
expect(credentialsMap.get(new RegionTag(Region.US_EAST_1, "jclouds#keyName"))).andReturn(
|
||||
expect(credentialsMap.get(new RegionAndName(Region.US_EAST_1, "jclouds#keyName"))).andReturn(
|
||||
new KeyPair(Region.US_EAST_1, "jclouds#keyName", "keyFingerprint", "pass"));
|
||||
|
||||
expect(instance.getAvailabilityZone()).andReturn(AvailabilityZone.US_EAST_1A).atLeastOnce();
|
||||
|
@ -245,7 +245,7 @@ public class RunningInstanceToNodeMetadataTest {
|
|||
public void testApplyWithTwoSecurityGroups()
|
||||
throws UnknownHostException {
|
||||
AMIClient amiClient = createMock(AMIClient.class);
|
||||
Map<RegionTag, KeyPair> credentialsMap = createMock(Map.class);
|
||||
Map<RegionAndName, KeyPair> credentialsMap = createMock(Map.class);
|
||||
|
||||
PopulateDefaultLoginCredentialsForImageStrategy credentialProvider = createMock(PopulateDefaultLoginCredentialsForImageStrategy.class);
|
||||
RunningInstance instance = createMock(RunningInstance.class);
|
||||
|
@ -278,7 +278,7 @@ public class RunningInstanceToNodeMetadataTest {
|
|||
|
||||
expect(credentialProvider.execute(image)).andReturn(new Credentials("user", "pass"));
|
||||
|
||||
expect(credentialsMap.get(new RegionTag(Region.US_EAST_1, "jclouds#keyName"))).andReturn(
|
||||
expect(credentialsMap.get(new RegionAndName(Region.US_EAST_1, "jclouds#keyName"))).andReturn(
|
||||
new KeyPair(Region.US_EAST_1, "jclouds#keyName", "keyFingerprint", "pass"));
|
||||
|
||||
expect(instance.getAvailabilityZone()).andReturn(AvailabilityZone.US_EAST_1A).atLeastOnce();
|
||||
|
|
|
@ -0,0 +1,289 @@
|
|||
/**
|
||||
*
|
||||
* 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.options;
|
||||
|
||||
import static org.jclouds.aws.ec2.compute.options.EC2TemplateOptions.Builder.authorizePublicKey;
|
||||
import static org.jclouds.aws.ec2.compute.options.EC2TemplateOptions.Builder.blockOnPort;
|
||||
import static org.jclouds.aws.ec2.compute.options.EC2TemplateOptions.Builder.inboundPorts;
|
||||
import static org.jclouds.aws.ec2.compute.options.EC2TemplateOptions.Builder.installPrivateKey;
|
||||
import static org.jclouds.aws.ec2.compute.options.EC2TemplateOptions.Builder.keyPair;
|
||||
import static org.jclouds.aws.ec2.compute.options.EC2TemplateOptions.Builder.noKeyPair;
|
||||
import static org.jclouds.aws.ec2.compute.options.EC2TemplateOptions.Builder.securityGroups;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Tests possible uses of EC2TemplateOptions and EC2TemplateOptions.Builder.*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class EC2TemplateOptionsTest {
|
||||
|
||||
public void testAs() {
|
||||
TemplateOptions options = new EC2TemplateOptions();
|
||||
assertEquals(options.as(EC2TemplateOptions.class), options);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testsecurityGroupsIterableBadFormat() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.securityGroups(ImmutableSet.of("group1", ""));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testsecurityGroupsIterableEmptyNotOk() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.securityGroups(ImmutableSet.<String> of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testsecurityGroupsIterable() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.securityGroups(ImmutableSet.of("group1", "group2"));
|
||||
assertEquals(options.getGroupIds(), ImmutableSet.of("group1", "group2"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testsecurityGroupsIterableStatic() {
|
||||
EC2TemplateOptions options = securityGroups(ImmutableSet.of("group1", "group2"));
|
||||
assertEquals(options.getGroupIds(), ImmutableSet.of("group1", "group2"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testsecurityGroupsVarArgsBadFormat() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.securityGroups("mygroup", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testsecurityGroupsVarArgs() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.securityGroups("group1", "group2");
|
||||
assertEquals(options.getGroupIds(), ImmutableSet.of("group1", "group2"));
|
||||
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testsecurityGroupsVarArgsEmptyNotOk() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.securityGroups();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultGroupsVarArgsEmpty() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
assertEquals(options.getGroupIds(), ImmutableSet.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testsecurityGroupsVarArgsStatic() {
|
||||
EC2TemplateOptions options = securityGroups("group1", "group2");
|
||||
assertEquals(options.getGroupIds(), ImmutableSet.of("group1", "group2"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testkeyPairBadFormat() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.keyPair("");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testkeyPairAndNoKeyPair() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.keyPair("mykeypair");
|
||||
options.noKeyPair();
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testNoKeyPairAndKeyPair() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.noKeyPair();
|
||||
options.keyPair("mykeypair");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testkeyPair() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.keyPair("mykeypair");
|
||||
assertEquals(options.getKeyPair(), "mykeypair");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullkeyPair() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
assertEquals(options.getKeyPair(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testkeyPairStatic() {
|
||||
EC2TemplateOptions options = keyPair("mykeypair");
|
||||
assertEquals(options.getKeyPair(), "mykeypair");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testkeyPairNPE() {
|
||||
keyPair(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testnoKeyPair() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.noKeyPair();
|
||||
assertEquals(options.getKeyPair(), null);
|
||||
assert !options.shouldAutomaticallyCreateKeyPair();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFalsenoKeyPair() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
assertEquals(options.getKeyPair(), null);
|
||||
assert options.shouldAutomaticallyCreateKeyPair();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testnoKeyPairStatic() {
|
||||
EC2TemplateOptions options = noKeyPair();
|
||||
assertEquals(options.getKeyPair(), null);
|
||||
assert !options.shouldAutomaticallyCreateKeyPair();
|
||||
}
|
||||
|
||||
// superclass tests
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testinstallPrivateKeyBadFormat() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.installPrivateKey("whompy");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testinstallPrivateKey() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.installPrivateKey("-----BEGIN RSA PRIVATE KEY-----");
|
||||
assertEquals(options.getPrivateKey(), "-----BEGIN RSA PRIVATE KEY-----");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullinstallPrivateKey() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
assertEquals(options.getPrivateKey(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testinstallPrivateKeyStatic() {
|
||||
EC2TemplateOptions options = installPrivateKey("-----BEGIN RSA PRIVATE KEY-----");
|
||||
assertEquals(options.getPrivateKey(), "-----BEGIN RSA PRIVATE KEY-----");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testinstallPrivateKeyNPE() {
|
||||
installPrivateKey(null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testauthorizePublicKeyBadFormat() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.authorizePublicKey("whompy");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testauthorizePublicKey() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.authorizePublicKey("ssh-rsa");
|
||||
assertEquals(options.getPublicKey(), "ssh-rsa");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullauthorizePublicKey() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
assertEquals(options.getPublicKey(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testauthorizePublicKeyStatic() {
|
||||
EC2TemplateOptions options = authorizePublicKey("ssh-rsa");
|
||||
assertEquals(options.getPublicKey(), "ssh-rsa");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testauthorizePublicKeyNPE() {
|
||||
authorizePublicKey(null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testblockOnPortBadFormat() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.blockOnPort(-1, -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testblockOnPort() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.blockOnPort(22, 30);
|
||||
assertEquals(options.getPort(), 22);
|
||||
assertEquals(options.getSeconds(), 30);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullblockOnPort() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
assertEquals(options.getPort(), -1);
|
||||
assertEquals(options.getSeconds(), -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testblockOnPortStatic() {
|
||||
EC2TemplateOptions options = blockOnPort(22, 30);
|
||||
assertEquals(options.getPort(), 22);
|
||||
assertEquals(options.getSeconds(), 30);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testinboundPortsBadFormat() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.inboundPorts(-1, -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testinboundPorts() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
options.inboundPorts(22, 30);
|
||||
assertEquals(options.getInboundPorts()[0], 22);
|
||||
assertEquals(options.getInboundPorts()[1], 30);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultOpen22() {
|
||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||
assertEquals(options.getInboundPorts()[0], 22);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testinboundPortsStatic() {
|
||||
EC2TemplateOptions options = inboundPorts(22, 30);
|
||||
assertEquals(options.getInboundPorts()[0], 22);
|
||||
assertEquals(options.getInboundPorts()[1], 30);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,376 @@
|
|||
/**
|
||||
*
|
||||
* 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.strategy;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.aws.domain.Region;
|
||||
import org.jclouds.aws.ec2.compute.domain.EC2Size;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.aws.ec2.compute.domain.RegionNameAndIngressRules;
|
||||
import org.jclouds.aws.ec2.compute.functions.CreateSecurityGroupIfNeeded;
|
||||
import org.jclouds.aws.ec2.compute.functions.CreateUniqueKeyPair;
|
||||
import org.jclouds.aws.ec2.compute.options.EC2TemplateOptions;
|
||||
import org.jclouds.aws.ec2.domain.KeyPair;
|
||||
import org.jclouds.aws.ec2.options.RunInstancesOptions;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "ec2.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest")
|
||||
public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
||||
|
||||
public void testExecuteWithDefaultOptions() throws SecurityException, NoSuchMethodException {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
EC2Size size = EC2Size.M1_SMALL;
|
||||
String systemGeneratedKeyPairName = "systemGeneratedKeyPair";
|
||||
String generatedGroup = "group";
|
||||
Set<String> generatedGroups = ImmutableSet.of(generatedGroup);
|
||||
|
||||
// create mocks
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy = createMock(
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class, new Method[] {
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class
|
||||
.getDeclaredMethod("createNewKeyPairUnlessUserSpecifiedOtherwise",
|
||||
String.class, String.class, EC2TemplateOptions.class),
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class
|
||||
.getDeclaredMethod("getSecurityGroupsForTagAndOptions",
|
||||
String.class, String.class, EC2TemplateOptions.class) });
|
||||
|
||||
EC2TemplateOptions options = createMock(EC2TemplateOptions.class);
|
||||
Template template = createMock(Template.class);
|
||||
|
||||
// setup expectations
|
||||
expect(template.getSize()).andReturn(size).atLeastOnce();
|
||||
expect(template.getOptions()).andReturn(options).atLeastOnce();
|
||||
expect(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options))
|
||||
.andReturn(systemGeneratedKeyPairName);
|
||||
expect(strategy.getSecurityGroupsForTagAndOptions(region, tag, options)).andReturn(
|
||||
generatedGroups);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
replay(template);
|
||||
replay(strategy);
|
||||
|
||||
// run
|
||||
RunInstancesOptions runOptions = strategy.execute(region, tag, template);
|
||||
assertEquals(runOptions.buildQueryParameters(), ImmutableMultimap.<String, String> of());
|
||||
assertEquals(runOptions.buildFormParameters().entries(), ImmutableMultimap
|
||||
.<String, String> of("InstanceType", size.getId(), "SecurityGroup.1",
|
||||
generatedGroup, "AdditionalInfo", tag, "KeyName",
|
||||
systemGeneratedKeyPairName).entries());
|
||||
assertEquals(runOptions.buildMatrixParameters(), ImmutableMultimap.<String, String> of());
|
||||
assertEquals(runOptions.buildRequestHeaders(), ImmutableMultimap.<String, String> of());
|
||||
assertEquals(runOptions.buildStringPayload(), null);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
verify(template);
|
||||
verify(strategy);
|
||||
}
|
||||
|
||||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_reusesKeyWhenToldTo() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String userSuppliedKeyPair = "myKeyPair";
|
||||
|
||||
// create mocks
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy = setupStrategy();
|
||||
EC2TemplateOptions options = createMock(EC2TemplateOptions.class);
|
||||
KeyPair keyPair = createMock(KeyPair.class);
|
||||
|
||||
// setup expectations
|
||||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
replay(keyPair);
|
||||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options),
|
||||
userSuppliedKeyPair);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
verify(keyPair);
|
||||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_createsNewKeyPairAndReturnsItsNameByDefault() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String userSuppliedKeyPair = null;
|
||||
boolean shouldAutomaticallyCreateKeyPair = true;
|
||||
String systemGeneratedKeyPairName = "systemGeneratedKeyPair";
|
||||
|
||||
// create mocks
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy = setupStrategy();
|
||||
EC2TemplateOptions options = createMock(EC2TemplateOptions.class);
|
||||
KeyPair keyPair = createMock(KeyPair.class);
|
||||
|
||||
// setup expectations
|
||||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.shouldAutomaticallyCreateKeyPair())
|
||||
.andReturn(shouldAutomaticallyCreateKeyPair);
|
||||
expect(strategy.createUniqueKeyPair.apply(new RegionAndName(region, tag))).andReturn(keyPair);
|
||||
expect(keyPair.getKeyName()).andReturn(systemGeneratedKeyPairName).atLeastOnce();
|
||||
expect(
|
||||
strategy.credentialsMap.put(new RegionAndName(region, systemGeneratedKeyPairName),
|
||||
keyPair)).andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
replay(keyPair);
|
||||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options),
|
||||
systemGeneratedKeyPairName);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
verify(keyPair);
|
||||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_doesntCreateAKeyPairAndReturnsNullWhenToldNotTo() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String userSuppliedKeyPair = null;
|
||||
boolean shouldAutomaticallyCreateKeyPair = false; // here's the important part!
|
||||
|
||||
// create mocks
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy = setupStrategy();
|
||||
EC2TemplateOptions options = createMock(EC2TemplateOptions.class);
|
||||
KeyPair keyPair = createMock(KeyPair.class);
|
||||
|
||||
// setup expectations
|
||||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.shouldAutomaticallyCreateKeyPair())
|
||||
.andReturn(shouldAutomaticallyCreateKeyPair);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
replay(keyPair);
|
||||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options),
|
||||
null);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
verify(keyPair);
|
||||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
public void testGetSecurityGroupsForTagAndOptions_createsNewGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesntExist() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String generatedMarkerGroup = "jclouds#tag";
|
||||
Set<String> groupIds = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] {};
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
boolean groupExisted = false;
|
||||
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
|
||||
|
||||
// create mocks
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy = setupStrategy();
|
||||
EC2TemplateOptions options = createMock(EC2TemplateOptions.class);
|
||||
|
||||
// setup expectations
|
||||
expect(options.getGroupIds()).andReturn(groupIds).atLeastOnce();
|
||||
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region,
|
||||
generatedMarkerGroup, ports, shouldAuthorizeSelf);
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(
|
||||
groupExisted);
|
||||
expect(strategy.createSecurityGroupIfNeeded.apply(regionNameAndIngressRules)).andReturn(
|
||||
generatedMarkerGroup);
|
||||
expect(strategy.securityGroupMap.put(regionNameAndIngressRules, generatedMarkerGroup))
|
||||
.andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, tag, options), returnVal);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
public void testGetSecurityGroupsForTagAndOptions_createsNewGroupByDefaultWhenPortsAreSpecifiedWhenDoesntExist() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String generatedMarkerGroup = "jclouds#tag";
|
||||
Set<String> groupIds = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] { 22, 80 };
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
boolean groupExisted = false;
|
||||
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
|
||||
|
||||
// create mocks
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy = setupStrategy();
|
||||
EC2TemplateOptions options = createMock(EC2TemplateOptions.class);
|
||||
|
||||
// setup expectations
|
||||
expect(options.getGroupIds()).andReturn(groupIds).atLeastOnce();
|
||||
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region,
|
||||
generatedMarkerGroup, ports, shouldAuthorizeSelf);
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(
|
||||
groupExisted);
|
||||
expect(strategy.createSecurityGroupIfNeeded.apply(regionNameAndIngressRules)).andReturn(
|
||||
generatedMarkerGroup);
|
||||
expect(strategy.securityGroupMap.put(regionNameAndIngressRules, generatedMarkerGroup))
|
||||
.andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, tag, options), returnVal);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
public void testGetSecurityGroupsForTagAndOptions_reusesGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesExist() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String generatedMarkerGroup = "jclouds#tag";
|
||||
Set<String> groupIds = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] {};
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
boolean groupExisted = true;
|
||||
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup);
|
||||
|
||||
// create mocks
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy = setupStrategy();
|
||||
EC2TemplateOptions options = createMock(EC2TemplateOptions.class);
|
||||
|
||||
// setup expectations
|
||||
expect(options.getGroupIds()).andReturn(groupIds).atLeastOnce();
|
||||
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region,
|
||||
generatedMarkerGroup, ports, shouldAuthorizeSelf);
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(
|
||||
groupExisted);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, tag, options), returnVal);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
public void testGetSecurityGroupsForTagAndOptions_reusesGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesExistAndAcceptsUserSuppliedGroups() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String generatedMarkerGroup = "jclouds#tag";
|
||||
Set<String> groupIds = ImmutableSet.<String> of("group1", "group2");
|
||||
int[] ports = new int[] {};
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
boolean groupExisted = true;
|
||||
Set<String> returnVal = ImmutableSet.<String> of(generatedMarkerGroup, "group1", "group2");
|
||||
|
||||
// create mocks
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy = setupStrategy();
|
||||
EC2TemplateOptions options = createMock(EC2TemplateOptions.class);
|
||||
|
||||
// setup expectations
|
||||
expect(options.getGroupIds()).andReturn(groupIds).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region,
|
||||
generatedMarkerGroup, ports, shouldAuthorizeSelf); // note this works since there's
|
||||
// no equals on portsq
|
||||
expect(strategy.securityGroupMap.containsKey(regionNameAndIngressRules)).andReturn(
|
||||
groupExisted);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, tag, options), returnVal);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
private void verifyStrategy(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy) {
|
||||
verify(strategy.credentialsMap);
|
||||
verify(strategy.securityGroupMap);
|
||||
verify(strategy.createUniqueKeyPair);
|
||||
verify(strategy.createSecurityGroupIfNeeded);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions setupStrategy() {
|
||||
Map<RegionAndName, KeyPair> credentialsMap = createMock(Map.class);
|
||||
Map<RegionAndName, String> securityGroupMap = createMock(Map.class);
|
||||
CreateUniqueKeyPair createUniqueKeyPair = createMock(CreateUniqueKeyPair.class);
|
||||
CreateSecurityGroupIfNeeded createSecurityGroupIfNeeded = createMock(CreateSecurityGroupIfNeeded.class);
|
||||
|
||||
return new CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions(credentialsMap,
|
||||
securityGroupMap, createUniqueKeyPair, createSecurityGroupIfNeeded);
|
||||
}
|
||||
|
||||
private void replayStrategy(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions strategy) {
|
||||
replay(strategy.credentialsMap);
|
||||
replay(strategy.securityGroupMap);
|
||||
replay(strategy.createUniqueKeyPair);
|
||||
replay(strategy.createSecurityGroupIfNeeded);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
/**
|
||||
*
|
||||
* 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.strategy;
|
||||
|
||||
import static org.easymock.EasyMock.eq;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.reportMatcher;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.easymock.IArgumentMatcher;
|
||||
import org.jclouds.aws.domain.Region;
|
||||
import org.jclouds.aws.ec2.compute.domain.EC2Size;
|
||||
import org.jclouds.aws.ec2.compute.functions.RunningInstanceToNodeMetadata;
|
||||
import org.jclouds.aws.ec2.compute.options.EC2TemplateOptions;
|
||||
import org.jclouds.aws.ec2.domain.AvailabilityZone;
|
||||
import org.jclouds.aws.ec2.domain.Reservation;
|
||||
import org.jclouds.aws.ec2.domain.RunningInstance;
|
||||
import org.jclouds.aws.ec2.options.RunInstancesOptions;
|
||||
import org.jclouds.aws.ec2.services.InstanceClient;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.jclouds.compute.util.ComputeUtils;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.LocationScope;
|
||||
import org.jclouds.domain.internal.LocationImpl;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "ec2.EC2RunNodesAndAddToSetStrategyTest")
|
||||
public class EC2RunNodesAndAddToSetStrategyTest {
|
||||
|
||||
@Test
|
||||
public void testZoneAsALocation() {
|
||||
assertRegionAndZoneForLocation(ZONE_AP_SOUTHEAST_1A, Region.AP_SOUTHEAST_1,
|
||||
AvailabilityZone.AP_SOUTHEAST_1A);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegionAsALocation() {
|
||||
assertRegionAndZoneForLocation(REGION_AP_SOUTHEAST_1, Region.AP_SOUTHEAST_1, null);
|
||||
}
|
||||
|
||||
// // fixtures
|
||||
|
||||
public static Iterable<NodeMetadata> containsNodeMetadata(final NodeMetadata in) {
|
||||
reportMatcher(new IArgumentMatcher() {
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuffer buffer) {
|
||||
buffer.append("contains(");
|
||||
buffer.append(in);
|
||||
buffer.append(")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object arg) {
|
||||
return Iterables.contains((Iterable<?>) arg, in);
|
||||
}
|
||||
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
private void assertRegionAndZoneForLocation(Location location, String region, String zone) {
|
||||
String imageId = "ami1";
|
||||
String instanceCreatedId = "instance1";
|
||||
// setup mocks
|
||||
EC2RunNodesAndAddToSetStrategy strategy = setupStrategy();
|
||||
InputParams input = new InputParams(location);
|
||||
RunInstancesOptions ec2Options = createMock(RunInstancesOptions.class);
|
||||
RunningInstance instance = createMock(RunningInstance.class);
|
||||
Reservation reservation = new Reservation(region, ImmutableSet.<String> of(), ImmutableSet
|
||||
.<RunningInstance> of(instance), "ownerId", "requesterId", "reservationId");
|
||||
NodeMetadata nodeMetadata = createMock(NodeMetadata.class);
|
||||
|
||||
// setup expectations
|
||||
expect(
|
||||
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.execute(region,
|
||||
input.tag, input.template)).andReturn(ec2Options);
|
||||
expect(input.template.getLocation()).andReturn(input.location).atLeastOnce();
|
||||
expect(input.template.getImage()).andReturn(input.image).atLeastOnce();
|
||||
expect(input.image.getId()).andReturn(imageId).atLeastOnce();
|
||||
expect(
|
||||
strategy.instanceClient.runInstancesInRegion(region, zone, imageId, 1, input.count,
|
||||
ec2Options)).andReturn(reservation);
|
||||
expect(instance.getId()).andReturn(instanceCreatedId).atLeastOnce();
|
||||
expect(strategy.instanceStateRunning.apply(instance)).andReturn(true);
|
||||
expect(strategy.instanceClient.describeInstancesInRegion(region, instanceCreatedId))
|
||||
.andReturn(ImmutableSet.of(reservation));
|
||||
expect(input.template.getOptions()).andReturn(input.options).atLeastOnce();
|
||||
|
||||
expect(strategy.runningInstanceToNodeMetadata.apply(instance)).andReturn(nodeMetadata);
|
||||
expect(
|
||||
strategy.utils.runOptionsOnNodesAndAddToGoodSetOrPutExceptionIntoBadMap(
|
||||
eq(input.options), containsNodeMetadata(nodeMetadata), eq(input.nodes),
|
||||
eq(input.badNodes))).andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
replay(ec2Options);
|
||||
replay(instance);
|
||||
replay(nodeMetadata);
|
||||
input.replayMe();
|
||||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
strategy.execute(input.tag, input.count, input.template, input.nodes, input.badNodes);
|
||||
|
||||
// verify mocks
|
||||
verify(ec2Options);
|
||||
verify(instance);
|
||||
verify(nodeMetadata);
|
||||
input.verifyMe();
|
||||
verifyStrategy(strategy);
|
||||
}
|
||||
|
||||
private static final Location REGION_AP_SOUTHEAST_1 = new LocationImpl(LocationScope.REGION,
|
||||
Region.AP_SOUTHEAST_1, Region.AP_SOUTHEAST_1, new LocationImpl(LocationScope.PROVIDER,
|
||||
"ec2", "ec2", null));
|
||||
private static final Location ZONE_AP_SOUTHEAST_1A = new LocationImpl(LocationScope.ZONE,
|
||||
AvailabilityZone.AP_SOUTHEAST_1A, AvailabilityZone.AP_SOUTHEAST_1A,
|
||||
REGION_AP_SOUTHEAST_1);
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////
|
||||
@SuppressWarnings("unchecked")
|
||||
private static class InputParams {
|
||||
String tag = "foo";
|
||||
int count = 1;
|
||||
Template template = createMock(Template.class);
|
||||
Set<NodeMetadata> nodes = createMock(Set.class);
|
||||
Map<NodeMetadata, Exception> badNodes = createMock(Map.class);
|
||||
EC2Size size = createMock(EC2Size.class);
|
||||
Image image = createMock(Image.class);
|
||||
final Location location;
|
||||
EC2TemplateOptions options = createMock(EC2TemplateOptions.class);
|
||||
|
||||
public InputParams(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
void replayMe() {
|
||||
replay(template);
|
||||
replay(size);
|
||||
replay(image);
|
||||
replay(nodes);
|
||||
replay(badNodes);
|
||||
replay(options);
|
||||
}
|
||||
|
||||
void verifyMe() {
|
||||
verify(template);
|
||||
verify(size);
|
||||
verify(image);
|
||||
verify(nodes);
|
||||
verify(badNodes);
|
||||
verify(options);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyStrategy(EC2RunNodesAndAddToSetStrategy strategy) {
|
||||
verify(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions);
|
||||
verify(strategy.instanceClient);
|
||||
verify(strategy.instanceStateRunning);
|
||||
verify(strategy.runningInstanceToNodeMetadata);
|
||||
verify(strategy.utils);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private EC2RunNodesAndAddToSetStrategy setupStrategy() {
|
||||
|
||||
InstanceClient instanceClient = createMock(InstanceClient.class);
|
||||
CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions = createMock(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class);
|
||||
Predicate<RunningInstance> instanceStateRunning = createMock(Predicate.class);
|
||||
RunningInstanceToNodeMetadata runningInstanceToNodeMetadata = createMock(RunningInstanceToNodeMetadata.class);
|
||||
ComputeUtils utils = createMock(ComputeUtils.class);
|
||||
return new EC2RunNodesAndAddToSetStrategy(instanceClient,
|
||||
createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions, instanceStateRunning,
|
||||
runningInstanceToNodeMetadata, utils);
|
||||
}
|
||||
|
||||
private void replayStrategy(EC2RunNodesAndAddToSetStrategy strategy) {
|
||||
replay(strategy.createKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions);
|
||||
replay(strategy.instanceClient);
|
||||
replay(strategy.instanceStateRunning);
|
||||
replay(strategy.runningInstanceToNodeMetadata);
|
||||
replay(strategy.utils);
|
||||
}
|
||||
|
||||
}
|
|
@ -93,15 +93,16 @@ public class TemplateBuilderImpl implements TemplateBuilder {
|
|||
@VisibleForTesting
|
||||
boolean fastest;
|
||||
|
||||
private TemplateOptions options = TemplateOptions.NONE;
|
||||
private TemplateOptions options;
|
||||
|
||||
@Inject
|
||||
protected TemplateBuilderImpl(Set<? extends Location> locations, Set<? extends Image> images,
|
||||
Set<? extends Size> sizes, Location defaultLocation) {
|
||||
Set<? extends Size> sizes, Location defaultLocation, TemplateOptions options) {
|
||||
this.locations = locations;
|
||||
this.images = images;
|
||||
this.sizes = sizes;
|
||||
this.locationId = defaultLocation.getId();
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
private final Predicate<ComputeMetadata> locationPredicate = new Predicate<ComputeMetadata>() {
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/**
|
||||
*
|
||||
* 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.compute.options;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
@ -6,7 +24,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Contains options supported in the {@code ComputeService#runNode} operation. <h2>
|
||||
* Contains options supported in the {@code ComputeService#runNodesWithTag} operation. <h2>
|
||||
* Usage</h2> The recommended way to instantiate a TemplateOptions object is to statically import
|
||||
* TemplateOptions.* and invoke a static creation method followed by an instance mutator (if
|
||||
* needed):
|
||||
|
@ -15,7 +33,8 @@ import java.util.Arrays;
|
|||
* import static org.jclouds.compute.options.TemplateOptions.Builder.*;
|
||||
* <p/>
|
||||
* ComputeService client = // get connection
|
||||
* NodeSet set = client.runNode(name, template.options(inboundPorts(22, 80, 8080, 443)));
|
||||
* templateBuilder.options(inboundPorts(22, 80, 8080, 443));
|
||||
* Set<? extends NodeMetadata> set = client.runNodesWithTag(tag, 2, templateBuilder.build());
|
||||
* <code>
|
||||
*
|
||||
* @author Adrian Cole
|
||||
|
@ -24,19 +43,19 @@ public class TemplateOptions {
|
|||
|
||||
public static final TemplateOptions NONE = new TemplateOptions();
|
||||
|
||||
private int[] inboundPorts = new int[] { 22 };
|
||||
protected int[] inboundPorts = new int[] { 22 };
|
||||
|
||||
private byte[] script;
|
||||
protected byte[] script;
|
||||
|
||||
private String privateKey;
|
||||
protected String privateKey;
|
||||
|
||||
private String publicKey;
|
||||
protected String publicKey;
|
||||
|
||||
private int port = -1;
|
||||
protected int port = -1;
|
||||
|
||||
private int seconds = -1;
|
||||
protected int seconds = -1;
|
||||
|
||||
private boolean includeMetadata;
|
||||
protected boolean includeMetadata;
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
|
@ -66,6 +85,10 @@ public class TemplateOptions {
|
|||
return includeMetadata;
|
||||
}
|
||||
|
||||
public <T extends TemplateOptions> T as(Class<T> clazz) {
|
||||
return clazz.cast(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the node is started, wait until the following port is active
|
||||
*/
|
||||
|
@ -180,4 +203,50 @@ public class TemplateOptions {
|
|||
+ (script != null) + ", port:seconds=" + port + ":" + seconds
|
||||
+ ", metadata/details: " + includeMetadata + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(inboundPorts);
|
||||
result = prime * result + (includeMetadata ? 1231 : 1237);
|
||||
result = prime * result + port;
|
||||
result = prime * result + ((privateKey == null) ? 0 : privateKey.hashCode());
|
||||
result = prime * result + ((publicKey == null) ? 0 : publicKey.hashCode());
|
||||
result = prime * result + Arrays.hashCode(script);
|
||||
result = prime * result + seconds;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
TemplateOptions other = (TemplateOptions) obj;
|
||||
if (!Arrays.equals(inboundPorts, other.inboundPorts))
|
||||
return false;
|
||||
if (includeMetadata != other.includeMetadata)
|
||||
return false;
|
||||
if (port != other.port)
|
||||
return false;
|
||||
if (privateKey == null) {
|
||||
if (other.privateKey != null)
|
||||
return false;
|
||||
} else if (!privateKey.equals(other.privateKey))
|
||||
return false;
|
||||
if (publicKey == null) {
|
||||
if (other.publicKey != null)
|
||||
return false;
|
||||
} else if (!publicKey.equals(other.publicKey))
|
||||
return false;
|
||||
if (!Arrays.equals(script, other.script))
|
||||
return false;
|
||||
if (seconds != other.seconds)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.jclouds.compute.util;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static org.jclouds.concurrent.ConcurrentUtils.awaitCompletion;
|
||||
import static org.jclouds.concurrent.ConcurrentUtils.makeListenable;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -85,6 +86,15 @@ public class ComputeUtils {
|
|||
private final Predicate<InetSocketAddress> socketTester;
|
||||
private final ExecutorService executor;
|
||||
|
||||
@Inject
|
||||
public ComputeUtils(Predicate<InetSocketAddress> socketTester,
|
||||
@Named("NOT_RUNNING") Predicate<CommandUsingClient> runScriptNotRunning,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
this.socketTester = socketTester;
|
||||
this.runScriptNotRunning = runScriptNotRunning;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public static String createExecutionErrorMessage(Map<?, Exception> executionExceptions) {
|
||||
Formatter fmt = new Formatter().format("Execution failures:%n%n");
|
||||
int index = 1;
|
||||
|
@ -96,6 +106,38 @@ public class ComputeUtils {
|
|||
return fmt.format("%s error[s]", executionExceptions.size()).toString();
|
||||
}
|
||||
|
||||
public Map<?, ListenableFuture<Void>> runOptionsOnNodesAndAddToGoodSetOrPutExceptionIntoBadMap(
|
||||
final TemplateOptions options, Iterable<NodeMetadata> runningNodes,
|
||||
final Set<NodeMetadata> goodNodes, final Map<NodeMetadata, Exception> badNodes) {
|
||||
Map<NodeMetadata, ListenableFuture<Void>> responses = Maps.newHashMap();
|
||||
for (final NodeMetadata node : runningNodes) {
|
||||
responses.put(node, makeListenable(executor
|
||||
.submit(runOptionsOnNodeAndAddToGoodSetOrPutExceptionIntoBadMap(node, badNodes,
|
||||
goodNodes, options)), executor));
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
||||
public Callable<Void> runOptionsOnNodeAndAddToGoodSetOrPutExceptionIntoBadMap(
|
||||
final NodeMetadata node, final Map<NodeMetadata, Exception> badNodes,
|
||||
final Set<NodeMetadata> goodNodes, final TemplateOptions options) {
|
||||
return new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
try {
|
||||
runOptionsOnNode(node, options);
|
||||
logger.debug("<< options applied node(%s)", node.getId());
|
||||
goodNodes.add(node);
|
||||
} catch (Exception e) {
|
||||
logger.error(e, "<< problem applying options to node(%s): ", node.getId(),
|
||||
Throwables.getRootCause(e).getMessage());
|
||||
badNodes.put(node, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static String createNodeErrorMessage(
|
||||
Map<? extends NodeMetadata, ? extends Throwable> failedNodes) {
|
||||
Formatter fmt = new Formatter().format("Node failures:%n%n");
|
||||
|
@ -108,15 +150,6 @@ public class ComputeUtils {
|
|||
return fmt.format("%s error[s]", failedNodes.size()).toString();
|
||||
}
|
||||
|
||||
@Inject
|
||||
public ComputeUtils(Predicate<InetSocketAddress> socketTester,
|
||||
@Named("NOT_RUNNING") Predicate<CommandUsingClient> runScriptNotRunning,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
||||
this.socketTester = socketTester;
|
||||
this.runScriptNotRunning = runScriptNotRunning;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public static Iterable<? extends ComputeMetadata> filterByName(
|
||||
Iterable<? extends ComputeMetadata> nodes, final String name) {
|
||||
return Iterables.filter(nodes, new Predicate<ComputeMetadata>() {
|
||||
|
|
|
@ -252,7 +252,7 @@ public abstract class BaseComputeServiceLiveTest {
|
|||
}
|
||||
}
|
||||
|
||||
private Map<NodeMetadata, ExecResponse> runScriptWithCreds(final String tag, OsFamily osFamily,
|
||||
protected Map<NodeMetadata, ExecResponse> runScriptWithCreds(final String tag, OsFamily osFamily,
|
||||
Credentials creds) throws RunScriptOnNodesException {
|
||||
try {
|
||||
return client.runScriptOnNodesMatching(new Predicate<NodeMetadata>() {
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.jclouds.compute.domain.Architecture;
|
|||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.domain.OsFamily;
|
||||
import org.jclouds.compute.domain.Size;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.LocationScope;
|
||||
import org.jclouds.domain.internal.LocationImpl;
|
||||
|
@ -41,8 +42,8 @@ public class TemplateBuilderImplTest {
|
|||
@Test
|
||||
public void testImageIdNullsEverythingElse() {
|
||||
TemplateBuilderImpl template = new TemplateBuilderImpl(ImmutableSet.<Location> of(),
|
||||
ImmutableSet.<Image> of(), ImmutableSet.<Size> of(),
|
||||
new LocationImpl(LocationScope.REGION, " id", "description", null));
|
||||
ImmutableSet.<Image> of(), ImmutableSet.<Size> of(), new LocationImpl(
|
||||
LocationScope.REGION, " id", "description", null), new TemplateOptions());
|
||||
template.architecture(Architecture.X86_32);
|
||||
template.imageDescriptionMatches("imageDescriptionMatches");
|
||||
template.imageNameMatches("imageNameMatches");
|
||||
|
|
Loading…
Reference in New Issue