blob: 781cb0ca2510f044de380bd12eaa5ee0baa4ead2 [file] [log] [blame]
/*
* 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.apache.brooklyn.entity.group;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.entity.Group;
import org.apache.brooklyn.api.entity.ImplementedBy;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.sensor.AttributeSensor;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.annotation.Effector;
import org.apache.brooklyn.core.annotation.EffectorParam;
import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.core.effector.MethodEffector;
import org.apache.brooklyn.core.entity.Attributes;
import org.apache.brooklyn.core.entity.factory.EntityFactory;
import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
import org.apache.brooklyn.core.entity.trait.MemberReplaceable;
import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
import org.apache.brooklyn.core.sensor.BasicNotificationSensor;
import org.apache.brooklyn.core.sensor.Sensors;
import org.apache.brooklyn.entity.group.zoneaware.BalancingNodePlacementStrategy;
import org.apache.brooklyn.entity.group.zoneaware.ProportionalZoneFailureDetector;
import org.apache.brooklyn.util.core.flags.SetFromFlag;
import org.apache.brooklyn.util.time.Duration;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import com.google.common.reflect.TypeToken;
/**
* A {@link Cluster} of entities that can dynamically increase or decrease the number of members.
* <p>
* When quarantine is enabled:
* <ul>
* <li>The cluster will have a child entity named <em>quarantine</em>, which is a {@link Group}
* for nodes that failed to start correctly.
* <li>The cluster's other children will be all nodes in the cluster (that have not been
* unmanaged/deleted).
* <li>The cluster's members will be all live nodes in the cluster.
* <li>The <em>quarantine</em> group's members will be any problem nodes (all nodes that failed
* to start correctly)
* </ul>
* When quarantine is disabled, the cluster will not have a <em>quarantine</em> child. Nodes that
* fail to start will be removed from the cluster (i.e. stopped and deleted).
* <p>
* Advanced users will wish to examine the configuration for the {@link NodePlacementStrategy} and
* {@link ZoneFailureDetector} interfaces and their implementations, which are used here to control
* the placement of nodes in particular availability zones and locations when the cluster is resized.
*
* @see DynamicGroup
* @see DynamicFabric
*/
// TODO document use of advanced availability zone configuration and features
@ImplementedBy(DynamicClusterImpl.class)
@SuppressWarnings("serial")
public interface DynamicCluster extends AbstractGroup, Cluster, MemberReplaceable {
@Beta
interface NodePlacementStrategy {
List<Location> locationsForAdditions(Multimap<Location, Entity> currentMembers, Collection<? extends Location> locs, int numToAdd);
List<Entity> entitiesToRemove(Multimap<Location, Entity> currentMembers, int numToRemove);
}
@Beta
interface ZoneFailureDetector {
// TODO Would like to add entity-down reporting
// TODO Should we push any of this into the AvailabilityZoneExtension, rather than on the dynamic cluster?
void onStartupSuccess(Location loc, Entity entity);
void onStartupFailure(Location loc, Entity entity, Throwable cause);
boolean hasFailed(Location loc);
}
MethodEffector<Collection<Entity>> RESIZE_BY_DELTA = new MethodEffector<Collection<Entity>>(DynamicCluster.class, "resizeByDelta");
@SetFromFlag("quarantineFailedEntities")
ConfigKey<Boolean> QUARANTINE_FAILED_ENTITIES = ConfigKeys.newBooleanConfigKey(
"dynamiccluster.quarantineFailedEntities", "If true, will quarantine entities that fail to start; if false, will get rid of them (i.e. delete them)", true);
@SetFromFlag("quarantineFilter")
ConfigKey<Predicate<? super Throwable>> QUARANTINE_FILTER = ConfigKeys.newConfigKey(
new TypeToken<Predicate<? super Throwable>>() {},
"dynamiccluster.quarantineFilter",
"Quarantine the failed nodes that pass this filter (given the exception thrown by the node). "
+ "Default is those that did not fail with NoMachinesAvailableException "
+ "(Config ignored if quarantineFailedEntities is false)",
null);
AttributeSensor<Lifecycle> SERVICE_STATE_ACTUAL = Attributes.SERVICE_STATE_ACTUAL;
BasicNotificationSensor<Entity> ENTITY_QUARANTINED = new BasicNotificationSensor<Entity>(Entity.class, "dynamiccluster.entityQuarantined", "Entity failed to start, and has been quarantined");
AttributeSensor<QuarantineGroup> QUARANTINE_GROUP = Sensors.newSensor(QuarantineGroup.class, "dynamiccluster.quarantineGroup", "Group of quarantined entities that failed to start");
@SetFromFlag("initialQuorumSize")
ConfigKey<Integer> INITIAL_QUORUM_SIZE = ConfigKeys.newIntegerConfigKey(
"cluster.initial.quorumSize",
"Initial cluster quorum size - number of initial nodes that must have been successfully started to report success (if < 0, then use value of INITIAL_SIZE)",
-1);
@SetFromFlag("memberSpec")
ConfigKey<EntitySpec<?>> MEMBER_SPEC = ConfigKeys.newConfigKey(
new TypeToken<EntitySpec<?>>() { },
"dynamiccluster.memberspec", "entity spec for creating new cluster members", null);
@SetFromFlag("firstMemberSpec")
ConfigKey<EntitySpec<?>> FIRST_MEMBER_SPEC = ConfigKeys.newConfigKey(
new TypeToken<EntitySpec<?>>() { },
"dynamiccluster.firstmemberspec", "entity spec for creating new cluster members, used for the very first member if different", null);
/** @deprecated since 0.7.0; use {@link #MEMBER_SPEC} instead. */
@SuppressWarnings("rawtypes")
@Deprecated
@SetFromFlag("factory")
ConfigKey<EntityFactory> FACTORY = ConfigKeys.newConfigKey(
EntityFactory.class, "dynamiccluster.factory", "factory for creating new cluster members", null);
@SetFromFlag("removalStrategy")
ConfigKey<Function<Collection<Entity>, Entity>> REMOVAL_STRATEGY = ConfigKeys.newConfigKey(
new TypeToken<Function<Collection<Entity>, Entity>>() {},
"dynamiccluster.removalstrategy", "strategy for deciding what to remove when down-sizing", null);
@SuppressWarnings("rawtypes")
@SetFromFlag("customChildFlags")
ConfigKey<Map> CUSTOM_CHILD_FLAGS = ConfigKeys.newConfigKey(
Map.class, "dynamiccluster.customChildFlags", "Additional flags to be passed to children when they are being created", ImmutableMap.of());
@SetFromFlag("enableAvailabilityZones")
ConfigKey<Boolean> ENABLE_AVAILABILITY_ZONES = ConfigKeys.newBooleanConfigKey(
"dynamiccluster.zone.enable", "Whether to use availability zones, or just deploy everything into the generic location", false);
@SetFromFlag("zoneFailureDetector")
ConfigKey<ZoneFailureDetector> ZONE_FAILURE_DETECTOR = ConfigKeys.newConfigKey(
ZoneFailureDetector.class, "dynamiccluster.zone.failureDetector", "Zone failure detector", new ProportionalZoneFailureDetector(2, Duration.ONE_HOUR, 0.9));
@SetFromFlag("zonePlacementStrategy")
ConfigKey<NodePlacementStrategy> ZONE_PLACEMENT_STRATEGY = ConfigKeys.newConfigKey(
NodePlacementStrategy.class, "dynamiccluster.zone.placementStrategy", "Node placement strategy", new BalancingNodePlacementStrategy());
@SetFromFlag("availabilityZoneNames")
ConfigKey<Collection<String>> AVAILABILITY_ZONE_NAMES = ConfigKeys.newConfigKey(
new TypeToken<Collection<String>>() {},
"dynamiccluster.availabilityZones", "availability zones to use (if non-null, overrides other configuration)", null);
@SetFromFlag("numAvailabilityZones")
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");
AttributeSensor<Set<Location>> FAILED_SUB_LOCATIONS = new BasicAttributeSensor<Set<Location>>(
new TypeToken<Set<Location>>() {},
"dynamiccluster.failedSubLocations", "Sub locations that seem to have failed");
AttributeSensor<Boolean> CLUSTER_MEMBER = Sensors.newBooleanSensor(
"cluster.member", "Set on an entity if it is a member of a cluster");
AttributeSensor<Entity> CLUSTER = Sensors.newSensor(Entity.class,
"cluster.entity", "The cluster an entity is a member of");
AttributeSensor<Boolean> CLUSTER_ONE_AND_ALL_MEMBERS_UP = Sensors.newBooleanSensor(
"cluster.one_and_all.members.up", "True cluster is running, there is on member, and all members are service.isUp");
/**
* Changes the cluster size by the given number.
*
* @param delta number of nodes to add or remove
* @return successfully added or removed nodes
* @see #grow(int)
*/
@Effector(description="Changes the size of the cluster.")
Collection<Entity> resizeByDelta(@EffectorParam(name="delta", description="The change in number of nodes") int delta);
void setRemovalStrategy(Function<Collection<Entity>, Entity> val);
void setZonePlacementStrategy(NodePlacementStrategy val);
void setZoneFailureDetector(ZoneFailureDetector val);
void setMemberSpec(EntitySpec<?> memberSpec);
/** @deprecated since 0.7.0; use {@link #setMemberSpec(EntitySpec)} */
@Deprecated
void setFactory(EntityFactory<?> factory);
Entity addNode(Location loc, Map<?,?> extraFlags);
}