Adding security groups to TemplateOptions, adding listSecurityGroupsForNode to extension, tests, pain.
Project: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/commit/c4d34570 Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/tree/c4d34570 Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/diff/c4d34570 Branch: refs/heads/jclouds-101 Commit: c4d34570acd77bdda418c598c05b8f814b218bc0 Parents: 23f24cd Author: Andrew Bayer <[email protected]> Authored: Wed Jun 12 15:40:09 2013 -0700 Committer: Andrew Bayer <[email protected]> Committed: Wed Jun 12 15:40:09 2013 -0700 ---------------------------------------------------------------------- .../extensions/SecurityGroupExtension.java | 8 +++ .../compute/options/TemplateOptions.java | 60 +++++++++++++++++++- .../stub/config/StubComputeServiceAdapter.java | 34 ++++++++++- .../StubComputeServiceDependenciesModule.java | 19 +++++++ .../extensions/StubSecurityGroupExtension.java | 18 ++++-- .../BaseSecurityGroupExtensionLiveTest.java | 38 +++++++++++++ ...ubSecurityGroupExtensionIntegrationTest.java | 14 ++++- 7 files changed, 181 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c4d34570/compute/src/main/java/org/jclouds/compute/extensions/SecurityGroupExtension.java ---------------------------------------------------------------------- diff --git a/compute/src/main/java/org/jclouds/compute/extensions/SecurityGroupExtension.java b/compute/src/main/java/org/jclouds/compute/extensions/SecurityGroupExtension.java index 24e162f..5676561 100644 --- a/compute/src/main/java/org/jclouds/compute/extensions/SecurityGroupExtension.java +++ b/compute/src/main/java/org/jclouds/compute/extensions/SecurityGroupExtension.java @@ -48,6 +48,14 @@ public interface SecurityGroupExtension { */ Set<SecurityGroup> listSecurityGroupsInLocation(Location location); + + /** + * List security groups for a given instance given the instance's ID. + * + * @return The set of @{link SecurityGroup}s for the given instance.. + */ + Set<SecurityGroup> listSecurityGroupsForNode(String id); + /** * Create a new @{link SecurityGroup} from the parameters given. * http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c4d34570/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java ---------------------------------------------------------------------- diff --git a/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java b/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java index 270633a..d17a6cd 100644 --- a/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java +++ b/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java @@ -70,6 +70,8 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable { to.inboundPorts(this.getInboundPorts()); if (this.getRunScript() != null) to.runScript(this.getRunScript()); + if (this.getGroups().size() > 0) + to.securityGroups(this.getGroups()); if (this.getPrivateKey() != null) to.installPrivateKey(this.getPrivateKey()); if (this.getPublicKey() != null) @@ -295,6 +297,21 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable { } @Override + public Set<String> getGroups() { + return delegate.getGroups(); + } + + @Override + public TemplateOptions securityGroups(Iterable<String> securityGroups) { + throw new IllegalArgumentException("tags are immutable"); + } + + @Override + public TemplateOptions securityGroups(String... securityGroups) { + throw new IllegalArgumentException("tags are immutable"); + } + + @Override public TemplateOptions userMetadata(Map<String, String> userMetadata) { throw new IllegalArgumentException("userMetadata is immutable"); } @@ -321,6 +338,8 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable { protected Set<String> tags = ImmutableSet.of(); + protected Set<String> securityGroups = ImmutableSet.of(); + protected String privateKey; protected String publicKey; @@ -339,13 +358,13 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable { return super.equals(that) && equal(this.inboundPorts, that.inboundPorts) && equal(this.script, that.script) && equal(this.publicKey, that.publicKey) && equal(this.privateKey, that.privateKey) && equal(this.blockUntilRunning, that.blockUntilRunning) && equal(this.tags, that.tags) - && equal(this.userMetadata, that.userMetadata); + && equal(this.securityGroups, that.securityGroups) && equal(this.userMetadata, that.userMetadata); } @Override public int hashCode() { return Objects.hashCode(super.hashCode(), inboundPorts, script, publicKey, privateKey, blockUntilRunning, tags, - userMetadata); + securityGroups, userMetadata); } @Override @@ -363,6 +382,8 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable { toString.add("blockUntilRunning", blockUntilRunning); if (tags.size() != 0) toString.add("tags", tags); + if (securityGroups.size() != 0) + toString.add("securityGroups", securityGroups); if (userMetadata.size() != 0) toString.add("userMetadata", userMetadata); return toString; @@ -380,6 +401,10 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable { return tags; } + public Set<String> getGroups() { + return securityGroups; + } + public String getPrivateKey() { return privateKey; } @@ -451,6 +476,21 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable { } /** + * assigns the created nodes to these security groups + */ + public TemplateOptions securityGroups(Iterable<String> securityGroups) { + this.securityGroups = ImmutableSet.copyOf(checkNotNull(securityGroups, "securityGroups")); + return this; + } + + /** + * @see TemplateOptions#securityGroups(Iterable<String>) + */ + public TemplateOptions securityGroups(String... securityGroups) { + return securityGroups(ImmutableSet.copyOf(securityGroups)); + } + + /** * Opens the set of ports to public access. */ public TemplateOptions inboundPorts(int... ports) { @@ -522,6 +562,22 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable { } /** + * @see TemplateOptions#securityGroups + */ + public static TemplateOptions securityGroups(Iterable<String> securityGroups) { + TemplateOptions options = new TemplateOptions(); + return options.securityGroups(securityGroups); + } + + /** + * @see TemplateOptions#securityGroups + */ + public static TemplateOptions securityGroups(String... securityGroups) { + TemplateOptions options = new TemplateOptions(); + return options.securityGroups(securityGroups); + } + + /** * @see TemplateOptions#blockUntilRunning(boolean) */ public static TemplateOptions blockUntilRunning(boolean blockUntilRunning) { http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c4d34570/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceAdapter.java ---------------------------------------------------------------------- diff --git a/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceAdapter.java b/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceAdapter.java index 925dc1a..22e7dcf 100644 --- a/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceAdapter.java +++ b/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceAdapter.java @@ -41,13 +41,18 @@ import org.jclouds.compute.domain.NodeMetadata.Status; import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OsFamily; +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.domain.SecurityGroupBuilder; import org.jclouds.compute.domain.Template; +import org.jclouds.compute.extensions.SecurityGroupExtension; import org.jclouds.compute.predicates.ImagePredicates; import org.jclouds.domain.Location; import org.jclouds.domain.LoginCredentials; import org.jclouds.location.suppliers.all.JustProvider; import org.jclouds.rest.ResourceNotFoundException; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; import com.google.common.base.Supplier; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; @@ -55,6 +60,7 @@ import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.google.common.util.concurrent.ListeningExecutorService; @@ -66,20 +72,25 @@ import com.google.common.util.concurrent.ListeningExecutorService; public class StubComputeServiceAdapter implements JCloudsNativeComputeServiceAdapter { private final Supplier<Location> location; private final ConcurrentMap<String, NodeMetadata> nodes; + private final Multimap<String, SecurityGroup> groupsForNodes; private final ListeningExecutorService ioExecutor; private final Provider<Integer> idProvider; + private final Provider<Integer> groupIdProvider; private final String publicIpPrefix; private final String privateIpPrefix; private final String passwordPrefix; private final Supplier<Set<? extends Location>> locationSupplier; private final Map<OsFamily, Map<String, String>> osToVersionMap; + private final Optional<SecurityGroupExtension> securityGroupExtension; @Inject public StubComputeServiceAdapter(ConcurrentMap<String, NodeMetadata> nodes, @Named(Constants.PROPERTY_IO_WORKER_THREADS) ListeningExecutorService ioExecutor, Supplier<Location> location, @Named("NODE_ID") Provider<Integer> idProvider, @Named("PUBLIC_IP_PREFIX") String publicIpPrefix, @Named("PRIVATE_IP_PREFIX") String privateIpPrefix, @Named("PASSWORD_PREFIX") String passwordPrefix, - JustProvider locationSupplier, Map<OsFamily, Map<String, String>> osToVersionMap) { + JustProvider locationSupplier, Map<OsFamily, Map<String, String>> osToVersionMap, + Multimap<String, SecurityGroup> groupsForNodes, @Named("GROUP_ID") Provider<Integer> groupIdProvider, + Optional<SecurityGroupExtension> securityGroupExtension) { this.nodes = nodes; this.ioExecutor = ioExecutor; this.location = location; @@ -89,6 +100,9 @@ public class StubComputeServiceAdapter implements JCloudsNativeComputeServiceAda this.passwordPrefix = passwordPrefix; this.locationSupplier = locationSupplier; this.osToVersionMap = osToVersionMap; + this.groupsForNodes = groupsForNodes; + this.groupIdProvider = groupIdProvider; + this.securityGroupExtension = securityGroupExtension; } protected void setStateOnNode(Status status, NodeMetadata node) { @@ -133,6 +147,22 @@ public class StubComputeServiceAdapter implements JCloudsNativeComputeServiceAda builder.credentials(LoginCredentials.builder().user("root").password(passwordPrefix + id).build()); NodeMetadata node = builder.build(); nodes.put(node.getId(), node); + + if (template.getOptions().getGroups().size() > 0) { + final String groupId = Iterables.getFirst(template.getOptions().getGroups(), "0"); + Optional<SecurityGroup> secGroup = Iterables.tryFind(securityGroupExtension.get().listSecurityGroups(), + new Predicate<SecurityGroup>() { + @Override + public boolean apply(SecurityGroup input) { + return input.getId().equals(groupId); + } + }); + + if (secGroup.isPresent()) { + groupsForNodes.put(node.getId(), secGroup.get()); + } + } + setStateOnNodeAfterDelay(Status.RUNNING, node, 100); return new NodeWithInitialCredentials(node); } @@ -195,6 +225,8 @@ public class StubComputeServiceAdapter implements JCloudsNativeComputeServiceAda return; setStateOnNodeAfterDelay(Status.PENDING, node, 0); setStateOnNodeAfterDelay(Status.TERMINATED, node, 50); + groupsForNodes.removeAll(id); + ioExecutor.execute(new Runnable() { @Override http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c4d34570/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceDependenciesModule.java ---------------------------------------------------------------------- diff --git a/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceDependenciesModule.java b/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceDependenciesModule.java index b6f22cb..0d07bbe 100644 --- a/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceDependenciesModule.java +++ b/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceDependenciesModule.java @@ -43,6 +43,8 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; import com.google.common.net.HostAndPort; import com.google.inject.AbstractModule; import com.google.inject.Provides; @@ -96,6 +98,23 @@ public class StubComputeServiceDependenciesModule extends AbstractModule { return groupBacking.get(creds.get().identity); } + protected static final LoadingCache<String, Multimap<String, SecurityGroup>> groupsForNodeBacking = CacheBuilder.newBuilder() + .build(new CacheLoader<String, Multimap<String, SecurityGroup>>() { + + @Override + public Multimap<String, SecurityGroup> load(String arg0) throws Exception { + return LinkedHashMultimap.create(); + } + + }); + + @Provides + @Singleton + protected Multimap<String, SecurityGroup> provideGroupsForNode(@Provider Supplier<Credentials> creds) + throws ExecutionException { + return groupsForNodeBacking.get(creds.get().identity); + } + protected static final LoadingCache<String, AtomicInteger> nodeIds = CacheBuilder.newBuilder().build( new CacheLoader<String, AtomicInteger>() { http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c4d34570/compute/src/main/java/org/jclouds/compute/stub/extensions/StubSecurityGroupExtension.java ---------------------------------------------------------------------- diff --git a/compute/src/main/java/org/jclouds/compute/stub/extensions/StubSecurityGroupExtension.java b/compute/src/main/java/org/jclouds/compute/stub/extensions/StubSecurityGroupExtension.java index f61cb84..b4c5b06 100644 --- a/compute/src/main/java/org/jclouds/compute/stub/extensions/StubSecurityGroupExtension.java +++ b/compute/src/main/java/org/jclouds/compute/stub/extensions/StubSecurityGroupExtension.java @@ -55,22 +55,25 @@ import com.google.common.util.concurrent.ListeningExecutorService; public class StubSecurityGroupExtension implements SecurityGroupExtension { private final Supplier<Location> location; - private final Provider<Integer> idProvider; + private final Provider<Integer> groupIdProvider; private final Supplier<Set<? extends Location>> locationSupplier; private final ListeningExecutorService ioExecutor; private final ConcurrentMap<String, SecurityGroup> groups; + private final Multimap<String, SecurityGroup> groupsForNodes; @Inject public StubSecurityGroupExtension(ConcurrentMap<String, SecurityGroup> groups, @Named(Constants.PROPERTY_IO_WORKER_THREADS) ListeningExecutorService ioExecutor, Supplier<Location> location, - @Named("GROUP_ID") Provider<Integer> idProvider, - JustProvider locationSupplier) { + @Named("GROUP_ID") Provider<Integer> groupIdProvider, + JustProvider locationSupplier, + Multimap<String, SecurityGroup> groupsForNodes) { this.groups = groups; this.ioExecutor = ioExecutor; this.location = location; - this.idProvider = idProvider; + this.groupIdProvider = groupIdProvider; this.locationSupplier = locationSupplier; + this.groupsForNodes = groupsForNodes; } @Override @@ -87,12 +90,17 @@ public class StubSecurityGroupExtension implements SecurityGroupExtension { } })); } + + @Override + public Set<SecurityGroup> listSecurityGroupsForNode(String nodeId) { + return ImmutableSet.copyOf(groupsForNodes.get(nodeId)); + } @Override public SecurityGroup createSecurityGroup(String name, Location location) { SecurityGroupBuilder builder = new SecurityGroupBuilder(); - String id = idProvider.get() + ""; + String id = groupIdProvider.get() + ""; builder.ids(id); builder.name(name); builder.location(location); http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c4d34570/compute/src/test/java/org/jclouds/compute/extensions/internal/BaseSecurityGroupExtensionLiveTest.java ---------------------------------------------------------------------- diff --git a/compute/src/test/java/org/jclouds/compute/extensions/internal/BaseSecurityGroupExtensionLiveTest.java b/compute/src/test/java/org/jclouds/compute/extensions/internal/BaseSecurityGroupExtensionLiveTest.java index ebb2a1a..c7fcb22 100644 --- a/compute/src/test/java/org/jclouds/compute/extensions/internal/BaseSecurityGroupExtensionLiveTest.java +++ b/compute/src/test/java/org/jclouds/compute/extensions/internal/BaseSecurityGroupExtensionLiveTest.java @@ -22,6 +22,7 @@ import static com.google.common.base.Predicates.not; import static com.google.common.collect.Iterables.filter; import static org.jclouds.util.Predicates2.retry; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import java.util.Set; @@ -32,11 +33,14 @@ import javax.inject.Named; import org.jclouds.compute.ComputeService; import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.SecurityGroup; import org.jclouds.compute.domain.SecurityGroupBuilder; import org.jclouds.compute.domain.Template; +import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.extensions.SecurityGroupExtension; import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; +import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.Location; import org.jclouds.logging.Logger; @@ -77,6 +81,8 @@ public abstract class BaseSecurityGroupExtensionLiveTest extends BaseComputeServ return view.getComputeService().templateBuilder().build(); } + + @Test(groups = { "integration", "live" }, singleThreaded = true) public void testCreateSecurityGroup() throws RunNodesException, InterruptedException, ExecutionException { @@ -207,6 +213,38 @@ public abstract class BaseSecurityGroupExtensionLiveTest extends BaseComputeServ } @Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testAddIpPermissionsFromSpec") + public void testCreateNodeWithSecurityGroup() throws RunNodesException, InterruptedException, ExecutionException { + + ComputeService computeService = view.getComputeService(); + + Optional<SecurityGroupExtension> securityGroupExtension = computeService.getSecurityGroupExtension(); + + assertTrue(securityGroupExtension.isPresent(), "security group extension was not present"); + + Template template = view.getComputeService().templateBuilder() + .options(TemplateOptions.Builder.securityGroups(groupId)) + .build(); + + NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test-create-node-with-group", 1, template)); + + Set<SecurityGroup> groups = securityGroupExtension.get().listSecurityGroupsForNode(node.getId()); + + assertTrue(groups.size() > 0, "node has no groups"); + + Optional<SecurityGroup> secGroup = Iterables.tryFind(securityGroupExtension.get().listSecurityGroupsForNode(node.getId()), + new Predicate<SecurityGroup>() { + @Override + public boolean apply(SecurityGroup input) { + return input.getId().equals(groupId); + } + }); + + assertTrue(secGroup.isPresent()); + + computeService.destroyNode(node.getId()); + } + + @Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testCreateNodeWithSecurityGroup") public void testDeleteSecurityGroup() { ComputeService computeService = view.getComputeService(); http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c4d34570/compute/src/test/java/org/jclouds/compute/stub/extensions/StubSecurityGroupExtensionIntegrationTest.java ---------------------------------------------------------------------- diff --git a/compute/src/test/java/org/jclouds/compute/stub/extensions/StubSecurityGroupExtensionIntegrationTest.java b/compute/src/test/java/org/jclouds/compute/stub/extensions/StubSecurityGroupExtensionIntegrationTest.java index 2266886..8c2b31c 100644 --- a/compute/src/test/java/org/jclouds/compute/stub/extensions/StubSecurityGroupExtensionIntegrationTest.java +++ b/compute/src/test/java/org/jclouds/compute/stub/extensions/StubSecurityGroupExtensionIntegrationTest.java @@ -21,6 +21,7 @@ import static org.jclouds.util.Predicates2.retry; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import java.util.Properties; import java.util.concurrent.ExecutionException; import javax.annotation.Resource; @@ -48,13 +49,22 @@ import com.google.common.collect.Iterables; /** * Base test for {@link SecurityGroupExtension} implementations. * - * @author David Alves + * @author Andrew Bayer * */ -@Test(groups = { "integration", "live" }, testName="StubSecurityGroupExtensionIntegrationTest") +@Test(groups = { "integration", "live" }, singleThreaded = true, testName="StubSecurityGroupExtensionIntegrationTest") public class StubSecurityGroupExtensionIntegrationTest extends BaseSecurityGroupExtensionLiveTest { public StubSecurityGroupExtensionIntegrationTest() { provider = "stub"; } + + @Override + protected Properties setupProperties() { + Properties overrides = super.setupProperties(); + // This is a hack to make sure we get a different set of node IDs, nodes, groups, etc from StubComputeServiceIntegrationTest. + overrides.setProperty(provider + ".identity", "sec-stub"); + + return overrides; + } }
