You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by an...@apache.org on 2017/07/17 09:41:42 UTC
[2/2] jclouds git commit: [JCLOUDS-1318] fix based on
nodeTerminatePredicate
[JCLOUDS-1318] fix based on nodeTerminatePredicate
- wait for serer deletion, before deleting the security group
- rename cleanupServer to cleanupResources
- remove keyPairCache
- better usage of tags to remove securityGroups created by jclouds
- remove keyPair after the creation of a group
- remove test for create unique keypair
- openstack nova re-adding support for existing keypair
- fix securityGroupApi check
- fix other unit tests
- remove ServerPredicates as it is now duplicated
- remove TemplateOptions.securityGroupNames as deprecated
- address commits for ApplyNovaTemplateOptionsCreatesNodesWithGroupEncodedIntoNameAndAddToSet
- fix testCreateNodeWhileUserSpecifiesKeyPairAndUserSpecifiedGroups
Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/aa11765b
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/aa11765b
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/aa11765b
Branch: refs/heads/master
Commit: aa11765bee8e5e7f2d062ba8123c0dced822f071
Parents: 0bc935d
Author: Andrea Turli <an...@gmail.com>
Authored: Thu Jul 6 18:18:44 2017 +0200
Committer: Andrea Turli <an...@gmail.com>
Committed: Mon Jul 17 11:32:24 2017 +0200
----------------------------------------------------------------------
.../nova/v2_0/compute/NovaComputeService.java | 10 +-
.../v2_0/compute/NovaComputeServiceAdapter.java | 82 ++++++-----
.../config/NovaComputeServiceContextModule.java | 131 +++++++++++------
.../AllocateAndAddFloatingIpToNode.java | 8 +-
.../compute/functions/CleanupResources.java | 106 ++++++++++++++
.../v2_0/compute/functions/CleanupServer.java | 123 ----------------
.../compute/loaders/CreateUniqueKeyPair.java | 76 ----------
.../compute/options/NovaTemplateOptions.java | 60 +-------
...desWithGroupEncodedIntoNameThenAddToSet.java | 140 ++++++++++++-------
.../nova/v2_0/options/CreateServerOptions.java | 3 -
.../nova/v2_0/predicates/ServerPredicates.java | 118 ----------------
.../NovaComputeServiceAdapterExpectTest.java | 26 ++--
.../compute/NovaComputeServiceExpectTest.java | 71 ++++++----
.../loaders/CreateUniqueKeyPairTest.java | 108 --------------
.../options/NovaTemplateOptionsTest.java | 50 -------
.../nova/v2_0/features/ServerApiLiveTest.java | 23 ++-
.../nova/v2_0/parse/ParseServerTest.java | 24 ++--
.../predicates/ServerPredicatesMockTest.java | 105 --------------
.../src/test/resources/logback-test.xml | 42 ++++++
.../src/test/resources/server_details.json | 2 +-
.../resources/server_details_suspended.json | 87 ++++++++++++
21 files changed, 549 insertions(+), 846 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java
index df3f1ca..584c95e 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java
@@ -54,7 +54,7 @@ import org.jclouds.compute.strategy.ResumeNodeStrategy;
import org.jclouds.compute.strategy.SuspendNodeStrategy;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
-import org.jclouds.openstack.nova.v2_0.compute.functions.CleanupServer;
+import org.jclouds.openstack.nova.v2_0.compute.functions.CleanupResources;
import org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions;
import org.jclouds.scriptbuilder.functions.InitAdminAccess;
@@ -65,7 +65,7 @@ import com.google.common.util.concurrent.ListeningExecutorService;
@Singleton
public class NovaComputeService extends BaseComputeService {
- protected final CleanupServer cleanupServer;
+ protected final CleanupResources cleanupResources;
@Inject
protected NovaComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@@ -83,7 +83,7 @@ public class NovaComputeService extends BaseComputeService {
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
- CleanupServer cleanupServer,
+ CleanupResources cleanupResources,
Optional<ImageExtension> imageExtension,
Optional<SecurityGroupExtension> securityGroupExtension) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getImageStrategy,
@@ -91,14 +91,14 @@ public class NovaComputeService extends BaseComputeService {
startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning,
nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory,
persistNodeCredentials, timeouts, userExecutor, imageExtension, securityGroupExtension);
- this.cleanupServer = checkNotNull(cleanupServer, "cleanupServer");
+ this.cleanupResources = checkNotNull(cleanupResources, "cleanupResources");
}
@Override
protected void cleanUpIncidentalResourcesOfDeadNodes(Set<? extends NodeMetadata> deadNodes) {
for (NodeMetadata deadNode : deadNodes) {
- cleanupServer.apply(deadNode.getId());
+ cleanupResources.apply(deadNode);
}
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java
index 9864d17..1149e94 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java
@@ -22,9 +22,11 @@ import static com.google.common.collect.Iterables.contains;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static java.lang.String.format;
-import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
+import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue;
-import static org.jclouds.util.Predicates2.retry;
+
+import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
@@ -39,32 +41,30 @@ import org.jclouds.domain.LoginCredentials;
import org.jclouds.location.Region;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v2_0.NovaApi;
-import org.jclouds.openstack.nova.v2_0.compute.functions.CleanupServer;
+import org.jclouds.openstack.nova.v2_0.compute.functions.CleanupResources;
import org.jclouds.openstack.nova.v2_0.compute.functions.RemoveFloatingIpFromNodeAndDeallocate;
import org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions;
import org.jclouds.openstack.nova.v2_0.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet;
import org.jclouds.openstack.nova.v2_0.domain.Flavor;
import org.jclouds.openstack.nova.v2_0.domain.Image;
-import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
import org.jclouds.openstack.nova.v2_0.domain.RebootType;
import org.jclouds.openstack.nova.v2_0.domain.Server;
import org.jclouds.openstack.nova.v2_0.domain.ServerCreated;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.FlavorInRegion;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ImageInRegion;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
-import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ServerInRegion;
import org.jclouds.openstack.nova.v2_0.options.CreateServerOptions;
import org.jclouds.openstack.nova.v2_0.predicates.ImagePredicates;
import com.google.common.base.Function;
import com.google.common.base.Objects;
-import com.google.common.base.Optional;
import com.google.common.base.Predicate;
+import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
-import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.collect.Sets;
/**
* The adapter used by the NovaComputeServiceContextModule to interface the nova-specific domain
@@ -80,20 +80,23 @@ public class NovaComputeServiceAdapter implements
protected final NovaApi novaApi;
protected final Supplier<Set<String>> regionIds;
protected final RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate;
- protected final LoadingCache<RegionAndName, KeyPair> keyPairCache;
- protected final CleanupServer cleanupServer;
-
+ private final Predicate<RegionAndId> serverRunningPredicate;
+ private final Predicate<RegionAndId> serverTerminatedPredicate;
+ private final CleanupResources cleanupResources;
@Inject
public NovaComputeServiceAdapter(NovaApi novaApi, @Region Supplier<Set<String>> regionIds,
- RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate,
- LoadingCache<RegionAndName, KeyPair> keyPairCache, CleanupServer cleanupServer) {
+ RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate,
+ @Named(TIMEOUT_NODE_RUNNING) Predicate<RegionAndId> serverRunningPredicate,
+ @Named(TIMEOUT_NODE_TERMINATED) Predicate<RegionAndId> serverTerminatedPredicate,
+ CleanupResources cleanupResources) {
this.novaApi = checkNotNull(novaApi, "novaApi");
this.regionIds = checkNotNull(regionIds, "regionIds");
this.removeFloatingIpFromNodeAndDeallocate = checkNotNull(removeFloatingIpFromNodeAndDeallocate,
"removeFloatingIpFromNodeAndDeallocate");
- this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
- this.cleanupServer = checkNotNull(cleanupServer, "cleanupServer");
+ this.serverRunningPredicate = serverRunningPredicate;
+ this.serverTerminatedPredicate = serverTerminatedPredicate;
+ this.cleanupResources = cleanupResources;
}
/**
@@ -104,18 +107,20 @@ public class NovaComputeServiceAdapter implements
@Override
public NodeAndInitialCredentials<ServerInRegion> createNodeWithGroupEncodedIntoName(String group, String name,
Template template) {
-
- LoginCredentials.Builder credentialsBuilder = LoginCredentials.builder();
+ final String regionId = template.getLocation().getId();
+ String imageId = template.getImage().getProviderId();
+ String flavorId = template.getHardware().getProviderId();
NovaTemplateOptions templateOptions = template.getOptions().as(NovaTemplateOptions.class);
CreateServerOptions options = new CreateServerOptions();
- options.metadata(metadataAndTagsAsCommaDelimitedValue(template.getOptions()));
- if (!templateOptions.getGroups().isEmpty())
- options.securityGroupNames(templateOptions.getGroups());
+ Map<String, String> metadataAndTagsAsCommaDelimitedValue = metadataAndTagsAsCommaDelimitedValue(template.getOptions());
+ options.metadata(metadataAndTagsAsCommaDelimitedValue);
+ if (!templateOptions.getGroups().isEmpty()) options.securityGroupNames(templateOptions.getGroups());
options.userData(templateOptions.getUserData());
options.diskConfig(templateOptions.getDiskConfig());
options.configDrive(templateOptions.getConfigDrive());
options.availabilityZone(templateOptions.getAvailabilityZone());
+
if (templateOptions.getNovaNetworks() != null) {
options.novaNetworks(templateOptions.getNovaNetworks());
}
@@ -123,41 +128,32 @@ public class NovaComputeServiceAdapter implements
options.networks(templateOptions.getNetworks());
}
- Optional<String> privateKey = Optional.absent();
if (templateOptions.getKeyPairName() != null) {
options.keyPairName(templateOptions.getKeyPairName());
- KeyPair keyPair = keyPairCache.getIfPresent(RegionAndName.fromRegionAndName(template.getLocation().getId(), templateOptions.getKeyPairName()));
- if (keyPair != null && keyPair.getPrivateKey() != null) {
- privateKey = Optional.of(keyPair.getPrivateKey());
- credentialsBuilder.privateKey(privateKey.get());
- }
}
-
-
- final String regionId = template.getLocation().getId();
- String imageId = template.getImage().getProviderId();
- String flavorId = template.getHardware().getProviderId();
-
+
logger.debug(">> creating new server region(%s) name(%s) image(%s) flavor(%s) options(%s)", regionId, name, imageId, flavorId, options);
final ServerCreated lightweightServer = novaApi.getServerApi(regionId).create(name, imageId, flavorId, options);
- if (!retry(new Predicate<String>() {
- @Override
- public boolean apply(String serverId) {
- Server server = novaApi.getServerApi(regionId).get(serverId);
- return server != null && server.getAddresses() != null && !server.getAddresses().isEmpty();
- }
- }, 30 * 60, 1, SECONDS).apply(lightweightServer.getId())) {
- final String message = format("Server %s was not created within %sms so it will be destroyed.", name, "30 * 60");
+ if (!serverRunningPredicate.apply(RegionAndId.fromRegionAndId(regionId, lightweightServer.getId()))) {
+ final String message = format("Server %s was not created within %sms. The resources created for it will be destroyed", name, "30 * 60");
logger.warn(message);
- destroyNode(RegionAndId.fromRegionAndId(regionId, lightweightServer.getId()).slashEncode());
+ String tagString = metadataAndTagsAsCommaDelimitedValue.get("jclouds_tags");
+ Set<String> tags = Sets.newHashSet(Splitter.on(',').split(tagString));
+ cleanupResources.removeSecurityGroupCreatedByJcloudsAndInvalidateCache(regionId, tags);
throw new IllegalStateException(message);
}
logger.trace("<< server(%s)", lightweightServer.getId());
Server server = novaApi.getServerApi(regionId).get(lightweightServer.getId());
ServerInRegion serverInRegion = new ServerInRegion(server, regionId);
- if (!privateKey.isPresent() && lightweightServer.getAdminPass().isPresent())
+
+ LoginCredentials.Builder credentialsBuilder = LoginCredentials.builder();
+ if (templateOptions.getLoginPrivateKey() != null) {
+ credentialsBuilder.privateKey(templateOptions.getLoginPrivateKey());
+ }
+ if (lightweightServer.getAdminPass().isPresent()) {
credentialsBuilder.password(lightweightServer.getAdminPass().get());
+ }
return new NodeAndInitialCredentials<ServerInRegion>(serverInRegion, serverInRegion.slashEncode(), credentialsBuilder
.build());
}
@@ -266,7 +262,9 @@ public class NovaComputeServiceAdapter implements
@Override
public void destroyNode(String id) {
- checkState(cleanupServer.apply(id), "server(%s) still there after deleting!?", id);
+ RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id);
+ novaApi.getServerApi(regionAndId.getRegion()).delete(regionAndId.getId());
+ checkState(serverTerminatedPredicate.apply(regionAndId), "server was not destroyed in the configured timeout");
}
@Override
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java
index cead92b..700a39b 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/config/NovaComputeServiceContextModule.java
@@ -16,7 +16,10 @@
*/
package org.jclouds.openstack.nova.v2_0.compute.config;
+import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
+import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
import static org.jclouds.openstack.nova.v2_0.config.NovaProperties.AUTO_ALLOCATE_FLOATING_IPS;
import static org.jclouds.openstack.nova.v2_0.config.NovaProperties.AUTO_GENERATE_KEYPAIRS;
import static org.jclouds.openstack.nova.v2_0.config.NovaProperties.TIMEOUT_SECURITYGROUP_PRESENT;
@@ -42,15 +45,17 @@ import org.jclouds.compute.domain.SecurityGroup;
import org.jclouds.compute.extensions.ImageExtension;
import org.jclouds.compute.extensions.SecurityGroupExtension;
import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet;
import org.jclouds.domain.Location;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.functions.IdentityFunction;
+import org.jclouds.openstack.nova.v2_0.NovaApi;
import org.jclouds.openstack.nova.v2_0.compute.NovaComputeService;
import org.jclouds.openstack.nova.v2_0.compute.NovaComputeServiceAdapter;
import org.jclouds.openstack.nova.v2_0.compute.extensions.NovaImageExtension;
import org.jclouds.openstack.nova.v2_0.compute.extensions.NovaSecurityGroupExtension;
-import org.jclouds.openstack.nova.v2_0.compute.functions.CleanupServer;
+import org.jclouds.openstack.nova.v2_0.compute.functions.CleanupResources;
import org.jclouds.openstack.nova.v2_0.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.openstack.nova.v2_0.compute.functions.FlavorInRegionToHardware;
import org.jclouds.openstack.nova.v2_0.compute.functions.ImageInRegionToImage;
@@ -58,14 +63,13 @@ import org.jclouds.openstack.nova.v2_0.compute.functions.ImageToOperatingSystem;
import org.jclouds.openstack.nova.v2_0.compute.functions.NovaSecurityGroupInRegionToSecurityGroup;
import org.jclouds.openstack.nova.v2_0.compute.functions.OrphanedGroupsByRegionId;
import org.jclouds.openstack.nova.v2_0.compute.functions.ServerInRegionToNodeMetadata;
-import org.jclouds.openstack.nova.v2_0.compute.loaders.CreateUniqueKeyPair;
import org.jclouds.openstack.nova.v2_0.compute.loaders.FindSecurityGroupOrCreate;
import org.jclouds.openstack.nova.v2_0.compute.loaders.LoadFloatingIpsForInstance;
import org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions;
import org.jclouds.openstack.nova.v2_0.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet;
import org.jclouds.openstack.nova.v2_0.domain.FloatingIP;
-import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
import org.jclouds.openstack.nova.v2_0.domain.Server;
+import org.jclouds.openstack.nova.v2_0.domain.Server.Status;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.FlavorInRegion;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ImageInRegion;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
@@ -142,17 +146,14 @@ public class NovaComputeServiceContextModule extends
bind(CreateNodesWithGroupEncodedIntoNameThenAddToSet.class).to(
ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.class);
- bind(new TypeLiteral<CacheLoader<RegionAndName, KeyPair>>() {
- }).to(CreateUniqueKeyPair.class);
-
bind(new TypeLiteral<ImageExtension>() {
}).to(NovaImageExtension.class);
bind(new TypeLiteral<SecurityGroupExtension>() {
}).to(NovaSecurityGroupExtension.class);
- bind(new TypeLiteral<Function<String, Boolean>>() {
- }).to(CleanupServer.class);
+ bind(new TypeLiteral<Function<NodeMetadata, Boolean>>() {
+ }).to(CleanupResources.class);
}
@Override
@@ -165,6 +166,23 @@ public class NovaComputeServiceContextModule extends
}
@Provides
+ @com.google.inject.name.Named(TIMEOUT_NODE_RUNNING)
+ protected Predicate<RegionAndId> provideServerRunningPredicate(final NovaApi api,
+ ComputeServiceConstants.Timeouts timeouts,
+ ComputeServiceConstants.PollPeriod pollPeriod) {
+ return retry(new ServerInStatusPredicate(api, Status.ACTIVE), timeouts.nodeRunning,
+ pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
+ }
+
+ @Provides
+ @com.google.inject.name.Named(TIMEOUT_NODE_TERMINATED)
+ protected Predicate<RegionAndId> provideServerTerminatedPredicate(final NovaApi api, ComputeServiceConstants.Timeouts timeouts,
+ ComputeServiceConstants.PollPeriod pollPeriod) {
+ return retry(new ServerTerminatedPredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod,
+ pollPeriod.pollMaxPeriod);
+ }
+
+ @Provides
@Singleton
@Named("FLOATINGIP")
protected final LoadingCache<RegionAndId, Iterable<? extends FloatingIP>> instanceToFloatingIps(
@@ -196,13 +214,6 @@ public class NovaComputeServiceContextModule extends
@Provides
@Singleton
- protected final LoadingCache<RegionAndName, KeyPair> keyPairMap(
- CacheLoader<RegionAndName, KeyPair> in) {
- return CacheBuilder.newBuilder().build(in);
- }
-
- @Provides
- @Singleton
protected final Supplier<Map<String, Location>> createLocationIndexedById(
@Memoized Supplier<Set<? extends Location>> locations) {
return Suppliers.compose(new Function<Set<? extends Location>, Map<String, Location>>() {
@@ -226,35 +237,35 @@ public class NovaComputeServiceContextModule extends
}
@VisibleForTesting
- public static final Map<Server.Status, NodeMetadata.Status> toPortableNodeStatus = ImmutableMap
- .<Server.Status, NodeMetadata.Status> builder()
- .put(Server.Status.ACTIVE, NodeMetadata.Status.RUNNING)
- .put(Server.Status.BUILD, NodeMetadata.Status.PENDING)
- .put(Server.Status.DELETED, NodeMetadata.Status.TERMINATED)
- .put(Server.Status.ERROR, NodeMetadata.Status.ERROR)
- .put(Server.Status.HARD_REBOOT, NodeMetadata.Status.PENDING)
- .put(Server.Status.MIGRATING, NodeMetadata.Status.PENDING)
- .put(Server.Status.PASSWORD, NodeMetadata.Status.PENDING)
- .put(Server.Status.PAUSED, NodeMetadata.Status.SUSPENDED)
- .put(Server.Status.REBOOT, NodeMetadata.Status.PENDING)
- .put(Server.Status.REBUILD, NodeMetadata.Status.PENDING)
- .put(Server.Status.RESCUE, NodeMetadata.Status.PENDING)
- .put(Server.Status.RESIZE, NodeMetadata.Status.PENDING)
- .put(Server.Status.REVERT_RESIZE, NodeMetadata.Status.PENDING)
- .put(Server.Status.SHELVED, NodeMetadata.Status.SUSPENDED)
- .put(Server.Status.SHELVED_OFFLOADED, NodeMetadata.Status.SUSPENDED)
- .put(Server.Status.SHUTOFF, NodeMetadata.Status.SUSPENDED)
- .put(Server.Status.SOFT_DELETED, NodeMetadata.Status.TERMINATED)
- .put(Server.Status.STOPPED, NodeMetadata.Status.SUSPENDED)
- .put(Server.Status.SUSPENDED, NodeMetadata.Status.SUSPENDED)
- .put(Server.Status.UNKNOWN, NodeMetadata.Status.UNRECOGNIZED)
- .put(Server.Status.UNRECOGNIZED, NodeMetadata.Status.UNRECOGNIZED)
- .put(Server.Status.VERIFY_RESIZE, NodeMetadata.Status.PENDING)
+ public static final Map<Status, NodeMetadata.Status> toPortableNodeStatus = ImmutableMap
+ .<Status, NodeMetadata.Status> builder()
+ .put(Status.ACTIVE, NodeMetadata.Status.RUNNING)
+ .put(Status.BUILD, NodeMetadata.Status.PENDING)
+ .put(Status.DELETED, NodeMetadata.Status.TERMINATED)
+ .put(Status.ERROR, NodeMetadata.Status.ERROR)
+ .put(Status.HARD_REBOOT, NodeMetadata.Status.PENDING)
+ .put(Status.MIGRATING, NodeMetadata.Status.PENDING)
+ .put(Status.PASSWORD, NodeMetadata.Status.PENDING)
+ .put(Status.PAUSED, NodeMetadata.Status.SUSPENDED)
+ .put(Status.REBOOT, NodeMetadata.Status.PENDING)
+ .put(Status.REBUILD, NodeMetadata.Status.PENDING)
+ .put(Status.RESCUE, NodeMetadata.Status.PENDING)
+ .put(Status.RESIZE, NodeMetadata.Status.PENDING)
+ .put(Status.REVERT_RESIZE, NodeMetadata.Status.PENDING)
+ .put(Status.SHELVED, NodeMetadata.Status.SUSPENDED)
+ .put(Status.SHELVED_OFFLOADED, NodeMetadata.Status.SUSPENDED)
+ .put(Status.SHUTOFF, NodeMetadata.Status.SUSPENDED)
+ .put(Status.SOFT_DELETED, NodeMetadata.Status.TERMINATED)
+ .put(Status.STOPPED, NodeMetadata.Status.SUSPENDED)
+ .put(Status.SUSPENDED, NodeMetadata.Status.SUSPENDED)
+ .put(Status.UNKNOWN, NodeMetadata.Status.UNRECOGNIZED)
+ .put(Status.UNRECOGNIZED, NodeMetadata.Status.UNRECOGNIZED)
+ .put(Status.VERIFY_RESIZE, NodeMetadata.Status.PENDING)
.build();
@Singleton
@Provides
- protected final Map<Server.Status, NodeMetadata.Status> toPortableNodeStatus() {
+ protected final Map<Status, NodeMetadata.Status> toPortableNodeStatus() {
return toPortableNodeStatus;
}
@@ -268,6 +279,46 @@ public class NovaComputeServiceContextModule extends
.put(org.jclouds.openstack.nova.v2_0.domain.Image.Status.UNKNOWN, Image.Status.UNRECOGNIZED)
.put(org.jclouds.openstack.nova.v2_0.domain.Image.Status.UNRECOGNIZED, Image.Status.UNRECOGNIZED).build();
+
+ @VisibleForTesting
+ static class ServerInStatusPredicate implements Predicate<RegionAndId> {
+
+ private final NovaApi api;
+ private final Status status;
+
+ public ServerInStatusPredicate(NovaApi api, Status status) {
+ this.api = checkNotNull(api, "api must not be null");
+ this.status = checkNotNull(status, "status must not be null");
+ }
+
+ @Override
+ public boolean apply(RegionAndId regionAndId) {
+ checkNotNull(regionAndId, "regionAndId");
+ Server server = api.getServerApi(regionAndId.getRegion()).get(regionAndId.getId());
+ if (server == null) {
+ throw new IllegalStateException(String.format("Server %s not found.", regionAndId.getId()));
+ }
+ return status.equals(server.getStatus());
+ }
+ }
+
+ @VisibleForTesting
+ static class ServerTerminatedPredicate implements Predicate<RegionAndId> {
+
+ private final NovaApi api;
+
+ public ServerTerminatedPredicate(NovaApi api) {
+ this.api = checkNotNull(api, "api must not be null");
+ }
+
+ @Override
+ public boolean apply(RegionAndId regionAndId) {
+ checkNotNull(regionAndId, "regionAndId");
+ Server server = api.getServerApi(regionAndId.getRegion()).get(regionAndId.getId());
+ return server == null;
+ }
+ }
+
@Singleton
@Provides
protected final Map<org.jclouds.openstack.nova.v2_0.domain.Image.Status, Image.Status> toPortableImageStatus() {
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNode.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNode.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNode.java
index 7689b53..ec7aaf8 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNode.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNode.java
@@ -64,15 +64,15 @@ public class AllocateAndAddFloatingIpToNode implements
private final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
private final NovaApi novaApi;
private final LoadingCache<RegionAndId, Iterable<? extends FloatingIP>> floatingIpCache;
- private final CleanupServer cleanupServer;
+ private final CleanupResources cleanupResources;
@Inject
public AllocateAndAddFloatingIpToNode(@Named(TIMEOUT_NODE_RUNNING) Predicate<AtomicReference<NodeMetadata>> nodeRunning,
- NovaApi novaApi, @Named("FLOATINGIP") LoadingCache<RegionAndId, Iterable<? extends FloatingIP>> floatingIpCache, CleanupServer cleanupServer) {
+ NovaApi novaApi, @Named("FLOATINGIP") LoadingCache<RegionAndId, Iterable<? extends FloatingIP>> floatingIpCache, CleanupResources cleanupResources) {
this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
this.novaApi = checkNotNull(novaApi, "novaApi");
this.floatingIpCache = checkNotNull(floatingIpCache, "floatingIpCache");
- this.cleanupServer = checkNotNull(cleanupServer, "cleanupServer");
+ this.cleanupResources = checkNotNull(cleanupResources, "cleanupResources");
}
@Override
@@ -86,7 +86,7 @@ public class AllocateAndAddFloatingIpToNode implements
Optional<FloatingIP> ip = allocateFloatingIPForNode(floatingIpApi, poolNames, node.getId());
if (!ip.isPresent()) {
- cleanupServer.apply(node.getId());
+ cleanupResources.apply(node);
throw new InsufficientResourcesException("Failed to allocate a FloatingIP for node(" + node.getId() + ")");
}
logger.debug(">> adding floatingIp(%s) to node(%s)", ip.get().getIp(), node.getId());
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupResources.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupResources.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupResources.java
new file mode 100644
index 0000000..9030395
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupResources.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * 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.v2_0.compute.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.nova.v2_0.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.JCLOUDS_SG_PREFIX;
+
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.logging.Logger;
+import org.jclouds.openstack.nova.v2_0.NovaApi;
+import org.jclouds.openstack.nova.v2_0.domain.SecurityGroup;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
+import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.FluentIterable;
+
+@Singleton
+public class CleanupResources implements Function<NodeMetadata, Boolean> {
+
+ @Resource
+ @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ protected final NovaApi novaApi;
+ protected final RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate;
+ protected final LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupMap;
+
+ @Inject
+ public CleanupResources(NovaApi novaApi, RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate,
+ LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupMap) {
+
+ this.novaApi = novaApi;
+ this.removeFloatingIpFromNodeAndDeallocate = removeFloatingIpFromNodeAndDeallocate;
+ this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap");
+ }
+
+ @Override
+ public Boolean apply(NodeMetadata node) {
+ final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(node.getId());
+ removeFloatingIpFromNodeifAny(regionAndId);
+ return removeSecurityGroupCreatedByJcloudsAndInvalidateCache(regionAndId.getRegion(), node.getTags());
+ }
+
+ public boolean removeSecurityGroupCreatedByJcloudsAndInvalidateCache(String regionId, Set<String> tags) {
+ String securityGroupIdCreatedByJclouds = getSecurityGroupIdCreatedByJclouds(tags);
+ if (securityGroupIdCreatedByJclouds != null) {
+ SecurityGroup securityGroup = novaApi.getSecurityGroupApi(regionId).get().get(securityGroupIdCreatedByJclouds);
+ RegionAndName regionAndName = RegionAndName.fromRegionAndName(regionId, securityGroup.getName());
+ logger.debug(">> deleting securityGroup(%s)", regionAndName);
+ novaApi.getSecurityGroupApi(regionId).get().delete(securityGroupIdCreatedByJclouds);
+ securityGroupMap.invalidate(regionAndName);
+ logger.debug("<< deleted securityGroup(%s)", regionAndName);
+ return true;
+ }
+ return false;
+ }
+
+ private void removeFloatingIpFromNodeifAny(RegionAndId regionAndId) {
+ try {
+ removeFloatingIpFromNodeAndDeallocate.apply(regionAndId);
+ } catch (RuntimeException e) {
+ logger.warn(e, "<< error removing and deallocating ip from node(%s): %s", regionAndId, e.getMessage());
+ }
+ }
+
+ private String getSecurityGroupIdCreatedByJclouds(Set<String> tags) {
+ return FluentIterable.from(tags).filter(new Predicate<String>() {
+ @Override
+ public boolean apply(String input) {
+ return input.startsWith(JCLOUDS_SG_PREFIX);
+ }
+ }).transform(new Function<String, String>() {
+ @Override
+ public String apply(String input) {
+ return input.substring(JCLOUDS_SG_PREFIX.length() + 1);
+ }
+ }).first().orNull();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupServer.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupServer.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupServer.java
deleted file mode 100644
index 5a922e8..0000000
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CleanupServer.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * 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.v2_0.compute.functions;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.jclouds.openstack.nova.v2_0.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.JCLOUDS_KP;
-import static org.jclouds.openstack.nova.v2_0.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.JCLOUDS_SG;
-
-import javax.annotation.Resource;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.jclouds.compute.reference.ComputeServiceConstants;
-import org.jclouds.logging.Logger;
-import org.jclouds.openstack.nova.v2_0.NovaApi;
-import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
-import org.jclouds.openstack.nova.v2_0.domain.SecurityGroup;
-import org.jclouds.openstack.nova.v2_0.domain.Server;
-import org.jclouds.openstack.nova.v2_0.domain.ServerWithSecurityGroups;
-import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndId;
-import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
-import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
-
-import com.google.common.base.Function;
-import com.google.common.cache.LoadingCache;
-
-@Singleton
-public class CleanupServer implements Function<String, Boolean> {
-
- @Resource
- @Named(ComputeServiceConstants.COMPUTE_LOGGER)
- protected Logger logger = Logger.NULL;
-
- protected final NovaApi novaApi;
- protected final RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate;
- protected final LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupMap;
- protected final LoadingCache<RegionAndName, KeyPair> keyPairCache;
-
- @Inject
- public CleanupServer(NovaApi novaApi, RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate,
- LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupMap,
- LoadingCache<RegionAndName, KeyPair> keyPairCache) {
- this.novaApi = novaApi;
- this.removeFloatingIpFromNodeAndDeallocate = removeFloatingIpFromNodeAndDeallocate;
- this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap");
- this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
-
- }
-
- @Override
- public Boolean apply(String id) {
- final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id);
- boolean secGroupsPresent = novaApi.getServerWithSecurityGroupsApi(regionAndId.getRegion()).isPresent();
- Server server;
-
- if (secGroupsPresent) {
- server = novaApi.getServerWithSecurityGroupsApi(regionAndId.getRegion()).get()
- .get(regionAndId.getId());
- } else {
- server = novaApi.getServerApi(regionAndId.getRegion()).get(regionAndId.getId());
- }
-
- if (novaApi.getFloatingIPApi(regionAndId.getRegion()).isPresent()) {
- try {
- removeFloatingIpFromNodeAndDeallocate.apply(regionAndId);
- } catch (RuntimeException e) {
- logger.warn(e, "<< error removing and deallocating ip from node(%s): %s", id, e.getMessage());
- }
- }
-
- if (containsMetadata(server, JCLOUDS_KP)) {
- if (novaApi.getKeyPairApi(regionAndId.getRegion()).isPresent()) {
- RegionAndName regionAndName = RegionAndName.fromRegionAndName(regionAndId.getRegion(), server.getKeyName());
- logger.debug(">> deleting keypair(%s)", regionAndName);
- novaApi.getKeyPairApi(regionAndId.getRegion()).get().delete(server.getKeyName());
- // TODO: test this clear happens
- keyPairCache.invalidate(regionAndName);
- logger.debug("<< deleted keypair(%s)", regionAndName);
- }
- }
-
- boolean serverDeleted = novaApi.getServerApi(regionAndId.getRegion()).delete(regionAndId.getId());
-
- if (containsMetadata(server, JCLOUDS_SG) && secGroupsPresent) {
- for (final String securityGroupName : ((ServerWithSecurityGroups)server).getSecurityGroupNames()) {
- for (SecurityGroup securityGroup : novaApi.getSecurityGroupApi(regionAndId.getRegion()).get().list().toList()) {
- if (securityGroup.getName().equalsIgnoreCase(securityGroupName)) {
- if (novaApi.getSecurityGroupApi(regionAndId.getRegion()).isPresent()) {
- RegionAndName regionAndName = RegionAndName.fromRegionAndName(regionAndId.getRegion(), securityGroup.getName());
- logger.debug(">> deleting securityGroup(%s)", regionAndName);
- novaApi.getSecurityGroupApi(regionAndId.getRegion()).get().delete(securityGroup.getId());
- // TODO: test this clear happens
- securityGroupMap.invalidate(regionAndName);
- logger.debug("<< deleted securityGroup(%s)", regionAndName);
- }
- }
- }
- }
- }
- return serverDeleted;
- }
-
- private boolean containsMetadata(Server server, String key) {
- if (server == null || server.getMetadata() == null || server.getMetadata().get("jclouds_tags") == null)
- return false;
- return server.getMetadata().get("jclouds_tags").contains(key);
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java
deleted file mode 100644
index 9d521c4..0000000
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * 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.v2_0.compute.loaders;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import javax.annotation.Resource;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.jclouds.compute.functions.GroupNamingConvention;
-import org.jclouds.compute.reference.ComputeServiceConstants;
-import org.jclouds.logging.Logger;
-import org.jclouds.openstack.nova.v2_0.NovaApi;
-import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
-import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
-import org.jclouds.openstack.nova.v2_0.extensions.KeyPairApi;
-
-import com.google.common.base.Optional;
-import com.google.common.cache.CacheLoader;
-import com.google.inject.Inject;
-
-@Singleton
-public class CreateUniqueKeyPair extends CacheLoader<RegionAndName, KeyPair> {
- @Resource
- @Named(ComputeServiceConstants.COMPUTE_LOGGER)
- protected Logger logger = Logger.NULL;
- protected final NovaApi novaApi;
- protected final GroupNamingConvention.Factory namingConvention;
-
- @Inject
- public CreateUniqueKeyPair(NovaApi novaApi, GroupNamingConvention.Factory namingConvention) {
- this.novaApi = checkNotNull(novaApi, "novaApi");
- this.namingConvention = checkNotNull(namingConvention, "namingConvention");
- }
-
- @Override
- public KeyPair load(RegionAndName regionAndName) {
- String regionId = checkNotNull(regionAndName, "regionAndName").getRegion();
- String prefix = regionAndName.getName();
-
- Optional<? extends KeyPairApi> api = novaApi.getKeyPairApi(regionId);
- checkArgument(api.isPresent(), "Key pairs are required, but the extension is not available in region %s!",
- regionId);
-
- logger.debug(">> creating keyPair region(%s) prefix(%s)", regionId, prefix);
-
- KeyPair keyPair = null;
- while (keyPair == null) {
- try {
- keyPair = api.get().create(namingConvention.createWithoutPrefix().uniqueNameForGroup(prefix));
- } catch (IllegalStateException e) {
-
- }
- }
-
- logger.debug("<< created keyPair(%s)", keyPair.getName());
- return keyPair;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java
index d8939ad..2811e05 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java
@@ -27,7 +27,9 @@ import java.util.Set;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.LoginCredentials;
+import org.jclouds.openstack.nova.v2_0.NovaApi;
import org.jclouds.openstack.nova.v2_0.domain.Network;
+import org.jclouds.openstack.nova.v2_0.options.CreateServerOptions;
import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.base.Objects;
@@ -65,8 +67,6 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
eTo.autoAssignFloatingIp(shouldAutoAssignFloatingIp());
if (getFloatingIpPoolNames().isPresent())
eTo.floatingIpPoolNames(getFloatingIpPoolNames().get());
- if (getSecurityGroupNames().isPresent())
- eTo.securityGroupNames(getSecurityGroupNames().get());
eTo.generateKeyPair(shouldGenerateKeyPair());
eTo.keyPairName(getKeyPairName());
if (getUserData() != null) {
@@ -134,8 +134,6 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
return toString;
}
- public static final NovaTemplateOptions NONE = new NovaTemplateOptions();
-
/**
* @see #getFloatingIpPoolNames()
*/
@@ -178,31 +176,9 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
}
/**
- *
- * @see org.jclouds.openstack.nova.v2_0.options.CreateServerOptions#getSecurityGroupNames
- * @deprecated Use @link {@link TemplateOptions#securityGroups(String...)} instead. To be removed in jclouds 2.0.
- */
- @Deprecated
- public NovaTemplateOptions securityGroupNames(String... securityGroupNames) {
- return securityGroupNames(ImmutableSet.copyOf(checkNotNull(securityGroupNames, "securityGroupNames")));
- }
-
- /**
- * @see org.jclouds.openstack.nova.v2_0.options.CreateServerOptions#getSecurityGroupNames
- * @deprecated Use {@link TemplateOptions#securityGroups(Iterable)} instead. To be removed in jclouds 2.0.
- */
- @Deprecated
- public NovaTemplateOptions securityGroupNames(Iterable<String> securityGroupNames) {
- for (String groupName : checkNotNull(securityGroupNames, "securityGroupNames"))
- checkNotNull(emptyToNull(groupName), "all security groups must be non-empty");
- securityGroups(securityGroupNames);
- return this;
- }
-
- /**
* <h3>Note</h3>
*
- * This requires that {@link NovaApi#getExtensionForRegion(String)} to return
+ * This requires that {@link NovaApi#getExtensionApi(String)} to return
* {@link Optional#isPresent present}
*
* @return true if auto assignment of a floating ip to each vm is enabled
@@ -242,7 +218,7 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
/**
* <h3>Note</h3>
*
- * This requires that {@link NovaApi#getKeyPairExtensionApi(String)} to return
+ * This requires that {@link NovaApi#getKeyPairApi(String)} to return
* {@link Optional#isPresent present}
*
* @return true if auto generation of keypairs is enabled
@@ -251,18 +227,6 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
return generateKeyPair;
}
- /**
- * if unset, generate a default group prefixed with {@link jclouds#} according
- * to {@link #getInboundPorts()}
- *
- * @see org.jclouds.openstack.nova.v2_0.options.CreateServerOptions#getSecurityGroupNames
- * @deprecated Use {@link TemplateOptions#getGroups()} instead. To be removed in jclouds 2.0.
- */
- @Deprecated
- public Optional<Set<String>> getSecurityGroupNames() {
- return getGroups().isEmpty() ? Optional.<Set<String>>absent() : Optional.of(getGroups());
- }
-
public byte[] getUserData() {
return userData;
}
@@ -334,22 +298,6 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
return new NovaTemplateOptions().keyPairName(keyPairName);
}
- /**
- * @see org.jclouds.openstack.nova.v2_0.options.CreateServerOptions#getSecurityGroupNames
- */
- public static NovaTemplateOptions securityGroupNames(String... groupNames) {
- NovaTemplateOptions options = new NovaTemplateOptions();
- return NovaTemplateOptions.class.cast(options.securityGroupNames(groupNames));
- }
-
- /**
- * @see org.jclouds.openstack.nova.v2_0.options.CreateServerOptions#getSecurityGroupNames
- */
- public static NovaTemplateOptions securityGroupNames(Iterable<String> groupNames) {
- NovaTemplateOptions options = new NovaTemplateOptions();
- return NovaTemplateOptions.class.cast(options.securityGroupNames(groupNames));
- }
-
// methods that only facilitate returning the correct object type
/**
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java
index ca02357..673781c 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java
@@ -18,7 +18,6 @@ package org.jclouds.openstack.nova.v2_0.compute.strategy;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
-import static org.jclouds.ssh.SshKeys.fingerprintPrivateKey;
import java.util.List;
import java.util.Map;
@@ -35,7 +34,6 @@ import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.functions.GroupNamingConvention;
-import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.ListNodesStrategy;
@@ -50,12 +48,14 @@ import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionSecurityGroupNa
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.SecurityGroupInRegion;
import com.google.common.base.Function;
+import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import com.google.common.primitives.Ints;
import com.google.common.util.concurrent.Atomics;
+import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
@@ -64,12 +64,10 @@ import com.google.common.util.concurrent.ListeningExecutorService;
public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet extends
CreateNodesWithGroupEncodedIntoNameThenAddToSet {
- public static final String JCLOUDS_SG = "jclouds_securityGroup";
- public static final String JCLOUDS_KP = "jclouds_keyPair";
+ public static final String JCLOUDS_SG_PREFIX = "jclouds_sg";
private final AllocateAndAddFloatingIpToNode createAndAddFloatingIpToNode;
protected final LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupCache;
- protected final LoadingCache<RegionAndName, KeyPair> keyPairCache;
protected final NovaApi novaApi;
@Inject
@@ -80,12 +78,10 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
AllocateAndAddFloatingIpToNode createAndAddFloatingIpToNode,
- LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupCache,
- LoadingCache<RegionAndName, KeyPair> keyPairCache, NovaApi novaApi) {
+ LoadingCache<RegionAndName, SecurityGroupInRegion> securityGroupCache, NovaApi novaApi) {
super(addNodeWithTagStrategy, listNodesStrategy, namingConvention, userExecutor,
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
this.securityGroupCache = checkNotNull(securityGroupCache, "securityGroupCache");
- this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
this.createAndAddFloatingIpToNode = checkNotNull(createAndAddFloatingIpToNode,
"createAndAddFloatingIpToNode");
this.novaApi = checkNotNull(novaApi, "novaApi");
@@ -95,63 +91,78 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
public Map<?, ListenableFuture<Void>> execute(String group, int count, Template template, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
- Template mutableTemplate = template.clone();
-
- NovaTemplateOptions templateOptions = NovaTemplateOptions.class.cast(mutableTemplate.getOptions());
-
- assert template.getOptions().equals(templateOptions) : "options didn't clone properly";
-
- String region = mutableTemplate.getLocation().getId();
- ImmutableList.Builder<String> tagsBuilder = ImmutableList.builder();
+ NovaTemplateOptions templateOptions = NovaTemplateOptions.class.cast(template.getOptions());
+ String region = template.getLocation().getId();
if (templateOptions.shouldAutoAssignFloatingIp()) {
checkArgument(novaApi.getFloatingIPApi(region).isPresent(),
"Floating IPs are required by options, but the extension is not available! options: %s",
templateOptions);
}
+ if (templateOptions.shouldGenerateKeyPair() || templateOptions.getKeyPairName() != null) {
+ checkArgument(novaApi.getKeyPairApi(region).isPresent(),
+ "Key Pairs are required by options, but the extension is not available! options: %s", templateOptions);
+ }
- boolean keyPairExtensionPresent = novaApi.getKeyPairApi(region).isPresent();
+ List<Integer> inboundPorts = Ints.asList(templateOptions.getInboundPorts());
+ if (!templateOptions.getGroups().isEmpty() || !inboundPorts.isEmpty()) {
+ checkArgument(novaApi.getSecurityGroupApi(region).isPresent(),
+ "Security groups are required by options, but the extension is not available! options: %s",
+ templateOptions);
+ }
+
+ KeyPair keyPair = null;
if (templateOptions.shouldGenerateKeyPair()) {
- checkArgument(keyPairExtensionPresent,
- "Key Pairs are required by options, but the extension is not available! options: %s", templateOptions);
- KeyPair keyPair = keyPairCache.getUnchecked(RegionAndName.fromRegionAndName(region, namingConvention.create()
- .sharedNameForGroup(group)));
- keyPairCache.asMap().put(RegionAndName.fromRegionAndName(region, keyPair.getName()), keyPair);
- templateOptions.keyPairName(keyPair.getName());
- tagsBuilder.add(JCLOUDS_KP);
- } else if (templateOptions.getKeyPairName() != null) {
- checkArgument(keyPairExtensionPresent,
- "Key Pairs are required by options, but the extension is not available! options: %s", templateOptions);
- if (templateOptions.getLoginPrivateKey() != null) {
- String pem = templateOptions.getLoginPrivateKey();
- KeyPair keyPair = KeyPair.builder().name(templateOptions.getKeyPairName())
- .fingerprint(fingerprintPrivateKey(pem)).privateKey(pem).build();
- keyPairCache.asMap().put(RegionAndName.fromRegionAndName(region, keyPair.getName()), keyPair);
+ keyPair = generateKeyPair(region, namingConvention.create().sharedNameForGroup(group));
+ // If a private key has not been explicitly set, configure the auto-generated one
+ if (Strings.isNullOrEmpty(templateOptions.getLoginPrivateKey())) {
+ templateOptions.overrideLoginPrivateKey(keyPair.getPrivateKey());
}
+ } else if (templateOptions.getKeyPairName() != null) {
+ keyPair = checkNotNull(novaApi.getKeyPairApi(region).get().get(templateOptions.getKeyPairName()),
+ "keypair %s doesn't exist", templateOptions.getKeyPairName());
+ }
+ if (keyPair != null) {
+ templateOptions.keyPairName(keyPair.getName());
}
- boolean securityGroupExtensionPresent = novaApi.getSecurityGroupApi(region).isPresent();
- List<Integer> inboundPorts = Ints.asList(templateOptions.getInboundPorts());
+ ImmutableList.Builder<String> tagsBuilder = ImmutableList.builder();
+
if (!templateOptions.getGroups().isEmpty()) {
- checkArgument(securityGroupExtensionPresent,
- "Security groups are required by options, but the extension is not available! options: %s",
- templateOptions);
- } else if (securityGroupExtensionPresent) {
- if (templateOptions.getGroups().isEmpty() && !inboundPorts.isEmpty()) {
- String securityGroupName = namingConvention.create().sharedNameForGroup(group);
- try {
- securityGroupCache.get(new RegionSecurityGroupNameAndPorts(region, securityGroupName, inboundPorts));
- } catch (ExecutionException e) {
- throw Throwables.propagate(e.getCause());
- }
- templateOptions.securityGroups(securityGroupName);
- tagsBuilder.add(JCLOUDS_SG);
+ for (String securityGroupName : templateOptions.getGroups()) {
+ checkNotNull(novaApi.getSecurityGroupApi(region).get().get(securityGroupName), "security group %s doesn't exist", securityGroupName);
}
}
- templateOptions.userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, group);
+ else if (!inboundPorts.isEmpty()) {
+ SecurityGroupInRegion securityGroupInRegion;
+ String securityGroupName = namingConvention.create().sharedNameForGroup(group);
+ try {
+ securityGroupInRegion = securityGroupCache.get(new RegionSecurityGroupNameAndPorts(region, securityGroupName, inboundPorts));
+ } catch (ExecutionException e) {
+ throw Throwables.propagate(e.getCause());
+ }
+ templateOptions.securityGroups(securityGroupName);
+ tagsBuilder.add(String.format("%s-%s", JCLOUDS_SG_PREFIX, securityGroupInRegion.getSecurityGroup().getId()));
+ }
templateOptions.tags(tagsBuilder.build());
- return super.execute(group, count, mutableTemplate, goodNodes, badNodes, customizationResponses);
+ Map<?, ListenableFuture<Void>> responses = super.execute(group, count, template, goodNodes, badNodes,
+ customizationResponses);
+
+ // Key pairs in Openstack are only required to create the Server. They aren't used anymore so it is better
+ // to delete the auto-generated key pairs at this point where we know exactly which ones have been
+ // auto-generated by jclouds.
+ if (templateOptions.shouldGenerateKeyPair() && keyPair != null) {
+ registerAutoGeneratedKeyPairCleanupCallbacks(responses, region, keyPair.getName());
+ }
+ return responses;
+ }
+
+ private KeyPair generateKeyPair(String region, String prefix) {
+ logger.debug(">> creating default keypair for node...");
+ KeyPair keyPair = novaApi.getKeyPairApi(region).get().create(namingConvention.createWithoutPrefix().uniqueNameForGroup(prefix));
+ logger.debug(">> keypair created! %s", keyPair.getName());
+ return keyPair;
}
@Override
@@ -177,4 +188,35 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
}
}
+ private void registerAutoGeneratedKeyPairCleanupCallbacks(final Map<?, ListenableFuture<Void>> responses,
+ final String region, final String generatedKeyPairName) {
+ // The Futures.allAsList fails immediately if some of the futures fail. The Futures.successfulAsList, however,
+ // returns a list containing the results or 'null' for those futures that failed. We want to wait for all them
+ // (even if they fail), so better use the latter form.
+ ListenableFuture<List<Void>> aggregatedResponses = Futures.successfulAsList(responses.values());
+
+ // Key pairs must be cleaned up after all futures completed (even if some failed).
+ Futures.addCallback(aggregatedResponses, new FutureCallback<List<Void>>() {
+ @Override
+ public void onSuccess(List<Void> result) {
+ cleanupAutoGeneratedKeyPair(generatedKeyPairName);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ cleanupAutoGeneratedKeyPair(generatedKeyPairName);
+ }
+
+ private void cleanupAutoGeneratedKeyPair(String keyPairName) {
+ logger.debug(">> cleaning up auto-generated key pairs...");
+ try {
+ novaApi.getKeyPairApi(region).get().delete(keyPairName);
+ } catch (Exception ex) {
+ logger.warn(">> could not delete key pair %s: %s", keyPairName, ex.getMessage());
+ }
+ }
+
+ }, userExecutor);
+ }
+
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java
index f9f5362..7dd3472 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java
@@ -367,9 +367,6 @@ public class CreateServerOptions implements MapBinder {
return securityGroupNames(ImmutableSet.copyOf(checkNotNull(securityGroupNames, "securityGroupNames")));
}
- /**
- * @see #getSecurityGroupNames()
- */
public CreateServerOptions securityGroupNames(Iterable<String> securityGroupNames) {
for (String groupName : checkNotNull(securityGroupNames, "securityGroupNames"))
checkNotNull(emptyToNull(groupName), "all security groups must be non-empty");
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/ServerPredicates.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/ServerPredicates.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/ServerPredicates.java
deleted file mode 100644
index 00da77f..0000000
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/ServerPredicates.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * 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.v2_0.predicates;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.jclouds.openstack.nova.v2_0.domain.Server.Status.ACTIVE;
-import static org.jclouds.openstack.nova.v2_0.domain.Server.Status.SHUTOFF;
-import static org.jclouds.util.Predicates2.retry;
-
-import org.jclouds.openstack.nova.v2_0.domain.Server;
-import org.jclouds.openstack.nova.v2_0.domain.Server.Status;
-import org.jclouds.openstack.nova.v2_0.features.ServerApi;
-
-import com.google.common.base.Predicate;
-
-/**
- * This class tests to see if a Server or ServerCreated has reached a desired status. This class is most useful when
- * paired with a RetryablePredicate as in the code below. Together these classes can be used to block execution until
- * the Server or ServerCreated has reached that desired status. This is useful when your Server needs to be 100% ready
- * before you can continue with execution.
- * <p/>
- * For example, you can use the factory methods like so.
- * <p/>
- * <pre>
- * {@code
- * ServerCreated serverCreated = serverApi.create("my-server", image.getId(), flavor.getId());
- *
- * if (!ServerPredicates.awaitActive(serverApi).apply(serverCreated.getId())) {
- * throw new TimeoutException("Timeout on server: " + serverCreated);
- * }
- * </pre>
- *
- * <pre>
- * {@code
- * if (!ServerPredicates.awaitStatus(serverApi, ACTIVE, 300, 2).apply(server.getId())) {
- * throw new TimeoutException("Timeout on server: " + serverCreated);
- * }
- * </pre>
- */
-public class ServerPredicates {
- private static final int THIRTY_MINUTES = 600 * 3;
- private static final int FIVE_SECONDS = 5;
-
- /**
- * Waits until a Server is ACTIVE.
- *
- * @param serverApi The ServerApi in the region where your Server resides.
- * @return Predicate that will check the status every 5 seconds for a maximum of 10 minutes.
- */
- public static Predicate<String> awaitActive(ServerApi serverApi) {
- return awaitStatus(serverApi, ACTIVE, THIRTY_MINUTES, FIVE_SECONDS);
- }
-
- /**
- * Waits until a Server is SHUTOFF.
- *
- * @param serverApi The ServerApi in the region where your Server resides.
- * @return Predicate that will check the status every 5 seconds for a maximum of 10 minutes.
- */
- public static Predicate<String> awaitShutoff(ServerApi serverApi) {
- return awaitStatus(serverApi, SHUTOFF, THIRTY_MINUTES, FIVE_SECONDS);
- }
-
- /**
- * Waits until a Server reaches Status.
- *
- * @param serverApi The ServerApi in the region where your Server resides.
- * @return Predicate that will check the status every periodInSec seconds for a maximum of maxWaitInSec minutes.
- */
- public static Predicate<String> awaitStatus(
- ServerApi serverApi, Status status, long maxWaitInSec, long periodInSec) {
- ServerStatusPredicate statusPredicate = new ServerStatusPredicate(serverApi, status);
-
- return retry(statusPredicate, maxWaitInSec, periodInSec, periodInSec, SECONDS);
- }
-
- public static class ServerStatusPredicate implements Predicate<String> {
- private final ServerApi serverApi;
- private final Status status;
-
- public ServerStatusPredicate(ServerApi serverApi, Status status) {
- this.serverApi = checkNotNull(serverApi, "serverApi must be defined");
- this.status = checkNotNull(status, "status must be defined");
- }
-
- /**
- * @return boolean Return true when the Server reaches the Status, false otherwise
- * @throws IllegalStateException if the Server associated with serverId does not exist
- */
- @Override
- public boolean apply(String serverId) {
- checkNotNull(serverId, "server must be defined");
-
- Server server = serverApi.get(serverId);
-
- if (server == null) {
- throw new IllegalStateException(String.format("Server %s not found.", serverId));
- }
-
- return status.equals(server.getStatus());
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java
index 5cb02a7..5528349 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java
@@ -32,20 +32,15 @@ import org.jclouds.domain.LoginCredentials;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions;
-import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
import org.jclouds.openstack.nova.v2_0.domain.Network;
import org.jclouds.openstack.nova.v2_0.domain.Server;
-import org.jclouds.openstack.nova.v2_0.domain.regionscoped.RegionAndName;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.ServerInRegion;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaComputeServiceContextExpectTest;
import org.testng.annotations.Test;
-import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Injector;
-import com.google.inject.Key;
-import com.google.inject.TypeLiteral;
/**
* Tests the compute service abstraction of the nova api.
@@ -239,7 +234,7 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
Injector forSecurityGroups = requestsSendResponses(requestResponseMap);
Template template = forSecurityGroups.getInstance(TemplateBuilder.class).build();
- template.getOptions().as(NovaTemplateOptions.class).securityGroupNames("group1", "group2");
+ template.getOptions().as(NovaTemplateOptions.class).securityGroups("group1", "group2");
NovaComputeServiceAdapter adapter = forSecurityGroups.getInstance(NovaComputeServiceAdapter.class);
@@ -281,17 +276,10 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
Injector forSecurityGroups = requestsSendResponses(requestResponseMap);
Template template = forSecurityGroups.getInstance(TemplateBuilder.class).build();
- template.getOptions().as(NovaTemplateOptions.class).keyPairName("foo");
+ template.getOptions().as(NovaTemplateOptions.class).keyPairName("foo").overrideLoginPrivateKey("privateKey");
NovaComputeServiceAdapter adapter = forSecurityGroups.getInstance(NovaComputeServiceAdapter.class);
- // we expect to have already an entry in the cache for the key
- LoadingCache<RegionAndName, KeyPair> keyPairCache = forSecurityGroups.getInstance(Key
- .get(new TypeLiteral<LoadingCache<RegionAndName, KeyPair>>() {
- }));
- keyPairCache.put(RegionAndName.fromRegionAndName("az-1.region-a.geo-1", "foo"), KeyPair.builder().name("foo")
- .privateKey("privateKey").build());
-
NodeAndInitialCredentials<ServerInRegion> server = adapter.createNodeWithGroupEncodedIntoName("test", "test-e92",
template);
assertNotNull(server);
@@ -359,13 +347,16 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
.statusCode(202)
.build();
+ HttpResponse serverDetailSuspendedResponse = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResource("/server_details_suspended.json")).build();
+
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
.put(extensionsOfNovaRequest, extensionsOfNovaResponse)
.put(listDetail, listDetailResponse)
.put(listFlavorsDetail, listFlavorsDetailResponse)
.put(suspendServer, suspendServerResponse)
- .put(serverDetail, serverDetailResponse).build();
+ .put(serverDetail, serverDetailSuspendedResponse).build();
Injector forAdminExtension = requestsSendResponses(requestResponseMap);
@@ -394,13 +385,16 @@ public class NovaComputeServiceAdapterExpectTest extends BaseNovaComputeServiceC
.statusCode(202)
.build();
+ HttpResponse serverDetailSuspendedResponse = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResource("/server_details_suspended.json")).build();
+
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
.put(extensionsOfNovaRequest, unmatchedExtensionsOfNovaResponse)
.put(listDetail, listDetailResponse)
.put(listFlavorsDetail, listFlavorsDetailResponse)
.put(suspendServer, suspendServerResponse)
- .put(serverDetail, serverDetailResponse).build();
+ .put(serverDetail, serverDetailSuspendedResponse).build();
Injector forAdminExtension = requestsSendResponses(requestResponseMap);
http://git-wip-us.apache.org/repos/asf/jclouds/blob/aa11765b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceExpectTest.java
index a163f02..49cc969 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceExpectTest.java
@@ -20,7 +20,6 @@ import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
import static org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions.Builder.blockUntilRunning;
import static org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions.Builder.keyPairName;
import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
@@ -174,7 +173,7 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
HttpResponse securityGroupWithPort22 = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/securitygroup_details_port22.json")).build();
- HttpRequest create = HttpRequest
+ HttpRequest createKeyPair = HttpRequest
.builder()
.method("POST")
.endpoint("https://nova-api.openstack.org:9774/v2/3456/os-keypairs")
@@ -188,6 +187,16 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
HttpResponse keyPairWithPrivateKey = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/keypair_created_computeservice.json")).build();
+ HttpRequest getKeyPair = HttpRequest
+ .builder()
+ .method("GET")
+ .endpoint("https://nova-api.openstack.org:9774/v2/3456/os-keypairs/fooPair")
+ .addHeader("Accept", "application/json")
+ .addHeader("X-Auth-Token", authToken).build();
+
+ HttpResponse keyPairDetails = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResource("/keypair_details.json")).build();
+
HttpRequest serverDetail = HttpRequest
.builder()
.method("GET")
@@ -202,18 +211,12 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
public void testCreateNodeWithGeneratedKeyPair() throws Exception {
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
.putAll(defaultTemplateOpenStack);
+ requestResponseMap.put(createKeyPair, keyPairWithPrivateKey);
requestResponseMap.put(list, notFound);
-
requestResponseMap.put(createWithPrefixOnGroup, securityGroupCreated);
-
requestResponseMap.put(createRuleForDefaultPort22, securityGroupRuleCreated);
-
requestResponseMap.put(getSecurityGroup, securityGroupWithPort22);
-
- requestResponseMap.put(create, keyPairWithPrivateKey);
-
- requestResponseMap.put(serverDetail, serverDetailResponse);
-
+
HttpRequest createServerWithGeneratedKeyPair = HttpRequest
.builder()
.method("POST")
@@ -222,13 +225,14 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
.addHeader("X-Auth-Token", authToken)
.payload(
payloadFromStringWithContentType(
- "{\"server\":{\"name\":\"test-1\",\"imageRef\":\"14\",\"flavorRef\":\"1\",\"metadata\":{\"jclouds-group\":\"test\",\"jclouds_tags\":\"jclouds_keyPair,jclouds_securityGroup\"},\"key_name\":\"jclouds-test-0\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
+ "{\"server\":{\"name\":\"test-1\",\"imageRef\":\"14\",\"flavorRef\":\"1\",\"metadata\":{\"jclouds_tags\":\"jclouds_sg-2769\"},\"key_name\":\"jclouds-test-0\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
"application/json")).build();
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
.payload(payloadFromResourceWithContentType("/new_server.json", "application/json; charset=UTF-8")).build();
requestResponseMap.put(createServerWithGeneratedKeyPair, createdServer);
+ requestResponseMap.put(serverDetail, serverDetailResponse);
ComputeService apiThatCreatesNode = requestsSendResponses(requestResponseMap.build(), new AbstractModule() {
@@ -260,14 +264,14 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
.putAll(defaultTemplateOpenStack);
requestResponseMap.put(list, notFound);
+ requestResponseMap.put(getKeyPair, keyPairDetails);
+
requestResponseMap.put(createWithPrefixOnGroup, securityGroupCreated);
requestResponseMap.put(createRuleForDefaultPort22, securityGroupRuleCreated);
requestResponseMap.put(getSecurityGroup, securityGroupWithPort22);
- requestResponseMap.put(serverDetail, serverDetailResponse);
-
HttpRequest createServerWithSuppliedKeyPair = HttpRequest
.builder()
.method("POST")
@@ -276,19 +280,20 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
.addHeader("X-Auth-Token", authToken)
.payload(
payloadFromStringWithContentType(
- "{\"server\":{\"name\":\"test-0\",\"imageRef\":\"14\",\"flavorRef\":\"1\",\"metadata\":{\"jclouds-group\":\"test\",\"jclouds_tags\":\"jclouds_securityGroup\"},\"key_name\":\"fooPair\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
+ "{\"server\":{\"name\":\"test-0\",\"imageRef\":\"14\",\"flavorRef\":\"1\",\"metadata\":{\"jclouds_tags\":\"jclouds_sg-2769\"},\"key_name\":\"testkeypair\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
"application/json")).build();
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
.payload(payloadFromResourceWithContentType("/new_server.json", "application/json; charset=UTF-8")).build();
requestResponseMap.put(createServerWithSuppliedKeyPair, createdServer);
+ requestResponseMap.put(serverDetail, serverDetailResponse);
ComputeService apiThatCreatesNode = requestsSendResponses(requestResponseMap.build(), new AbstractModule() {
@Override
protected void configure() {
- // predicatable node names
+ // predictable node names
final AtomicInteger suffix = new AtomicInteger();
bind(new TypeLiteral<Supplier<String>>() {
}).toInstance(new Supplier<String>() {
@@ -304,20 +309,37 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
});
NodeMetadata node = Iterables.getOnlyElement(apiThatCreatesNode.createNodesInGroup("test", 1,
- keyPairName("fooPair").blockUntilRunning(false)));
+ keyPairName("fooPair").overrideLoginPrivateKey("privateKey").blockUntilRunning(false)));
// we don't have access to this private key
- assertFalse(node.getCredentials().getOptionalPrivateKey().isPresent());
+ assertTrue(node.getCredentials().getOptionalPrivateKey().isPresent());
}
-
@Test
public void testCreateNodeWhileUserSpecifiesKeyPairAndUserSpecifiedGroups() throws Exception {
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
.putAll(defaultTemplateOpenStack);
requestResponseMap.put(list, notFound);
- requestResponseMap.put(serverDetail, serverDetailResponse);
+ requestResponseMap.put(getKeyPair, keyPairDetails);
+
+ requestResponseMap.put(createWithPrefixOnGroup, securityGroupCreated);
+
+ requestResponseMap.put(createRuleForDefaultPort22, securityGroupRuleCreated);
+ requestResponseMap.put(getSecurityGroup, securityGroupWithPort22);
+
+ HttpRequest getSecurityGroup = HttpRequest
+ .builder()
+ .method("GET")
+ .endpoint("https://nova-api.openstack.org:9774/v2/3456/os-security-groups/mygroup")
+ .addHeader("Accept", "application/json")
+ .addHeader("X-Auth-Token", authToken).build();
+
+ HttpResponse securityGroupWDetails = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResource("/securitygroup_details_port22.json")).build();
+
+ requestResponseMap.put(getSecurityGroup, securityGroupWDetails);
+
HttpRequest createServerWithSuppliedKeyPairAndGroup = HttpRequest
.builder()
.method("POST")
@@ -326,20 +348,21 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
.addHeader("X-Auth-Token", authToken)
.payload(
payloadFromStringWithContentType(
- "{\"server\":{\"name\":\"test-0\",\"imageRef\":\"14\",\"flavorRef\":\"1\"," +
- "\"metadata\":{\"jclouds-group\":\"test\"},\"key_name\":\"fooPair\",\"security_groups\":[{\"name\":\"mygroup\"}]}}",
+ "{\"server\":{\"name\":\"test-0\",\"imageRef\":\"14\",\"flavorRef\":\"1\",\"key_name\":\"testkeypair\",\"security_groups\":[{\"name\":\"mygroup\"}]}}",
"application/json")).build();
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
.payload(payloadFromResourceWithContentType("/new_server.json", "application/json; charset=UTF-8")).build();
requestResponseMap.put(createServerWithSuppliedKeyPairAndGroup, createdServer);
+
+ requestResponseMap.put(serverDetail, serverDetailResponse);
ComputeService apiThatCreatesNode = requestsSendResponses(requestResponseMap.build(), new AbstractModule() {
@Override
protected void configure() {
- // predicatable node names
+ // predictable node names
final AtomicInteger suffix = new AtomicInteger();
bind(new TypeLiteral<Supplier<String>>() {
}).toInstance(new Supplier<String>() {
@@ -355,9 +378,9 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
});
NodeMetadata node = Iterables.getOnlyElement(apiThatCreatesNode.createNodesInGroup("test", 1,
- keyPairName("fooPair").securityGroupNames("mygroup").blockUntilRunning(false)));
+ keyPairName("fooPair").securityGroups("mygroup").blockUntilRunning(false)));
// we don't have access to this private key
- assertFalse(node.getCredentials().getOptionalPrivateKey().isPresent());
+ assertTrue(!node.getCredentials().getOptionalPrivateKey().isPresent());
}
}