mirror of https://github.com/apache/jclouds.git
openstack-nova: adding logic for implicit keypair option
This commit is contained in:
parent
e81ac99daa
commit
9045fa2463
|
@ -54,10 +54,13 @@ import org.jclouds.domain.Credentials;
|
|||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.openstack.nova.v1_1.NovaClient;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.KeyPair;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
|
||||
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient;
|
||||
import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupClient;
|
||||
import org.jclouds.openstack.nova.v1_1.predicates.KeyPairPredicates;
|
||||
import org.jclouds.openstack.nova.v1_1.predicates.SecurityGroupPredicates;
|
||||
import org.jclouds.scriptbuilder.functions.InitAdminAccess;
|
||||
|
||||
|
@ -77,6 +80,7 @@ import com.google.common.collect.Multimap;
|
|||
public class NovaComputeService extends BaseComputeService {
|
||||
private final NovaClient novaClient;
|
||||
private final LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap;
|
||||
private final LoadingCache<ZoneAndName, KeyPair> keyPairCache;
|
||||
private final Function<Set<? extends NodeMetadata>, Multimap<String, String>> orphanedGroupsByZoneId;
|
||||
|
||||
@Inject
|
||||
|
@ -96,6 +100,7 @@ public class NovaComputeService extends BaseComputeService {
|
|||
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, NovaClient novaClient,
|
||||
LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap,
|
||||
LoadingCache<ZoneAndName, KeyPair> keyPairCache,
|
||||
Function<Set<? extends NodeMetadata>, Multimap<String, String>> orphanedGroupsByZoneId) {
|
||||
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
||||
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
|
||||
|
@ -104,6 +109,7 @@ public class NovaComputeService extends BaseComputeService {
|
|||
timeouts, executor);
|
||||
this.novaClient = checkNotNull(novaClient, "novaClient");
|
||||
this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap");
|
||||
this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
|
||||
this.orphanedGroupsByZoneId = checkNotNull(orphanedGroupsByZoneId, "orphanedGroupsByZoneId");
|
||||
}
|
||||
|
||||
|
@ -117,6 +123,7 @@ public class NovaComputeService extends BaseComputeService {
|
|||
|
||||
protected void cleanOrphanedGroupsInZone(Set<String> groups, String zoneId) {
|
||||
cleanupOrphanedSecurityGroupsInZone(groups, zoneId);
|
||||
cleanupOrphanedKeyPairsInZone(groups, zoneId);
|
||||
}
|
||||
|
||||
private void cleanupOrphanedSecurityGroupsInZone(Set<String> groups, String zoneId) {
|
||||
|
@ -136,6 +143,24 @@ public class NovaComputeService extends BaseComputeService {
|
|||
}
|
||||
}
|
||||
|
||||
private void cleanupOrphanedKeyPairsInZone(Set<String> groups, String zoneId) {
|
||||
Optional<KeyPairClient> keyPairClient = novaClient.getKeyPairExtensionForZone(zoneId);
|
||||
if (keyPairClient.isPresent()) {
|
||||
for (String group : groups) {
|
||||
for (Map<String, KeyPair> wrapper : keyPairClient.get().listKeyPairs()) {
|
||||
for (KeyPair pair : Iterables.filter(wrapper.values(), KeyPairPredicates.nameStartsWith("jclouds#" + group + "#"))) {
|
||||
ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, pair.getName());
|
||||
logger.debug(">> deleting keypair(%s)", zoneAndName);
|
||||
keyPairClient.get().deleteKeyPair(pair.getName());
|
||||
// TODO: test this clear happens
|
||||
keyPairCache.invalidate(zoneAndName);
|
||||
logger.debug("<< deleted keypair(%s)", zoneAndName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns template options, except of type {@link NovaTemplateOptions}.
|
||||
*/
|
||||
|
|
|
@ -26,6 +26,7 @@ import javax.annotation.Resource;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import org.jclouds.compute.ComputeServiceAdapter;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
|
@ -39,12 +40,14 @@ import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions;
|
|||
import org.jclouds.openstack.nova.v1_1.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Flavor;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Image;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.KeyPair;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.RebootType;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.FlavorInZone;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ImageInZone;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ServerInZone;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
|
||||
import org.jclouds.openstack.nova.v1_1.options.CreateServerOptions;
|
||||
import org.jclouds.openstack.nova.v1_1.predicates.ImagePredicates;
|
||||
|
||||
|
@ -70,14 +73,17 @@ public class NovaComputeServiceAdapter implements
|
|||
protected final NovaClient novaClient;
|
||||
protected final Supplier<Set<String>> zoneIds;
|
||||
protected final RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate;
|
||||
protected final LoadingCache<ZoneAndName, KeyPair> keyPairCache;
|
||||
|
||||
@Inject
|
||||
public NovaComputeServiceAdapter(NovaClient novaClient, @Zone Supplier<Set<String>> zoneIds,
|
||||
RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate) {
|
||||
RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate,
|
||||
LoadingCache<ZoneAndName, KeyPair> keyPairCache) {
|
||||
this.novaClient = checkNotNull(novaClient, "novaClient");
|
||||
this.zoneIds = checkNotNull(zoneIds, "zoneIds");
|
||||
this.removeFloatingIpFromNodeAndDeallocate = checkNotNull(removeFloatingIpFromNodeAndDeallocate,
|
||||
"removeFloatingIpFromNodeAndDeallocate");
|
||||
this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,15 +95,26 @@ public class NovaComputeServiceAdapter implements
|
|||
public NodeAndInitialCredentials<ServerInZone> createNodeWithGroupEncodedIntoName(String group, String name,
|
||||
Template template) {
|
||||
|
||||
LoginCredentials.Builder credentialsBuilder = LoginCredentials.builder();
|
||||
NovaTemplateOptions templateOptions = template.getOptions().as(NovaTemplateOptions.class);
|
||||
CreateServerOptions options = new CreateServerOptions();
|
||||
options.securityGroupNames(template.getOptions().as(NovaTemplateOptions.class).getSecurityGroupNames());
|
||||
options.securityGroupNames(templateOptions.getSecurityGroupNames());
|
||||
|
||||
String keyName = templateOptions.getKeyPairName();
|
||||
if (keyName != null) {
|
||||
options.withKeyName(keyName);
|
||||
KeyPair keyPair = keyPairCache.getIfPresent(ZoneAndName.fromZoneAndName(template.getLocation().getId(), keyName));
|
||||
if (keyPair != null) {
|
||||
credentialsBuilder.privateKey(keyPair.getPrivateKey());
|
||||
}
|
||||
}
|
||||
|
||||
String zoneId = template.getLocation().getId();
|
||||
Server server = novaClient.getServerClientForZone(zoneId).createServer(name, template.getImage().getProviderId(),
|
||||
template.getHardware().getProviderId(), options);
|
||||
ServerInZone serverInZone = new ServerInZone(server, zoneId);
|
||||
return new NodeAndInitialCredentials<ServerInZone>(serverInZone, serverInZone.slashEncode(), LoginCredentials
|
||||
.builder().password(server.getAdminPass()).build());
|
||||
return new NodeAndInitialCredentials<ServerInZone>(serverInZone, serverInZone.slashEncode(), credentialsBuilder
|
||||
.password(server.getAdminPass()).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.jclouds.openstack.nova.v1_1.compute.config;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -42,16 +43,13 @@ import org.jclouds.openstack.nova.v1_1.NovaAsyncClient;
|
|||
import org.jclouds.openstack.nova.v1_1.NovaClient;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.NovaComputeService;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.NovaComputeServiceAdapter;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupIfNeeded;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.functions.FlavorInZoneToHardware;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.functions.ImageInZoneToImage;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.functions.NovaImageToOperatingSystem;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.functions.OrphanedGroupsByZoneId;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.functions.ServerInZoneToNodeMetadata;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.functions.*;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.loaders.FindKeyPairOrCreate;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.loaders.FindSecurityGroupOrCreate;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.loaders.LoadFloatingIpsForInstance;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.KeyPair;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.FlavorInZone;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ImageInZone;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
|
||||
|
@ -131,6 +129,11 @@ public class NovaComputeServiceContextModule
|
|||
bind(CreateNodesWithGroupEncodedIntoNameThenAddToSet.class).to(
|
||||
ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.class);
|
||||
|
||||
bind(new TypeLiteral<Function<ZoneAndName, KeyPair>>() {
|
||||
}).to(CreateUniqueKeyPair.class);
|
||||
|
||||
bind(new TypeLiteral<CacheLoader<ZoneAndName, KeyPair>>() {
|
||||
}).to(FindKeyPairOrCreate.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -166,6 +169,27 @@ public class NovaComputeServiceContextModule
|
|||
return new RetryablePredicate<AtomicReference<ZoneAndName>>(in, msDelay, 100l, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected LoadingCache<ZoneAndName, KeyPair> keyPairMap(
|
||||
CacheLoader<ZoneAndName, KeyPair> in) {
|
||||
return CacheBuilder.newBuilder().build(in);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Supplier<String> provideSuffix() {
|
||||
return new Supplier<String>() {
|
||||
final SecureRandom random = new SecureRandom();
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
return random.nextInt(100) + "";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Supplier<Map<String, Location>> createLocationIndexedById(
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.nova.v1_1.compute.functions;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.openstack.nova.v1_1.NovaClient;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.KeyPair;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
@Singleton
|
||||
public class CreateUniqueKeyPair implements Function<ZoneAndName, KeyPair> {
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
protected final NovaClient novaClient;
|
||||
protected final Supplier<String> randomSuffix;
|
||||
|
||||
@Inject
|
||||
public CreateUniqueKeyPair(NovaClient novaClient, Supplier<String> randomSuffix) {
|
||||
this.novaClient = checkNotNull(novaClient, "novaClient");
|
||||
this.randomSuffix = randomSuffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyPair apply(ZoneAndName zoneAndName) {
|
||||
checkNotNull(zoneAndName, "zoneAndName");
|
||||
return createNewKeyPairInZone(zoneAndName.getZone(), zoneAndName.getName());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
KeyPair createNewKeyPairInZone(String zone, String group) {
|
||||
checkNotNull(zone, "zone");
|
||||
checkNotNull(group, "group");
|
||||
logger.debug(">> creating keyPair zone(%s) group(%s)", zone, group);
|
||||
|
||||
KeyPair keyPair = null;
|
||||
while (keyPair == null) {
|
||||
try {
|
||||
keyPair = novaClient.getKeyPairExtensionForZone(zone).get().createKeyPair(getNextName(group));
|
||||
} catch (IllegalStateException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("<< created keyPair(%s)", keyPair);
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
private String getNextName(String group) {
|
||||
return String.format("jclouds#%s#%s", group, randomSuffix.get());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.nova.v1_1.compute.loaders;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.KeyPair;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
public class FindKeyPairOrCreate extends CacheLoader<ZoneAndName, KeyPair> {
|
||||
protected final Function<ZoneAndName, KeyPair> keypairCreator;
|
||||
|
||||
@Inject
|
||||
public FindKeyPairOrCreate(
|
||||
Function<ZoneAndName, KeyPair> keypairCreator) {
|
||||
this.keypairCreator = checkNotNull(keypairCreator, "keypairCreator");
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyPair load(ZoneAndName in) {
|
||||
// not retrieving KeyPairs from the server as the private key isn't returned
|
||||
return keypairCreator.apply(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "returnExistingKeyPairInZoneOrCreateAsNeeded()";
|
||||
}
|
||||
|
||||
}
|
|
@ -72,6 +72,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
private boolean autoAssignFloatingIp = false;
|
||||
private boolean generateKeyPair = false;
|
||||
private Set<String> securityGroupNames = ImmutableSet.of();
|
||||
private String keyPairName;
|
||||
|
||||
public static final NovaTemplateOptions NONE = new NovaTemplateOptions();
|
||||
|
||||
|
@ -91,6 +92,14 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #shouldGenerateKeyPair()
|
||||
*/
|
||||
public NovaTemplateOptions keyPairName(String keyPairName) {
|
||||
this.keyPairName = keyPairName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see org.jclouds.openstack.nova.v1_1.options.CreateServerOptions#getSecurityGroupNames
|
||||
|
@ -121,6 +130,14 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
return autoAssignFloatingIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the keypair used to run instances with
|
||||
* @return the keypair to be used
|
||||
*/
|
||||
public String getKeyPairName() {
|
||||
return keyPairName;
|
||||
}
|
||||
|
||||
/**
|
||||
* <h3>Note</h3>
|
||||
*
|
||||
|
@ -156,6 +173,13 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
|||
return new NovaTemplateOptions().generateKeyPair(enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see NovaTemplateOptions#getKeyPairName()
|
||||
*/
|
||||
public static NovaTemplateOptions keyPairName(String keyPairName) {
|
||||
return new NovaTemplateOptions().keyPairName(keyPairName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jclouds.openstack.nova.v1_1.options.CreateServerOptions#getSecurityGroupNames
|
||||
*/
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.jclouds.concurrent.Futures;
|
|||
import org.jclouds.openstack.nova.v1_1.NovaClient;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.functions.AllocateAndAddFloatingIpToNode;
|
||||
import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.KeyPair;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneSecurityGroupNameAndPorts;
|
||||
|
@ -66,6 +67,7 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
|
|||
|
||||
private final AllocateAndAddFloatingIpToNode allocateAndAddFloatingIpToNode;
|
||||
private final LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupCache;
|
||||
private final LoadingCache<ZoneAndName, KeyPair> keyPairCache;
|
||||
private final NovaClient novaClient;
|
||||
private final Provider<TemplateBuilder> templateBuilderProvider;
|
||||
|
||||
|
@ -78,11 +80,13 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
|
|||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
|
||||
Provider<TemplateBuilder> templateBuilderProvider,
|
||||
AllocateAndAddFloatingIpToNode allocateAndAddFloatingIpToNode,
|
||||
LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupCache, NovaClient novaClient) {
|
||||
LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupCache,
|
||||
LoadingCache<ZoneAndName, KeyPair> keyPairCache, NovaClient novaClient) {
|
||||
super(addNodeWithTagStrategy, listNodesStrategy, nodeNamingConvention, executor,
|
||||
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
|
||||
this.templateBuilderProvider = checkNotNull(templateBuilderProvider, "templateBuilderProvider");
|
||||
this.securityGroupCache = checkNotNull(securityGroupCache, "securityGroupCache");
|
||||
this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
|
||||
this.allocateAndAddFloatingIpToNode = checkNotNull(allocateAndAddFloatingIpToNode,
|
||||
"allocateAndAddFloatingIpToNode");
|
||||
this.novaClient = checkNotNull(novaClient, "novaClient");
|
||||
|
@ -93,9 +97,6 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
|
|||
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
|
||||
// ensure we don't mutate the input template
|
||||
Template mutableTemplate = templateBuilderProvider.get().fromTemplate(template).build();
|
||||
|
||||
// TODO: make NovaTemplateOptions with the following:
|
||||
// security group, key pair
|
||||
NovaTemplateOptions templateOptions = NovaTemplateOptions.class.cast(mutableTemplate.getOptions());
|
||||
|
||||
String zone = mutableTemplate.getLocation().getId();
|
||||
|
@ -110,6 +111,11 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
|
|||
checkArgument(novaClient.getKeyPairExtensionForZone(zone).isPresent(),
|
||||
"Key Pairs are required by options, but the extension is not available! options: %s",
|
||||
templateOptions);
|
||||
if (templateOptions.getKeyPairName() == null) {
|
||||
KeyPair keyPair = keyPairCache.getUnchecked(ZoneAndName.fromZoneAndName(zone, "jclouds#" + group));
|
||||
keyPairCache.asMap().put(ZoneAndName.fromZoneAndName(zone, keyPair.getName()), keyPair);
|
||||
templateOptions.keyPairName(keyPair.getName());
|
||||
}
|
||||
}
|
||||
|
||||
boolean securityGroupExensionPresent = novaClient.getSecurityGroupExtensionForZone(zone).isPresent();
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.nova.v1_1.predicates;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.KeyPair;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Predicates handy when working with KeyPairs
|
||||
*
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
|
||||
public class KeyPairPredicates {
|
||||
|
||||
/**
|
||||
* matches name of the given keypair starts with the specified prefix
|
||||
*
|
||||
* @param prefix the prefix you are looking for
|
||||
* @return the predicate
|
||||
*/
|
||||
public static Predicate<KeyPair> nameStartsWith(final String prefix) {
|
||||
checkNotNull(prefix, "name must be defined");
|
||||
|
||||
return new Predicate<KeyPair>() {
|
||||
@Override
|
||||
public boolean apply(KeyPair ext) {
|
||||
return ext.getName() != null && ext.getName().startsWith(prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "nameStartsWith(" + prefix + ")";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.nova.v1_1.compute.functions;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Supplier;
|
||||
import org.jclouds.openstack.nova.v1_1.NovaClient;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.KeyPair;
|
||||
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.*;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
@Test(groups = "unit")
|
||||
public class CreateUniqueKeyPairTest {
|
||||
|
||||
@Test
|
||||
public void testApply() throws UnknownHostException {
|
||||
NovaClient client = createMock(NovaClient.class);
|
||||
KeyPairClient keyClient = createMock(KeyPairClient.class);
|
||||
Supplier<String> uniqueIdSupplier = createMock(Supplier.class);
|
||||
|
||||
KeyPair pair = createMock(KeyPair.class);
|
||||
|
||||
expect(client.getKeyPairExtensionForZone("zone")).andReturn(Optional.of(keyClient)).atLeastOnce();
|
||||
|
||||
expect(uniqueIdSupplier.get()).andReturn("1");
|
||||
expect(keyClient.createKeyPair("jclouds#group#1")).andReturn(pair);
|
||||
|
||||
replay(client);
|
||||
replay(keyClient);
|
||||
replay(uniqueIdSupplier);
|
||||
|
||||
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(client, uniqueIdSupplier);
|
||||
|
||||
assertEquals(parser.createNewKeyPairInZone("zone", "group"), pair);
|
||||
|
||||
verify(client);
|
||||
verify(keyClient);
|
||||
verify(uniqueIdSupplier);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyWithIllegalStateException() throws UnknownHostException {
|
||||
NovaClient client = createMock(NovaClient.class);
|
||||
KeyPairClient keyClient = createMock(KeyPairClient.class);
|
||||
Supplier<String> uniqueIdSupplier = createMock(Supplier.class);
|
||||
|
||||
KeyPair pair = createMock(KeyPair.class);
|
||||
|
||||
expect(client.getKeyPairExtensionForZone("zone")).andReturn(Optional.of(keyClient)).atLeastOnce();
|
||||
|
||||
expect(uniqueIdSupplier.get()).andReturn("1");
|
||||
expect(keyClient.createKeyPair("jclouds#group#1")).andThrow(new IllegalStateException());
|
||||
expect(uniqueIdSupplier.get()).andReturn("2");
|
||||
expect(keyClient.createKeyPair("jclouds#group#2")).andReturn(pair);
|
||||
|
||||
replay(client);
|
||||
replay(keyClient);
|
||||
replay(uniqueIdSupplier);
|
||||
|
||||
CreateUniqueKeyPair parser = new CreateUniqueKeyPair(client, uniqueIdSupplier);
|
||||
|
||||
assertEquals(parser.createNewKeyPairInZone("zone", "group"), pair);
|
||||
|
||||
verify(client);
|
||||
verify(keyClient);
|
||||
verify(uniqueIdSupplier);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue