http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBrokerImpl.java ---------------------------------------------------------------------- diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBrokerImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBrokerImpl.java index 24c570b..fa69522 100644 --- a/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBrokerImpl.java +++ b/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBrokerImpl.java @@ -26,6 +26,7 @@ import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import brooklyn.entity.basic.Lifecycle; import brooklyn.entity.basic.SoftwareProcessImpl; import brooklyn.entity.messaging.Queue; import brooklyn.entity.messaging.Topic; @@ -132,9 +133,17 @@ public abstract class JMSBrokerImpl<Q extends JMSDestination & Queue, T extends addQueue(name, MutableMap.of()); } + public void checkStartingOrRunning() { + Lifecycle state = getAttribute(SERVICE_STATE_ACTUAL); + if (getAttribute(SERVICE_STATE_ACTUAL) == Lifecycle.RUNNING) return; + if (getAttribute(SERVICE_STATE_ACTUAL) == Lifecycle.STARTING) return; + // TODO this check may be redundant or even inappropriate + throw new IllegalStateException("Cannot run against "+this+" in state "+state); + } + @Override public void addQueue(String name, Map properties) { - checkModifiable(); + checkStartingOrRunning(); properties.put("name", name); queues.put(name, createQueue(properties)); } @@ -149,7 +158,7 @@ public abstract class JMSBrokerImpl<Q extends JMSDestination & Queue, T extends @Override public void addTopic(String name, Map properties) { - checkModifiable(); + checkStartingOrRunning(); properties.put("name", name); topics.put(name, createTopic(properties)); }
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java ---------------------------------------------------------------------- diff --git a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java index 520e0af..511bb6b 100644 --- a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java +++ b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java @@ -79,26 +79,23 @@ public class ZooKeeperEnsembleImpl extends DynamicClusterImpl implements ZooKeep if (member.getAttribute(ZooKeeperNode.MY_ID) == null) { ((EntityInternal) member).setAttribute(ZooKeeperNode.MY_ID, myId.incrementAndGet()); } - entity.setAttribute(SERVICE_UP, ((ZooKeeperEnsembleImpl)entity).calculateServiceUp()); } @Override protected void onEntityRemoved(Entity member) { - entity.setAttribute(SERVICE_UP, ((ZooKeeperEnsembleImpl)entity).calculateServiceUp()); } }; @Override - public synchronized boolean addMember(Entity member) { - boolean result = super.addMember(member); - setAttribute(SERVICE_UP, calculateServiceUp()); - return result; + protected void initEnrichers() { + super.initEnrichers(); + } - + @Override public void start(Collection<? extends Location> locations) { super.start(locations); - setAttribute(Startable.SERVICE_UP, calculateServiceUp()); + List<String> zookeeperServers = Lists.newArrayList(); for (Entity zookeeper : getMembers()) { zookeeperServers.add(zookeeper.getAttribute(Attributes.HOSTNAME)); @@ -106,13 +103,4 @@ public class ZooKeeperEnsembleImpl extends DynamicClusterImpl implements ZooKeep setAttribute(ZOOKEEPER_SERVERS, zookeeperServers); } - @Override - protected boolean calculateServiceUp() { - boolean up = false; - for (Entity member : getMembers()) { - if (Boolean.TRUE.equals(member.getAttribute(SERVICE_UP))) up = true; - } - return up; - } - } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java ---------------------------------------------------------------------- diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java index 9bf442b..b04e362 100644 --- a/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java +++ b/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraDatacenterImpl.java @@ -38,6 +38,7 @@ import brooklyn.entity.basic.DynamicGroup; import brooklyn.entity.basic.Entities; import brooklyn.entity.basic.EntityPredicates; import brooklyn.entity.basic.Lifecycle; +import brooklyn.entity.basic.ServiceStateLogic.ServiceNotUpLogic; import brooklyn.entity.effector.EffectorBody; import brooklyn.entity.group.AbstractMembershipTrackingPolicy; import brooklyn.entity.group.DynamicClusterImpl; @@ -111,7 +112,7 @@ public class CassandraDatacenterImpl extends DynamicClusterImpl implements Cassa return ImmutableSet.of(); } else if (hasPublishedSeeds) { Set<Entity> currentSeeds = getAttribute(CURRENT_SEEDS); - if (getAttribute(SERVICE_STATE) == Lifecycle.STARTING) { + if (getAttribute(SERVICE_STATE_ACTUAL) == Lifecycle.STARTING) { if (Sets.intersection(currentSeeds, potentialSeeds).isEmpty()) { log.warn("Cluster {} lost all its seeds while starting! Subsequent failure likely, but changing seeds during startup would risk split-brain: seeds={}", new Object[] {CassandraDatacenterImpl.this, currentSeeds}); } @@ -426,12 +427,6 @@ public class CassandraDatacenterImpl extends DynamicClusterImpl implements Cassa .build()); } - - subscribeToMembers(this, SERVICE_UP, new SensorEventListener<Boolean>() { - @Override public void onEvent(SensorEvent<Boolean> event) { - setAttribute(SERVICE_UP, calculateServiceUp()); - } - }); } @Override @@ -477,19 +472,11 @@ public class CassandraDatacenterImpl extends DynamicClusterImpl implements Cassa setAttribute(THRIFT_PORT, null); setAttribute(CASSANDRA_CLUSTER_NODES, Collections.<String>emptyList()); } - - setAttribute(SERVICE_UP, upNode.isPresent() && calculateServiceUp()); + + ServiceNotUpLogic.updateNotUpIndicatorRequiringNonEmptyList(this, CASSANDRA_CLUSTER_NODES); } } - @Override - protected boolean calculateServiceUp() { - if (!super.calculateServiceUp()) return false; - List<String> nodes = getAttribute(CASSANDRA_CLUSTER_NODES); - if (nodes==null || nodes.isEmpty()) return false; - return true; - } - /** * For tracking our seeds. This gets fiddly! High-level logic is: * <ul> http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraFabricImpl.java ---------------------------------------------------------------------- diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraFabricImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraFabricImpl.java index 5d3c219..fe0b503 100644 --- a/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraFabricImpl.java +++ b/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraFabricImpl.java @@ -72,8 +72,6 @@ public class CassandraFabricImpl extends DynamicFabricImpl implements CassandraF // Mutex for synchronizing during re-size operations private final Object mutex = new Object[0]; - private MemberTrackingPolicy policy; - private final Supplier<Set<Entity>> defaultSeedSupplier = new Supplier<Set<Entity>>() { @Override public Set<Entity> get() { // TODO Remove duplication from CassandraClusterImpl.defaultSeedSupplier @@ -95,7 +93,7 @@ public class CassandraFabricImpl extends DynamicFabricImpl implements CassandraF if (hasPublishedSeeds) { Set<Entity> currentSeeds = getAttribute(CURRENT_SEEDS); - Lifecycle serviceState = getAttribute(SERVICE_STATE); + Lifecycle serviceState = getAttribute(SERVICE_STATE_ACTUAL); if (serviceState == Lifecycle.STARTING) { if (Sets.intersection(currentSeeds, ImmutableSet.copyOf(Iterables.concat(potentialSeeds.values()))).isEmpty()) { log.warn("Fabric {} lost all its seeds while starting! Subsequent failure likely, but changing seeds during startup would risk split-brain: seeds={}", new Object[] {CassandraFabricImpl.this, currentSeeds}); @@ -211,7 +209,7 @@ public class CassandraFabricImpl extends DynamicFabricImpl implements CassandraF setConfig(CassandraDatacenter.SEED_SUPPLIER, getSeedSupplier()); // track members - policy = addPolicy(PolicySpec.create(MemberTrackingPolicy.class) + addPolicy(PolicySpec.create(MemberTrackingPolicy.class) .displayName("Cassandra Fabric Tracker") .configure("group", this)); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java index 11c56d7..b47f133 100644 --- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java +++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java @@ -35,13 +35,13 @@ import brooklyn.entity.basic.Attributes; import brooklyn.entity.basic.Entities; import brooklyn.entity.basic.EntityInternal; import brooklyn.entity.basic.Lifecycle; +import brooklyn.entity.basic.QuorumCheck; +import brooklyn.entity.basic.ServiceStateLogic; import brooklyn.entity.group.AbstractMembershipTrackingPolicy; import brooklyn.entity.group.DynamicClusterImpl; import brooklyn.entity.proxying.EntitySpec; import brooklyn.entity.trait.Startable; import brooklyn.event.AttributeSensor; -import brooklyn.event.SensorEvent; -import brooklyn.event.SensorEventListener; import brooklyn.location.Location; import brooklyn.policy.PolicySpec; import brooklyn.util.collections.MutableSet; @@ -129,8 +129,7 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas super.start(locations); connectSensors(); - connectEnrichers(); - + //start timeout before adding the servers Time.sleep(getConfig(SERVICE_UP_TIME_OUT)); @@ -165,7 +164,7 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas //check Repeater. } } else { - setAttribute(SERVICE_STATE, Lifecycle.ON_FIRE); + ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE); } } @@ -175,16 +174,6 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas super.stop(); } - public void connectEnrichers() { - - subscribeToMembers(this, SERVICE_UP, new SensorEventListener<Boolean>() { - @Override - public void onEvent(SensorEvent<Boolean> event) { - setAttribute(SERVICE_UP, calculateServiceUp()); - } - }); - } - protected void connectSensors() { addPolicy(PolicySpec.create(MemberTrackingPolicy.class) .displayName("Controller targets tracker") @@ -292,13 +281,22 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas } @Override - protected boolean calculateServiceUp() { - if (!super.calculateServiceUp()) return false; - Set<Entity> upNodes = getAttribute(COUCHBASE_CLUSTER_UP_NODES); - if (upNodes == null || upNodes.isEmpty() || upNodes.size() < getQuorumSize()) return false; - return true; + protected void initEnrichers() { + if (getConfigRaw(UP_QUORUM_CHECK, false).isAbsent()) { + class CouchbaseQuorumCheck implements QuorumCheck { + @Override + public boolean isQuorate(int sizeHealthy, int totalSize) { + // check members count passed in AND the sensor + if (sizeHealthy < getQuorumSize()) return false; + Set<Entity> upNodes = getAttribute(COUCHBASE_CLUSTER_UP_NODES); + return (upNodes != null && !upNodes.isEmpty() && upNodes.size() >= getQuorumSize()); + } + } + setConfig(UP_QUORUM_CHECK, new CouchbaseQuorumCheck()); + } + super.initEnrichers(); } - + protected void addServers(Set<Entity> serversToAdd) { Preconditions.checkNotNull(serversToAdd); for (Entity e : serversToAdd) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/nosql/src/main/java/brooklyn/entity/nosql/couchdb/CouchDBClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchdb/CouchDBClusterImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchdb/CouchDBClusterImpl.java index a149140..4835f72 100644 --- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchdb/CouchDBClusterImpl.java +++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchdb/CouchDBClusterImpl.java @@ -18,22 +18,18 @@ */ package brooklyn.entity.nosql.couchdb; -import java.util.Collection; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import brooklyn.entity.Entity; import brooklyn.entity.group.DynamicClusterImpl; import brooklyn.entity.proxying.EntitySpec; -import brooklyn.entity.trait.Startable; -import brooklyn.location.Location; /** * Implementation of {@link CouchDBCluster}. */ public class CouchDBClusterImpl extends DynamicClusterImpl implements CouchDBCluster { + @SuppressWarnings("unused") private static final Logger log = LoggerFactory.getLogger(CouchDBClusterImpl.class); public CouchDBClusterImpl() { @@ -52,19 +48,4 @@ public class CouchDBClusterImpl extends DynamicClusterImpl implements CouchDBClu return getAttribute(CLUSTER_NAME); } - @Override - public void start(Collection<? extends Location> locations) { - super.start(locations); - - setAttribute(Startable.SERVICE_UP, calculateServiceUp()); - } - - @Override - protected boolean calculateServiceUp() { - boolean up = false; - for (Entity member : getMembers()) { - if (Boolean.TRUE.equals(member.getAttribute(SERVICE_UP))) up = true; - } - return up; - } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/nosql/src/main/java/brooklyn/entity/nosql/elasticsearch/ElasticSearchClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/elasticsearch/ElasticSearchClusterImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/elasticsearch/ElasticSearchClusterImpl.java index da719dd..a773006 100644 --- a/software/nosql/src/main/java/brooklyn/entity/nosql/elasticsearch/ElasticSearchClusterImpl.java +++ b/software/nosql/src/main/java/brooklyn/entity/nosql/elasticsearch/ElasticSearchClusterImpl.java @@ -20,7 +20,6 @@ package brooklyn.entity.nosql.elasticsearch; import java.util.concurrent.atomic.AtomicInteger; -import brooklyn.entity.Entity; import brooklyn.entity.group.DynamicClusterImpl; import brooklyn.entity.proxying.EntitySpec; @@ -29,15 +28,6 @@ public class ElasticSearchClusterImpl extends DynamicClusterImpl implements Elas private AtomicInteger nextMemberId = new AtomicInteger(0); @Override - protected boolean calculateServiceUp() { - boolean up = false; - for (Entity member : getMembers()) { - if (Boolean.TRUE.equals(member.getAttribute(SERVICE_UP))) up = true; - } - return up; - } - - @Override protected EntitySpec<?> getMemberSpec() { EntitySpec<?> spec = EntitySpec.create(getConfig(MEMBER_SPEC, EntitySpec.create(ElasticSearchNode.class))); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/nosql/src/main/java/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java ---------------------------------------------------------------------- diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java index b859765..b1e2393 100644 --- a/software/nosql/src/main/java/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java +++ b/software/nosql/src/main/java/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java @@ -40,6 +40,7 @@ import org.slf4j.LoggerFactory; import brooklyn.enricher.Enrichers; import brooklyn.entity.Entity; import brooklyn.entity.basic.Lifecycle; +import brooklyn.entity.basic.ServiceStateLogic; import brooklyn.entity.group.AbstractMembershipTrackingPolicy; import brooklyn.entity.group.DynamicClusterImpl; import brooklyn.entity.proxying.EntitySpec; @@ -200,7 +201,7 @@ public class MongoDBReplicaSetImpl extends DynamicClusterImpl implements MongoDB setAttribute(PRIMARY_ENTITY, server); setAttribute(Startable.SERVICE_UP, true); } else { - setAttribute(SERVICE_STATE, Lifecycle.ON_FIRE); + ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE); } } else { if (LOG.isDebugEnabled()) http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/nosql/src/main/java/brooklyn/entity/nosql/mongodb/sharding/MongoDBConfigServerClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/mongodb/sharding/MongoDBConfigServerClusterImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/mongodb/sharding/MongoDBConfigServerClusterImpl.java index 28ee33a..df85c36 100644 --- a/software/nosql/src/main/java/brooklyn/entity/nosql/mongodb/sharding/MongoDBConfigServerClusterImpl.java +++ b/software/nosql/src/main/java/brooklyn/entity/nosql/mongodb/sharding/MongoDBConfigServerClusterImpl.java @@ -38,23 +38,11 @@ public class MongoDBConfigServerClusterImpl extends DynamicClusterImpl implement return EntitySpec.create(MongoDBConfigServer.class); } - - @Override - protected boolean calculateServiceUp() { - // Number of config servers is fixed at INITIAL_SIZE - int requiredMembers = this.getConfig(INITIAL_SIZE); - int availableMembers = 0; - for (Entity entity : getMembers()) { - if (entity instanceof MongoDBConfigServer & entity.getAttribute(SERVICE_UP)) { - availableMembers++; - } - } - return availableMembers >= requiredMembers; - } - @Override public void start(Collection<? extends Location> locs) { super.start(locs); + + // TODO this should be an enricher Iterable<String> memberHostNamesAndPorts = Iterables.transform(getMembers(), new Function<Entity, String>() { @Override public String apply(Entity entity) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/nosql/src/main/java/brooklyn/entity/nosql/riak/RiakClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/riak/RiakClusterImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/riak/RiakClusterImpl.java index 9826300..a75c422 100644 --- a/software/nosql/src/main/java/brooklyn/entity/nosql/riak/RiakClusterImpl.java +++ b/software/nosql/src/main/java/brooklyn/entity/nosql/riak/RiakClusterImpl.java @@ -21,6 +21,7 @@ package brooklyn.entity.nosql.riak; import static brooklyn.util.JavaGroovyEquivalents.groovyTruth; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; @@ -39,6 +40,8 @@ import brooklyn.entity.Entity; import brooklyn.entity.basic.Entities; import brooklyn.entity.basic.EntityInternal; import brooklyn.entity.basic.Lifecycle; +import brooklyn.entity.basic.ServiceStateLogic; +import brooklyn.entity.basic.ServiceStateLogic.ServiceNotUpLogic; import brooklyn.entity.group.AbstractMembershipTrackingPolicy; import brooklyn.entity.group.DynamicClusterImpl; import brooklyn.entity.proxying.EntitySpec; @@ -80,7 +83,7 @@ public class RiakClusterImpl extends DynamicClusterImpl implements RiakCluster { setAttribute(IS_CLUSTER_INIT, true); } else { log.warn("No Riak Nodes are found on the cluster: {}. Initialization Failed", getId()); - setAttribute(SERVICE_STATE, Lifecycle.ON_FIRE); + ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE); } } @@ -100,11 +103,11 @@ public class RiakClusterImpl extends DynamicClusterImpl implements RiakCluster { if (log.isTraceEnabled()) log.trace("For {}, considering membership of {} which is in locations {}", new Object[]{this, member, member.getLocations()}); + Map<Entity, String> nodes = getAttribute(RIAK_CLUSTER_NODES); if (belongsInServerPool(member)) { // TODO can we discover the nodes by asking the riak cluster, rather than assuming what we add will be in there? // TODO and can we do join as part of node starting? - Map<Entity, String> nodes = getAttribute(RIAK_CLUSTER_NODES); if (nodes == null) nodes = Maps.newLinkedHashMap(); String riakName = getRiakName(member); @@ -151,7 +154,6 @@ public class RiakClusterImpl extends DynamicClusterImpl implements RiakCluster { } } } else { - Map<Entity, String> nodes = getAttribute(RIAK_CLUSTER_NODES); if (nodes != null && nodes.containsKey(member)) { final Entity memberToBeRemoved = member; @@ -172,6 +174,8 @@ public class RiakClusterImpl extends DynamicClusterImpl implements RiakCluster { } } + + ServiceNotUpLogic.updateNotUpIndicatorRequiringNonEmptyMap(this, RIAK_CLUSTER_NODES); if (log.isTraceEnabled()) log.trace("Done {} checkEntity {}", this, member); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java b/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java index 9e0b151..d405fab 100644 --- a/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java +++ b/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java @@ -325,7 +325,7 @@ public abstract class AbstractControllerImpl extends SoftwareProcessImpl impleme @Override protected void postRebind() { super.postRebind(); - Lifecycle state = getAttribute(SERVICE_STATE); + Lifecycle state = getAttribute(SERVICE_STATE_ACTUAL); if (state != null && state == Lifecycle.RUNNING) { isActive = true; update(); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/webapp/src/main/java/brooklyn/entity/proxy/LoadBalancerClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/LoadBalancerClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/proxy/LoadBalancerClusterImpl.java index 8c4f389..bc8f88d 100644 --- a/software/webapp/src/main/java/brooklyn/entity/proxy/LoadBalancerClusterImpl.java +++ b/software/webapp/src/main/java/brooklyn/entity/proxy/LoadBalancerClusterImpl.java @@ -18,14 +18,10 @@ */ package brooklyn.entity.proxy; -import java.util.Collection; import java.util.Map; import brooklyn.entity.Entity; -import brooklyn.entity.group.AbstractMembershipTrackingPolicy; import brooklyn.entity.group.DynamicClusterImpl; -import brooklyn.location.Location; -import brooklyn.policy.PolicySpec; /** * A cluster of load balancers, where configuring the cluster (through the LoadBalancer interface) @@ -49,33 +45,6 @@ public class LoadBalancerClusterImpl extends DynamicClusterImpl implements LoadB super(); } - @Override - public void start(Collection<? extends Location> locs) { - super.start(locs); - - // TODO Is there a race here, where (dispite super.stop() calling policy.suspend), - // this could still be executing setAttribute(true) and hence incorrectly leave - // the cluster in a service_up==true state after stop() returns? - addPolicy(PolicySpec.create(MemberTrackingPolicy.class) - .configure("group", this)); - } - - public static class MemberTrackingPolicy extends AbstractMembershipTrackingPolicy { - @Override protected void onEntityEvent(EventType type, Entity member) { - entity.setAttribute(SERVICE_UP, ((LoadBalancerClusterImpl)entity).calculateServiceUp()); - } - } - - /** - * Up if running and has at least one load-balancer in the cluster. - * - * TODO Could also look at service_up of each load-balancer, but currently does not do that. - */ - @Override - protected boolean calculateServiceUp() { - return super.calculateServiceUp() && getCurrentSize() > 0; - } - /* NOTE The following methods come from {@link LoadBalancer} but are probably safe to ignore */ @Override http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java index f482422..3e36ada 100644 --- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java +++ b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java @@ -66,7 +66,7 @@ public class NginxControllerImpl extends AbstractControllerImpl implements Nginx public void reload() { NginxSshDriver driver = (NginxSshDriver)getDriver(); if (driver==null) { - Lifecycle state = getAttribute(NginxController.SERVICE_STATE); + Lifecycle state = getAttribute(NginxController.SERVICE_STATE_ACTUAL); throw new IllegalStateException("Cannot reload (no driver instance; stopped? (state="+state+")"); } @@ -181,7 +181,7 @@ public class NginxControllerImpl extends AbstractControllerImpl implements Nginx if (driver==null) { if (LOG.isDebugEnabled()) LOG.debug("No driver for {}, so not deploying archive (is entity stopping? state={})", - this, getAttribute(NginxController.SERVICE_STATE)); + this, getAttribute(NginxController.SERVICE_STATE_ACTUAL)); return; } @@ -248,7 +248,7 @@ public class NginxControllerImpl extends AbstractControllerImpl implements Nginx if (driver==null) { if (LOG.isDebugEnabled()) LOG.debug("No driver for {}, so not generating config file (is entity stopping? state={})", - this, getAttribute(NginxController.SERVICE_STATE)); + this, getAttribute(NginxController.SERVICE_STATE_ACTUAL)); return null; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java index 81e74fd..8a3f2c6 100644 --- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java +++ b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java @@ -380,8 +380,8 @@ public class NginxSshDriver extends AbstractSoftwareProcessSshDriver implements // calling waitForEntityStart()), we can guarantee that the start-thread's call to update will happen after // this call to reload. So we this can be a no-op, and just rely on that subsequent call to update. - Lifecycle lifecycle = entity.getAttribute(NginxController.SERVICE_STATE); if (!isRunning()) { + Lifecycle lifecycle = entity.getAttribute(NginxController.SERVICE_STATE_ACTUAL); log.debug("Ignoring reload of nginx "+entity+", because service is not running (state "+lifecycle+")"); return; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java index 0c263d9..72b2bb6 100644 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java +++ b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java @@ -93,7 +93,7 @@ public interface ControlledDynamicWebAppCluster extends DynamicGroup, Entity, St public static final AttributeSensor<String> HOSTNAME = Attributes.HOSTNAME; - public static final AttributeSensor<Lifecycle> SERVICE_STATE = Attributes.SERVICE_STATE; + public static final AttributeSensor<Lifecycle> SERVICE_STATE_ACTUAL = Attributes.SERVICE_STATE_ACTUAL; public LoadBalancer getController(); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java index 47e7ec9..acff382 100644 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java +++ b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java @@ -19,10 +19,9 @@ package brooklyn.entity.webapp; import java.util.Collection; -import java.util.EnumSet; import java.util.List; import java.util.Map; -import java.util.concurrent.ExecutionException; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,6 +34,9 @@ import brooklyn.entity.basic.DynamicGroupImpl; import brooklyn.entity.basic.Entities; import brooklyn.entity.basic.EntityPredicates; import brooklyn.entity.basic.Lifecycle; +import brooklyn.entity.basic.QuorumCheck; +import brooklyn.entity.basic.QuorumCheck.QuorumChecks; +import brooklyn.entity.basic.ServiceStateLogic; import brooklyn.entity.proxy.LoadBalancer; import brooklyn.entity.proxy.nginx.NginxController; import brooklyn.entity.proxying.EntitySpec; @@ -71,7 +73,6 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme @Deprecated public ControlledDynamicWebAppClusterImpl(Map<?,?> flags, Entity parent) { super(flags, parent); - setAttribute(SERVICE_UP, false); } @Override @@ -137,6 +138,14 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme doBind(); } + + @Override + protected void initEnrichers() { + if (getConfigRaw(UP_QUORUM_CHECK, false).isAbsent()) { + setConfig(UP_QUORUM_CHECK, QuorumChecks.newInstance(2, 1.0, false)); + } + super.initEnrichers(); + } @Override public void rebind() { @@ -174,7 +183,7 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme @Override public void start(Collection<? extends Location> locations) { - setAttribute(Attributes.SERVICE_STATE, Lifecycle.STARTING); + ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING); try { if (isLegacyConstruction()) { @@ -202,13 +211,9 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme // (will happen asynchronously as members come online, but we want to force it to happen) getController().update(); - setAttribute(SERVICE_UP, getCluster().getAttribute(SERVICE_UP)); - setAttribute(SERVICE_STATE, Lifecycle.RUNNING); - } catch (InterruptedException e) { - setAttribute(Attributes.SERVICE_STATE, Lifecycle.ON_FIRE); - throw Exceptions.propagate(e); - } catch (ExecutionException e) { - setAttribute(Attributes.SERVICE_STATE, Lifecycle.ON_FIRE); + ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING); + } catch (Exception e) { + ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE); throw Exceptions.propagate(e); } finally { connectSensors(); @@ -217,7 +222,7 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme @Override public void stop() { - setAttribute(SERVICE_STATE, Lifecycle.STOPPING); + ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING); try { List<Startable> tostop = Lists.newArrayList(); @@ -228,10 +233,9 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme clearLocations(); - setAttribute(SERVICE_STATE, Lifecycle.STOPPED); - setAttribute(SERVICE_UP, false); + ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPED); } catch (Exception e) { - setAttribute(SERVICE_STATE, Lifecycle.ON_FIRE); + ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE); throw Exceptions.propagate(e); } } @@ -246,8 +250,9 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme } void connectSensors() { + // FIXME no longer needed addEnricher(Enrichers.builder() - .propagatingAllBut(SERVICE_STATE, SERVICE_UP, ROOT_URL, GROUP_MEMBERS, GROUP_SIZE) + .propagatingAllButUsualAnd(ROOT_URL, GROUP_MEMBERS, GROUP_SIZE) .from(getCluster()) .build()); addEnricher(Enrichers.builder() @@ -255,40 +260,6 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme .propagating(LoadBalancer.HOSTNAME, Attributes.ADDRESS, ROOT_URL) .from(getController()) .build()); - - SensorEventListener<Boolean> updateServiceUp = new SensorEventListener<Boolean>() { - @Override - public void onEvent(SensorEvent<Boolean> event) { - setAttribute(SERVICE_UP, calculateServiceUp()); - } - }; - SensorEventListener<Lifecycle> updateServiceState = new SensorEventListener<Lifecycle>() { - @Override - public void onEvent(SensorEvent<Lifecycle> event) { - setAttribute(SERVICE_STATE, calculateServiceState()); - } - }; - - subscribe(getCluster(), SERVICE_STATE, updateServiceState); - subscribe(getController(), SERVICE_STATE, updateServiceState); - subscribe(getCluster(), SERVICE_UP, updateServiceUp); - subscribe(getController(), SERVICE_UP, updateServiceUp); - } - - protected Lifecycle calculateServiceState() { - Lifecycle currentState = getAttribute(SERVICE_STATE); - if (EnumSet.of(Lifecycle.ON_FIRE, Lifecycle.RUNNING).contains(currentState)) { - if (getCluster().getAttribute(SERVICE_STATE) == Lifecycle.ON_FIRE) currentState = Lifecycle.ON_FIRE; - if (getController().getAttribute(SERVICE_STATE) == Lifecycle.ON_FIRE) currentState = Lifecycle.ON_FIRE; - } - return currentState; - } - - /** - * Default impl is to be up when running, and !up otherwise. - */ - protected boolean calculateServiceUp() { - return getAttribute(SERVICE_STATE) == Lifecycle.RUNNING; } @Override http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java index bfdc666..951e3b4 100644 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java +++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java @@ -37,8 +37,6 @@ import brooklyn.entity.effector.Effectors; import brooklyn.entity.group.DynamicCluster; import brooklyn.entity.group.DynamicClusterImpl; import brooklyn.event.AttributeSensor; -import brooklyn.event.SensorEvent; -import brooklyn.event.SensorEventListener; import brooklyn.management.Task; import brooklyn.management.TaskAdaptable; import brooklyn.util.collections.MutableMap; @@ -123,45 +121,6 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna } } - public void onManagementStarted() { - super.onManagementStarted(); - - subscribeToMembers(this, SERVICE_UP, new SensorEventListener<Boolean>() { - @Override public void onEvent(SensorEvent<Boolean> event) { - if (!isRebinding()) { - setAttribute(SERVICE_UP, calculateServiceUp()); - } - } - }); - } - - @Override - public synchronized boolean addMember(Entity member) { - boolean result = super.addMember(member); - if (!isRebinding()) { - setAttribute(SERVICE_UP, calculateServiceUp()); - } - return result; - } - - @Override - public synchronized boolean removeMember(Entity member) { - boolean result = super.removeMember(member); - if (!isRebinding()) { - setAttribute(SERVICE_UP, calculateServiceUp()); - } - return result; - } - - @Override - protected boolean calculateServiceUp() { - boolean up = false; - for (Entity member : getMembers()) { - if (Boolean.TRUE.equals(member.getAttribute(SERVICE_UP))) up = true; - } - return up; - } - // TODO this will probably be useful elsewhere ... but where to put it? // TODO add support for this in DependentConfiguration (see TODO there) /** Waits for the given target to report service up, then runs the given task http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/webapp/src/main/java/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java index ce8fdec..9d2c7ec 100644 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java +++ b/software/webapp/src/main/java/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java @@ -130,7 +130,7 @@ public class Jetty6ServerImpl extends JavaWebAppSoftwareProcessImpl implements J protected void restartIfRunning() { // TODO for now we simply restart jetty to achieve "hot deployment"; should use the config mechanisms - Lifecycle serviceState = getAttribute(SERVICE_STATE); + Lifecycle serviceState = getAttribute(SERVICE_STATE_ACTUAL); if (serviceState == Lifecycle.RUNNING) restart(); // may need a restart also if deploy effector is done in parallel to starting http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java index 74e23b5..f731eca 100644 --- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java +++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java @@ -50,6 +50,7 @@ import brooklyn.location.LocationSpec; import brooklyn.location.basic.LocalhostMachineProvisioningLocation; import brooklyn.management.ManagementContext; import brooklyn.test.Asserts; +import brooklyn.test.EntityTestUtils; import brooklyn.test.WebAppMonitor; import com.google.common.base.Predicates; @@ -134,7 +135,7 @@ public class NginxRebindIntegrationTest extends RebindTestFixtureWithApp { assertEquals(newNginx.getConfigFile(), origConfigFile); - assertEquals(newNginx.getAttribute(NginxController.SERVICE_STATE), Lifecycle.RUNNING); + EntityTestUtils.assertAttributeEqualsEventually(newNginx, NginxController.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING); assertEquals(newNginx.getAttribute(NginxController.PROXY_HTTP_PORT), (Integer)nginxPort); assertEquals(newNginx.getAttribute(NginxController.ROOT_URL), rootUrl); assertEquals(newNginx.getAttribute(NginxController.PROXY_HTTP_PORT), origNginx.getAttribute(NginxController.PROXY_HTTP_PORT)); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/software/webapp/src/test/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java b/software/webapp/src/test/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java index d5d960b..df486aa 100644 --- a/software/webapp/src/test/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java +++ b/software/webapp/src/test/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java @@ -317,6 +317,6 @@ public class ControlledDynamicWebAppClusterTest { Entities.unmanage(controller); cluster.stop(); - EntityTestUtils.assertAttributeEquals(cluster, ControlledDynamicWebAppCluster.SERVICE_STATE, Lifecycle.STOPPED); + EntityTestUtils.assertAttributeEquals(cluster, ControlledDynamicWebAppCluster.SERVICE_STATE_ACTUAL, Lifecycle.STOPPED); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/usage/rest-server/src/main/java/brooklyn/rest/transform/ApplicationTransformer.java ---------------------------------------------------------------------- diff --git a/usage/rest-server/src/main/java/brooklyn/rest/transform/ApplicationTransformer.java b/usage/rest-server/src/main/java/brooklyn/rest/transform/ApplicationTransformer.java index 7067898..88e8da4 100644 --- a/usage/rest-server/src/main/java/brooklyn/rest/transform/ApplicationTransformer.java +++ b/usage/rest-server/src/main/java/brooklyn/rest/transform/ApplicationTransformer.java @@ -57,7 +57,7 @@ public class ApplicationTransformer { public static Status statusFromApplication(Application application) { if (application == null) return UNKNOWN; - Lifecycle state = application.getAttribute(Attributes.SERVICE_STATE); + Lifecycle state = application.getAttribute(Attributes.SERVICE_STATE_ACTUAL); if (state != null) return statusFromLifecycle(state); Boolean up = application.getAttribute(Startable.SERVICE_UP); if (up != null && up.booleanValue()) return RUNNING; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/97eed6bd/utils/common/src/main/java/brooklyn/util/guava/Functionals.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/guava/Functionals.java b/utils/common/src/main/java/brooklyn/util/guava/Functionals.java index a93c551..ef66ded 100644 --- a/utils/common/src/main/java/brooklyn/util/guava/Functionals.java +++ b/utils/common/src/main/java/brooklyn/util/guava/Functionals.java @@ -23,6 +23,7 @@ import brooklyn.util.guava.IfFunctions.IfFunctionBuilderApplyingFirst; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Predicate; +import com.google.common.base.Supplier; public class Functionals { @@ -80,4 +81,34 @@ public class Functionals { } } + /** like guava {@link Functions#forSupplier(Supplier)} but parametrises the input generic type */ + public static <I,O> Function<I,O> function(final Supplier<O> supplier) { + class SupplierAsFunction implements Function<I,O> { + @Override public O apply(I input) { + return supplier.get(); + } + } + return new SupplierAsFunction(); + } + + public static <I> Function<I,Void> function(final Runnable runnable) { + class RunnableAsFunction implements Function<I,Void> { + @Override public Void apply(I input) { + runnable.run(); + return null; + } + } + return new RunnableAsFunction(); + } + + public static Runnable runnable(final Supplier<?> supplier) { + class SupplierAsRunnable implements Runnable { + @Override + public void run() { + supplier.get(); + } + } + return new SupplierAsRunnable(); + } + }
