Repository: incubator-brooklyn Updated Branches: refs/heads/master f1d90c638 -> ed692e059
Add sequential ID number to each DynamicCluster member Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/cea34628 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/cea34628 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/cea34628 Branch: refs/heads/master Commit: cea346284a9c0d2556f2ffd7ee2fd033c4e4adbd Parents: d2a5d4b Author: Mike Zaccardo <[email protected]> Authored: Fri Oct 16 13:08:52 2015 -0500 Committer: Mike Zaccardo <[email protected]> Committed: Fri Oct 16 13:08:52 2015 -0500 ---------------------------------------------------------------------- .../brooklyn/entity/group/DynamicCluster.java | 4 + .../entity/group/DynamicClusterImpl.java | 25 +++++- .../entity/group/DynamicClusterTest.java | 88 ++++++++++++++++++-- 3 files changed, 108 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cea34628/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java index b6ee23a..4033a1e 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java +++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicCluster.java @@ -161,6 +161,10 @@ public interface DynamicCluster extends AbstractGroup, Cluster, MemberReplaceabl ConfigKey<Integer> NUM_AVAILABILITY_ZONES = ConfigKeys.newIntegerConfigKey( "dynamiccluster.numAvailabilityZones", "number of availability zones to use (will attempt to auto-discover this number)"); + @SetFromFlag("clusterMemberId") + ConfigKey<Integer> CLUSTER_MEMBER_ID = ConfigKeys.newIntegerConfigKey( + "cluster.member.id", "The unique ID number (sequential) of a member of a cluster"); + AttributeSensor<List<Location>> SUB_LOCATIONS = new BasicAttributeSensor<List<Location>>( new TypeToken<List<Location>>() {}, "dynamiccluster.subLocations", "Locations for each availability zone to use"); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cea34628/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java index 3fcebdf..f8e8f1e 100644 --- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java +++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java @@ -28,16 +28,17 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Nullable; import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntityLocal; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.api.location.MachineProvisioningLocation; import org.apache.brooklyn.api.mgmt.Task; import org.apache.brooklyn.api.policy.Policy; +import org.apache.brooklyn.api.sensor.AttributeSensor; import org.apache.brooklyn.core.config.render.RendererHints; import org.apache.brooklyn.core.effector.Effectors; import org.apache.brooklyn.core.entity.Entities; @@ -50,9 +51,8 @@ import org.apache.brooklyn.core.entity.trait.Startable; import org.apache.brooklyn.core.entity.trait.StartableMethods; import org.apache.brooklyn.core.location.Locations; import org.apache.brooklyn.core.location.cloud.AvailabilityZoneExtension; +import org.apache.brooklyn.core.sensor.Sensors; import org.apache.brooklyn.entity.stock.DelegateEntity; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks; @@ -67,11 +67,14 @@ import org.apache.brooklyn.util.javalang.JavaClassNames; import org.apache.brooklyn.util.javalang.Reflections; import org.apache.brooklyn.util.text.StringPredicates; import org.apache.brooklyn.util.text.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Predicates; +import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -81,12 +84,17 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; +import com.google.common.reflect.TypeToken; /** * A cluster of entities that can dynamically increase or decrease the number of entities. */ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicCluster { + @SuppressWarnings("serial") + private static final AttributeSensor<Supplier<Integer>> NEXT_CLUSTER_MEMBER_ID = Sensors.newSensor(new TypeToken<Supplier<Integer>>() {}, + "next.cluster.member.id", "Returns the ID number of the next member to be added"); + // TODO better mechanism for arbitrary class name to instance type coercion static { TypeCoercions.registerAdapter(String.class, NodePlacementStrategy.class, new Function<String, NodePlacementStrategy>() { @@ -147,12 +155,22 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus } }; + private static class NextClusterMemberIdSupplier implements Supplier<Integer> { + private AtomicInteger nextId = new AtomicInteger(0); + + @Override + public Integer get() { + return nextId.getAndIncrement(); + } + } + public DynamicClusterImpl() { } @Override public void init() { super.init(); + sensors().set(NEXT_CLUSTER_MEMBER_ID, new NextClusterMemberIdSupplier()); } @Override @@ -765,6 +783,7 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus Map<?,?> createFlags = MutableMap.builder() .putAll(getCustomChildFlags()) .putAll(extraFlags) + .put(CLUSTER_MEMBER_ID, getAttribute(NEXT_CLUSTER_MEMBER_ID).get()) .build(); if (LOG.isDebugEnabled()) { LOG.debug("Creating and adding a node to cluster {}({}) with properties {}", new Object[] { this, getId(), createFlags }); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cea34628/core/src/test/java/org/apache/brooklyn/entity/group/DynamicClusterTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/entity/group/DynamicClusterTest.java b/core/src/test/java/org/apache/brooklyn/entity/group/DynamicClusterTest.java index f575a42..dd37e58 100644 --- a/core/src/test/java/org/apache/brooklyn/entity/group/DynamicClusterTest.java +++ b/core/src/test/java/org/apache/brooklyn/entity/group/DynamicClusterTest.java @@ -18,6 +18,7 @@ */ package org.apache.brooklyn.entity.group; +import static org.apache.brooklyn.entity.group.DynamicCluster.CLUSTER_MEMBER_ID; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; @@ -25,6 +26,7 @@ import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -39,9 +41,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.location.Location; @@ -60,9 +59,6 @@ import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.core.test.entity.TestEntityImpl; -import org.apache.brooklyn.entity.group.DynamicCluster; -import org.apache.brooklyn.entity.group.QuarantineGroup; -import org.apache.brooklyn.entity.group.StopFailedRuntimeException; import org.apache.brooklyn.entity.stock.BasicEntity; import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.test.EntityTestUtils; @@ -71,6 +67,9 @@ import org.apache.brooklyn.util.collections.MutableSet; import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.time.Time; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; import com.google.common.base.Function; import com.google.common.base.Predicates; @@ -79,6 +78,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.google.common.util.concurrent.Atomics; @@ -966,6 +966,82 @@ public class DynamicClusterTest extends BrooklynAppUnitTestSupport { assertEquals(ImmutableList.copyOf(member.getLocations()), ImmutableList.of(loc2)); } + @Test + public void testAllClusterMemberIdsAddedInOrderOnCreation() throws Exception { + int clusterSize = 5; + + DynamicCluster cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class) + .configure("factory", new EntityFactory() { + @Override + public Entity newEntity(Map flags, Entity parent) { + return new TestEntityImpl(flags); + } + }).configure("initialSize", clusterSize)); + + cluster.start(ImmutableList.of(loc)); + + Iterator<Entity> clusterMembersIterator = cluster.getMembers().iterator(); + + for (Integer expectedClusterMemberId = 0; expectedClusterMemberId < clusterSize; expectedClusterMemberId++) { + Entity clusterMember = clusterMembersIterator.next(); + assertEquals(clusterMember.config().get(CLUSTER_MEMBER_ID), expectedClusterMemberId); + } + } + + @Test + public void testAllClusterMemberIdsAddedInOrderOnPositiveResize() throws Exception { + int clusterSize = 5; + + DynamicCluster cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class) + .configure("factory", new EntityFactory() { + @Override + public Entity newEntity(Map flags, Entity parent) { + return new TestEntityImpl(flags); + } + }).configure("initialSize", clusterSize)); + + cluster.start(ImmutableList.of(loc)); + + int positiveResizeDelta = 3; + cluster.resizeByDelta(positiveResizeDelta); + + Iterator<Entity> clusterMembersIterator = cluster.getMembers().iterator(); + + for (Integer expectedClusterMemberId = 0; expectedClusterMemberId < clusterSize + positiveResizeDelta; expectedClusterMemberId++) { + Entity clusterMember = clusterMembersIterator.next(); + assertEquals(clusterMember.config().get(CLUSTER_MEMBER_ID), expectedClusterMemberId); + } + } + + @Test + public void testAllClusterMemberIdsAddedInOrderOnNegativeThenPositiveResize() throws Exception { + int clusterSize = 5; + + DynamicCluster cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class) + .configure("factory", new EntityFactory() { + @Override + public Entity newEntity(Map flags, Entity parent) { + return new TestEntityImpl(flags); + } + }).configure("initialSize", clusterSize)); + + cluster.start(ImmutableList.of(loc)); + + int negativeResizeDelta = -3; + cluster.resizeByDelta(negativeResizeDelta); + + int positiveResizeDelta = 2; + cluster.resizeByDelta(positiveResizeDelta); + + Iterator<Entity> clusterMembersIterator = cluster.getMembers().iterator(); + + Integer[] expectedClusterMemberIds = {0, 1, 5, 6}; + + for (Integer expectedClusterMemberId : expectedClusterMemberIds) { + Entity clusterMember = clusterMembersIterator.next(); + assertEquals(clusterMember.config().get(CLUSTER_MEMBER_ID), expectedClusterMemberId); + } + } private void assertFirstAndNonFirstCounts(Collection<Entity> members, int expectedFirstCount, int expectedNonFirstCount) { Set<Entity> found = MutableSet.of();
