Merge branch 'develop' into feature/SLIDER-82-pass-3.1
# Conflicts:
# slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
# slider-core/src/test/groovy/org/apache/slider/client/TestClientBadArgs.groovy
diff --git a/slider-assembly/src/conf/slider-client.xml b/slider-assembly/src/conf/slider-client.xml
index 3a42bee..9c2e76d 100644
--- a/slider-assembly/src/conf/slider-client.xml
+++ b/slider-assembly/src/conf/slider-client.xml
@@ -22,14 +22,6 @@
-->
<configuration>
- <!--
- The recommended approach is to configure slider-env.sh and set HADOOP_CONF_DIR.
- Otherwise, appropriate configurations from hdfs-site, yarn-site, can be dropped in this file
- for Slider client to work. The following list is not an exhaustive list but the minimal config
- needed to interact with a non-secure cluster.
- -->
-
- <!--
<property>
<name>slider.client.resource.origin</name>
<value>conf/slider-client.xml</value>
@@ -37,14 +29,41 @@
</property>
<property>
- <name>yarn.log-aggregation-enable</name>
- <value>true</value>
+ <name>slider.security.protocol.acl</name>
+ <value>*</value>
+ <description>When security is enabled, set appropriate acl. Default value means allow everyone.</description>
</property>
<property>
- <name>slider.security.protocol.acl</name>
- <value>*</value>
- <description>When security is enabled, set appropriate acl. Default value means allow everyone.</description>
+ <name>slider.yarn.queue</name>
+ <value/>
+ <description>the name of the YARN queue to use.</description>
+ </property>
+
+ <property>
+ <name>slider.yarn.queue.priority</name>
+ <value>1</value>
+ <description>the priority of the application.</description>
+ </property>
+
+ <property>
+ <name>slider.am.login.keytab.required</name>
+ <value>false</value>
+ <description>Declare that a keytab must be provided.</description>
+ </property>
+
+ <!--
+ The recommended approach is to configure slider-env.sh and set HADOOP_CONF_DIR.
+ Otherwise, appropriate configurations from hdfs-site, yarn-site, can be dropped in this file
+ for Slider client to work. The following list is not an exhaustive list but the minimal config
+ needed to interact with a non-secure cluster.
+ -->
+
+ <!--
+
+ <property>
+ <name>yarn.log-aggregation-enable</name>
+ <value>true</value>
</property>
<property>
diff --git a/slider-core/src/main/java/org/apache/slider/api/ClusterDescription.java b/slider-core/src/main/java/org/apache/slider/api/ClusterDescription.java
index 025bd32..8358491 100644
--- a/slider-core/src/main/java/org/apache/slider/api/ClusterDescription.java
+++ b/slider-core/src/main/java/org/apache/slider/api/ClusterDescription.java
@@ -65,6 +65,12 @@
* As a wire format it is less efficient in both xfer and ser/deser than
* a binary format, but by having one unified format for wire and persistence,
* the code paths are simplified.
+ *
+ * This was the original single-file specification/model used in the Hoya
+ * precursor to Slider. Its now retained primarily as a way to publish
+ * the current state of the application, or at least a fraction thereof ...
+ * the larger set of information from the REST API is beyond the scope of
+ * this structure.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
@@ -165,41 +171,35 @@
* cluster-specific options -to control both
* the Slider AM and the application that it deploys
*/
- public Map<String, String> options =
- new HashMap<String, String>();
+ public Map<String, String> options = new HashMap<>();
/**
* cluster information
* This is only valid when querying the cluster status.
*/
- public Map<String, String> info =
- new HashMap<String, String>();
+ public Map<String, String> info = new HashMap<>();
/**
* Statistics. This is only relevant when querying the cluster status
*/
- public Map<String, Map<String, Integer>> statistics =
- new HashMap<String, Map<String, Integer>>();
+ public Map<String, Map<String, Integer>> statistics = new HashMap<>();
/**
* Instances: role->count
*/
- public Map<String, List<String>> instances =
- new HashMap<String, List<String>>();
+ public Map<String, List<String>> instances = new HashMap<>();
/**
* Role options,
* role -> option -> value
*/
- public Map<String, Map<String, String>> roles =
- new HashMap<String, Map<String, String>>();
+ public Map<String, Map<String, String>> roles = new HashMap<>();
/**
* List of key-value pairs to add to a client config to set up the client
*/
- public Map<String, String> clientProperties =
- new HashMap<String, String>();
+ public Map<String, String> clientProperties = new HashMap<>();
/**
* Status information
@@ -218,7 +218,6 @@
public ClusterDescription() {
}
-
@Override
public String toString() {
try {
@@ -284,8 +283,8 @@
* @param dataOutputStream an outout stream that will always be closed
* @throws IOException any failure
*/
- private void writeJsonAsBytes(DataOutputStream dataOutputStream) throws
- IOException {
+ private void writeJsonAsBytes(DataOutputStream dataOutputStream)
+ throws IOException {
try {
String json = toJsonString();
byte[] b = json.getBytes(UTF_8);
@@ -303,7 +302,7 @@
* @throws IOException IO problems
*/
public static ClusterDescription load(FileSystem fs, Path path)
- throws IOException, JsonParseException, JsonMappingException {
+ throws IOException, JsonParseException, JsonMappingException {
FileStatus status = fs.getFileStatus(path);
byte[] b = new byte[(int) status.getLen()];
FSDataInputStream dataInputStream = fs.open(path);
@@ -389,7 +388,7 @@
try {
return mapper.readValue(jsonFile, ClusterDescription.class);
} catch (IOException e) {
- log.error("Exception while parsing json file {}: {}" , jsonFile, e);
+ log.error("Exception while parsing json file {}" , jsonFile, e);
throw e;
}
}
@@ -528,20 +527,20 @@
}
String val = roleopts.get(option);
if (val == null) {
- throw new BadConfigException("Missing option '%s' in role %s ", option,
- role);
+ throw new BadConfigException("Missing option '%s' in role %s ", option, role);
}
return val;
}
- /**
+
+ /**
* Get a mandatory integer role option
* @param role role to get from
* @param option option name
* @return resolved value
* @throws BadConfigException if the option is not defined
*/
- public int getMandatoryRoleOptInt(String role, String option) throws
- BadConfigException {
+ public int getMandatoryRoleOptInt(String role, String option)
+ throws BadConfigException {
getMandatoryRoleOpt(role, option);
return getRoleOptInt(role, option, 0);
}
@@ -564,7 +563,7 @@
public Map<String, String> getOrAddRole(String role) {
Map<String, String> map = getRole(role);
if (map == null) {
- map = new HashMap<String, String>();
+ map = new HashMap<>();
}
roles.put(role, map);
return map;
@@ -575,7 +574,7 @@
*/
@JsonIgnore
public Set<String> getRoleNames() {
- return new HashSet<String>(roles.keySet());
+ return new HashSet<>(roles.keySet());
}
/**
diff --git a/slider-core/src/main/java/org/apache/slider/api/ClusterDescriptionOperations.java b/slider-core/src/main/java/org/apache/slider/api/ClusterDescriptionOperations.java
index 21ece2b..5b95414 100644
--- a/slider-core/src/main/java/org/apache/slider/api/ClusterDescriptionOperations.java
+++ b/slider-core/src/main/java/org/apache/slider/api/ClusterDescriptionOperations.java
@@ -80,8 +80,7 @@
}
private static void mergeInComponentMap(ClusterDescription cd,
- ConfTree confTree
- ) {
+ ConfTree confTree) {
Map<String, Map<String, String>> components = confTree.components;
for (Map.Entry<String, Map<String, String>> compEntry : components.entrySet()) {
diff --git a/slider-core/src/main/java/org/apache/slider/api/ClusterNode.java b/slider-core/src/main/java/org/apache/slider/api/ClusterNode.java
index 2608cd7..d255db0 100644
--- a/slider-core/src/main/java/org/apache/slider/api/ClusterNode.java
+++ b/slider-core/src/main/java/org/apache/slider/api/ClusterNode.java
@@ -38,11 +38,11 @@
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL )
public final class ClusterNode implements Cloneable {
protected static final Logger
- LOG = LoggerFactory.getLogger(ClusterDescription.class);
+ LOG = LoggerFactory.getLogger(ClusterNode.class);
@JsonIgnore
public ContainerId containerId;
-
+
/**
* server name
*/
@@ -67,8 +67,7 @@
public boolean released;
public String host;
public String hostUrl;
-
-
+
/**
* state from {@link ClusterDescription}
*/
@@ -165,7 +164,7 @@
try {
return mapper.readValue(json, ClusterNode.class);
} catch (IOException e) {
- LOG.error("Exception while parsing json : " + e + "\n" + json, e);
+ LOG.error("Exception while parsing json : {}\n{}", e , json, e);
throw e;
}
}
diff --git a/slider-core/src/main/java/org/apache/slider/api/RoleKeys.java b/slider-core/src/main/java/org/apache/slider/api/RoleKeys.java
index 4512354..eda01ad 100644
--- a/slider-core/src/main/java/org/apache/slider/api/RoleKeys.java
+++ b/slider-core/src/main/java/org/apache/slider/api/RoleKeys.java
@@ -65,6 +65,11 @@
String ROLE_PREEMPTED_INSTANCES = "role.failed.preempted.instances";
/**
+ * Number of pending anti-affine instances: {@value}
+ */
+ String ROLE_PENDING_AA_INSTANCES = "role.pending.aa.instances";
+
+ /**
* Status report: number currently being released: {@value}
*/
String ROLE_FAILED_STARTING_INSTANCES = "role.failed.starting.instances";
@@ -98,19 +103,4 @@
*/
String ENV_PREFIX = "env.";
-
- /**
- * Default no. of cores in the AM {@value}
- */
- int DEFAULT_AM_V_CORES = 1;
-
- /**
- * The default memory of the AM: {@value}
- */
- int DEFAULT_AM_MEMORY = 1024;
-
- /**
- * The default heap of the AM: {@value}
- */
- String DEFAULT_AM_HEAP = "512M";
}
diff --git a/slider-core/src/main/java/org/apache/slider/api/SliderApplicationApi.java b/slider-core/src/main/java/org/apache/slider/api/SliderApplicationApi.java
index 3668c66..d21785f 100644
--- a/slider-core/src/main/java/org/apache/slider/api/SliderApplicationApi.java
+++ b/slider-core/src/main/java/org/apache/slider/api/SliderApplicationApi.java
@@ -22,6 +22,7 @@
import org.apache.slider.api.types.ComponentInformation;
import org.apache.slider.api.types.ContainerInformation;
import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
import org.apache.slider.api.types.PingInformation;
import org.apache.slider.core.conf.AggregateConf;
import org.apache.slider.core.conf.ConfTree;
@@ -37,7 +38,7 @@
/**
* Get the aggregate desired model
* @return the aggregate configuration of what was asked for
- * —before resolution has taken place
+ * -before resolution has taken place
* @throws IOException on any failure
*/
AggregateConf getDesiredModel() throws IOException;
@@ -45,7 +46,7 @@
/**
* Get the desired application configuration
* @return the application configuration asked for
- * —before resolution has taken place
+ * -before resolution has taken place
* @throws IOException on any failure
*/
ConfTreeOperations getDesiredAppconf() throws IOException;
@@ -53,7 +54,7 @@
/**
* Get the desired YARN resources
* @return the resources asked for
- * —before resolution has taken place
+ * -before resolution has taken place
* @throws IOException on any failure
*/
ConfTreeOperations getDesiredResources() throws IOException;
@@ -69,7 +70,7 @@
/**
* Get the aggregate resolved model
* @return the aggregate configuration of what was asked for
- * —after resolution has taken place
+ * -after resolution has taken place
* @throws IOException on any failure
*/
AggregateConf getResolvedModel() throws IOException;
@@ -77,7 +78,7 @@
/**
* Get the resolved application configuration
* @return the application configuration asked for
- * —after resolution has taken place
+ * -after resolution has taken place
* @throws IOException on any failure
*/
ConfTreeOperations getResolvedAppconf() throws IOException;
@@ -85,7 +86,7 @@
/**
* Get the resolved YARN resources
* @return the resources asked for
- * —after resolution has taken place
+ * -after resolution has taken place
* @throws IOException on any failure
*/
ConfTreeOperations getResolvedResources() throws IOException;
@@ -126,13 +127,13 @@
* @throws IOException on any failure
*/
ComponentInformation getComponent(String componentName) throws IOException;
-
+
/**
* List all nodes into a map of [name:info]
- * @return a possibly empty map of nodes
+ * @return a possibly empty list of nodes
* @throws IOException on any failure
*/
- Map<String, NodeInformation> getLiveNodes() throws IOException;
+ NodeInformationList getLiveNodes() throws IOException;
/**
* Get information about a node
diff --git a/slider-core/src/main/java/org/apache/slider/api/proto/Messages.java b/slider-core/src/main/java/org/apache/slider/api/proto/Messages.java
index 569660d..373d64d 100644
--- a/slider-core/src/main/java/org/apache/slider/api/proto/Messages.java
+++ b/slider-core/src/main/java/org/apache/slider/api/proto/Messages.java
@@ -15110,6 +15110,16 @@
* <code>optional int32 pendingAntiAffineRequestCount = 18;</code>
*/
int getPendingAntiAffineRequestCount();
+
+ // optional bool isAARequestOutstanding = 19;
+ /**
+ * <code>optional bool isAARequestOutstanding = 19;</code>
+ */
+ boolean hasIsAARequestOutstanding();
+ /**
+ * <code>optional bool isAARequestOutstanding = 19;</code>
+ */
+ boolean getIsAARequestOutstanding();
}
/**
* Protobuf type {@code org.apache.slider.api.ComponentInformationProto}
@@ -15260,6 +15270,11 @@
pendingAntiAffineRequestCount_ = input.readInt32();
break;
}
+ case 152: {
+ bitField0_ |= 0x00020000;
+ isAARequestOutstanding_ = input.readBool();
+ break;
+ }
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -15659,6 +15674,22 @@
return pendingAntiAffineRequestCount_;
}
+ // optional bool isAARequestOutstanding = 19;
+ public static final int ISAAREQUESTOUTSTANDING_FIELD_NUMBER = 19;
+ private boolean isAARequestOutstanding_;
+ /**
+ * <code>optional bool isAARequestOutstanding = 19;</code>
+ */
+ public boolean hasIsAARequestOutstanding() {
+ return ((bitField0_ & 0x00020000) == 0x00020000);
+ }
+ /**
+ * <code>optional bool isAARequestOutstanding = 19;</code>
+ */
+ public boolean getIsAARequestOutstanding() {
+ return isAARequestOutstanding_;
+ }
+
private void initFields() {
name_ = "";
priority_ = 0;
@@ -15678,6 +15709,7 @@
nodeFailed_ = 0;
preempted_ = 0;
pendingAntiAffineRequestCount_ = 0;
+ isAARequestOutstanding_ = false;
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@@ -15745,6 +15777,9 @@
if (((bitField0_ & 0x00010000) == 0x00010000)) {
output.writeInt32(18, pendingAntiAffineRequestCount_);
}
+ if (((bitField0_ & 0x00020000) == 0x00020000)) {
+ output.writeBool(19, isAARequestOutstanding_);
+ }
getUnknownFields().writeTo(output);
}
@@ -15831,6 +15866,10 @@
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(18, pendingAntiAffineRequestCount_);
}
+ if (((bitField0_ & 0x00020000) == 0x00020000)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBoolSize(19, isAARequestOutstanding_);
+ }
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@@ -15941,6 +15980,11 @@
result = result && (getPendingAntiAffineRequestCount()
== other.getPendingAntiAffineRequestCount());
}
+ result = result && (hasIsAARequestOutstanding() == other.hasIsAARequestOutstanding());
+ if (hasIsAARequestOutstanding()) {
+ result = result && (getIsAARequestOutstanding()
+ == other.getIsAARequestOutstanding());
+ }
result = result &&
getUnknownFields().equals(other.getUnknownFields());
return result;
@@ -16026,6 +16070,10 @@
hash = (37 * hash) + PENDINGANTIAFFINEREQUESTCOUNT_FIELD_NUMBER;
hash = (53 * hash) + getPendingAntiAffineRequestCount();
}
+ if (hasIsAARequestOutstanding()) {
+ hash = (37 * hash) + ISAAREQUESTOUTSTANDING_FIELD_NUMBER;
+ hash = (53 * hash) + hashBoolean(getIsAARequestOutstanding());
+ }
hash = (29 * hash) + getUnknownFields().hashCode();
memoizedHashCode = hash;
return hash;
@@ -16176,6 +16224,8 @@
bitField0_ = (bitField0_ & ~0x00010000);
pendingAntiAffineRequestCount_ = 0;
bitField0_ = (bitField0_ & ~0x00020000);
+ isAARequestOutstanding_ = false;
+ bitField0_ = (bitField0_ & ~0x00040000);
return this;
}
@@ -16278,6 +16328,10 @@
to_bitField0_ |= 0x00010000;
}
result.pendingAntiAffineRequestCount_ = pendingAntiAffineRequestCount_;
+ if (((from_bitField0_ & 0x00040000) == 0x00040000)) {
+ to_bitField0_ |= 0x00020000;
+ }
+ result.isAARequestOutstanding_ = isAARequestOutstanding_;
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@@ -16359,6 +16413,9 @@
if (other.hasPendingAntiAffineRequestCount()) {
setPendingAntiAffineRequestCount(other.getPendingAntiAffineRequestCount());
}
+ if (other.hasIsAARequestOutstanding()) {
+ setIsAARequestOutstanding(other.getIsAARequestOutstanding());
+ }
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@@ -17122,6 +17179,39 @@
return this;
}
+ // optional bool isAARequestOutstanding = 19;
+ private boolean isAARequestOutstanding_ ;
+ /**
+ * <code>optional bool isAARequestOutstanding = 19;</code>
+ */
+ public boolean hasIsAARequestOutstanding() {
+ return ((bitField0_ & 0x00040000) == 0x00040000);
+ }
+ /**
+ * <code>optional bool isAARequestOutstanding = 19;</code>
+ */
+ public boolean getIsAARequestOutstanding() {
+ return isAARequestOutstanding_;
+ }
+ /**
+ * <code>optional bool isAARequestOutstanding = 19;</code>
+ */
+ public Builder setIsAARequestOutstanding(boolean value) {
+ bitField0_ |= 0x00040000;
+ isAARequestOutstanding_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional bool isAARequestOutstanding = 19;</code>
+ */
+ public Builder clearIsAARequestOutstanding() {
+ bitField0_ = (bitField0_ & ~0x00040000);
+ isAARequestOutstanding_ = false;
+ onChanged();
+ return this;
+ }
+
// @@protoc_insertion_point(builder_scope:org.apache.slider.api.ComponentInformationProto)
}
@@ -20324,6 +20414,21 @@
* <code>required int64 lastUsed = 10;</code>
*/
long getLastUsed();
+
+ // required string name = 11;
+ /**
+ * <code>required string name = 11;</code>
+ */
+ boolean hasName();
+ /**
+ * <code>required string name = 11;</code>
+ */
+ java.lang.String getName();
+ /**
+ * <code>required string name = 11;</code>
+ */
+ com.google.protobuf.ByteString
+ getNameBytes();
}
/**
* Protobuf type {@code org.apache.slider.api.NodeEntryInformationProto}
@@ -20426,6 +20531,11 @@
lastUsed_ = input.readInt64();
break;
}
+ case 90: {
+ bitField0_ |= 0x00000400;
+ name_ = input.readBytes();
+ break;
+ }
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -20626,6 +20736,49 @@
return lastUsed_;
}
+ // required string name = 11;
+ public static final int NAME_FIELD_NUMBER = 11;
+ private java.lang.Object name_;
+ /**
+ * <code>required string name = 11;</code>
+ */
+ public boolean hasName() {
+ return ((bitField0_ & 0x00000400) == 0x00000400);
+ }
+ /**
+ * <code>required string name = 11;</code>
+ */
+ public java.lang.String getName() {
+ java.lang.Object ref = name_;
+ if (ref instanceof java.lang.String) {
+ return (java.lang.String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ name_ = s;
+ }
+ return s;
+ }
+ }
+ /**
+ * <code>required string name = 11;</code>
+ */
+ public com.google.protobuf.ByteString
+ getNameBytes() {
+ java.lang.Object ref = name_;
+ if (ref instanceof java.lang.String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ name_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
private void initFields() {
priority_ = 0;
requested_ = 0;
@@ -20637,6 +20790,7 @@
live_ = 0;
releasing_ = 0;
lastUsed_ = 0L;
+ name_ = "";
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@@ -20683,6 +20837,10 @@
memoizedIsInitialized = 0;
return false;
}
+ if (!hasName()) {
+ memoizedIsInitialized = 0;
+ return false;
+ }
memoizedIsInitialized = 1;
return true;
}
@@ -20720,6 +20878,9 @@
if (((bitField0_ & 0x00000200) == 0x00000200)) {
output.writeInt64(10, lastUsed_);
}
+ if (((bitField0_ & 0x00000400) == 0x00000400)) {
+ output.writeBytes(11, getNameBytes());
+ }
getUnknownFields().writeTo(output);
}
@@ -20769,6 +20930,10 @@
size += com.google.protobuf.CodedOutputStream
.computeInt64Size(10, lastUsed_);
}
+ if (((bitField0_ & 0x00000400) == 0x00000400)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(11, getNameBytes());
+ }
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@@ -20842,6 +21007,11 @@
result = result && (getLastUsed()
== other.getLastUsed());
}
+ result = result && (hasName() == other.hasName());
+ if (hasName()) {
+ result = result && getName()
+ .equals(other.getName());
+ }
result = result &&
getUnknownFields().equals(other.getUnknownFields());
return result;
@@ -20895,6 +21065,10 @@
hash = (37 * hash) + LASTUSED_FIELD_NUMBER;
hash = (53 * hash) + hashLong(getLastUsed());
}
+ if (hasName()) {
+ hash = (37 * hash) + NAME_FIELD_NUMBER;
+ hash = (53 * hash) + getName().hashCode();
+ }
hash = (29 * hash) + getUnknownFields().hashCode();
memoizedHashCode = hash;
return hash;
@@ -21024,6 +21198,8 @@
bitField0_ = (bitField0_ & ~0x00000100);
lastUsed_ = 0L;
bitField0_ = (bitField0_ & ~0x00000200);
+ name_ = "";
+ bitField0_ = (bitField0_ & ~0x00000400);
return this;
}
@@ -21092,6 +21268,10 @@
to_bitField0_ |= 0x00000200;
}
result.lastUsed_ = lastUsed_;
+ if (((from_bitField0_ & 0x00000400) == 0x00000400)) {
+ to_bitField0_ |= 0x00000400;
+ }
+ result.name_ = name_;
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@@ -21138,6 +21318,11 @@
if (other.hasLastUsed()) {
setLastUsed(other.getLastUsed());
}
+ if (other.hasName()) {
+ bitField0_ |= 0x00000400;
+ name_ = other.name_;
+ onChanged();
+ }
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@@ -21183,6 +21368,10 @@
return false;
}
+ if (!hasName()) {
+
+ return false;
+ }
return true;
}
@@ -21535,6 +21724,80 @@
return this;
}
+ // required string name = 11;
+ private java.lang.Object name_ = "";
+ /**
+ * <code>required string name = 11;</code>
+ */
+ public boolean hasName() {
+ return ((bitField0_ & 0x00000400) == 0x00000400);
+ }
+ /**
+ * <code>required string name = 11;</code>
+ */
+ public java.lang.String getName() {
+ java.lang.Object ref = name_;
+ if (!(ref instanceof java.lang.String)) {
+ java.lang.String s = ((com.google.protobuf.ByteString) ref)
+ .toStringUtf8();
+ name_ = s;
+ return s;
+ } else {
+ return (java.lang.String) ref;
+ }
+ }
+ /**
+ * <code>required string name = 11;</code>
+ */
+ public com.google.protobuf.ByteString
+ getNameBytes() {
+ java.lang.Object ref = name_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ name_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+ /**
+ * <code>required string name = 11;</code>
+ */
+ public Builder setName(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000400;
+ name_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>required string name = 11;</code>
+ */
+ public Builder clearName() {
+ bitField0_ = (bitField0_ & ~0x00000400);
+ name_ = getDefaultInstance().getName();
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>required string name = 11;</code>
+ */
+ public Builder setNameBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000400;
+ name_ = value;
+ onChanged();
+ return this;
+ }
+
// @@protoc_insertion_point(builder_scope:org.apache.slider.api.NodeEntryInformationProto)
}
@@ -32299,47 +32562,27 @@
public interface GetLiveNodesResponseProtoOrBuilder
extends com.google.protobuf.MessageOrBuilder {
- // repeated string names = 1;
+ // repeated .org.apache.slider.api.NodeInformationProto nodes = 1;
/**
- * <code>repeated string names = 1;</code>
- */
- java.util.List<java.lang.String>
- getNamesList();
- /**
- * <code>repeated string names = 1;</code>
- */
- int getNamesCount();
- /**
- * <code>repeated string names = 1;</code>
- */
- java.lang.String getNames(int index);
- /**
- * <code>repeated string names = 1;</code>
- */
- com.google.protobuf.ByteString
- getNamesBytes(int index);
-
- // repeated .org.apache.slider.api.NodeInformationProto nodes = 2;
- /**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
java.util.List<org.apache.slider.api.proto.Messages.NodeInformationProto>
getNodesList();
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
org.apache.slider.api.proto.Messages.NodeInformationProto getNodes(int index);
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
int getNodesCount();
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
java.util.List<? extends org.apache.slider.api.proto.Messages.NodeInformationProtoOrBuilder>
getNodesOrBuilderList();
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
org.apache.slider.api.proto.Messages.NodeInformationProtoOrBuilder getNodesOrBuilder(
int index);
@@ -32397,16 +32640,8 @@
}
case 10: {
if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
- names_ = new com.google.protobuf.LazyStringArrayList();
- mutable_bitField0_ |= 0x00000001;
- }
- names_.add(input.readBytes());
- break;
- }
- case 18: {
- if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
nodes_ = new java.util.ArrayList<org.apache.slider.api.proto.Messages.NodeInformationProto>();
- mutable_bitField0_ |= 0x00000002;
+ mutable_bitField0_ |= 0x00000001;
}
nodes_.add(input.readMessage(org.apache.slider.api.proto.Messages.NodeInformationProto.PARSER, extensionRegistry));
break;
@@ -32420,9 +32655,6 @@
e.getMessage()).setUnfinishedMessage(this);
} finally {
if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
- names_ = new com.google.protobuf.UnmodifiableLazyStringList(names_);
- }
- if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
nodes_ = java.util.Collections.unmodifiableList(nodes_);
}
this.unknownFields = unknownFields.build();
@@ -32456,66 +32688,36 @@
return PARSER;
}
- // repeated string names = 1;
- public static final int NAMES_FIELD_NUMBER = 1;
- private com.google.protobuf.LazyStringList names_;
- /**
- * <code>repeated string names = 1;</code>
- */
- public java.util.List<java.lang.String>
- getNamesList() {
- return names_;
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public int getNamesCount() {
- return names_.size();
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public java.lang.String getNames(int index) {
- return names_.get(index);
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public com.google.protobuf.ByteString
- getNamesBytes(int index) {
- return names_.getByteString(index);
- }
-
- // repeated .org.apache.slider.api.NodeInformationProto nodes = 2;
- public static final int NODES_FIELD_NUMBER = 2;
+ // repeated .org.apache.slider.api.NodeInformationProto nodes = 1;
+ public static final int NODES_FIELD_NUMBER = 1;
private java.util.List<org.apache.slider.api.proto.Messages.NodeInformationProto> nodes_;
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public java.util.List<org.apache.slider.api.proto.Messages.NodeInformationProto> getNodesList() {
return nodes_;
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public java.util.List<? extends org.apache.slider.api.proto.Messages.NodeInformationProtoOrBuilder>
getNodesOrBuilderList() {
return nodes_;
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public int getNodesCount() {
return nodes_.size();
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public org.apache.slider.api.proto.Messages.NodeInformationProto getNodes(int index) {
return nodes_.get(index);
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public org.apache.slider.api.proto.Messages.NodeInformationProtoOrBuilder getNodesOrBuilder(
int index) {
@@ -32523,7 +32725,6 @@
}
private void initFields() {
- names_ = com.google.protobuf.LazyStringArrayList.EMPTY;
nodes_ = java.util.Collections.emptyList();
}
private byte memoizedIsInitialized = -1;
@@ -32544,11 +32745,8 @@
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
getSerializedSize();
- for (int i = 0; i < names_.size(); i++) {
- output.writeBytes(1, names_.getByteString(i));
- }
for (int i = 0; i < nodes_.size(); i++) {
- output.writeMessage(2, nodes_.get(i));
+ output.writeMessage(1, nodes_.get(i));
}
getUnknownFields().writeTo(output);
}
@@ -32559,18 +32757,9 @@
if (size != -1) return size;
size = 0;
- {
- int dataSize = 0;
- for (int i = 0; i < names_.size(); i++) {
- dataSize += com.google.protobuf.CodedOutputStream
- .computeBytesSizeNoTag(names_.getByteString(i));
- }
- size += dataSize;
- size += 1 * getNamesList().size();
- }
for (int i = 0; i < nodes_.size(); i++) {
size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(2, nodes_.get(i));
+ .computeMessageSize(1, nodes_.get(i));
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
@@ -32595,8 +32784,6 @@
org.apache.slider.api.proto.Messages.GetLiveNodesResponseProto other = (org.apache.slider.api.proto.Messages.GetLiveNodesResponseProto) obj;
boolean result = true;
- result = result && getNamesList()
- .equals(other.getNamesList());
result = result && getNodesList()
.equals(other.getNodesList());
result = result &&
@@ -32612,10 +32799,6 @@
}
int hash = 41;
hash = (19 * hash) + getDescriptorForType().hashCode();
- if (getNamesCount() > 0) {
- hash = (37 * hash) + NAMES_FIELD_NUMBER;
- hash = (53 * hash) + getNamesList().hashCode();
- }
if (getNodesCount() > 0) {
hash = (37 * hash) + NODES_FIELD_NUMBER;
hash = (53 * hash) + getNodesList().hashCode();
@@ -32730,11 +32913,9 @@
public Builder clear() {
super.clear();
- names_ = com.google.protobuf.LazyStringArrayList.EMPTY;
- bitField0_ = (bitField0_ & ~0x00000001);
if (nodesBuilder_ == null) {
nodes_ = java.util.Collections.emptyList();
- bitField0_ = (bitField0_ & ~0x00000002);
+ bitField0_ = (bitField0_ & ~0x00000001);
} else {
nodesBuilder_.clear();
}
@@ -32765,16 +32946,10 @@
public org.apache.slider.api.proto.Messages.GetLiveNodesResponseProto buildPartial() {
org.apache.slider.api.proto.Messages.GetLiveNodesResponseProto result = new org.apache.slider.api.proto.Messages.GetLiveNodesResponseProto(this);
int from_bitField0_ = bitField0_;
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- names_ = new com.google.protobuf.UnmodifiableLazyStringList(
- names_);
- bitField0_ = (bitField0_ & ~0x00000001);
- }
- result.names_ = names_;
if (nodesBuilder_ == null) {
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
nodes_ = java.util.Collections.unmodifiableList(nodes_);
- bitField0_ = (bitField0_ & ~0x00000002);
+ bitField0_ = (bitField0_ & ~0x00000001);
}
result.nodes_ = nodes_;
} else {
@@ -32795,21 +32970,11 @@
public Builder mergeFrom(org.apache.slider.api.proto.Messages.GetLiveNodesResponseProto other) {
if (other == org.apache.slider.api.proto.Messages.GetLiveNodesResponseProto.getDefaultInstance()) return this;
- if (!other.names_.isEmpty()) {
- if (names_.isEmpty()) {
- names_ = other.names_;
- bitField0_ = (bitField0_ & ~0x00000001);
- } else {
- ensureNamesIsMutable();
- names_.addAll(other.names_);
- }
- onChanged();
- }
if (nodesBuilder_ == null) {
if (!other.nodes_.isEmpty()) {
if (nodes_.isEmpty()) {
nodes_ = other.nodes_;
- bitField0_ = (bitField0_ & ~0x00000002);
+ bitField0_ = (bitField0_ & ~0x00000001);
} else {
ensureNodesIsMutable();
nodes_.addAll(other.nodes_);
@@ -32822,7 +32987,7 @@
nodesBuilder_.dispose();
nodesBuilder_ = null;
nodes_ = other.nodes_;
- bitField0_ = (bitField0_ & ~0x00000002);
+ bitField0_ = (bitField0_ & ~0x00000001);
nodesBuilder_ =
com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
getNodesFieldBuilder() : null;
@@ -32864,106 +33029,13 @@
}
private int bitField0_;
- // repeated string names = 1;
- private com.google.protobuf.LazyStringList names_ = com.google.protobuf.LazyStringArrayList.EMPTY;
- private void ensureNamesIsMutable() {
- if (!((bitField0_ & 0x00000001) == 0x00000001)) {
- names_ = new com.google.protobuf.LazyStringArrayList(names_);
- bitField0_ |= 0x00000001;
- }
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public java.util.List<java.lang.String>
- getNamesList() {
- return java.util.Collections.unmodifiableList(names_);
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public int getNamesCount() {
- return names_.size();
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public java.lang.String getNames(int index) {
- return names_.get(index);
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public com.google.protobuf.ByteString
- getNamesBytes(int index) {
- return names_.getByteString(index);
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public Builder setNames(
- int index, java.lang.String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- ensureNamesIsMutable();
- names_.set(index, value);
- onChanged();
- return this;
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public Builder addNames(
- java.lang.String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- ensureNamesIsMutable();
- names_.add(value);
- onChanged();
- return this;
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public Builder addAllNames(
- java.lang.Iterable<java.lang.String> values) {
- ensureNamesIsMutable();
- super.addAll(values, names_);
- onChanged();
- return this;
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public Builder clearNames() {
- names_ = com.google.protobuf.LazyStringArrayList.EMPTY;
- bitField0_ = (bitField0_ & ~0x00000001);
- onChanged();
- return this;
- }
- /**
- * <code>repeated string names = 1;</code>
- */
- public Builder addNamesBytes(
- com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- ensureNamesIsMutable();
- names_.add(value);
- onChanged();
- return this;
- }
-
- // repeated .org.apache.slider.api.NodeInformationProto nodes = 2;
+ // repeated .org.apache.slider.api.NodeInformationProto nodes = 1;
private java.util.List<org.apache.slider.api.proto.Messages.NodeInformationProto> nodes_ =
java.util.Collections.emptyList();
private void ensureNodesIsMutable() {
- if (!((bitField0_ & 0x00000002) == 0x00000002)) {
+ if (!((bitField0_ & 0x00000001) == 0x00000001)) {
nodes_ = new java.util.ArrayList<org.apache.slider.api.proto.Messages.NodeInformationProto>(nodes_);
- bitField0_ |= 0x00000002;
+ bitField0_ |= 0x00000001;
}
}
@@ -32971,7 +33043,7 @@
org.apache.slider.api.proto.Messages.NodeInformationProto, org.apache.slider.api.proto.Messages.NodeInformationProto.Builder, org.apache.slider.api.proto.Messages.NodeInformationProtoOrBuilder> nodesBuilder_;
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public java.util.List<org.apache.slider.api.proto.Messages.NodeInformationProto> getNodesList() {
if (nodesBuilder_ == null) {
@@ -32981,7 +33053,7 @@
}
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public int getNodesCount() {
if (nodesBuilder_ == null) {
@@ -32991,7 +33063,7 @@
}
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public org.apache.slider.api.proto.Messages.NodeInformationProto getNodes(int index) {
if (nodesBuilder_ == null) {
@@ -33001,7 +33073,7 @@
}
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public Builder setNodes(
int index, org.apache.slider.api.proto.Messages.NodeInformationProto value) {
@@ -33018,7 +33090,7 @@
return this;
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public Builder setNodes(
int index, org.apache.slider.api.proto.Messages.NodeInformationProto.Builder builderForValue) {
@@ -33032,7 +33104,7 @@
return this;
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public Builder addNodes(org.apache.slider.api.proto.Messages.NodeInformationProto value) {
if (nodesBuilder_ == null) {
@@ -33048,7 +33120,7 @@
return this;
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public Builder addNodes(
int index, org.apache.slider.api.proto.Messages.NodeInformationProto value) {
@@ -33065,7 +33137,7 @@
return this;
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public Builder addNodes(
org.apache.slider.api.proto.Messages.NodeInformationProto.Builder builderForValue) {
@@ -33079,7 +33151,7 @@
return this;
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public Builder addNodes(
int index, org.apache.slider.api.proto.Messages.NodeInformationProto.Builder builderForValue) {
@@ -33093,7 +33165,7 @@
return this;
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public Builder addAllNodes(
java.lang.Iterable<? extends org.apache.slider.api.proto.Messages.NodeInformationProto> values) {
@@ -33107,12 +33179,12 @@
return this;
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public Builder clearNodes() {
if (nodesBuilder_ == null) {
nodes_ = java.util.Collections.emptyList();
- bitField0_ = (bitField0_ & ~0x00000002);
+ bitField0_ = (bitField0_ & ~0x00000001);
onChanged();
} else {
nodesBuilder_.clear();
@@ -33120,7 +33192,7 @@
return this;
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public Builder removeNodes(int index) {
if (nodesBuilder_ == null) {
@@ -33133,14 +33205,14 @@
return this;
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public org.apache.slider.api.proto.Messages.NodeInformationProto.Builder getNodesBuilder(
int index) {
return getNodesFieldBuilder().getBuilder(index);
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public org.apache.slider.api.proto.Messages.NodeInformationProtoOrBuilder getNodesOrBuilder(
int index) {
@@ -33150,7 +33222,7 @@
}
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public java.util.List<? extends org.apache.slider.api.proto.Messages.NodeInformationProtoOrBuilder>
getNodesOrBuilderList() {
@@ -33161,14 +33233,14 @@
}
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public org.apache.slider.api.proto.Messages.NodeInformationProto.Builder addNodesBuilder() {
return getNodesFieldBuilder().addBuilder(
org.apache.slider.api.proto.Messages.NodeInformationProto.getDefaultInstance());
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public org.apache.slider.api.proto.Messages.NodeInformationProto.Builder addNodesBuilder(
int index) {
@@ -33176,7 +33248,7 @@
index, org.apache.slider.api.proto.Messages.NodeInformationProto.getDefaultInstance());
}
/**
- * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 2;</code>
+ * <code>repeated .org.apache.slider.api.NodeInformationProto nodes = 1;</code>
*/
public java.util.List<org.apache.slider.api.proto.Messages.NodeInformationProto.Builder>
getNodesBuilderList() {
@@ -33189,7 +33261,7 @@
nodesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
org.apache.slider.api.proto.Messages.NodeInformationProto, org.apache.slider.api.proto.Messages.NodeInformationProto.Builder, org.apache.slider.api.proto.Messages.NodeInformationProtoOrBuilder>(
nodes_,
- ((bitField0_ & 0x00000002) == 0x00000002),
+ ((bitField0_ & 0x00000001) == 0x00000001),
getParentForChildren(),
isClean());
nodes_ = null;
@@ -34023,7 +34095,7 @@
" \002(\t\022\023\n\013application\030\003 \002(\t\"`\n#Application" +
"LivenessInformationProto\022\034\n\024allRequestsS" +
"atisfied\030\001 \001(\010\022\033\n\023requestsOutstanding\030\002 " +
- "\001(\005\"\216\003\n\031ComponentInformationProto\022\014\n\004nam",
+ "\001(\005\"\256\003\n\031ComponentInformationProto\022\014\n\004nam",
"e\030\001 \001(\t\022\020\n\010priority\030\002 \001(\005\022\017\n\007desired\030\003 \001" +
"(\005\022\016\n\006actual\030\004 \001(\005\022\021\n\treleasing\030\005 \001(\005\022\021\n" +
"\trequested\030\006 \001(\005\022\016\n\006failed\030\007 \001(\005\022\017\n\007star" +
@@ -34033,54 +34105,55 @@
"(\005\022\022\n\ncontainers\030\016 \003(\t\022\026\n\016failedRecently" +
"\030\017 \001(\005\022\022\n\nnodeFailed\030\020 \001(\005\022\021\n\tpreempted\030" +
"\021 \001(\005\022%\n\035pendingAntiAffineRequestCount\030\022" +
- " \001(\005\"\210\002\n\031ContainerInformationProto\022\023\n\013co",
- "ntainerId\030\001 \001(\t\022\021\n\tcomponent\030\002 \001(\t\022\020\n\010re" +
- "leased\030\003 \001(\010\022\r\n\005state\030\004 \001(\005\022\020\n\010exitCode\030" +
- "\005 \001(\005\022\023\n\013diagnostics\030\006 \001(\t\022\022\n\ncreateTime" +
- "\030\007 \001(\003\022\021\n\tstartTime\030\010 \001(\003\022\016\n\006output\030\t \003(" +
- "\t\022\014\n\004host\030\n \001(\t\022\017\n\007hostURL\030\013 \001(\t\022\021\n\tplac" +
- "ement\030\014 \001(\t\022\022\n\nappVersion\030\r \001(\t\"N\n\024PingI" +
- "nformationProto\022\014\n\004text\030\001 \001(\t\022\014\n\004verb\030\002 " +
- "\001(\t\022\014\n\004body\030\003 \001(\t\022\014\n\004time\030\004 \001(\003\"\325\001\n\031Node" +
- "EntryInformationProto\022\020\n\010priority\030\001 \002(\005\022" +
- "\021\n\trequested\030\002 \002(\005\022\020\n\010starting\030\003 \002(\005\022\023\n\013",
- "startFailed\030\004 \002(\005\022\016\n\006failed\030\005 \002(\005\022\026\n\016fai" +
- "ledRecently\030\006 \002(\005\022\021\n\tpreempted\030\007 \002(\005\022\014\n\004" +
- "live\030\010 \002(\005\022\021\n\treleasing\030\t \002(\005\022\020\n\010lastUse" +
- "d\030\n \002(\003\"\334\001\n\024NodeInformationProto\022\020\n\010host" +
- "name\030\001 \002(\t\022\r\n\005state\030\002 \002(\t\022\023\n\013httpAddress" +
- "\030\003 \002(\t\022\020\n\010rackName\030\004 \002(\t\022\016\n\006labels\030\005 \002(\t" +
- "\022\024\n\014healthReport\030\006 \002(\t\022\023\n\013lastUpdated\030\007 " +
- "\002(\003\022A\n\007entries\030\010 \003(\01320.org.apache.slider" +
- ".api.NodeEntryInformationProto\"\026\n\024GetMod" +
- "elRequestProto\"\035\n\033GetModelDesiredRequest",
- "Proto\"$\n\"GetModelDesiredAppconfRequestPr" +
- "oto\"&\n$GetModelDesiredResourcesRequestPr" +
- "oto\"%\n#GetModelResolvedAppconfRequestPro" +
- "to\"\'\n%GetModelResolvedResourcesRequestPr" +
- "oto\"#\n!GetModelLiveResourcesRequestProto" +
- "\"\037\n\035GetLiveContainersRequestProto\"u\n\036Get" +
- "LiveContainersResponseProto\022\r\n\005names\030\001 \003" +
- "(\t\022D\n\ncontainers\030\002 \003(\01320.org.apache.slid" +
- "er.api.ContainerInformationProto\"3\n\034GetL" +
- "iveContainerRequestProto\022\023\n\013containerId\030",
- "\001 \002(\t\"\037\n\035GetLiveComponentsRequestProto\"u" +
- "\n\036GetLiveComponentsResponseProto\022\r\n\005name" +
- "s\030\001 \003(\t\022D\n\ncomponents\030\002 \003(\01320.org.apache" +
- ".slider.api.ComponentInformationProto\",\n" +
- "\034GetLiveComponentRequestProto\022\014\n\004name\030\001 " +
- "\002(\t\"$\n\"GetApplicationLivenessRequestProt" +
- "o\"\023\n\021EmptyPayloadProto\" \n\020WrappedJsonPro" +
- "to\022\014\n\004json\030\001 \002(\t\"h\n\037GetCertificateStoreR" +
- "equestProto\022\020\n\010hostname\030\001 \001(\t\022\023\n\013request" +
- "erId\030\002 \002(\t\022\020\n\010password\030\003 \002(\t\022\014\n\004type\030\004 \002",
- "(\t\"1\n GetCertificateStoreResponseProto\022\r" +
- "\n\005store\030\001 \002(\014\"\032\n\030GetLiveNodesRequestProt" +
- "o\"f\n\031GetLiveNodesResponseProto\022\r\n\005names\030" +
- "\001 \003(\t\022:\n\005nodes\030\002 \003(\0132+.org.apache.slider" +
- ".api.NodeInformationProto\"\'\n\027GetLiveNode" +
- "RequestProto\022\014\n\004name\030\001 \002(\tB-\n\033org.apache" +
- ".slider.api.protoB\010Messages\210\001\001\240\001\001"
+ " \001(\005\022\036\n\026isAARequestOutstanding\030\023 \001(\010\"\210\002\n",
+ "\031ContainerInformationProto\022\023\n\013containerI" +
+ "d\030\001 \001(\t\022\021\n\tcomponent\030\002 \001(\t\022\020\n\010released\030\003" +
+ " \001(\010\022\r\n\005state\030\004 \001(\005\022\020\n\010exitCode\030\005 \001(\005\022\023\n" +
+ "\013diagnostics\030\006 \001(\t\022\022\n\ncreateTime\030\007 \001(\003\022\021" +
+ "\n\tstartTime\030\010 \001(\003\022\016\n\006output\030\t \003(\t\022\014\n\004hos" +
+ "t\030\n \001(\t\022\017\n\007hostURL\030\013 \001(\t\022\021\n\tplacement\030\014 " +
+ "\001(\t\022\022\n\nappVersion\030\r \001(\t\"N\n\024PingInformati" +
+ "onProto\022\014\n\004text\030\001 \001(\t\022\014\n\004verb\030\002 \001(\t\022\014\n\004b" +
+ "ody\030\003 \001(\t\022\014\n\004time\030\004 \001(\003\"\343\001\n\031NodeEntryInf" +
+ "ormationProto\022\020\n\010priority\030\001 \002(\005\022\021\n\treque",
+ "sted\030\002 \002(\005\022\020\n\010starting\030\003 \002(\005\022\023\n\013startFai" +
+ "led\030\004 \002(\005\022\016\n\006failed\030\005 \002(\005\022\026\n\016failedRecen" +
+ "tly\030\006 \002(\005\022\021\n\tpreempted\030\007 \002(\005\022\014\n\004live\030\010 \002" +
+ "(\005\022\021\n\treleasing\030\t \002(\005\022\020\n\010lastUsed\030\n \002(\003\022" +
+ "\014\n\004name\030\013 \002(\t\"\334\001\n\024NodeInformationProto\022\020" +
+ "\n\010hostname\030\001 \002(\t\022\r\n\005state\030\002 \002(\t\022\023\n\013httpA" +
+ "ddress\030\003 \002(\t\022\020\n\010rackName\030\004 \002(\t\022\016\n\006labels" +
+ "\030\005 \002(\t\022\024\n\014healthReport\030\006 \002(\t\022\023\n\013lastUpda" +
+ "ted\030\007 \002(\003\022A\n\007entries\030\010 \003(\01320.org.apache." +
+ "slider.api.NodeEntryInformationProto\"\026\n\024",
+ "GetModelRequestProto\"\035\n\033GetModelDesiredR" +
+ "equestProto\"$\n\"GetModelDesiredAppconfReq" +
+ "uestProto\"&\n$GetModelDesiredResourcesReq" +
+ "uestProto\"%\n#GetModelResolvedAppconfRequ" +
+ "estProto\"\'\n%GetModelResolvedResourcesReq" +
+ "uestProto\"#\n!GetModelLiveResourcesReques" +
+ "tProto\"\037\n\035GetLiveContainersRequestProto\"" +
+ "u\n\036GetLiveContainersResponseProto\022\r\n\005nam" +
+ "es\030\001 \003(\t\022D\n\ncontainers\030\002 \003(\01320.org.apach" +
+ "e.slider.api.ContainerInformationProto\"3",
+ "\n\034GetLiveContainerRequestProto\022\023\n\013contai" +
+ "nerId\030\001 \002(\t\"\037\n\035GetLiveComponentsRequestP" +
+ "roto\"u\n\036GetLiveComponentsResponseProto\022\r" +
+ "\n\005names\030\001 \003(\t\022D\n\ncomponents\030\002 \003(\01320.org." +
+ "apache.slider.api.ComponentInformationPr" +
+ "oto\",\n\034GetLiveComponentRequestProto\022\014\n\004n" +
+ "ame\030\001 \002(\t\"$\n\"GetApplicationLivenessReque" +
+ "stProto\"\023\n\021EmptyPayloadProto\" \n\020WrappedJ" +
+ "sonProto\022\014\n\004json\030\001 \002(\t\"h\n\037GetCertificate" +
+ "StoreRequestProto\022\020\n\010hostname\030\001 \001(\t\022\023\n\013r",
+ "equesterId\030\002 \002(\t\022\020\n\010password\030\003 \002(\t\022\014\n\004ty" +
+ "pe\030\004 \002(\t\"1\n GetCertificateStoreResponseP" +
+ "roto\022\r\n\005store\030\001 \002(\014\"\032\n\030GetLiveNodesReque" +
+ "stProto\"W\n\031GetLiveNodesResponseProto\022:\n\005" +
+ "nodes\030\001 \003(\0132+.org.apache.slider.api.Node" +
+ "InformationProto\"\'\n\027GetLiveNodeRequestPr" +
+ "oto\022\014\n\004name\030\001 \002(\tB-\n\033org.apache.slider.a" +
+ "pi.protoB\010Messages\210\001\001\240\001\001"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -34236,7 +34309,7 @@
internal_static_org_apache_slider_api_ComponentInformationProto_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_org_apache_slider_api_ComponentInformationProto_descriptor,
- new java.lang.String[] { "Name", "Priority", "Desired", "Actual", "Releasing", "Requested", "Failed", "Started", "StartFailed", "Completed", "TotalRequested", "FailureMessage", "PlacementPolicy", "Containers", "FailedRecently", "NodeFailed", "Preempted", "PendingAntiAffineRequestCount", });
+ new java.lang.String[] { "Name", "Priority", "Desired", "Actual", "Releasing", "Requested", "Failed", "Started", "StartFailed", "Completed", "TotalRequested", "FailureMessage", "PlacementPolicy", "Containers", "FailedRecently", "NodeFailed", "Preempted", "PendingAntiAffineRequestCount", "IsAARequestOutstanding", });
internal_static_org_apache_slider_api_ContainerInformationProto_descriptor =
getDescriptor().getMessageTypes().get(25);
internal_static_org_apache_slider_api_ContainerInformationProto_fieldAccessorTable = new
@@ -34254,7 +34327,7 @@
internal_static_org_apache_slider_api_NodeEntryInformationProto_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_org_apache_slider_api_NodeEntryInformationProto_descriptor,
- new java.lang.String[] { "Priority", "Requested", "Starting", "StartFailed", "Failed", "FailedRecently", "Preempted", "Live", "Releasing", "LastUsed", });
+ new java.lang.String[] { "Priority", "Requested", "Starting", "StartFailed", "Failed", "FailedRecently", "Preempted", "Live", "Releasing", "LastUsed", "Name", });
internal_static_org_apache_slider_api_NodeInformationProto_descriptor =
getDescriptor().getMessageTypes().get(28);
internal_static_org_apache_slider_api_NodeInformationProto_fieldAccessorTable = new
@@ -34380,7 +34453,7 @@
internal_static_org_apache_slider_api_GetLiveNodesResponseProto_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_org_apache_slider_api_GetLiveNodesResponseProto_descriptor,
- new java.lang.String[] { "Names", "Nodes", });
+ new java.lang.String[] { "Nodes", });
internal_static_org_apache_slider_api_GetLiveNodeRequestProto_descriptor =
getDescriptor().getMessageTypes().get(49);
internal_static_org_apache_slider_api_GetLiveNodeRequestProto_fieldAccessorTable = new
diff --git a/slider-core/src/main/java/org/apache/slider/api/proto/RestTypeMarshalling.java b/slider-core/src/main/java/org/apache/slider/api/proto/RestTypeMarshalling.java
index 115405c..feebe1d 100644
--- a/slider-core/src/main/java/org/apache/slider/api/proto/RestTypeMarshalling.java
+++ b/slider-core/src/main/java/org/apache/slider/api/proto/RestTypeMarshalling.java
@@ -38,7 +38,10 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Class to handle marshalling of REST
@@ -84,8 +87,12 @@
if (wire.hasFailureMessage()) {
info.failureMessage = wire.getFailureMessage();
}
- info.pendingAntiAffineRequestCount = wire.getPendingAntiAffineRequestCount();
- info.pendingAntiAffineRequest = info.pendingAntiAffineRequestCount > 0;
+ if (wire.hasPendingAntiAffineRequestCount()) {
+ info.pendingAntiAffineRequestCount = wire.getPendingAntiAffineRequestCount();
+ }
+ if (wire.hasIsAARequestOutstanding()) {
+ info.isAARequestOutstanding = wire.getIsAARequestOutstanding();
+ }
return info;
}
@@ -136,6 +143,7 @@
builder.addAllContainers(info.containers);
}
builder.setPendingAntiAffineRequestCount(info.pendingAntiAffineRequestCount);
+ builder.setIsAARequestOutstanding(info.isAARequestOutstanding);
return builder.build();
}
@@ -145,33 +153,25 @@
Messages.NodeInformationProto.newBuilder();
builder.setHostname(info.hostname);
builder.setLastUpdated(info.lastUpdated);
- if (info.state != null) {
- builder.setState(info.state);
- }
- if (info.rackName != null) {
- builder.setRackName(info.rackName);
- }
- if (info.healthReport != null) {
- builder.setHealthReport(info.healthReport);
- }
- if (info.httpAddress != null) {
- builder.setHttpAddress(info.httpAddress);
- }
- if (info.labels != null) {
- builder.setLabels(info.labels);
- }
+ builder.setState(info.state != null? info.state : "unknown");
+ builder.setRackName(info.rackName != null ? info.rackName : "");
+ builder.setHealthReport(info.healthReport != null ? info.healthReport : "");
+ builder.setHttpAddress(info.httpAddress != null ? info.httpAddress : "");
+ builder.setLabels(info.labels != null ? info.labels: "");
- List<NodeEntryInformation> entries = info.entries;
- if (entries != null) {
- for (NodeEntryInformation entry : entries) {
+
+ if (info.entries != null) {
+ for (Map.Entry<String, NodeEntryInformation> elt : info.entries.entrySet()) {
+ NodeEntryInformation entry = elt.getValue();
Messages.NodeEntryInformationProto.Builder node =
Messages.NodeEntryInformationProto.newBuilder();
+ node.setPriority(entry.priority);
+ node.setName(elt.getKey());
node.setFailed(entry.failed);
node.setFailedRecently(entry.failedRecently);
node.setLive(entry.live);
node.setLastUsed(entry.lastUsed);
node.setPreempted(entry.preempted);
- node.setPriority(entry.priority);
node.setRequested(entry.requested);
node.setReleasing(entry.releasing);
node.setStartFailed(entry.startFailed);
@@ -193,7 +193,7 @@
info.state = wire.getState();
List<Messages.NodeEntryInformationProto> entriesList = wire.getEntriesList();
if (entriesList != null) {
- info.entries = new ArrayList<>(entriesList.size());
+ info.entries = new HashMap<>(entriesList.size());
for (Messages.NodeEntryInformationProto entry : entriesList) {
NodeEntryInformation nei = new NodeEntryInformation();
nei.failed = entry.getFailed();
@@ -206,7 +206,7 @@
nei.releasing = entry.getReleasing();
nei.startFailed = entry.getStartFailed();
nei.starting = entry.getStarting();
- info.entries.add(nei);
+ info.entries.put(entry.getName(), nei);
}
}
return info;
diff --git a/slider-core/src/main/java/org/apache/slider/api/types/ApplicationLivenessInformation.java b/slider-core/src/main/java/org/apache/slider/api/types/ApplicationLivenessInformation.java
index 4dd2cb7..9879d05 100644
--- a/slider-core/src/main/java/org/apache/slider/api/types/ApplicationLivenessInformation.java
+++ b/slider-core/src/main/java/org/apache/slider/api/types/ApplicationLivenessInformation.java
@@ -30,9 +30,15 @@
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class ApplicationLivenessInformation {
+ /** flag set if the cluster is at size */
public boolean allRequestsSatisfied;
+
+ /** number of outstanding requests: those needed to satisfy */
public int requestsOutstanding;
+ /** number of requests submitted to YARN */
+ public int activeRequests;
+
@Override
public String toString() {
final StringBuilder sb =
diff --git a/slider-core/src/main/java/org/apache/slider/api/types/ComponentInformation.java b/slider-core/src/main/java/org/apache/slider/api/types/ComponentInformation.java
index 3b4b8bd..c46a59f 100644
--- a/slider-core/src/main/java/org/apache/slider/api/types/ComponentInformation.java
+++ b/slider-core/src/main/java/org/apache/slider/api/types/ComponentInformation.java
@@ -52,8 +52,8 @@
public int requested;
public int failed, started, startFailed, completed, totalRequested;
public int nodeFailed, failedRecently, preempted;
- public boolean pendingAntiAffineRequest;
public int pendingAntiAffineRequestCount;
+ public boolean isAARequestOutstanding;
public String failureMessage;
public List<String> containers;
@@ -85,19 +85,20 @@
new StringBuilder("ComponentInformation{");
sb.append(", name='").append(name).append('\'');
sb.append(", actual=").append(actual);
- sb.append(", anti-affine pending").append(pendingAntiAffineRequestCount);
sb.append(", completed=").append(completed);
sb.append(", desired=").append(desired);
sb.append(", failed=").append(failed);
sb.append(", failureMessage='").append(failureMessage).append('\'');
sb.append(", placementPolicy=").append(placementPolicy);
+ sb.append(", isAARequestOutstanding=").append(isAARequestOutstanding);
+ sb.append(", pendingAntiAffineRequestCount=").append(pendingAntiAffineRequestCount);
sb.append(", priority=").append(priority);
sb.append(", releasing=").append(releasing);
sb.append(", requested=").append(requested);
sb.append(", started=").append(started);
sb.append(", startFailed=").append(startFailed);
sb.append(", totalRequested=").append(totalRequested);
- sb.append("container count='")
+ sb.append(", container count='")
.append(containers == null ? 0 : containers.size())
.append('\'');
sb.append('}');
diff --git a/slider-core/src/main/java/org/apache/slider/api/types/NodeEntryInformation.java b/slider-core/src/main/java/org/apache/slider/api/types/NodeEntryInformation.java
index 482b0c7..8424be2 100644
--- a/slider-core/src/main/java/org/apache/slider/api/types/NodeEntryInformation.java
+++ b/slider-core/src/main/java/org/apache/slider/api/types/NodeEntryInformation.java
@@ -28,7 +28,6 @@
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class NodeEntryInformation {
-
/** incrementing counter of instances that failed */
public int failed;
@@ -58,4 +57,22 @@
/** number of starting instances */
public int starting;
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder(
+ "NodeEntryInformation{");
+ sb.append("priority=").append(priority);
+ sb.append(", live=").append(live);
+ sb.append(", requested=").append(requested);
+ sb.append(", releasing=").append(releasing);
+ sb.append(", starting=").append(starting);
+ sb.append(", failed=").append(failed);
+ sb.append(", failedRecently=").append(failedRecently);
+ sb.append(", startFailed=").append(startFailed);
+ sb.append(", preempted=").append(preempted);
+ sb.append(", lastUsed=").append(lastUsed);
+ sb.append('}');
+ return sb.toString();
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/api/types/NodeInformation.java b/slider-core/src/main/java/org/apache/slider/api/types/NodeInformation.java
index 049ee52..4fe5b4c 100644
--- a/slider-core/src/main/java/org/apache/slider/api/types/NodeInformation.java
+++ b/slider-core/src/main/java/org/apache/slider/api/types/NodeInformation.java
@@ -22,7 +22,9 @@
import org.codehaus.jackson.map.annotate.JsonSerialize;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Serialized node information. Must be kept in sync with the protobuf equivalent.
@@ -31,12 +33,27 @@
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class NodeInformation {
- public String healthReport;
public String hostname;
- public String httpAddress;
- public String labels;
- public long lastUpdated;
- public String rackName;
public String state;
- public List<NodeEntryInformation> entries = new ArrayList<>();
+ public String labels;
+ public String rackName;
+ public String httpAddress;
+ public String healthReport;
+ public long lastUpdated;
+ public Map<String, NodeEntryInformation> entries = new HashMap<>();
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder(
+ "NodeInformation{");
+ sb.append("hostname='").append(hostname).append('\'');
+ sb.append(", state='").append(state).append('\'');
+ sb.append(", labels='").append(labels).append('\'');
+ sb.append(", rackName='").append(rackName).append('\'');
+ sb.append(", httpAddress='").append(httpAddress).append('\'');
+ sb.append(", healthReport='").append(healthReport).append('\'');
+ sb.append(", lastUpdated=").append(lastUpdated);
+ sb.append('}');
+ return sb.toString();
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/api/types/NodeInformationList.java b/slider-core/src/main/java/org/apache/slider/api/types/NodeInformationList.java
new file mode 100644
index 0000000..741523e
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/api/types/NodeInformationList.java
@@ -0,0 +1,41 @@
+/*
+ * 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.slider.api.types;
+
+import org.apache.slider.core.persist.JsonSerDeser;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class NodeInformationList extends ArrayList<NodeInformation> {
+ public NodeInformationList() {
+ }
+
+ public NodeInformationList(Collection<? extends NodeInformation> c) {
+ super(c);
+ }
+
+ public NodeInformationList(int initialCapacity) {
+ super(initialCapacity);
+ }
+
+ public static JsonSerDeser<NodeInformationList> createSerializer() {
+ return new JsonSerDeser<>(NodeInformationList.class);
+ }
+}
diff --git a/slider-core/src/main/java/org/apache/slider/api/types/RoleStatistics.java b/slider-core/src/main/java/org/apache/slider/api/types/RoleStatistics.java
new file mode 100644
index 0000000..c926600
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/api/types/RoleStatistics.java
@@ -0,0 +1,66 @@
+/*
+ * 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.slider.api.types;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+
+/**
+ * Simple role statistics for state views; can be generated by RoleStatus
+ * instances, and aggregated for summary information.
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RoleStatistics {
+ public long activeAA = 0L;
+ public long actual = 0L;
+ public long completed = 0L;
+ public long desired = 0L;
+ public long failed = 0L;
+ public long failedRecently = 0L;
+ public long limitsExceeded = 0L;
+ public long nodeFailed = 0L;
+ public long preempted = 0L;
+ public long releasing = 0L;
+ public long requested = 0L;
+ public long started = 0L;
+ public long startFailed = 0L;
+ public long totalRequested = 0L;
+
+ /**
+ * Add another statistics instance
+ * @param that the other value
+ * @return this entry
+ */
+ public RoleStatistics add(final RoleStatistics that) {
+ activeAA += that.activeAA;
+ actual += that.actual;
+ completed += that.completed;
+ desired += that.desired;
+ failed += that.failed;
+ failedRecently += that.failedRecently;
+ limitsExceeded += that.limitsExceeded;
+ nodeFailed += that.nodeFailed;
+ preempted += that.preempted;
+ releasing += that.releasing;
+ requested += that.requested;
+ started += that.started;
+ startFailed += that.totalRequested;
+ totalRequested += that.totalRequested;
+ return this;
+ }
+}
diff --git a/slider-core/src/main/java/org/apache/slider/client/SliderClient.java b/slider-core/src/main/java/org/apache/slider/client/SliderClient.java
index f44b739..da94dd4 100644
--- a/slider-core/src/main/java/org/apache/slider/client/SliderClient.java
+++ b/slider-core/src/main/java/org/apache/slider/client/SliderClient.java
@@ -64,11 +64,14 @@
import org.apache.hadoop.yarn.util.ConverterUtils;
import org.apache.slider.api.ClusterDescription;
import org.apache.slider.api.ClusterNode;
+import org.apache.slider.api.SliderApplicationApi;
import org.apache.slider.api.SliderClusterProtocol;
import org.apache.slider.api.StateValues;
import org.apache.slider.api.proto.Messages;
import org.apache.slider.api.types.ContainerInformation;
+import org.apache.slider.api.types.NodeInformationList;
import org.apache.slider.api.types.SliderInstanceDescription;
+import org.apache.slider.client.ipc.SliderApplicationIpcClient;
import org.apache.slider.client.ipc.SliderClusterOperations;
import org.apache.slider.common.Constants;
import org.apache.slider.common.SliderExitCodes;
@@ -91,6 +94,7 @@
import org.apache.slider.common.params.ActionKillContainerArgs;
import org.apache.slider.common.params.ActionListArgs;
import org.apache.slider.common.params.ActionLookupArgs;
+import org.apache.slider.common.params.ActionNodesArgs;
import org.apache.slider.common.params.ActionPackageArgs;
import org.apache.slider.common.params.ActionRegistryArgs;
import org.apache.slider.common.params.ActionResolveArgs;
@@ -104,6 +108,7 @@
import org.apache.slider.common.tools.ConfigHelper;
import org.apache.slider.common.tools.Duration;
import org.apache.slider.common.tools.SliderFileSystem;
+import org.apache.slider.common.tools.SliderUtils;
import org.apache.slider.common.tools.SliderVersionInfo;
import org.apache.slider.core.build.InstanceBuilder;
import org.apache.slider.core.build.InstanceIO;
@@ -133,6 +138,7 @@
import org.apache.slider.core.persist.AppDefinitionPersister;
import org.apache.slider.core.persist.ApplicationReportSerDeser;
import org.apache.slider.core.persist.ConfPersister;
+import org.apache.slider.core.persist.JsonSerDeser;
import org.apache.slider.core.persist.LockAcquireFailedException;
import org.apache.slider.core.registry.SliderRegistryUtils;
import org.apache.slider.core.registry.YarnAppListClient;
@@ -166,7 +172,6 @@
import java.io.BufferedReader;
import java.io.File;
-import java.io.FilenameFilter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -333,7 +338,7 @@
if (isUnset(action)) {
throw new SliderException(EXIT_USAGE, serviceArgs.usage());
}
-
+
int exitCode = EXIT_SUCCESS;
String clusterName = serviceArgs.getClusterName();
// actions
@@ -405,11 +410,15 @@
case ACTION_LIST:
exitCode = actionList(clusterName, serviceArgs.getActionListArgs());
break;
-
+
case ACTION_LOOKUP:
exitCode = actionLookup(serviceArgs.getActionLookupArgs());
break;
+ case ACTION_NODES:
+ exitCode = actionNodes("", serviceArgs.getActionNodesArgs());
+ break;
+
case ACTION_PACKAGE:
exitCode = actionPackage(serviceArgs.getActionPackageArgs());
break;
@@ -2111,9 +2120,7 @@
commandLine.add(Arguments.ARG_FILESYSTEM, serviceArgs.getFilesystemBinding());
}
- /**
- * pass the registry binding
- */
+ // pass the registry binding
commandLine.addConfOptionToCLI(config, RegistryConstants.KEY_REGISTRY_ZK_ROOT,
RegistryConstants.DEFAULT_ZK_REGISTRY_ROOT);
commandLine.addMandatoryConfOption(config, RegistryConstants.KEY_REGISTRY_ZK_QUORUM);
@@ -2123,6 +2130,15 @@
// the relevant security settings go over
commandLine.addConfOption(config, DFS_NAMENODE_KERBEROS_PRINCIPAL_KEY);
}
+
+ // copy over any/all YARN RM client values, in case the server-side XML conf file
+ // has the 0.0.0.0 address
+ commandLine.addConfOptions(config,
+ YarnConfiguration.RM_ADDRESS,
+ YarnConfiguration.RM_CLUSTER_ID,
+ YarnConfiguration.RM_HOSTNAME,
+ YarnConfiguration.RM_PRINCIPAL);
+
// write out the path output
commandLine.addOutAndErrFiles(STDOUT_AM, STDERR_AM);
@@ -2137,12 +2153,8 @@
// Set the priority for the application master
-
- int amPriority = config.getInt(KEY_YARN_QUEUE_PRIORITY,
- DEFAULT_YARN_QUEUE_PRIORITY);
-
-
- amLauncher.setPriority(amPriority);
+ amLauncher.setPriority(config.getInt(KEY_YARN_QUEUE_PRIORITY,
+ DEFAULT_YARN_QUEUE_PRIORITY));
// Set the queue to which this application is to be submitted in the RM
// Queue for App master
@@ -2153,7 +2165,7 @@
log.info("Using queue {} for the application instance.", amQueue);
}
- if (amQueue != null) {
+ if (isSet(amQueue)) {
amLauncher.setQueue(amQueue);
}
@@ -4226,6 +4238,73 @@
throw new UsageException("%s %s", errMsg, CommonArgs.usage(serviceArgs,
actionName));
}
+
+ /**
+ * List the nodes in the cluster, possibly filtering by node state or label.
+ *
+ * @param args argument list
+ * @return a possibly empty list of nodes in the cluster
+ * @throws IOException IO problems
+ * @throws YarnException YARN problems
+ */
+ @Override
+ public NodeInformationList listYarnClusterNodes(ActionNodesArgs args)
+ throws YarnException, IOException {
+ return yarnClient.listNodes(args.label, args.healthy);
+ }
+
+ /**
+ * List the nodes in the cluster, possibly filtering by node state or label.
+ *
+ * @param args argument list
+ * @return a possibly empty list of nodes in the cluster
+ * @throws IOException IO problems
+ * @throws YarnException YARN problems
+ */
+ public NodeInformationList listInstanceNodes(String instance, ActionNodesArgs args)
+ throws YarnException, IOException {
+ // TODO
+ log.info("listInstanceNodes {}", instance);
+ SliderClusterOperations clusterOps =
+ new SliderClusterOperations(bondToCluster(instance));
+ return clusterOps.getLiveNodes();
+ }
+
+ /**
+ * List the nodes in the cluster, possibly filtering by node state or label.
+ * Prints them to stdout unless the args names a file instead.
+ * @param args argument list
+ * @throws IOException IO problems
+ * @throws YarnException YARN problems
+ */
+ public int actionNodes(String instance, ActionNodesArgs args) throws YarnException, IOException {
+
+ args.instance = instance;
+ NodeInformationList nodes;
+ if (SliderUtils.isUnset(instance)) {
+ nodes = listYarnClusterNodes(args);
+ } else {
+ nodes = listInstanceNodes(instance, args);
+ }
+ log.debug("Node listing for {} has {} nodes", args, nodes.size());
+ JsonSerDeser<NodeInformationList> serDeser = NodeInformationList.createSerializer();
+ if (args.outputFile != null) {
+ serDeser.save(nodes, args.outputFile);
+ } else {
+ println(serDeser.toJson(nodes));
+ }
+ return 0;
+ }
+
+ /**
+ * Create a new IPC client for talking to slider via what follows the REST API.
+ * Client must already be bonded to the cluster
+ * @return a new IPC client
+ */
+ public SliderApplicationApi createIpcClient()
+ throws IOException, YarnException {
+ return new SliderApplicationIpcClient(createClusterOperations());
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java b/slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java
index d87b121..5c5d96b 100644
--- a/slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java
+++ b/slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java
@@ -23,6 +23,7 @@
import org.apache.hadoop.yarn.api.records.ApplicationReport;
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.slider.api.types.NodeInformationList;
import org.apache.slider.api.types.SliderInstanceDescription;
import org.apache.slider.common.params.AbstractClusterBuildingActionArgs;
import org.apache.slider.common.params.ActionAMSuicideArgs;
@@ -36,6 +37,7 @@
import org.apache.slider.common.params.ActionInstallKeytabArgs;
import org.apache.slider.common.params.ActionInstallPackageArgs;
import org.apache.slider.common.params.ActionKeytabArgs;
+import org.apache.slider.common.params.ActionNodesArgs;
import org.apache.slider.common.params.ActionPackageArgs;
import org.apache.slider.common.params.ActionKillContainerArgs;
import org.apache.slider.common.params.ActionListArgs;
@@ -342,4 +344,14 @@
*/
int actionDependency(ActionDependencyArgs dependencyArgs) throws IOException,
YarnException;
+
+ /**
+ * List the nodes
+ * @param args
+ * @return
+ * @throws YarnException
+ * @throws IOException
+ */
+ NodeInformationList listYarnClusterNodes(ActionNodesArgs args)
+ throws YarnException, IOException;
}
diff --git a/slider-core/src/main/java/org/apache/slider/client/SliderYarnClientImpl.java b/slider-core/src/main/java/org/apache/slider/client/SliderYarnClientImpl.java
index 3b7a65c..85a582b 100644
--- a/slider-core/src/main/java/org/apache/slider/client/SliderYarnClientImpl.java
+++ b/slider-core/src/main/java/org/apache/slider/client/SliderYarnClientImpl.java
@@ -20,6 +20,7 @@
import com.google.common.base.Preconditions;
import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.yarn.api.ApplicationClientProtocol;
@@ -27,12 +28,18 @@
import org.apache.hadoop.yarn.api.protocolrecords.KillApplicationResponse;
import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.api.records.ApplicationReport;
+import org.apache.hadoop.yarn.api.records.NodeReport;
+import org.apache.hadoop.yarn.api.records.NodeState;
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
import org.apache.hadoop.yarn.client.api.impl.YarnClientImpl;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.util.ConverterUtils;
import org.apache.hadoop.yarn.util.Records;
+import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
import org.apache.slider.common.SliderKeys;
+import org.apache.slider.common.params.ActionNodesArgs;
import org.apache.slider.common.tools.CoreFileSystem;
import org.apache.slider.common.tools.Duration;
import org.apache.slider.common.tools.SliderFileSystem;
@@ -42,6 +49,8 @@
import org.slf4j.LoggerFactory;
import java.io.IOException;
+import java.net.BindException;
+import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@@ -55,8 +64,7 @@
* from the slider entry point service
*/
public class SliderYarnClientImpl extends YarnClientImpl {
- protected static final Logger
- log = LoggerFactory.getLogger(SliderYarnClientImpl.class);
+ protected static final Logger log = LoggerFactory.getLogger(SliderYarnClientImpl.class);
/**
* Keyword to use in the {@link #emergencyForceKill(String)}
@@ -65,6 +73,18 @@
*/
public static final String KILL_ALL = "all";
+ @Override
+ protected void serviceInit(Configuration conf) throws Exception {
+ InetSocketAddress clientRpcAddress = SliderUtils.getRmAddress(conf);
+ if (!SliderUtils.isAddressDefined(clientRpcAddress)) {
+ // address isn't known; fail fast
+ throw new BindException("Invalid " + YarnConfiguration.RM_ADDRESS
+ + " value:" + conf.get(YarnConfiguration.RM_ADDRESS)
+ + " - see https://wiki.apache.org/hadoop/UnsetHostnameOrPort");
+ }
+ super.serviceInit(conf);
+ }
+
/**
* Get the RM Client RPC interface
* @return an RPC interface valid after initialization and authentication
@@ -96,10 +116,10 @@
public List<ApplicationReport> listDeployedInstances(String user)
throws YarnException, IOException {
Preconditions.checkArgument(user != null, "Null User");
- Set<String> types = new HashSet<String>(1);
+ Set<String> types = new HashSet<>(1);
types.add(SliderKeys.APP_TYPE);
List<ApplicationReport> allApps = getApplications(types);
- List<ApplicationReport> results = new ArrayList<ApplicationReport>();
+ List<ApplicationReport> results = new ArrayList<>();
for (ApplicationReport report : allApps) {
if (StringUtils.isEmpty(user) || user.equals(report.getUser())) {
results.add(report);
@@ -108,7 +128,6 @@
return results;
}
-
/**
* find all instances of a specific app -if there is more than one in the
* YARN cluster,
@@ -124,7 +143,7 @@
List<ApplicationReport> instances = listDeployedInstances(user);
List<ApplicationReport> results =
- new ArrayList<ApplicationReport>(instances.size());
+ new ArrayList<>(instances.size());
for (ApplicationReport report : instances) {
if (report.getName().equals(appname)) {
results.add(report);
@@ -142,8 +161,7 @@
public boolean isApplicationLive(ApplicationReport app) {
Preconditions.checkArgument(app != null, "Null app report");
- return app.getYarnApplicationState().ordinal() <=
- YarnApplicationState.RUNNING.ordinal();
+ return app.getYarnApplicationState().ordinal() <= YarnApplicationState.RUNNING.ordinal();
}
@@ -330,8 +348,6 @@
Preconditions.checkArgument(StringUtils.isNotEmpty(appname),
"Null/empty application name");
Preconditions.checkArgument(desiredState != null, "Null desiredState");
- ApplicationReport found = null;
- ApplicationReport foundAndLive = null;
log.debug("Searching {} records for instance name {} in state '{}'",
instances.size(), appname, desiredState);
for (ApplicationReport app : instances) {
@@ -350,4 +366,45 @@
log.debug("No match");
return null;
}
+
+ /**
+ * List the nodes in the cluster, possibly filtering by node state or label.
+ *
+ * @param label label to filter by -or "" for any
+ * @param live flag to request running nodes only
+ * @return a possibly empty list of nodes in the cluster
+ * @throws IOException IO problems
+ * @throws YarnException YARN problems
+ */
+ public NodeInformationList listNodes(String label, boolean live)
+ throws IOException, YarnException {
+ Preconditions.checkArgument(label != null, "null label");
+ NodeState[] states;
+ if (live) {
+ states = new NodeState[1];
+ states[0] = NodeState.RUNNING;
+ } else {
+ states = new NodeState[0];
+ }
+ List<NodeReport> reports = getNodeReports(states);
+ NodeInformationList results = new NodeInformationList(reports.size());
+ for (NodeReport report : reports) {
+ if (live && report.getNodeState() != NodeState.RUNNING) {
+ continue;
+ }
+ if (!label.isEmpty() && !report.getNodeLabels().contains(label)) {
+ continue;
+ }
+ // build node info from report
+ NodeInformation info = new NodeInformation();
+ info.hostname = report.getNodeId().getHost();
+ info.healthReport = report.getHealthReport();
+ info.httpAddress = report.getHttpAddress();
+ info.labels = SliderUtils.extractNodeLabel(report);
+ info.rackName = report.getRackName();
+ info.state = report.getNodeState().toString();
+ results.add(info);
+ }
+ return results;
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/client/ipc/SliderApplicationIpcClient.java b/slider-core/src/main/java/org/apache/slider/client/ipc/SliderApplicationIpcClient.java
index 291583d..a007326 100644
--- a/slider-core/src/main/java/org/apache/slider/client/ipc/SliderApplicationIpcClient.java
+++ b/slider-core/src/main/java/org/apache/slider/client/ipc/SliderApplicationIpcClient.java
@@ -24,6 +24,7 @@
import org.apache.slider.api.types.ComponentInformation;
import org.apache.slider.api.types.ContainerInformation;
import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
import org.apache.slider.api.types.PingInformation;
import org.apache.slider.api.SliderApplicationApi;
import org.apache.slider.core.conf.AggregateConf;
@@ -196,7 +197,7 @@
}
@Override
- public Map<String, NodeInformation> getLiveNodes() throws IOException {
+ public NodeInformationList getLiveNodes() throws IOException {
try {
return operations.getLiveNodes();
} catch (IOException e) {
diff --git a/slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java b/slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java
index e1ec971..392f451 100644
--- a/slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java
+++ b/slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java
@@ -19,6 +19,9 @@
package org.apache.slider.client.ipc;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import org.apache.hadoop.yarn.api.records.NodeReport;
+import org.apache.hadoop.yarn.api.records.NodeState;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.slider.api.ClusterDescription;
import org.apache.slider.api.ClusterNode;
@@ -31,8 +34,10 @@
import org.apache.slider.api.types.ComponentInformation;
import org.apache.slider.api.types.ContainerInformation;
import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
import org.apache.slider.api.types.PingInformation;
import org.apache.slider.common.tools.Duration;
+import org.apache.slider.common.tools.SliderUtils;
import org.apache.slider.core.conf.AggregateConf;
import org.apache.slider.core.conf.ConfTree;
import org.apache.slider.core.conf.ConfTreeOperations;
@@ -237,7 +242,7 @@
/**
* Get the details on a list of uuids
- * @param uuids
+ * @param uuids instance IDs
* @return a possibly empty list of node details
* @throws IOException
* @throws YarnException
@@ -468,22 +473,16 @@
return unmarshall(proto);
}
- public Map<String, NodeInformation> getLiveNodes() throws IOException {
+ public NodeInformationList getLiveNodes() throws IOException {
Messages.GetLiveNodesResponseProto response =
appMaster.getLiveNodes(Messages.GetLiveNodesRequestProto.newBuilder().build());
- int namesCount = response.getNamesCount();
int records = response.getNodesCount();
- if (namesCount != records) {
- throw new IOException(
- "Number of names returned (" + namesCount + ")" +
- " does not match the number of records returned: " + records);
+ NodeInformationList nil = new NodeInformationList(records);
+ for (int i = 0; i < records; i++) {
+ nil.add(unmarshall(response.getNodes(i)));
}
- Map<String, NodeInformation> map = new HashMap<>(namesCount);
- for (int i = 0; i < namesCount; i++) {
- map.put(response.getNames(i), unmarshall(response.getNodes(i)));
- }
- return map;
+ return nil;
}
public NodeInformation getLiveNode(String hostname) throws IOException {
@@ -527,5 +526,4 @@
return unmarshall(response);
}
-
}
diff --git a/slider-core/src/main/java/org/apache/slider/client/rest/SliderApplicationApiRestClient.java b/slider-core/src/main/java/org/apache/slider/client/rest/SliderApplicationApiRestClient.java
index ce2817a..4283ee8 100644
--- a/slider-core/src/main/java/org/apache/slider/client/rest/SliderApplicationApiRestClient.java
+++ b/slider-core/src/main/java/org/apache/slider/client/rest/SliderApplicationApiRestClient.java
@@ -21,7 +21,6 @@
import com.google.common.base.Preconditions;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
-import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
@@ -32,11 +31,11 @@
import org.apache.slider.api.types.ContainerInformation;
import org.apache.slider.api.SliderApplicationApi;
import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
import org.apache.slider.core.conf.AggregateConf;
import org.apache.slider.core.conf.ConfTree;
import org.apache.slider.core.conf.ConfTreeOperations;
import org.apache.slider.core.exceptions.ExceptionConverter;
-import org.apache.slider.core.persist.ConfTreeSerDeser;
import org.apache.slider.core.restclient.HttpVerb;
import org.apache.slider.api.types.PingInformation;
import org.slf4j.Logger;
@@ -68,6 +67,19 @@
this.appResource = appResource;
}
+ /**
+ * Create an instance
+ * @param jerseyClient jersey client for operations
+ * @param appmaster URL of appmaster/proxy to AM
+ */
+ public SliderApplicationApiRestClient(Client jerseyClient, String appmaster) {
+ super(jerseyClient);
+ WebResource amResource = jerseyClient.resource(appmaster);
+ amResource.type(MediaType.APPLICATION_JSON);
+ this.appResource = amResource.path(SLIDER_PATH_APPLICATION);
+ }
+
+
@Override
public String toString() {
final StringBuilder sb =
@@ -244,14 +256,13 @@
}
@Override
- public Map<String, NodeInformation> getLiveNodes() throws IOException {
- return getApplicationResource(LIVE_NODES,
- new GenericType<Map<String, NodeInformation>>() { });
+ public NodeInformationList getLiveNodes() throws IOException {
+ return getApplicationResource(LIVE_NODES, NodeInformationList.class);
}
@Override
public NodeInformation getLiveNode(String hostname) throws IOException {
- return getApplicationResource(LIVE_COMPONENTS + "/" + hostname,
+ return getApplicationResource(LIVE_NODES + "/" + hostname,
NodeInformation.class);
}
diff --git a/slider-core/src/main/java/org/apache/slider/common/SliderXmlConfKeys.java b/slider-core/src/main/java/org/apache/slider/common/SliderXmlConfKeys.java
index 07214b2..26109a7 100644
--- a/slider-core/src/main/java/org/apache/slider/common/SliderXmlConfKeys.java
+++ b/slider-core/src/main/java/org/apache/slider/common/SliderXmlConfKeys.java
@@ -125,6 +125,8 @@
"hadoop.http.filter.initializers";
String KEY_KEYSTORE_LOCATION = "ssl.server.keystore.location";
String KEY_AM_LOGIN_KEYTAB_NAME = "slider.am.login.keytab.name";
+ /** Declare that a keytab must be provided */
+ String KEY_AM_LOGIN_KEYTAB_REQUIRED = "slider.am.login.keytab.required";
String KEY_HDFS_KEYTAB_DIR = "slider.hdfs.keytab.dir";
String KEY_AM_KEYTAB_LOCAL_PATH = "slider.am.keytab.local.path";
String KEY_KEYTAB_PRINCIPAL = "slider.keytab.principal.name";
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/AbstractActionArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/AbstractActionArgs.java
index 17c235f..d0b1693 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/AbstractActionArgs.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/AbstractActionArgs.java
@@ -56,7 +56,7 @@
* This is the default parameter
*/
@Parameter
- public final List<String> parameters = new ArrayList<String>();
+ public final List<String> parameters = new ArrayList<>();
/**
* get the name: relies on arg 1 being the cluster name in all operations
@@ -77,7 +77,7 @@
*/
@Parameter(names = ARG_DEFINE, arity = 1, description = "Definitions")
- public final List<String> definitions = new ArrayList<String>();
+ public final List<String> definitions = new ArrayList<>();
/**
* System properties
@@ -85,7 +85,7 @@
@Parameter(names = {ARG_SYSPROP}, arity = 1,
description = "system properties in the form name value" +
" These are set after the JVM is started.")
- public final List<String> sysprops = new ArrayList<String>(0);
+ public final List<String> sysprops = new ArrayList<>(0);
@Parameter(names = {ARG_MANAGER_SHORT, ARG_MANAGER},
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/AbstractClusterBuildingActionArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/AbstractClusterBuildingActionArgs.java
index f2e3c61..1c694bd 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/AbstractClusterBuildingActionArgs.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/AbstractClusterBuildingActionArgs.java
@@ -59,7 +59,7 @@
/**
* --image path
- the full path to a .tar or .tar.gz path containing an HBase image.
+ * the full path to a .tar or .tar.gz path containing an HBase image.
*/
@Parameter(names = ARG_IMAGE,
description = "The full path to a .tar or .tar.gz path containing the application",
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/ActionAMSuicideArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/ActionAMSuicideArgs.java
index d6cabf5..5b4cfdc 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/ActionAMSuicideArgs.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/ActionAMSuicideArgs.java
@@ -21,7 +21,6 @@
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
-
@Parameters(commandNames = {SliderActions.ACTION_AM_SUICIDE},
commandDescription = SliderActions.DESCRIBE_ACTION_AM_SUICIDE)
public class ActionAMSuicideArgs extends AbstractActionArgs {
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/ActionEchoArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/ActionEchoArgs.java
index b0f53f8..d05f10b 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/ActionEchoArgs.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/ActionEchoArgs.java
@@ -20,15 +20,10 @@
import com.beust.jcommander.Parameter;
-/*
-
-@Parameters(commandNames = {SliderActions.ACTION_KILL_CONTAINER},
- commandDescription = SliderActions.DESCRIBE_ACTION_KILL_CONTAINER)
-*/
public class ActionEchoArgs extends AbstractActionArgs {
@Override
public String getActionName() {
- return SliderActions.ACTION_DESTROY;
+ return SliderActions.ACTION_ECHO;
}
@Parameter(names = {ARG_MESSAGE},
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/ActionListArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/ActionListArgs.java
index 0bc5792..739b5fc 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/ActionListArgs.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/ActionListArgs.java
@@ -57,7 +57,7 @@
@Parameter(names = {ARG_COMPONENTS}, variableArity = true,
description = "Filter containers by component names (used with " +
ARG_CONTAINERS + ")")
- public Set<String> components = new HashSet<>(0);;
+ public Set<String> components = new HashSet<>(0);
/**
* Get the min #of params expected
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/ActionLookupArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/ActionLookupArgs.java
index 3b69e74..1b73522 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/ActionLookupArgs.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/ActionLookupArgs.java
@@ -43,7 +43,7 @@
}
@Parameter(names = {ARG_ID},
- description = "ID of the container")
+ description = "ID of the application")
public String id;
@Parameter(names = {ARG_OUTPUT, ARG_OUTPUT_SHORT},
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/ActionNodesArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/ActionNodesArgs.java
new file mode 100644
index 0000000..5ddccf6
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/common/params/ActionNodesArgs.java
@@ -0,0 +1,66 @@
+/*
+ * 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.slider.common.params;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+import java.io.File;
+
+@Parameters(commandNames = {SliderActions.ACTION_NODES},
+ commandDescription = SliderActions.DESCRIBE_ACTION_NODES)
+public class ActionNodesArgs extends AbstractActionArgs {
+
+ /**
+ * Instance for API use; on CLI the name is derived from {@link #getClusterName()}.
+ */
+ public String instance;
+
+ @Override
+ public String getActionName() {
+ return SliderActions.ACTION_NODES;
+ }
+
+ @Parameter(names = {ARG_OUTPUT, ARG_OUTPUT_SHORT},
+ description = "Output file for the information")
+ public File outputFile;
+
+ @Parameter(names = {ARG_LABEL})
+ public String label = "";
+
+ @Parameter(names = {ARG_HEALTHY} )
+ public boolean healthy;
+
+ @Override
+ public int getMinParams() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder(
+ "ActionNodesArgs{");
+ sb.append("instance='").append(instance).append('\'');
+ sb.append(", outputFile=").append(outputFile);
+ sb.append(", label='").append(label).append('\'');
+ sb.append(", healthy=").append(healthy);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/ActionStatusArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/ActionStatusArgs.java
index a7edb65..00178df 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/ActionStatusArgs.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/ActionStatusArgs.java
@@ -25,13 +25,14 @@
commandDescription = SliderActions.DESCRIBE_ACTION_STATUS)
public class ActionStatusArgs extends AbstractActionArgs {
+
@Override
public String getActionName() {
return SliderActions.ACTION_STATUS;
}
@Parameter(names = {ARG_OUTPUT, ARG_OUTPUT_SHORT},
- description = "Output file for the configuration data")
+ description = "Output file for the status information")
public String output;
public String getOutput() {
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/ActionUpgradeArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/ActionUpgradeArgs.java
index 832e1cc..6ef51b2 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/ActionUpgradeArgs.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/ActionUpgradeArgs.java
@@ -61,11 +61,11 @@
@Parameter(names={ARG_CONTAINERS}, variableArity = true,
description = "stop specific containers")
- public List<String> containers = new ArrayList<String>(0);
+ public List<String> containers = new ArrayList<>(0);
@Parameter(names={ARG_COMPONENTS}, variableArity = true,
description = "stop all containers of specific components")
- public List<String> components = new ArrayList<String>(0);
+ public List<String> components = new ArrayList<>(0);
@Parameter(names = {ARG_FORCE},
description = "force spec upgrade operation")
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/AddonArgsDelegate.java b/slider-core/src/main/java/org/apache/slider/common/params/AddonArgsDelegate.java
index 65ebc4b..3ef8e19 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/AddonArgsDelegate.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/AddonArgsDelegate.java
@@ -34,7 +34,7 @@
arity = 2,
description = "--addon <name> <folder or package>",
splitter = DontSplitArguments.class)
- public List<String> addonTuples = new ArrayList<String>(0);
+ public List<String> addonTuples = new ArrayList<>(0);
/**
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/AppAndResouceOptionArgsDelegate.java b/slider-core/src/main/java/org/apache/slider/common/params/AppAndResouceOptionArgsDelegate.java
index 1f07de3..248e4c2 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/AppAndResouceOptionArgsDelegate.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/AppAndResouceOptionArgsDelegate.java
@@ -37,7 +37,7 @@
@Parameter(names = {ARG_OPTION, ARG_OPTION_SHORT}, arity = 2,
description = ARG_OPTION + "<name> <value>",
splitter = DontSplitArguments.class)
- public List<String> optionTuples = new ArrayList<String>(0);
+ public List<String> optionTuples = new ArrayList<>(0);
/**
@@ -47,7 +47,7 @@
description = "Component option " + ARG_COMP_OPT +
" <component> <name> <option>",
splitter = DontSplitArguments.class)
- public List<String> compOptTriples = new ArrayList<String>(0);
+ public List<String> compOptTriples = new ArrayList<>(0);
/**
* Resource Options
@@ -55,7 +55,7 @@
@Parameter(names = {ARG_RESOURCE_OPT, ARG_RESOURCE_OPT_SHORT}, arity = 2,
description = "Resource option "+ ARG_RESOURCE_OPT + "<name> <value>",
splitter = DontSplitArguments.class)
- public List<String> resOptionTuples = new ArrayList<String>(0);
+ public List<String> resOptionTuples = new ArrayList<>(0);
/**
@@ -65,7 +65,7 @@
description = "Component resource option " + ARG_RES_COMP_OPT +
" <component> <name> <option>",
splitter = DontSplitArguments.class)
- public List<String> resCompOptTriples = new ArrayList<String>(0);
+ public List<String> resCompOptTriples = new ArrayList<>(0);
public Map<String, String> getOptionsMap() throws
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/ArgOps.java b/slider-core/src/main/java/org/apache/slider/common/params/ArgOps.java
index aeb2979..12a2032 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/ArgOps.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/ArgOps.java
@@ -44,20 +44,13 @@
* create a 3-tuple
*/
public static List<Object> triple(String msg, int min, int max) {
- List<Object> l = new ArrayList<Object>(3);
+ List<Object> l = new ArrayList<>(3);
l.add(msg);
l.add(min);
l.add(max);
return l;
}
- /**
- * Create a tuple
- */
- public static List<Object> tuple(String msg, int min) {
- return triple(msg, min, min);
- }
-
public static void applyFileSystemBinding(String filesystemBinding,
Configuration conf) {
if (filesystemBinding != null) {
@@ -100,7 +93,7 @@
public static Map<String, String> convertTupleListToMap(String description,
List<String> list) throws
BadCommandArgumentsException {
- Map<String, String> results = new HashMap<String, String>();
+ Map<String, String> results = new HashMap<>();
if (list != null && !list.isEmpty()) {
int size = list.size();
if (size % 2 != 0) {
@@ -131,10 +124,9 @@
* @throws BadCommandArgumentsException odd #of arguments received
*/
public static Map<String, Map<String, String>> convertTripleListToMaps(String description,
- List<String> list) throws
- BadCommandArgumentsException {
- Map<String, Map<String, String>> results =
- new HashMap<String, Map<String, String>>();
+ List<String> list) throws BadCommandArgumentsException {
+
+ Map<String, Map<String, String>> results = new HashMap<>();
if (list != null && !list.isEmpty()) {
int size = list.size();
if (size % 3 != 0) {
@@ -149,7 +141,7 @@
Map<String, String> roleMap = results.get(role);
if (roleMap == null) {
//demand create new role map
- roleMap = new HashMap<String, String>();
+ roleMap = new HashMap<>();
results.put(role, roleMap);
}
if (roleMap.get(key) != null) {
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java b/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java
index c2fa09c..ca22c24 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java
@@ -60,6 +60,7 @@
String ARG_GETCONF = "--getconf";
String ARG_GETEXP = "--getexp";
String ARG_GETFILES = "--getfiles";
+ String ARG_HEALTHY= "--healthy";
String ARG_HELP = "--help";
String ARG_HOSTNAME = "--hostname";
String ARG_ID = "--id";
@@ -70,6 +71,7 @@
String ARG_KEYTABINSTALL = "--install";
String ARG_KEYTABDELETE = "--delete";
String ARG_KEYTABLIST = "--list";
+ String ARG_LABEL = "--label";
String ARG_LEVEL = "--level";
String ARG_LIST = "--list";
String ARG_LISTCONF = "--listconf";
@@ -125,10 +127,14 @@
/**
- * Deprecated
+ * Deprecated: use ARG_COMPONENT
*/
@Deprecated
String ARG_ROLE = "--role";
+
+ /**
+ * Deprecated: use ARG_COMP_OPT
+ */
@Deprecated
String ARG_ROLEOPT = "--roleopt";
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/ClientArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/ClientArgs.java
index 3c430f3..ea1448b 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/ClientArgs.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/ClientArgs.java
@@ -66,6 +66,7 @@
new ActionKillContainerArgs();
private final ActionListArgs actionListArgs = new ActionListArgs();
private final ActionLookupArgs actionLookupArgs = new ActionLookupArgs();
+ private final ActionNodesArgs actionNodesArgs = new ActionNodesArgs();
private final ActionRegistryArgs actionRegistryArgs = new ActionRegistryArgs();
private final ActionResolveArgs actionResolveArgs = new ActionResolveArgs();
private final ActionStatusArgs actionStatusArgs = new ActionStatusArgs();
@@ -86,31 +87,32 @@
protected void addActionArguments() {
addActions(
- actionPackageArgs,
- actionKeytabArgs,
+ actionAMSuicideArgs,
actionBuildArgs,
- actionDependencyArgs,
- actionCreateArgs,
- actionListArgs,
- actionStatusArgs,
- actionRegistryArgs,
actionClientArgs,
- actionFlexArgs,
+ actionCreateArgs,
+ actionDependencyArgs,
+ actionDestroyArgs,
actionDiagnosticArgs,
+ actionExistsArgs,
+ actionFlexArgs,
actionFreezeArgs,
+ actionHelpArgs,
+ actionInstallKeytabArgs,
+ actionInstallPackageArgs,
+ actionKeytabArgs,
+ actionKillContainerArgs,
+ actionListArgs,
+ actionLookupArgs,
+ actionNodesArgs,
+ actionPackageArgs,
+ actionRegistryArgs,
+ actionResolveArgs,
+ actionStatusArgs,
actionThawArgs,
actionUpdateArgs,
actionUpgradeArgs,
- actionDestroyArgs,
- actionExistsArgs,
- actionLookupArgs,
- actionResolveArgs,
- actionKillContainerArgs,
- actionAMSuicideArgs,
- actionInstallPackageArgs,
- actionInstallKeytabArgs,
- actionVersionArgs,
- actionHelpArgs
+ actionVersionArgs
);
}
@@ -196,6 +198,10 @@
return actionListArgs;
}
+ public ActionNodesArgs getActionNodesArgs() {
+ return actionNodesArgs;
+ }
+
public ActionLookupArgs getActionLookupArgs() {
return actionLookupArgs;
}
@@ -286,6 +292,9 @@
} else if (SliderActions.ACTION_LOOKUP.equals(action)) {
bindCoreAction(actionLookupArgs);
+ } else if (SliderActions.ACTION_NODES.equals(action)) {
+ bindCoreAction(actionNodesArgs);
+
} else if (SliderActions.ACTION_REGISTRY.equals(action)) {
bindCoreAction(actionRegistryArgs);
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/CommonArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/CommonArgs.java
index 7e02eec..162a87d 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/CommonArgs.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/CommonArgs.java
@@ -91,12 +91,12 @@
return coreAction.getClusterName();
}
- public CommonArgs(String[] args) {
+ protected CommonArgs(String[] args) {
this.args = args;
commander = new JCommander(this);
}
- public CommonArgs(Collection args) {
+ protected CommonArgs(Collection args) {
List<String> argsAsStrings = SliderUtils.collectionToStringList(args);
this.args = argsAsStrings.toArray(new String[argsAsStrings.size()]);
commander = new JCommander(this);
@@ -123,7 +123,7 @@
.append("Most commands print help when invoked without parameters or with --help");
result = helperMessage.toString();
} else {
- helperMessage.append("\nUsage: slider " + commandOfInterest);
+ helperMessage.append("\nUsage: slider ").append(commandOfInterest);
helperMessage.append(serviceArgs.coreAction.getMinParams() > 0 ? " <application>" : "");
helperMessage.append("\n");
for (ParameterDescription paramDesc : serviceArgs.commander.getCommands()
@@ -171,7 +171,7 @@
/**
* Add a command
* @param name action
- * @param arg
+ * @param arg value
*/
protected void addAction(String name, Object arg) {
commander.addCommand(name, arg);
@@ -249,7 +249,7 @@
throw new BadCommandArgumentsException(badArgMsgBuilder.toString());
} catch (UsageException e) {
StringBuilder badArgMsgBuilder = new StringBuilder();
- badArgMsgBuilder.append(e.toString() + "\n");
+ badArgMsgBuilder.append(e.toString()).append("\n");
badArgMsgBuilder.append(usage(this, coreAction.getActionName()));
throw new UsageException(badArgMsgBuilder.toString());
}
@@ -289,12 +289,6 @@
return coreAction.manager;
}
-
-// public String getRmAddress() {
-// return rmAddress;
-// }
-
-
public String getAction() {
return commander.getParsedCommand();
}
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/ComponentArgsDelegate.java b/slider-core/src/main/java/org/apache/slider/common/params/ComponentArgsDelegate.java
index 494258e..abda53f 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/ComponentArgsDelegate.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/ComponentArgsDelegate.java
@@ -34,7 +34,7 @@
arity = 2,
description = "--component <name> <count>",
splitter = DontSplitArguments.class)
- public List<String> componentTuples = new ArrayList<String>(0);
+ public List<String> componentTuples = new ArrayList<>(0);
/**
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/DontSplitArguments.java b/slider-core/src/main/java/org/apache/slider/common/params/DontSplitArguments.java
index 3225133..0344305 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/DontSplitArguments.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/DontSplitArguments.java
@@ -27,7 +27,7 @@
@Override
public List<String> split(String value) {
- List<String> list = new ArrayList<String>(1);
+ List<String> list = new ArrayList<>(1);
list.add(value);
return list;
}
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/SliderActions.java b/slider-core/src/main/java/org/apache/slider/common/params/SliderActions.java
index 54d2746..1d4e0ea 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/SliderActions.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/SliderActions.java
@@ -39,6 +39,7 @@
String ACTION_KILL_CONTAINER = "kill-container";
String ACTION_LIST = "list";
String ACTION_LOOKUP = "lookup";
+ String ACTION_NODES = "nodes";
String ACTION_PREFLIGHT = "preflight";
String ACTION_RECONFIGURE = "reconfigure";
String ACTION_REGISTRY = "registry";
@@ -80,6 +81,7 @@
"List running Slider applications";
String DESCRIBE_ACTION_LOOKUP =
"look up a YARN application";
+ String DESCRIBE_ACTION_NODES = "List the node information for the YARN cluster or a running application";
String DESCRIBE_ACTION_MONITOR =
"Monitor a running application";
String DESCRIBE_ACTION_REGISTRY =
diff --git a/slider-core/src/main/java/org/apache/slider/common/tools/Comparators.java b/slider-core/src/main/java/org/apache/slider/common/tools/Comparators.java
index 0ccca0f..6380d0c 100644
--- a/slider-core/src/main/java/org/apache/slider/common/tools/Comparators.java
+++ b/slider-core/src/main/java/org/apache/slider/common/tools/Comparators.java
@@ -21,6 +21,9 @@
import java.io.Serializable;
import java.util.Comparator;
+/**
+ * Some general comparators
+ */
public class Comparators {
public static class LongComparator implements Comparator<Long>, Serializable {
@@ -30,12 +33,20 @@
// need to comparisons with a diff greater than integer size
if (result < 0 ) {
return -1;
- } else if (result >0) {
+ } else if (result > 0) {
return 1;
}
return 0;
}
}
+public static class InvertedLongComparator implements Comparator<Long>, Serializable {
+ private static final LongComparator inner = new LongComparator();
+ @Override
+ public int compare(Long o1, Long o2) {
+ return -inner.compare(o1, o2);
+ }
+ }
+
/**
* Little template class to reverse any comparitor
diff --git a/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java b/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java
index 1f97982..712eb75 100644
--- a/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java
+++ b/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java
@@ -47,6 +47,7 @@
import org.apache.hadoop.yarn.api.records.ApplicationReport;
import org.apache.hadoop.yarn.api.records.Container;
import org.apache.hadoop.yarn.api.records.LocalResource;
+import org.apache.hadoop.yarn.api.records.NodeReport;
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
import org.apache.hadoop.yarn.client.api.AMRMClient;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
@@ -155,6 +156,7 @@
* name of docker program
*/
public static final String DOCKER = "docker";
+ public static final int NODE_LIST_LIMIT = 10;
private SliderUtils() {
}
@@ -746,10 +748,7 @@
* through
*/
public static boolean filter(String value, String filter) {
- if (StringUtils.isEmpty(filter) || filter.equals(value)) {
- return false;
- }
- return true;
+ return !(StringUtils.isEmpty(filter) || filter.equals(value));
}
/**
@@ -1776,6 +1775,19 @@
return toTruncate.substring(0, maxSize - pad.length()).concat(pad);
}
+ /**
+ * Get a string node label value from a node report
+ * @param report node report
+ * @return a single trimmed label or ""
+ */
+ public static String extractNodeLabel(NodeReport report) {
+ Set<String> newlabels = report.getNodeLabels();
+ if (newlabels != null && !newlabels.isEmpty()) {
+ return newlabels.iterator().next().trim();
+ } else {
+ return "";
+ }
+ }
/**
* Callable for async/scheduled halt
@@ -2028,10 +2040,10 @@
errorText.append("No native IO library. ");
}
try {
- String path = Shell.getQualifiedBinPath("winutils.exe");
+ String path = Shell.getQualifiedBinPath(WINUTILS);
log.debug("winutils is at {}", path);
} catch (IOException e) {
- errorText.append("No WINUTILS.EXE. ");
+ errorText.append("No " + WINUTILS);
log.warn("No winutils: {}", e, e);
}
try {
@@ -2334,6 +2346,7 @@
public static String getClientConfigPath() {
URL path = ConfigHelper.class.getClassLoader().getResource(
SliderKeys.SLIDER_CLIENT_XML);
+ Preconditions.checkNotNull(path, "Failed to locate resource " + SliderKeys.SLIDER_CLIENT_XML);
return path.toString();
}
@@ -2470,7 +2483,7 @@
* @return +ve if x is less than y, -ve if y is greater than x; 0 for equality
*/
public static int compareTwoLongsReverse(long x, long y) {
- return (x < y) ? +1 : ((x == y) ? 0 : -1);
+ return (x < y) ? 1 : ((x == y) ? 0 : -1);
}
public static String getSystemEnv(String property) {
@@ -2482,7 +2495,8 @@
}
public static String requestToString(AMRMClient.ContainerRequest request) {
- StringBuffer buffer = new StringBuffer(request.toString());
+ Preconditions.checkArgument(request != null, "Null request");
+ StringBuilder buffer = new StringBuilder(request.toString());
buffer.append("; ");
buffer.append("relaxLocality=").append(request.getRelaxLocality()).append("; ");
String labels = request.getNodeLabelExpression();
@@ -2491,9 +2505,15 @@
}
List<String> nodes = request.getNodes();
if (nodes != null) {
- buffer.append("Nodes = [")
- .append(join(nodes, ", ", false))
- .append("]; ");
+ buffer.append("Nodes = [ ");
+ int size = nodes.size();
+ for (int i = 0; i < Math.min(NODE_LIST_LIMIT, size); i++) {
+ buffer.append(nodes.get(i)).append(' ');
+ }
+ if (size > NODE_LIST_LIMIT) {
+ buffer.append(String.format("...(total %d entries)", size));
+ }
+ buffer.append("]; ");
}
List<String> racks = request.getRacks();
if (racks != null) {
diff --git a/slider-core/src/main/java/org/apache/slider/core/conf/ConfTreeOperations.java b/slider-core/src/main/java/org/apache/slider/core/conf/ConfTreeOperations.java
index bc116e7..58896ee 100644
--- a/slider-core/src/main/java/org/apache/slider/core/conf/ConfTreeOperations.java
+++ b/slider-core/src/main/java/org/apache/slider/core/conf/ConfTreeOperations.java
@@ -432,5 +432,14 @@
public void setComponentOpt(String role, String option, int val) {
setComponentOpt(role, option, Integer.toString(val));
}
+ /**
+ * Set a long role option, creating the role if necessary
+ * @param role role name
+ * @param option option name
+ * @param val long value
+ */
+ public void setComponentOpt(String role, String option, long val) {
+ setComponentOpt(role, option, Long.toString(val));
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/core/launch/CommandLineBuilder.java b/slider-core/src/main/java/org/apache/slider/core/launch/CommandLineBuilder.java
index 57b8965..dbaa981 100644
--- a/slider-core/src/main/java/org/apache/slider/core/launch/CommandLineBuilder.java
+++ b/slider-core/src/main/java/org/apache/slider/core/launch/CommandLineBuilder.java
@@ -19,11 +19,8 @@
package org.apache.slider.core.launch;
import com.google.common.base.Preconditions;
-import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.ApplicationConstants;
-import org.apache.slider.common.params.Arguments;
import org.apache.slider.common.tools.SliderUtils;
-import org.apache.slider.core.exceptions.BadConfigException;
import java.util.ArrayList;
import java.util.List;
@@ -104,56 +101,4 @@
return argumentList;
}
- public boolean addConfOption(Configuration conf, String key) {
- String val = conf.get(key);
- return defineIfSet(key, val);
- }
-
- public String addConfOptionToCLI(Configuration conf,
- String key,
- String defVal) {
- String val = conf.get(key, defVal);
- define(key, val);
- return val;
- }
-
- /**
- * Add a <code>-D key=val</code> command to the CLI
- * @param key key
- * @param val value
- */
- public void define(String key, String val) {
- Preconditions.checkArgument(key != null, "null key");
- Preconditions.checkArgument(val != null, "null value");
- add(Arguments.ARG_DEFINE, key + "=" + val);
- }
-
- /**
- * Add a <code>-D key=val</code> command to the CLI if <code>val</code>
- * is not null
- * @param key key
- * @param val value
- */
- public boolean defineIfSet(String key, String val) {
- Preconditions.checkArgument(key != null, "null key");
- if (val != null) {
- define(key, val);
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Add a mandatory config option
- * @param conf configuration
- * @param key key
- * @throws BadConfigException if the key is missing
- */
- public void addMandatoryConfOption(Configuration conf,
- String key) throws BadConfigException {
- if (!addConfOption(conf, key)) {
- throw new BadConfigException("Missing configuration option: " + key);
- }
- }
}
diff --git a/slider-core/src/main/java/org/apache/slider/core/launch/ContainerLauncher.java b/slider-core/src/main/java/org/apache/slider/core/launch/ContainerLauncher.java
index f8ea4ee..69b937d 100644
--- a/slider-core/src/main/java/org/apache/slider/core/launch/ContainerLauncher.java
+++ b/slider-core/src/main/java/org/apache/slider/core/launch/ContainerLauncher.java
@@ -55,17 +55,13 @@
public UserGroupInformation setupUGI() {
UserGroupInformation user =
UserGroupInformation.createRemoteUser(container.getId().toString());
- String cmIpPortStr =
- container.getNodeId().getHost() + ":" + container.getNodeId().getPort();
- final InetSocketAddress cmAddress =
- NetUtils.createSocketAddr(cmIpPortStr);
+ String cmIpPortStr = container.getNodeId().getHost() + ":" + container.getNodeId().getPort();
+ final InetSocketAddress cmAddress = NetUtils.createSocketAddr(cmIpPortStr);
- org.apache.hadoop.yarn.api.records.Token containerToken =
- container.getContainerToken();
+ org.apache.hadoop.yarn.api.records.Token containerToken = container.getContainerToken();
if (containerToken != null) {
Token<ContainerTokenIdentifier> token =
- ConverterUtils.convertFromYarn(containerToken,
- cmAddress);
+ ConverterUtils.convertFromYarn(containerToken, cmAddress);
user.addToken(token);
}
return user;
diff --git a/slider-core/src/main/java/org/apache/slider/core/launch/JavaCommandLineBuilder.java b/slider-core/src/main/java/org/apache/slider/core/launch/JavaCommandLineBuilder.java
index 0b3fa10..dcb322e 100644
--- a/slider-core/src/main/java/org/apache/slider/core/launch/JavaCommandLineBuilder.java
+++ b/slider-core/src/main/java/org/apache/slider/core/launch/JavaCommandLineBuilder.java
@@ -20,11 +20,15 @@
import com.google.common.base.Preconditions;
+import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.ApplicationConstants;
import org.apache.slider.common.tools.SliderUtils;
+import org.apache.slider.core.exceptions.BadConfigException;
/**
- * Command line builder purely for the Java CLI
+ * Command line builder purely for the Java CLI.
+ * Some of the <code>define</code> methods are designed to work with Hadoop tool and
+ * Slider launcher applications.
*/
public class JavaCommandLineBuilder extends CommandLineBuilder {
@@ -80,4 +84,68 @@
sysprop("java.awt.headless", "true");
return this;
}
+
+ public boolean addConfOption(Configuration conf, String key) {
+ return defineIfSet(key, conf.get(key));
+ }
+
+ /**
+ * Add a varargs list of configuration parameters —if they are present
+ * @param conf configuration source
+ * @param keys keys
+ */
+ public void addConfOptions(Configuration conf, String...keys) {
+ for (String key : keys) {
+ addConfOption(conf, key);
+ }
+ }
+
+ public String addConfOptionToCLI(Configuration conf,
+ String key,
+ String defVal) {
+ String val = conf.get(key, defVal);
+ define(key, val);
+ return val;
+ }
+
+ /**
+ * Add a <code>-D key=val</code> command to the CLI. This is very Hadoop API
+ * @param key key
+ * @param val value
+ */
+ public void define(String key, String val) {
+ Preconditions.checkArgument(key != null, "null key");
+ Preconditions.checkArgument(val != null, "null value");
+ add("-D", key + "=" + val);
+ }
+
+ /**
+ * Add a <code>-D key=val</code> command to the CLI if <code>val</code>
+ * is not null
+ * @param key key
+ * @param val value
+ */
+ public boolean defineIfSet(String key, String val) {
+ Preconditions.checkArgument(key != null, "null key");
+ if (val != null) {
+ define(key, val);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Add a mandatory config option
+ * @param conf configuration
+ * @param key key
+ * @throws BadConfigException if the key is missing
+ */
+ public void addMandatoryConfOption(Configuration conf,
+ String key) throws BadConfigException {
+ if (!addConfOption(conf, key)) {
+ throw new BadConfigException("Missing configuration option: " + key);
+ }
+ }
+
}
diff --git a/slider-core/src/main/java/org/apache/slider/core/persist/ConfPersister.java b/slider-core/src/main/java/org/apache/slider/core/persist/ConfPersister.java
index 60717f6..9759205 100644
--- a/slider-core/src/main/java/org/apache/slider/core/persist/ConfPersister.java
+++ b/slider-core/src/main/java/org/apache/slider/core/persist/ConfPersister.java
@@ -101,7 +101,7 @@
* Make the persistent directory
* @throws IOException IO failure
*/
- private void mkPersistDir() throws IOException {
+ public void mkPersistDir() throws IOException {
coreFS.getFileSystem().mkdirs(persistDir);
}
@@ -165,13 +165,15 @@
* Acquire the writelock
* @throws IOException IO
* @throws LockAcquireFailedException
- * @throws FileNotFoundException if the target dir does not exist
+ * @throws FileNotFoundException if the target dir does not exist.
*/
@VisibleForTesting
boolean acquireReadLock() throws FileNotFoundException,
IOException,
LockAcquireFailedException {
if (!coreFS.getFileSystem().exists(persistDir)) {
+ // the dir is not there, so the data is not there, so there
+ // is nothing to read
throw new FileNotFoundException(persistDir.toString());
}
long now = System.currentTimeMillis();
diff --git a/slider-core/src/main/java/org/apache/slider/core/persist/JsonSerDeser.java b/slider-core/src/main/java/org/apache/slider/core/persist/JsonSerDeser.java
index c5908bb..4f60c06 100644
--- a/slider-core/src/main/java/org/apache/slider/core/persist/JsonSerDeser.java
+++ b/slider-core/src/main/java/org/apache/slider/core/persist/JsonSerDeser.java
@@ -91,10 +91,11 @@
*/
public T fromFile(File jsonFile)
throws IOException, JsonParseException, JsonMappingException {
+ File absoluteFile = jsonFile.getAbsoluteFile();
try {
- return mapper.readValue(jsonFile, classType);
+ return mapper.readValue(absoluteFile, classType);
} catch (IOException e) {
- log.error("Exception while parsing json file {}: {}", jsonFile, e);
+ log.error("Exception while parsing json file {}", absoluteFile, e);
throw e;
}
}
@@ -106,7 +107,6 @@
* @throws IOException IO problems
* @throws JsonMappingException failure to map from the JSON to this class
*/
-/* JDK7
public T fromResource(String resource)
throws IOException, JsonParseException, JsonMappingException {
try(InputStream resStream = this.getClass().getResourceAsStream(resource)) {
@@ -115,34 +115,9 @@
}
return (T) (mapper.readValue(resStream, classType));
} catch (IOException e) {
- log.error("Exception while parsing json resource {}: {}", resource, e);
+ log.error("Exception while parsing json resource {}", resource, e);
throw e;
}
- }*/
-
- /**
- * Convert from a JSON file
- * @param resource input file
- * @return the parsed JSON
- * @throws IOException IO problems
- * @throws JsonMappingException failure to map from the JSON to this class
- */
- @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
- public synchronized T fromResource(String resource)
- throws IOException, JsonParseException, JsonMappingException {
- InputStream resStream = null;
- try {
- resStream = this.getClass().getResourceAsStream(resource);
- if (resStream == null) {
- throw new FileNotFoundException(resource);
- }
- return (T) (mapper.readValue(resStream, classType));
- } catch (IOException e) {
- log.error("Exception while parsing json resource {}: {}", resource, e);
- throw e;
- } finally {
- IOUtils.closeStream(resStream);
- }
}
/**
@@ -155,7 +130,7 @@
try {
return (T) (mapper.readValue(stream, classType));
} catch (IOException e) {
- log.error("Exception while parsing json input stream: {}", e);
+ log.error("Exception while parsing json input stream", e);
throw e;
} finally {
IOUtils.closeStream(stream);
@@ -201,7 +176,7 @@
FSDataInputStream dataInputStream = fs.open(path);
int count = dataInputStream.read(b);
if (count != len) {
- throw new EOFException("Read finished prematurely");
+ throw new EOFException("Read of " + path +" finished prematurely");
}
return fromBytes(b);
}
@@ -230,9 +205,9 @@
*/
public void save(T instance, File file) throws
IOException {
- writeJsonAsBytes(instance, new FileOutputStream(file));
+ writeJsonAsBytes(instance, new FileOutputStream(file.getAbsoluteFile()));
}
-
+
/**
* Write the json as bytes -then close the file
* @param dataOutputStream an outout stream that will always be closed
@@ -251,7 +226,6 @@
}
}
-
/**
* Convert an object to a JSON string
* @param instance instance to convert
@@ -265,6 +239,5 @@
mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
return mapper.writeValueAsString(instance);
}
-
-
+
}
diff --git a/slider-core/src/main/java/org/apache/slider/providers/AbstractProviderService.java b/slider-core/src/main/java/org/apache/slider/providers/AbstractProviderService.java
index 7cba840..c701a55 100644
--- a/slider-core/src/main/java/org/apache/slider/providers/AbstractProviderService.java
+++ b/slider-core/src/main/java/org/apache/slider/providers/AbstractProviderService.java
@@ -81,7 +81,7 @@
protected YarnRegistryViewForProviders yarnRegistry;
protected QueueAccess queueAccess;
- public AbstractProviderService(String name) {
+ protected AbstractProviderService(String name) {
super(name);
setStopIfNoChildServicesAtStartup(false);
}
@@ -343,12 +343,6 @@
return details;
}
-
- protected String getInfoAvoidingNull(ClusterDescription clusterDesc, String key) {
- String value = clusterDesc.getInfo(key);
-
- return null == value ? "N/A" : value;
- }
@Override
public void buildEndpointDetails(Map<String, String> details) {
@@ -363,10 +357,8 @@
if (!urls.isEmpty()) {
details.put(endpoint.api, urls.get(0).toString());
}
- } catch (InvalidRecordException ignored) {
+ } catch (InvalidRecordException | MalformedURLException ignored) {
// Ignored
- } catch (MalformedURLException ignored) {
- // ignored
}
}
diff --git a/slider-core/src/main/java/org/apache/slider/providers/PlacementPolicy.java b/slider-core/src/main/java/org/apache/slider/providers/PlacementPolicy.java
index 4e85a93..71d7566 100644
--- a/slider-core/src/main/java/org/apache/slider/providers/PlacementPolicy.java
+++ b/slider-core/src/main/java/org/apache/slider/providers/PlacementPolicy.java
@@ -27,7 +27,12 @@
/**
* Default value: history used, anti-affinity hinted at on rebuild/flex up
*/
- public static final int DEFAULT = 0;
+ public static final int NONE = 0;
+
+ /**
+ * Default value: history used, anti-affinity hinted at on rebuild/flex up
+ */
+ public static final int DEFAULT = NONE;
/**
* Strict placement: when asking for an instance for which there is
@@ -41,7 +46,7 @@
public static final int NO_DATA_LOCALITY = 2;
/**
- * Anti-affinity is mandatory. This is not supported in YARN
+ * Anti-affinity is mandatory.
*/
public static final int ANTI_AFFINITY_REQUIRED = 4;
diff --git a/slider-core/src/main/java/org/apache/slider/providers/ProviderRole.java b/slider-core/src/main/java/org/apache/slider/providers/ProviderRole.java
index 3009f50..1b95b42 100644
--- a/slider-core/src/main/java/org/apache/slider/providers/ProviderRole.java
+++ b/slider-core/src/main/java/org/apache/slider/providers/ProviderRole.java
@@ -32,13 +32,15 @@
public int placementPolicy;
public int nodeFailureThreshold;
public final long placementTimeoutSeconds;
+ public final String labelExpression;
public ProviderRole(String name, int id) {
this(name,
id,
PlacementPolicy.DEFAULT,
ResourceKeys.DEFAULT_NODE_FAILURE_THRESHOLD,
- ResourceKeys.DEFAULT_PLACEMENT_ESCALATE_DELAY_SECONDS);
+ ResourceKeys.DEFAULT_PLACEMENT_ESCALATE_DELAY_SECONDS,
+ ResourceKeys.DEF_YARN_LABEL_EXPRESSION);
}
/**
@@ -49,18 +51,20 @@
* @param nodeFailureThreshold threshold for node failures (within a reset interval)
* after which a node failure is considered an app failure
* @param placementTimeoutSeconds for lax placement, timeout in seconds before
- * a relaxed placement request is generated.
+ * @param labelExpression label expression for requests; may be null
*/
public ProviderRole(String name,
int id,
int policy,
int nodeFailureThreshold,
- long placementTimeoutSeconds) {
+ long placementTimeoutSeconds,
+ String labelExpression) {
this.name = name;
this.id = id;
this.placementPolicy = policy;
this.nodeFailureThreshold = nodeFailureThreshold;
this.placementTimeoutSeconds = placementTimeoutSeconds;
+ this.labelExpression = labelExpression;
}
@Override
@@ -83,11 +87,14 @@
@Override
public String toString() {
- return "ProviderRole {" +
- "name='" + name + '\'' +
- ", id=" + id +
- ", policy=" + placementPolicy +
- ", nodeFailureThreshold=" + nodeFailureThreshold +
- '}';
+ final StringBuilder sb = new StringBuilder("ProviderRole{");
+ sb.append("name='").append(name).append('\'');
+ sb.append(", id=").append(id);
+ sb.append(", placementPolicy=").append(placementPolicy);
+ sb.append(", nodeFailureThreshold=").append(nodeFailureThreshold);
+ sb.append(", placementTimeoutSeconds=").append(placementTimeoutSeconds);
+ sb.append(", labelExpression='").append(labelExpression).append('\'');
+ sb.append('}');
+ return sb.toString();
}
}
diff --git a/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMClientProvider.java b/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMClientProvider.java
index 9bd4dc9..e5430f2 100644
--- a/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMClientProvider.java
+++ b/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMClientProvider.java
@@ -90,7 +90,7 @@
new ProviderRole(COMPONENT_AM, KEY_AM,
PlacementPolicy.EXCLUDE_FROM_FLEXING,
ResourceKeys.DEFAULT_NODE_FAILURE_THRESHOLD,
- 0);
+ 0, "");
/**
* Initialize role list
@@ -218,11 +218,12 @@
* @param instanceDescription
* @param providerResources
* @throws IOException
+ * @throws BadConfigException if there's no keytab and it is explicitly required.
*/
protected void addKeytabResourceIfNecessary(SliderFileSystem fileSystem,
AggregateConf instanceDescription,
Map<String, LocalResource> providerResources)
- throws IOException {
+ throws IOException, BadConfigException {
if (UserGroupInformation.isSecurityEnabled()) {
String keytabPathOnHost = instanceDescription.getAppConfOperations()
.getComponent(SliderKeys.COMPONENT_AM).get(
@@ -243,10 +244,16 @@
providerResources.put(SliderKeys.KEYTAB_DIR + "/" +
amKeytabName, keytabRes);
} else {
- log.warn("No keytab file was found at {}. The AM will be "
- + "started without a kerberos authenticated identity. "
- + "The application is therefore not guaranteed to remain "
- + "operational beyond 24 hours.", keytabPath);
+ log.warn("No keytab file was found at {}.", keytabPath);
+ if (getConf().getBoolean(KEY_AM_LOGIN_KEYTAB_REQUIRED, false)) {
+ throw new BadConfigException("No keytab file was found at %s.", keytabPath);
+
+ } else {
+ log.warn("The AM will be "
+ + "started without a kerberos authenticated identity. "
+ + "The application is therefore not guaranteed to remain "
+ + "operational beyond 24 hours.");
+ }
}
}
}
diff --git a/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMProviderService.java b/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMProviderService.java
index cee7a97..e382058 100644
--- a/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMProviderService.java
+++ b/slider-core/src/main/java/org/apache/slider/providers/slideram/SliderAMProviderService.java
@@ -88,12 +88,11 @@
MapOperations resourceComponent,
MapOperations appComponent,
Path containerTmpDirPath) throws IOException, SliderException {
-
}
@Override
public List<ProviderRole> getRoles() {
- return new ArrayList<ProviderRole>(0);
+ return new ArrayList<>(0);
}
@Override
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/ProtobufClusterServices.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/ProtobufClusterServices.java
index 50b5dad..5d52441 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/ProtobufClusterServices.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/ProtobufClusterServices.java
@@ -20,6 +20,7 @@
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.util.Records;
+import org.apache.hadoop.yarn.util.resource.Resources;
import org.apache.slider.server.appmaster.state.AbstractClusterServices;
public class ProtobufClusterServices extends AbstractClusterServices {
@@ -27,4 +28,9 @@
public Resource newResource() {
return Records.newRecord(Resource.class);
}
+
+ @Override
+ public Resource newResource(int memory, int cores) {
+ return Resources.createResource(memory, cores);
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
index fd9253e..18d5bfa 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
@@ -57,6 +57,7 @@
import org.apache.hadoop.yarn.api.records.ContainerStatus;
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
import org.apache.hadoop.yarn.api.records.NodeReport;
+import org.apache.hadoop.yarn.api.records.NodeState;
import org.apache.hadoop.yarn.api.records.Priority;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.client.api.AMRMClient;
@@ -64,6 +65,7 @@
import org.apache.hadoop.yarn.client.api.async.NMClientAsync;
import org.apache.hadoop.yarn.client.api.async.impl.NMClientAsyncImpl;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import static org.apache.hadoop.yarn.conf.YarnConfiguration.*;
import org.apache.hadoop.yarn.exceptions.InvalidApplicationMasterRequestException;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.ipc.YarnRPC;
@@ -84,6 +86,7 @@
import org.apache.slider.api.RoleKeys;
import org.apache.slider.api.StatusKeys;
import org.apache.slider.api.proto.SliderClusterAPI;
+import org.apache.slider.client.SliderYarnClientImpl;
import org.apache.slider.common.SliderExitCodes;
import org.apache.slider.common.SliderKeys;
import org.apache.slider.common.params.AbstractActionArgs;
@@ -143,6 +146,7 @@
import org.apache.slider.server.appmaster.rpc.SliderIPCService;
import org.apache.slider.server.appmaster.security.SecurityConfiguration;
import org.apache.slider.server.appmaster.state.AppState;
+import org.apache.slider.server.appmaster.state.AppStateBindingInfo;
import org.apache.slider.server.appmaster.state.ContainerAssignment;
import org.apache.slider.server.appmaster.state.ProviderAppState;
import org.apache.slider.server.appmaster.operations.RMOperationHandler;
@@ -168,6 +172,7 @@
import java.io.File;
import java.io.IOException;
+import java.net.BindException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URL;
@@ -210,8 +215,7 @@
*/
protected static final Logger LOG_YARN = log;
- public static final String SERVICE_CLASSNAME_SHORT =
- "SliderAppMaster";
+ public static final String SERVICE_CLASSNAME_SHORT = "SliderAppMaster";
public static final String SERVICE_CLASSNAME =
"org.apache.slider.server.appmaster." + SERVICE_CLASSNAME_SHORT;
@@ -356,16 +360,6 @@
private RegistryOperations registryOperations;
/**
- * Record of the max no. of cores allowed in this cluster
- */
- private int containerMaxCores;
-
- /**
- * limit container memory
- */
- private int containerMaxMemory;
-
- /**
* The stop request received...the exit details are extracted
* from this
*/
@@ -415,6 +409,12 @@
*/
private boolean securityEnabled;
private ContentCache contentCache;
+ private SliderYarnClientImpl yarnClient;
+
+ /**
+ * resource limits
+ */
+ private Resource maximumResourceCapability;
/**
* Service Constructor
@@ -437,10 +437,8 @@
// Load in the server configuration - if it is actually on the Classpath
URL serverXmlUrl = ConfigHelper.getResourceUrl(SLIDER_SERVER_XML);
if (serverXmlUrl != null) {
-
log.info("Loading {} at {}", SLIDER_SERVER_XML, serverXmlUrl);
- Configuration serverConf =
- ConfigHelper.loadFromResource(SLIDER_SERVER_XML);
+ Configuration serverConf = ConfigHelper.loadFromResource(SLIDER_SERVER_XML);
ConfigHelper.mergeConfigurations(customConf, serverConf,
SLIDER_SERVER_XML, true);
}
@@ -496,8 +494,7 @@
metrics.registerAll(new GarbageCollectorMetricSet());
*/
- contentCache = ApplicationResouceContentCacheFactory.createContentCache(
- stateForProviders);
+ contentCache = ApplicationResouceContentCacheFactory.createContentCache(stateForProviders);
executorService = new WorkflowExecutorService<>("AmExecutor",
Executors.newFixedThreadPool(2,
@@ -505,7 +502,7 @@
addService(executorService);
addService(actionQueues);
-
+
//init all child services
super.serviceInit(conf);
}
@@ -536,8 +533,7 @@
* @param args argument list
*/
@Override // RunService
- public Configuration bindArgs(Configuration config, String... args) throws
- Exception {
+ public Configuration bindArgs(Configuration config, String... args) throws Exception {
// let the superclass process it
Configuration superConf = super.bindArgs(config, args);
// add the slider XML config
@@ -564,8 +560,7 @@
//dump the system properties if in debug mode
if (log.isDebugEnabled()) {
- log.debug("System properties:\n" +
- SliderUtils.propertiesToString(System.getProperties()));
+ log.debug("System properties:\n" + SliderUtils.propertiesToString(System.getProperties()));
}
//choose the action
@@ -630,13 +625,11 @@
Configuration serviceConf = getConfig();
- securityConfiguration = new SecurityConfiguration(
- serviceConf, instanceDefinition, clustername);
+ securityConfiguration = new SecurityConfiguration(serviceConf, instanceDefinition, clustername);
// obtain security state
securityEnabled = securityConfiguration.isSecurityEnabled();
// set the global security flag for the instance definition
- instanceDefinition.getAppConfOperations().set(
- KEY_SECURITY_ENABLED, securityEnabled);
+ instanceDefinition.getAppConfOperations().set(KEY_SECURITY_ENABLED, securityEnabled);
// triggers resolution and snapshotting for agent
appState.setInitialInstanceDefinition(instanceDefinition);
@@ -654,44 +647,53 @@
InternalKeys.INTERNAL_PROVIDER_NAME);
log.info("Cluster provider type is {}", providerType);
SliderProviderFactory factory =
- SliderProviderFactory.createSliderProviderFactory(
- providerType);
+ SliderProviderFactory.createSliderProviderFactory(providerType);
providerService = factory.createServerProvider();
// init the provider BUT DO NOT START IT YET
initAndAddService(providerService);
- providerRMOperationHandler =
- new ProviderNotifyingOperationHandler(providerService);
+ providerRMOperationHandler = new ProviderNotifyingOperationHandler(providerService);
// create a slider AM provider
sliderAMProvider = new SliderAMProviderService();
initAndAddService(sliderAMProvider);
- InetSocketAddress address = SliderUtils.getRmSchedulerAddress(serviceConf);
- log.info("RM is at {}", address);
+ InetSocketAddress rmSchedulerAddress = SliderUtils.getRmSchedulerAddress(serviceConf);
+ log.info("RM is at {}", rmSchedulerAddress);
yarnRPC = YarnRPC.create(serviceConf);
+ // set up the YARN client. This may require patching in the RM client-API address if it
+ // is (somehow) unset server-side. String clientRMaddr = serviceConf.get(YarnConfiguration.RM_ADDRESS);
+ InetSocketAddress clientRpcAddress = SliderUtils.getRmAddress(serviceConf);
+ if (!SliderUtils.isAddressDefined(clientRpcAddress)) {
+ // client addr is being unset. We can lift it from the other RM APIs
+ log.warn("Yarn RM address was unbound; attempting to fix up");
+ serviceConf.set(YarnConfiguration.RM_ADDRESS,
+ String.format("%s:%d", rmSchedulerAddress.getHostString(), clientRpcAddress.getPort() ));
+ }
+ initAndAddService(yarnClient = new SliderYarnClientImpl());
+ yarnClient.start();
+
/*
* Extract the container ID. This is then
* turned into an (incompete) container
*/
appMasterContainerID = ConverterUtils.toContainerId(
- SliderUtils.mandatoryEnvVariable(
- ApplicationConstants.Environment.CONTAINER_ID.name()));
+ SliderUtils.mandatoryEnvVariable(ApplicationConstants.Environment.CONTAINER_ID.name()));
appAttemptID = appMasterContainerID.getApplicationAttemptId();
ApplicationId appid = appAttemptID.getApplicationId();
log.info("AM for ID {}", appid.getId());
- appInformation.put(StatusKeys.INFO_AM_CONTAINER_ID,
- appMasterContainerID.toString());
- appInformation.put(StatusKeys.INFO_AM_APP_ID,
- appid.toString());
- appInformation.put(StatusKeys.INFO_AM_ATTEMPT_ID,
- appAttemptID.toString());
+ appInformation.put(StatusKeys.INFO_AM_CONTAINER_ID, appMasterContainerID.toString());
+ appInformation.put(StatusKeys.INFO_AM_APP_ID, appid.toString());
+ appInformation.put(StatusKeys.INFO_AM_ATTEMPT_ID, appAttemptID.toString());
Map<String, String> envVars;
List<Container> liveContainers;
+ List<NodeReport> nodeReports = yarnClient.getNodeReports(NodeState.RUNNING);
+ log.info("Yarn node report count: {}", nodeReports.size());
+
/*
* It is critical this section is synchronized, to stop async AM events
* arriving while registering a restarting AM.
@@ -715,7 +717,7 @@
if (securityEnabled) {
// fix up the ACLs if they are not set
- String acls = getConfig().get(KEY_PROTOCOL_ACL);
+ String acls = serviceConf.get(KEY_PROTOCOL_ACL);
if (acls == null) {
getConfig().set(KEY_PROTOCOL_ACL, "*");
}
@@ -731,8 +733,7 @@
appMasterHostname = rpcServiceAddress.getHostName();
appMasterRpcPort = rpcServiceAddress.getPort();
appMasterTrackingUrl = null;
- log.info("AM Server is listening at {}:{}", appMasterHostname,
- appMasterRpcPort);
+ log.info("AM Server is listening at {}:{}", appMasterHostname, appMasterRpcPort);
appInformation.put(StatusKeys.INFO_AM_HOSTNAME, appMasterHostname);
appInformation.set(StatusKeys.INFO_AM_RPC_PORT, appMasterRpcPort);
@@ -776,24 +777,27 @@
// *****************************************************
log.info("Connecting to RM at {},address tracking URL={}",
appMasterRpcPort, appMasterTrackingUrl);
- amRegistrationData = asyncRMClient
- .registerApplicationMaster(appMasterHostname,
+ amRegistrationData = asyncRMClient.registerApplicationMaster(appMasterHostname,
appMasterRpcPort,
appMasterTrackingUrl);
- Resource maxResources =
- amRegistrationData.getMaximumResourceCapability();
- containerMaxMemory = maxResources.getMemory();
- containerMaxCores = maxResources.getVirtualCores();
- appState.setContainerLimits(maxResources.getMemory(),
- maxResources.getVirtualCores());
+ maximumResourceCapability = amRegistrationData.getMaximumResourceCapability();
+
+ int minMemory = serviceConf.getInt(RM_SCHEDULER_MINIMUM_ALLOCATION_MB,
+ DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_MB);
+ // validate scheduler vcores allocation setting
+ int minCores = serviceConf.getInt(RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES,
+ DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES);
+ int maxMemory = maximumResourceCapability.getMemory();
+ int maxCores = maximumResourceCapability.getVirtualCores();
+ appState.setContainerLimits(minMemory,maxMemory, minCores, maxCores );
// build the handler for RM request/release operations; this uses
// the max value as part of its lookup
- rmOperationHandler = new AsyncRMOperationHandler(asyncRMClient, maxResources);
+ rmOperationHandler = new AsyncRMOperationHandler(asyncRMClient, maximumResourceCapability);
// set the RM-defined maximum cluster values
- appInformation.put(ResourceKeys.YARN_CORES, Integer.toString(containerMaxCores));
- appInformation.put(ResourceKeys.YARN_MEMORY, Integer.toString(containerMaxMemory));
+ appInformation.put(ResourceKeys.YARN_CORES, Integer.toString(maxCores));
+ appInformation.put(ResourceKeys.YARN_MEMORY, Integer.toString(maxMemory));
processAMCredentials(securityConfiguration);
@@ -837,15 +841,18 @@
Path historyDir = new Path(clusterDirPath, HISTORY_DIR_NAME);
//build the instance
- appState.buildInstance(instanceDefinition,
- serviceConf,
- providerConf,
- providerRoles,
- fs.getFileSystem(),
- historyDir,
- liveContainers,
- appInformation,
- providerService.createContainerReleaseSelector());
+ AppStateBindingInfo binding = new AppStateBindingInfo();
+ binding.instanceDefinition = instanceDefinition;
+ binding.serviceConfig = serviceConf;
+ binding.publishedProviderConf = providerConf;
+ binding.roles = providerRoles;
+ binding.fs = fs.getFileSystem();
+ binding.historyPath = historyDir;
+ binding.liveContainers = liveContainers;
+ binding.applicationInfo = appInformation;
+ binding.releaseSelector = providerService.createContainerReleaseSelector();
+ binding.nodeReports = nodeReports;
+ appState.buildInstance(binding);
providerService.rebuildContainerDetails(liveContainers,
instanceDefinition.getName(), appState.getRolePriorityMap());
@@ -1877,7 +1884,15 @@
LOG_YARN.info("onNodesUpdated({})", updatedNodes.size());
log.info("Updated nodes {}", updatedNodes);
// Check if any nodes are lost or revived and update state accordingly
- appState.onNodesUpdated(updatedNodes);
+
+ AppState.NodeUpdatedOutcome outcome = appState.onNodesUpdated(updatedNodes);
+ if (!outcome.operations.isEmpty()) {
+ execute(outcome.operations);
+ }
+ // trigger a review if the cluster changed
+ if (outcome.clusterChanged) {
+ reviewRequestAndReleaseNodes("nodes updated");
+ }
}
/**
@@ -1937,15 +1952,6 @@
/* =================================================================== */
/**
- * Update the cluster description with anything interesting
- */
- public synchronized ClusterDescription updateClusterStatus() {
- Map<String, String> providerStatus = providerService.buildProviderStatus();
- assert providerStatus != null : "null provider status";
- return appState.refreshClusterStatus(providerStatus);
- }
-
- /**
* Launch the provider service
*
* @param instanceDefinition definition of the service
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/actions/ActionKillContainer.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/actions/ActionKillContainer.java
index 1aa9088..7446e82 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/actions/ActionKillContainer.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/actions/ActionKillContainer.java
@@ -77,7 +77,7 @@
public void execute(SliderAppMaster appMaster,
QueueAccess queueService,
AppState appState) throws Exception {
- List<AbstractRMOperation> opsList = new LinkedList<AbstractRMOperation>();
+ List<AbstractRMOperation> opsList = new LinkedList<>();
ContainerReleaseOperation release = new ContainerReleaseOperation(containerId);
opsList.add(release);
//now apply the operations
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/actions/QueueService.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/actions/QueueService.java
index 146dea4..34acade 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/actions/QueueService.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/actions/QueueService.java
@@ -58,20 +58,20 @@
* Immediate actions.
*/
public final BlockingDeque<AsyncAction> actionQueue =
- new LinkedBlockingDeque<AsyncAction>();
+ new LinkedBlockingDeque<>();
/**
* Actions to be scheduled in the future
*/
- public final DelayQueue<AsyncAction> scheduledActions = new DelayQueue<AsyncAction>();
+ public final DelayQueue<AsyncAction> scheduledActions = new DelayQueue<>();
/**
* Map of renewing actions by name ... this is to allow them to
* be cancelled by name
*/
private final Map<String, RenewingAction<? extends AsyncAction>> renewingActions
- = new ConcurrentHashMap<String, RenewingAction<? extends AsyncAction>>();
-
+ = new ConcurrentHashMap<>();
+
/**
* Create a queue instance with a single thread executor
*/
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/BoolMetricPredicate.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/BoolMetricPredicate.java
new file mode 100644
index 0000000..82bcd3a
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/BoolMetricPredicate.java
@@ -0,0 +1,44 @@
+/*
+ * 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.slider.server.appmaster.management;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Metric;
+
+/**
+ * A metric which takes a predicate and returns 1 if the predicate evaluates
+ * to true. The predicate is evaluated whenever the metric is read.
+ */
+public class BoolMetricPredicate implements Metric, Gauge<Integer> {
+
+ private final Eval predicate;
+
+ public BoolMetricPredicate(Eval predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public Integer getValue() {
+ return predicate.eval() ? 1: 0;
+ }
+
+ public interface Eval {
+ boolean eval();
+ }
+}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/LongGauge.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/LongGauge.java
index 08f61ec..c93467b 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/LongGauge.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/LongGauge.java
@@ -24,69 +24,75 @@
import java.util.concurrent.atomic.AtomicLong;
/**
- * This is a long which acts as a gauge
+ * This is a {@link AtomicLong} which acts as a metrics gauge: its state can be exposed as
+ * a metrics.
+ * It also exposes some of the same method names as the Codahale Counter class, so that
+ * it's easy to swap in.
+ *
*/
-public class LongGauge implements Metric, Gauge<Long> {
-
- private final AtomicLong value;
+public class LongGauge extends AtomicLong implements Metric, Gauge<Long> {
/**
* Instantiate
* @param val current value
*/
public LongGauge(long val) {
- this.value = new AtomicLong(val);
+ super(val);
}
+ /**
+ * Instantiate with value 0
+ */
public LongGauge() {
this(0);
}
/**
- * Set to a new value.
- * @param val value
+ * Get the value as a metric
+ * @return current value
*/
- public synchronized void set(long val) {
- value.set(val);
- }
-
- public void inc() {
- inc(1);
- }
-
- public void dec() {
- dec(1);
- }
-
- public synchronized void inc(int delta) {
- set(value.get() + delta);
- }
-
- public synchronized void dec(int delta) {
- set(value.get() - delta);
- }
-
- public long get() {
- return value.get();
- }
-
@Override
public Long getValue() {
return get();
}
- @Override
- public String toString() {
- return value.toString();
+ /**
+ * Method from {@Code counter}; used here for drop-in replacement
+ * without any recompile
+ * @return current value
+ */
+ public Long getCount() {
+ return get();
}
- @Override
- public int hashCode() {
- return value.hashCode();
+ /**
+ * {@code ++}
+ */
+ public void inc() {
+ incrementAndGet();
}
- @Override
- public boolean equals(Object obj) {
- return value.equals(obj);
+ /**
+ * {@code --}
+ */
+ public void dec() {
+ decrementAndGet();
+ }
+
+ /**
+ * Decrement to the floor of 0. Operations in parallel may cause confusion here,
+ * but it will still never go below zero
+ * @param delta delta
+ * @return the current value
+ */
+ public long decToFloor(long delta) {
+ long l = get();
+ long r = l - delta;
+ if (r < 0) {
+ r = 0;
+ }
+ // if this fails, the decrement has been lost
+ compareAndSet(l, r);
+ return get();
}
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/LongMetricFunction.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/LongMetricFunction.java
new file mode 100644
index 0000000..1de7345
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/LongMetricFunction.java
@@ -0,0 +1,44 @@
+/*
+ * 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.slider.server.appmaster.management;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Metric;
+
+/**
+ * A metric which takes a function to generate a long value.
+ * The function is evaluated whenever the metric is read.
+ */
+public class LongMetricFunction implements Metric, Gauge<Long> {
+
+ private final Eval function;
+
+ public LongMetricFunction(Eval function) {
+ this.function = function;
+ }
+
+ @Override
+ public Long getValue() {
+ return function.eval();
+ }
+
+ public interface Eval {
+ long eval();
+ }
+}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsAndMonitoring.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsAndMonitoring.java
index cced42a..37a8935 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsAndMonitoring.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsAndMonitoring.java
@@ -20,9 +20,12 @@
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.MetricSet;
import com.codahale.metrics.health.HealthCheckRegistry;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.service.CompositeService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
@@ -33,7 +36,8 @@
* Class for all metrics and monitoring
*/
public class MetricsAndMonitoring extends CompositeService {
-
+ protected static final Logger log =
+ LoggerFactory.getLogger(MetricsAndMonitoring.class);
public MetricsAndMonitoring(String name) {
super(name);
}
@@ -52,13 +56,15 @@
private final Map<String, MeterAndCounter> meterAndCounterMap
= new ConcurrentHashMap<>();
+ private final List<MetricSet> metricSets = new ArrayList<>();
+
/**
* List of recorded events
*/
private final List<RecordedEvent> eventHistory = new ArrayList<>(100);
public static final int EVENT_LIMIT = 1000;
-
+
public MetricRegistry getMetrics() {
return metrics;
}
@@ -74,6 +80,14 @@
super.serviceInit(conf);
}
+ @Override
+ protected void serviceStop() throws Exception {
+ super.serviceStop();
+ for (MetricSet set : metricSets) {
+ unregister(set);
+ }
+ }
+
public MeterAndCounter getMeterAndCounter(String name) {
return meterAndCounterMap.get(name);
}
@@ -144,5 +158,38 @@
public synchronized List<RecordedEvent> cloneEventHistory() {
return new ArrayList<>(eventHistory);
}
+
+ /**
+ * Add a metric set for registering and deregistration on service stop
+ * @param metricSet metric set
+ */
+ public void addMetricSet(MetricSet metricSet) {
+ metricSets.add(metricSet);
+ metrics.registerAll(metricSet);
+ }
+
+ /**
+ * add a metric set, giving each entry a prefix
+ * @param prefix prefix (a trailing "." is automatically added)
+ * @param metricSet the metric set to register
+ */
+ public void addMetricSet(String prefix, MetricSet metricSet) {
+ addMetricSet(new PrefixedMetricsSet(prefix, metricSet));
+ }
+
+ /**
+ * Unregister a metric set; robust
+ * @param metricSet metric set to unregister
+ */
+ public void unregister(MetricSet metricSet) {
+ for (String s : metricSet.getMetrics().keySet()) {
+ try {
+ metrics.remove(s);
+ } catch (IllegalArgumentException e) {
+ // log but continue
+ log.info("Exception when trying to unregister {}", s, e);
+ }
+ }
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsBindingService.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsBindingService.java
index f8646bf..864a1cf 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsBindingService.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsBindingService.java
@@ -19,7 +19,9 @@
package org.apache.slider.server.appmaster.management;
import com.codahale.metrics.JmxReporter;
+import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.MetricSet;
import com.codahale.metrics.ScheduledReporter;
import com.codahale.metrics.Slf4jReporter;
import com.google.common.base.Preconditions;
@@ -29,6 +31,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
@@ -79,7 +84,7 @@
JmxReporter jmxReporter;
jmxReporter = JmxReporter.forRegistry(metrics).build();
jmxReporter.start();
- addService(new ClosingService<JmxReporter>(jmxReporter));
+ addService(new ClosingService<>(jmxReporter));
// Ganglia
@@ -128,7 +133,7 @@
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build();
reporter.start(interval, TimeUnit.MINUTES);
- addService(new ClosingService<ScheduledReporter>(reporter));
+ addService(new ClosingService<>(reporter));
summary.append(String.format(", SLF4J to log %s interval=%d",
logName, interval));
}
@@ -136,8 +141,11 @@
log.info(reportingDetails);
}
+
@Override
public String toString() {
return super.toString() + " " + reportingDetails;
}
+
+
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsConstants.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsConstants.java
index 31a82a3..fa6bfc0 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsConstants.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsConstants.java
@@ -53,4 +53,6 @@
*/
public static final String CONTAINERS_START_FAILED = "containers.start-failed";
+ public static final String PREFIX_SLIDER_ROLES = "slider.roles.";
+
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/PrefixedMetricsSet.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/PrefixedMetricsSet.java
new file mode 100644
index 0000000..e9ad46a
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/PrefixedMetricsSet.java
@@ -0,0 +1,53 @@
+/*
+ * 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.slider.server.appmaster.management;
+
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricSet;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * From an existing metrics set, generate a new metrics set with the
+ * prefix in front of every key.
+ *
+ * The prefix is added directly: if you want a '.' between prefix and metric
+ * keys, include it in the prefix.
+ */
+public class PrefixedMetricsSet implements MetricSet {
+
+ private final String prefix;
+ private final MetricSet source;
+
+ public PrefixedMetricsSet(String prefix, MetricSet source) {
+ this.prefix = prefix;
+ this.source = source;
+ }
+
+ @Override
+ public Map<String, Metric> getMetrics() {
+ Map<String, Metric> sourceMetrics = source.getMetrics();
+ Map<String, Metric> metrics = new HashMap<>(sourceMetrics.size());
+ for (Map.Entry<String, Metric> entry : sourceMetrics.entrySet()) {
+ metrics.put(prefix + "." + entry.getKey(), entry.getValue());
+ }
+ return metrics;
+ }
+}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/AbstractRMOperation.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/AbstractRMOperation.java
index b5b27c5..ed3f197 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/AbstractRMOperation.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/AbstractRMOperation.java
@@ -26,5 +26,5 @@
* @param handler handler to perform the execution
*/
public abstract void execute(RMOperationHandlerActions handler);
-
+
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/CancelSingleRequest.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/CancelSingleRequest.java
index 08eb5bc..d7673d3 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/CancelSingleRequest.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/CancelSingleRequest.java
@@ -18,7 +18,9 @@
package org.apache.slider.server.appmaster.operations;
+import com.google.common.base.Preconditions;
import org.apache.hadoop.yarn.client.api.AMRMClient;
+import org.apache.slider.server.appmaster.state.ContainerPriority;
/**
* Cancel a container request
@@ -28,6 +30,7 @@
private final AMRMClient.ContainerRequest request;
public CancelSingleRequest(AMRMClient.ContainerRequest request) {
+ Preconditions.checkArgument(request != null, "Null container request");
this.request = request;
}
@@ -42,7 +45,9 @@
@Override
public String toString() {
- return "cancel single request for container at " + request.getPriority().toString();
+ return "Cancel container request"
+ + " for :" + ContainerPriority.toString(request.getPriority())
+ + " request " + request;
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/ContainerReleaseOperation.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/ContainerReleaseOperation.java
index 46da536..4271d50 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/ContainerReleaseOperation.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/ContainerReleaseOperation.java
@@ -18,13 +18,16 @@
package org.apache.slider.server.appmaster.operations;
+import com.google.common.base.Preconditions;
import org.apache.hadoop.yarn.api.records.ContainerId;
+import org.apache.slider.server.appmaster.state.ContainerPriority;
public class ContainerReleaseOperation extends AbstractRMOperation {
private final ContainerId containerId;
public ContainerReleaseOperation(ContainerId containerId) {
+ Preconditions.checkArgument(containerId != null, "Null containerId");
this.containerId = containerId;
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/ContainerRequestOperation.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/ContainerRequestOperation.java
index 6685b2a..e29ddd0 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/ContainerRequestOperation.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/operations/ContainerRequestOperation.java
@@ -54,7 +54,9 @@
@Override
public String toString() {
- return "request container for " + ContainerPriority.toString(getPriority())
+ return "request container for role "
+ + ContainerPriority.toString(getPriority())
+ + " request " + request
+ " relaxLocality=" + getRelaxLocality();
}
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderIPCService.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderIPCService.java
index bb8f512..fda23aa 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderIPCService.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderIPCService.java
@@ -31,6 +31,7 @@
import org.apache.slider.api.types.ComponentInformation;
import org.apache.slider.api.types.ContainerInformation;
import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
import org.apache.slider.core.conf.AggregateConf;
import org.apache.slider.core.conf.ConfTree;
import org.apache.slider.core.exceptions.ServiceNotReadyException;
@@ -423,14 +424,12 @@
@Override
public Messages.GetLiveNodesResponseProto getLiveNodes(Messages.GetLiveNodesRequestProto request)
throws IOException {
- Map<String, NodeInformation> infoMap =
- (Map<String, NodeInformation>) cache.lookupWithIOE(LIVE_NODES);
+ NodeInformationList info = (NodeInformationList) cache.lookupWithIOE(LIVE_NODES);
Messages.GetLiveNodesResponseProto.Builder builder =
Messages.GetLiveNodesResponseProto.newBuilder();
- for (Map.Entry<String, NodeInformation> entry : infoMap.entrySet()) {
- builder.addNames(entry.getKey());
- builder.addNodes(marshall(entry.getValue()));
+ for (NodeInformation nodeInformation : info) {
+ builder.addNodes(marshall(nodeInformation));
}
return builder.build();
}
@@ -448,7 +447,6 @@
}
}
-
@Override
public Messages.WrappedJsonProto getModelDesired(Messages.EmptyPayloadProto request) throws IOException {
return lookupAggregateConf(MODEL_DESIRED);
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AbstractClusterServices.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AbstractClusterServices.java
index 27e25f9..54f384b 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AbstractClusterServices.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AbstractClusterServices.java
@@ -18,16 +18,44 @@
package org.apache.slider.server.appmaster.state;
+import com.google.common.base.Preconditions;
import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.util.resource.DefaultResourceCalculator;
/**
* Cluster services offered by the YARN infrastructure.
*/
public abstract class AbstractClusterServices {
+
+ private final DefaultResourceCalculator
+ defaultResourceCalculator = new DefaultResourceCalculator();
+
/**
* Create a resource for requests
* @return a resource which can be built up.
*/
public abstract Resource newResource();
+ public abstract Resource newResource(int memory, int cores);
+
+ /**
+ * Normalise memory, CPU and other resources according to the YARN AM-supplied
+ * values and the resource calculator in use (currently hard-coded to the
+ * {@link DefaultResourceCalculator}.
+ * Those resources which aren't normalized (currently: CPU) are left
+ * as is.
+ * @param resource resource requirements of a role
+ * @param minR minimum values of this queue
+ * @param maxR max values of this queue
+ * @return a normalized value.
+ */
+ public Resource normalize(Resource resource, Resource minR, Resource maxR) {
+ Preconditions.checkArgument(resource != null, "null resource");
+ Preconditions.checkArgument(minR != null, "null minR");
+ Preconditions.checkArgument(maxR != null, "null maxR");
+
+ Resource normalize = defaultResourceCalculator.normalize(resource, minR,
+ maxR, minR);
+ return newResource(normalize.getMemory(), resource.getVirtualCores());
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppState.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppState.java
index eadb1dc..4b4d7a7 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppState.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppState.java
@@ -18,12 +18,11 @@
package org.apache.slider.server.appmaster.state;
-import com.codahale.metrics.Counter;
+import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricRegistry;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.yarn.api.records.Container;
import org.apache.hadoop.yarn.api.records.ContainerId;
@@ -36,6 +35,7 @@
import org.apache.hadoop.yarn.client.api.AMRMClient;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
+import org.apache.hadoop.yarn.util.resource.Resources;
import org.apache.slider.api.ClusterDescription;
import org.apache.slider.api.ClusterDescriptionKeys;
import org.apache.slider.api.ClusterDescriptionOperations;
@@ -46,6 +46,7 @@
import org.apache.slider.api.StatusKeys;
import org.apache.slider.api.types.ApplicationLivenessInformation;
import org.apache.slider.api.types.ComponentInformation;
+import org.apache.slider.api.types.RoleStatistics;
import org.apache.slider.common.SliderExitCodes;
import org.apache.slider.common.SliderKeys;
import org.apache.slider.common.tools.ConfigHelper;
@@ -64,6 +65,7 @@
import org.apache.slider.core.persist.ConfTreeSerDeser;
import org.apache.slider.providers.PlacementPolicy;
import org.apache.slider.providers.ProviderRole;
+import org.apache.slider.server.appmaster.management.LongGauge;
import org.apache.slider.server.appmaster.management.MetricsAndMonitoring;
import org.apache.slider.server.appmaster.management.MetricsConstants;
import org.apache.slider.server.appmaster.operations.AbstractRMOperation;
@@ -85,9 +87,34 @@
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
-import static org.apache.slider.api.ResourceKeys.*;
-import static org.apache.slider.api.RoleKeys.*;
-import static org.apache.slider.api.StateValues.*;
+import static org.apache.slider.api.ResourceKeys.COMPONENT_INSTANCES;
+import static org.apache.slider.api.ResourceKeys.COMPONENT_PLACEMENT_POLICY;
+import static org.apache.slider.api.ResourceKeys.COMPONENT_PRIORITY;
+import static org.apache.slider.api.ResourceKeys.CONTAINER_FAILURE_THRESHOLD;
+import static org.apache.slider.api.ResourceKeys.DEFAULT_CONTAINER_FAILURE_THRESHOLD;
+import static org.apache.slider.api.ResourceKeys.DEFAULT_NODE_FAILURE_THRESHOLD;
+import static org.apache.slider.api.ResourceKeys.DEFAULT_PLACEMENT_ESCALATE_DELAY_SECONDS;
+import static org.apache.slider.api.ResourceKeys.DEF_YARN_CORES;
+import static org.apache.slider.api.ResourceKeys.DEF_YARN_LABEL_EXPRESSION;
+import static org.apache.slider.api.ResourceKeys.DEF_YARN_MEMORY;
+import static org.apache.slider.api.ResourceKeys.NODE_FAILURE_THRESHOLD;
+import static org.apache.slider.api.ResourceKeys.PLACEMENT_ESCALATE_DELAY;
+import static org.apache.slider.api.ResourceKeys.YARN_CORES;
+import static org.apache.slider.api.ResourceKeys.YARN_LABEL_EXPRESSION;
+import static org.apache.slider.api.ResourceKeys.YARN_MEMORY;
+import static org.apache.slider.api.ResourceKeys.YARN_RESOURCE_MAX;
+import static org.apache.slider.api.RoleKeys.ROLE_FAILED_INSTANCES;
+import static org.apache.slider.api.RoleKeys.ROLE_FAILED_RECENTLY_INSTANCES;
+import static org.apache.slider.api.RoleKeys.ROLE_FAILED_STARTING_INSTANCES;
+import static org.apache.slider.api.RoleKeys.ROLE_NODE_FAILED_INSTANCES;
+import static org.apache.slider.api.RoleKeys.ROLE_PENDING_AA_INSTANCES;
+import static org.apache.slider.api.RoleKeys.ROLE_PREEMPTED_INSTANCES;
+import static org.apache.slider.api.RoleKeys.ROLE_RELEASING_INSTANCES;
+import static org.apache.slider.api.RoleKeys.ROLE_REQUESTED_INSTANCES;
+import static org.apache.slider.api.StateValues.STATE_CREATED;
+import static org.apache.slider.api.StateValues.STATE_DESTROYED;
+import static org.apache.slider.api.StateValues.STATE_LIVE;
+import static org.apache.slider.api.StateValues.STATE_SUBMITTED;
/**
@@ -142,7 +169,7 @@
private ConfTreeOperations resourcesSnapshot;
private ConfTreeOperations appConfSnapshot;
private ConfTreeOperations internalsSnapshot;
-
+
/**
* This is the status, the live model
*/
@@ -152,7 +179,7 @@
* Metadata provided by the AM for use in filling in status requests
*/
private Map<String, String> applicationInfo;
-
+
/**
* Client properties created via the provider -static for the life
* of the application
@@ -196,33 +223,33 @@
/**
* Counter for completed containers ( complete denotes successful or failed )
*/
- private final Counter completedContainerCount = new Counter();
+ private final LongGauge completedContainerCount = new LongGauge();
/**
* Count of failed containers
*/
- private final Counter failedContainerCount = new Counter();
+ private final LongGauge failedContainerCount = new LongGauge();
/**
* # of started containers
*/
- private final Counter startedContainers = new Counter();
+ private final LongGauge startedContainers = new LongGauge();
/**
* # of containers that failed to start
*/
- private final Counter startFailedContainerCount = new Counter();
+ private final LongGauge startFailedContainerCount = new LongGauge();
/**
* Track the number of surplus containers received and discarded
*/
- private final Counter surplusContainers = new Counter();
-
+ private final LongGauge surplusContainers = new LongGauge();
/**
- * Track the number of requested Containers
+ * Track the number of requested containers.
+ * Important: this does not include AA requests which are yet to be issued.
*/
- private final Counter outstandingContainerRequests = new Counter();
+ private final LongGauge outstandingContainerRequests = new LongGauge();
/**
* Map of requested nodes. This records the command used to start it,
@@ -265,28 +292,32 @@
/**
- * Record of the max no. of cores allowed in this cluster
+ * limits of container core numbers in this queue
*/
private int containerMaxCores;
+ private int containerMinCores;
/**
- * limit container memory
+ * limits of container memory in this queue
*/
private int containerMaxMemory;
-
+ private int containerMinMemory;
+
private RoleHistory roleHistory;
private Configuration publishedProviderConf;
private long startTimeThreshold;
-
+
private int failureThreshold = 10;
private int nodeFailureThreshold = 3;
-
+
private String logServerURL = "";
/**
* Selector of containers to release; application wide.
*/
private ContainerReleaseSelector containerReleaseSelector;
+ private Resource minResource;
+ private Resource maxResource;
/**
* Create an instance
@@ -295,6 +326,8 @@
*/
public AppState(AbstractClusterServices recordFactory,
MetricsAndMonitoring metricsAndMonitoring) {
+ Preconditions.checkArgument(recordFactory != null, "null recordFactory");
+ Preconditions.checkArgument(metricsAndMonitoring != null, "null metricsAndMonitoring");
this.recordFactory = recordFactory;
this.metricsAndMonitoring = metricsAndMonitoring;
@@ -307,7 +340,7 @@
register(MetricsConstants.CONTAINERS_START_FAILED, startFailedContainerCount);
}
- private void register(String name, Counter counter) {
+ private void register(String name, Metric counter) {
this.metricsAndMonitoring.getMetrics().register(
MetricRegistry.name(AppState.class, name), counter);
}
@@ -374,7 +407,6 @@
return completedContainers;
}
-
public Map<ContainerId, RoleInstance> getFailedContainers() {
return failedContainers;
}
@@ -447,27 +479,31 @@
}
/**
- * Set the container limits -the max that can be asked for,
- * which are used when the "max" values are requested
+ * Set the container limits -the min and max values for
+ * resource requests. All requests must be multiples of the min
+ * values.
+ * @param minMemory min memory MB
* @param maxMemory maximum memory
+ * @param minCores min v core count
* @param maxCores maximum cores
*/
- public void setContainerLimits(int maxMemory, int maxCores) {
+ public void setContainerLimits(int minMemory,int maxMemory, int minCores, int maxCores) {
+ containerMinCores = minCores;
containerMaxCores = maxCores;
+ containerMinMemory = minMemory;
containerMaxMemory = maxMemory;
+ minResource = recordFactory.newResource(containerMinMemory, containerMinCores);
+ maxResource = recordFactory.newResource(containerMaxMemory, containerMaxCores);
}
-
public ConfTreeOperations getResourcesSnapshot() {
return resourcesSnapshot;
}
-
public ConfTreeOperations getAppConfSnapshot() {
return appConfSnapshot;
}
-
public ConfTreeOperations getInternalsSnapshot() {
return internalsSnapshot;
}
@@ -488,38 +524,17 @@
return unresolvedInstanceDefinition;
}
- /**
- * Build up the application state
- * @param instanceDefinition definition of the applicatin instance
- * @param appmasterConfig
- * @param publishedProviderConf any configuration info to be published by a provider
- * @param providerRoles roles offered by a provider
- * @param fs filesystem
- * @param historyDir directory containing history files
- * @param liveContainers list of live containers supplied on an AM restart
- * @param applicationInfo app info to retain for web views
- * @param releaseSelector selector of containers to release
- */
- public synchronized void buildInstance(AggregateConf instanceDefinition,
- Configuration appmasterConfig,
- Configuration publishedProviderConf,
- List<ProviderRole> providerRoles,
- FileSystem fs,
- Path historyDir,
- List<Container> liveContainers,
- Map<String, String> applicationInfo,
- ContainerReleaseSelector releaseSelector)
- throws BadClusterStateException, BadConfigException, IOException {
- Preconditions.checkArgument(instanceDefinition != null);
- Preconditions.checkArgument(releaseSelector != null);
+ public synchronized void buildInstance(AppStateBindingInfo binding)
+ throws BadClusterStateException, BadConfigException, IOException {
+ binding.validate();
log.debug("Building application state");
- this.publishedProviderConf = publishedProviderConf;
- this.applicationInfo = applicationInfo != null ? applicationInfo
- : new HashMap<String, String>();
+ publishedProviderConf = binding.publishedProviderConf;
+ applicationInfo = binding.applicationInfo != null ? binding.applicationInfo
+ : new HashMap<String, String>();
clientProperties = new HashMap<>();
- containerReleaseSelector = releaseSelector;
+ containerReleaseSelector = binding.releaseSelector;
Set<String> confKeys = ConfigHelper.sortedConfigKeys(publishedProviderConf);
@@ -532,15 +547,15 @@
// set the cluster specification (once its dependency the client properties
// is out the way
- setInitialInstanceDefinition(instanceDefinition);
+ setInitialInstanceDefinition(binding.instanceDefinition);
//build the initial role list
- for (ProviderRole providerRole : providerRoles) {
+ List<ProviderRole> roleList = new ArrayList<>(binding.roles);
+ for (ProviderRole providerRole : roleList) {
buildRole(providerRole);
}
- ConfTreeOperations resources =
- instanceDefinition.getResourceOperations();
+ ConfTreeOperations resources = instanceDefinition.getResourceOperations();
Set<String> roleNames = resources.getComponentNames();
for (String name : roleNames) {
@@ -548,44 +563,43 @@
// this is a new value
log.info("Adding role {}", name);
MapOperations resComponent = resources.getComponent(name);
- ProviderRole dynamicRole =
- createDynamicProviderRole(name, resComponent);
+ ProviderRole dynamicRole = createDynamicProviderRole(name, resComponent);
buildRole(dynamicRole);
- providerRoles.add(dynamicRole);
+ roleList.add(dynamicRole);
}
}
//then pick up the requirements
buildRoleRequirementsFromResources();
-
//set the livespan
- MapOperations globalResOpts =
- instanceDefinition.getResourceOperations().getGlobalOptions();
-
+ MapOperations globalResOpts = instanceDefinition.getResourceOperations().getGlobalOptions();
+
startTimeThreshold = globalResOpts.getOptionInt(
InternalKeys.INTERNAL_CONTAINER_FAILURE_SHORTLIFE,
InternalKeys.DEFAULT_INTERNAL_CONTAINER_FAILURE_SHORTLIFE);
failureThreshold = globalResOpts.getOptionInt(
- ResourceKeys.CONTAINER_FAILURE_THRESHOLD,
- ResourceKeys.DEFAULT_CONTAINER_FAILURE_THRESHOLD);
+ CONTAINER_FAILURE_THRESHOLD,
+ DEFAULT_CONTAINER_FAILURE_THRESHOLD);
nodeFailureThreshold = globalResOpts.getOptionInt(
- ResourceKeys.NODE_FAILURE_THRESHOLD,
- ResourceKeys.DEFAULT_NODE_FAILURE_THRESHOLD);
+ NODE_FAILURE_THRESHOLD,
+ DEFAULT_NODE_FAILURE_THRESHOLD);
initClusterStatus();
// set up the role history
- roleHistory = new RoleHistory(providerRoles);
+ roleHistory = new RoleHistory(roleStatusMap.values(), recordFactory);
roleHistory.register(metricsAndMonitoring);
- roleHistory.onStart(fs, historyDir);
+ roleHistory.onStart(binding.fs, binding.historyPath);
+ // trigger first node update
+ roleHistory.onNodesUpdated(binding.nodeReports);
+
//rebuild any live containers
- rebuildModelFromRestart(liveContainers);
+ rebuildModelFromRestart(binding.liveContainers);
// any am config options to pick up
- logServerURL = appmasterConfig.get(YarnConfiguration.YARN_LOG_SERVER_URL, "");
-
+ logServerURL = binding.serviceConfig.get(YarnConfiguration.YARN_LOG_SERVER_URL, "");
//mark as live
applicationLive = true;
}
@@ -625,32 +639,31 @@
* @return a new provider role
* @throws BadConfigException bad configuration
*/
- public ProviderRole createDynamicProviderRole(String name,
- MapOperations component) throws
- BadConfigException {
- String priOpt = component.getMandatoryOption(ResourceKeys.COMPONENT_PRIORITY);
- int priority = SliderUtils.parseAndValidate("value of " + name + " " +
- ResourceKeys.COMPONENT_PRIORITY,
- priOpt, 0, 1, -1);
- String placementOpt = component.getOption(
- ResourceKeys.COMPONENT_PLACEMENT_POLICY,
+ public ProviderRole createDynamicProviderRole(String name, MapOperations component)
+ throws BadConfigException {
+ String priOpt = component.getMandatoryOption(COMPONENT_PRIORITY);
+ int priority = SliderUtils.parseAndValidate(
+ "value of " + name + " " + COMPONENT_PRIORITY, priOpt, 0, 1, -1);
+
+ String placementOpt = component.getOption(COMPONENT_PLACEMENT_POLICY,
Integer.toString(PlacementPolicy.DEFAULT));
- int placement = SliderUtils.parseAndValidate("value of " + name + " " +
- ResourceKeys.COMPONENT_PLACEMENT_POLICY,
- placementOpt, 0, 0, -1);
- int placementTimeout =
- component.getOptionInt(ResourceKeys.PLACEMENT_ESCALATE_DELAY,
- ResourceKeys.DEFAULT_PLACEMENT_ESCALATE_DELAY_SECONDS);
+
+ int placement = SliderUtils.parseAndValidate(
+ "value of " + name + " " + COMPONENT_PLACEMENT_POLICY, placementOpt, 0, 0, -1);
+
+ int placementTimeout = component.getOptionInt(PLACEMENT_ESCALATE_DELAY,
+ DEFAULT_PLACEMENT_ESCALATE_DELAY_SECONDS);
+
ProviderRole newRole = new ProviderRole(name,
priority,
placement,
getNodeFailureThresholdForRole(name),
- placementTimeout);
+ placementTimeout,
+ component.getOption(YARN_LABEL_EXPRESSION, DEF_YARN_LABEL_EXPRESSION));
log.info("New {} ", newRole);
return newRole;
}
-
/**
* Actions to perform when an instance definition is updated
* Currently:
@@ -665,56 +678,52 @@
*
* @throws BadConfigException
*/
- private synchronized void onInstanceDefinitionUpdated() throws
- BadConfigException,
- IOException {
+ private synchronized void onInstanceDefinitionUpdated()
+ throws BadConfigException, IOException {
+
log.debug("Instance definition updated");
//note the time
snapshotTime = now();
-
+
// resolve references if not already done
instanceDefinition.resolve();
// force in the AM desired state values
- ConfTreeOperations resources =
- instanceDefinition.getResourceOperations();
+ ConfTreeOperations resources = instanceDefinition.getResourceOperations();
+
if (resources.getComponent(SliderKeys.COMPONENT_AM) != null) {
resources.setComponentOpt(
- SliderKeys.COMPONENT_AM, ResourceKeys.COMPONENT_INSTANCES, "1");
+ SliderKeys.COMPONENT_AM, COMPONENT_INSTANCES, "1");
}
//snapshot all three sectons
- resourcesSnapshot =
- ConfTreeOperations.fromInstance(instanceDefinition.getResources());
- appConfSnapshot =
- ConfTreeOperations.fromInstance(instanceDefinition.getAppConf());
- internalsSnapshot =
- ConfTreeOperations.fromInstance(instanceDefinition.getInternal());
+ resourcesSnapshot = ConfTreeOperations.fromInstance(instanceDefinition.getResources());
+ appConfSnapshot = ConfTreeOperations.fromInstance(instanceDefinition.getAppConf());
+ internalsSnapshot = ConfTreeOperations.fromInstance(instanceDefinition.getInternal());
//build a new aggregate from the snapshots
instanceDefinitionSnapshot = new AggregateConf(resourcesSnapshot.confTree,
appConfSnapshot.confTree,
internalsSnapshot.confTree);
instanceDefinitionSnapshot.setName(instanceDefinition.getName());
- clusterStatusTemplate =
- ClusterDescriptionOperations.buildFromInstanceDefinition(
+ clusterStatusTemplate = ClusterDescriptionOperations.buildFromInstanceDefinition(
instanceDefinition);
-
-// Add the -site configuration properties
+ // Add the -site configuration properties
for (Map.Entry<String, String> prop : clientProperties.entrySet()) {
clusterStatusTemplate.clientProperties.put(prop.getKey(), prop.getValue());
}
-
+
}
-
+
/**
* The resource configuration is updated -review and update state.
* @param resources updated resources specification
* @return a list of any dynamically added provider roles
* (purely for testing purposes)
*/
+ @VisibleForTesting
public synchronized List<ProviderRole> updateResourceDefinitions(ConfTree resources)
throws BadConfigException, IOException {
log.debug("Updating resources to {}", resources);
@@ -741,9 +750,9 @@
private List<ProviderRole> buildRoleRequirementsFromResources() throws BadConfigException {
List<ProviderRole> newRoles = new ArrayList<>(0);
-
- //now update every role's desired count.
- //if there are no instance values, that role count goes to zero
+
+ // now update every role's desired count.
+ // if there are no instance values, that role count goes to zero
ConfTreeOperations resources =
instanceDefinition.getResourceOperations();
@@ -754,10 +763,8 @@
// skip inflexible roles, e.g AM itself
continue;
}
- int currentDesired = roleStatus.getDesired();
+ long currentDesired = roleStatus.getDesired();
String role = roleStatus.getName();
- MapOperations comp =
- resources.getComponent(role);
int desiredInstanceCount = getDesiredInstanceCount(resources, role);
if (desiredInstanceCount == 0) {
log.info("Role {} has 0 instances specified", role);
@@ -769,23 +776,25 @@
}
}
- //now the dynamic ones. Iterate through the the cluster spec and
- //add any role status entries not in the role status
+ // now the dynamic ones. Iterate through the the cluster spec and
+ // add any role status entries not in the role status
Set<String> roleNames = resources.getComponentNames();
for (String name : roleNames) {
if (!roles.containsKey(name)) {
// this is a new value
log.info("Adding new role {}", name);
MapOperations component = resources.getComponent(name);
- ProviderRole dynamicRole = createDynamicProviderRole(name,
- component);
+ ProviderRole dynamicRole = createDynamicProviderRole(name, component);
RoleStatus roleStatus = buildRole(dynamicRole);
roleStatus.setDesired(getDesiredInstanceCount(resources, name));
log.info("New role {}", roleStatus);
- roleHistory.addNewProviderRole(dynamicRole);
+ roleHistory.addNewRole(roleStatus);
newRoles.add(dynamicRole);
}
}
+ // and fill in all those roles with their requirements
+ buildRoleResourceRequirements();
+
return newRoles;
}
@@ -799,7 +808,7 @@
private int getDesiredInstanceCount(ConfTreeOperations resources,
String role) throws BadConfigException {
int desiredInstanceCount =
- resources.getComponentOptInt(role, ResourceKeys.COMPONENT_INSTANCES, 0);
+ resources.getComponentOptInt(role, COMPONENT_INSTANCES, 0);
if (desiredInstanceCount < 0) {
log.error("Role {} has negative desired instances : {}", role,
@@ -821,7 +830,7 @@
* @throws BadConfigException if a role of that priority already exists
*/
public RoleStatus buildRole(ProviderRole providerRole) throws BadConfigException {
- //build role status map
+ // build role status map
int priority = providerRole.id;
if (roleStatusMap.containsKey(priority)) {
throw new BadConfigException("Duplicate Provider Key: %s and %s",
@@ -830,12 +839,26 @@
}
RoleStatus roleStatus = new RoleStatus(providerRole);
roleStatusMap.put(priority, roleStatus);
- roles.put(providerRole.name, providerRole);
+ String name = providerRole.name;
+ roles.put(name, providerRole);
rolePriorityMap.put(priority, providerRole);
+ // register its entries
+ metricsAndMonitoring.addMetricSet(MetricsConstants.PREFIX_SLIDER_ROLES + name, roleStatus);
return roleStatus;
}
/**
+ * Build up the requirements of every resource
+ */
+ private void buildRoleResourceRequirements() {
+ roleStatusMap.values();
+ for (RoleStatus role : roleStatusMap.values()) {
+ role.setResourceRequirements(
+ buildResourceRequirements(role, recordFactory.newResource()));
+ }
+ }
+
+ /**
* build up the special master node, which lives
* in the live node set but has a lifecycle bonded to the AM
* @param containerId the AM master
@@ -861,10 +884,9 @@
//it is also added to the set of live nodes
getLiveContainers().put(containerId, am);
putOwnedContainer(containerId, am);
-
+
// patch up the role status
- RoleStatus roleStatus = roleStatusMap.get(
- (SliderKeys.ROLE_AM_PRIORITY_INDEX));
+ RoleStatus roleStatus = roleStatusMap.get(SliderKeys.ROLE_AM_PRIORITY_INDEX);
roleStatus.setDesired(1);
roleStatus.incActual();
roleStatus.incStarted();
@@ -890,11 +912,12 @@
appMasterNode.state = STATE_LIVE;
}
- public RoleInstance getAppMasterNode() {
- return appMasterNode;
- }
-
-
+ /**
+ * Look up the status entry of a role or raise an exception
+ * @param key role ID
+ * @return the status entry
+ * @throws RuntimeException if the role cannot be found
+ */
public RoleStatus lookupRoleStatus(int key) {
RoleStatus rs = getRoleStatusMap().get(key);
if (rs == null) {
@@ -902,8 +925,15 @@
}
return rs;
}
-
- public RoleStatus lookupRoleStatus(Container c) throws YarnRuntimeException {
+
+ /**
+ * Look up the status entry of a container or raise an exception
+ *
+ * @param c container
+ * @return the status entry
+ * @throws RuntimeException if the role cannot be found
+ */
+ public RoleStatus lookupRoleStatus(Container c) {
return lookupRoleStatus(ContainerPriority.extractRole(c));
}
@@ -914,7 +944,7 @@
*/
public List<RoleStatus> cloneRoleStatusList() {
Collection<RoleStatus> statuses = roleStatusMap.values();
- List<RoleStatus> statusList = new ArrayList<RoleStatus>(statuses.size());
+ List<RoleStatus> statusList = new ArrayList<>(statuses.size());
try {
for (RoleStatus status : statuses) {
statusList.add((RoleStatus)(status.clone()));
@@ -926,6 +956,12 @@
}
+ /**
+ * Look up a role in the map
+ * @param name role name
+ * @return the instance
+ * @throws YarnRuntimeException if not found
+ */
public RoleStatus lookupRoleStatus(String name) throws YarnRuntimeException {
ProviderRole providerRole = roles.get(name);
if (providerRole == null) {
@@ -941,7 +977,7 @@
*/
public synchronized List<RoleInstance> cloneOwnedContainerList() {
Collection<RoleInstance> values = ownedContainers.values();
- return new ArrayList<RoleInstance>(values);
+ return new ArrayList<>(values);
}
/**
@@ -1040,7 +1076,6 @@
}
}
-
public synchronized List<RoleInstance> getLiveInstancesByContainerIDs(
Collection<String> containerIDs) {
//first, a hashmap of those containerIDs is built up
@@ -1094,7 +1129,6 @@
return nodes;
}
-
/**
* Build an instance map.
* @return the map of Role name to list of role instances
@@ -1111,8 +1145,7 @@
}
return map;
}
-
-
+
/**
* Build a map of role->nodename->node-info
*
@@ -1179,43 +1212,39 @@
roleHistory.onContainerReleaseSubmitted(container);
}
-
/**
- * Set up the resource requirements with all that this role needs,
- * then create the container request itself.
- * @param role role to ask an instance of
- * @param capability a resource to set up
- * @return the request for a new container
+ * Create a container request.
+ * Update internal state, such as the role request count.
+ * Anti-Affine: the {@link RoleStatus#outstandingAArequest} is set here.
+ * This is where role history information will be used for placement decisions.
+ * @param role role
+ * @return the container request to submit or null if there is none
*/
- public AMRMClient.ContainerRequest buildContainerResourceAndRequest(
- RoleStatus role,
- Resource capability) {
- buildResourceRequirements(role, capability);
- String labelExpression = getLabelExpression(role);
- //get the role history to select a suitable node, if available
- AMRMClient.ContainerRequest containerRequest =
- createContainerRequest(role, capability, labelExpression);
- return containerRequest;
+ private AMRMClient.ContainerRequest createContainerRequest(RoleStatus role) {
+ if (role.isAntiAffinePlacement()) {
+ return createAAContainerRequest(role);
+ } else {
+ incrementRequestCount(role);
+ return roleHistory.requestContainerForRole(role).getIssuedRequest();
+ }
}
/**
* Create a container request.
- * Update internal state, such as the role request count
- * This is where role history information will be used for placement decisions -
+ * Update internal state, such as the role request count.
+ * Anti-Affine: the {@link RoleStatus#outstandingAArequest} is set here.
+ * This is where role history information will be used for placement decisions.
* @param role role
- * @param resource requirements
- * @param labelExpression label expression to satisfy
- * @return the container request to submit
+ * @return the container request to submit or null if there is none
*/
- private AMRMClient.ContainerRequest createContainerRequest(RoleStatus role,
- Resource resource,
- String labelExpression) {
-
-
- AMRMClient.ContainerRequest request;
- request = roleHistory.requestNode(role, resource, labelExpression);
+ private AMRMClient.ContainerRequest createAAContainerRequest(RoleStatus role) {
+ OutstandingRequest request = roleHistory.requestContainerForAARole(role);
+ if (request == null) {
+ return null;
+ }
incrementRequestCount(role);
- return request;
+ role.setOutstandingAArequest(request);
+ return request.getIssuedRequest();
}
/**
@@ -1229,24 +1258,11 @@
incOutstandingContainerRequests();
}
-
- /**
- * dec requested count of a role
- * <p>
- * Also updates application state counters.
- * @param role role to decrement
- */
- protected synchronized void decrementRequestCount(RoleStatus role) {
- role.decRequested();
- }
-
/**
* Inc #of outstanding requests.
*/
private void incOutstandingContainerRequests() {
- synchronized (outstandingContainerRequests) {
- outstandingContainerRequests.inc();
- }
+ outstandingContainerRequests.inc();
}
/**
@@ -1279,11 +1295,11 @@
String option,
int defVal,
int maxVal) {
-
+
String val = resources.getComponentOpt(name, option,
Integer.toString(defVal));
Integer intVal;
- if (ResourceKeys.YARN_RESOURCE_MAX.equals(val)) {
+ if (YARN_RESOURCE_MAX.equals(val)) {
intVal = maxVal;
} else {
intVal = Integer.decode(val);
@@ -1291,15 +1307,15 @@
return intVal;
}
-
/**
* Build up the resource requirements for this role from the
* cluster specification, including substituing max allowed values
* if the specification asked for it.
* @param role role
- * @param capability capability to set up
+ * @param capability capability to set up. A new one may be created
+ * during normalization
*/
- public void buildResourceRequirements(RoleStatus role, Resource capability) {
+ public Resource buildResourceRequirements(RoleStatus role, Resource capability) {
// Set up resource requirements from role values
String name = role.getName();
ConfTreeOperations resources = getResourcesSnapshot();
@@ -1314,17 +1330,16 @@
DEF_YARN_MEMORY,
containerMaxMemory);
capability.setMemory(ram);
- }
-
- /**
- * Extract the label expression for this role.
- * @param role role
- */
- public String getLabelExpression(RoleStatus role) {
- // Set up resource requirements from role values
- String name = role.getName();
- ConfTreeOperations resources = getResourcesSnapshot();
- return resources.getComponentOpt(name, YARN_LABEL_EXPRESSION, DEF_YARN_LABEL_EXPRESSION);
+ log.debug("Component {} has RAM={}, vCores ={}", name, ram, cores);
+ Resource normalized = recordFactory.normalize(capability, minResource,
+ maxResource);
+ if (!Resources.equals(normalized, capability)) {
+ // resource requirements normalized to something other than asked for.
+ // LOG @ WARN so users can see why this is happening.
+ log.warn("Resource requirements of {} normalized" +
+ " from {} to {}", name, capability, normalized);
+ }
+ return normalized;
}
/**
@@ -1382,7 +1397,7 @@
RoleInstance starting = getStartingContainers().remove(containerId);
if (null == starting) {
throw new YarnRuntimeException(
- "Container "+ containerId +"%s is already started");
+ "Container "+ containerId +" is already started");
}
instance.state = STATE_LIVE;
RoleStatus roleStatus = lookupRoleStatus(instance.roleId);
@@ -1427,11 +1442,31 @@
* Handle node update from the RM. This syncs up the node map with the RM's view
* @param updatedNodes updated nodes
*/
- public synchronized void onNodesUpdated(List<NodeReport> updatedNodes) {
- roleHistory.onNodesUpdated(updatedNodes);
+ public synchronized NodeUpdatedOutcome onNodesUpdated(List<NodeReport> updatedNodes) {
+ boolean changed = roleHistory.onNodesUpdated(updatedNodes);
+ if (changed) {
+ log.info("YARN cluster changed —cancelling current AA requests");
+ List<AbstractRMOperation> operations = cancelOutstandingAARequests();
+ log.debug("Created {} cancel requests", operations.size());
+ return new NodeUpdatedOutcome(true, operations);
+ }
+ return new NodeUpdatedOutcome(false, new ArrayList<AbstractRMOperation>(0));
}
/**
+ * Return value of the {@link #onNodesUpdated(List)} call.
+ */
+ public static class NodeUpdatedOutcome {
+ public final boolean clusterChanged;
+ public final List<AbstractRMOperation> operations;
+
+ public NodeUpdatedOutcome(boolean clusterChanged,
+ List<AbstractRMOperation> operations) {
+ this.clusterChanged = clusterChanged;
+ this.operations = operations;
+ }
+ }
+ /**
* Is a role short lived by the threshold set for this application
* @param instance instance
* @return true if the instance is considered short lived
@@ -1475,7 +1510,6 @@
public int exitStatus = 0;
public boolean unknownNode = false;
-
public String toString() {
final StringBuilder sb =
new StringBuilder("NodeCompletionResult{");
@@ -1489,10 +1523,10 @@
return sb.toString();
}
}
-
+
/**
* handle completed node in the CD -move something from the live
- * server list to the completed server list
+ * server list to the completed server list.
* @param status the node that has just completed
* @return NodeCompletionResult
*/
@@ -1507,9 +1541,9 @@
log.info("Container was queued for release : {}", containerId);
Container container = containersBeingReleased.remove(containerId);
RoleStatus roleStatus = lookupRoleStatus(container);
- int releasing = roleStatus.decReleasing();
- int actual = roleStatus.decActual();
- int completedCount = roleStatus.incCompleted();
+ long releasing = roleStatus.decReleasing();
+ long actual = roleStatus.decActual();
+ long completedCount = roleStatus.incCompleted();
log.info("decrementing role count for role {} to {}; releasing={}, completed={}",
roleStatus.getName(),
actual,
@@ -1552,7 +1586,7 @@
if (failedContainer != null) {
String completedLogsUrl = getLogsURLForContainer(failedContainer);
message = String.format("Failure %s on host %s (%d): %s",
- roleInstance.getContainerId().toString(),
+ roleInstance.getContainerId(),
failedContainer.getNodeId().getHost(),
exitStatus,
completedLogsUrl);
@@ -1601,10 +1635,10 @@
log.warn("Received notification of completion of unknown node {}", id);
completionOfNodeNotInLiveListEvent.incrementAndGet();
}
-
+
// and the active node list if present
removeOwnedContainer(containerId);
-
+
// finally, verify the node doesn't exist any more
assert !containersBeingReleased.containsKey(
containerId) : "container still in release queue";
@@ -1639,9 +1673,6 @@
return completedLogsUrl;
}
-
-
-
/**
* Return the percentage done that Slider is to have YARN display in its
* Web UI
@@ -1649,7 +1680,7 @@
*/
public synchronized float getApplicationProgressPercentage() {
float percentage;
- int desired = 0;
+ long desired = 0;
float actual = 0;
for (RoleStatus role : getRoleStatusMap().values()) {
desired += role.getDesired();
@@ -1670,7 +1701,7 @@
public ClusterDescription refreshClusterStatus() {
return refreshClusterStatus(null);
}
-
+
/**
* Update the cluster description with the current application state
* @param providerStatus status from the provider for the cluster info section
@@ -1683,13 +1714,13 @@
now);
if (providerStatus != null) {
for (Map.Entry<String, String> entry : providerStatus.entrySet()) {
- cd.setInfo(entry.getKey(),entry.getValue());
+ cd.setInfo(entry.getKey(), entry.getValue());
}
}
MapOperations infoOps = new MapOperations("info", cd.info);
infoOps.mergeWithoutOverwrite(applicationInfo);
SliderUtils.addBuildInfo(infoOps, "status");
- cd.statistics = new HashMap<String, Map<String, Integer>>();
+ cd.statistics = new HashMap<>();
// build the map of node -> container IDs
Map<String, List<String>> instanceMap = createRoleToInstanceMap();
@@ -1698,7 +1729,7 @@
//build the map of node -> containers
Map<String, Map<String, ClusterNode>> clusterNodes =
createRoleToClusterNodeMap();
- cd.status = new HashMap<String, Object>();
+ cd.status = new HashMap<>();
cd.status.put(ClusterDescriptionKeys.KEY_CLUSTER_LIVE, clusterNodes);
@@ -1706,7 +1737,7 @@
String rolename = role.getName();
List<String> instances = instanceMap.get(rolename);
int nodeCount = instances != null ? instances.size(): 0;
- cd.setRoleOpt(rolename, ResourceKeys.COMPONENT_INSTANCES,
+ cd.setRoleOpt(rolename, COMPONENT_INSTANCES,
role.getDesired());
cd.setRoleOpt(rolename, RoleKeys.ROLE_ACTUAL_INSTANCES, nodeCount);
cd.setRoleOpt(rolename, ROLE_REQUESTED_INSTANCES, role.getRequested());
@@ -1716,17 +1747,19 @@
cd.setRoleOpt(rolename, ROLE_FAILED_RECENTLY_INSTANCES, role.getFailedRecently());
cd.setRoleOpt(rolename, ROLE_NODE_FAILED_INSTANCES, role.getNodeFailed());
cd.setRoleOpt(rolename, ROLE_PREEMPTED_INSTANCES, role.getPreempted());
+ if (role.isAntiAffinePlacement()) {
+ cd.setRoleOpt(rolename, ROLE_PENDING_AA_INSTANCES, role.getPendingAntiAffineRequests());
+ }
Map<String, Integer> stats = role.buildStatistics();
cd.statistics.put(rolename, stats);
}
-
Map<String, Integer> sliderstats = getLiveStatistics();
cd.statistics.put(SliderKeys.COMPONENT_AM, sliderstats);
-
+
// liveness
cd.liveness = getApplicationLivenessInformation();
-
+
return cd;
}
@@ -1736,12 +1769,14 @@
*/
public ApplicationLivenessInformation getApplicationLivenessInformation() {
ApplicationLivenessInformation li = new ApplicationLivenessInformation();
- int outstanding = (int) outstandingContainerRequests.getCount();
+ RoleStatistics stats = getRoleStatistics();
+ int outstanding = (int)(stats.desired - stats.actual);
li.requestsOutstanding = outstanding;
li.allRequestsSatisfied = outstanding <= 0;
+ li.activeRequests = (int)stats.requested;
return li;
}
-
+
/**
* Get the live statistics map
* @return a map of statistics values, defined in the {@link StatusKeys}
@@ -1752,21 +1787,33 @@
sliderstats.put(StatusKeys.STATISTICS_CONTAINERS_LIVE,
liveNodes.size());
sliderstats.put(StatusKeys.STATISTICS_CONTAINERS_COMPLETED,
- (int)completedContainerCount.getCount());
+ completedContainerCount.intValue());
sliderstats.put(StatusKeys.STATISTICS_CONTAINERS_FAILED,
- (int)failedContainerCount.getCount());
+ failedContainerCount.intValue());
sliderstats.put(StatusKeys.STATISTICS_CONTAINERS_STARTED,
- (int)startedContainers.getCount());
+ startedContainers.intValue());
sliderstats.put(StatusKeys.STATISTICS_CONTAINERS_START_FAILED,
- (int) startFailedContainerCount.getCount());
+ startFailedContainerCount.intValue());
sliderstats.put(StatusKeys.STATISTICS_CONTAINERS_SURPLUS,
- (int)surplusContainers.getCount());
+ surplusContainers.intValue());
sliderstats.put(StatusKeys.STATISTICS_CONTAINERS_UNKNOWN_COMPLETED,
completionOfUnknownContainerEvent.get());
return sliderstats;
}
/**
+ * Get the aggregate statistics across all roles
+ * @return role statistics
+ */
+ public RoleStatistics getRoleStatistics() {
+ RoleStatistics stats = new RoleStatistics();
+ for (RoleStatus role : getRoleStatusMap().values()) {
+ stats.add(role.getStatistics());
+ }
+ return stats;
+ }
+
+ /**
* Get a snapshot of component information.
* <p>
* This does <i>not</i> include any container list, which
@@ -1776,8 +1823,7 @@
public Map<String, ComponentInformation> getComponentInfoSnapshot() {
Map<Integer, RoleStatus> statusMap = getRoleStatusMap();
- Map<String, ComponentInformation> results =
- new HashMap<String, ComponentInformation>(
+ Map<String, ComponentInformation> results = new HashMap<>(
statusMap.size());
for (RoleStatus status : statusMap.values()) {
@@ -1794,7 +1840,7 @@
public synchronized List<AbstractRMOperation> reviewRequestAndReleaseNodes()
throws SliderInternalStateException, TriggerClusterTeardownException {
log.debug("in reviewRequestAndReleaseNodes()");
- List<AbstractRMOperation> allOperations = new ArrayList<AbstractRMOperation>();
+ List<AbstractRMOperation> allOperations = new ArrayList<>();
for (RoleStatus roleStatus : getRoleStatusMap().values()) {
if (!roleStatus.isExcludeFromFlexing()) {
List<AbstractRMOperation> operations = reviewOneRole(roleStatus);
@@ -1814,8 +1860,10 @@
throws TriggerClusterTeardownException {
long failures = role.getFailedRecently();
int threshold = getFailureThresholdForRole(role);
- log.debug("Failure count of component: {}: {}, threshold={}",
- role.getName(), failures, threshold);
+ if (log.isDebugEnabled() && failures > 0) {
+ log.debug("Failure count of component: {}: {}, threshold={}",
+ role.getName(), failures, threshold);
+ }
if (failures > threshold) {
throw new TriggerClusterTeardownException(
@@ -1841,7 +1889,7 @@
ConfTreeOperations resources =
instanceDefinition.getResourceOperations();
return resources.getComponentOptInt(roleStatus.getName(),
- ResourceKeys.CONTAINER_FAILURE_THRESHOLD,
+ CONTAINER_FAILURE_THRESHOLD,
failureThreshold);
}
@@ -1855,7 +1903,7 @@
ConfTreeOperations resources =
instanceDefinition.getResourceOperations();
return resources.getComponentOptInt(roleName,
- ResourceKeys.NODE_FAILURE_THRESHOLD,
+ NODE_FAILURE_THRESHOLD,
nodeFailureThreshold);
}
@@ -1879,7 +1927,25 @@
public List<AbstractRMOperation> escalateOutstandingRequests() {
return roleHistory.escalateOutstandingRequests();
}
-
+
+ /**
+ * Cancel any outstanding AA Requests, building up the list of ops to
+ * cancel, removing them from RoleHistory structures and the RoleStatus
+ * entries.
+ * @return a (usually empty) list of cancel/request operations.
+ */
+ public synchronized List<AbstractRMOperation> cancelOutstandingAARequests() {
+ // get the list of cancel operations
+ List<AbstractRMOperation> operations = roleHistory.cancelOutstandingAARequests();
+ for (RoleStatus roleStatus : roleStatusMap.values()) {
+ if (roleStatus.isAARequestOutstanding()) {
+ log.info("Cancelling outstanding AA request for {}", roleStatus);
+ roleStatus.cancelOutstandingAARequest();
+ }
+ }
+ return operations;
+ }
+
/**
* Look at the allocation status of one role, and trigger add/release
* actions if the number of desired role instances doesn't equal
@@ -1896,15 +1962,16 @@
private List<AbstractRMOperation> reviewOneRole(RoleStatus role)
throws SliderInternalStateException, TriggerClusterTeardownException {
List<AbstractRMOperation> operations = new ArrayList<>();
- int delta;
- int expected;
+ long delta;
+ long expected;
String name = role.getName();
synchronized (role) {
delta = role.getDelta();
expected = role.getDesired();
}
- log.info("Reviewing {} : expected {}", role, expected);
+ log.info("Reviewing {} : ", role);
+ log.debug("Expected {}, Delta: {}", expected, delta);
checkFailureThreshold(role);
if (expected < 0 ) {
@@ -1917,38 +1984,53 @@
}
if (delta > 0) {
- log.info("{}: Asking for {} more nodes(s) for a total of {} ", name,
- delta, expected);
// more workers needed than we have -ask for more
- for (int i = 0; i < delta; i++) {
- Resource capability = recordFactory.newResource();
- AMRMClient.ContainerRequest containerAsk =
- buildContainerResourceAndRequest(role, capability);
- log.info("Container ask is {} and label = {}", containerAsk,
- containerAsk.getNodeLabelExpression());
- int askMemory = containerAsk.getCapability().getMemory();
- if (askMemory > this.containerMaxMemory) {
- log.warn("Memory requested: {} > max of {}", askMemory, containerMaxMemory);
+ log.info("{}: Asking for {} more nodes(s) for a total of {} ", name, delta, expected);
+
+ if (role.isAntiAffinePlacement()) {
+ long pending = delta;
+ if (roleHistory.canPlaceAANodes()) {
+ // build one only if there is none outstanding, the role history knows
+ // enough about the cluster to ask, and there is somewhere to place
+ // the node
+ if (!role.isAARequestOutstanding()) {
+ // no outstanding AA; try to place things
+ AMRMClient.ContainerRequest request = createAAContainerRequest(role);
+ if (request != null) {
+ pending--;
+ log.info("Starting an anti-affine request sequence for {} nodes; pending={}",
+ delta, pending);
+ addContainerRequest(operations, request);
+ } else {
+ log.info("No location for anti-affine request");
+ }
+ }
+ } else {
+ log.warn("Awaiting node map before generating anti-affinity requests");
}
- operations.add(new ContainerRequestOperation(containerAsk));
+ log.info("Setting pending to {}", pending);
+ role.setPendingAntiAffineRequests(pending);
+ } else {
+
+ for (int i = 0; i < delta; i++) {
+ //get the role history to select a suitable node, if available
+ addContainerRequest(operations, createContainerRequest(role));
+ }
}
} else if (delta < 0) {
log.info("{}: Asking for {} fewer node(s) for a total of {}", name,
-delta,
expected);
// reduce the number expected (i.e. subtract the delta)
+ long excess = -delta;
- // then pick some containers to kill
- int excess = -delta;
-
- // how many requests are outstanding
- int outstandingRequests = role.getRequested();
+ // how many requests are outstanding? for AA roles, this includes pending
+ long outstandingRequests = role.getRequested() + role.getPendingAntiAffineRequests();
if (outstandingRequests > 0) {
// outstanding requests.
- int toCancel = Math.min(outstandingRequests, excess);
+ int toCancel = (int)Math.min(outstandingRequests, excess);
// Delegate to Role History
-
List<AbstractRMOperation> cancellations = roleHistory.cancelRequestsForRole(role, toCancel);
log.info("Found {} outstanding requests to cancel", cancellations.size());
operations.addAll(cancellations);
@@ -1968,7 +2050,6 @@
}
}
-
// after the cancellation there may be no excess
if (excess > 0) {
@@ -1982,7 +2063,7 @@
log.info("No containers for component {}", roleId);
}
- // cut all release-in-progress nodes
+ // filter out all release-in-progress nodes
ListIterator<RoleInstance> li = containersToRelease.listIterator();
while (li.hasNext()) {
RoleInstance next = li.next();
@@ -2002,16 +2083,13 @@
// ask the release selector to sort the targets
containersToRelease = containerReleaseSelector.sortCandidates(
roleId,
- containersToRelease,
- excess);
+ containersToRelease);
- //crop to the excess
-
- List<RoleInstance> finalCandidates = (excess < numberAvailableForRelease)
- ? containersToRelease.subList(0, excess)
+ // crop to the excess
+ List<RoleInstance> finalCandidates = (excess < numberAvailableForRelease)
+ ? containersToRelease.subList(0, (int)excess)
: containersToRelease;
-
// then build up a release operation, logging each container as released
for (RoleInstance possible : finalCandidates) {
log.info("Targeting for release: {}", possible);
@@ -2020,13 +2098,43 @@
}
}
+ } else {
+ // actual + requested == desired
+ // there's a special case here: clear all pending AA requests
+ if (role.getPendingAntiAffineRequests() > 0) {
+ log.debug("Clearing outstanding pending AA requests");
+ role.setPendingAntiAffineRequests(0);
+ }
}
- // list of operations to execute
+ // there's now a list of operations to execute
+ log.debug("operations scheduled: {}; updated role: {}", operations.size(), role);
return operations;
}
/**
+ * Add a container request if the request is non-null
+ * @param operations operations to add the entry to
+ * @param containerAsk what to ask for
+ * @return true if a request was added
+ */
+ private boolean addContainerRequest(List<AbstractRMOperation> operations,
+ AMRMClient.ContainerRequest containerAsk) {
+ if (containerAsk != null) {
+ log.info("Container ask is {} and label = {}", containerAsk,
+ containerAsk.getNodeLabelExpression());
+ int askMemory = containerAsk.getCapability().getMemory();
+ if (askMemory > this.containerMaxMemory) {
+ log.warn("Memory requested: {} > max of {}", askMemory, containerMaxMemory);
+ }
+ operations.add(new ContainerRequestOperation(containerAsk));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
* Releases a container based on container id
* @param containerId
* @return
@@ -2105,54 +2213,42 @@
* a list of operations to perform
* @param allocatedContainers the containers allocated
* @param assignments the assignments of roles to containers
- * @param releaseOperations any release operations
+ * @param operations any allocation or release operations
*/
public synchronized void onContainersAllocated(List<Container> allocatedContainers,
List<ContainerAssignment> assignments,
- List<AbstractRMOperation> releaseOperations) {
+ List<AbstractRMOperation> operations) {
assignments.clear();
- releaseOperations.clear();
+ operations.clear();
List<Container> ordered = roleHistory.prepareAllocationList(allocatedContainers);
log.debug("onContainersAllocated(): Total containers allocated = {}", ordered.size());
for (Container container : ordered) {
- String containerHostInfo = container.getNodeId().getHost()
- + ":" +
- container.getNodeId().getPort();
+ final NodeId nodeId = container.getNodeId();
+ String containerHostInfo = nodeId.getHost() + ":" + nodeId.getPort();
//get the role
final ContainerId cid = container.getId();
final RoleStatus role = lookupRoleStatus(container);
-
//dec requested count
- decrementRequestCount(role);
+ role.decRequested();
//inc allocated count -this may need to be dropped in a moment,
// but us needed to update the logic below
- final int allocated = role.incActual();
- final int desired = role.getDesired();
+ final long allocated = role.incActual();
+ final long desired = role.getDesired();
final String roleName = role.getName();
- final ContainerAllocation allocation =
+ final ContainerAllocationResults allocation =
roleHistory.onContainerAllocated(container, desired, allocated);
final ContainerAllocationOutcome outcome = allocation.outcome;
- // cancel an allocation request which granted this, so as to avoid repeated
- // requests
- if (allocation.origin != null && allocation.origin.getIssuedRequest() != null) {
- releaseOperations.add(allocation.origin.createCancelOperation());
- } else {
- // there's a request, but no idea what to cancel.
- // rather than try to recover from it inelegantly, (and cause more confusion),
- // log the event, but otherwise continue
- log.warn("Unexpected allocation of container "
- + SliderUtils.containerToString(container));
- }
+ // add all requests to the operations list
+ operations.addAll(allocation.operations);
//look for condition where we get more back than we asked
if (allocated > desired) {
- log.info("Discarding surplus {} container {} on {}", roleName, cid,
- containerHostInfo);
- releaseOperations.add(new ContainerReleaseOperation(cid));
+ log.info("Discarding surplus {} container {} on {}", roleName, cid, containerHostInfo);
+ operations.add(new ContainerReleaseOperation(cid));
//register as a surplus node
surplusNodes.add(cid);
surplusContainers.inc();
@@ -2168,13 +2264,34 @@
" on {}:{},",
roleName,
cid,
- container.getNodeId().getHost(),
- container.getNodeId().getPort()
- );
+ nodeId.getHost(),
+ nodeId.getPort());
assignments.add(new ContainerAssignment(container, role, outcome));
//add to the history
roleHistory.onContainerAssigned(container);
+ // now for AA requests, add some more
+ if (role.isAntiAffinePlacement()) {
+ role.completeOutstandingAARequest();
+ // check invariants. The new node must become unavailable.
+ NodeInstance node = roleHistory.getOrCreateNodeInstance(container);
+ if (node.canHost(role.getKey(), role.getLabelExpression())) {
+ log.error("Assigned node still declares as available {}", node.toFullString() );
+ }
+ if (role.getPendingAntiAffineRequests() > 0) {
+ // still an outstanding AA request: need to issue a new one.
+ log.info("Asking for next container for AA role {}", roleName);
+ if (!addContainerRequest(operations, createAAContainerRequest(role))) {
+ log.info("No capacity in cluster for new requests");
+ } else {
+ role.decPendingAntiAffineRequests();
+ }
+ log.debug("Current AA role status {}", role);
+ } else {
+ log.info("AA request sequence completed for role {}", role);
+ }
+ }
+
}
}
}
@@ -2237,7 +2354,7 @@
cid,
roleName,
containerHostInfo);
-
+
//update app state internal structures and maps
RoleInstance instance = new RoleInstance(container);
@@ -2257,4 +2374,32 @@
// now pretend it has just started
innerOnNodeManagerContainerStarted(cid);
}
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("AppState{");
+ sb.append("applicationLive=").append(applicationLive);
+ sb.append(", live nodes=").append(liveNodes.size());
+ sb.append(", startedContainers=").append(startedContainers);
+ sb.append(", startFailedContainerCount=").append(startFailedContainerCount);
+ sb.append(", surplusContainers=").append(surplusContainers);
+ sb.append(", failedContainerCount=").append(failedContainerCount);
+ sb.append(", outstanding non-AA Container Requests=")
+ .append(outstandingContainerRequests);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ /**
+ * Build map of role ID-> name
+ * @return
+ */
+ public Map<Integer, String> buildNamingMap() {
+ Map<Integer, RoleStatus> statusMap = getRoleStatusMap();
+ Map<Integer, String> naming = new HashMap<>(statusMap.size());
+ for (Map.Entry<Integer, RoleStatus> entry : statusMap.entrySet()) {
+ naming.put(entry.getKey(), entry.getValue().getName());
+ }
+ return naming;
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppStateBindingInfo.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppStateBindingInfo.java
new file mode 100644
index 0000000..a8aa1a2
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppStateBindingInfo.java
@@ -0,0 +1,63 @@
+/*
+ * 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.slider.server.appmaster.state;
+
+import com.google.common.base.Preconditions;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.yarn.api.records.Container;
+import org.apache.hadoop.yarn.api.records.NodeReport;
+import org.apache.slider.core.conf.AggregateConf;
+import org.apache.slider.providers.ProviderRole;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Binding information for application states; designed to be extensible
+ * so that tests don't have to be massivley reworked when new arguments
+ * are added.
+ */
+public class AppStateBindingInfo {
+ public AggregateConf instanceDefinition;
+ public Configuration serviceConfig = new Configuration();
+ public Configuration publishedProviderConf = new Configuration(false);
+ public List<ProviderRole> roles = new ArrayList<>();
+ public FileSystem fs;
+ public Path historyPath;
+ public List<Container> liveContainers = new ArrayList<>(0);
+ public Map<String, String> applicationInfo = new HashMap<>();
+ public ContainerReleaseSelector releaseSelector = new SimpleReleaseSelector();
+ /** node reports off the RM. */
+ public List<NodeReport> nodeReports = new ArrayList<>(0);
+
+ public void validate() throws IllegalArgumentException {
+ Preconditions.checkArgument(instanceDefinition != null, "null instanceDefinition");
+ Preconditions.checkArgument(serviceConfig != null, "null appmasterConfig");
+ Preconditions.checkArgument(publishedProviderConf != null, "null publishedProviderConf");
+ Preconditions.checkArgument(releaseSelector != null, "null releaseSelector");
+ Preconditions.checkArgument(roles != null, "null providerRoles");
+ Preconditions.checkArgument(fs != null, "null fs");
+ Preconditions.checkArgument(historyPath != null, "null historyDir");
+ Preconditions.checkArgument(nodeReports != null, "null nodeReports");
+ }
+}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerAllocation.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerAllocationResults.java
similarity index 77%
rename from slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerAllocation.java
rename to slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerAllocationResults.java
index 306ffb2..e80639e 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerAllocation.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerAllocationResults.java
@@ -18,10 +18,15 @@
package org.apache.slider.server.appmaster.state;
+import org.apache.slider.server.appmaster.operations.AbstractRMOperation;
+
+import java.util.ArrayList;
+import java.util.List;
+
/**
* This is just a tuple of the outcome of a container allocation
*/
-public class ContainerAllocation {
+public class ContainerAllocationResults {
/**
* What was the outcome of this allocation: placed, escalated, ...
@@ -35,12 +40,11 @@
*/
public OutstandingRequest origin;
- public ContainerAllocation(ContainerAllocationOutcome outcome,
- OutstandingRequest origin) {
- this.outcome = outcome;
- this.origin = origin;
- }
+ /**
+ * A possibly empty list of requests to add to the follow-up actions
+ */
+ public List<AbstractRMOperation> operations = new ArrayList<>(0);
- public ContainerAllocation() {
+ public ContainerAllocationResults() {
}
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerPriority.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerPriority.java
index 3cc2106..0322f83 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerPriority.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerPriority.java
@@ -57,10 +57,9 @@
locationSpecified));
return pri;
}
-
-
+
public static int extractRole(int priority) {
- return priority >= NOLOCATION ? priority^NOLOCATION : priority;
+ return priority >= NOLOCATION ? priority ^ NOLOCATION : priority;
}
/**
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerReleaseSelector.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerReleaseSelector.java
index 0cbc134..fafbada 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerReleaseSelector.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerReleaseSelector.java
@@ -30,9 +30,8 @@
* Given a list of candidate containers, return a sorted version of the priority
* in which they should be released.
* @param candidates candidate list ... everything considered suitable
- * @return
+ * @return the list of candidates
*/
List<RoleInstance> sortCandidates(int roleId,
- List<RoleInstance> candidates,
- int minimumToSelect);
+ List<RoleInstance> candidates);
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/MostRecentContainerReleaseSelector.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/MostRecentContainerReleaseSelector.java
index 9d936a1..38c5b8e 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/MostRecentContainerReleaseSelector.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/MostRecentContainerReleaseSelector.java
@@ -32,8 +32,7 @@
@Override
public List<RoleInstance> sortCandidates(int roleId,
- List<RoleInstance> candidates,
- int minimumToSelect) {
+ List<RoleInstance> candidates) {
Collections.sort(candidates, new newerThan());
return candidates;
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeEntry.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeEntry.java
index 8ff0895..cf3881e 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeEntry.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeEntry.java
@@ -18,6 +18,7 @@
package org.apache.slider.server.appmaster.state;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.slider.api.types.NodeEntryInformation;
/**
@@ -37,7 +38,7 @@
* <p>
*
*/
-public class NodeEntry {
+public class NodeEntry implements Cloneable {
public final int rolePriority;
@@ -89,7 +90,16 @@
* the number of instances > 1.
*/
public synchronized boolean isAvailable() {
- return getActive() == 0 && (requested == 0) && starting == 0;
+ return live + requested + starting - releasing <= 0;
+ }
+
+ /**
+ * Are the anti-affinity constraints held. That is, zero or one
+ * node running or starting
+ * @return true if the constraint holds.
+ */
+ public synchronized boolean isAntiAffinityConstraintHeld() {
+ return (live - releasing + starting) <= 1;
}
/**
@@ -256,10 +266,16 @@
return failedRecently;
}
+ @VisibleForTesting
+ public synchronized void setFailedRecently(int failedRecently) {
+ this.failedRecently = failedRecently;
+ }
+
public synchronized int getPreempted() {
return preempted;
}
+
/**
* Reset the failed recently count.
*/
@@ -301,4 +317,9 @@
info.lastUsed = lastUsed;
return info;
}
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeInstance.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeInstance.java
index 2afdc42..cc17cf0 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeInstance.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeInstance.java
@@ -18,17 +18,20 @@
package org.apache.slider.server.appmaster.state;
+import org.apache.hadoop.yarn.api.records.Container;
import org.apache.hadoop.yarn.api.records.NodeReport;
import org.apache.hadoop.yarn.api.records.NodeState;
-import org.apache.slider.api.types.NodeEntryInformation;
import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.common.tools.Comparators;
import org.apache.slider.common.tools.SliderUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
+import java.util.Map;
/**
* A node instance -stores information about a node in the cluster.
@@ -45,6 +48,9 @@
*/
private NodeState nodeState = NodeState.RUNNING;
+ /**
+ * Last node report. If null: none
+ */
private NodeReport nodeReport = null;
/**
@@ -52,6 +58,18 @@
*/
private long nodeStateUpdateTime = 0;
+ /**
+ * Node labels.
+ *
+ * IMPORTANT: we assume that there is one label/node, which is the policy
+ * for Hadoop as of November 2015
+ */
+ private String nodeLabels = "";
+
+ /**
+ * An unordered list of node entries of specific roles. There's nothing
+ * indexed so as to support sparser datastructures.
+ */
private final List<NodeEntry> nodeEntries;
/**
@@ -63,18 +81,35 @@
nodeEntries = new ArrayList<>(roles);
}
-
/**
- * Update the node status
+ * Update the node status.
+ * The return code is true if the node state changed enough to
+ * trigger a re-evaluation of pending requests. That is, either a node
+ * became available when it was previously not, or the label changed
+ * on an available node.
+ *
+ * Transitions of a node from live to dead aren't treated as significant,
+ * nor label changes on a dead node.
+ *
* @param report latest node report
- * @return true if the node state changed
+ * @return true if the node state changed enough for a request evaluation.
*/
- public boolean updateNode(NodeReport report) {
+ public synchronized boolean updateNode(NodeReport report) {
+ nodeStateUpdateTime = report.getLastHealthReportTime();
nodeReport = report;
NodeState oldState = nodeState;
+ boolean oldStateUnusable = oldState.isUnusable();
nodeState = report.getNodeState();
- nodeStateUpdateTime = report.getLastHealthReportTime();
- return nodeState != oldState;
+ boolean newUsable = !nodeState.isUnusable();
+ boolean nodeNowAvailable = oldStateUnusable && newUsable;
+ String labels = this.nodeLabels;
+ nodeLabels = SliderUtils.extractNodeLabel(report);
+ return nodeNowAvailable
+ || newUsable && !this.nodeLabels.equals(labels);
+ }
+
+ public String getNodeLabels() {
+ return nodeLabels;
}
/**
@@ -108,6 +143,15 @@
}
/**
+ * Get the node entry matching a container on this node
+ * @param container container
+ * @return matching node instance for the role
+ */
+ public NodeEntry getOrCreate(Container container) {
+ return getOrCreate(ContainerPriority.extractRole(container));
+ }
+
+ /**
* Count the number of active role instances on this node
* @param role role index
* @return 0 if there are none, otherwise the #of nodes that are running and
@@ -129,6 +173,14 @@
}
/**
+ * Is the node considered online
+ * @return the node
+ */
+ public boolean isOnline() {
+ return !nodeState.isUnusable();
+ }
+
+ /**
* Query for a node being considered unreliable
* @param role role key
* @param threshold threshold above which a node is considered unreliable
@@ -136,7 +188,6 @@
*/
public boolean isConsideredUnreliable(int role, int threshold) {
NodeEntry entry = get(role);
-
return entry != null && entry.getFailedRecently() > threshold;
}
@@ -158,7 +209,6 @@
nodeEntries.add(nodeEntry);
}
-
/**
* run through each entry; gc'ing & removing old ones that don't have
* a recent failure count (we care about those)
@@ -201,11 +251,12 @@
public String toFullString() {
final StringBuilder sb =
new StringBuilder(toString());
- int i = 0;
+ sb.append("{ ");
for (NodeEntry entry : nodeEntries) {
sb.append(String.format("\n [%02d] ", entry.rolePriority));
sb.append(entry.toString());
}
+ sb.append("} ");
return sb.toString();
}
@@ -249,39 +300,59 @@
/**
* Produced a serialized form which can be served up as JSON
+ * @param naming map of priority -> value for naming entries
* @return a summary of the current role status.
*/
- public synchronized NodeInformation serialize() {
+ public synchronized NodeInformation serialize(Map<Integer, String> naming) {
NodeInformation info = new NodeInformation();
info.hostname = hostname;
// null-handling state constructor
info.state = "" + nodeState;
info.lastUpdated = nodeStateUpdateTime;
+ info.labels = nodeLabels;
if (nodeReport != null) {
info.httpAddress = nodeReport.getHttpAddress();
info.rackName = nodeReport.getRackName();
- info.labels = SliderUtils.join(nodeReport.getNodeLabels(), ", ", false);
info.healthReport = nodeReport.getHealthReport();
}
- info.entries = new ArrayList<>(nodeEntries.size());
+ info.entries = new HashMap<>(nodeEntries.size());
for (NodeEntry nodeEntry : nodeEntries) {
- info.entries.add(nodeEntry.serialize());
+ String name = naming.get(nodeEntry.rolePriority);
+ if (name == null) {
+ name = Integer.toString(nodeEntry.rolePriority);
+ }
+ info.entries.put(name, nodeEntry.serialize());
}
return info;
}
/**
+ * Is this node instance a suitable candidate for the specific role?
+ * @param role role ID
+ * @param label label which must match, or "" for no label checks
+ * @return true if the node has space for this role, is running and the labels
+ * match.
+ */
+ public boolean canHost(int role, String label) {
+ return isOnline()
+ && (SliderUtils.isUnset(label) || label.equals(nodeLabels)) // label match
+ && getOrCreate(role).isAvailable(); // no live role
+ }
+
+ /**
* A comparator for sorting entries where the node is preferred over another.
- * <p>
- * The exact algorithm may change
- *
+ *
+ * The exact algorithm may change: current policy is "most recent first", so sorted
+ * on the lastUsed
+ *
* the comparision is a positive int if left is preferred to right;
* negative if right over left, 0 for equal
*/
- public static class Preferred implements Comparator<NodeInstance>,
- Serializable {
+ public static class Preferred implements Comparator<NodeInstance>, Serializable {
- final int role;
+ private static final Comparators.InvertedLongComparator comparator =
+ new Comparators.InvertedLongComparator();
+ private final int role;
public Preferred(int role) {
this.role = role;
@@ -291,16 +362,9 @@
public int compare(NodeInstance o1, NodeInstance o2) {
NodeEntry left = o1.get(role);
NodeEntry right = o2.get(role);
- long ageL = left != null ? left.getLastUsed() : 0;
- long ageR = right != null ? right.getLastUsed() : 0;
-
- if (ageL > ageR) {
- return -1;
- } else if (ageL < ageR) {
- return 1;
- }
- // equal
- return 0;
+ long ageL = left != null ? left.getLastUsed() : -1;
+ long ageR = right != null ? right.getLastUsed() : -1;
+ return comparator.compare(ageL, ageR);
}
}
@@ -313,7 +377,7 @@
public static class MoreActiveThan implements Comparator<NodeInstance>,
Serializable {
- final int role;
+ private final int role;
public MoreActiveThan(int role) {
this.role = role;
@@ -326,5 +390,20 @@
return activeRight - activeLeft;
}
}
+ /**
+ * A comparator for sorting entries alphabetically
+ */
+ public static class CompareNames implements Comparator<NodeInstance>,
+ Serializable {
+
+ public CompareNames() {
+ }
+
+ @Override
+ public int compare(NodeInstance left, NodeInstance right) {
+ return left.hostname.compareTo(right.hostname);
+ }
+ }
+
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeMap.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeMap.java
index b631057..3858b68 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeMap.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/NodeMap.java
@@ -92,20 +92,24 @@
}
}
-
/**
- * Update the node state
+ * Update the node state. Return true if the node state changed: either by
+ * being created, or by changing its internal state as defined
+ * by {@link NodeInstance#updateNode(NodeReport)}.
+ *
* @param hostname host name
* @param report latest node report
- * @return the updated node.
+ * @return true if the node state changed enough for a request evaluation.
*/
public boolean updateNode(String hostname, NodeReport report) {
- return getOrCreate(hostname).updateNode(report);
+ boolean nodeExisted = get(hostname) != null;
+ boolean updated = getOrCreate(hostname).updateNode(report);
+ return updated || !nodeExisted;
}
/**
* Clone point
- * @return
+ * @return a shallow clone
*/
@Override
public Object clone() {
@@ -123,4 +127,48 @@
put(node.hostname, node);
}
}
+
+ /**
+ * Test helper: build or update a cluster from a list of node reports
+ * @param reports the list of reports
+ * @return true if this has been considered to have changed the cluster
+ */
+ @VisibleForTesting
+ public boolean buildOrUpdate(List<NodeReport> reports) {
+ boolean updated = false;
+ for (NodeReport report : reports) {
+ updated |= getOrCreate(report.getNodeId().getHost()).updateNode(report);
+ }
+ return updated;
+ }
+
+ /**
+ * Scan the current node map for all nodes capable of hosting an instance
+ * @param role role ID
+ * @param label label which must match, or "" for no label checks
+ * @return a possibly empty list of node instances matching the criteria.
+ */
+ public List<NodeInstance> findAllNodesForRole(int role, String label) {
+ List<NodeInstance> nodes = new ArrayList<>(size());
+ for (NodeInstance instance : values()) {
+ if (instance.canHost(role, label)) {
+ nodes.add(instance);
+ }
+ }
+ Collections.sort(nodes, new NodeInstance.CompareNames());
+ return nodes;
+ }
+
+ @Override
+ public synchronized String toString() {
+ final StringBuilder sb = new StringBuilder("NodeMap{");
+ List<String> keys = new ArrayList<>(keySet());
+ Collections.sort(keys);
+ for (String key : keys) {
+ sb.append(key).append(": ");
+ sb.append(get(key).toFullString()).append("\n");
+ }
+ sb.append('}');
+ return sb.toString();
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequest.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequest.java
index f5689dd..3a75f27 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequest.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequest.java
@@ -29,6 +29,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -43,24 +44,21 @@
* instance constructed with (role, hostname) can be used to look up
* a complete request instance in the {@link OutstandingRequestTracker} map
*/
-public final class OutstandingRequest {
+public final class OutstandingRequest extends RoleHostnamePair {
protected static final Logger log =
LoggerFactory.getLogger(OutstandingRequest.class);
/**
- * requested role
- */
- public final int roleId;
-
- /**
* Node the request is for -may be null
*/
public final NodeInstance node;
-
+
/**
- * hostname -will be null if node==null
+ * A list of all possible nodes to list in an AA request. For a non-AA
+ * request where {@link #node} is set, element 0 of the list is the same
+ * value.
*/
- public final String hostname;
+ public final List<NodeInstance> nodes = new ArrayList<>(1);
/**
* Optional label. This is cached as the request option (explicit-location + label) is forbidden,
@@ -71,21 +69,21 @@
/**
* Requested time in millis.
* <p>
- * Only valid after {@link #buildContainerRequest(Resource, RoleStatus, long, String)}
+ * Only valid after {@link #buildContainerRequest(Resource, RoleStatus, long)}
*/
private AMRMClient.ContainerRequest issuedRequest;
/**
* Requested time in millis.
* <p>
- * Only valid after {@link #buildContainerRequest(Resource, RoleStatus, long, String)}
+ * Only valid after {@link #buildContainerRequest(Resource, RoleStatus, long)}
*/
private long requestedTimeMillis;
/**
* Time in millis after which escalation should be triggered..
* <p>
- * Only valid after {@link #buildContainerRequest(Resource, RoleStatus, long, String)}
+ * Only valid after {@link #buildContainerRequest(Resource, RoleStatus, long)}
*/
private long escalationTimeoutMillis;
@@ -105,15 +103,21 @@
private int priority = -1;
/**
+ * Is this an Anti-affine request which should be cancelled on
+ * a cluster resize?
+ */
+ private boolean antiAffine = false;
+
+ /**
* Create a request
* @param roleId role
* @param node node -can be null
*/
public OutstandingRequest(int roleId,
NodeInstance node) {
- this.roleId = roleId;
+ super(roleId, node != null ? node.hostname : null);
this.node = node;
- this.hostname = node != null ? node.hostname : null;
+ nodes.add(node);
}
/**
@@ -125,9 +129,21 @@
* @param hostname hostname
*/
public OutstandingRequest(int roleId, String hostname) {
+ super(roleId, hostname);
this.node = null;
- this.roleId = roleId;
- this.hostname = hostname;
+ }
+
+ /**
+ * Create an Anti-affine reques, including all listed nodes (there must be one)
+ * as targets.
+ * @param roleId role
+ * @param nodes list of nodes
+ */
+ public OutstandingRequest(int roleId, List<NodeInstance> nodes) {
+ super(roleId, nodes.get(0).hostname);
+ this.node = null;
+ this.antiAffine = true;
+ this.nodes.addAll(nodes);
}
/**
@@ -162,6 +178,14 @@
return priority;
}
+ public boolean isAntiAffine() {
+ return antiAffine;
+ }
+
+ public void setAntiAffine(boolean antiAffine) {
+ this.antiAffine = antiAffine;
+ }
+
/**
* Build a container request.
* <p>
@@ -178,16 +202,15 @@
* @param resource resource
* @param role role
* @param time time in millis to record as request time
- * @param labelExpression label to satisfy
* @return the request to raise
*/
public synchronized AMRMClient.ContainerRequest buildContainerRequest(
- Resource resource, RoleStatus role, long time, String labelExpression) {
+ Resource resource, RoleStatus role, long time) {
Preconditions.checkArgument(resource != null, "null `resource` arg");
Preconditions.checkArgument(role != null, "null `role` arg");
// cache label for escalation
- label = labelExpression;
+ label = role.getLabelExpression();
requestedTimeMillis = time;
escalationTimeoutMillis = time + role.getPlacementTimeoutSeconds() * 1000;
String[] hosts;
@@ -196,7 +219,23 @@
NodeInstance target = this.node;
String nodeLabels;
- if (target != null) {
+ if (isAntiAffine()) {
+ int size = nodes.size();
+ log.info("Creating anti-affine request across {} nodes; first node = {}",
+ size, hostname);
+ hosts = new String[size];
+ StringBuilder builder = new StringBuilder(size * 16);
+ int c = 0;
+ for (NodeInstance nodeInstance : nodes) {
+ hosts[c++] = nodeInstance.hostname;
+ builder.append(nodeInstance.hostname).append(" ");
+ }
+ log.debug("Full host list: [ {}]", builder);
+ escalated = false;
+ mayEscalate = false;
+ relaxLocality = false;
+ nodeLabels = null;
+ } else if (target != null) {
// placed request. Hostname is used in request
hosts = new String[1];
hosts[0] = target.hostname;
@@ -218,7 +257,7 @@
escalated = true;
// and forbid it happening
mayEscalate = false;
- nodeLabels = labelExpression;
+ nodeLabels = label;
}
Priority pri = ContainerPriority.createPriority(roleId, !relaxLocality);
priority = pri.getPriority();
@@ -228,7 +267,6 @@
pri,
relaxLocality,
nodeLabels);
-
validate();
return issuedRequest;
}
@@ -254,7 +292,7 @@
String[] nodes;
List<String> issuedRequestNodes = issuedRequest.getNodes();
- if (label == null && issuedRequestNodes != null) {
+ if (SliderUtils.isUnset(label) && issuedRequestNodes != null) {
nodes = issuedRequestNodes.toArray(new String[issuedRequestNodes.size()]);
} else {
nodes = null;
@@ -302,58 +340,22 @@
return issuedRequest != null && issuedRequest.getCapability().equals(resource);
}
- /**
- * Equality is on hostname and role
- * @param o other
- * @return true on a match
- */
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- OutstandingRequest request = (OutstandingRequest) o;
-
- if (roleId != request.roleId) {
- return false;
- }
- if (hostname != null
- ? !hostname.equals(request.hostname)
- : request.hostname != null) {
- return false;
- }
- return true;
- }
-
- /**
- * hash on hostname and role
- * @return hash code
- */
- @Override
- public int hashCode() {
- int result = roleId;
- result = 31 * result + (hostname != null ? hostname.hashCode() : 0);
- return result;
- }
-
@Override
public String toString() {
- int requestRoleId = ContainerPriority.extractRole(getPriority());
boolean requestHasLocation = ContainerPriority.hasLocation(getPriority());
final StringBuilder sb = new StringBuilder("OutstandingRequest{");
- sb.append("roleId=").append(this.roleId);
+ sb.append("roleId=").append(roleId);
+ if (hostname != null) {
+ sb.append(", hostname='").append(hostname).append('\'');
+ }
sb.append(", node=").append(node);
- sb.append(", hostname='").append(hostname).append('\'');
sb.append(", hasLocation=").append(requestHasLocation);
sb.append(", requestedTimeMillis=").append(requestedTimeMillis);
sb.append(", mayEscalate=").append(mayEscalate);
sb.append(", escalated=").append(escalated);
sb.append(", escalationTimeoutMillis=").append(escalationTimeoutMillis);
- sb.append(", issuedRequest=").append(SliderUtils.requestToString(issuedRequest));
+ sb.append(", issuedRequest=").append(
+ issuedRequest != null ? SliderUtils.requestToString(issuedRequest) : "(null)");
sb.append('}');
return sb.toString();
}
@@ -367,14 +369,13 @@
return new CancelSingleRequest(issuedRequest);
}
-
/**
* Valid if a node label expression specified on container request is valid or
* not. Mimics the logic in AMRMClientImpl, so can be used for preflight checking
* and in mock tests
*
*/
- public void validate() throws InvalidContainerRequestException {
+ public void validate() throws InvalidContainerRequestException {
Preconditions.checkNotNull(issuedRequest, "request has not yet been built up");
AMRMClient.ContainerRequest containerRequest = issuedRequest;
String exp = containerRequest.getNodeLabelExpression();
@@ -390,7 +391,7 @@
+ " in a single node label expression: " + this);
}
- // Don't allow specify node label against ANY request
+ // Don't allow specify node label against ANY request listing hosts or racks
if ((containerRequest.getRacks() != null &&
(!containerRequest.getRacks().isEmpty()))
||
@@ -410,5 +411,12 @@
}
}
+ /**
+ * Create a new role/hostname pair for indexing.
+ * @return a new index.
+ */
+ public RoleHostnamePair getIndex() {
+ return new RoleHostnamePair(roleId, hostname);
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequestTracker.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequestTracker.java
index a8787f0..64698f2 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequestTracker.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequestTracker.java
@@ -35,10 +35,12 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
+import java.util.Set;
/**
* Tracks outstanding requests made with a specific placement option.
@@ -62,8 +64,7 @@
*/
private final List<AbstractRMOperation> NO_REQUESTS = new ArrayList<>(0);
- private Map<OutstandingRequest, OutstandingRequest> placedRequests =
- new HashMap<>();
+ private Map<RoleHostnamePair, OutstandingRequest> placedRequests = new HashMap<>();
/**
* List of open requests; no specific details on them.
@@ -82,10 +83,9 @@
* @return a new request
*/
public synchronized OutstandingRequest newRequest(NodeInstance instance, int role) {
- OutstandingRequest request =
- new OutstandingRequest(role, instance);
+ OutstandingRequest request = new OutstandingRequest(role, instance);
if (request.isLocated()) {
- placedRequests.put(request, request);
+ placedRequests.put(request.getIndex(), request);
} else {
openRequests.add(request);
}
@@ -93,6 +93,31 @@
}
/**
+ * Create a new Anti-affine request for the specific role
+ * <p>
+ * It is added to {@link #openRequests}
+ * <p>
+ * This does not update the node instance's role's request count
+ * @param role role index
+ * @param nodes list of suitable nodes
+ * @param label label to use
+ * @return a new request
+ */
+ public synchronized OutstandingRequest newAARequest(int role,
+ List<NodeInstance> nodes,
+ String label) {
+ Preconditions.checkArgument(!nodes.isEmpty());
+ // safety check to verify the allocation will hold
+ for (NodeInstance node : nodes) {
+ Preconditions.checkState(node.canHost(role, label),
+ "Cannot allocate role ID %d to node %s", role, node);
+ }
+ OutstandingRequest request = new OutstandingRequest(role, nodes);
+ openRequests.add(request);
+ return request;
+ }
+
+ /**
* Look up any oustanding request to a (role, hostname).
* @param role role index
* @param hostname hostname
@@ -101,7 +126,7 @@
@VisibleForTesting
public synchronized OutstandingRequest lookupPlacedRequest(int role, String hostname) {
Preconditions.checkArgument(hostname != null, "null hostname");
- return placedRequests.get(new OutstandingRequest(role, hostname));
+ return placedRequests.get(new RoleHostnamePair(role, hostname));
}
/**
@@ -115,25 +140,30 @@
}
/**
- * Notification that a container has been allocated -drop it
- * from the {@link #placedRequests} structure.
+ * Notification that a container has been allocated
+ *
+ * <ol>
+ * <li>drop it from the {@link #placedRequests} structure.</li>
+ * <li>generate the cancellation request</li>
+ * <li>for AA placement, any actions needed</li>
+ * </ol>
+ *
* @param role role index
* @param hostname hostname
* @return the allocation outcome
*/
- public synchronized ContainerAllocation onContainerAllocated(int role,
+ public synchronized ContainerAllocationResults onContainerAllocated(int role,
String hostname,
Container container) {
final String containerDetails = SliderUtils.containerToString(container);
log.debug("Processing allocation for role {} on {}", role,
containerDetails);
- ContainerAllocation allocation = new ContainerAllocation();
+ ContainerAllocationResults allocation = new ContainerAllocationResults();
ContainerAllocationOutcome outcome;
- OutstandingRequest request =
- placedRequests.remove(new OutstandingRequest(role, hostname));
+ OutstandingRequest request = placedRequests.remove(new OutstandingRequest(role, hostname));
if (request != null) {
//satisfied request
- log.debug("Found placed request for container: {}", request);
+ log.debug("Found oustanding placed request for container: {}", request);
request.completed();
// derive outcome from status of tracked request
outcome = request.isEscalated()
@@ -144,16 +174,25 @@
// scan through all containers in the open request list
request = removeOpenRequest(container);
if (request != null) {
- log.debug("Found open request for container: {}", request);
+ log.debug("Found open outstanding request for container: {}", request);
request.completed();
outcome = ContainerAllocationOutcome.Open;
} else {
- log.warn("No open request found for container {}, outstanding queue has {} entries ",
+ log.warn("No oustanding request found for container {}, outstanding queue has {} entries ",
containerDetails,
openRequests.size());
outcome = ContainerAllocationOutcome.Unallocated;
}
}
+ if (request != null && request.getIssuedRequest() != null) {
+ allocation.operations.add(request.createCancelOperation());
+ } else {
+ // there's a request, but no idea what to cancel.
+ // rather than try to recover from it inelegantly, (and cause more confusion),
+ // log the event, but otherwise continue
+ log.warn("Unexpected allocation of container " + SliderUtils.containerToString(container));
+ }
+
allocation.origin = request;
allocation.outcome = outcome;
return allocation;
@@ -280,12 +319,12 @@
*/
public synchronized List<NodeInstance> resetOutstandingRequests(int role) {
List<NodeInstance> hosts = new ArrayList<>();
- Iterator<Map.Entry<OutstandingRequest,OutstandingRequest>> iterator =
+ Iterator<Map.Entry<RoleHostnamePair, OutstandingRequest>> iterator =
placedRequests.entrySet().iterator();
while (iterator.hasNext()) {
- Map.Entry<OutstandingRequest, OutstandingRequest> next =
+ Map.Entry<RoleHostnamePair, OutstandingRequest> next =
iterator.next();
- OutstandingRequest request = next.getKey();
+ OutstandingRequest request = next.getValue();
if (request.roleId == role) {
iterator.remove();
request.completed();
@@ -350,6 +389,47 @@
}
/**
+ * Cancel all outstanding AA requests from the lists of requests.
+ *
+ * This does not remove them from the role status; they must be reset
+ * by the caller.
+ *
+ */
+ @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
+ public synchronized List<AbstractRMOperation> cancelOutstandingAARequests() {
+
+ log.debug("Looking for AA request to cancel");
+ List<AbstractRMOperation> operations = new ArrayList<>();
+
+ // first, all placed requests
+ for (Map.Entry<RoleHostnamePair, OutstandingRequest> entry : placedRequests.entrySet()) {
+ OutstandingRequest outstandingRequest = entry.getValue();
+ synchronized (outstandingRequest) {
+ if (outstandingRequest.isAntiAffine()) {
+ // time to escalate
+ operations.add(outstandingRequest.createCancelOperation());
+ placedRequests.remove(entry.getKey());
+ }
+ }
+ }
+ // second, all open requests
+ ListIterator<OutstandingRequest> orit = openRequests.listIterator();
+ while (orit.hasNext()) {
+ OutstandingRequest outstandingRequest = orit.next();
+ synchronized (outstandingRequest) {
+ if (outstandingRequest.isAntiAffine()) {
+ // time to escalate
+ operations.add(outstandingRequest.createCancelOperation());
+ orit.remove();
+ }
+ }
+ }
+ log.info("Cancelling {} outstanding AA requests", operations.size());
+
+ return operations;
+ }
+
+ /**
* Extract a specific number of open requests for a role
* @param roleId role Id
* @param count count to extract
@@ -368,6 +448,7 @@
}
return results;
}
+
/**
* Extract a specific number of placed requests for a role
* @param roleId role Id
@@ -376,9 +457,10 @@
*/
public synchronized List<OutstandingRequest> extractPlacedRequestsForRole(int roleId, int count) {
List<OutstandingRequest> results = new ArrayList<>();
- Iterator<OutstandingRequest> iterator = placedRequests.keySet().iterator();
+ Iterator<Map.Entry<RoleHostnamePair, OutstandingRequest>>
+ iterator = placedRequests.entrySet().iterator();
while (iterator.hasNext() && count > 0) {
- OutstandingRequest request = iterator.next();
+ OutstandingRequest request = iterator.next().getValue();
if (request.roleId == roleId) {
results.add(request);
count--;
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ProviderAppState.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ProviderAppState.java
index 82b2f2a..c409114 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ProviderAppState.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ProviderAppState.java
@@ -26,6 +26,7 @@
import org.apache.slider.api.types.ApplicationLivenessInformation;
import org.apache.slider.api.types.ComponentInformation;
import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.RoleStatistics;
import org.apache.slider.core.conf.AggregateConf;
import org.apache.slider.core.conf.ConfTreeOperations;
import org.apache.slider.core.exceptions.NoSuchNodeException;
@@ -290,12 +291,18 @@
@Override
public Map<String, NodeInformation> getNodeInformationSnapshot() {
- return appState.getRoleHistory().getNodeInformationSnapshot();
+ return appState.getRoleHistory()
+ .getNodeInformationSnapshot(appState.buildNamingMap());
}
@Override
public NodeInformation getNodeInformation(String hostname) {
- return appState.getRoleHistory().getNodeInformation(hostname);
+ return appState.getRoleHistory()
+ .getNodeInformation(hostname, appState.buildNamingMap());
}
+ @Override
+ public RoleStatistics getRoleStatistics() {
+ return appState.getRoleStatistics();
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHistory.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHistory.java
index df3983a..0584d30 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHistory.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHistory.java
@@ -19,19 +19,18 @@
package org.apache.slider.server.appmaster.state;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.yarn.api.records.Container;
import org.apache.hadoop.yarn.api.records.NodeReport;
import org.apache.hadoop.yarn.api.records.NodeState;
import org.apache.hadoop.yarn.api.records.Resource;
-import org.apache.hadoop.yarn.client.api.AMRMClient;
import org.apache.slider.api.types.NodeInformation;
import org.apache.slider.common.tools.SliderUtils;
import org.apache.slider.core.exceptions.BadConfigException;
import org.apache.slider.providers.ProviderRole;
import org.apache.slider.server.appmaster.management.BoolMetric;
-import org.apache.slider.server.appmaster.management.LongGauge;
import org.apache.slider.server.appmaster.management.MetricsAndMonitoring;
import org.apache.slider.server.appmaster.management.Timestamp;
import org.apache.slider.server.appmaster.operations.AbstractRMOperation;
@@ -47,11 +46,10 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
/**
* The Role History.
@@ -71,12 +69,17 @@
protected static final Logger log =
LoggerFactory.getLogger(RoleHistory.class);
private final List<ProviderRole> providerRoles;
+ /** the roles in here are shared with App State */
+ private final Map<Integer, RoleStatus> roleStatusMap = new HashMap<>();
+ private final AbstractClusterServices recordFactory;
+
private long startTime;
/** Time when saved */
private final Timestamp saveTime = new Timestamp(0);
- /** If the history was loaded, the time at which the history was saved */
+ /** If the history was loaded, the time at which the history was saved.
+ * That is: the time the data was valid */
private final Timestamp thawedDataTime = new Timestamp(0);
private NodeMap nodemap;
@@ -87,8 +90,8 @@
private RoleHistoryWriter historyWriter = new RoleHistoryWriter();
/**
- * When were the nodes updated in a {@link #onNodesUpdated(List)} call.
- * If zero: never
+ * When were the nodes updated in a {@link #onNodesUpdated(List)} call?
+ * If zero: never.
*/
private final Timestamp nodesUpdatedTime = new Timestamp(0);
private final BoolMetric nodeUpdateReceived = new BoolMetric(false);
@@ -98,20 +101,24 @@
/**
* For each role, lists nodes that are available for data-local allocation,
- ordered by more recently released - To accelerate node selection
+ * ordered by more recently released - to accelerate node selection.
+ * That is, they are "recently used nodes"
*/
- private Map<Integer, LinkedList<NodeInstance>> availableNodes;
+ private Map<Integer, LinkedList<NodeInstance>> recentNodes;
/**
- * Track the failed nodes. Currently used to make wiser decision of container
- * ask with/without locality. Has other potential uses as well.
+ * Instantiate
+ * @param roles initial role list
+ * @param recordFactory yarn record factory
+ * @throws BadConfigException
*/
- private Set<String> failedNodes = new HashSet<>();
-
-
- public RoleHistory(List<ProviderRole> providerRoles) throws BadConfigException {
- this.providerRoles = providerRoles;
- roleSize = providerRoles.size();
+ public RoleHistory(Collection<RoleStatus> roles, AbstractClusterServices recordFactory) throws BadConfigException {
+ this.recordFactory = recordFactory;
+ roleSize = roles.size();
+ providerRoles = new ArrayList<>(roleSize);
+ for (RoleStatus role : roles) {
+ addNewRole(role);
+ }
reset();
}
@@ -122,15 +129,8 @@
protected synchronized void reset() throws BadConfigException {
nodemap = new NodeMap(roleSize);
- failedNodes = new HashSet<>();
resetAvailableNodeLists();
-
outstandingRequests = new OutstandingRequestTracker();
-
- Map<Integer, RoleStatus> roleStats = new HashMap<>();
- for (ProviderRole providerRole : providerRoles) {
- checkProviderRole(roleStats, providerRole);
- }
}
/**
@@ -146,46 +146,33 @@
}
/**
- * safety check: make sure the provider role is unique amongst
+ * safety check: make sure the role is unique amongst
* the role stats...which is extended with the new role
- * @param roleStats role stats
- * @param providerRole role
+ * @param roleStatus role
* @throws ArrayIndexOutOfBoundsException
* @throws BadConfigException
*/
- protected void checkProviderRole(Map<Integer, RoleStatus> roleStats,
- ProviderRole providerRole)
- throws BadConfigException {
- int index = providerRole.id;
+ protected void putRole(RoleStatus roleStatus) throws BadConfigException {
+ int index = roleStatus.getKey();
if (index < 0) {
- throw new BadConfigException("Provider " + providerRole
- + " id is out of range");
+ throw new BadConfigException("Provider " + roleStatus + " id is out of range");
}
- if (roleStats.get(index) != null) {
+ if (roleStatusMap.get(index) != null) {
throw new BadConfigException(
- providerRole.toString() + " id duplicates that of " +
- roleStats.get(index));
+ roleStatus.toString() + " id duplicates that of " +
+ roleStatusMap.get(index));
}
- roleStats.put(index, new RoleStatus(providerRole));
+ roleStatusMap.put(index, roleStatus);
}
/**
- * Add a new provider role to the map
- * @param providerRole new provider role
+ * Add a new role
+ * @param roleStatus new role
*/
- public void addNewProviderRole(ProviderRole providerRole)
- throws BadConfigException {
- log.debug("Validating/adding new provider role to role history: {} ",
- providerRole);
- Map<Integer, RoleStatus> roleStats = new HashMap<>();
-
- for (ProviderRole role : providerRoles) {
- roleStats.put(role.id, new RoleStatus(role));
- }
-
- checkProviderRole(roleStats, providerRole);
- log.debug("Check successful; adding role");
- this.providerRoles.add(providerRole);
+ public void addNewRole(RoleStatus roleStatus) throws BadConfigException {
+ log.debug("Validating/adding new role to role history: {} ", roleStatus);
+ putRole(roleStatus);
+ this.providerRoles.add(roleStatus.getProviderRole());
}
/**
@@ -206,7 +193,7 @@
* Clear the lists of available nodes
*/
private synchronized void resetAvailableNodeLists() {
- availableNodes = new HashMap<>(roleSize);
+ recentNodes = new ConcurrentHashMap<>(roleSize);
}
/**
@@ -322,12 +309,14 @@
/**
* Get snapshot of the node map
* @return a snapshot of the current node state
+ * @param naming naming map of priority to enty name; entries must be unique.
+ * It's OK to be incomplete, for those the list falls back to numbers.
*/
- public Map<String, NodeInformation> getNodeInformationSnapshot() {
- NodeMap map = cloneNodemap();
- Map<String, NodeInformation> result = new HashMap<>(map.size());
- for (Map.Entry<String, NodeInstance> entry : map.entrySet()) {
- result.put(entry.getKey(), entry.getValue().serialize());
+ public synchronized Map<String, NodeInformation> getNodeInformationSnapshot(
+ Map<Integer, String> naming) {
+ Map<String, NodeInformation> result = new HashMap<>(nodemap.size());
+ for (Map.Entry<String, NodeInstance> entry : nodemap.entrySet()) {
+ result.put(entry.getKey(), entry.getValue().serialize(naming));
}
return result;
}
@@ -335,11 +324,14 @@
/**
* Get the information on a node
* @param hostname hostname
+ * @param naming naming map of priority to enty name; entries must be unique.
+ * It's OK to be incomplete, for those the list falls back to numbers.
* @return the information about that host, or null if there is none
*/
- public NodeInformation getNodeInformation(String hostname) {
+ public NodeInformation getNodeInformation(String hostname,
+ Map<Integer, String> naming) {
NodeInstance nodeInstance = nodemap.get(hostname);
- return nodeInstance != null ? nodeInstance.serialize() : null;
+ return nodeInstance != null ? nodeInstance.serialize(naming) : null;
}
/**
@@ -363,7 +355,7 @@
public synchronized void insert(Collection<NodeInstance> nodes) {
nodemap.insert(nodes);
}
-
+
/**
* Get current time. overrideable for test subclasses
* @return current time in millis
@@ -435,8 +427,7 @@
* @param historyDir path in FS for history
* @return true if the history was thawed
*/
- public boolean onStart(FileSystem fs, Path historyDir) throws
- BadConfigException {
+ public boolean onStart(FileSystem fs, Path historyDir) throws BadConfigException {
assert filesystem == null;
filesystem = fs;
historyPath = historyDir;
@@ -483,7 +474,7 @@
}
//start is then completed
- buildAvailableNodeLists();
+ buildRecentNodeLists();
} else {
//fallback to bootstrap procedure
onBootstrap();
@@ -496,7 +487,7 @@
* (After the start), rebuild the availability data structures
*/
@VisibleForTesting
- public synchronized void buildAvailableNodeLists() {
+ public synchronized void buildRecentNodeLists() {
resetAvailableNodeLists();
// build the list of available nodes
for (Map.Entry<String, NodeInstance> entry : nodemap.entrySet()) {
@@ -505,13 +496,13 @@
NodeEntry nodeEntry = ni.get(i);
if (nodeEntry != null && nodeEntry.isAvailable()) {
log.debug("Adding {} for role {}", ni, i);
- getOrCreateNodesForRoleId(i).add(ni);
+ listRecentNodesForRoleId(i).add(ni);
}
}
}
// sort the resulting arrays
for (int i = 0; i < roleSize; i++) {
- sortAvailableNodeList(i);
+ sortRecentNodeList(i);
}
}
@@ -521,30 +512,35 @@
* @return potentially null list
*/
@VisibleForTesting
- public List<NodeInstance> getNodesForRoleId(int id) {
- return availableNodes.get(id);
+ public List<NodeInstance> getRecentNodesForRoleId(int id) {
+ return recentNodes.get(id);
}
-
+
/**
- * Get the nodes for an ID -may be null
+ * Get a possibly empty list of suggested nodes for a role.
* @param id role ID
* @return list
*/
- private LinkedList<NodeInstance> getOrCreateNodesForRoleId(int id) {
- LinkedList<NodeInstance> instances = availableNodes.get(id);
+ private LinkedList<NodeInstance> listRecentNodesForRoleId(int id) {
+ LinkedList<NodeInstance> instances = recentNodes.get(id);
if (instances == null) {
- instances = new LinkedList<>();
- availableNodes.put(id, instances);
+ synchronized (this) {
+ // recheck in the synchronized block and recreate
+ if (recentNodes.get(id) == null) {
+ recentNodes.put(id, new LinkedList<NodeInstance>());
+ }
+ instances = recentNodes.get(id);
+ }
}
return instances;
}
-
+
/**
- * Sort an available node list
+ * Sort a the recent node list for a single role
* @param role role to sort
*/
- private void sortAvailableNodeList(int role) {
- List<NodeInstance> nodesForRoleId = getNodesForRoleId(role);
+ private void sortRecentNodeList(int role) {
+ List<NodeInstance> nodesForRoleId = getRecentNodesForRoleId(role);
if (nodesForRoleId != null) {
Collections.sort(nodesForRoleId, new NodeInstance.Preferred(role));
}
@@ -556,7 +552,7 @@
* @return the instance, or null for none
*/
@VisibleForTesting
- public synchronized NodeInstance findNodeForNewInstance(RoleStatus role) {
+ public synchronized NodeInstance findRecentNodeForNewInstance(RoleStatus role) {
if (!role.isPlacementDesired()) {
// no data locality policy
return null;
@@ -566,7 +562,7 @@
NodeInstance nodeInstance = null;
// Get the list of possible targets.
// This is a live list: changes here are preserved
- List<NodeInstance> targets = getNodesForRoleId(roleId);
+ List<NodeInstance> targets = getRecentNodesForRoleId(roleId);
if (targets == null) {
// nothing to allocate on
return null;
@@ -578,7 +574,8 @@
NodeInstance candidate = targets.get(i);
if (candidate.getActiveRoleInstances(roleId) == 0) {
// no active instances: check failure statistics
- if (strictPlacement || !candidate.exceedsFailureThreshold(role)) {
+ if (strictPlacement
+ || (candidate.isOnline() && !candidate.exceedsFailureThreshold(role))) {
targets.remove(i);
// exit criteria for loop is now met
nodeInstance = candidate;
@@ -597,6 +594,18 @@
}
/**
+ * Find a node for use
+ * @param role role
+ * @return the instance, or null for none
+ */
+ @VisibleForTesting
+ public synchronized List<NodeInstance> findNodeForNewAAInstance(RoleStatus role) {
+ // all nodes that are live and can host the role; no attempt to exclude ones
+ // considered failing
+ return nodemap.findAllNodesForRole(role.getKey(), role.getLabelExpression());
+ }
+
+ /**
* Request an instance on a given node.
* An outstanding request is created & tracked, with the
* relevant node entry for that role updated.
@@ -606,47 +615,57 @@
* Returns the request that is now being tracked.
* If the node instance is not null, it's details about the role is incremented
*
- *
* @param node node to target or null for "any"
* @param role role to request
- * @param labelExpression label to satisfy
- * @return the container priority
+ * @return the request
*/
- public synchronized AMRMClient.ContainerRequest requestInstanceOnNode(
- NodeInstance node, RoleStatus role, Resource resource, String labelExpression) {
+ public synchronized OutstandingRequest requestInstanceOnNode(
+ NodeInstance node, RoleStatus role, Resource resource) {
OutstandingRequest outstanding = outstandingRequests.newRequest(node, role.getKey());
- return outstanding.buildContainerRequest(resource, role, now(), labelExpression);
- }
-
- /**
- * Find a node for a role and request an instance on that (or a location-less
- * instance) with a label expression
- * @param role role status
- * @param resource resource capabilities
- * @param labelExpression label to satisfy
- * @return a request ready to go
- */
- public synchronized AMRMClient.ContainerRequest requestNode(RoleStatus role,
- Resource resource,
- String labelExpression) {
- NodeInstance node = findNodeForNewInstance(role);
- return requestInstanceOnNode(node, role, resource, labelExpression);
+ outstanding.buildContainerRequest(resource, role, now());
+ return outstanding;
}
/**
* Find a node for a role and request an instance on that (or a location-less
* instance)
* @param role role status
- * @param resource resource capabilities
- * @return a request ready to go
+ * @return a request ready to go, or null if this is an AA request and no
+ * location can be found.
*/
- public synchronized AMRMClient.ContainerRequest requestNode(RoleStatus role,
- Resource resource) {
- NodeInstance node = findNodeForNewInstance(role);
- return requestInstanceOnNode(node, role, resource, null);
+ public synchronized OutstandingRequest requestContainerForRole(RoleStatus role) {
+
+ if (role.isAntiAffinePlacement()) {
+ return requestContainerForAARole(role);
+ } else {
+ Resource resource = recordFactory.newResource();
+ role.copyResourceRequirements(resource);
+ NodeInstance node = findRecentNodeForNewInstance(role);
+ return requestInstanceOnNode(node, role, resource);
+ }
}
/**
+ * Find a node for an AA role and request an instance on that (or a location-less
+ * instance)
+ * @param role role status
+ * @return a request ready to go, or null if no location can be found.
+ */
+ public synchronized OutstandingRequest requestContainerForAARole(RoleStatus role) {
+ List<NodeInstance> nodes = findNodeForNewAAInstance(role);
+ if (!nodes.isEmpty()) {
+ OutstandingRequest outstanding = outstandingRequests.newAARequest(
+ role.getKey(), nodes, role.getLabelExpression());
+ Resource resource = recordFactory.newResource();
+ role.copyResourceRequirements(resource);
+ outstanding.buildContainerRequest(resource, role, now());
+ return outstanding;
+ } else {
+ log.warn("No suitable location for {}", role.getName());
+ return null;
+ }
+ }
+ /**
* Get the list of active nodes ... walks the node map so
* is {@code O(nodes)}
* @param role role index
@@ -655,7 +674,7 @@
public synchronized List<NodeInstance> listActiveNodes(int role) {
return nodemap.listActiveNodes(role);
}
-
+
/**
* Get the node entry of a container
* @param container container to look up
@@ -663,8 +682,7 @@
* @throws RuntimeException if the container has no hostname
*/
public NodeEntry getOrCreateNodeEntry(Container container) {
- NodeInstance node = getOrCreateNodeInstance(container);
- return node.getOrCreate(ContainerPriority.extractRole(container));
+ return getOrCreateNodeInstance(container).getOrCreate(container);
}
/**
@@ -705,7 +723,7 @@
* @return list of containers potentially reordered
*/
public synchronized List<Container> prepareAllocationList(List<Container> allocatedContainers) {
-
+
//partition into requested and unrequested
List<Container> requested =
new ArrayList<>(allocatedContainers.size());
@@ -717,7 +735,7 @@
requested.addAll(unrequested);
return requested;
}
-
+
/**
* A container has been allocated on a node -update the data structures
* @param container container
@@ -725,13 +743,14 @@
* @param actualCount current count of instances
* @return The allocation outcome
*/
- public synchronized ContainerAllocation onContainerAllocated(Container container,
- int desiredCount,
- int actualCount) {
+ public synchronized ContainerAllocationResults onContainerAllocated(Container container,
+ long desiredCount,
+ long actualCount) {
int role = ContainerPriority.extractRole(container);
+
String hostname = RoleHistoryUtils.hostnameOf(container);
- List<NodeInstance> nodeInstances = getOrCreateNodesForRoleId(role);
- ContainerAllocation outcome =
+ List<NodeInstance> nodeInstances = listRecentNodesForRoleId(role);
+ ContainerAllocationResults outcome =
outstandingRequests.onContainerAllocated(role, hostname, container);
if (desiredCount <= actualCount) {
// all outstanding requests have been satisfied
@@ -741,7 +760,7 @@
//add the list
log.info("Adding {} hosts for role {}", hosts.size(), role);
nodeInstances.addAll(hosts);
- sortAvailableNodeList(role);
+ sortRecentNodeList(role);
}
}
return outcome;
@@ -752,8 +771,10 @@
* @param container container
*/
public void onContainerAssigned(Container container) {
- NodeEntry nodeEntry = getOrCreateNodeEntry(container);
+ NodeInstance node = getOrCreateNodeInstance(container);
+ NodeEntry nodeEntry = node.getOrCreate(container);
nodeEntry.onStarting();
+ log.debug("Node {} has updated NodeEntry {}", node, nodeEntry);
}
/**
@@ -763,9 +784,7 @@
*/
public void onContainerStartSubmitted(Container container,
RoleInstance instance) {
- NodeEntry nodeEntry = getOrCreateNodeEntry(container);
- int role = ContainerPriority.extractRole(container);
- // any actions we want here
+ // no actions here
}
/**
@@ -789,6 +808,16 @@
}
/**
+ * Does the RoleHistory have enough information about the YARN cluster
+ * to start placing AA requests? That is: has it the node map and
+ * any label information needed?
+ * @return true if the caller can start requesting AA nodes
+ */
+ public boolean canPlaceAANodes() {
+ return nodeUpdateReceived.get();
+ }
+
+ /**
* Get the last time the nodes were updated from YARN
* @return the update time or zero if never updated.
*/
@@ -798,33 +827,35 @@
/**
* Update failedNodes and nodemap based on the node state
- *
+ *
* @param updatedNodes list of updated nodes
+ * @return true if a review should be triggered.
*/
- public synchronized void onNodesUpdated(List<NodeReport> updatedNodes) {
+ public synchronized boolean onNodesUpdated(List<NodeReport> updatedNodes) {
log.debug("Updating {} nodes", updatedNodes.size());
nodesUpdatedTime.set(now());
nodeUpdateReceived.set(true);
+ int printed = 0;
+ boolean triggerReview = false;
for (NodeReport updatedNode : updatedNodes) {
String hostname = updatedNode.getNodeId() == null
- ? null
- : updatedNode.getNodeId().getHost();
+ ? ""
+ : updatedNode.getNodeId().getHost();
NodeState nodeState = updatedNode.getNodeState();
- if (hostname == null || nodeState == null) {
+ if (hostname.isEmpty() || nodeState == null) {
+ log.warn("Ignoring incomplete update");
continue;
}
+ if (log.isDebugEnabled() && printed++ < 10) {
+ // log the first few, but avoid overloading the logs for a full cluster
+ // update
+ log.debug("Node \"{}\" is in state {}", hostname, nodeState);
+ }
// update the node; this also creates an instance if needed
boolean updated = nodemap.updateNode(hostname, updatedNode);
- if (updated) {
- log.debug("Updated host {} to state {}", hostname, nodeState);
- if (nodeState.isUnusable()) {
- log.info("Failed node {}", hostname);
- failedNodes.add(hostname);
- } else {
- failedNodes.remove(hostname);
- }
- }
+ triggerReview |= updated;
}
+ return triggerReview;
}
/**
@@ -862,7 +893,7 @@
/**
* Mark a container finished; if it was released then that is treated
- * differently. history is touch()ed
+ * differently. history is {@code touch()}-ed
*
*
* @param container completed container
@@ -892,7 +923,7 @@
/**
* If the node is marked as available; queue it for assignments.
- * Unsynced: expects caller to be in a sync block.
+ * Unsynced: requires caller to be in a sync block.
* @param container completed container
* @param nodeEntry node
* @param available available flag
@@ -907,7 +938,7 @@
NodeInstance ni = getOrCreateNodeInstance(container);
int roleId = ContainerPriority.extractRole(container);
log.debug("Node {} is now available for role id {}", ni, roleId);
- getOrCreateNodesForRoleId(roleId).addFirst(ni);
+ listRecentNodesForRoleId(roleId).addFirst(ni);
}
return available;
}
@@ -918,8 +949,7 @@
public synchronized void dump() {
for (ProviderRole role : providerRoles) {
log.info(role.toString());
- List<NodeInstance> instances =
- getOrCreateNodesForRoleId(role.id);
+ List<NodeInstance> instances = listRecentNodesForRoleId(role.id);
log.info(" available: " + instances.size()
+ " " + SliderUtils.joinWithInnerSeparator(" ", instances));
}
@@ -928,9 +958,6 @@
for (NodeInstance node : nodemap.values()) {
log.info(node.toFullString());
}
-
- log.info("Failed nodes: {}",
- SliderUtils.joinWithInnerSeparator(" ", failedNodes));
}
/**
@@ -951,8 +978,8 @@
* @return a clone of the list
*/
@VisibleForTesting
- public List<NodeInstance> cloneAvailableList(int role) {
- return new LinkedList<>(getOrCreateNodesForRoleId(role));
+ public List<NodeInstance> cloneRecentNodeList(int role) {
+ return new LinkedList<>(listRecentNodesForRoleId(role));
}
/**
@@ -974,31 +1001,42 @@
}
/**
- * Get a clone of the failedNodes
- *
- * @return the list
- */
- public List<String> cloneFailedNodes() {
- List<String> lst = new ArrayList<>();
- lst.addAll(failedNodes);
- return lst;
- }
-
- /**
* Escalate operation as triggered by external timer.
* @return a (usually empty) list of cancel/request operations.
*/
public List<AbstractRMOperation> escalateOutstandingRequests() {
return outstandingRequests.escalateOutstandingRequests(now());
}
+ /**
+ * Escalate operation as triggered by external timer.
+ * @return a (usually empty) list of cancel/request operations.
+ */
+ public List<AbstractRMOperation> cancelOutstandingAARequests() {
+ return outstandingRequests.cancelOutstandingAARequests();
+ }
+
+ /**
+ * Cancel a number of outstanding requests for a role -that is, not
+ * actual containers, just requests for new ones.
+ * @param role role
+ * @param toCancel number to cancel
+ * @return a list of cancellable operations.
+ */
+ public List<AbstractRMOperation> cancelRequestsForRole(RoleStatus role, int toCancel) {
+ return role.isAntiAffinePlacement() ?
+ cancelRequestsForAARole(role, toCancel)
+ : cancelRequestsForSimpleRole(role, toCancel);
+ }
/**
* Build the list of requests to cancel from the outstanding list.
- * @param role
- * @param toCancel
+ * @param role role
+ * @param toCancel number to cancel
* @return a list of cancellable operations.
*/
- public synchronized List<AbstractRMOperation> cancelRequestsForRole(RoleStatus role, int toCancel) {
+ private synchronized List<AbstractRMOperation> cancelRequestsForSimpleRole(RoleStatus role, int toCancel) {
+ Preconditions.checkArgument(toCancel > 0,
+ "trying to cancel invalid number of requests: " + toCancel);
List<AbstractRMOperation> results = new ArrayList<>(toCancel);
// first scan through the unplaced request list to find all of a role
int roleId = role.getKey();
@@ -1017,4 +1055,47 @@
return results;
}
+ /**
+ * Build the list of requests to cancel for an AA role. This reduces the number
+ * of outstanding pending requests first, then cancels any active request,
+ * before finally asking for any placed containers
+ * @param role role
+ * @param toCancel number to cancel
+ * @return a list of cancellable operations.
+ */
+ private synchronized List<AbstractRMOperation> cancelRequestsForAARole(RoleStatus role, int toCancel) {
+ List<AbstractRMOperation> results = new ArrayList<>(toCancel);
+ int roleId = role.getKey();
+ List<OutstandingRequest> requests = new ArrayList<>(toCancel);
+ // there may be pending requests which can be cancelled here
+ long pending = role.getPendingAntiAffineRequests();
+ if (pending > 0) {
+ // there are some pending ones which can be cancelled first
+ long pendingToCancel = Math.min(pending, toCancel);
+ log.info("Cancelling {} pending AA allocations, leaving {}", toCancel,
+ pendingToCancel);
+ role.setPendingAntiAffineRequests(pending - pendingToCancel);
+ toCancel -= pendingToCancel;
+ }
+ if (toCancel > 0 && role.isAARequestOutstanding()) {
+ // not enough
+ log.info("Cancelling current AA request");
+ // find the single entry which may be running
+ requests = outstandingRequests.extractOpenRequestsForRole(roleId, toCancel);
+ role.cancelOutstandingAARequest();
+ toCancel--;
+ }
+
+ // ask for some excess nodes
+ if (toCancel > 0) {
+ requests.addAll(outstandingRequests.extractPlacedRequestsForRole(roleId, toCancel));
+ }
+
+ // build cancellations
+ for (OutstandingRequest request : requests) {
+ results.add(request.createCancelOperation());
+ }
+ return results;
+ }
+
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHostnamePair.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHostnamePair.java
new file mode 100644
index 0000000..920887a
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHostnamePair.java
@@ -0,0 +1,75 @@
+/*
+ * 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.slider.server.appmaster.state;
+
+import java.util.Objects;
+
+public class RoleHostnamePair {
+
+ /**
+ * requested role
+ */
+ public final int roleId;
+
+ /**
+ * hostname -will be null if node==null
+ */
+ public final String hostname;
+
+ public RoleHostnamePair(int roleId, String hostname) {
+ this.roleId = roleId;
+ this.hostname = hostname;
+ }
+
+ public int getRoleId() {
+ return roleId;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof RoleHostnamePair)) {
+ return false;
+ }
+ RoleHostnamePair that = (RoleHostnamePair) o;
+ return Objects.equals(roleId, that.roleId) &&
+ Objects.equals(hostname, that.hostname);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(roleId, hostname);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder(
+ "RoleHostnamePair{");
+ sb.append("roleId=").append(roleId);
+ sb.append(", hostname='").append(hostname).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleStatus.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleStatus.java
index 98a8311..656f96c 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleStatus.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleStatus.java
@@ -18,22 +18,32 @@
package org.apache.slider.server.appmaster.state;
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricSet;
+import com.google.common.base.Preconditions;
+import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.slider.api.types.ComponentInformation;
+import org.apache.slider.api.types.RoleStatistics;
import org.apache.slider.providers.PlacementPolicy;
import org.apache.slider.providers.ProviderRole;
+import org.apache.slider.server.appmaster.management.BoolMetric;
+import org.apache.slider.server.appmaster.management.BoolMetricPredicate;
+import org.apache.slider.server.appmaster.management.LongGauge;
import java.io.Serializable;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-
/**
- * Models the ongoing status of all nodes in
- * Nothing here is synchronized: grab the whole instance to update.
+ * Models the ongoing status of all nodes in an application.
+ *
+ * These structures are shared across the {@link AppState} and {@link RoleHistory} structures,
+ * and must be designed for synchronous access. Atomic counters are preferred to anything which
+ * requires synchronization. Where synchronized access is good is that it allows for
+ * the whole instance to be locked, for updating multiple entries.
*/
-public final class RoleStatus implements Cloneable {
+public final class RoleStatus implements Cloneable, MetricSet {
private final String name;
@@ -41,25 +51,31 @@
* Role priority
*/
private final int key;
-
private final ProviderRole providerRole;
- private int desired, actual, requested, releasing;
- private int failed, startFailed;
- private int started, completed, totalRequested;
- private final AtomicLong preempted = new AtomicLong(0);
- private final AtomicLong nodeFailed = new AtomicLong(0);
- private final AtomicLong failedRecently = new AtomicLong(0);
- private final AtomicLong limitsExceeded = new AtomicLong(0);
+ private final LongGauge actual = new LongGauge();
+ private final LongGauge completed = new LongGauge();
+ private final LongGauge desired = new LongGauge();
+ private final LongGauge failed = new LongGauge();
+ private final LongGauge failedRecently = new LongGauge(0);
+ private final LongGauge limitsExceeded = new LongGauge(0);
+ private final LongGauge nodeFailed = new LongGauge(0);
+ /** Number of AA requests queued. */
+ private final LongGauge pendingAntiAffineRequests = new LongGauge(0);
+ private final LongGauge preempted = new LongGauge(0);
+ private final LongGauge releasing = new LongGauge();
+ private final LongGauge requested = new LongGauge();
+ private final LongGauge started = new LongGauge();
+ private final LongGauge startFailed = new LongGauge();
+ private final LongGauge totalRequested = new LongGauge();
- /** flag set to true if there is an outstanding anti-affine request */
- private final AtomicBoolean pendingAARequest = new AtomicBoolean(false);
+ /** resource requirements */
+ private Resource resourceRequirements;
- /**
- * Number of AA requests queued. These should be reduced first on a
- * flex down.
- */
- private int pendingAntiAffineRequestCount = 0;
+
+ /** any pending AA request */
+ private volatile OutstandingRequest outstandingAArequest = null;
+
private String failureMessage = "";
@@ -68,7 +84,37 @@
this.name = providerRole.name;
this.key = providerRole.id;
}
-
+
+ @Override
+ public Map<String, Metric> getMetrics() {
+ Map<String, Metric> metrics = new HashMap<>(15);
+ metrics.put("actual", actual);
+ metrics.put("completed", completed );
+ metrics.put("desired", desired);
+ metrics.put("failed", failed);
+ metrics.put("limitsExceeded", limitsExceeded);
+ metrics.put("nodeFailed", nodeFailed);
+ metrics.put("preempted", preempted);
+ metrics.put("pendingAntiAffineRequests", pendingAntiAffineRequests);
+ metrics.put("releasing", releasing);
+ metrics.put("requested", requested);
+ metrics.put("preempted", preempted);
+ metrics.put("releasing", releasing );
+ metrics.put("requested", requested);
+ metrics.put("started", started);
+ metrics.put("startFailed", startFailed);
+ metrics.put("totalRequested", totalRequested);
+
+ metrics.put("outstandingAArequest",
+ new BoolMetricPredicate(new BoolMetricPredicate.Eval() {
+ @Override
+ public boolean eval() {
+ return isAARequestOutstanding();
+ }
+ }));
+ return metrics;
+ }
+
public String getName() {
return name;
}
@@ -123,63 +169,64 @@
return !hasPlacementPolicy(PlacementPolicy.NO_DATA_LOCALITY);
}
- public synchronized int getDesired() {
- return desired;
+ public long getDesired() {
+ return desired.get();
}
- public synchronized void setDesired(int desired) {
- this.desired = desired;
+ public void setDesired(long desired) {
+ this.desired.set(desired);
}
- public synchronized int getActual() {
- return actual;
+ public long getActual() {
+ return actual.get();
}
- public synchronized int incActual() {
- return ++actual;
+ public long incActual() {
+ return actual.incrementAndGet();
}
- public synchronized int decActual() {
- actual = Math.max(0, actual - 1);
- return actual;
+ public long decActual() {
+ return actual.decToFloor(1);
}
- public synchronized int getRequested() {
- return requested;
+ /**
+ * Get the request count.
+ * @return a count of requested containers
+ */
+ public long getRequested() {
+ return requested.get();
}
- public synchronized int incRequested() {
- totalRequested++;
- return ++requested;
+ public long incRequested() {
+ totalRequested.incrementAndGet();
+ return requested.incrementAndGet();
}
- public synchronized int cancel(int count) {
- requested = Math.max(0, requested - count);
- return requested;
- }
-
- public synchronized int decRequested() {
- return cancel(1);
+ public void cancel(long count) {
+ requested.decToFloor(count);
}
- public synchronized int getReleasing() {
- return releasing;
+ public void decRequested() {
+ cancel(1);
}
- public synchronized int incReleasing() {
- return ++releasing;
+ public long getReleasing() {
+ return releasing.get();
}
- public synchronized int decReleasing() {
- releasing = Math.max(0, releasing - 1);
- return releasing;
+ public long incReleasing() {
+ return releasing.incrementAndGet();
}
- public synchronized int getFailed() {
- return failed;
+ public long decReleasing() {
+ return releasing.decToFloor(1);
}
- public synchronized long getFailedRecently() {
+ public long getFailed() {
+ return failed.get();
+ }
+
+ public long getFailedRecently() {
return failedRecently.get();
}
@@ -195,6 +242,26 @@
return limitsExceeded.get();
}
+ public long incPendingAntiAffineRequests(long v) {
+ return pendingAntiAffineRequests.addAndGet(v);
+ }
+
+ /**
+ * Probe for an outstanding AA request being true
+ * @return true if there is an outstanding AA Request
+ */
+ public boolean isAARequestOutstanding() {
+ return outstandingAArequest != null;
+ }
+
+ /**
+ * expose the predicate {@link #isAARequestOutstanding()} as an integer,
+ * which is very convenient in tests
+ * @return 1 if there is an outstanding request; 0 if not
+ */
+ public int getOutstandingAARequestCount() {
+ return isAARequestOutstanding()? 1: 0;
+ }
/**
* Note that a role failed, text will
* be used in any diagnostics if an exception
@@ -215,7 +282,7 @@
case Node_failure:
nodeFailed.incrementAndGet();
- failed++;
+ failed.incrementAndGet();
break;
case Failed_limits_exceeded: // exceeded memory or CPU; app/configuration related
@@ -223,7 +290,7 @@
// fall through
case Failed: // application failure, possibly node related, possibly not
default: // anything else (future-proofing)
- failed++;
+ failed.incrementAndGet();
failedRecently.incrementAndGet();
//have a look to see if it short lived
if (startupFailure) {
@@ -233,39 +300,39 @@
}
}
- public synchronized int getStartFailed() {
- return startFailed;
+ public long getStartFailed() {
+ return startFailed.get();
}
public synchronized void incStartFailed() {
- startFailed++;
+ startFailed.getAndIncrement();
}
public synchronized String getFailureMessage() {
return failureMessage;
}
- public synchronized int getCompleted() {
- return completed;
+ public long getCompleted() {
+ return completed.get();
}
public synchronized void setCompleted(int completed) {
- this.completed = completed;
+ this.completed.set(completed);
}
- public synchronized int incCompleted() {
- return completed ++;
+ public long incCompleted() {
+ return completed.incrementAndGet();
}
- public synchronized int getStarted() {
- return started;
+ public long getStarted() {
+ return started.get();
}
public synchronized void incStarted() {
- started++;
+ started.incrementAndGet();
}
- public synchronized int getTotalRequested() {
- return totalRequested;
+ public long getTotalRequested() {
+ return totalRequested.get();
}
public long getPreempted() {
@@ -276,19 +343,58 @@
return nodeFailed.get();
}
+ public long getPendingAntiAffineRequests() {
+ return pendingAntiAffineRequests.get();
+ }
+
+ public void setPendingAntiAffineRequests(long pendingAntiAffineRequests) {
+ this.pendingAntiAffineRequests.set(pendingAntiAffineRequests);
+ }
+
+ public long decPendingAntiAffineRequests() {
+ return pendingAntiAffineRequests.decToFloor(1);
+ }
+
+ public OutstandingRequest getOutstandingAArequest() {
+ return outstandingAArequest;
+ }
+
+ public void setOutstandingAArequest(OutstandingRequest outstandingAArequest) {
+ this.outstandingAArequest = outstandingAArequest;
+ }
+
+ /**
+ * Complete the outstanding AA request (there's no check for one in progress, caller
+ * expected to have done that).
+ */
+ public void completeOutstandingAARequest() {
+ setOutstandingAArequest(null);
+ }
+
+ /**
+ * Cancel any outstanding AA request. Harmless if the role is non-AA, or
+ * if there are no outstanding requests.
+ */
+ public void cancelOutstandingAARequest() {
+ if (outstandingAArequest != null) {
+ setOutstandingAArequest(null);
+ setPendingAntiAffineRequests(0);
+ decRequested();
+ }
+ }
+
/**
* Get the number of roles we are short of.
* nodes released are ignored.
* @return the positive or negative number of roles to add/release.
* 0 means "do nothing".
*/
- public synchronized int getDelta() {
- int inuse = getActualAndRequested();
- //don't know how to view these. Are they in-use or not?
- int delta = desired - inuse;
+ public long getDelta() {
+ long inuse = getActualAndRequested();
+ long delta = desired.get() - inuse;
if (delta < 0) {
//if we are releasing, remove the number that are already released.
- delta += releasing;
+ delta += releasing.get();
//but never switch to a positive
delta = Math.min(delta, 0);
}
@@ -296,32 +402,41 @@
}
/**
- * Get count of actual and requested containers
- * @return the size of the application when outstanding requests are included
+ * Get count of actual and requested containers. This includes pending ones
+ * @return the size of the application when outstanding requests are included.
*/
- public synchronized int getActualAndRequested() {
- return actual + requested;
+ public long getActualAndRequested() {
+ return actual.get() + requested.get();
}
@Override
- public synchronized String toString() {
- return "RoleStatus{" +
- "name='" + name + '\'' +
- ", key=" + key +
- ", desired=" + desired +
- ", actual=" + actual +
- ", requested=" + requested +
- ", releasing=" + releasing +
- ", pendingAntiAffineRequestCount=" + pendingAntiAffineRequestCount +
- ", failed=" + failed +
- ", failed recently=" + failedRecently.get() +
- ", node failed=" + nodeFailed.get() +
- ", pre-empted=" + preempted.get() +
- ", started=" + started +
- ", startFailed=" + startFailed +
- ", completed=" + completed +
- ", failureMessage='" + failureMessage + '\'' +
- '}';
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("RoleStatus{");
+ sb.append("name='").append(name).append('\'');
+ sb.append(", key=").append(key);
+ sb.append(", desired=").append(desired);
+ sb.append(", actual=").append(actual);
+ sb.append(", requested=").append(requested);
+ sb.append(", releasing=").append(releasing);
+ sb.append(", failed=").append(failed);
+ sb.append(", startFailed=").append(startFailed);
+ sb.append(", started=").append(started);
+ sb.append(", completed=").append(completed);
+ sb.append(", totalRequested=").append(totalRequested);
+ sb.append(", preempted=").append(preempted);
+ sb.append(", nodeFailed=").append(nodeFailed);
+ sb.append(", failedRecently=").append(failedRecently);
+ sb.append(", limitsExceeded=").append(limitsExceeded);
+ sb.append(", resourceRequirements=").append(resourceRequirements);
+ sb.append(", isAntiAffinePlacement=").append(isAntiAffinePlacement());
+ if (isAntiAffinePlacement()) {
+ sb.append(", pendingAntiAffineRequests=").append(pendingAntiAffineRequests);
+ sb.append(", outstandingAArequest=").append(outstandingAArequest);
+ }
+ sb.append(", failureMessage='").append(failureMessage).append('\'');
+ sb.append(", providerRole=").append(providerRole);
+ sb.append('}');
+ return sb.toString();
}
@Override
@@ -354,23 +469,39 @@
ComponentInformation info = new ComponentInformation();
info.name = name;
info.priority = getPriority();
- info.desired = desired;
- info.actual = actual;
- info.requested = requested;
- info.releasing = releasing;
- info.failed = failed;
- info.startFailed = startFailed;
+ info.desired = desired.intValue();
+ info.actual = actual.intValue();
+ info.requested = requested.intValue();
+ info.releasing = releasing.intValue();
+ info.failed = failed.intValue();
+ info.startFailed = startFailed.intValue();
info.placementPolicy = getPlacementPolicy();
info.failureMessage = failureMessage;
- info.totalRequested = totalRequested;
+ info.totalRequested = totalRequested.intValue();
info.failedRecently = failedRecently.intValue();
info.nodeFailed = nodeFailed.intValue();
info.preempted = preempted.intValue();
- info.pendingAntiAffineRequest = pendingAARequest.get();
- info.pendingAntiAffineRequestCount = pendingAntiAffineRequestCount;
+ info.pendingAntiAffineRequestCount = pendingAntiAffineRequests.intValue();
+ info.isAARequestOutstanding = isAARequestOutstanding();
return info;
}
-
+
+ /**
+ * Get the (possibly null) label expression for this role
+ * @return a string or null
+ */
+ public String getLabelExpression() {
+ return providerRole.labelExpression;
+ }
+
+ public Resource getResourceRequirements() {
+ return resourceRequirements;
+ }
+
+ public void setResourceRequirements(Resource resourceRequirements) {
+ this.resourceRequirements = resourceRequirements;
+ }
+
/**
* Compare two role status entries by name
*/
@@ -392,5 +523,35 @@
return (o1.getKey() < o2.getKey() ? -1 : (o1.getKey() == o2.getKey() ? 0 : 1));
}
}
-
+
+ /**
+ * Given a resource, set its requirements to those this role needs
+ * @param resource resource to configure
+ * @return the resource
+ */
+ public Resource copyResourceRequirements(Resource resource) {
+ Preconditions.checkNotNull(resourceRequirements,
+ "Role resource requirements have not been set");
+ resource.setMemory(resourceRequirements.getMemory());
+ resource.setVirtualCores(resourceRequirements.getVirtualCores());
+ return resource;
+ }
+
+ public synchronized RoleStatistics getStatistics() {
+ RoleStatistics stats = new RoleStatistics();
+ stats.activeAA = getOutstandingAARequestCount();
+ stats.actual = actual.get();
+ stats.desired = desired.get();
+ stats.failed = failed.get();
+ stats.limitsExceeded = limitsExceeded.get();
+ stats.nodeFailed = nodeFailed.get();
+ stats.preempted = preempted.get();
+ stats.releasing = releasing.get();
+ stats.requested = requested.get();
+ stats.started = started.get();
+ stats.startFailed = startFailed.get();
+ stats.totalRequested = totalRequested.get();
+ return stats;
+ }
+
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/SimpleReleaseSelector.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/SimpleReleaseSelector.java
index b7f0e05..b848096 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/SimpleReleaseSelector.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/SimpleReleaseSelector.java
@@ -27,8 +27,7 @@
@Override
public List<RoleInstance> sortCandidates(int roleId,
- List<RoleInstance> candidates,
- int minimumToSelect) {
+ List<RoleInstance> candidates) {
return candidates;
}
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/StateAccessForProviders.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/StateAccessForProviders.java
index 2fc00b2..ad91183 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/StateAccessForProviders.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/StateAccessForProviders.java
@@ -27,6 +27,7 @@
import org.apache.slider.api.types.ApplicationLivenessInformation;
import org.apache.slider.api.types.ComponentInformation;
import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.RoleStatistics;
import org.apache.slider.core.conf.AggregateConf;
import org.apache.slider.core.conf.ConfTreeOperations;
import org.apache.slider.core.exceptions.NoSuchNodeException;
@@ -303,4 +304,10 @@
* @return the information, or null if there is no information held.
*/
NodeInformation getNodeInformation(String hostname);
+
+ /**
+ * Get the aggregate statistics across all roles
+ * @return role statistics
+ */
+ RoleStatistics getRoleStatistics();
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/SliderAMWebApp.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/SliderAMWebApp.java
index 84f0eba..7ecc00c 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/SliderAMWebApp.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/SliderAMWebApp.java
@@ -92,7 +92,7 @@
String regex = "(?!/ws)";
serveRegex(regex).with(SliderDefaultWrapperServlet.class);
- Map<String, String> params = new HashMap<String, String>();
+ Map<String, String> params = new HashMap<>();
params.put(ResourceConfig.FEATURE_IMPLICIT_VIEWABLES, "true");
params.put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, "true");
params.put(ResourceConfig.FEATURE_XMLROOTELEMENT_PROCESSING, "true");
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/AbstractSliderResource.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/AbstractSliderResource.java
index cfddb12..7ff83b6 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/AbstractSliderResource.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/AbstractSliderResource.java
@@ -45,12 +45,11 @@
protected final WebAppApi slider;
protected final MetricsAndMonitoring metricsAndMonitoring;
- public AbstractSliderResource(WebAppApi slider) {
+ protected AbstractSliderResource(WebAppApi slider) {
this.slider = slider;
metricsAndMonitoring = slider.getMetricsAndMonitoring();
}
-
/**
* Generate a redirect to the WASL
* @param request to base the URL on
@@ -105,6 +104,7 @@
protected void mark(String verb, String path) {
metricsAndMonitoring.markMeterAndCounter(verb + "-" + path);
}
+
/**
* Mark an GET operation on a path
* @param verb HTTP Verb
@@ -129,6 +129,7 @@
protected void markGet(String path, String subpath) {
mark("GET", path, subpath);
}
+
/**
* Mark a GET operation on a path
* @param path path relative to slider API
@@ -136,6 +137,7 @@
protected void markPost(String path, String subpath) {
mark("POST", path, subpath);
}
+
/**
* Mark a GET operation on a path
* @param path path relative to slider API
@@ -143,6 +145,7 @@
protected void markPut(String path, String subpath) {
mark("PUT", path, subpath);
}
+
/**
* Mark a GET operation on a path
* @param path path relative to slider API
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/RestPaths.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/RestPaths.java
index 424107c..b90eb62 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/RestPaths.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/RestPaths.java
@@ -148,4 +148,15 @@
public static final String ACTION = "/action";
public static final String ACTION_PING = ACTION + "/ping";
public static final String ACTION_STOP = ACTION + "/stop";
+
+ /**
+ * Path to a role
+ * @param name role name
+ * @return a path to it
+ */
+ public String pathToRole(String name) {
+
+ // ws/v1/slider/application/live/components/$name
+ return SLIDER_PATH_APPLICATION + LIVE_COMPONENTS + "/" + name;
+ }
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/application/ApplicationResource.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/application/ApplicationResource.java
index 1b54a31..52068d6 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/application/ApplicationResource.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/application/ApplicationResource.java
@@ -26,6 +26,7 @@
import org.apache.slider.api.types.ComponentInformation;
import org.apache.slider.api.types.ContainerInformation;
import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
import org.apache.slider.core.conf.AggregateConf;
import org.apache.slider.core.conf.ConfTree;
import org.apache.slider.core.exceptions.NoSuchNodeException;
@@ -350,31 +351,31 @@
@GET
@Path(LIVE_NODES)
@Produces({APPLICATION_JSON})
- public Map<String, NodeInformation> getLiveNodes() {
+ public NodeInformationList getLiveNodes() {
markGet(SLIDER_SUBPATH_APPLICATION, LIVE_COMPONENTS);
try {
- return (Map<String, NodeInformation>) cache.lookup(LIVE_NODES);
+ return (NodeInformationList) cache.lookup(LIVE_NODES);
} catch (Exception e) {
throw buildException(LIVE_COMPONENTS, e);
}
}
@GET
- @Path(LIVE_NODES + "/{node}")
+ @Path(LIVE_NODES + "/{hostname}")
@Produces({APPLICATION_JSON})
- public NodeInformation getLiveNode(@PathParam("node") String node) {
+ public NodeInformation getLiveNode(@PathParam("hostname") String hostname) {
markGet(SLIDER_SUBPATH_APPLICATION, LIVE_COMPONENTS);
try {
- NodeInformation ni = state.getNodeInformation(node);
+ NodeInformation ni = state.getNodeInformation(hostname);
if (ni != null) {
return ni;
} else {
- throw new NotFoundException("Unknown node: " + node);
+ throw new NotFoundException("Unknown node: " + hostname);
}
} catch (NotFoundException e) {
throw e;
} catch (Exception e) {
- throw buildException(LIVE_CONTAINERS + "/" + node, e);
+ throw buildException(LIVE_COMPONENTS + "/" + hostname, e);
}
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/application/resources/LiveNodesRefresher.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/application/resources/LiveNodesRefresher.java
index d4ab8fe..aeb7a11 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/application/resources/LiveNodesRefresher.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/application/resources/LiveNodesRefresher.java
@@ -18,16 +18,14 @@
package org.apache.slider.server.appmaster.web.rest.application.resources;
-import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
import org.apache.slider.server.appmaster.state.StateAccessForProviders;
-import java.util.Map;
-
/**
* Update the live nodes map
*/
public class LiveNodesRefresher
- implements ResourceRefresher<Map<String, NodeInformation>> {
+ implements ResourceRefresher<NodeInformationList> {
private final StateAccessForProviders state;
@@ -36,7 +34,8 @@
}
@Override
- public Map<String, NodeInformation> refresh() {
- return state.getNodeInformationSnapshot();
+ public NodeInformationList refresh() {
+
+ return new NodeInformationList(state.getNodeInformationSnapshot().values());
}
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/management/resources/AggregateConfResource.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/management/resources/AggregateConfResource.java
index 75d417b..794daf9 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/management/resources/AggregateConfResource.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/management/resources/AggregateConfResource.java
@@ -37,23 +37,13 @@
public AggregateConfResource(AggregateConf conf, UriBuilder uriBuilder) {
if (uriBuilder != null) {
- this.href =
- uriBuilder.build().toASCIIString();
- resources =
- ResourceFactory.createConfTreeResource(conf.getAppConf(),
- uriBuilder.clone().path(
- "configurations").path(
- "resources"));
- internal =
- ResourceFactory.createConfTreeResource(conf.getInternal(),
- uriBuilder.clone().path(
- "configurations").path(
- "internal"));
- appConf =
- ResourceFactory.createConfTreeResource(conf.getAppConf(),
- uriBuilder.clone().path(
- "configurations").path(
- "appConf"));
+ this.href = uriBuilder.build().toASCIIString();
+ resources = ResourceFactory.createConfTreeResource(conf.getResources(),
+ uriBuilder.clone().path("configurations").path("resources"));
+ internal = ResourceFactory.createConfTreeResource(conf.getInternal(),
+ uriBuilder.clone().path("configurations").path("internal"));
+ appConf = ResourceFactory.createConfTreeResource(conf.getAppConf(),
+ uriBuilder.clone().path("configurations").path("appConf"));
initConfMap();
} else {
resources = null;
@@ -63,7 +53,7 @@
}
private void initConfMap() {
- confMap = new HashMap<String, ConfTreeResource>();
+ confMap = new HashMap<>();
confMap.put("internal", internal);
confMap.put("resources", resources);
confMap.put("appConf", appConf);
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/ClusterSpecificationBlock.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/ClusterSpecificationBlock.java
index 137c476..2f02f27 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/ClusterSpecificationBlock.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/ClusterSpecificationBlock.java
@@ -18,23 +18,16 @@
import com.google.inject.Inject;
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet;
-import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
-import org.apache.slider.server.appmaster.state.StateAccessForProviders;
import org.apache.slider.server.appmaster.web.WebAppApi;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
*
*/
-public class ClusterSpecificationBlock extends HtmlBlock {
- private static final Logger log = LoggerFactory.getLogger(ClusterSpecificationBlock.class);
-
- private StateAccessForProviders appState;
+public class ClusterSpecificationBlock extends SliderHamletBlock {
@Inject
public ClusterSpecificationBlock(WebAppApi slider) {
- this.appState = slider.getAppState();
+ super(slider);
}
@Override
@@ -50,7 +43,7 @@
pre().
_(getJson())._()._();
}
-
+
/**
* Get the JSON, catching any exceptions and returning error text instead
* @return
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/ContainerStatsBlock.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/ContainerStatsBlock.java
index 0896e2b..56285c2 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/ContainerStatsBlock.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/ContainerStatsBlock.java
@@ -26,12 +26,10 @@
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TABLE;
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TBODY;
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TR;
-import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
import org.apache.slider.api.ClusterDescription;
import org.apache.slider.api.ClusterNode;
import org.apache.slider.api.types.ComponentInformation;
import org.apache.slider.server.appmaster.state.RoleInstance;
-import org.apache.slider.server.appmaster.state.StateAccessForProviders;
import org.apache.slider.server.appmaster.web.WebAppApi;
import java.io.Serializable;
@@ -45,19 +43,18 @@
/**
*
*/
-public class ContainerStatsBlock extends HtmlBlock {
+public class ContainerStatsBlock extends SliderHamletBlock {
private static final String EVEN = "even", ODD = "odd", BOLD = "bold", SCHEME = "http://", PATH = "/node/container/";
// Some functions that help transform the data into an object we can use to abstract presentation specifics
protected static final Function<Entry<String,Integer>,Entry<TableContent,Integer>> stringIntPairFunc = toTableContentFunction();
+ protected static final Function<Entry<String,Long>,Entry<TableContent,Long>> stringLongPairFunc = toTableContentFunction();
protected static final Function<Entry<String,String>,Entry<TableContent,String>> stringStringPairFunc = toTableContentFunction();
- private WebAppApi slider;
-
@Inject
public ContainerStatsBlock(WebAppApi slider) {
- this.slider = slider;
+ super(slider);
}
/**
@@ -92,7 +89,6 @@
@Override
protected void render(Block html) {
- StateAccessForProviders appState = slider.getAppState();
final Map<String,RoleInstance> containerInstances = getContainerInstances(
appState.cloneOwnedContainerList());
@@ -108,7 +104,7 @@
DIV<Hamlet> div = html.div("role-info ui-widget-content ui-corner-all");
List<ClusterNode> nodesInRole =
- new ArrayList<ClusterNode>(clusterNodesInRole.values());
+ new ArrayList<>(clusterNodesInRole.values());
div.h2(BOLD, StringUtils.capitalize(name));
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/IndexBlock.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/IndexBlock.java
index 5131b5e..b3be3bf 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/IndexBlock.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/IndexBlock.java
@@ -21,50 +21,52 @@
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet;
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.DIV;
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.UL;
-import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
import org.apache.slider.api.ClusterDescription;
import org.apache.slider.api.StatusKeys;
import org.apache.slider.api.types.ApplicationLivenessInformation;
+import org.apache.slider.api.types.RoleStatistics;
import org.apache.slider.common.tools.SliderUtils;
import org.apache.slider.providers.ProviderService;
import org.apache.slider.server.appmaster.state.RoleStatus;
-import org.apache.slider.server.appmaster.state.StateAccessForProviders;
import org.apache.slider.server.appmaster.web.WebAppApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
+import static org.apache.slider.server.appmaster.web.rest.RestPaths.LIVE_COMPONENTS;
+
/**
- *
+ * The main content on the Slider AM web page
*/
-public class IndexBlock extends HtmlBlock {
+public class IndexBlock extends SliderHamletBlock {
private static final Logger log = LoggerFactory.getLogger(IndexBlock.class);
- private StateAccessForProviders appView;
- private ProviderService providerService;
+ /**
+ * Message printed when application is at full size.
+ *
+ * {@value}
+ */
+ public static final String ALL_CONTAINERS_ALLOCATED = "all containers allocated";
@Inject
public IndexBlock(WebAppApi slider) {
- this.appView = slider.getAppState();
- this.providerService = slider.getProviderService();
+ super(slider);
}
@Override
protected void render(Block html) {
- final String providerName = getProviderName();
-
- doIndex(html, providerName);
+ doIndex(html, getProviderName());
}
// An extra method to make testing easier since you can't make an instance of Block
@VisibleForTesting
protected void doIndex(Hamlet html, String providerName) {
- ClusterDescription clusterStatus = appView.getClusterStatus();
+ ClusterDescription clusterStatus = appState.getClusterStatus();
String name = clusterStatus.name;
if (name != null && (name.startsWith(" ") || name.endsWith(" "))) {
name = "'" + name + "'";
@@ -74,10 +76,9 @@
"Application: " + name);
ApplicationLivenessInformation liveness =
- appView.getApplicationLivenessInformation();
- String livestatus =
- liveness.allRequestsSatisfied
- ? "all containers allocated"
+ appState.getApplicationLivenessInformation();
+ String livestatus = liveness.allRequestsSatisfied
+ ? ALL_CONTAINERS_ALLOCATED
: String.format("Awaiting %d containers", liveness.requestsOutstanding);
Hamlet.TABLE<DIV<Hamlet>> table1 = div.table();
table1.tr()
@@ -86,7 +87,7 @@
._();
table1.tr()
.td("Total number of containers")
- .td(Integer.toString(appView.getNumOwnedContainers()))
+ .td(Integer.toString(appState.getNumOwnedContainers()))
._();
table1.tr()
.td("Create time: ")
@@ -108,44 +109,132 @@
.td("Application configuration path: ")
.td(clusterStatus.originConfigurationPath)
._();
- table1._()._();
+ table1._();
+ div._();
+ div = null;
+ DIV<Hamlet> containers = html.div("container_instances")
+ .h3("Component Instances");
- html.div("container_instances").h3("Component Instances");
+ int aaRoleWithNoSuitableLocations = 0;
+ int aaRoleWithOpenRequest = 0;
+ int roleWithOpenRequest = 0;
- Hamlet.TABLE<DIV<Hamlet>> table = div.table();
- table.tr()
- .td("Component")
- .td("Desired")
- .td("Actual")
- .td("Outstanding Requests")
- .td("Failed")
- .td("Failed to start")
- ._();
+ Hamlet.TABLE<DIV<Hamlet>> table = containers.table();
+ Hamlet.TR<Hamlet.THEAD<Hamlet.TABLE<DIV<Hamlet>>>> header = table.thead().tr();
+ trb(header, "Component");
+ trb(header, "Desired");
+ trb(header, "Actual");
+ trb(header, "Outstanding Requests");
+ trb(header, "Failed");
+ trb(header, "Failed to start");
+ trb(header, "Placement");
+ header._()._(); // tr & thead
- List<RoleStatus> roleStatuses = appView.cloneRoleStatusList();
+ List<RoleStatus> roleStatuses = appState.cloneRoleStatusList();
Collections.sort(roleStatuses, new RoleStatus.CompareByName());
for (RoleStatus status : roleStatuses) {
+ String roleName = status.getName();
+ String nameUrl = apiPath(LIVE_COMPONENTS) + "/" + roleName;
+ String aatext;
+ if (status.isAntiAffinePlacement()) {
+ boolean aaRequestOutstanding = status.isAARequestOutstanding();
+ int pending = (int)status.getPendingAntiAffineRequests();
+ aatext = buildAADetails(aaRequestOutstanding, pending);
+ if (SliderUtils.isSet(status.getLabelExpression())) {
+ aatext += " (label: " + status.getLabelExpression() + ")";
+ }
+ if (pending > 0 && !aaRequestOutstanding) {
+ aaRoleWithNoSuitableLocations ++;
+ } else if (aaRequestOutstanding) {
+ aaRoleWithOpenRequest++;
+ }
+ } else {
+ if (SliderUtils.isSet(status.getLabelExpression())) {
+ aatext = "label: " + status.getLabelExpression();
+ } else {
+ aatext = "";
+ }
+ if (status.getRequested() > 0) {
+ roleWithOpenRequest ++;
+ }
+ }
table.tr()
- .td(status.getName())
- .td(String.format("%d", status.getDesired()))
- .td(String.format("%d", status.getActual()))
- .td(String.format("%d", status.getRequested()))
- .td(String.format("%d", status.getFailed()))
- .td(String.format("%d", status.getStartFailed()))
- ._();
+ .td().a(nameUrl, roleName)._()
+ .td(String.format("%d", status.getDesired()))
+ .td(String.format("%d", status.getActual()))
+ .td(String.format("%d", status.getRequested()))
+ .td(String.format("%d", status.getFailed()))
+ .td(String.format("%d", status.getStartFailed()))
+ .td(aatext)
+ ._();
}
- table._()._();
+ // empty row for some more spacing
+ table.tr()._();
+ // close table
+ table._();
+
+ containers._();
+ containers = null;
// some spacing
- html.p()._();
- html.p()._();
+ html.div()._();
+ html.div()._();
- html.div("provider_info").h3(providerName + " information");
- UL<DIV<Hamlet>> ul = div.ul();
+ DIV<Hamlet> diagnostics = html.div("diagnostics");
+
+ List<String> statusEntries = new ArrayList<>(0);
+ if (roleWithOpenRequest > 0) {
+ statusEntries.add(String.format("%d %s with requests unsatisfiable by cluster",
+ roleWithOpenRequest, plural(roleWithOpenRequest, "component")));
+ }
+ if (aaRoleWithNoSuitableLocations > 0) {
+ statusEntries.add(String.format("%d anti-affinity %s no suitable nodes in the cluster",
+ aaRoleWithNoSuitableLocations,
+ plural(aaRoleWithNoSuitableLocations, "component has", "components have")));
+ }
+ if (aaRoleWithOpenRequest > 0) {
+ statusEntries.add(String.format("%d anti-affinity %s with requests unsatisfiable by cluster",
+ aaRoleWithOpenRequest,
+ plural(aaRoleWithOpenRequest, "component has", "components have")));
+
+ }
+ if (!statusEntries.isEmpty()) {
+ diagnostics.h3("Diagnostics");
+ Hamlet.TABLE<DIV<Hamlet>> diagnosticsTable = diagnostics.table();
+ for (String entry : statusEntries) {
+ diagnosticsTable.tr().td(entry)._();
+ }
+ diagnosticsTable._();
+ }
+ diagnostics._();
+
+ DIV<Hamlet> provider_info = html.div("provider_info");
+ provider_info.h3(providerName + " information");
+ UL<Hamlet> ul = html.ul();
addProviderServiceOptions(providerService, ul, clusterStatus);
- ul._()._();
+ ul._();
+ provider_info._();
+ }
+
+ @VisibleForTesting
+ String buildAADetails(boolean outstanding, int pending) {
+ return String.format("Anti-affinity:%s %d pending %s",
+ (outstanding ? " 1 active request and" : ""),
+ pending, plural(pending, "request"));
+ }
+
+ private String plural(int n, String singular) {
+ return plural(n, singular, singular + "s");
+ }
+ private String plural(int n, String singular, String plural) {
+ return n == 1 ? singular : plural;
+ }
+
+ private void trb(Hamlet.TR tr,
+ String text) {
+ tr.td().b(text)._();
}
private String getProviderName() {
@@ -153,14 +242,14 @@
}
private String getInfoAvoidingNulls(String key) {
- String createTime = appView.getClusterStatus().getInfo(key);
+ String createTime = appState.getClusterStatus().getInfo(key);
return null == createTime ? "N/A" : createTime;
}
- protected void addProviderServiceOptions(ProviderService providerService,
- UL<DIV<Hamlet>> ul, ClusterDescription clusterStatus) {
- Map<String, String> details = providerService.buildMonitorDetails(
+ protected void addProviderServiceOptions(ProviderService provider,
+ UL ul, ClusterDescription clusterStatus) {
+ Map<String, String> details = provider.buildMonitorDetails(
clusterStatus);
if (null == details) {
return;
@@ -176,4 +265,5 @@
}
}
+
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/NavBlock.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/NavBlock.java
index b2327ba..069d386 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/NavBlock.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/NavBlock.java
@@ -16,16 +16,21 @@
*/
package org.apache.slider.server.appmaster.web.view;
-import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
+import com.google.inject.Inject;
+import org.apache.slider.server.appmaster.web.WebAppApi;
+
import static org.apache.slider.server.appmaster.web.SliderAMWebApp.*;
import static org.apache.slider.server.appmaster.web.rest.RestPaths.*;
-import static org.apache.hadoop.yarn.util.StringHelper.ujoin;
-
/**
*
*/
-public class NavBlock extends HtmlBlock {
+public class NavBlock extends SliderHamletBlock {
+
+ @Inject
+ public NavBlock(WebAppApi slider) {
+ super(slider);
+ }
@Override
protected void render(Block html) {
@@ -36,7 +41,6 @@
li().a(this.prefix(), "Overview")._().
li().a(relPath(CONTAINER_STATS), "Statistics")._().
li().a(relPath(CLUSTER_SPEC), "Specification")._().
- li().a(relPath(CLUSTER_SPEC), "Specification")._().
li().a(rootPath(SYSTEM_METRICS_JSON), "Metrics")._().
li().a(rootPath(SYSTEM_HEALTHCHECK), "Health")._().
li().a(rootPath(SYSTEM_THREADS), "Threads")._().
@@ -48,20 +52,11 @@
li().a(apiPath(LIVE_RESOURCES), "Resources")._().
li().a(apiPath(LIVE_COMPONENTS), "Components")._().
li().a(apiPath(LIVE_CONTAINERS), "Containers")._().
+ li().a(apiPath(LIVE_NODES), "Nodes")._().
+ li().a(apiPath(LIVE_STATISTICS), "Statistics")._().
li().a(apiPath(LIVE_LIVENESS), "Liveness")._()
._()
._();
}
- private String rootPath(String absolutePath) {
- return root_url(absolutePath);
- }
-
- private String relPath(String... args) {
- return ujoin(this.prefix(), args);
- }
- private String apiPath(String api) {
- return root_url(SLIDER_PATH_APPLICATION, api);
- }
-
}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/SliderHamletBlock.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/SliderHamletBlock.java
new file mode 100644
index 0000000..82d7c8f
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/SliderHamletBlock.java
@@ -0,0 +1,56 @@
+/*
+ * 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.slider.server.appmaster.web.view;
+
+import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
+import org.apache.slider.providers.ProviderService;
+import org.apache.slider.server.appmaster.state.StateAccessForProviders;
+import org.apache.slider.server.appmaster.web.WebAppApi;
+import org.apache.slider.server.appmaster.web.rest.RestPaths;
+
+import static org.apache.hadoop.yarn.util.StringHelper.ujoin;
+import static org.apache.slider.server.appmaster.web.rest.RestPaths.SLIDER_PATH_APPLICATION;
+
+/**
+ * Anything we want to share across slider hamlet blocks
+ */
+public abstract class SliderHamletBlock extends HtmlBlock {
+
+ protected final StateAccessForProviders appState;
+ protected final ProviderService providerService;
+ protected final RestPaths restPaths = new RestPaths();
+
+ public SliderHamletBlock(WebAppApi slider) {
+ this.appState = slider.getAppState();
+ this.providerService = slider.getProviderService();
+ }
+
+ protected String rootPath(String absolutePath) {
+ return root_url(absolutePath);
+ }
+
+ protected String relPath(String... args) {
+ return ujoin(this.prefix(), args);
+ }
+
+ protected String apiPath(String api) {
+ return root_url(SLIDER_PATH_APPLICATION, api);
+ }
+
+}
diff --git a/slider-core/src/main/proto/SliderClusterMessages.proto b/slider-core/src/main/proto/SliderClusterMessages.proto
index 50c10e4..b8bdc59 100644
--- a/slider-core/src/main/proto/SliderClusterMessages.proto
+++ b/slider-core/src/main/proto/SliderClusterMessages.proto
@@ -25,10 +25,7 @@
//import "Security.proto";
/*
- To debug compilation problems, bypass the maven build and invoke protoc
- from the command line
-
- protoc --java_out=target src/main/proto/SliderClusterMessages.proto
+ Look at SliderClusterProtocol.proto to see how to build this
*/
message RoleInstanceState {
@@ -258,6 +255,7 @@
optional int32 nodeFailed = 16;
optional int32 preempted = 17;
optional int32 pendingAntiAffineRequestCount = 18;
+ optional bool isAARequestOutstanding = 19;
}
/*
@@ -301,6 +299,7 @@
required int32 live = 8;
required int32 releasing = 9;
required int64 lastUsed = 10;
+ required string name = 11;
}
message NodeInformationProto {
@@ -389,8 +388,7 @@
}
message GetLiveNodesResponseProto {
- repeated string names = 1;
- repeated NodeInformationProto nodes = 2;
+ repeated NodeInformationProto nodes = 1;
}
message GetLiveNodeRequestProto {
diff --git a/slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/appConfig.json b/slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/appConfig.json
new file mode 100644
index 0000000..6e3ef14
--- /dev/null
+++ b/slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/appConfig.json
@@ -0,0 +1,7 @@
+{
+ "schema": "http://example.org/specification/v2.0.0",
+ "metadata": {
+ },
+ "global": {
+ }
+}
diff --git a/slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/metainfo.json b/slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/metainfo.json
index c8ada2c..073d1ff 100644
--- a/slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/metainfo.json
+++ b/slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/metainfo.json
@@ -1,16 +1,24 @@
{
- "schemaVersion": "2.1",
- "application": {
- "name": "SLEEPER",
- "components": [
- {
- "name": "SLEEP_100",
- "commands": [
- {
- "exec": "sleep 180"
- }
- ]
- }
+ "schemaVersion": "2.1",
+ "application": {
+ "name": "SLEEPER",
+ "components": [
+ {
+ "name": "SLEEP_100",
+ "commands": [
+ {
+ "exec": "sleep 180"
+ }
]
- }
+ },
+ {
+ "name": "SLEEP_LONG",
+ "commands": [
+ {
+ "exec": "sleep 180000"
+ }
+ ]
+ }
+ ]
+ }
}
diff --git a/slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/resources.json b/slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/resources.json
index be7b962..e0ed16a 100644
--- a/slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/resources.json
+++ b/slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/resources.json
@@ -11,7 +11,13 @@
"SLEEP_100": {
"yarn.role.priority": "1",
"yarn.component.instances": "1",
- "yarn.memory": "256"
+ "yarn.memory": "128"
+ },
+ "SLEEP_LONG": {
+ "yarn.role.priority": "2",
+ "yarn.component.instances": "0",
+ "yarn.memory": "128",
+ "yarn.component.placement.policy": "4"
}
}
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/agent/AgentMiniClusterTestBase.groovy b/slider-core/src/test/groovy/org/apache/slider/agent/AgentMiniClusterTestBase.groovy
index a7bc0a3..b37ee3a 100644
--- a/slider-core/src/test/groovy/org/apache/slider/agent/AgentMiniClusterTestBase.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/agent/AgentMiniClusterTestBase.groovy
@@ -27,15 +27,13 @@
import org.apache.slider.client.SliderClient
import org.apache.slider.common.SliderXMLConfKeysForTesting
import org.apache.slider.common.params.Arguments
-import org.apache.slider.common.tools.SliderUtils
import org.apache.slider.core.main.ServiceLauncher
import org.apache.slider.providers.agent.AgentKeys
+import org.apache.slider.test.KeysForTests
import org.apache.slider.test.YarnZKMiniClusterTestBase
import org.junit.AfterClass
import org.junit.BeforeClass
import org.junit.rules.TemporaryFolder
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
/**
* test base for agent clusters
@@ -43,8 +41,7 @@
@CompileStatic
@Slf4j
public abstract class AgentMiniClusterTestBase
-extends YarnZKMiniClusterTestBase {
- private static Logger LOG = LoggerFactory.getLogger(AgentMiniClusterTestBase)
+extends YarnZKMiniClusterTestBase implements KeysForTests {
protected static File agentConf
protected static File agentDef
protected static Map<String, String> agentDefOptions
@@ -92,7 +89,7 @@
@AfterClass
public static void cleanSubConfFiles() {
- def tempRoot
+ def tempRoot = ""
try {
tempRoot = tempFolder.root
if (tempRoot.exists()) {
@@ -101,7 +98,7 @@
} catch (IOException e) {
log.info("Failed to delete $tempRoot :$e", e)
} catch (IllegalStateException e) {
- log.warn("Temp folder deletion failed: $e")
+ log.warn("Temp folder deletion failed: $e", e)
}
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/agent/rest/AbstractAppApiTestDelegates.groovy b/slider-core/src/test/groovy/org/apache/slider/agent/rest/AbstractAppApiTestDelegates.groovy
index 6d1bcfc..6727a29 100644
--- a/slider-core/src/test/groovy/org/apache/slider/agent/rest/AbstractAppApiTestDelegates.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/agent/rest/AbstractAppApiTestDelegates.groovy
@@ -24,10 +24,8 @@
import org.apache.slider.api.StateValues
import org.apache.slider.api.types.ComponentInformation
import org.apache.slider.api.types.ContainerInformation
-import org.apache.slider.api.types.NodeInformation
import org.apache.slider.core.conf.ConfTreeOperations
import org.apache.slider.test.Outcome
-import org.junit.Test
import static org.apache.slider.api.ResourceKeys.*
import static org.apache.slider.api.StatusKeys.*
@@ -210,10 +208,10 @@
describe "Node listing via $appAPI"
def liveNodes = appAPI.liveNodes
assert liveNodes.size() > 0
- def h = liveNodes.keySet()[0];
+ prettyPrintAsJson(liveNodes)
+ def h = liveNodes[0].hostname;
def localhost = appAPI.getLiveNode(h)
-
-
+ assert localhost.httpAddress == liveNodes[0].httpAddress
}
/**
@@ -239,7 +237,7 @@
testLiveContainers();
testRESTModel()
testAppLiveness()
-// testListNodes();
+ testListNodes();
}
public void testFlexOperation() {
diff --git a/slider-core/src/test/groovy/org/apache/slider/agent/rest/TestStandaloneREST.groovy b/slider-core/src/test/groovy/org/apache/slider/agent/rest/TestStandaloneREST.groovy
index 97b3009..b0ae102 100644
--- a/slider-core/src/test/groovy/org/apache/slider/agent/rest/TestStandaloneREST.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/agent/rest/TestStandaloneREST.groovy
@@ -32,6 +32,7 @@
import org.apache.slider.core.main.ServiceLauncher
import org.apache.slider.core.restclient.HttpOperationResponse
import org.apache.slider.server.appmaster.rpc.RpcBinder
+import org.apache.slider.test.KeysForTests
import org.junit.Test
import static org.apache.slider.server.appmaster.management.MetricsKeys.*
@@ -39,8 +40,7 @@
@CompileStatic
@Slf4j
-class TestStandaloneREST extends AgentMiniClusterTestBase {
-
+class TestStandaloneREST extends AgentMiniClusterTestBase {
@Test
public void testStandaloneREST() throws Throwable {
@@ -65,15 +65,14 @@
ApplicationReport report = waitForClusterLive(client)
def proxyAM = report.trackingUrl
def directAM = report.originalTrackingUrl
-
-
+
// set up url config to match
initHttpTestSupport(launcher.configuration)
execOperation(WEB_STARTUP_TIME) {
GET(directAM)
}
-
+
execOperation(WEB_STARTUP_TIME) {
def metrics = GET(directAM, SYSTEM_METRICS_JSON)
log.info prettyPrintJson(metrics)
@@ -86,14 +85,12 @@
log.info GET(proxyAM, SYSTEM_HEALTHCHECK)
log.info GET(proxyAM, SYSTEM_METRICS_JSON)
- // using the metrics, await the first node status update
- /* SLIDER--82: disabled
- awaitGaugeValue(
- appendToURL(proxyAM, SYSTEM_METRICS_JSON),
- "org.apache.slider.server.appmaster.state.RoleHistory.nodes-updated.flag",
+ // using the metrics, await the first node status update.
+ // this should be from AM launch itself
+ awaitGaugeValue(proxyAM,
+ NODES_UPDATED_FLAG_METRIC,
1,
WEB_STARTUP_TIME * 2, 500)
- */
// Is the back door required? If so, don't test complex verbs via the proxy
def proxyComplexVerbs = !SliderXmlConfKeys.X_DEV_INSECURE_REQUIRED
diff --git a/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestBuildStandaloneAM.groovy b/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestBuildStandaloneAM.groovy
index 5495e62..6637c73 100644
--- a/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestBuildStandaloneAM.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestBuildStandaloneAM.groovy
@@ -169,9 +169,5 @@
Map<String, String> masterRole = cd.getRole(master)
assert masterRole != null, "Role hbase-master must exist"
assert cd.roleNames.contains(master), "Role names must contain hbase-master"
-
- // and check liveness
- assert cd.liveness.allRequestsSatisfied
- assert 0 == cd.liveness.requestsOutstanding
}
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/client/TestClientBadArgs.groovy b/slider-core/src/test/groovy/org/apache/slider/client/TestClientBadArgs.groovy
index 1a90c88..17b176c 100644
--- a/slider-core/src/test/groovy/org/apache/slider/client/TestClientBadArgs.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/client/TestClientBadArgs.groovy
@@ -21,14 +21,12 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.apache.hadoop.conf.Configuration
-import org.apache.slider.common.params.ActionRegistryArgs
+import org.apache.hadoop.yarn.conf.YarnConfiguration
import org.apache.slider.common.params.Arguments
import org.apache.slider.common.params.SliderActions
import org.apache.slider.core.exceptions.BadCommandArgumentsException
import org.apache.slider.core.exceptions.ErrorStrings
import org.apache.slider.core.exceptions.UsageException
-import org.apache.slider.core.exceptions.BadConfigException
-import org.apache.slider.core.main.ServiceLauncher
import org.apache.slider.core.main.ServiceLauncherBaseTest
import org.junit.Test
@@ -38,13 +36,11 @@
@CompileStatic
@Slf4j
class TestClientBadArgs extends ServiceLauncherBaseTest {
-
- static String TEST_FILES = "./src/test/resources/org/apache/slider/providers/agent/tests/"
-
+
@Test
public void testNoAction() throws Throwable {
launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"Usage: slider COMMAND",
[])
@@ -53,7 +49,7 @@
@Test
public void testUnknownAction() throws Throwable {
launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"not-a-known-action",
["not-a-known-action"])
}
@@ -61,7 +57,7 @@
@Test
public void testActionWithoutOptions() throws Throwable {
launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"Usage: slider build <application>",
[SliderActions.ACTION_BUILD])
}
@@ -69,7 +65,7 @@
@Test
public void testActionWithoutEnoughArgs() throws Throwable {
launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
ErrorStrings.ERROR_NOT_ENOUGH_ARGUMENTS,
[SliderActions.ACTION_THAW])
}
@@ -77,7 +73,7 @@
@Test
public void testActionWithTooManyArgs() throws Throwable {
launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
ErrorStrings.ERROR_TOO_MANY_ARGUMENTS,
[SliderActions.ACTION_HELP,
"hello, world"])
@@ -86,7 +82,7 @@
@Test
public void testBadImageArg() throws Throwable {
launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"Unknown option: --image",
[SliderActions.ACTION_HELP,
Arguments.ARG_IMAGE])
@@ -95,7 +91,7 @@
@Test
public void testRegistryUsage() throws Throwable {
def exception = launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"org.apache.slider.core.exceptions.UsageException: Argument --name missing",
[SliderActions.ACTION_REGISTRY])
assert exception instanceof UsageException
@@ -105,7 +101,7 @@
@Test
public void testRegistryExportBadUsage1() throws Throwable {
def exception = launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"Expected a value after parameter --getexp",
[SliderActions.ACTION_REGISTRY,
Arguments.ARG_NAME,
@@ -118,7 +114,7 @@
@Test
public void testRegistryExportBadUsage2() throws Throwable {
def exception = launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"Expected a value after parameter --getexp",
[SliderActions.ACTION_REGISTRY,
Arguments.ARG_NAME,
@@ -132,7 +128,7 @@
@Test
public void testRegistryExportBadUsage3() throws Throwable {
def exception = launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"Usage: registry",
[SliderActions.ACTION_REGISTRY,
Arguments.ARG_NAME,
@@ -147,7 +143,7 @@
@Test
public void testUpgradeUsage() throws Throwable {
def exception = launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"org.apache.slider.core.exceptions.BadCommandArgumentsException: Not enough arguments for action: upgrade Expected minimum 1 but got 0",
[SliderActions.ACTION_UPGRADE])
assert exception instanceof BadCommandArgumentsException
@@ -158,7 +154,7 @@
public void testUpgradeWithTemplateOptionOnly() throws Throwable {
String appName = "test_hbase"
def exception = launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"BadCommandArgumentsException: Option --resources must be specified with option --template",
[SliderActions.ACTION_UPGRADE,
appName,
@@ -169,11 +165,17 @@
log.info(exception.toString())
}
+ public Configuration createTestConfig() {
+ def configuration = new Configuration()
+ configuration.set(YarnConfiguration.RM_ADDRESS, "127.0.0.1:8032")
+ return configuration
+ }
+
@Test
public void testUpgradeWithResourcesOptionOnly() throws Throwable {
String appName = "test_hbase"
def exception = launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"BadCommandArgumentsException: Option --template must be specified with option --resources",
[SliderActions.ACTION_UPGRADE,
appName,
@@ -188,7 +190,7 @@
public void testUpgradeWithTemplateResourcesAndContainersOption() throws Throwable {
String appName = "test_hbase"
def exception = launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"BadCommandArgumentsException: Option --containers cannot be "
+ "specified with --template or --resources",
[SliderActions.ACTION_UPGRADE,
@@ -208,7 +210,7 @@
public void testUpgradeWithTemplateResourcesAndComponentsOption() throws Throwable {
String appName = "test_hbase"
def exception = launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"BadCommandArgumentsException: Option --components cannot be "
+ "specified with --template or --resources",
[SliderActions.ACTION_UPGRADE,
@@ -228,7 +230,7 @@
public void testCreateAppWithAddonPkgBadArg1() throws Throwable {
//add on package without specifying add on package name
def exception = launchExpectingException(SliderClient,
- new Configuration(),
+ createTestConfig(),
"Expected 2 values after --addon",
[SliderActions.ACTION_CREATE,
"cl1",
@@ -239,6 +241,15 @@
}
@Test
+ public void testNodesMissingFile() throws Throwable {
+ def exception = launchExpectingException(SliderClient,
+ createTestConfig(),
+ "after parameter --out",
+ [SliderActions.ACTION_NODES, Arguments.ARG_OUTPUT])
+ assert exception instanceof BadCommandArgumentsException
+ }
+
+ @Test
public void testFlexWithNoCompoents() throws Throwable {
def exception = launchExpectingException(SliderClient,
new Configuration(),
diff --git a/slider-core/src/test/groovy/org/apache/slider/client/TestSliderClientMethods.groovy b/slider-core/src/test/groovy/org/apache/slider/client/TestSliderClientMethods.groovy
index 168415c..e244923 100644
--- a/slider-core/src/test/groovy/org/apache/slider/client/TestSliderClientMethods.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/client/TestSliderClientMethods.groovy
@@ -30,6 +30,7 @@
import org.apache.slider.core.launch.LaunchedApplication
import org.apache.slider.core.main.ServiceLauncherBaseTest
import org.apache.slider.core.persist.LockAcquireFailedException
+import org.apache.slider.server.appmaster.model.mock.MockApplicationId
import org.easymock.EasyMock
import org.junit.Assert
import org.junit.Test
@@ -137,7 +138,7 @@
AggregateConf instanceDefinition,
boolean debugAM)
throws YarnException, IOException {
- return new LaunchedApplication(clustername, new SliderYarnClientImpl());
+ return new LaunchedApplication(new MockApplicationId(1), new SliderYarnClientImpl());
}
}
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/client/TestUpgradeCommandOptions.groovy b/slider-core/src/test/groovy/org/apache/slider/client/TestUpgradeCommandOptions.groovy
index 8d5aef1..5295f9b 100644
--- a/slider-core/src/test/groovy/org/apache/slider/client/TestUpgradeCommandOptions.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/client/TestUpgradeCommandOptions.groovy
@@ -82,10 +82,8 @@
new File(tmpDir, "resources.json").toURI()
])
fail("Upgrade command should have failed")
- } catch (SliderException e) {
- log.info(e.toString())
- assert e instanceof UnknownApplicationInstanceException
- assert e.getMessage().contains("Unknown application instance")
+ } catch (UnknownApplicationInstanceException e) {
+ assertExceptionDetails(e, SliderExitCodes.EXIT_UNKNOWN_INSTANCE, "Unknown application instance")
}
}
@@ -301,10 +299,6 @@
assert launcher.serviceExitCode == 0
}
- private File getTempLocation () {
- return new File(System.getProperty("user.dir") + "/target/_")
- }
-
static class TestSliderClient extends SliderClient {
public TestSliderClient() {
super()
diff --git a/slider-core/src/test/groovy/org/apache/slider/providers/agent/AgentTestBase.groovy b/slider-core/src/test/groovy/org/apache/slider/providers/agent/AgentTestBase.groovy
index 5bf1c1f..e5951ac 100644
--- a/slider-core/src/test/groovy/org/apache/slider/providers/agent/AgentTestBase.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/providers/agent/AgentTestBase.groovy
@@ -32,6 +32,7 @@
import org.junit.Before
import org.junit.Rule
import org.junit.rules.TemporaryFolder
+import org.slf4j.Logger
import static org.apache.slider.common.SliderXMLConfKeysForTesting.*
import static org.apache.slider.providers.agent.AgentKeys.CONF_RESOURCE
@@ -53,7 +54,7 @@
*/
public static void assumeValidServerEnv() {
try {
- SliderUtils.validateSliderServerEnvironment(log, true)
+ SliderUtils.validateSliderServerEnvironment(log as Logger, true)
} catch (Exception e) {
skip(e.toString())
}
@@ -135,12 +136,8 @@
boolean create,
boolean blockUntilRunning) {
-
YarnConfiguration conf = testConfiguration
-
- def clusterOps = [
- :
- ]
+ def clusterOps = [:]
return createOrBuildCluster(
create ? SliderActions.ACTION_CREATE : SliderActions.ACTION_BUILD,
@@ -166,11 +163,7 @@
List<String> extraArgs,
boolean deleteExistingData) {
- YarnConfiguration conf = testConfiguration
-
- def clusterOps = [
- :
- ]
+ def clusterOps = [:]
return createOrBuildCluster(
SliderActions.ACTION_UPDATE,
diff --git a/slider-core/src/test/groovy/org/apache/slider/providers/agent/DemoAgentAAEcho.groovy b/slider-core/src/test/groovy/org/apache/slider/providers/agent/DemoAgentAAEcho.groovy
new file mode 100644
index 0000000..855ed36
--- /dev/null
+++ b/slider-core/src/test/groovy/org/apache/slider/providers/agent/DemoAgentAAEcho.groovy
@@ -0,0 +1,49 @@
+/*
+ * 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.slider.providers.agent
+
+import org.apache.slider.client.SliderClient
+
+/**
+ * Overridde the test actions with a sleep command, so that developers
+ * can see what the application is up to
+ */
+class DemoAgentAAEcho extends TestAgentAAEcho {
+
+ @Override
+ protected void postLaunchActions(
+ SliderClient sliderClient,
+ String clustername,
+ String rolename,
+ Map<String, Integer> roles,
+ String proxyAM) {
+
+ def url = proxyAM
+ // spin repeating the URl in the logs so YARN chatter doesn't lose it
+ describe("Web UI is at $url")
+
+ // run the superclass rest tests
+ // queryRestAPI(sliderClient, roles, proxyAM)
+
+ 5.times {
+ describe("Web UI is at $url")
+ sleep(60 *1000)
+ }
+ }
+}
diff --git a/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestAgentAAEcho.groovy b/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestAgentAAEcho.groovy
new file mode 100644
index 0000000..e193563
--- /dev/null
+++ b/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestAgentAAEcho.groovy
@@ -0,0 +1,209 @@
+/*
+ * 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.slider.providers.agent
+
+import groovy.transform.CompileStatic
+import groovy.util.logging.Slf4j
+import org.apache.slider.api.ResourceKeys
+import org.apache.slider.api.RoleKeys
+import org.apache.slider.api.StatusKeys
+import org.apache.slider.client.SliderClient
+import org.apache.slider.client.rest.SliderApplicationApiRestClient
+import org.apache.slider.common.SliderXmlConfKeys
+import org.apache.slider.common.params.ActionNodesArgs
+import org.apache.slider.core.main.ServiceLauncher
+import org.apache.slider.providers.PlacementPolicy
+import org.apache.slider.server.appmaster.management.MetricsConstants
+import org.junit.Test
+
+import static org.apache.slider.common.params.Arguments.*
+import static org.apache.slider.providers.agent.AgentKeys.*
+import static org.apache.slider.server.appmaster.management.MetricsKeys.METRICS_LOGGING_ENABLED
+import static org.apache.slider.server.appmaster.management.MetricsKeys.METRICS_LOGGING_LOG_INTERVAL
+import static org.apache.slider.server.appmaster.web.rest.RestPaths.SYSTEM_METRICS_JSON
+
+/**
+ * Tests an echo command
+ */
+@CompileStatic
+@Slf4j
+class TestAgentAAEcho extends TestAgentEcho {
+
+ @Test
+ public void testAgentEcho() throws Throwable {
+ assumeValidServerEnv()
+ def conf = configuration
+ conf.setBoolean(METRICS_LOGGING_ENABLED, true)
+ conf.setInt(METRICS_LOGGING_LOG_INTERVAL, 1)
+ String clustername = createMiniCluster("testaaecho",
+ configuration,
+ 1,
+ 1,
+ 1,
+ true,
+ false)
+
+ validatePaths()
+
+ def echo = "echo"
+ Map<String, Integer> roles = buildRoleMap(echo)
+ ServiceLauncher<SliderClient> launcher = buildAgentCluster(clustername,
+ roles,
+ [
+ ARG_OPTION, PACKAGE_PATH, slider_core.absolutePath,
+ ARG_OPTION, APP_DEF, toURIArg(app_def_path),
+ ARG_OPTION, AGENT_CONF, toURIArg(agt_conf_path),
+ ARG_OPTION, AGENT_VERSION, toURIArg(agt_ver_path),
+ ARG_RES_COMP_OPT, echo, ResourceKeys.COMPONENT_PRIORITY, "1",
+ ARG_RES_COMP_OPT, echo, ResourceKeys.COMPONENT_PLACEMENT_POLICY,
+ "" + PlacementPolicy.ANTI_AFFINITY_REQUIRED,
+ ARG_COMP_OPT, echo, SCRIPT_PATH, echo_py,
+ ARG_COMP_OPT, echo, SERVICE_NAME, "Agent",
+ ARG_DEFINE, SliderXmlConfKeys.KEY_SLIDER_AM_DEPENDENCY_CHECKS_DISABLED + "=false",
+ ARG_COMP_OPT, echo, TEST_RELAX_VERIFICATION, "true",
+ ],
+ true, true,
+ true)
+ SliderClient sliderClient = launcher.service
+ initHttpTestSupport(sliderClient.config)
+ def applicationReport = sliderClient.applicationReport
+ def proxyAM = applicationReport.trackingUrl
+ try {
+ postLaunchActions(sliderClient, clustername, echo, roles, proxyAM)
+ } catch (Exception ex) {
+ logMetricsQuietly(proxyAM)
+ throw ex;
+ }
+ }
+
+ /**
+ * retrieve cluster metrics and log quietly
+ * @param proxyAM
+ */
+ protected void logMetricsQuietly(String proxyAM) {
+ try {
+ log.error prettyPrintAsJson(GET(proxyAM, SYSTEM_METRICS_JSON));
+ } catch (Exception ex) {
+ log.warn("failed to get AM", ex)
+ }
+ }
+
+ /**
+ * Build the role map to use when creating teh cluster
+ * @param roleName the name used for the echo role
+ * @return the map
+ */
+ protected Map<String, Integer> buildRoleMap(String roleName) {
+ [
+ (roleName): 3,
+ ];
+ }
+
+ /**
+ * Any actions to perform after starting the agent cluster.
+ * HTTP client operations will have been set up already.
+ * @param sliderClient client for the cluster
+ * @param clustername cluster name
+ * @param rolename name of the echo role
+ * @param roles original set of roles
+ * @param proxyAM URl to proxy AM.
+ */
+ protected void postLaunchActions(
+ SliderClient sliderClient,
+ String clustername,
+ String rolename,
+ Map<String, Integer> roles,
+ String proxyAM) {
+ def onlyOneEcho = [(rolename): 1]
+ def requested = roles[rolename]
+
+ waitForRoleCount(sliderClient, onlyOneEcho, AGENT_CLUSTER_STARTUP_TIME)
+ //sleep a bit
+ sleep(5000)
+ //expect the role count to be the same
+ waitForRoleCount(sliderClient, onlyOneEcho, 1000)
+ def cd = sliderClient.getClusterDescription()
+ assert cd.getRoleOptInt(rolename, RoleKeys.ROLE_PENDING_AA_INSTANCES, -1) == requested - 1;
+ assert !cd.liveness.allRequestsSatisfied
+ assert cd.liveness.requestsOutstanding == requested - 1
+ def ipcClient = sliderClient.createIpcClient()
+
+ def echoInstances = sliderClient.listNodeUUIDsByRole(rolename)
+ queryRestAPI(sliderClient, roles, proxyAM)
+ // flex size
+ // while running, ask for many more, expect them to still be outstanding
+ sleep(5000)
+
+ requested = 50
+ def expectedPending = requested - 1
+
+ sliderClient.flex(clustername, [(rolename): requested]);
+ waitForRoleCount(sliderClient, onlyOneEcho, 1000)
+ sleep(4000)
+ def now = System.currentTimeMillis();
+ sleep(1000)
+
+ def componentInformation = ipcClient.getComponent(rolename)
+ assert !ipcClient.getComponent(rolename).isAARequestOutstanding
+
+ assert componentInformation.pendingAntiAffineRequestCount == expectedPending
+
+ cd = sliderClient.getClusterDescription()
+ assert !cd.liveness.allRequestsSatisfied
+ assert cd.liveness.requestsOutstanding == requested - 1
+ assert now <= Long.valueOf(cd.info.get(StatusKeys.INFO_STATUS_TIME_MILLIS))
+ assert expectedPending == cd.getRoleOptInt(rolename, RoleKeys.ROLE_PENDING_AA_INSTANCES, -1)
+
+ // while running, flex it to size = 1
+ sleep(1000)
+ sliderClient.flex(clustername, onlyOneEcho);
+ waitForRoleCount(sliderClient, onlyOneEcho, 1000)
+
+ def echoInstances2 = sliderClient.listNodeUUIDsByRole(rolename)
+ assertArrayEquals(echoInstances, echoInstances2)
+
+ assert !ipcClient.getComponent(rolename).isAARequestOutstanding
+ cd = sliderClient.getClusterDescription()
+ assert cd.liveness.allRequestsSatisfied
+
+
+ assert cd.getRoleOptInt(rolename, RoleKeys.ROLE_PENDING_AA_INSTANCES, -1) == 0;
+
+ def nodes = sliderClient.listYarnClusterNodes(new ActionNodesArgs())
+ assert nodes.size() == 1
+ def activeNodes = sliderClient.listInstanceNodes(clustername, new ActionNodesArgs())
+ assert activeNodes[0].entries[rolename] && activeNodes[0].entries[rolename].live == 1
+ }
+
+ protected void queryRestAPI(SliderClient sliderClient, Map<String, Integer> roles, String proxyAM) {
+ GET(proxyAM)
+ describe "Proxy SliderRestClient Tests"
+ SliderApplicationApiRestClient restAPI =
+ new SliderApplicationApiRestClient(createUGIJerseyClient(), proxyAM)
+ awaitGaugeValue(proxyAM,
+ MetricsConstants.PREFIX_SLIDER_ROLES + "echo.pendingAntiAffineRequests",
+ 2,
+ WEB_STARTUP_TIME * 2, 500)
+
+ def echoInfo = restAPI.getComponent(ECHO)
+ assert echoInfo.pendingAntiAffineRequestCount == 2
+ // no active requests ... there's no capacity
+ assert !echoInfo.isAARequestOutstanding
+ }
+}
diff --git a/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestAgentEcho.groovy b/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestAgentEcho.groovy
index 973114d..23a7bbb 100644
--- a/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestAgentEcho.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestAgentEcho.groovy
@@ -22,11 +22,14 @@
import groovy.util.logging.Slf4j
import org.apache.hadoop.yarn.conf.YarnConfiguration
import org.apache.slider.api.ResourceKeys
+import org.apache.slider.api.types.NodeInformationList
import org.apache.slider.client.SliderClient
import org.apache.slider.common.SliderExitCodes
import org.apache.slider.common.SliderXmlConfKeys
+import org.apache.slider.common.params.ActionNodesArgs
import org.apache.slider.core.exceptions.BadClusterStateException
import org.apache.slider.core.main.ServiceLauncher
+import org.apache.slider.core.persist.JsonSerDeser
import org.junit.Before
import org.junit.Test
@@ -40,6 +43,7 @@
@Slf4j
class TestAgentEcho extends AgentTestBase {
+ protected static final String ECHO = "echo"
File slider_core
String echo_py
File echo_py_path
@@ -59,7 +63,6 @@
agt_ver_path = new File(slider_core, agt_ver)
agt_conf = "agent.ini"
agt_conf_path = new File(slider_core, agt_conf)
-
}
@Override
@@ -68,7 +71,7 @@
}
@Test
- public void testEchoOperation() throws Throwable {
+ public void testAgentEcho() throws Throwable {
assumeValidServerEnv()
String clustername = createMiniCluster("",
@@ -79,12 +82,9 @@
true,
false)
- assert echo_py_path.exists()
- assert app_def_path.exists()
- assert agt_ver_path.exists()
- assert agt_conf_path.exists()
+ validatePaths()
- def role = "echo"
+ def role = ECHO
Map<String, Integer> roles = [
(role): 2,
];
@@ -127,5 +127,41 @@
assertExceptionDetails(e, SliderExitCodes.EXIT_BAD_STATE, "negative")
}
+
+ runNodemapTests(sliderClient)
+
+ }
+
+ /**
+ * do some nodemap checks, currently cluster-wide
+ * @param sliderClient
+ */
+ protected void runNodemapTests(SliderClient sliderClient) {
+ describe "slider nodes"
+ sliderClient.actionNodes("", new ActionNodesArgs())
+
+ def allNodes = sliderClient.listYarnClusterNodes(new ActionNodesArgs()).collect { it.httpAddress }
+ assert !allNodes.empty
+
+ // healthy only
+ def healthyNodes = sliderClient.listYarnClusterNodes(new ActionNodesArgs(healthy: true))
+ assert healthyNodes.collect { it.httpAddress }.containsAll(allNodes)
+ // look for an unknown label and expect none
+ def gpuNodes = sliderClient.listYarnClusterNodes(new ActionNodesArgs(label: "gpu"))
+ assert gpuNodes.empty
+ File t1 = createTempJsonFile()
+ sliderClient.actionNodes("", new ActionNodesArgs(outputFile: t1))
+ assert t1.exists()
+ JsonSerDeser<NodeInformationList> serDeser = new JsonSerDeser<>(NodeInformationList.class);
+ NodeInformationList loaded = serDeser.fromFile(t1)
+ assert allNodes.containsAll(loaded.collect { it.httpAddress })
+
+ }
+
+ protected void validatePaths() {
+ assert echo_py_path.exists()
+ assert app_def_path.exists()
+ assert agt_ver_path.exists()
+ assert agt_conf_path.exists()
}
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestBuildBasicAgent.groovy b/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestBuildBasicAgent.groovy
index 264d260..60e9035 100644
--- a/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestBuildBasicAgent.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestBuildBasicAgent.groovy
@@ -94,7 +94,9 @@
1,
true,
false)
- buildAgentCluster("test_build_basic_agent_node_only",
+
+ def cluster01 = clustername + "_01"
+ buildAgentCluster(cluster01,
[(ROLE_NODE): 1],
[
ARG_OPTION, CONTROLLER_URL, "http://localhost",
@@ -110,7 +112,9 @@
def master = "hbase-master"
def rs = "hbase-rs"
- ServiceLauncher<SliderClient> launcher = buildAgentCluster(clustername,
+
+ def cluster02 = clustername + "_02"
+ ServiceLauncher<SliderClient> launcher = buildAgentCluster(cluster02,
[
(ROLE_NODE): 1,
(master): 1,
@@ -149,10 +153,11 @@
def rscomponent = resource.getMandatoryComponent(rs)
assert "5" == rscomponent.getMandatoryOption(ResourceKeys.COMPONENT_INSTANCES)
- // now create an instance with no role priority for the newnode role
+ describe "build a cluster with no role priority for the newnode role"
+
try {
- def name2 = clustername + "-2"
- buildAgentCluster(name2,
+ def cluster03 = clustername + "_03"
+ buildAgentCluster(cluster03,
[
(ROLE_NODE): 2,
"role3": 1,
@@ -166,14 +171,16 @@
],
true, false,
false)
- failWithBuildSucceeding(name2, "no priority for one role")
+ failWithBuildSucceeding(cluster03, "no priority for one role")
} catch (BadConfigException expected) {
}
+ describe "build a cluster with the number of agents out of range"
try {
- launcher = buildAgentCluster(clustername + "-10",
+ def cluster04 = clustername + "_04"
+ launcher = buildAgentCluster(cluster04,
[
- (ROLE_NODE): 4,
+ (ROLE_NODE): 2000,
],
[
ARG_OPTION, CONTROLLER_URL, "http://localhost",
@@ -185,15 +192,18 @@
],
true, false,
false)
- failWithBuildSucceeding(ROLE_NODE, "too many instances")
+ failWithBuildSucceeding(cluster04, "too many instances")
} catch (BadConfigException expected) {
- assert expected.message.contains("Expected minimum is 1 and maximum is 2")
- assert expected.message.contains("Component echo, yarn.component.instances value 4 out of range.")
+ assertExceptionDetails(expected, SliderExitCodes.EXIT_BAD_CONFIGURATION,
+ "Expected minimum is 1 and maximum is")
+ assertExceptionDetails(expected, SliderExitCodes.EXIT_BAD_CONFIGURATION,
+ "out of range.")
}
- //duplicate priorities
+
+ describe "build a cluster with duplicate priorities for roles"
try {
- def name3 = clustername + "-3"
- buildAgentCluster(name3,
+ def cluster05 = clustername + "_05"
+ buildAgentCluster(cluster05,
[
(ROLE_NODE): 5,
(master): 1,
@@ -206,16 +216,16 @@
true, false,
false)
- failWithBuildSucceeding(name3, "duplicate priorities")
+ failWithBuildSucceeding(cluster05, "duplicate priorities")
} catch (BadConfigException expected) {
}
- def cluster4 = clustername + "-4"
+ def cluster06 = clustername + "_06"
def jvmopts = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
- buildAgentCluster(cluster4,
+ buildAgentCluster(cluster06,
[
(master): 1,
(rs): 5
@@ -235,7 +245,7 @@
false)
//now we want to look at the value
- AggregateConf instanceDefinition = loadInstanceDefinition(cluster4)
+ AggregateConf instanceDefinition = loadInstanceDefinition(cluster06)
def opt = instanceDefinition.getAppConfOperations().getComponentOpt(
SliderKeys.COMPONENT_AM,
RoleKeys.JVM_OPTS,
@@ -245,8 +255,8 @@
// now create an instance with no component options, hence no
// entry in the app config
- def name5 = clustername + "-5"
- buildAgentCluster(name5,
+ def name07 = clustername + "_07"
+ buildAgentCluster(name07,
[
"hbase-rs": 1,
],
@@ -403,9 +413,8 @@
def rscomponent2 = resource2.getMandatoryComponent(rs)
assert "6" == rscomponent2.getMandatoryOption(ResourceKeys.COMPONENT_INSTANCES)
}
-
+
public AggregateConf loadInstanceDefinition(String name) {
- def cluster4
def sliderFS = createSliderFileSystem()
def dirPath = sliderFS.buildClusterDirPath(name)
ConfPersister persister = new ConfPersister(sliderFS, dirPath)
@@ -697,10 +706,8 @@
}
public void failWithBuildSucceeding(String name, String reason) {
- def badArgs1
AggregateConf instanceDefinition = loadInstanceDefinition(name)
- log.error(
- "Build operation should have failed from $reason : \n$instanceDefinition")
+ log.error("Build operation should have failed from $reason : \n$instanceDefinition")
fail("Build operation should have failed from $reason")
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/BaseMockAppStateAATest.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/BaseMockAppStateAATest.groovy
new file mode 100644
index 0000000..7b3a65d
--- /dev/null
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/BaseMockAppStateAATest.groovy
@@ -0,0 +1,62 @@
+/*
+ * 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.slider.server.appmaster.model.appstate
+
+import groovy.transform.CompileStatic
+import groovy.util.logging.Slf4j
+import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
+import org.apache.slider.server.appmaster.model.mock.MockFactory
+import org.apache.slider.server.appmaster.model.mock.MockRoles
+import org.apache.slider.server.appmaster.state.AppStateBindingInfo
+import org.apache.slider.server.appmaster.state.RoleStatus
+
+/**
+ * class for basis of Anti-affine placement tests; sets up role2
+ * for anti-affinity
+ */
+@CompileStatic
+@Slf4j
+class BaseMockAppStateAATest extends BaseMockAppStateTest
+ implements MockRoles {
+
+ /** Role status for the base AA role */
+ RoleStatus aaRole
+
+ /** Role status for the AA role requiring a node with the gpu label */
+ RoleStatus gpuRole
+
+ @Override
+ AppStateBindingInfo buildBindingInfo() {
+ def bindingInfo = super.buildBindingInfo()
+ bindingInfo.roles = [
+ MockFactory.PROVIDER_ROLE0,
+ MockFactory.AAROLE_1_GPU,
+ MockFactory.AAROLE_2,
+ ]
+ bindingInfo
+ }
+
+ @Override
+ void setup() {
+ super.setup()
+ aaRole = lookupRole(MockFactory.AAROLE_2.name)
+ gpuRole = lookupRole(MockFactory.AAROLE_1_GPU.name)
+ }
+
+}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateAAOvercapacity.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateAAOvercapacity.groovy
new file mode 100644
index 0000000..a8c50d1
--- /dev/null
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateAAOvercapacity.groovy
@@ -0,0 +1,102 @@
+/*
+ * 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.slider.server.appmaster.model.appstate
+
+import groovy.transform.CompileStatic
+import groovy.util.logging.Slf4j
+import org.apache.hadoop.yarn.api.records.Container
+import org.apache.slider.core.main.LauncherExitCodes
+import org.apache.slider.server.appmaster.model.mock.MockRoles
+import org.apache.slider.server.appmaster.model.mock.MockYarnEngine
+import org.apache.slider.server.appmaster.operations.AbstractRMOperation
+import org.apache.slider.server.appmaster.state.AppState
+import org.junit.Test
+
+/**
+ * Test Anti-affine placement with a cluster of size 1
+ */
+@CompileStatic
+@Slf4j
+class TestMockAppStateAAOvercapacity extends BaseMockAppStateAATest
+ implements MockRoles {
+
+ private int NODES = 1
+
+ @Override
+ MockYarnEngine createYarnEngine() {
+ new MockYarnEngine(NODES, 1)
+ }
+
+ void assertAllContainersAA() {
+ assertAllContainersAA(aaRole.key)
+ }
+
+ /**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testOvercapacityRecovery() throws Throwable {
+
+ describe("Ask for 1 more than the no of available nodes;" +
+ "verify the state. kill the allocated container and review")
+ //more than expected
+ long desired = 3
+ aaRole.desired = desired
+ assert appState.roleHistory.canPlaceAANodes()
+
+ //first request
+ List<AbstractRMOperation > operations = appState.reviewRequestAndReleaseNodes()
+ assert aaRole.AARequestOutstanding
+ assert desired - 1 == aaRole.pendingAntiAffineRequests
+ List<AbstractRMOperation > operationsOut = []
+ // allocate and re-submit
+ def instances = submitOperations(operations, [], operationsOut)
+ assert 1 == instances.size()
+ assertAllContainersAA()
+
+ // expect an outstanding AA request to be unsatisfied
+ assert aaRole.actual < aaRole.desired
+ assert !aaRole.requested
+ assert !aaRole.AARequestOutstanding
+ assert desired - 1 == aaRole.pendingAntiAffineRequests
+ List<Container> allocatedContainers = engine.execute(operations, [])
+ assert 0 == allocatedContainers.size()
+
+ // now lets trigger a failure
+ def nodemap = cloneNodemap()
+ assert nodemap.size() == 1
+
+ def instance = instances[0]
+ def cid = instance.containerId
+
+ AppState.NodeCompletionResult result = appState.onCompletedNode(containerStatus(cid,
+ LauncherExitCodes.EXIT_TASK_LAUNCH_FAILURE))
+ assert result.containerFailed
+
+ assert aaRole.failed == 1
+ assert aaRole.actual == 0
+ def availablePlacements = appState.getRoleHistory().findNodeForNewAAInstance(aaRole)
+ assert availablePlacements.size() == 1
+ describe "expecting a successful review with available placements of $availablePlacements"
+ operations = appState.reviewRequestAndReleaseNodes()
+ assert operations.size() == 1
+ }
+
+ }
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateAAPlacement.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateAAPlacement.groovy
new file mode 100644
index 0000000..e43d894
--- /dev/null
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateAAPlacement.groovy
@@ -0,0 +1,340 @@
+/*
+ * 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.slider.server.appmaster.model.appstate
+
+import groovy.transform.CompileStatic
+import groovy.util.logging.Slf4j
+import org.apache.hadoop.yarn.api.records.Container
+import org.apache.hadoop.yarn.api.records.NodeState
+import org.apache.hadoop.yarn.client.api.AMRMClient
+import org.apache.slider.api.ResourceKeys
+import org.apache.slider.api.types.NodeInformationList
+import org.apache.slider.core.conf.ConfTreeOperations
+import org.apache.slider.providers.PlacementPolicy
+import org.apache.slider.server.appmaster.model.mock.MockAppState
+import org.apache.slider.server.appmaster.model.mock.MockFactory
+import org.apache.slider.server.appmaster.model.mock.MockNodeReport
+import org.apache.slider.server.appmaster.model.mock.MockRoles
+import org.apache.slider.server.appmaster.model.mock.MockYarnEngine
+import org.apache.slider.server.appmaster.operations.AbstractRMOperation
+import org.apache.slider.server.appmaster.state.AppState
+import org.apache.slider.server.appmaster.state.ContainerAssignment
+import org.apache.slider.server.appmaster.state.RoleInstance
+import org.junit.Test
+
+/**
+ * Test Anti-affine placement
+ */
+@CompileStatic
+@Slf4j
+class TestMockAppStateAAPlacement extends BaseMockAppStateAATest
+ implements MockRoles {
+
+ private int NODES = 3
+
+ /**
+ * The YARN engine has a cluster with very few nodes (3) and lots of containers, so
+ * if AA placement isn't working, there will be affine placements surfacing.
+ * @return
+ */
+ @Override
+ MockYarnEngine createYarnEngine() {
+ new MockYarnEngine(NODES, 8)
+ }
+
+ /**
+ * This is the simplest AA allocation: no lables, so allocate anywhere
+ * @throws Throwable
+ */
+ @Test
+ public void testAllocateAANoLabel() throws Throwable {
+ assert cloneNodemap().size() > 0
+
+ // want multiple instances, so there will be iterations
+ aaRole.desired = 2
+
+ List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes()
+ AMRMClient.ContainerRequest request = getSingleRequest(ops)
+ assert !request.relaxLocality
+ assert request.nodes.size() == engine.cluster.clusterSize
+ assert request.racks == null
+ assert request.capability
+
+ Container allocated = engine.allocateContainer(request)
+
+ // notify the container ane expect
+ List<ContainerAssignment> assignments = [];
+ List<AbstractRMOperation> operations = []
+ appState.onContainersAllocated([allocated], assignments, operations)
+
+ def host = allocated.nodeId.host
+ def hostInstance = cloneNodemap().get(host)
+ assert hostInstance.get(aaRole.key).starting == 1
+ assert !hostInstance.canHost(aaRole.key, "")
+ assert !hostInstance.canHost(aaRole.key, null)
+
+ // assignment
+ assert assignments.size() == 1
+
+ // verify the release matches the allocation
+ assert operations.size() == 2
+ assert getCancel(operations, 0).capability.equals(allocated.resource)
+
+ // we also expect a new allocation request to have been issued
+
+ def req2 = getRequest(operations, 1)
+ assert req2.nodes.size() == engine.cluster.clusterSize - 1
+
+ assert !req2.nodes.contains(host)
+ assert !request.relaxLocality
+
+ // verify the pending couner is down
+ assert 0L == aaRole.pendingAntiAffineRequests
+ Container allocated2 = engine.allocateContainer(req2)
+
+ // placement must be on a different host
+ assert allocated2.nodeId != allocated.nodeId
+
+ ContainerAssignment assigned = assignments[0]
+ Container container = assigned.container
+ RoleInstance ri = roleInstance(assigned)
+ //tell the app it arrived
+ appState.containerStartSubmitted(container, ri);
+ assert appState.onNodeManagerContainerStarted(container.id)
+ ops = appState.reviewRequestAndReleaseNodes()
+ assert ops.size() == 0
+ assertAllContainersAA();
+
+ // identify those hosts with an aa role on
+ def naming = appState.buildNamingMap()
+ assert naming.size() == 3
+
+ def name = aaRole.name
+ assert name == naming[aaRole.key]
+ def info = appState.roleHistory.getNodeInformationSnapshot(naming);
+ assert info
+
+ def nodeInformation = info[host]
+ assert nodeInformation
+ assert nodeInformation.entries
+ assert nodeInformation.entries[name]
+ assert nodeInformation.entries[name].live
+ }
+
+ @Test
+ public void testAllocateFlexUp() throws Throwable {
+ // want multiple instances, so there will be iterations
+ aaRole.desired = 2
+ List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes()
+ getSingleRequest(ops)
+ assert aaRole.requested == 1
+ assert aaRole.pendingAntiAffineRequests == 1
+ assert aaRole.actualAndRequested + aaRole.pendingAntiAffineRequests == aaRole.desired
+
+ // now trigger that flex up
+ aaRole.desired = 3
+
+ // expect: no new reqests, pending count ++
+ List<AbstractRMOperation> ops2 = appState.reviewRequestAndReleaseNodes()
+ assert ops2.empty
+ assert aaRole.actual + aaRole.pendingAntiAffineRequests + aaRole.outstandingAARequestCount ==
+ aaRole.desired
+
+ // 1 outstanding
+ assert aaRole.actual == 0
+ assert aaRole.AARequestOutstanding
+ // and one AA
+ assert aaRole.pendingAntiAffineRequests == 2
+ assertAllContainersAA()
+
+ // next iter
+ assert 1 == submitOperations(ops, [], ops2).size()
+ assert 2 == ops2.size()
+ assert aaRole.pendingAntiAffineRequests == 1
+ assertAllContainersAA()
+
+ assert 0 == appState.reviewRequestAndReleaseNodes().size()
+ // now trigger the next execution cycle
+ List<AbstractRMOperation> ops3 = []
+ assert 1 == submitOperations(ops2, [], ops3).size()
+ assert 2 == ops3.size()
+ assert aaRole.pendingAntiAffineRequests == 0
+ assertAllContainersAA()
+
+ }
+
+ @Test
+ public void testAllocateFlexDownDecrementsPending() throws Throwable {
+ // want multiple instances, so there will be iterations
+ aaRole.desired = 2
+ List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes()
+ getSingleRequest(ops)
+ assert aaRole.pendingAntiAffineRequests == 1
+ assert aaRole.AARequestOutstanding
+
+ // flex down so that the next request should be cancelled
+ aaRole.desired = 1
+
+ // expect: no new requests, pending count --
+ List<AbstractRMOperation> ops2 = appState.reviewRequestAndReleaseNodes()
+ assert ops2.empty
+ assert aaRole.AARequestOutstanding
+ assert aaRole.pendingAntiAffineRequests == 0
+ assertAllContainersAA()
+
+ // next iter
+ submitOperations(ops, [], ops2).size()
+ assert 1 == ops2.size()
+ assertAllContainersAA()
+ }
+
+ /**
+ * Here flex down while there is only one outstanding request.
+ * The outstanding flex should be cancelled
+ * @throws Throwable
+ */
+ @Test
+ public void testAllocateFlexDownForcesCancel() throws Throwable {
+ // want multiple instances, so there will be iterations
+ aaRole.desired = 1
+ List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes()
+ getSingleRequest(ops)
+ assert aaRole.pendingAntiAffineRequests == 0
+ assert aaRole.AARequestOutstanding
+
+ // flex down so that the next request should be cancelled
+ aaRole.desired = 0
+ // expect: no new reqests, pending count --
+ List<AbstractRMOperation> ops2 = appState.reviewRequestAndReleaseNodes()
+ assert aaRole.pendingAntiAffineRequests == 0
+ assert !aaRole.AARequestOutstanding
+ assert ops2.size() == 1
+ getSingleCancel(ops2)
+
+ // next iter
+ submitOperations(ops, [], ops2).size()
+ assert 1 == ops2.size()
+ }
+
+ void assertAllContainersAA() {
+ assertAllContainersAA(aaRole.key)
+ }
+
+ /**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testAskForTooMany() throws Throwable {
+
+ describe("Ask for 1 more than the no of available nodes;" +
+ " expect the final request to be unsatisfied until the cluster changes size")
+ //more than expected
+ aaRole.desired = NODES + 1
+ List<AbstractRMOperation > operations = appState.reviewRequestAndReleaseNodes()
+ assert aaRole.AARequestOutstanding
+ assert NODES == aaRole.pendingAntiAffineRequests
+ for (int i = 0; i < NODES; i++) {
+ def iter = "Iteration $i role = $aaRole"
+ log.info(iter)
+ List<AbstractRMOperation > operationsOut = []
+ assert 1 == submitOperations(operations, [], operationsOut).size(), iter
+ operations = operationsOut
+ if (i + 1 < NODES) {
+ assert operations.size() == 2
+ } else {
+ assert operations.size() == 1
+ }
+ assertAllContainersAA()
+ }
+ // expect an outstanding AA request to be unsatisfied
+ assert aaRole.actual < aaRole.desired
+ assert !aaRole.requested
+ assert !aaRole.AARequestOutstanding
+ List<Container> allocatedContainers = engine.execute(operations, [])
+ assert 0 == allocatedContainers.size()
+ // in a review now, no more requests can be generated, as there is no space for AA placements,
+ // even though there is cluster capacity
+ assert 0 == appState.reviewRequestAndReleaseNodes().size()
+
+ // now do a node update (this doesn't touch the YARN engine; the node isn't really there)
+ def outcome = addNewNode()
+ assert cloneNodemap().size() == NODES + 1
+ assert outcome.clusterChanged
+ // no active calls to empty
+ assert outcome.operations.empty
+ assert 1 == appState.reviewRequestAndReleaseNodes().size()
+ }
+
+ protected AppState.NodeUpdatedOutcome addNewNode() {
+ updateNodes(new MockNodeReport("4", NodeState.RUNNING, "gpu"))
+ }
+
+ @Test
+ public void testClusterSizeChangesDuringRequestSequence() throws Throwable {
+ describe("Change the cluster size where the cluster size changes during a test sequence.")
+ aaRole.desired = NODES + 1
+ appState.reviewRequestAndReleaseNodes()
+ assert aaRole.AARequestOutstanding
+ assert NODES == aaRole.pendingAntiAffineRequests
+ def outcome = addNewNode()
+ assert outcome.clusterChanged
+ // one call to cancel
+ assert 1 == outcome.operations.size()
+ // and on a review, one more to rebuild
+ assert 1 == appState.reviewRequestAndReleaseNodes().size()
+ }
+
+ @Test
+ public void testBindingInfoMustHaveNodeMap() throws Throwable {
+ def bindingInfo = buildBindingInfo()
+ bindingInfo.nodeReports = null;
+ try {
+ def state = new MockAppState(bindingInfo)
+ fail("Expected an exception, got $state")
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testAMRestart() throws Throwable {
+ def desiredAA = 3
+ aaRole.desired = desiredAA
+ List<RoleInstance> instances = createAndStartNodes()
+ List<Container> containers = instances.collect { it.container }
+
+ // now destroy the app state
+ def bindingInfo = buildBindingInfo()
+ bindingInfo.instanceDefinition = factory.newInstanceDefinition(0, 0, desiredAA)
+ ConfTreeOperations cto = new ConfTreeOperations(bindingInfo.instanceDefinition.resources)
+ cto.setComponentOpt(ROLE2,
+ ResourceKeys.COMPONENT_PLACEMENT_POLICY,
+ PlacementPolicy.ANTI_AFFINITY_REQUIRED)
+ bindingInfo.liveContainers = containers
+ appState = new MockAppState(bindingInfo)
+
+ def aaRole = lookupRole(MockFactory.AAROLE_2.name)
+ def gpuRole = lookupRole(MockFactory.AAROLE_1_GPU.name)
+ appState.reviewRequestAndReleaseNodes()
+ assert aaRole.antiAffinePlacement
+ assert aaRole.AARequestOutstanding
+
+ }
+
+}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateAppRestIntegration.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateAppRestIntegration.groovy
index d36fdbc..6739623 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateAppRestIntegration.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateAppRestIntegration.groovy
@@ -41,11 +41,6 @@
@Slf4j
class TestMockAppStateAppRestIntegration extends BaseMockAppStateTest implements MockRoles {
- @Override
- String getTestName() {
- return "TestMockAppStateAppRestIntegration"
- }
-
@Test
public void testCachedIntDocument() throws Throwable {
ContentCache cache = new ContentCache()
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateContainerFailure.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateContainerFailure.groovy
index 1b79115..3235827 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateContainerFailure.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateContainerFailure.groovy
@@ -58,7 +58,7 @@
*/
@Override
MockYarnEngine createYarnEngine() {
- return new MockYarnEngine(8000, 4)
+ return new MockYarnEngine(4, 8000)
}
@Override
@@ -95,7 +95,7 @@
//view the world
appState.getRoleHistory().dump();
- List<NodeInstance> queue = appState.roleHistory.cloneAvailableList(0)
+ List<NodeInstance> queue = appState.roleHistory.cloneRecentNodeList(0)
assert queue.size() == 0
}
@@ -123,7 +123,7 @@
//view the world
appState.getRoleHistory().dump();
- List<NodeInstance> queue = appState.roleHistory.cloneAvailableList(0)
+ List<NodeInstance> queue = appState.roleHistory.cloneRecentNodeList(0)
assert queue.size() == 1
}
@@ -148,7 +148,7 @@
RoleHistory history = appState.roleHistory
history.dump();
- List<NodeInstance> queue = history.cloneAvailableList(0)
+ List<NodeInstance> queue = history.cloneRecentNodeList(0)
assert queue.size() == 0
NodeInstance ni = history.getOrCreateNodeInstance(instance.container)
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicHistory.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicHistory.groovy
index aa7bb11..e57f341 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicHistory.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicHistory.groovy
@@ -20,7 +20,6 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.yarn.api.records.ContainerId
import org.apache.slider.api.ResourceKeys
import org.apache.slider.core.conf.ConfTreeOperations
@@ -28,7 +27,6 @@
import org.apache.slider.providers.PlacementPolicy
import org.apache.slider.providers.ProviderRole
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
-import org.apache.slider.server.appmaster.model.mock.MockAppState
import org.apache.slider.server.appmaster.model.mock.MockRoleHistory
import org.apache.slider.server.appmaster.model.mock.MockRoles
import org.apache.slider.server.appmaster.model.mock.MockYarnEngine
@@ -36,7 +34,7 @@
import org.apache.slider.server.appmaster.state.AppState
import org.apache.slider.server.appmaster.state.NodeInstance
import org.apache.slider.server.appmaster.state.RoleInstance
-import org.apache.slider.server.appmaster.state.SimpleReleaseSelector
+import org.apache.slider.server.appmaster.state.RoleStatus
import org.junit.Test
/**
@@ -47,11 +45,6 @@
class TestMockAppStateDynamicHistory extends BaseMockAppStateTest
implements MockRoles {
- @Override
- String getTestName() {
- return "TestMockAppStateDynamicHistory"
- }
-
/**
* Small cluster with multiple containers per node,
* to guarantee many container allocations on each node
@@ -62,26 +55,6 @@
return new MockYarnEngine(8, 1)
}
- @Override
- void initApp() {
- super.initApp()
- appState = new MockAppState()
- appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES)
-
- def instance = factory.newInstanceDefinition(0,0,0)
-
- appState.buildInstance(
- instance,
- new Configuration(),
- new Configuration(false),
- factory.ROLES,
- fs,
- historyPath,
- null,
- null, new SimpleReleaseSelector())
- }
-
-
@Test
public void testDynamicRoleHistory() throws Throwable {
@@ -199,7 +172,7 @@
assert !entry.live
- def nodesForRoleId = roleHistory.getNodesForRoleId(role_priority_8)
+ def nodesForRoleId = roleHistory.getRecentNodesForRoleId(role_priority_8)
assert nodesForRoleId
// make sure new nodes will default to a different host in the engine
@@ -215,21 +188,16 @@
@Test(expected = BadConfigException.class)
public void testRoleHistoryRoleAdditions() throws Throwable {
MockRoleHistory roleHistory = new MockRoleHistory([])
- roleHistory.addNewProviderRole(new ProviderRole("one", 1))
- roleHistory.addNewProviderRole(new ProviderRole("two", 1))
+ roleHistory.addNewRole(new RoleStatus(new ProviderRole("one", 1)))
+ roleHistory.addNewRole(new RoleStatus(new ProviderRole("two", 1)))
roleHistory.dump()
- fail("should have raised an exception")
}
-
-
+
@Test(expected = BadConfigException.class)
public void testRoleHistoryRoleStartupConflict() throws Throwable {
MockRoleHistory roleHistory = new MockRoleHistory([
new ProviderRole("one", 1), new ProviderRole("two", 1)
])
roleHistory.dump()
- fail("should have raised an exception")
}
-
-
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicRoles.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicRoles.groovy
index ee4abd6..d0163d2 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicRoles.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicRoles.groovy
@@ -20,21 +20,17 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-import org.apache.hadoop.conf.Configuration
-import org.apache.hadoop.yarn.api.records.ContainerId
import org.apache.slider.api.ResourceKeys
+import org.apache.slider.core.conf.AggregateConf
import org.apache.slider.providers.PlacementPolicy
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
-import org.apache.slider.server.appmaster.model.mock.MockAppState
import org.apache.slider.server.appmaster.model.mock.MockRoles
import org.apache.slider.server.appmaster.model.mock.MockYarnEngine
import org.apache.slider.server.appmaster.operations.AbstractRMOperation
import org.apache.slider.server.appmaster.operations.ContainerRequestOperation
-import org.apache.slider.server.appmaster.state.AppState
import org.apache.slider.server.appmaster.state.ContainerPriority
import org.apache.slider.server.appmaster.state.RoleHistoryUtils
import org.apache.slider.server.appmaster.state.RoleInstance
-import org.apache.slider.server.appmaster.state.SimpleReleaseSelector
import org.junit.Test
/**
@@ -65,40 +61,27 @@
}
@Override
- void initApp() {
- super.initApp()
- appState = new MockAppState()
- appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES)
- def instance = factory.newInstanceDefinition(0,0,0)
-
+ AggregateConf buildInstanceDefinition() {
+ def instance = factory.newInstanceDefinition(0, 0, 0)
def opts = [
- (ResourceKeys.COMPONENT_PRIORITY): ROLE4,
+ (ResourceKeys.COMPONENT_PRIORITY) : ROLE4,
(ResourceKeys.COMPONENT_INSTANCES): "1",
]
- instance.resourceOperations.components[ROLE4]= opts
+ instance.resourceOperations.components[ROLE4] = opts
def opts5 = [
- (ResourceKeys.COMPONENT_PRIORITY) : ROLE5,
- (ResourceKeys.COMPONENT_INSTANCES): "1",
+ (ResourceKeys.COMPONENT_PRIORITY) : ROLE5,
+ (ResourceKeys.COMPONENT_INSTANCES) : "1",
(ResourceKeys.COMPONENT_PLACEMENT_POLICY):
Integer.toString(PlacementPolicy.STRICT),
- (ResourceKeys.NODE_FAILURE_THRESHOLD):
+ (ResourceKeys.NODE_FAILURE_THRESHOLD) :
Integer.toString(2),
]
- instance.resourceOperations.components[ROLE5]= opts5
-
- appState.buildInstance(
- instance,
- new Configuration(),
- new Configuration(false),
- factory.ROLES,
- fs,
- historyPath,
- null,
- null, new SimpleReleaseSelector())
+ instance.resourceOperations.components[ROLE5] = opts5
+ instance
}
@Test
@@ -115,21 +98,16 @@
* @param actions source list
* @return found list
*/
- List<ContainerRequestOperation> findAllocationsForRole(int role,
+ Collection<ContainerRequestOperation> findAllocationsForRole(int role,
List<AbstractRMOperation> actions) {
- List <ContainerRequestOperation > results = []
- actions.each { AbstractRMOperation operation ->
- if (operation instanceof ContainerRequestOperation) {
- def req = (ContainerRequestOperation) operation;
- def reqrole = ContainerPriority.extractRole(req.request.priority)
- if (role == reqrole) {
- results << req
- }
- }
+ def requests = actions.findAll {
+ it instanceof ContainerRequestOperation}.collect {it as ContainerRequestOperation}
+
+ requests.findAll {
+ role == ContainerPriority.extractRole(it.request.priority)
}
- return results
- }
-
+ }
+
@Test
public void testStrictPlacementInitialRequest() throws Throwable {
log.info("Initial engine state = $engine")
@@ -141,7 +119,6 @@
assertRelaxLocalityFlag(ID5, null, true, actions)
}
-
@Test
public void testPolicyPropagation() throws Throwable {
assert !(appState.lookupRoleStatus(ROLE4).placementPolicy & PlacementPolicy.STRICT)
@@ -153,7 +130,6 @@
public void testNodeFailureThresholdPropagation() throws Throwable {
assert (appState.lookupRoleStatus(ROLE4).nodeFailureThreshold == 3)
assert (appState.lookupRoleStatus(ROLE5).nodeFailureThreshold == 2)
-
}
@Test
@@ -173,7 +149,6 @@
assert instanceA
def hostname = RoleHistoryUtils.hostnameOf(instanceA.container)
-
log.info("Allocated engine state = $engine")
assert engine.containerCount() == 1
@@ -183,8 +158,7 @@
role4.desired = 0
appState.lookupRoleStatus(ROLE4).desired = 0
def completionResults = []
- def containersToRelease = []
- instances = createStartAndStopNodes(completionResults)
+ createStartAndStopNodes(completionResults)
assert engine.containerCount() == 0
assert completionResults.size() == 1
@@ -215,19 +189,16 @@
}
assert instanceA
def hostname = RoleHistoryUtils.hostnameOf(instanceA.container)
-
-
log.info("Allocated engine state = $engine")
assert engine.containerCount() == 1
assert role5.actual == 1
- // shrinking cluster
+ // shrinking cluster
role5.desired = 0
def completionResults = []
- def containersToRelease = []
- instances = createStartAndStopNodes(completionResults)
+ createStartAndStopNodes(completionResults)
assert engine.containerCount() == 0
assert completionResults.size() == 1
assert role5.actual == 0
@@ -240,16 +211,15 @@
def nodes = cro.request.nodes
assert nodes.size() == 1
assert hostname == nodes[0]
-
}
public void assertRelaxLocalityFlag(
- int id,
+ int role,
String expectedHost,
boolean expectedRelaxFlag,
List<AbstractRMOperation> actions) {
def requests
- requests = findAllocationsForRole(id, actions)
+ requests = findAllocationsForRole(role, actions)
assert requests.size() == 1
def req = requests[0]
assert expectedRelaxFlag == req.request.relaxLocality
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexDynamicRoles.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexDynamicRoles.groovy
index 5d880b4..7bc6fe4 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexDynamicRoles.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexDynamicRoles.groovy
@@ -20,21 +20,22 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs.Path
import org.apache.slider.api.ResourceKeys
+import org.apache.slider.core.conf.AggregateConf
import org.apache.slider.core.conf.ConfTreeOperations
import org.apache.slider.core.exceptions.BadConfigException
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
import org.apache.slider.server.appmaster.model.mock.MockAppState
import org.apache.slider.server.appmaster.model.mock.MockRoles
import org.apache.slider.server.appmaster.model.mock.MockYarnEngine
+import org.apache.slider.server.appmaster.state.AppStateBindingInfo
import org.apache.slider.server.appmaster.state.MostRecentContainerReleaseSelector
import org.apache.slider.server.avro.RoleHistoryWriter
import org.junit.Test
/**
- * Test that if you have >1 role, the right roles are chosen for release.
+ * Test that if you have more than one role, the right roles are chosen for release.
*/
@CompileStatic
@Slf4j
@@ -57,32 +58,25 @@
}
@Override
- void initApp() {
- super.initApp()
- appState = new MockAppState()
- appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES)
+ AppStateBindingInfo buildBindingInfo() {
+ def bindingInfo = super.buildBindingInfo()
+ bindingInfo.releaseSelector = new MostRecentContainerReleaseSelector()
+ bindingInfo
+ }
+ @Override
+ AggregateConf buildInstanceDefinition() {
def instance = factory.newInstanceDefinition(0, 0, 0)
def opts = [
(ResourceKeys.COMPONENT_INSTANCES): "1",
- (ResourceKeys.COMPONENT_PRIORITY): "6",
+ (ResourceKeys.COMPONENT_PRIORITY) : "6",
]
instance.resourceOperations.components["dynamic-6"] = opts
-
-
- appState.buildInstance(instance,
- new Configuration(),
- new Configuration(false),
- factory.ROLES,
- fs,
- historyPath,
- null, null,
- new MostRecentContainerReleaseSelector())
+ instance
}
-
private ConfTreeOperations init() {
createAndStartNodes();
def resources = appState.instanceDefinition.resources;
@@ -181,16 +175,10 @@
def historyWorkDir2 = new File("target/history" + testName + "-0002")
def historyPath2 = new Path(historyWorkDir2.toURI())
appState = new MockAppState()
- appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES)
- appState.buildInstance(
- factory.newInstanceDefinition(0, 0, 0),
- new Configuration(),
- new Configuration(false),
- factory.ROLES,
- fs,
- historyPath2,
- null, null,
- new MostRecentContainerReleaseSelector())
+ def binding2 = buildBindingInfo()
+ binding2.instanceDefinition = factory.newInstanceDefinition(0, 0, 0)
+ binding2.historyPath = historyPath2
+ appState.buildInstance(binding2)
// on this read there won't be the right number of roles
def loadedRoleHistory = historyWriter.read(fs, history)
assert 0 == appState.roleHistory.rebuild(loadedRoleHistory)
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexing.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexing.groovy
index 257092a..548842c 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexing.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexing.groovy
@@ -20,7 +20,6 @@
import groovy.util.logging.Slf4j
import org.apache.hadoop.yarn.api.records.Container
-import org.apache.slider.api.ClusterDescription
import org.apache.slider.core.exceptions.TriggerClusterTeardownException
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
import org.apache.slider.server.appmaster.model.mock.MockRoles
@@ -76,7 +75,7 @@
ops = appState.reviewRequestAndReleaseNodes()
assert ops.empty
- RoleInstance ri2 = appState.innerOnNodeManagerContainerStarted(target.id)
+ appState.innerOnNodeManagerContainerStarted(target.id)
}
@Test
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateRMOperations.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateRMOperations.groovy
index 9ac6fcf..ba7588a 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateRMOperations.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateRMOperations.groovy
@@ -110,7 +110,6 @@
// four outstanding
assert role0.requested == 4
-
// flex cluster to 3
role0.desired = 3
ops = appState.reviewRequestAndReleaseNodes()
@@ -226,8 +225,7 @@
public void testFlexUpNoSpace() throws Throwable {
// engine only has two nodes, so > 2 will be outstanding
engine = new MockYarnEngine(1, 2)
- List<AbstractRMOperation> ops
- // role: desired = 2, requested = 1, actual=1
+ // role: desired = 2, requested = 1, actual=1
def role0 = role0Status
role0.desired = 4
createAndSubmitNodes()
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateRebuildOnAMRestart.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateRebuildOnAMRestart.groovy
index c310583..0e526b6 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateRebuildOnAMRestart.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateRebuildOnAMRestart.groovy
@@ -20,14 +20,11 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.yarn.api.records.Container
import org.apache.slider.api.StatusKeys
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
import org.apache.slider.server.appmaster.model.mock.MockAppState
import org.apache.slider.server.appmaster.model.mock.MockRoles
-import org.apache.slider.server.appmaster.operations.AbstractRMOperation
-import org.apache.slider.server.appmaster.state.MostRecentContainerReleaseSelector
import org.apache.slider.server.appmaster.state.NodeEntry
import org.apache.slider.server.appmaster.state.NodeInstance
import org.apache.slider.server.appmaster.state.NodeMap
@@ -35,12 +32,11 @@
import org.junit.Test
/**
- * Test that if you have >1 role, the right roles are chosen for release.
+ * Test that app state is rebuilt on a restart
*/
@CompileStatic
@Slf4j
-class TestMockAppStateRebuildOnAMRestart extends BaseMockAppStateTest
- implements MockRoles {
+class TestMockAppStateRebuildOnAMRestart extends BaseMockAppStateTest implements MockRoles {
@Override
String getTestName() {
@@ -62,28 +58,15 @@
assert instances.size() == clusterSize
//clone the list
- List<RoleInstance> cloned = [];
- List<Container> containers = []
- instances.each { RoleInstance elt ->
- cloned.add(elt.clone() as RoleInstance)
- containers.add(elt.container)
- }
+ List<Container> containers = instances.collect { it.container }
NodeMap nodemap = appState.roleHistory.cloneNodemap()
- // now destroy the app state
- appState = new MockAppState()
-
//and rebuild
- appState.buildInstance(
- factory.newInstanceDefinition(r0, r1, r2),
- new Configuration(),
- new Configuration(false),
- factory.ROLES,
- fs,
- historyPath,
- containers,
- null,
- new MostRecentContainerReleaseSelector())
+
+ def bindingInfo = buildBindingInfo()
+ bindingInfo.instanceDefinition = factory.newInstanceDefinition(r0, r1, r2)
+ bindingInfo.liveContainers = containers
+ appState = new MockAppState(bindingInfo)
assert appState.startedCountainerCount == clusterSize
@@ -107,22 +90,18 @@
assertNotNull("Null entry in original nodemap for " + hostname, orig)
for (int i = 0; i < ROLE_COUNT; i++) {
-
- assert (nodeInstance.getActiveRoleInstances(i) ==
- orig.getActiveRoleInstances(i))
+ assert (nodeInstance.getActiveRoleInstances(i) == orig.getActiveRoleInstances(i))
NodeEntry origRE = orig.getOrCreate(i)
NodeEntry newRE = nodeInstance.getOrCreate(i)
assert origRE.live == newRE.live
- assert newRE.starting == 0
+ assert 0 == newRE.starting
}
}
- List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes()
- assert ops.size() == 0
+ assert 0 == appState.reviewRequestAndReleaseNodes().size()
- def status = appState.getClusterStatus()
+ def status = appState.clusterStatus
// verify the AM restart container count was set
- String restarted = status.getInfo(
- StatusKeys.INFO_CONTAINERS_AM_RESTART)
+ String restarted = status.getInfo(StatusKeys.INFO_CONTAINERS_AM_RESTART)
assert restarted != null;
//and that the count == 1 master + the region servers
assert Integer.parseInt(restarted) == containers.size()
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockContainerResourceAllocations.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockContainerResourceAllocations.groovy
index 4ba0afd..93cce95 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockContainerResourceAllocations.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockContainerResourceAllocations.groovy
@@ -25,6 +25,7 @@
import org.apache.slider.core.conf.ConfTree
import org.apache.slider.core.conf.ConfTreeOperations
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
+import org.apache.slider.server.appmaster.model.mock.MockAppState
import org.apache.slider.server.appmaster.model.mock.MockRoles
import org.apache.slider.server.appmaster.operations.AbstractRMOperation
import org.apache.slider.server.appmaster.operations.ContainerRequestOperation
@@ -37,11 +38,6 @@
@Slf4j
class TestMockContainerResourceAllocations extends BaseMockAppStateTest {
- @Override
- String getTestName() {
- "TestMockContainerResourceAllocations"
- }
-
@Test
public void testNormalAllocations() throws Throwable {
ConfTree clusterSpec = factory.newConfTree(1, 0, 0)
@@ -71,7 +67,7 @@
assert ops.size() == 1
ContainerRequestOperation operation = (ContainerRequestOperation) ops[0]
Resource requirements = operation.request.capability
- assert requirements.memory == RM_MAX_RAM
+ assert requirements.memory == MockAppState.RM_MAX_RAM
assert requirements.virtualCores == 2
}
@@ -89,7 +85,7 @@
ContainerRequestOperation operation = (ContainerRequestOperation) ops[0]
Resource requirements = operation.request.capability
assert requirements.memory == 512
- assert requirements.virtualCores == RM_MAX_CORES
+ assert requirements.virtualCores == MockAppState.RM_MAX_CORES
}
@Test
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockLabelledAAPlacement.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockLabelledAAPlacement.groovy
new file mode 100644
index 0000000..f0fed95
--- /dev/null
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockLabelledAAPlacement.groovy
@@ -0,0 +1,139 @@
+/*
+ * 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.slider.server.appmaster.model.appstate
+
+import groovy.transform.CompileStatic
+import groovy.util.logging.Slf4j
+import org.apache.hadoop.yarn.api.records.Container
+import org.apache.hadoop.yarn.api.records.NodeState
+import org.apache.slider.server.appmaster.model.mock.MockNodeReport
+import org.apache.slider.server.appmaster.model.mock.MockRoles
+import org.apache.slider.server.appmaster.model.mock.MockYarnEngine
+import org.apache.slider.server.appmaster.operations.AbstractRMOperation
+import org.apache.slider.server.appmaster.state.AppState
+import org.junit.Test
+
+/**
+ * Test Anti-affine placement
+ */
+@CompileStatic
+@Slf4j
+class TestMockLabelledAAPlacement extends BaseMockAppStateAATest
+ implements MockRoles {
+
+ private int NODES = 3
+ private int GPU_NODES = 2
+ private String HOST0 = "00000000"
+ private String HOST1 = "00000001"
+
+
+ @Override
+ void setup() {
+ super.setup()
+ // node 1 is GPU
+
+ updateNodes(new MockNodeReport(HOST0, NodeState.RUNNING, LABEL_GPU))
+ updateNodes(new MockNodeReport(HOST1, NodeState.RUNNING, LABEL_GPU))
+ }
+
+ @Override
+ MockYarnEngine createYarnEngine() {
+ new MockYarnEngine(NODES, 8)
+ }
+
+ void assertAllContainersAA() {
+ assertAllContainersAA(gpuRole.key)
+ }
+
+ /**
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void testAskForTooMany() throws Throwable {
+
+ describe("Ask for 1 more than the no of available nodes;" +
+ " expect the final request to be unsatisfied until the cluster changes size")
+ //more than expected
+ int size = GPU_NODES
+ gpuRole.desired = size + 1
+
+ List<AbstractRMOperation > operations = appState.reviewRequestAndReleaseNodes()
+ assert gpuRole.AARequestOutstanding
+
+ assert gpuRole.pendingAntiAffineRequests == size
+ for (int i = 0; i < size; i++) {
+ def iter = "Iteration $i role = $aaRole"
+ describe iter
+ List<AbstractRMOperation > operationsOut = []
+
+ def roleInstances = submitOperations(operations, [], operationsOut)
+ // one instance per request
+ assert 1 == roleInstances.size()
+ appState.onNodeManagerContainerStarted(roleInstances[0].containerId)
+ assertAllContainersAA()
+ // there should be none left
+ log.debug(nodeInformationSnapshotAsString())
+ operations = operationsOut
+ if (i + 1 < size) {
+ assert operations.size() == 2
+ } else {
+ assert operations.size() == 1
+ }
+ }
+ // expect an outstanding AA request to be unsatisfied
+ assert gpuRole.actual < gpuRole.desired
+ assert !gpuRole.requested
+ assert !gpuRole.AARequestOutstanding
+ List<Container> allocatedContainers = engine.execute(operations, [])
+ assert 0 == allocatedContainers.size()
+ // in a review now, no more requests can be generated, as there is no space for AA placements,
+ // even though there is cluster capacity
+ assert 0 == appState.reviewRequestAndReleaseNodes().size()
+
+ // switch node 2 into being labelled
+ def outcome = updateNodes(new MockNodeReport("00000002", NodeState.RUNNING, "gpu"))
+
+ assert cloneNodemap().size() == NODES
+ assert outcome.clusterChanged
+ // no active calls to empty
+ assert outcome.operations.empty
+ assert 1 == appState.reviewRequestAndReleaseNodes().size()
+ }
+
+ protected AppState.NodeUpdatedOutcome addNewNode() {
+ updateNodes(new MockNodeReport("00000004", NodeState.RUNNING, "gpu"))
+ }
+
+ @Test
+ public void testClusterSizeChangesDuringRequestSequence() throws Throwable {
+ describe("Change the cluster size where the cluster size changes during a test sequence.")
+ gpuRole.desired = GPU_NODES + 1
+ List<AbstractRMOperation> operations = appState.reviewRequestAndReleaseNodes()
+ assert gpuRole.AARequestOutstanding
+ assert GPU_NODES == gpuRole.pendingAntiAffineRequests
+ def outcome = addNewNode()
+ assert outcome.clusterChanged
+ // one call to cancel
+ assert 1 == outcome.operations.size()
+ // and on a review, one more to rebuild
+ assert 1 == appState.reviewRequestAndReleaseNodes().size()
+ }
+
+}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryAA.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryAA.groovy
new file mode 100644
index 0000000..db84b0b
--- /dev/null
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryAA.groovy
@@ -0,0 +1,254 @@
+/*
+ * 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.slider.server.appmaster.model.history
+
+import groovy.util.logging.Slf4j
+import org.apache.hadoop.yarn.api.records.NodeReport
+import org.apache.hadoop.yarn.api.records.NodeState
+import org.apache.slider.api.proto.Messages
+import org.apache.slider.api.proto.RestTypeMarshalling
+import org.apache.slider.api.types.NodeInformation
+import org.apache.slider.api.types.NodeInformationList
+import org.apache.slider.server.appmaster.model.mock.MockFactory
+import org.apache.slider.server.appmaster.model.mock.MockNodeReport
+import org.apache.slider.server.appmaster.model.mock.MockRoleHistory
+import org.apache.slider.server.appmaster.state.NodeEntry
+import org.apache.slider.server.appmaster.state.NodeInstance
+import org.apache.slider.server.appmaster.state.NodeMap
+import org.apache.slider.server.appmaster.state.RoleHistory
+import org.apache.slider.test.SliderTestBase
+import org.junit.Test
+
+/**
+ * Test anti-affine
+ */
+//@CompileStatic
+@Slf4j
+class TestRoleHistoryAA extends SliderTestBase {
+
+ List<String> hostnames = ["1", "2", "3"]
+ NodeMap nodeMap, gpuNodeMap
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
+
+
+ @Override
+ void setup() {
+ super.setup()
+ nodeMap = createNodeMap(hostnames, NodeState.RUNNING)
+ gpuNodeMap = createNodeMap(hostnames, NodeState.RUNNING, "GPU")
+ }
+
+ @Test
+ public void testFindNodesInFullCluster() throws Throwable {
+ // all three will surface at first
+ verifyResultSize(3, nodeMap.findAllNodesForRole(1, ""))
+ }
+
+ @Test
+ public void testFindNodesInUnhealthyCluster() throws Throwable {
+ // all three will surface at first
+ markNodeOneUnhealthy()
+ verifyResultSize(2, nodeMap.findAllNodesForRole(1, ""))
+ }
+
+ public boolean markNodeOneUnhealthy() {
+ return setNodeState(nodeMap.get("1"), NodeState.UNHEALTHY)
+ }
+
+ protected boolean setNodeState(NodeInstance node, NodeState state) {
+ node.updateNode(new MockNodeReport(node.hostname, state))
+ }
+
+ @Test
+ public void testFindNoNodesWrongLabel() throws Throwable {
+ // all three will surface at first
+ verifyResultSize(0, nodeMap.findAllNodesForRole(1, "GPU"))
+ }
+
+ @Test
+ public void testFindSomeNodesSomeLabel() throws Throwable {
+ // all three will surface at first
+ update(nodeMap, [new MockNodeReport("1", NodeState.RUNNING, "GPU")])
+ def gpuNodes = nodeMap.findAllNodesForRole(1, "GPU")
+ verifyResultSize(1, gpuNodes)
+ def instance = gpuNodes[0]
+ instance.getOrCreate(1).onStarting()
+ assert !instance.canHost(1, "GPU")
+ assert !instance.canHost(1, "")
+ verifyResultSize(0, nodeMap.findAllNodesForRole(1, "GPU"))
+
+ }
+
+ @Test
+ public void testFindNoNodesRightLabel() throws Throwable {
+ // all three will surface at first
+ verifyResultSize(3, gpuNodeMap.findAllNodesForRole(1, "GPU"))
+ }
+
+ @Test
+ public void testFindNoNodesNoLabel() throws Throwable {
+ // all three will surface at first
+ verifyResultSize(3, gpuNodeMap.findAllNodesForRole(1, ""))
+ }
+
+ @Test
+ public void testFindNoNodesClusterRequested() throws Throwable {
+ // all three will surface at first
+ applyToNodeEntries(nodeMap) {
+ NodeEntry it -> it.request()
+ }
+ assertNoAvailableNodes(1)
+ }
+
+ @Test
+ public void testFindNoNodesClusterBusy() throws Throwable {
+ // all three will surface at first
+ applyToNodeEntries(nodeMap) {
+ NodeEntry it -> it.request()
+ }
+ assertNoAvailableNodes(1)
+ }
+
+ /**
+ * Tag all nodes as starting, then walk one through a bit
+ * more of its lifecycle
+ */
+ @Test
+ public void testFindNoNodesLifecycle() throws Throwable {
+ // all three will surface at first
+ applyToNodeEntries(nodeMap) {
+ NodeEntry it -> it.onStarting()
+ }
+ assertNoAvailableNodes(1)
+
+ // walk one of the nodes through the lifecycle
+ def node1 = nodeMap.get("1")
+ assert !node1.canHost(1,"")
+ node1.get(1).onStartCompleted()
+ assert !node1.canHost(1,"")
+ assertNoAvailableNodes()
+ node1.get(1).release()
+ assert node1.canHost(1,"")
+ def list2 = verifyResultSize(1, nodeMap.findAllNodesForRole(1, ""))
+ assert list2[0].hostname == "1"
+
+ // now tag that node as unhealthy and expect it to go away
+ markNodeOneUnhealthy()
+ assertNoAvailableNodes()
+ }
+
+ @Test
+ public void testRolesIndependent() throws Throwable {
+ def node1 = nodeMap.get("1")
+ def role1 = node1.getOrCreate(1)
+ def role2 = node1.getOrCreate(2)
+ nodeMap.values().each {
+ it.updateNode(new MockNodeReport("0", NodeState.UNHEALTHY))
+ }
+ assertNoAvailableNodes(1)
+ assertNoAvailableNodes(2)
+ assert setNodeState(node1, NodeState.RUNNING)
+ // tag role 1 as busy
+ role1.onStarting()
+ assertNoAvailableNodes(1)
+
+ verifyResultSize(1, nodeMap.findAllNodesForRole(2, ""))
+ assert node1.canHost(2,"")
+ }
+
+ @Test
+ public void testNodeEntryAvailablity() throws Throwable {
+ def entry = new NodeEntry(1)
+ assert entry.available
+ entry.onStarting()
+ assert !entry.available
+ entry.onStartCompleted()
+ assert !entry.available
+ entry.release()
+ assert entry.available
+ entry.onStarting()
+ assert !entry.available
+ entry.onStartFailed()
+ assert entry.available
+ }
+
+ @Test
+ public void testNodeInstanceSerialization() throws Throwable {
+ def rh2 = new MockRoleHistory([])
+ rh2.getOrCreateNodeInstance("localhost")
+ def instance = rh2.getOrCreateNodeInstance("localhost")
+ instance.getOrCreate(1).onStartCompleted()
+ def Map<Integer, String> naming = [(1):"manager"]
+ def ni = instance.serialize(naming)
+ assert 1 == ni.entries["manager"].live
+ def ni2 = rh2.getNodeInformation("localhost", naming)
+ assert 1 == ni2.entries["manager"].live
+ def info = rh2.getNodeInformationSnapshot(naming)
+ assert 1 == info["localhost"].entries["manager"].live
+ def nil = new NodeInformationList(info.values());
+ assert 1 == nil[0].entries["manager"].live
+
+ def nodeInformationProto = RestTypeMarshalling.marshall(ni)
+ def entryProto = nodeInformationProto.getEntries(0)
+ assert entryProto && entryProto.getPriority() == 1
+ def unmarshalled = RestTypeMarshalling.unmarshall(nodeInformationProto)
+ assert unmarshalled.hostname == ni.hostname
+ assert unmarshalled.entries.keySet().containsAll(ni.entries.keySet())
+
+ }
+
+ @Test
+ public void testBuildRolenames() throws Throwable {
+
+ }
+ public List<NodeInstance> assertNoAvailableNodes(int role = 1, String label = "") {
+ return verifyResultSize(0, nodeMap.findAllNodesForRole(role, label))
+ }
+
+ List<NodeInstance> verifyResultSize(int size, List<NodeInstance> list) {
+ if (list.size() != size) {
+ list.each { log.error(it.toFullString()) }
+ }
+ assert size == list.size()
+ list
+ }
+
+ def applyToNodeEntries(Collection<NodeInstance> list, Closure cl) {
+ list.each { it -> cl(it.getOrCreate(1)) }
+ }
+
+ def applyToNodeEntries(NodeMap nodeMap, Closure cl) {
+ applyToNodeEntries(nodeMap.values(), cl)
+ }
+
+ def NodeMap createNodeMap(List<NodeReport> nodeReports) {
+ NodeMap nodeMap = new NodeMap(1)
+ update(nodeMap, nodeReports)
+ nodeMap
+ }
+
+ protected boolean update(NodeMap nodeMap, List<NodeReport> nodeReports) {
+ nodeMap.buildOrUpdate(nodeReports)
+ }
+
+ def NodeMap createNodeMap(List<String> hosts, NodeState state,
+ String label = "") {
+ createNodeMap(MockNodeReport.createInstances(hosts, state, label))
+ }
+}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryContainerEvents.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryContainerEvents.groovy
index fa10145..ca42546 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryContainerEvents.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryContainerEvents.groovy
@@ -28,13 +28,11 @@
import org.apache.hadoop.yarn.api.records.Resource
import org.apache.hadoop.yarn.client.api.AMRMClient
import org.apache.slider.api.ResourceKeys
-import org.apache.slider.providers.ProviderRole
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
import org.apache.slider.server.appmaster.model.mock.MockContainer
import org.apache.slider.server.appmaster.model.mock.MockFactory
import org.apache.slider.server.appmaster.model.mock.MockNodeId
import org.apache.slider.server.appmaster.state.*
-import org.junit.Before
import org.junit.Test
/**
@@ -60,15 +58,20 @@
String roleName = "test"
List<NodeInstance> nodes = [age2Active2, age2Active0, age4Active1, age1Active4, age3Active0]
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory
Resource resource
- @Before
- public void setupRH() {
- roleHistory.onStart(fs, historyPath)
+ AMRMClient.ContainerRequest requestContainer(RoleStatus roleStatus) {
+ roleHistory.requestContainerForRole(roleStatus).issuedRequest
+ }
+
+ @Override
+ void setup() {
+ super.setup()
+ roleHistory = appState.roleHistory
roleHistory.insert(nodes)
- roleHistory.buildAvailableNodeLists();
+ roleHistory.buildRecentNodeLists();
resource = Resource.newInstance(ResourceKeys.DEF_YARN_CORES,
ResourceKeys.DEF_YARN_MEMORY);
}
@@ -76,11 +79,10 @@
@Test
public void testFindAndCreate() throws Throwable {
int role = 0
- ProviderRole provRole = new ProviderRole(roleName, role)
- RoleStatus roleStatus = new RoleStatus(provRole)
+ RoleStatus roleStatus = appState.lookupRoleStatus(role)
AMRMClient.ContainerRequest request =
- roleHistory.requestNode(roleStatus, resource);
+ requestContainer(roleStatus);
List<String> nodes = request.getNodes()
assert nodes != null
@@ -113,14 +115,13 @@
@Test
public void testCreateAndRelease() throws Throwable {
int role = 1
- ProviderRole provRole = new ProviderRole(roleName, role)
- RoleStatus roleStatus = new RoleStatus(provRole)
+ RoleStatus roleStatus = appState.lookupRoleStatus(role)
//verify it is empty
assert roleHistory.listActiveNodes(role).empty
AMRMClient.ContainerRequest request =
- roleHistory.requestNode(roleStatus, resource);
+ requestContainer(roleStatus);
assert request.nodes == null
@@ -169,7 +170,7 @@
// ask for a container and expect to get the recently released one
AMRMClient.ContainerRequest request2 =
- roleHistory.requestNode(roleStatus, resource);
+ requestContainer(roleStatus);
List<String> nodes2 = request2.nodes
assert nodes2 != null
@@ -205,11 +206,10 @@
@Test
public void testStartFailed() throws Throwable {
int role = 0
- ProviderRole provRole = new ProviderRole(roleName, role)
- RoleStatus roleStatus = new RoleStatus(provRole)
+ RoleStatus roleStatus = appState.lookupRoleStatus(role)
AMRMClient.ContainerRequest request =
- roleHistory.requestNode(roleStatus, resource);
+ requestContainer(roleStatus);
String hostname = request.getNodes()[0]
assert hostname == age3Active0.hostname
@@ -239,10 +239,10 @@
@Test
public void testStartFailedWithoutWarning() throws Throwable {
int role = 0
- ProviderRole provRole = new ProviderRole(roleName, role)
- RoleStatus roleStatus = new RoleStatus(provRole)
+ RoleStatus roleStatus = appState.lookupRoleStatus(role)
+
AMRMClient.ContainerRequest request =
- roleHistory.requestNode(roleStatus, resource);
+ requestContainer(roleStatus);
String hostname = request.getNodes()[0]
assert hostname == age3Active0.hostname
@@ -270,10 +270,10 @@
describe("fail a container without declaring it as starting")
int role = 0
- ProviderRole provRole = new ProviderRole(roleName, role)
- RoleStatus roleStatus = new RoleStatus(provRole)
+ RoleStatus roleStatus = appState.lookupRoleStatus(role)
+
AMRMClient.ContainerRequest request =
- roleHistory.requestNode(roleStatus, resource);
+ requestContainer(roleStatus);
String hostname = request.getNodes()[0]
assert hostname == age3Active0.hostname
@@ -309,10 +309,10 @@
public void testContainerFailedWithoutWarning() throws Throwable {
describe( "fail a container without declaring it as starting")
int role = 0
- ProviderRole provRole = new ProviderRole(roleName, role)
- RoleStatus roleStatus = new RoleStatus(provRole)
+ RoleStatus roleStatus = appState.lookupRoleStatus(role)
+
AMRMClient.ContainerRequest request =
- roleHistory.requestNode(roleStatus, resource);
+ requestContainer(roleStatus);
String hostname = request.getNodes()[0]
assert hostname == age3Active0.hostname
@@ -342,10 +342,10 @@
public void testAllocationListPrep() throws Throwable {
describe("test prepareAllocationList")
int role = 0
- ProviderRole provRole = new ProviderRole(roleName, role)
- RoleStatus roleStatus = new RoleStatus(provRole)
+ RoleStatus roleStatus = appState.lookupRoleStatus(role)
+
AMRMClient.ContainerRequest request =
- roleHistory.requestNode(roleStatus, resource);
+ requestContainer(roleStatus);
String hostname = request.getNodes()[0]
assert hostname == age3Active0.hostname
@@ -374,9 +374,10 @@
describe("fail a node")
int role = 0
- ProviderRole provRole = new ProviderRole(roleName, role)
- RoleStatus roleStatus = new RoleStatus(provRole)
- AMRMClient.ContainerRequest request = roleHistory.requestNode(roleStatus, resource);
+ RoleStatus roleStatus = appState.lookupRoleStatus(role)
+
+ AMRMClient.ContainerRequest request =
+ roleHistory.requestContainerForRole(roleStatus).issuedRequest;
String hostname = request.getNodes()[0]
assert age3Active0.hostname == hostname
@@ -399,7 +400,7 @@
int startSize = nodemap.size()
// now send a list of updated (failed) nodes event
- List<NodeReport> nodesUpdated = new ArrayList<NodeReport>();
+ List<NodeReport> nodesUpdated = new ArrayList<>();
NodeReport nodeReport = NodeReport.newInstance(
NodeId.newInstance(hostname, 0),
NodeState.LOST,
@@ -412,7 +413,7 @@
// as even unused nodes are added to the list, we expect the map size to be >1
assert startSize <= endSize
assert nodemap[hostname] != null
- assert roleHistory.cloneFailedNodes().contains(hostname)
+ assert !nodemap[hostname].online
// add a failure of a node we've never head of
def newhost = "newhost"
@@ -425,9 +426,8 @@
roleHistory.onNodesUpdated(nodesUpdated)
def nodemap2 = roleHistory.cloneNodemap()
- assert nodemap2.size() > endSize
- assert roleHistory.cloneFailedNodes().contains(newhost)
assert nodemap2[newhost]
+ assert !nodemap2[newhost].online
}
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryFindNodesForNewInstances.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryFindNodesForNewInstances.groovy
index 79d23e5..f36724e 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryFindNodesForNewInstances.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryFindNodesForNewInstances.groovy
@@ -23,6 +23,7 @@
import org.apache.slider.providers.ProviderRole
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
import org.apache.slider.server.appmaster.model.mock.MockFactory
+import org.apache.slider.server.appmaster.model.mock.MockRoleHistory
import org.apache.slider.server.appmaster.state.ContainerOutcome
import org.apache.slider.server.appmaster.state.NodeInstance
import org.apache.slider.server.appmaster.state.RoleHistory
@@ -32,10 +33,8 @@
/**
* Testing finding nodes for new instances.
- * These tests validate the (currently) suboptimal
- * behavior of not listing any known nodes when there
- * are none in the available list -even if there are nodes
- * known to be not running live instances in the cluster.
+ *
+ * This stresses the non-AA codepath
*/
@Slf4j
@CompileStatic
@@ -54,7 +53,7 @@
NodeInstance empty = new NodeInstance("empty", MockFactory.ROLE_COUNT)
List<NodeInstance> nodes = [age2Active2, age2Active0, age4Active1, age1Active4, age3Active0]
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
String roleName = "test"
RoleStatus roleStat = new RoleStatus(new ProviderRole(roleName, 0))
@@ -63,14 +62,14 @@
@Before
public void setupNodeMap() {
roleHistory.insert(nodes)
- roleHistory.buildAvailableNodeLists();
+ roleHistory.buildRecentNodeLists();
}
public List<NodeInstance> findNodes(int count, RoleStatus roleStatus = roleStat) {
List < NodeInstance > found = [];
for (int i = 0; i < count; i++) {
- NodeInstance f = roleHistory.findNodeForNewInstance(roleStatus)
+ NodeInstance f = roleHistory.findRecentNodeForNewInstance(roleStatus)
if (f) {
found << f
};
@@ -80,17 +79,17 @@
@Test
public void testFind1NodeR0() throws Throwable {
- NodeInstance found = roleHistory.findNodeForNewInstance(roleStat)
+ NodeInstance found = roleHistory.findRecentNodeForNewInstance(roleStat)
log.info("found: $found")
assert [age3Active0].contains(found)
}
@Test
public void testFind2NodeR0() throws Throwable {
- NodeInstance found = roleHistory.findNodeForNewInstance(roleStat)
+ NodeInstance found = roleHistory.findRecentNodeForNewInstance(roleStat)
log.info("found: $found")
assert [age2Active0, age3Active0].contains(found)
- NodeInstance found2 = roleHistory.findNodeForNewInstance(roleStat)
+ NodeInstance found2 = roleHistory.findRecentNodeForNewInstance(roleStat)
log.info("found: $found2")
assert [age2Active0, age3Active0].contains(found2)
assert found != found2;
@@ -99,7 +98,7 @@
@Test
public void testFind3NodeR0ReturnsNull() throws Throwable {
assert 2== findNodes(2).size()
- NodeInstance found = roleHistory.findNodeForNewInstance(roleStat)
+ NodeInstance found = roleHistory.findRecentNodeForNewInstance(roleStat)
assert found == null;
}
@@ -123,7 +122,7 @@
assert age2Active0.getActiveRoleInstances(0) != 0
age3Active0.get(0).onStartCompleted()
assert age3Active0.getActiveRoleInstances(0) != 0
- NodeInstance found = roleHistory.findNodeForNewInstance(roleStat)
+ NodeInstance found = roleHistory.findRecentNodeForNewInstance(roleStat)
log.info(found ?.toFullString())
assert found == null
}
@@ -147,7 +146,7 @@
assert age2Active0.exceedsFailureThreshold(roleStat)
// get the role & expect age3 to be picked up, even though it is older
- NodeInstance found = roleHistory.findNodeForNewInstance(roleStat)
+ NodeInstance found = roleHistory.findRecentNodeForNewInstance(roleStat)
assert age3Active0.is(found)
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryNIComparators.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryNIComparators.groovy
index b26b2f0..bcd8f9f 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryNIComparators.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryNIComparators.groovy
@@ -18,6 +18,7 @@
package org.apache.slider.server.appmaster.model.history
+import groovy.transform.CompileStatic
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
import org.apache.slider.server.appmaster.model.mock.MockFactory
import org.apache.slider.server.appmaster.state.NodeInstance
@@ -27,17 +28,20 @@
/**
* Unit test to verify the comparators sort as expected
*/
+@CompileStatic
class TestRoleHistoryNIComparators extends BaseMockAppStateTest {
- NodeInstance age1Active4 = nodeInstance(1000, 4, 0, 0)
- NodeInstance age2Active2 = nodeInstance(1001, 2, 0, 0)
- NodeInstance age3Active0 = nodeInstance(1002, 0, 0, 0)
- NodeInstance age4Active1 = nodeInstance(1005, 0, 0, 0)
+ NodeInstance age1Active4 = nodeInstance(1001, 4, 0, 0)
+ NodeInstance age2Active2 = nodeInstance(1002, 2, 0, 0)
+ NodeInstance age3Active0 = nodeInstance(1003, 0, 0, 0)
+ NodeInstance age4Active1 = nodeInstance(1004, 1, 0, 0)
NodeInstance empty = new NodeInstance("empty", MockFactory.ROLE_COUNT)
NodeInstance age6failing = nodeInstance(1006, 0, 0, 0)
- NodeInstance age1failing = nodeInstance(1000, 0, 0, 0)
+ NodeInstance age1failing = nodeInstance(1001, 0, 0, 0)
List<NodeInstance> nodes = [age2Active2, age4Active1, age1Active4, age3Active0]
+ List<NodeInstance> nodesPlusEmpty = [age2Active2, age4Active1, age1Active4, age3Active0, empty]
+ List<NodeInstance> allnodes = [age6failing, age2Active2, age4Active1, age1Active4, age3Active0, age1failing]
@Before
public void setup() {
@@ -51,43 +55,48 @@
}
@Test
- public void testNewerThan() throws Throwable {
-
+ public void testPreferred() throws Throwable {
Collections.sort(nodes, new NodeInstance.Preferred(0))
- assertListEquals(nodes,
- [age4Active1, age3Active0, age2Active2, age1Active4])
+ assertListEquals(nodes, [age4Active1, age3Active0, age2Active2, age1Active4])
+ }
+
+ /**
+ * The preferred sort still includes failures; up to next phase in process
+ * to handle that
+ * @throws Throwable
+ */
+ @Test
+ public void testPreferredWithFailures() throws Throwable {
+ Collections.sort(allnodes, new NodeInstance.Preferred(0))
+ assert allnodes[0] == age6failing
+ assert allnodes[1] == age4Active1
}
@Test
- public void testFailureCountFirst() throws Throwable {
+ public void testPreferredComparatorDowngradesFailures() throws Throwable {
def preferred = new NodeInstance.Preferred(0)
assert preferred.compare(age6failing, age1failing) == -1
assert preferred.compare(age1failing, age6failing) == 1
}
-
+
@Test
public void testNewerThanNoRole() throws Throwable {
-
- nodes << empty
- Collections.sort(nodes, new NodeInstance.Preferred(0))
- assertListEquals(nodes,
- [age4Active1, age3Active0, age2Active2, age1Active4, empty])
+ Collections.sort(nodesPlusEmpty, new NodeInstance.Preferred(0))
+ assertListEquals(nodesPlusEmpty, [age4Active1, age3Active0, age2Active2, age1Active4, empty])
}
@Test
public void testMoreActiveThan() throws Throwable {
Collections.sort(nodes, new NodeInstance.MoreActiveThan(0))
- assertListEquals(nodes,
- [age1Active4, age2Active2, age4Active1, age3Active0],)
+ assertListEquals(nodes, [age1Active4, age2Active2, age4Active1, age3Active0])
}
@Test
public void testMoreActiveThanEmpty() throws Throwable {
- nodes << empty
- Collections.sort(nodes, new NodeInstance.MoreActiveThan(0))
- assertListEquals(nodes,
- [age1Active4, age2Active2, age4Active1, age3Active0, empty])
+
+ Collections.sort(nodesPlusEmpty, new NodeInstance.MoreActiveThan(0))
+ assertListEquals(nodesPlusEmpty, [age1Active4, age2Active2, age4Active1, age3Active0, empty])
}
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryOutstandingRequestTracker.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryOutstandingRequestTracker.groovy
index 653af84..6969b38 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryOutstandingRequestTracker.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryOutstandingRequestTracker.groovy
@@ -27,6 +27,7 @@
import org.apache.slider.server.appmaster.operations.AbstractRMOperation
import org.apache.slider.server.appmaster.operations.CancelSingleRequest
import org.apache.slider.server.appmaster.operations.ContainerRequestOperation
+import org.apache.slider.server.appmaster.state.AppStateBindingInfo
import org.apache.slider.server.appmaster.state.ContainerAllocationOutcome
import org.apache.slider.server.appmaster.state.ContainerPriority
import org.apache.slider.server.appmaster.state.NodeInstance
@@ -35,16 +36,28 @@
import org.apache.slider.server.appmaster.state.RoleStatus
import org.junit.Test
-class TestRoleHistoryOutstandingRequestTracker extends BaseMockAppStateTest {
+class TestRoleHistoryOutstandingRequestTracker extends BaseMockAppStateTest {
+ public static final String WORKERS_LABEL = "workers"
NodeInstance host1 = new NodeInstance("host1", 3)
NodeInstance host2 = new NodeInstance("host2", 3)
+ def resource = factory.newResource(48, 1)
OutstandingRequestTracker tracker = new OutstandingRequestTracker()
-
+
+ public static final ProviderRole WORKER = new ProviderRole(
+ "worker",
+ 5,
+ PlacementPolicy.NONE,
+ 2,
+ 1,
+ WORKERS_LABEL)
+
@Override
- String getTestName() {
- return "TestOutstandingRequestTracker"
+ AppStateBindingInfo buildBindingInfo() {
+ def bindingInfo = super.buildBindingInfo()
+ bindingInfo.roles = [ WORKER ] + bindingInfo.roles
+ bindingInfo
}
@Test
@@ -57,10 +70,16 @@
@Test
public void testAddCompleteEntry() throws Throwable {
- tracker.newRequest(host1, 0)
- tracker.newRequest(host2, 0)
- tracker.newRequest(host1, 1)
- assert tracker.onContainerAllocated(1, "host1", null).outcome == ContainerAllocationOutcome.Placed
+ def req1 = tracker.newRequest(host1, 0)
+ req1.buildContainerRequest(resource, role0Status, 0)
+
+ tracker.newRequest(host2, 0).buildContainerRequest(resource, role0Status, 0)
+ tracker.newRequest(host1, 1).buildContainerRequest(resource, role0Status, 0)
+
+ def allocation = tracker.onContainerAllocated(1, "host1", null)
+ assert allocation.outcome == ContainerAllocationOutcome.Placed
+ assert allocation.operations[0] instanceof CancelSingleRequest
+
assert !tracker.lookupPlacedRequest(1, "host1")
assert tracker.lookupPlacedRequest(0, "host1")
}
@@ -80,46 +99,40 @@
@Test
public void testRemoveOpenRequestUnissued() throws Throwable {
def req1 = tracker.newRequest(null, 0)
+ req1.buildContainerRequest(resource, role0Status, 0)
assert tracker.listOpenRequests().size() == 1
- def c1 = factory.newContainer()
- c1.setPriority(new MockPriority(0))
+ def c1 = factory.newContainer(null, new MockPriority(0))
+ c1.resource = resource
- def resource = factory.newResource()
- resource.virtualCores=1
- resource.memory = 48;
- c1.setResource(resource)
- ContainerAllocationOutcome outcome = tracker.onContainerAllocated(0, "host1", c1).outcome
+ def allocation = tracker.onContainerAllocated(0, "host1", c1)
+ ContainerAllocationOutcome outcome = allocation.outcome
assert outcome == ContainerAllocationOutcome.Unallocated
+ assert allocation.operations.empty
assert tracker.listOpenRequests().size() == 1
}
@Test
public void testIssuedOpenRequest() throws Throwable {
def req1 = tracker.newRequest(null, 0)
- def resource = factory.newResource()
- resource.virtualCores = 1
- resource.memory = 48;
- def yarnRequest = req1.buildContainerRequest(resource, role0Status, 0, "")
+ req1.buildContainerRequest(resource, role0Status, 0)
assert tracker.listOpenRequests().size() == 1
- def c1 = factory.newContainer()
-
- def nodeId = factory.newNodeId()
- c1.nodeId = nodeId
- nodeId.host ="hostname-1"
def pri = ContainerPriority.buildPriority(0, false)
assert pri > 0
- c1.setPriority(new MockPriority(pri))
+ def nodeId = factory.newNodeId("hostname-1")
+ def c1 = factory.newContainer(nodeId, new MockPriority(pri))
- c1.setResource(resource)
+ c1.resource = resource
def issued = req1.issuedRequest
assert issued.capability == resource
- assert issued.priority.priority == c1.getPriority().getPriority()
+ assert issued.priority.priority == c1.priority.priority
assert req1.resourceRequirementsMatch(resource)
def allocation = tracker.onContainerAllocated(0, nodeId.host, c1)
assert tracker.listOpenRequests().size() == 0
+ assert allocation.operations[0] instanceof CancelSingleRequest
+
assert allocation.outcome == ContainerAllocationOutcome.Open
assert allocation.origin.is(req1)
}
@@ -146,7 +159,7 @@
// first request: default placement
assert role0Status.placementPolicy == PlacementPolicy.DEFAULT;
final def (res0, outstanding0) = newRequest(role0Status)
- final def initialRequest = outstanding0.buildContainerRequest(res0, role0Status, 0, null)
+ final def initialRequest = outstanding0.buildContainerRequest(res0, role0Status, 0)
assert outstanding0.issuedRequest != null;
assert outstanding0.located
assert !outstanding0.escalated
@@ -157,7 +170,6 @@
// process skips entries which are in the list but have not been issued.
// ...which can be a race condition between request issuance & escalation.
// (not one observed outside test authoring, but retained for completeness)
- assert role2Status.placementPolicy == PlacementPolicy.ANTI_AFFINITY_REQUIRED
def (res2, outstanding2) = newRequest(role2Status)
// simulate some time escalation of role 1 MUST now be triggered
@@ -182,7 +194,7 @@
// build that second request from an anti-affine entry
// these get placed as well
now += interval
- final def containerReq2 = outstanding2.buildContainerRequest(res2, role2Status, now, null)
+ final def containerReq2 = outstanding2.buildContainerRequest(res2, role2Status, now)
// escalate a little bit more
final List<AbstractRMOperation> escalations2 = tracker.escalateOutstandingRequests(now)
// and expect no new entries
@@ -223,18 +235,19 @@
resource.virtualCores = 1
resource.memory = 48;
- def label = "workers"
+ def workerRole = lookupRole(WORKER.name)
// initial request
- def yarnRequest = req1.buildContainerRequest(resource, role0Status, 0, label)
+ def yarnRequest = req1.buildContainerRequest(resource, workerRole, 0)
assert (yarnRequest.nodeLabelExpression == null)
assert (!yarnRequest.relaxLocality)
+ // escalation
def yarnRequest2 = req1.escalate()
- assert (yarnRequest2.nodeLabelExpression == label)
+ assert (yarnRequest2.nodeLabelExpression == WORKERS_LABEL)
assert (yarnRequest2.relaxLocality)
}
/**
- * If the placement doesnt include a lablel, then the escalation request
+ * If the placement doesnt include a label, then the escalation request
* retains the node list, but sets relaxLocality==true
* @throws Throwable
*/
@@ -246,17 +259,44 @@
resource.virtualCores = 1
resource.memory = 48;
- def label = null
// initial request
- def yarnRequest = req1.buildContainerRequest(resource, role0Status, 0, label)
- assert (yarnRequest.nodes != null)
- assert (yarnRequest.nodeLabelExpression == null)
- assert (!yarnRequest.relaxLocality)
+ def yarnRequest = req1.buildContainerRequest(resource, role0Status, 0)
+ assert yarnRequest.nodes != null
+ assert !yarnRequest.nodeLabelExpression
+ assert !yarnRequest.relaxLocality
def yarnRequest2 = req1.escalate()
- assert (yarnRequest2.nodes != null)
- assert (yarnRequest2.relaxLocality)
+ assert yarnRequest2.nodes != null
+ assert yarnRequest2.relaxLocality
}
+ @Test(expected = IllegalArgumentException)
+ public void testAARequestNoNodes() throws Throwable {
+ tracker.newAARequest(role0Status.key, [], "")
+ }
+
+ @Test
+ public void testAARequest() throws Throwable {
+ def role0 = role0Status.key
+ OutstandingRequest request = tracker.newAARequest(role0, [host1], "")
+ assert host1.hostname == request.hostname
+ assert !request.located
+ }
+
+ @Test
+ public void testAARequestPair() throws Throwable {
+ def role0 = role0Status.key
+ OutstandingRequest request = tracker.newAARequest(role0, [host1, host2], "")
+ assert host1.hostname == request.hostname
+ assert !request.located
+ def yarnRequest = request.buildContainerRequest(
+ role0Status.copyResourceRequirements(new MockResource(0, 0)),
+ role0Status,
+ 0)
+ assert !yarnRequest.relaxLocality
+ assert !request.mayEscalate()
+
+ assert yarnRequest.nodes.size() == 2
+ }
/**
* Create a new request (always against host1)
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRW.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRW.groovy
index c81c686..72e4240 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRW.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRW.groovy
@@ -22,15 +22,15 @@
import groovy.util.logging.Slf4j
import org.apache.hadoop.fs.FSDataOutputStream
import org.apache.hadoop.fs.Path
+import org.apache.slider.api.ResourceKeys
import org.apache.slider.providers.PlacementPolicy
import org.apache.slider.providers.ProviderRole
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
import org.apache.slider.server.appmaster.model.mock.MockFactory
-import org.apache.slider.server.appmaster.model.mock.MockRoles
+import org.apache.slider.server.appmaster.model.mock.MockRoleHistory
import org.apache.slider.server.appmaster.state.NodeEntry
import org.apache.slider.server.appmaster.state.NodeInstance
import org.apache.slider.server.appmaster.state.RoleHistory
-import org.apache.slider.server.avro.LoadedRoleHistory
import org.apache.slider.server.avro.RoleHistoryWriter
import org.junit.Test
@@ -48,7 +48,8 @@
3,
PlacementPolicy.STRICT,
3,
- 3)
+ 3,
+ ResourceKeys.DEF_YARN_LABEL_EXPRESSION)
@Override
String getTestName() {
@@ -57,7 +58,7 @@
@Test
public void testWriteReadEmpty() throws Throwable {
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
roleHistory.onStart(fs, historyPath)
Path history = roleHistory.saveHistory(time++)
assert fs.isFile(history)
@@ -67,7 +68,7 @@
@Test
public void testWriteReadData() throws Throwable {
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
assert !roleHistory.onStart(fs, historyPath)
String addr = "localhost"
NodeInstance instance = roleHistory.getOrCreateNodeInstance(addr)
@@ -77,7 +78,7 @@
Path history = roleHistory.saveHistory(time++)
assert fs.isFile(history)
RoleHistoryWriter historyWriter = new RoleHistoryWriter();
- RoleHistory rh2 = new RoleHistory(MockFactory.ROLES)
+ RoleHistory rh2 = new MockRoleHistory(MockFactory.ROLES)
def loadedRoleHistory = historyWriter.read(fs, history)
@@ -92,7 +93,7 @@
@Test
public void testWriteReadActiveData() throws Throwable {
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
roleHistory.onStart(fs, historyPath)
String addr = "localhost"
String addr2 = "rack1server5"
@@ -117,7 +118,7 @@
describe("Loaded")
log.info("testWriteReadActiveData in $history")
RoleHistoryWriter historyWriter = new RoleHistoryWriter();
- RoleHistory rh2 = new RoleHistory(MockFactory.ROLES)
+ RoleHistory rh2 = new MockRoleHistory(MockFactory.ROLES)
def loadedRoleHistory = historyWriter.read(fs, history)
assert 3 == loadedRoleHistory.size()
rh2.rebuild(loadedRoleHistory)
@@ -136,16 +137,16 @@
assert rh2.thawedDataTime == savetime
// now start it
- rh2.buildAvailableNodeLists();
+ rh2.buildRecentNodeLists();
describe("starting")
rh2.dump();
- List<NodeInstance> available0 = rh2.cloneAvailableList(0)
+ List<NodeInstance> available0 = rh2.cloneRecentNodeList(0)
assert available0.size() == 1
NodeInstance entry = available0.get(0)
assert entry.hostname == "localhost"
assert entry == localhost
- List<NodeInstance> available1 = rh2.cloneAvailableList(1)
+ List<NodeInstance> available1 = rh2.cloneRecentNodeList(1)
assert available1.size() == 2
//and verify that even if last used was set, the save time is picked up
assert entry.get(1).lastUsed == roleHistory.saveTime
@@ -154,7 +155,7 @@
@Test
public void testWriteThaw() throws Throwable {
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
assert !roleHistory.onStart(fs, historyPath)
String addr = "localhost"
NodeInstance instance = roleHistory.getOrCreateNodeInstance(addr)
@@ -164,7 +165,7 @@
Path history = roleHistory.saveHistory(time++)
long savetime =roleHistory.saveTime;
assert fs.isFile(history)
- RoleHistory rh2 = new RoleHistory(MockFactory.ROLES)
+ RoleHistory rh2 = new MockRoleHistory(MockFactory.ROLES)
assert rh2.onStart(fs, historyPath)
NodeInstance ni2 = rh2.getExistingNodeInstance(addr)
assert ni2 != null
@@ -211,7 +212,7 @@
@Test
public void testSkipEmptyFileOnRead() throws Throwable {
describe "verify that empty histories are skipped on read; old histories purged"
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
roleHistory.onStart(fs, historyPath)
time = 0
Path oldhistory = roleHistory.saveHistory(time++)
@@ -226,7 +227,7 @@
RoleHistoryWriter historyWriter = new RoleHistoryWriter();
Path touched = touch(historyWriter, time++)
- RoleHistory rh2 = new RoleHistory(MockFactory.ROLES)
+ RoleHistory rh2 = new MockRoleHistory(MockFactory.ROLES)
assert rh2.onStart(fs, historyPath)
NodeInstance ni2 = rh2.getExistingNodeInstance(addr)
assert ni2 != null
@@ -240,7 +241,7 @@
@Test
public void testSkipBrokenFileOnRead() throws Throwable {
describe "verify that empty histories are skipped on read; old histories purged"
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
roleHistory.onStart(fs, historyPath)
time = 0
Path oldhistory = roleHistory.saveHistory(time++)
@@ -258,7 +259,7 @@
out.writeBytes("{broken:true}")
out.close()
- RoleHistory rh2 = new RoleHistory(MockFactory.ROLES)
+ RoleHistory rh2 = new MockRoleHistory(MockFactory.ROLES)
describe("IGNORE STACK TRACE BELOW")
assert rh2.onStart(fs, historyPath)
@@ -285,7 +286,7 @@
def loadedRoleHistory = writer.read(source)
assert 4 == loadedRoleHistory.size()
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
assert 0 == roleHistory.rebuild(loadedRoleHistory)
}
@@ -300,7 +301,7 @@
def loadedRoleHistory = writer.read(source)
assert 6 == loadedRoleHistory.size()
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
assert 3 == roleHistory.rebuild(loadedRoleHistory)
}
@@ -318,7 +319,7 @@
assert 4 == loadedRoleHistory.size()
def expandedRoles = new ArrayList(MockFactory.ROLES)
expandedRoles << PROVIDER_ROLE3
- RoleHistory roleHistory = new RoleHistory(expandedRoles)
+ RoleHistory roleHistory = new MockRoleHistory(expandedRoles)
assert 0 == roleHistory.rebuild(loadedRoleHistory)
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRWOrdering.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRWOrdering.groovy
index aef22fb..8a0c1ca 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRWOrdering.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRWOrdering.groovy
@@ -18,11 +18,13 @@
package org.apache.slider.server.appmaster.model.history
+import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.apache.hadoop.fs.Path
import org.apache.slider.common.SliderKeys
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
import org.apache.slider.server.appmaster.model.mock.MockFactory
+import org.apache.slider.server.appmaster.model.mock.MockRoleHistory
import org.apache.slider.server.appmaster.state.NodeEntry
import org.apache.slider.server.appmaster.state.NodeInstance
import org.apache.slider.server.appmaster.state.RoleHistory
@@ -34,14 +36,15 @@
import java.util.regex.Pattern
@Slf4j
+@CompileStatic
class TestRoleHistoryRWOrdering extends BaseMockAppStateTest {
- def paths = pathlist(
+ List<Path> paths = pathlist(
[
- "hdfs://localhost/history-0406c.json",
- "hdfs://localhost/history-5fffa.json",
- "hdfs://localhost/history-0001a.json",
- "hdfs://localhost/history-0001f.json",
+ "hdfs://localhost/history-0406c.json",
+ "hdfs://localhost/history-5fffa.json",
+ "hdfs://localhost/history-0001a.json",
+ "hdfs://localhost/history-0001f.json",
]
)
Path h_0406c = paths[0]
@@ -50,9 +53,7 @@
List<Path> pathlist(List<String> pathnames) {
- def result = []
- pathnames.each { result << new Path(new URI(it as String)) }
- result
+ pathnames.collect{ new Path(new URI(it as String)) }
}
@Override
@@ -60,7 +61,6 @@
return "TestHistoryRWOrdering"
}
-
/**
* This tests regexp pattern matching. It uses the current time so isn't
* repeatable -but it does test a wider range of values in the process
@@ -79,13 +79,12 @@
}
}
-
@Test
public void testWriteSequenceReadData() throws Throwable {
describe "test that if multiple entries are written, the newest is picked up"
long time = System.currentTimeMillis();
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
assert !roleHistory.onStart(fs, historyPath)
String addr = "localhost"
NodeInstance instance = roleHistory.getOrCreateNodeInstance(addr)
@@ -94,7 +93,7 @@
Path history1 = roleHistory.saveHistory(time++)
Path history2 = roleHistory.saveHistory(time++)
- Path history3 = roleHistory.saveHistory(time++)
+ Path history3 = roleHistory.saveHistory(time)
//inject a later file with a different name
sliderFileSystem.cat(new Path(historyPath, "file.json"), true, "hello, world")
@@ -116,7 +115,7 @@
public void testPathStructure() throws Throwable {
assert h_5fffa.getName() == "history-5fffa.json"
}
-
+
@Test
public void testPathnameComparator() throws Throwable {
@@ -137,10 +136,10 @@
RoleHistoryWriter.sortHistoryPaths(paths2)
assertListEquals(paths2,
[
- paths[1],
- paths[0],
- paths[3],
- paths[2]
+ paths[1],
+ paths[0],
+ paths[3],
+ paths[2]
])
}
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRequestTracking.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRequestTracking.groovy
index 9847992..2f160cb 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRequestTracking.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRequestTracking.groovy
@@ -18,6 +18,7 @@
package org.apache.slider.server.appmaster.model.history
+import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.apache.hadoop.yarn.api.records.Container
import org.apache.hadoop.yarn.api.records.Resource
@@ -27,6 +28,7 @@
import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
import org.apache.slider.server.appmaster.model.mock.MockContainer
import org.apache.slider.server.appmaster.model.mock.MockFactory
+import org.apache.slider.server.appmaster.model.mock.MockRoleHistory
import org.apache.slider.server.appmaster.state.ContainerAllocationOutcome
import org.apache.slider.server.appmaster.state.NodeEntry
import org.apache.slider.server.appmaster.state.NodeInstance
@@ -41,6 +43,7 @@
* get removed and added
*/
@Slf4j
+@CompileStatic
class TestRoleHistoryRequestTracking extends BaseMockAppStateTest {
String roleName = "test"
@@ -53,12 +56,17 @@
NodeInstance empty = new NodeInstance("empty", MockFactory.ROLE_COUNT)
List<NodeInstance> nodes = [age2Active2, age2Active0, age4Active1, age1Active4, age3Active0]
- RoleHistory roleHistory = new RoleHistory(MockFactory.ROLES)
+ RoleHistory roleHistory = new MockRoleHistory(MockFactory.ROLES)
+ /** 1MB, 1 vcore*/
Resource resource = Resource.newInstance(1, 1)
ProviderRole provRole = new ProviderRole(roleName, 0)
RoleStatus roleStatus = new RoleStatus(provRole)
+ AMRMClient.ContainerRequest requestContainer(RoleStatus roleStatus) {
+ roleHistory.requestContainerForRole(roleStatus).issuedRequest
+ }
+
@Override
String getTestName() {
return "TestRoleHistoryAvailableList"
@@ -67,46 +75,44 @@
@Before
public void setupNodeMap() {
roleHistory.insert(nodes)
- roleHistory.buildAvailableNodeLists();
+ roleHistory.buildRecentNodeLists();
+ roleStatus.setResourceRequirements(Resource.newInstance(1, 1))
}
@Test
public void testAvailableListBuiltForRoles() throws Throwable {
- List<NodeInstance> available0 = roleHistory.cloneAvailableList(0)
+ List<NodeInstance> available0 = roleHistory.cloneRecentNodeList(0)
assertListEquals([age3Active0, age2Active0], available0)
}
@Test
public void testRequestedNodeOffList() throws Throwable {
- List<NodeInstance> available0 = roleHistory.cloneAvailableList(0)
- NodeInstance ni = roleHistory.findNodeForNewInstance(roleStatus)
+ NodeInstance ni = roleHistory.findRecentNodeForNewInstance(roleStatus)
assert age3Active0 == ni
- AMRMClient.ContainerRequest req = roleHistory.requestInstanceOnNode(ni,
+ assertListEquals([age2Active0], roleHistory.cloneRecentNodeList(0))
+ roleHistory.requestInstanceOnNode(ni,
roleStatus,
- resource,
- "")
- List<NodeInstance> a2 = roleHistory.cloneAvailableList(0)
- assertListEquals([age2Active0], a2)
+ resource
+ )
}
@Test
public void testRequestedNodeOffListWithFailures() throws Throwable {
assert 0 == roleStatus.key
- assert !roleHistory.cloneAvailableList(0).isEmpty()
+ assert !roleHistory.cloneRecentNodeList(0).empty
NodeEntry age3role0 = recordAsFailed(age3Active0, 0, 4)
assert age3Active0.isConsideredUnreliable(0, roleStatus.nodeFailureThreshold)
recordAsFailed(age2Active0, 0, 4)
assert age2Active0.isConsideredUnreliable(0, roleStatus.nodeFailureThreshold)
// expect to get a null node back
- NodeInstance ni = roleHistory.findNodeForNewInstance(roleStatus)
+ NodeInstance ni = roleHistory.findRecentNodeForNewInstance(roleStatus)
assert !ni
// which is translated to a no-location request
AMRMClient.ContainerRequest req = roleHistory.requestInstanceOnNode(ni,
roleStatus,
- resource,
- "")
+ resource).issuedRequest
assertNull(req.nodes)
@@ -115,57 +121,61 @@
roleHistory.dump()
assert 0 == age3role0.failedRecently
assert !age3Active0.isConsideredUnreliable(0, roleStatus.nodeFailureThreshold)
- assert !roleHistory.cloneAvailableList(0).isEmpty()
+ assert !roleHistory.cloneRecentNodeList(0).empty
// looking for a node should now find one
- ni = roleHistory.findNodeForNewInstance(roleStatus)
+ ni = roleHistory.findRecentNodeForNewInstance(roleStatus)
assert ni == age3Active0
- req = roleHistory.requestInstanceOnNode(ni,
- roleStatus,
- resource,
- "")
+ req = roleHistory.requestInstanceOnNode(ni, roleStatus, resource).issuedRequest
assert 1 == req.nodes.size()
}
+ /**
+ * verify that strict placement policies generate requests for nodes irrespective
+ * of their failed status
+ * @throws Throwable
+ */
@Test
public void testStrictPlacementIgnoresFailures() throws Throwable {
def targetRole = role1Status
final ProviderRole providerRole1 = targetRole.providerRole
assert providerRole1.placementPolicy == PlacementPolicy.STRICT
- int key = targetRole.key
+ int key1 = targetRole.key
+ def key0 = role0Status.key
- recordAsFailed(age1Active4, key, 4)
- recordAsFailed(age2Active0, key, 4)
- recordAsFailed(age2Active2, key, 4)
- recordAsFailed(age3Active0, key, 4)
- recordAsFailed(age4Active1, key, 4)
+ def nodes = [age1Active4, age2Active0, age2Active2, age3Active0, age4Active1]
+ recordAllFailed(key0, 4, nodes)
+ recordAllFailed(key1, 4, nodes)
// trigger a list rebuild
- roleHistory.buildAvailableNodeLists();
+ roleHistory.buildRecentNodeLists();
+ def recentRole0 = roleHistory.cloneRecentNodeList(key0)
+ assert recentRole0.indexOf(age3Active0) < recentRole0.indexOf(age2Active0)
- assert !roleHistory.cloneAvailableList(key).isEmpty()
+ // the non-strict role has no suitable nodes
+ assert null == roleHistory.findRecentNodeForNewInstance(role0Status)
- NodeInstance ni = roleHistory.findNodeForNewInstance(targetRole)
- assert ni == age4Active1!= null
- // next lookup returns next node
- ni = roleHistory.findNodeForNewInstance(roleStatus)
- assert ni == age3Active0
+ def ni = roleHistory.findRecentNodeForNewInstance(targetRole)
+ assert ni
+
+ def ni2 = roleHistory.findRecentNodeForNewInstance(targetRole)
+ assert ni2
+ assert ni != ni2
}
-
@Test
public void testFindAndRequestNode() throws Throwable {
- AMRMClient.ContainerRequest req = roleHistory.requestNode(roleStatus, resource)
+ AMRMClient.ContainerRequest req = requestContainer(roleStatus)
assert age3Active0.hostname == req.nodes[0]
- List<NodeInstance> a2 = roleHistory.cloneAvailableList(0)
+ List<NodeInstance> a2 = roleHistory.cloneRecentNodeList(0)
assertListEquals([age2Active0], a2)
}
@Test
public void testRequestedNodeIntoReqList() throws Throwable {
- AMRMClient.ContainerRequest req = roleHistory.requestNode(roleStatus, resource)
+ requestContainer(roleStatus)
List<OutstandingRequest> requests = roleHistory.listPlacedRequests()
assert requests.size() == 1
assert age3Active0.hostname == requests[0].hostname
@@ -173,7 +183,7 @@
@Test
public void testCompletedRequestDropsNode() throws Throwable {
- AMRMClient.ContainerRequest req = roleHistory.requestNode(roleStatus, resource)
+ AMRMClient.ContainerRequest req = requestContainer(roleStatus)
List<OutstandingRequest> requests = roleHistory.listPlacedRequests()
assert requests.size() == 1
String hostname = requests[0].hostname
@@ -202,8 +212,8 @@
@Test
public void testTwoRequests() throws Throwable {
- AMRMClient.ContainerRequest req = roleHistory.requestNode(roleStatus, resource)
- AMRMClient.ContainerRequest req2 = roleHistory.requestNode(roleStatus, resource)
+ AMRMClient.ContainerRequest req = requestContainer(roleStatus)
+ AMRMClient.ContainerRequest req2 = requestContainer(roleStatus)
List<OutstandingRequest> requests = roleHistory.listPlacedRequests()
assert requests.size() == 2
MockContainer container = factory.newContainer(req, req.nodes[0])
@@ -216,9 +226,9 @@
@Test
public void testThreeRequestsOneUnsatisified() throws Throwable {
- AMRMClient.ContainerRequest req = roleHistory.requestNode(roleStatus, resource)
- AMRMClient.ContainerRequest req2 = roleHistory.requestNode(roleStatus, resource)
- AMRMClient.ContainerRequest req3 = roleHistory.requestNode(roleStatus, resource)
+ AMRMClient.ContainerRequest req = requestContainer(roleStatus)
+ AMRMClient.ContainerRequest req2 = requestContainer(roleStatus)
+ AMRMClient.ContainerRequest req3 = requestContainer(roleStatus)
List<OutstandingRequest> requests = roleHistory.listPlacedRequests()
assert requests.size() == 2
MockContainer container = factory.newContainer(req, req.nodes[0])
@@ -239,15 +249,15 @@
roleHistory.listOpenRequests().empty
// and the remainder goes onto the available list
- List<NodeInstance> a2 = roleHistory.cloneAvailableList(0)
+ List<NodeInstance> a2 = roleHistory.cloneRecentNodeList(0)
assertListEquals([age2Active0], a2)
}
@Test
public void testThreeRequests() throws Throwable {
- AMRMClient.ContainerRequest req = roleHistory.requestNode(roleStatus, resource)
- AMRMClient.ContainerRequest req2 = roleHistory.requestNode(roleStatus, resource)
- AMRMClient.ContainerRequest req3 = roleHistory.requestNode(roleStatus, resource)
+ AMRMClient.ContainerRequest req = requestContainer(roleStatus)
+ AMRMClient.ContainerRequest req2 = requestContainer(roleStatus)
+ AMRMClient.ContainerRequest req3 = requestContainer(roleStatus)
assertOutstandingPlacedRequests(2)
assert req3.nodes == null
MockContainer container = factory.newContainer(req, req.nodes[0])
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/BaseMockAppStateTest.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/BaseMockAppStateTest.groovy
index 29eefa5..69a98eb 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/BaseMockAppStateTest.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/BaseMockAppStateTest.groovy
@@ -20,35 +20,38 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs.FileSystem as HadoopFS
import org.apache.hadoop.fs.Path
import org.apache.hadoop.yarn.api.records.Container
import org.apache.hadoop.yarn.api.records.ContainerId
import org.apache.hadoop.yarn.api.records.ContainerState
import org.apache.hadoop.yarn.api.records.ContainerStatus
+import org.apache.hadoop.yarn.api.records.NodeReport
+import org.apache.hadoop.yarn.client.api.AMRMClient
import org.apache.hadoop.yarn.conf.YarnConfiguration
import org.apache.slider.common.tools.SliderFileSystem
import org.apache.slider.common.tools.SliderUtils
import org.apache.slider.core.conf.AggregateConf
import org.apache.slider.core.main.LauncherExitCodes
import org.apache.slider.server.appmaster.operations.AbstractRMOperation
+import org.apache.slider.server.appmaster.operations.CancelSingleRequest
+import org.apache.slider.server.appmaster.operations.ContainerRequestOperation
import org.apache.slider.server.appmaster.state.AppState
+import org.apache.slider.server.appmaster.state.AppStateBindingInfo
import org.apache.slider.server.appmaster.state.ContainerAssignment
import org.apache.slider.server.appmaster.state.ContainerOutcome
import org.apache.slider.server.appmaster.state.NodeEntry
import org.apache.slider.server.appmaster.state.NodeInstance
+import org.apache.slider.server.appmaster.state.NodeMap
+import org.apache.slider.server.appmaster.state.ProviderAppState
import org.apache.slider.server.appmaster.state.RoleInstance
import org.apache.slider.server.appmaster.state.RoleStatus
-import org.apache.slider.server.appmaster.state.SimpleReleaseSelector
+import org.apache.slider.server.appmaster.state.StateAccessForProviders
import org.apache.slider.test.SliderTestBase
-import org.junit.Before
@CompileStatic
@Slf4j
abstract class BaseMockAppStateTest extends SliderTestBase implements MockRoles {
- public static final int RM_MAX_RAM = 4096
- public static final int RM_MAX_CORES = 64
MockFactory factory = new MockFactory()
MockAppState appState
MockYarnEngine engine
@@ -58,6 +61,16 @@
protected Path historyPath;
protected MockApplicationId applicationId;
protected MockApplicationAttemptId applicationAttemptId;
+ protected StateAccessForProviders stateAccess
+
+ /**
+ * Override point: called in setup() to create the YARN engine; can
+ * be changed for different sizes and options
+ * @return
+ */
+ public MockYarnEngine createYarnEngine() {
+ return new MockYarnEngine(8, 8)
+ }
@Override
void setup() {
@@ -66,49 +79,46 @@
fs = HadoopFS.get(new URI("file:///"), conf)
sliderFileSystem = new SliderFileSystem(fs, conf)
engine = createYarnEngine()
+ initApp()
}
/**
- * Override point: called in setup() to create the YARN engine; can
- * be changed for different sizes and options
- * @return
+ * Initialize the application.
+ * This uses the binding information supplied by {@link #buildBindingInfo()}.
*/
- public MockYarnEngine createYarnEngine() {
- return new MockYarnEngine(64, 1)
- }
-
- @Before
void initApp(){
-
String historyDirName = testName;
-
-
- YarnConfiguration conf = SliderUtils.createConfiguration()
applicationId = new MockApplicationId(id: 1, clusterTimestamp: 0)
applicationAttemptId = new MockApplicationAttemptId(
applicationId: applicationId,
attemptId: 1)
- fs = HadoopFS.get(new URI("file:///"), conf)
historyWorkDir = new File("target/history", historyDirName)
historyPath = new Path(historyWorkDir.toURI())
fs.delete(historyPath, true)
- appState = new MockAppState()
- appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES)
- appState.buildInstance(
- buildInstanceDefinition(),
- new Configuration(),
- new Configuration(false),
- factory.ROLES,
- fs,
- historyPath,
- null, null,
- new SimpleReleaseSelector())
+ appState = new MockAppState(buildBindingInfo())
+ stateAccess = new ProviderAppState(testName, appState)
+ }
+
+ /**
+ * Build the binding info from the default constructor values,
+ * the roles from {@link #factory}, and an instance definition
+ * from {@link #buildInstanceDefinition()}
+ * @return
+ */
+ AppStateBindingInfo buildBindingInfo() {
+ AppStateBindingInfo binding = new AppStateBindingInfo()
+ binding.instanceDefinition = buildInstanceDefinition();
+ binding.roles = factory.ROLES
+ binding.fs = fs
+ binding.historyPath = historyPath
+ binding.nodeReports = engine.nodeReports as List<NodeReport>
+ binding
}
/**
* Override point, define the instance definition
- * @return
+ * @return the instance definition
*/
public AggregateConf buildInstanceDefinition() {
factory.newInstanceDefinition(0, 0, 0)
@@ -116,22 +126,26 @@
/**
* Get the test name ... defaults to method name
- * @return
+ * @return the method name
*/
String getTestName() {
methodName.methodName;
}
public RoleStatus getRole0Status() {
- return appState.lookupRoleStatus(ROLE0)
+ lookupRole(ROLE0)
+ }
+
+ public RoleStatus lookupRole(String role) {
+ appState.lookupRoleStatus(role)
}
public RoleStatus getRole1Status() {
- return appState.lookupRoleStatus(ROLE1)
+ lookupRole(ROLE1)
}
public RoleStatus getRole2Status() {
- return appState.lookupRoleStatus(ROLE2)
+ lookupRole(ROLE2)
}
/**
@@ -147,7 +161,6 @@
return ri
}
-
public NodeInstance nodeInstance(long age, int live0, int live1=0, int live2=0) {
NodeInstance ni = new NodeInstance("age${age}-[${live0},${live1},$live2]",
MockFactory.ROLE_COUNT)
@@ -200,7 +213,6 @@
return createStartAndStopNodes([])
}
-
/**
* Create, Start and stop nodes
* @param completionResults List filled in with the status on all completed nodes
@@ -266,7 +278,7 @@
* @return a list of roles
*/
public List<RoleInstance> createAndSubmitNodes() {
- return createAndSubmitNodes([])
+ return createAndSubmitNodes([], [])
}
/**
@@ -275,35 +287,36 @@
* @return a list of roles allocated
*/
public List<RoleInstance> createAndSubmitNodes(
- List<ContainerId> released) {
+ List<ContainerId> containerIds,
+ List<AbstractRMOperation> operationsOut = []) {
List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes()
- return submitOperations(ops, released)
+ return submitOperations(ops, containerIds, operationsOut)
}
/**
* Process the RM operations and send <code>onContainersAllocated</code>
* events to the app state
- * @param ops
- * @param released
- * @return
+ * @param operationsIn list of incoming ops
+ * @param released released containers
+ * @return list of outbound operations
*/
public List<RoleInstance> submitOperations(
- List<AbstractRMOperation> ops,
- List<ContainerId> released) {
- List<Container> allocatedContainers = engine.execute(ops, released)
+ List<AbstractRMOperation> operationsIn,
+ List<ContainerId> released,
+ List<AbstractRMOperation> operationsOut = []) {
+ List<Container> allocatedContainers = engine.execute(operationsIn, released)
List<ContainerAssignment> assignments = [];
- List<AbstractRMOperation> operations = []
- appState.onContainersAllocated(allocatedContainers, assignments, operations)
- List<RoleInstance> instances = []
- for (ContainerAssignment assigned : assignments) {
+ appState.onContainersAllocated(allocatedContainers, assignments, operationsOut)
+
+ assignments.collect {
+ ContainerAssignment assigned ->
Container container = assigned.container
RoleInstance ri = roleInstance(assigned)
- instances << ri
//tell the app it arrived
log.debug("Start submitted ${ri.role} on ${container.id} ")
appState.containerStartSubmitted(container, ri);
+ ri
}
- return instances
}
/**
@@ -326,13 +339,7 @@
List<ContainerId> extractContainerIds(
List<RoleInstance> instances,
int role) {
- List<ContainerId> cids = []
- instances.each { RoleInstance instance ->
- if (instance.roleId == role) {
- cids << instance.id
- }
- }
- return cids
+ instances.findAll { it.roleId == role }.collect { RoleInstance instance -> instance.id }
}
/**
@@ -351,4 +358,99 @@
}
entry
}
+
+ def recordAllFailed(int id, int count, List<NodeInstance> nodes) {
+ nodes.each { NodeInstance node -> recordAsFailed(node, id, count)}
+ }
+
+ /**
+ * Get the container request of an indexed entry. Includes some assertions for better diagnostics
+ * @param ops operation list
+ * @param index index in the list
+ * @return the request.
+ */
+ AMRMClient.ContainerRequest getRequest(List<AbstractRMOperation> ops, int index) {
+ assert index < ops.size()
+ def op = ops[index]
+ assert op instanceof ContainerRequestOperation
+ ((ContainerRequestOperation) op).request
+ }
+
+ /**
+ * Get the cancel request of an indexed entry. Includes some assertions for better diagnostics
+ * @param ops operation list
+ * @param index index in the list
+ * @return the request.
+ */
+ AMRMClient.ContainerRequest getCancel(List<AbstractRMOperation> ops, int index) {
+ assert index < ops.size()
+ def op = ops[index]
+ assert op instanceof CancelSingleRequest
+ ((CancelSingleRequest) op).request
+ }
+
+ /**
+ * Get the single request of a list of operations; includes the check for the size
+ * @param ops operations list of size 1
+ * @return the request within the first ContainerRequestOperation
+ */
+ public AMRMClient.ContainerRequest getSingleRequest(List<AbstractRMOperation> ops) {
+ assert 1 == ops.size()
+ getRequest(ops, 0)
+ }
+
+ /**
+ * Get the node information as a large JSON String
+ * @return
+ */
+ String nodeInformationSnapshotAsString() {
+ prettyPrintAsJson(stateAccess.nodeInformationSnapshot)
+ }
+
+ /**
+ * Scan through all containers and assert that the assignment is AA
+ * @param index role index
+ */
+ void assertAllContainersAA(int index) {
+ cloneNodemap().each { name, info ->
+ def nodeEntry = info.get(index)
+ assert nodeEntry == null || nodeEntry.antiAffinityConstraintHeld
+ "too many instances on node $name"
+ }
+ }
+
+ List<NodeInstance> verifyNodeInstanceCount(int size, List<NodeInstance> list) {
+ if (list.size() != size) {
+ list.each { log.error(it.toFullString()) }
+ }
+ assert size == list.size()
+ list
+ }
+
+ /**
+ * Get the single request of a list of operations; includes the check for the size
+ * @param ops operations list of size 1
+ * @return the request within the first operation
+ */
+ public AMRMClient.ContainerRequest getSingleCancel(List<AbstractRMOperation> ops) {
+ assert 1 == ops.size()
+ getCancel(ops, 0)
+ }
+
+ /**
+ * Get a snapshot of the nodemap of the application state
+ * @return a cloned nodemap
+ */
+ protected NodeMap cloneNodemap() {
+ appState.roleHistory.cloneNodemap()
+ }
+
+ /**
+ * Issue a nodes updated event
+ * @param report report to notify
+ * @return response of AM
+ */
+ protected AppState.NodeUpdatedOutcome updateNodes(NodeReport report) {
+ appState.onNodesUpdated([report])
+ }
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockAppState.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockAppState.groovy
index 6e21a38..c041ce5 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockAppState.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockAppState.groovy
@@ -21,14 +21,18 @@
import org.apache.slider.server.appmaster.management.MetricsAndMonitoring
import org.apache.slider.server.appmaster.state.AbstractClusterServices
import org.apache.slider.server.appmaster.state.AppState
+import org.apache.slider.server.appmaster.state.AppStateBindingInfo
/**
* Extended app state that makes more things public
*/
class MockAppState extends AppState {
+ public static final int RM_MAX_RAM = 4096
+ public static final int RM_MAX_CORES = 64
public MockAppState(AbstractClusterServices recordFactory) {
super(recordFactory, new MetricsAndMonitoring());
+ setContainerLimits(1, RM_MAX_RAM, 1, RM_MAX_CORES)
}
long time = 0;
@@ -37,7 +41,12 @@
* Instance with a mock record factory
*/
public MockAppState() {
- super(new MockClusterServices(), new MetricsAndMonitoring());
+ this(new MockClusterServices());
+ }
+
+ MockAppState(AppStateBindingInfo bindingInfo) {
+ this()
+ buildInstance(bindingInfo)
}
public Map<String, ProviderRole> getRoleMap() {
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockClusterServices.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockClusterServices.groovy
index d27a6bb..dfecc94 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockClusterServices.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockClusterServices.groovy
@@ -27,4 +27,9 @@
Resource newResource() {
return new MockResource()
}
+
+ @Override
+ Resource newResource(int memory, int cores) {
+ return new MockResource(memory, cores)
+ }
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockFactory.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockFactory.groovy
index 6071ef0..4bbfbd8 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockFactory.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockFactory.groovy
@@ -44,26 +44,59 @@
Ignore any IDE hints about needless references to the ROLE values; groovyc fails without them.
*/
+ /**
+ * basic role
+ */
public static final ProviderRole PROVIDER_ROLE0 = new ProviderRole(
MockRoles.ROLE0,
0,
PlacementPolicy.DEFAULT,
2,
- 1)
- // role 1 is strict. timeout should be irrelevant; same as failures
+ 1,
+ ResourceKeys.DEF_YARN_LABEL_EXPRESSION)
+ /**
+ * role 1 is strict. timeout should be irrelevant; same as failures
+ */
public static final ProviderRole PROVIDER_ROLE1 = new ProviderRole(
MockRoles.ROLE1,
1,
PlacementPolicy.STRICT,
2,
- 1)
- // role 2: longer delay
+ 1,
+ ResourceKeys.DEF_YARN_LABEL_EXPRESSION)
+
+ /**
+ * role 2: longer delay
+ */
public static final ProviderRole PROVIDER_ROLE2 = new ProviderRole(
MockRoles.ROLE2,
2,
+ PlacementPolicy.NO_DATA_LOCALITY,
+ 2,
+ 2,
+ ResourceKeys.DEF_YARN_LABEL_EXPRESSION)
+
+ /**
+ * Patch up a "role2" role to have anti-affinity set
+ */
+ public static final ProviderRole AAROLE_2 = new ProviderRole(
+ MockRoles.ROLE2,
+ 2,
PlacementPolicy.ANTI_AFFINITY_REQUIRED,
2,
- 2)
+ 2,
+ null)
+
+ /**
+ * Patch up a "role1" role to have anti-affinity set and GPI as the label
+ */
+ public static final ProviderRole AAROLE_1_GPU = new ProviderRole(
+ MockRoles.ROLE1,
+ 1,
+ PlacementPolicy.ANTI_AFFINITY_REQUIRED,
+ 2,
+ 1,
+ MockRoles.LABEL_GPU)
int appIdCount;
int attemptIdCount;
@@ -80,7 +113,7 @@
PROVIDER_ROLE1,
PROVIDER_ROLE2,
]
-
+
public static final int ROLE_COUNT = ROLES.size();
MockContainerId newContainerId() {
@@ -107,8 +140,8 @@
return id;
}
- MockNodeId newNodeId() {
- new MockNodeId()
+ MockNodeId newNodeId(String host = null) {
+ new MockNodeId(host: host)
}
MockContainer newContainer(ContainerId cid) {
@@ -202,12 +235,11 @@
]
}
- MockResource newResource() {
- return new MockResource()
+ MockResource newResource(int memory = 0, int vcores = 0) {
+ return new MockResource(memory, vcores)
}
MockContainerStatus newContainerStatus() {
return new MockContainerStatus()
-
}
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockNodeReport.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockNodeReport.groovy
new file mode 100644
index 0000000..8c3b712
--- /dev/null
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockNodeReport.groovy
@@ -0,0 +1,75 @@
+/*
+ * 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.slider.server.appmaster.model.mock
+
+import groovy.transform.CompileStatic
+import org.apache.hadoop.yarn.api.records.NodeId
+import org.apache.hadoop.yarn.api.records.NodeReport
+import org.apache.hadoop.yarn.api.records.NodeState
+import org.apache.hadoop.yarn.api.records.Resource
+
+/**
+ * Node report for testing
+ */
+@CompileStatic
+class MockNodeReport extends NodeReport {
+ NodeId nodeId;
+ NodeState nodeState;
+ String httpAddress;
+ String rackName;
+ Resource used;
+ Resource capability;
+ int numContainers;
+ String healthReport;
+ long lastHealthReportTime;
+ Set<String> nodeLabels;
+
+ MockNodeReport() {
+ }
+
+ /**
+ * Create a single instance
+ * @param hostname
+ * @param nodeState
+ * @param label
+ */
+ MockNodeReport(String hostname, NodeState nodeState, String label ="") {
+ nodeId = NodeId.newInstance(hostname, 80)
+ Integer.valueOf(hostname, 16)
+ this.nodeState = nodeState
+ this.httpAddress = "http$hostname:80"
+ this.nodeLabels = new HashSet<>()
+ nodeLabels.add(label)
+ }
+
+ /**
+ * Create a list of instances -one for each hostname
+ * @param hostnames hosts
+ * @param nodeState state of all of them
+ * @param label label for all of them
+ * @return
+ */
+ static List<MockNodeReport> createInstances(
+ List<String> hostnames,
+ NodeState nodeState = NodeState.RUNNING,
+ String label = "") {
+ hostnames.collect { String name ->
+ new MockNodeReport(name, nodeState, label)}
+ }
+}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockResource.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockResource.groovy
index f4c54f3..91ab43b 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockResource.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockResource.groovy
@@ -24,7 +24,7 @@
int memory
int virtualCores
- MockResource(int memory=0, int vcores=0) {
+ MockResource(int memory = 0, int vcores = 0) {
this.memory = memory
this.virtualCores = vcores
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockRoleHistory.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockRoleHistory.groovy
index c521697..4553e22 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockRoleHistory.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockRoleHistory.groovy
@@ -21,15 +21,22 @@
import org.apache.slider.core.exceptions.BadConfigException
import org.apache.slider.providers.ProviderRole
import org.apache.slider.server.appmaster.state.RoleHistory
+import org.apache.slider.server.appmaster.state.RoleStatus
/**
* subclass to enable access to some of the protected methods
*/
class MockRoleHistory extends RoleHistory {
+ /**
+ * Take a list of provider roles and build the history from them, dynamically creating
+ * the role status entries on the way
+ * @param providerRoles provider role list
+ * @throws BadConfigException configuration problem with the role list
+ */
MockRoleHistory(List<ProviderRole> providerRoles) throws BadConfigException {
- super(providerRoles)
+ super(providerRoles.collect { new RoleStatus(it) },
+ new MockClusterServices())
}
-
-
+
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockRoles.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockRoles.groovy
index b44482d..5ee8f24 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockRoles.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockRoles.groovy
@@ -24,4 +24,6 @@
String ROLE1 = "role1"
String ROLE2 = "role2"
int ROLE_COUNT = 3
+ String LABEL_GPU = "gpu"
+
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockYarnCluster.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockYarnCluster.groovy
index 6056e3a..265a796 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockYarnCluster.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockYarnCluster.groovy
@@ -22,6 +22,7 @@
import groovy.util.logging.Slf4j
import org.apache.hadoop.yarn.api.records.ContainerId
import org.apache.hadoop.yarn.api.records.NodeId
+import org.apache.hadoop.yarn.api.records.NodeState
/**
* Models the cluster itself: a set of mock cluster nodes.
@@ -143,21 +144,30 @@
}
return total;
}
-
+
+ /**
+ * Get the list of node reports. These are not cloned; updates will persist in the nodemap
+ * @return current node report list
+ */
+ List<MockNodeReport> getNodeReports() {
+ nodes.collect { MockYarnClusterNode n -> n.nodeReport }
+ }
/**
* Model cluster nodes on the simpler "slot" model than the YARN-era
- * resource allocation model. Why? Makes it easier to implement.
+ * resource allocation model. Why? Easier to implement scheduling.
+ * Of course, if someone does want to implement the full process...
*
- * When a cluster is offline,
*/
public static class MockYarnClusterNode {
public final int nodeIndex
public final String hostname;
+ public List<String> labels = []
public final MockNodeId nodeId;
public final MockYarnClusterContainer[] containers;
private boolean offline;
+ public MockNodeReport nodeReport
public MockYarnClusterNode(int index, int size) {
nodeIndex = index;
@@ -170,6 +180,10 @@
MockContainerId mci = new MockContainerId(containerId: cid)
containers[i] = new MockYarnClusterContainer(mci)
}
+
+ nodeReport = new MockNodeReport()
+ nodeReport.nodeId = nodeId
+ nodeReport.nodeState = NodeState.RUNNING
}
/**
@@ -230,8 +244,6 @@
}
return result
}
-
-
/**
* Release a container
@@ -291,8 +303,8 @@
return (hostIndex << 8) | containerIndex & 0xff;
}
- public static final int extractHost(int cid) {
- return (cid >>> 8);
+ public static final int extractHost(long cid) {
+ return (cid >>> 8) & 0xffff;
}
public static final int extractContainer(int cid) {
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockYarnEngine.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockYarnEngine.groovy
index 5860c6b..7ab97fa 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockYarnEngine.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/MockYarnEngine.groovy
@@ -26,6 +26,7 @@
import org.apache.hadoop.yarn.api.records.ContainerId
import org.apache.hadoop.yarn.client.api.AMRMClient
import org.apache.slider.server.appmaster.operations.AbstractRMOperation
+import org.apache.slider.server.appmaster.operations.CancelSingleRequest
import org.apache.slider.server.appmaster.operations.ContainerReleaseOperation
import org.apache.slider.server.appmaster.operations.ContainerRequestOperation
import org.junit.Assert
@@ -113,7 +114,9 @@
ContainerId cid = cro.containerId
assert releaseContainer(cid);
released.add(cid)
- } else {
+ } else if (op instanceof CancelSingleRequest) {
+ // no-op
+ } else if (op instanceof ContainerRequestOperation) {
ContainerRequestOperation req = (ContainerRequestOperation) op
Container container = allocateContainer(req.request)
if (container != null) {
@@ -123,6 +126,8 @@
log.debug("Unsatisfied allocation $req")
pending.add(req)
}
+ } else {
+ log.warn("Unsupported operation $op")
}
}
return allocation
@@ -157,4 +162,11 @@
}
}
+ /**
+ * Get the list of node reports. These are not cloned; updates will persist in the nodemap
+ * @return current node report list
+ */
+ List<MockNodeReport> getNodeReports() {
+ cluster.nodeReports
+ }
}
\ No newline at end of file
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/web/view/TestIndexBlock.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/web/view/TestIndexBlock.groovy
index c2ea837..a818e53 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/web/view/TestIndexBlock.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/web/view/TestIndexBlock.groovy
@@ -24,8 +24,10 @@
import org.apache.hadoop.yarn.api.records.Priority
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet
import org.apache.slider.providers.ProviderService
+import org.apache.slider.server.appmaster.model.appstate.BaseMockAppStateAATest
import org.apache.slider.server.appmaster.model.mock.*
import org.apache.slider.server.appmaster.state.ContainerOutcome
+import org.apache.slider.server.appmaster.state.OutstandingRequest
import org.apache.slider.server.appmaster.state.ProviderAppState
import org.apache.slider.server.appmaster.web.WebAppApi
import org.apache.slider.server.appmaster.web.WebAppApiImpl
@@ -34,7 +36,7 @@
@Slf4j
//@CompileStatic
-public class TestIndexBlock extends BaseMockAppStateTest {
+public class TestIndexBlock extends BaseMockAppStateAATest {
private IndexBlock indexBlock;
@@ -81,42 +83,80 @@
public void testIndex() {
def role0 = role0Status
def role1 = role1Status
- role0.desired = 8
- role0.incActual()
- role0.incActual()
- role0.incActual()
- role0.incActual()
- role0.incActual()
- role1.incRequested()
- role1.incRequested()
- role1.incRequested()
+ def role2 = role2Status
+
+ def role0_desired = 8
+
+ role0.desired = role0_desired
+ int role0_actual = 5
+ int role0_requested = role0_desired - role0_actual
+ role0_actual.times {
+ role0.incActual()
+ }
+ assert role0.getActual() == role0_actual
+ role0_requested.times {
+ role0.incRequested()
+ }
+ assert role0.getRequested() == role0_requested
+
+ def role0_failures = 2
+
role0.noteFailed(false, "", ContainerOutcome.Failed)
role0.noteFailed(true, "", ContainerOutcome.Failed)
+ // all aa roles fields are in the
+ def aarole_desired = 200
+ aaRole.desired = aarole_desired
+ def aarole_actual = 90
+ def aarole_active = 1
+ def aarole_requested = aarole_desired - aarole_actual
+ def aarole_pending = aarole_requested - 1
+ def aarole_failures = 0
+ aarole_actual.times {
+ aaRole.incActual()
+ }
+ assert aaRole.actual == aarole_actual
+ aaRole.outstandingAArequest = new OutstandingRequest(2, "")
+ // add a requested
+ aaRole.incRequested()
+ aaRole.setPendingAntiAffineRequests(aarole_pending)
+ assert aaRole.pendingAntiAffineRequests == aarole_pending
+
+ assert aaRole.actualAndRequested == aarole_actual + 1
StringWriter sw = new StringWriter(64);
PrintWriter pw = new PrintWriter(sw);
Hamlet hamlet = new Hamlet(pw, 0, false);
-
- int level = hamlet.nestLevel();
+
indexBlock.doIndex(hamlet, "accumulo");
def body = sw.toString()
log.info(body)
- assertEquals(body, level, hamlet.nestLevel())
// verify role data came out
assert body.contains("role0")
- //
- assert body.contains("8")
- assert body.contains("5")
- assert body.contains("3")
- assert body.contains("2")
- assert body.contains("1")
-
+ assertContains(role0_desired, body)
+ assertContains(role0_actual, body)
+ assertContains(role0_requested, body)
+ assertContains(role0_failures, body)
+
assert body.contains("role1")
assert body.contains("role2")
+
+ assertContains(aarole_desired, body)
+ assertContains(aarole_actual, body)
+// assertContains(aarole_requested, body)
+ assertContains(aarole_failures, body)
+ assert body.contains(indexBlock.buildAADetails(true, aarole_pending))
+
// verify that the sorting took place
assert body.indexOf("role0") < body.indexOf("role1")
assert body.indexOf("role1") < body.indexOf("role2")
+
+ assert !body.contains(IndexBlock.ALL_CONTAINERS_ALLOCATED)
+ // role
+ }
+
+ def assertContains(int ex, String html) {
+ assertStringContains(Integer.toString(ex), html)
}
}
\ No newline at end of file
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/management/TestGauges.groovy b/slider-core/src/test/groovy/org/apache/slider/server/management/TestGauges.groovy
new file mode 100644
index 0000000..451bdae
--- /dev/null
+++ b/slider-core/src/test/groovy/org/apache/slider/server/management/TestGauges.groovy
@@ -0,0 +1,52 @@
+/*
+ * 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.slider.server.management
+
+import org.apache.slider.server.appmaster.management.LongGauge
+import org.apache.slider.test.SliderTestBase
+import org.junit.Test
+
+class TestGauges extends SliderTestBase {
+
+ @Test
+ public void testLongGaugeOperations() throws Throwable {
+ LongGauge gauge = new LongGauge();
+ assert gauge.get() == 0
+ gauge.inc()
+ assert gauge.get() == 1
+ gauge.inc()
+ assert gauge.get() == 2
+ gauge.inc()
+ assert gauge.get() == 3
+ assert gauge.getValue() == gauge.get()
+ assert gauge.count == gauge.get()
+
+ gauge.dec()
+ assert gauge.get() == 2
+ assert gauge.decToFloor(1) == 1
+ assert gauge.get() == 1
+ assert gauge.decToFloor(1) == 0
+ assert gauge.decToFloor(1) == 0
+ assert gauge.decToFloor(0) == 0
+
+ gauge.set(4)
+ assert gauge.decToFloor(8) == 0
+
+ }
+}
diff --git a/slider-core/src/test/groovy/org/apache/slider/test/KeysForTests.groovy b/slider-core/src/test/groovy/org/apache/slider/test/KeysForTests.groovy
index 4721552..b4a7ac9 100644
--- a/slider-core/src/test/groovy/org/apache/slider/test/KeysForTests.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/test/KeysForTests.groovy
@@ -33,8 +33,9 @@
String USERNAME = "bigdataborat"
int WAIT_TIME = 120;
- String WAIT_TIME_ARG = WAIT_TIME.toString()
+ String WAIT_TIME_ARG = Integer.toString(WAIT_TIME)
String SLIDER_TEST_XML = "slider-test.xml"
+ String NODES_UPDATED_FLAG_METRIC = "org.apache.slider.server.appmaster.state.RoleHistory.nodes-updated.flag"
}
\ No newline at end of file
diff --git a/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy b/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy
index ae07187..cb6ce0e 100644
--- a/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy
@@ -109,11 +109,29 @@
JsonOutput.prettyPrint(json)
}
+ /**
+ * Convert a JSON string to something readable
+ * @param json
+ * @return a string for printing
+ */
+ public static String prettyPrintAsJson(Object src) {
+ JsonOutput.prettyPrint(JsonOutput.toJson(src))
+ }
+
+ /**
+ * Skip the test with a message
+ * @param message message logged and thrown
+ */
public static void skip(String message) {
log.warn("Skipping test: {}", message)
Assume.assumeTrue(message, false);
}
+ /**
+ * Skip the test with a message if condition holds
+ * @param condition predicate
+ * @param message message logged and thrown
+ */
public static void assume(boolean condition, String message) {
if (!condition) {
skip(message)
@@ -123,18 +141,25 @@
/**
* Skip a test if not running on Windows
*/
- public assumeWindows() {
+ public static void assumeWindows() {
assume(Shell.WINDOWS, "not windows")
}
/**
* Skip a test if running on Windows
*/
- public assumeNotWindows() {
+ public static void assumeNotWindows() {
assume(!Shell.WINDOWS, "windows")
}
/**
+ * skip a test on windows
+ */
+ public static void skipOnWindows() {
+ assumeNotWindows();
+ }
+
+ /**
* Equality size for a list
* @param left
* @param right
@@ -234,15 +259,6 @@
}
/**
- * skip a test on windows
- */
- public static void skipOnWindows() {
- if (Shell.WINDOWS) {
- skip("Not supported on windows")
- }
- }
-
- /**
* Assert that any needed libraries being present. On Unix none are needed;
* on windows they must be present
*/
@@ -621,7 +637,6 @@
static UrlConnectionOperations connectionOperations
static UgiJerseyBinding jerseyBinding;
-
/**
* Static initializer of the connection operations
* @param conf config
@@ -869,6 +884,29 @@
log.info("$realkey = $val")
return val
}
+ /**
+ * Create a temp JSON file. After coming up with the name, the file
+ * is deleted
+ * @return the filename
+ */
+ public static File createTempJsonFile() {
+ return tmpFile(".json")
+ }
+
+ /**
+ * Create a temp file with the specific name. It's deleted after creation,
+ * to avoid "file exists exceptions"
+ * @param suffix suffix, e.g. ".txt"
+ * @return a path to a file which may be created
+ */
+ public static File tmpFile(String suffix) {
+ File reportFile = File.createTempFile(
+ "temp",
+ suffix,
+ new File("target"))
+ reportFile.delete()
+ return reportFile
+ }
/**
* Execute a closure, assert it fails with a given exit code and text
@@ -1442,15 +1480,16 @@
/**
* Await a specific gauge being of the desired value
- * @param target target URL
+ * @param am URL of appmaster
* @param gauge gauge name
* @param desiredValue desired value
* @param timeout timeout in millis
* @param sleepDur sleep in millis
*/
- public void awaitGaugeValue(String target, String gauge, int desiredValue,
+ public void awaitGaugeValue(String am, String gauge, int desiredValue,
int timeout,
int sleepDur) {
+ String target = appendToURL(am, SYSTEM_METRICS_JSON)
def text = "Probe $target for gauge $gauge == $desiredValue"
repeatUntilSuccess(text,
this.&probeMetricGaugeValue,
@@ -1465,6 +1504,13 @@
}
}
+ /**
+ * Probe for a metric gauge holding a value.
+ *
+ * Keys: "url:String", "gauge:String", "desiredValue:int"
+ * @param args argument map
+ * @return success on the desired value, retry if not; fail on IOE
+ */
Outcome probeMetricGaugeValue(Map args) {
String url = requiredMapValue(args, "url")
String gauge = requiredMapValue(args, "gauge")
@@ -1481,4 +1527,13 @@
}
}
+ public static void assertStringContains(String expected, String text) {
+ assertNotNull("null text", text)
+ if (!text.contains(expected)) {
+ def message = "id not find $expected in \"$text\""
+ log.error(message)
+ fail(message)
+ }
+
+ }
}
diff --git a/slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/agent/TestAMAgentWebServices.java b/slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/agent/TestAMAgentWebServices.java
index 4c43168..7237ff4 100644
--- a/slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/agent/TestAMAgentWebServices.java
+++ b/slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/agent/TestAMAgentWebServices.java
@@ -24,10 +24,10 @@
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.json.JSONConfiguration;
-import junit.framework.Assert;
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.slider.common.SliderKeys;
@@ -35,10 +35,12 @@
import org.apache.slider.core.conf.MapOperations;
import org.apache.slider.core.exceptions.SliderException;
import org.apache.slider.server.appmaster.management.MetricsAndMonitoring;
+import org.apache.slider.server.appmaster.model.mock.MockAppState;
import org.apache.slider.server.appmaster.model.mock.MockFactory;
import org.apache.slider.server.appmaster.model.mock.MockProviderService;
import org.apache.slider.server.appmaster.model.mock.MockClusterServices;
import org.apache.slider.server.appmaster.state.AppState;
+import org.apache.slider.server.appmaster.state.AppStateBindingInfo;
import org.apache.slider.server.appmaster.state.ProviderAppState;
import org.apache.slider.server.appmaster.state.SimpleReleaseSelector;
import org.apache.slider.server.appmaster.web.WebAppApi;
@@ -71,26 +73,19 @@
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
- if (hostname.equals("localhost")) {
- return true;
- }
- return false;
+ return hostname.equals("localhost");
}
});
-
}
protected static final Logger log =
LoggerFactory.getLogger(TestAMAgentWebServices.class);
- public static final int RM_MAX_RAM = 4096;
- public static final int RM_MAX_CORES = 64;
public static final String AGENT_URL =
"https://localhost:${PORT}/ws/v1/slider/agents/";
static MockFactory factory = new MockFactory();
- private static Configuration conf = new Configuration();
private static WebAppApi slider;
private static FileSystem fs;
@@ -117,28 +112,16 @@
YarnConfiguration conf = SliderUtils.createConfiguration();
fs = FileSystem.get(new URI("file:///"), conf);
AppState appState = null;
- try {
- fs = FileSystem.get(new URI("file:///"), conf);
- File
- historyWorkDir =
- new File("target/history", "TestAMAgentWebServices");
- org.apache.hadoop.fs.Path
- historyPath =
- new org.apache.hadoop.fs.Path(historyWorkDir.toURI());
- fs.delete(historyPath, true);
- appState = new AppState(new MockClusterServices(), new MetricsAndMonitoring());
- appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES);
- appState.buildInstance(
- factory.newInstanceDefinition(0, 0, 0),
- new Configuration(),
- new Configuration(false),
- factory.ROLES,
- fs,
- historyPath,
- null, null, new SimpleReleaseSelector());
- } catch (Exception e) {
- log.error("Failed to set up app {}", e, e);
- }
+ File historyWorkDir = new File("target/history", "TestAMAgentWebServices");
+ Path historyPath = new Path(historyWorkDir.toURI());
+ fs.delete(historyPath, true);
+ appState = new MockAppState(new MockClusterServices());
+ AppStateBindingInfo binding = new AppStateBindingInfo();
+ binding.instanceDefinition = factory.newInstanceDefinition(0, 0, 0);
+ binding.roles = MockFactory.ROLES;
+ binding.fs = fs;
+ binding.historyPath = historyPath;
+ appState.buildInstance(binding);
ProviderAppState providerAppState = new ProviderAppState("undefined",
appState);
@@ -173,7 +156,7 @@
WebResource webResource = client.resource(base_url + "test/register");
response = webResource.type(MediaType.APPLICATION_JSON)
.post(RegistrationResponse.class, createDummyJSONRegister());
- Assert.assertEquals(RegistrationStatus.OK, response.getResponseStatus());
+ assertEquals(RegistrationStatus.OK, response.getResponseStatus());
}
protected Client createTestClient() {
diff --git a/slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/management/TestAMManagementWebServices.java b/slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/management/TestAMManagementWebServices.java
index df7e002..49ad71a 100644
--- a/slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/management/TestAMManagementWebServices.java
+++ b/slider-core/src/test/java/org/apache/slider/server/appmaster/web/rest/management/TestAMManagementWebServices.java
@@ -31,7 +31,6 @@
import com.sun.jersey.test.framework.WebAppDescriptor;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
import org.apache.slider.common.tools.SliderUtils;
import org.apache.slider.core.conf.AggregateConf;
@@ -39,13 +38,13 @@
import org.apache.slider.core.exceptions.BadClusterStateException;
import org.apache.slider.core.exceptions.BadConfigException;
import org.apache.slider.core.persist.JsonSerDeser;
-import org.apache.slider.server.appmaster.management.MetricsAndMonitoring;
+import org.apache.slider.server.appmaster.model.mock.MockAppState;
+import org.apache.slider.server.appmaster.model.mock.MockClusterServices;
import org.apache.slider.server.appmaster.model.mock.MockFactory;
import org.apache.slider.server.appmaster.model.mock.MockProviderService;
-import org.apache.slider.server.appmaster.model.mock.MockClusterServices;
import org.apache.slider.server.appmaster.state.AppState;
+import org.apache.slider.server.appmaster.state.AppStateBindingInfo;
import org.apache.slider.server.appmaster.state.ProviderAppState;
-import org.apache.slider.server.appmaster.state.SimpleReleaseSelector;
import org.apache.slider.server.appmaster.web.WebAppApi;
import org.apache.slider.server.appmaster.web.WebAppApiImpl;
import org.apache.slider.server.appmaster.web.rest.AMWebServices;
@@ -67,15 +66,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertTrue;
public class TestAMManagementWebServices extends JerseyTest {
protected static final Logger log =
LoggerFactory.getLogger(TestAMManagementWebServices.class);
- public static final int RM_MAX_RAM = 4096;
- public static final int RM_MAX_CORES = 64;
- public static final String EXAMPLES =
- "/org/apache/slider/core/conf/examples/";
+ public static final String EXAMPLES = "/org/apache/slider/core/conf/examples/";
static MockFactory factory = new MockFactory();
private static Configuration conf = new Configuration();
private static WebAppApi slider;
@@ -116,40 +112,27 @@
}
protected AggregateConf getAggregateConf() {
- JsonSerDeser<ConfTree> confTreeJsonSerDeser =
- new JsonSerDeser<ConfTree>(ConfTree.class);
- ConfTree internal = null;
- ConfTree app_conf = null;
- ConfTree resources = null;
try {
- internal =
- confTreeJsonSerDeser.fromResource(
- EXAMPLES +"internal.json");
- app_conf =
- confTreeJsonSerDeser.fromResource(
- EXAMPLES + "app_configuration.json");
- resources =
- confTreeJsonSerDeser.fromResource(
- EXAMPLES + "resources.json");
+ JsonSerDeser<ConfTree> confTreeJsonSerDeser = new JsonSerDeser<>(ConfTree.class);
+ AggregateConf aggregateConf = new AggregateConf(
+ confTreeJsonSerDeser.fromResource(EXAMPLES + "resources.json"),
+ confTreeJsonSerDeser.fromResource(EXAMPLES + "app_configuration.json"),
+ confTreeJsonSerDeser.fromResource(EXAMPLES + "internal.json")
+ );
+ aggregateConf.setName("test");
+ return aggregateConf;
} catch (IOException e) {
- fail(e.getMessage());
+ throw new AssertionError(e.getMessage(), e);
}
- AggregateConf aggregateConf = new AggregateConf(
- resources,
- app_conf,
- internal);
- aggregateConf.setName("test");
- return aggregateConf;
}
-
}
+
@Before
@Override
public void setUp() throws Exception {
super.setUp();
injector = createInjector();
- YarnConfiguration conf = SliderUtils.createConfiguration();
- fs = FileSystem.get(new URI("file:///"), conf);
+ fs = FileSystem.get(new URI("file:///"), SliderUtils.createConfiguration());
}
private static Injector createInjector() {
@@ -160,23 +143,17 @@
AppState appState = null;
try {
fs = FileSystem.get(new URI("file:///"), conf);
- File
- historyWorkDir =
- new File("target/history", "TestAMManagementWebServices");
- org.apache.hadoop.fs.Path
- historyPath =
+ File historyWorkDir = new File("target/history", "TestAMManagementWebServices");
+ org.apache.hadoop.fs.Path historyPath =
new org.apache.hadoop.fs.Path(historyWorkDir.toURI());
fs.delete(historyPath, true);
- appState = new AppState(new MockClusterServices(), new MetricsAndMonitoring());
- appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES);
- appState.buildInstance(
- factory.newInstanceDefinition(0, 0, 0),
- new Configuration(),
- new Configuration(false),
- factory.ROLES,
- fs,
- historyPath,
- null, null, new SimpleReleaseSelector());
+ appState = new MockAppState(new MockClusterServices());
+ AppStateBindingInfo binding = new AppStateBindingInfo();
+ binding.instanceDefinition = factory.newInstanceDefinition(0, 0, 0);
+ binding.roles = MockFactory.ROLES;
+ binding.fs = fs;
+ binding.historyPath = historyPath;
+ appState.buildInstance(binding);
} catch (IOException | BadClusterStateException | URISyntaxException | BadConfigException e) {
log.error("{}", e, e);
}
@@ -239,9 +216,19 @@
assertEquals("wrong href",
"http://localhost:9998/slideram/ws/v1/slider/mgmt/app/configurations/internal",
json.getHref());
- assertEquals("wrong description",
- "Internal configuration DO NOT EDIT",
- json.getMetadata().get("description"));
+
+ assertDescriptionContains("org/apache/slider/core/conf/examples/internal.json", json);
+ }
+
+ private void assertDescriptionContains(String expected, ConfTreeResource json) {
+
+ Map<String, Object> metadata = json.getMetadata();
+ assertNotNull("No metadata", metadata);
+ Object actual = metadata.get("description");
+ assertNotNull("No description", actual);
+
+ assertTrue(String.format("Did not find \"%s\" in \"%s\"", expected, actual),
+ actual.toString().contains(expected));
}
@Test
@@ -263,6 +250,7 @@
assertNotNull("no components", components);
assertEquals("incorrect number of components", 2, components.size());
assertNotNull("wrong component", components.get("worker"));
+ assertDescriptionContains("org/apache/slider/core/conf/examples/resources.json", json);
}
@Test
@@ -283,5 +271,7 @@
assertNotNull("no components", components);
assertEquals("incorrect number of components", 2, components.size());
assertNotNull("wrong component", components.get("worker"));
+ assertDescriptionContains("org/apache/slider/core/conf/examples/app_configuration.json", json);
+
}
}
diff --git a/slider-core/src/test/python/agent.py b/slider-core/src/test/python/agent.py
index 4177074..1c9ff5b 100644
--- a/slider-core/src/test/python/agent.py
+++ b/slider-core/src/test/python/agent.py
@@ -24,14 +24,21 @@
from optparse import OptionParser
import os
+
# A representative Agent code for the embedded agent
def main():
- print "Executing echo"
- print 'Argument List: {0}'.format(str(sys.argv))
+ print "Executing src/test/python/agent.py"
+ try:
+ print 'Argument List: {0}'.format(str(sys.argv))
+ except AttributeError:
+ pass
parser = OptionParser()
parser.add_option("--log", dest="log_folder", help="log destination")
parser.add_option("--config", dest="conf_folder", help="conf folder")
+ parser.add_option('--sleep', dest='sleep', help='sleep time')
+ parser.add_option('--exitcode', dest='exitcode', help='exit code to return')
+
(options, args) = parser.parse_args()
if options.log_folder:
@@ -43,9 +50,17 @@
logging.info("Number of arguments: %s arguments.", str(len(sys.argv)))
logging.info("Argument List: %s", str(sys.argv))
- time.sleep(30)
+ sleeptime = 30
+ if options.sleep:
+ sleeptime = int(options.sleep)
+ if sleeptime > 0:
+ logging.info("Sleeping for %d seconds", sleeptime)
+ time.sleep(sleeptime)
+ exitcode = 0
+ if options.exitcode:
+ exitcode = int(options.exitcode)
+ return exitcode
if __name__ == "__main__":
- main()
- sys.exit(0)
+ sys.exit(main())
diff --git a/slider-core/src/test/python/agent/main.py b/slider-core/src/test/python/agent/main.py
index 116d179..2eacc89 100755
--- a/slider-core/src/test/python/agent/main.py
+++ b/slider-core/src/test/python/agent/main.py
@@ -26,7 +26,7 @@
def main():
- print "Executing echo"
+ print "Executing src/test/python/agent/main.py"
try:
print 'Argument List: {0}'.format(str(sys.argv))
except AttributeError:
@@ -37,6 +37,8 @@
parser.add_option("--config", dest="conf_folder", help="conf folder")
parser.add_option('--command', dest='command', help='command to execute')
parser.add_option('--label', dest='label', help='label')
+ parser.add_option('--sleep', dest='sleep', help='sleep time')
+ parser.add_option('--exitcode', dest='exitcode', help='exit code to return')
parser.add_option('--zk-quorum', dest='host:2181', help='zookeeper quorum')
parser.add_option('--zk-reg-path', dest='/register/org-apache-slider/cl1', help='zookeeper registry path')
@@ -51,9 +53,17 @@
logging.info("Number of arguments: %s arguments.", str(len(sys.argv)))
logging.info("Argument List: %s", str(sys.argv))
- time.sleep(30)
+ sleeptime = 300
+ if options.sleep:
+ sleeptime = int(options.sleep)
+ if sleeptime > 0:
+ logging.info("Sleeping for %d seconds", sleeptime)
+ time.sleep(sleeptime)
+ exitcode = 0
+ if options.exitcode:
+ exitcode = int(options.exitcode)
+ return exitcode
if __name__ == "__main__":
- main()
- sys.exit(0)
+ sys.exit(main())
diff --git a/slider-core/src/test/python/echo.py b/slider-core/src/test/python/echo.py
index ea5e8ce..1dabf1c 100644
--- a/slider-core/src/test/python/echo.py
+++ b/slider-core/src/test/python/echo.py
@@ -26,13 +26,18 @@
def main():
- print "Executing echo"
- print 'Argument List: {0}'.format(str(sys.argv))
+ print "Executing src/test/python/echo.py"
+ try:
+ print 'Argument List: {0}'.format(str(sys.argv))
+ except AttributeError:
+ pass
parser = OptionParser()
parser.add_option("--log", dest="log_folder", help="log destination")
parser.add_option("--config", dest="conf_folder", help="conf folder")
parser.add_option('--command', dest='command', help='command to execute')
+ parser.add_option('--sleep', dest='sleep', help='sleep time')
+ parser.add_option('--exitcode', dest='exitcode', help='exit code to return')
(options, args) = parser.parse_args()
if options.log_folder:
@@ -44,9 +49,17 @@
logging.info("Number of arguments: %s arguments.", str(len(sys.argv)))
logging.info("Argument List: %s", str(sys.argv))
- time.sleep(30)
+ sleeptime = 300
+ if options.sleep:
+ sleeptime = int(options.sleep)
+ if sleeptime > 0:
+ logging.info("Sleeping for %d seconds", sleeptime)
+ time.sleep(sleeptime)
+ exitcode = 0
+ if options.exitcode:
+ exitcode = int(options.exitcode)
+ return exitcode
if __name__ == "__main__":
- main()
- sys.exit(0)
+ sys.exit(main())
diff --git a/slider-core/src/test/python/metainfo.xml b/slider-core/src/test/python/metainfo.xml
index cf4afe1..b7251d3 100644
--- a/slider-core/src/test/python/metainfo.xml
+++ b/slider-core/src/test/python/metainfo.xml
@@ -24,7 +24,7 @@
</comment>
<version>0.1</version>
<type>YARN-APP</type>
- <minHadoopVersion>2.1.0</minHadoopVersion>
+ <minHadoopVersion>2.6.0</minHadoopVersion>
<components>
<component>
<name>hbase-rs</name>
@@ -51,7 +51,7 @@
<name>echo</name>
<category>MASTER</category>
<minInstanceCount>1</minInstanceCount>
- <maxInstanceCount>2</maxInstanceCount>
+ <maxInstanceCount>100</maxInstanceCount>
<commandScript>
<script>echo.py</script>
<scriptType>PYTHON</scriptType>
diff --git a/slider-core/src/test/resources/example-slider-test.xml b/slider-core/src/test/resources/example-slider-test.xml
index abf42f9..ee9fc59 100644
--- a/slider-core/src/test/resources/example-slider-test.xml
+++ b/slider-core/src/test/resources/example-slider-test.xml
@@ -33,12 +33,6 @@
</property>
<property>
- <name>slider.test.teardown.killall</name>
- <description>Kill all hbase/accumulo, etc processes on test teardown</description>
- <value>true</value>
- </property>
-
- <property>
<name>slider.test.thaw.wait.seconds</name>
<description>Time to wait for a start to work</description>
<value>60</value>
@@ -50,68 +44,4 @@
<value>60</value>
</property>
-
- <!-- Properties for the slider-hbase-provider only -not HBase-under-agent- -->
- <property>
- <name>slider.test.hbase.enabled</name>
- <description>Flag to enable/disable HBase tests</description>
- <value>true</value>
- </property>
-
- <property>
- <name>slider.test.hbase.launch.wait.seconds</name>
- <description>Time to wait for the HBase application to be live</description>
- <value>180</value>
- </property>
-
- <property>
- <name>slider.test.hbase.home</name>
- <value>/home/slider/Projects/hbase/hbase-assembly/target/hbase-0.98.1</value>
- <description>HBASE Home</description>
- </property>
-
- <property>
- <name>slider.test.hbase.tar</name>
- <value>/home/slider/Projects/hbase/hbase-assembly/target/hbase-0.98.1-bin.tar.gz</value>
- <description>HBASE archive URI</description>
- </property>
-
- <!-- Properties for the slider-accumulo-provider only -not HBase-under-agent- -->
-
- <property>
- <name>slider.test.accumulo.enabled</name>
- <description>Flag to enable/disable Accumulo tests</description>
- <value>true</value>
- </property>
-
- <property>
- <name>slider.test.accumulo.launch.wait.seconds</name>
- <description>Time to wait for the accumulo application to be live</description>
- <value>180</value>
- </property>
-
- <property>
- <name>slider.test.accumulo.home</name>
- <value>/home/slider/accumulo</value>
- <description>Accumulo Home</description>
- </property>
-
- <property>
- <name>slider.test.accumulo.tar</name>
- <value>/home/slider/Projects/accumulo/accumulo-1.6.0-bin.tar.gz</value>
- <description>Accumulo archive URI</description>
- </property>
-
- <property>
- <name>zk.home</name>
- <value>/home/slider/zookeeper</value>
- <description>Zookeeper home dir on target systems</description>
- </property>
-
- <property>
- <name>hadoop.home</name>
- <value>/home/slider/hadoop/</value>
- <description>Hadoop home dir on target systems</description>
- </property>
-
</configuration>
diff --git a/slider-core/src/test/resources/log4j.properties b/slider-core/src/test/resources/log4j.properties
index ed19a5b..5858f55 100644
--- a/slider-core/src/test/resources/log4j.properties
+++ b/slider-core/src/test/resources/log4j.properties
@@ -38,6 +38,7 @@
#crank back on some noise
log4j.logger.org.apache.hadoop.util.Shell=ERROR
log4j.logger.org.apache.hadoop.util.NativeCodeLoader=ERROR
+log4j.logger.org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager=FATAL
log4j.logger.org.apache.hadoop.hdfs.server.datanode.BlockPoolSliceScanner=WARN
log4j.logger.org.apache.hadoop.hdfs.server.blockmanagement=WARN
log4j.logger.org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit=WARN
@@ -49,6 +50,7 @@
log4j.logger.org.apache.zookeeper=WARN
log4j.logger.org.apache.zookeeper.ClientCnxn=FATAL
+log4j.logger.org.apache.hadoop.yarn.server.nodemanager.NodeResourceMonitorImpl=ERROR
log4j.logger.org.apache.hadoop.yarn.server.resourcemanager.security=WARN
log4j.logger.org.apache.hadoop.metrics2=ERROR
log4j.logger.org.apache.hadoop.util.HostsFileReader=WARN
diff --git a/slider-core/src/test/resources/org/apache/slider/core/conf/examples/app_configuration.json b/slider-core/src/test/resources/org/apache/slider/core/conf/examples/app_configuration.json
index 489acda..5690225 100644
--- a/slider-core/src/test/resources/org/apache/slider/core/conf/examples/app_configuration.json
+++ b/slider-core/src/test/resources/org/apache/slider/core/conf/examples/app_configuration.json
@@ -1,6 +1,8 @@
{
"schema": "http://example.org/specification/v2.0.0",
-
+ "metadata": {
+ "description": "org/apache/slider/core/conf/examples/app_configuration.json"
+ },
"global": {
"zookeeper.port": "2181",
diff --git a/slider-core/src/test/resources/org/apache/slider/core/conf/examples/internal-resolved.json b/slider-core/src/test/resources/org/apache/slider/core/conf/examples/internal-resolved.json
index 592b4dc..da53b94 100644
--- a/slider-core/src/test/resources/org/apache/slider/core/conf/examples/internal-resolved.json
+++ b/slider-core/src/test/resources/org/apache/slider/core/conf/examples/internal-resolved.json
@@ -2,7 +2,7 @@
"schema": "http://example.org/specification/v2.0.0",
"metadata": {
- "description": "Internal configuration DO NOT EDIT"
+ "description": "Internal resolved - org/apache/slider/core/conf/examples/internal-resolved.json"
},
"global": {
"application.name": "small_cluster",
diff --git a/slider-core/src/test/resources/org/apache/slider/core/conf/examples/internal.json b/slider-core/src/test/resources/org/apache/slider/core/conf/examples/internal.json
index 4c782fb..b628d10 100644
--- a/slider-core/src/test/resources/org/apache/slider/core/conf/examples/internal.json
+++ b/slider-core/src/test/resources/org/apache/slider/core/conf/examples/internal.json
@@ -2,7 +2,7 @@
"schema": "http://example.org/specification/v2.0.0",
"metadata": {
- "description": "Internal configuration DO NOT EDIT"
+ "description": "Internal unresolved - org/apache/slider/core/conf/examples/internal.json"
},
"global": {
"application.name": "small_cluster",
diff --git a/slider-core/src/test/resources/org/apache/slider/core/conf/examples/resources.json b/slider-core/src/test/resources/org/apache/slider/core/conf/examples/resources.json
index 9d1e916..206424d 100644
--- a/slider-core/src/test/resources/org/apache/slider/core/conf/examples/resources.json
+++ b/slider-core/src/test/resources/org/apache/slider/core/conf/examples/resources.json
@@ -2,7 +2,7 @@
"schema": "http://example.org/specification/v2.0.0",
"metadata": {
- "description": "example of a resources file"
+ "description": "example of a resources file: org/apache/slider/core/conf/examples/resources.json"
},
"global": {
diff --git a/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy b/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy
index d3a6680..5fa4c2a 100644
--- a/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy
+++ b/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy
@@ -29,15 +29,17 @@
import org.apache.hadoop.yarn.api.records.YarnApplicationState
import org.apache.hadoop.yarn.conf.YarnConfiguration
import org.apache.slider.api.StatusKeys
-import org.apache.slider.common.tools.ConfigHelper
-import org.apache.slider.core.launch.SerializedApplicationReport
-import org.apache.slider.core.main.ServiceLauncher
+import org.apache.slider.api.types.NodeInformationList
+import org.apache.slider.client.SliderClient
import org.apache.slider.common.SliderKeys
import org.apache.slider.common.SliderXmlConfKeys
import org.apache.slider.api.ClusterDescription
+import org.apache.slider.common.tools.ConfigHelper
import org.apache.slider.common.tools.SliderUtils
-import org.apache.slider.client.SliderClient
+import org.apache.slider.core.launch.SerializedApplicationReport
+import org.apache.slider.core.main.ServiceLauncher
import org.apache.slider.core.persist.ApplicationReportSerDeser
+import org.apache.slider.core.persist.JsonSerDeser
import org.apache.slider.test.SliderTestUtils
import org.apache.slider.test.Outcome;
@@ -88,7 +90,6 @@
* Keytab for secure cluster
*/
public static final String TEST_AM_KEYTAB
- static File keytabFile
/**
* shell-escaped ~ symbol. On windows this does
@@ -207,7 +208,7 @@
return false;
}
}
-
+
/**
* Add a jar to the slider classpath by looking up a class and determining
* its containing JAR
@@ -326,7 +327,6 @@
])
}
-
static SliderShell freeze(
int exitCode,
String name,
@@ -360,9 +360,9 @@
static SliderShell killContainer(String name, String containerID) {
slider(0,
[
- ACTION_KILL_CONTAINER,
- name,
- containerID
+ ACTION_KILL_CONTAINER,
+ name,
+ containerID
])
}
@@ -441,9 +441,7 @@
}
static SliderShell registry(Collection<String> commands) {
- slider(0,
- [ACTION_REGISTRY] + commands
- )
+ slider(0, [ACTION_REGISTRY] + commands)
}
/**
@@ -573,7 +571,7 @@
List<String> argsList = [action, clustername]
argsList << ARG_ZKHOSTS <<
- SLIDER_CONFIG.getTrimmed(RegistryConstants.KEY_REGISTRY_ZK_QUORUM)
+ SLIDER_CONFIG.getTrimmed(RegistryConstants.KEY_REGISTRY_ZK_QUORUM)
if (blockUntilRunning) {
@@ -775,24 +773,6 @@
}
/**
- * Create a temp JSON file. After coming up with the name, the file
- * is deleted
- * @return the filename
- */
- public static File createTempJsonFile() {
- return tmpFile(".json")
- }
-
- public static File tmpFile(String suffix) {
- File reportFile = File.createTempFile(
- "launch",
- suffix,
- new File("target"))
- reportFile.delete()
- return reportFile
- }
-
- /**
* If the option is not null/empty, add the command and the option
* @param args arg list being built up
* @param command command to add option
@@ -813,20 +793,20 @@
ApplicationReportSerDeser serDeser = new ApplicationReportSerDeser()
def report = serDeser.fromFile(reportFile)
return report
- }
+ }
return null;
- }
-
+ }
+
public static SerializedApplicationReport loadAppReport(File reportFile) {
- if (reportFile.exists() && reportFile.length()> 0) {
+ if (reportFile.exists() && reportFile.length() > 0) {
ApplicationReportSerDeser serDeser = new ApplicationReportSerDeser()
def report = serDeser.fromFile(reportFile)
return report
- } else {
+ }else {
throw new FileNotFoundException(reportFile.absolutePath)
- }
- }
-
+ }
+ }
+
public static SerializedApplicationReport maybeLookupFromLaunchReport(File launchReport) {
def report = maybeLoadAppReport(launchReport)
if (report) {
@@ -857,7 +837,50 @@
}
}
-
+ /**
+ * Lookup an application, return null if loading failed
+ * @param id application ID
+ * @return an application report or null
+ */
+ public static NodeInformationList listNodes(String name = "", boolean healthy = false, String label = "") {
+ File reportFile = createTempJsonFile();
+ try {
+ def shell = nodes(name, reportFile, healthy, label)
+ if (log.isDebugEnabled()) {
+ shell.dumpOutput()
+ }
+ JsonSerDeser<NodeInformationList> serDeser = NodeInformationList.createSerializer();
+ serDeser.fromFile(reportFile)
+ } finally {
+ reportFile.delete()
+ }
+ }
+
+ /**
+ * List cluster nodes
+ * @param name of cluster or null
+ * @param out output file (or null)
+ * @param healthy list healthy nodes only
+ * @param label label to filter on
+ * @return output
+ */
+ static SliderShell nodes(String name, File out = null, boolean healthy = false, String label = "") {
+ def commands = [ACTION_NODES]
+ if (label) {
+ commands += [ ARG_LABEL, label]
+ }
+ if (name) {
+ commands << name
+ }
+ if (out) {
+ commands += [ARG_OUTPUT, out.absolutePath]
+ }
+ if (healthy) {
+ commands << ARG_HEALTHY
+ }
+ slider(0, commands)
+ }
+
public Path buildClusterPath(String clustername) {
return new Path(
clusterFS.homeDirectory,
@@ -931,11 +954,7 @@
}
// trigger a failure on registry lookup
- SliderShell shell = registry(0, [
- ARG_NAME,
- application,
- ARG_LISTEXP
- ])
+ registry(0, [ARG_NAME, application, ARG_LISTEXP])
}
}
@@ -1206,7 +1225,6 @@
}
public ClusterDescription execStatus(String application) {
- ClusterDescription cd
File statusFile = File.createTempFile("status", ".json")
try {
slider(EXIT_SUCCESS,
@@ -1280,6 +1298,13 @@
}
}
+ /**
+ * Assert that exactly the number of containers are live
+ * @param clustername name of cluster
+ * @param component component to probe
+ * @param count count
+ * @return
+ */
public ClusterDescription assertContainersLive(String clustername,
String component,
int count) {
@@ -1426,8 +1451,8 @@
}
/**
- * Is the registry accessible for an application?
- * @param args argument map containing <code>"application"</code>
+ * probe for the output {@code command: List} containing {@code text}
+ * @param args argument map containing the required parameters
* @return probe outcome
*/
protected Outcome commandOutputContains(Map args) {
@@ -1436,9 +1461,10 @@
SliderShell shell = slider(0, command)
return Outcome.fromBool(shell.outputContains(text))
}
+
/**
- * Is the registry accessible for an application?
- * @param args argument map containing <code>"application"</code>
+ * probe for a command {@code command: List} succeeeding
+ * @param args argument map containing the required parameters
* @return probe outcome
*/
protected Outcome commandSucceeds(Map args) {
@@ -1446,9 +1472,11 @@
SliderShell shell = slider(command)
return Outcome.fromBool(shell.ret == 0)
}
+
/**
- * Is the registry accessible for an application?
- * @param args argument map
+ * probe for a command {@code command: List} generating a file 'filename'
+ * which must contain the text 'text'
+ * @param args argument map containing the required parameters
* @return probe outcome
*/
protected Outcome generatedFileContains(Map args) {
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/ResourcePaths.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/ResourcePaths.groovy
new file mode 100644
index 0000000..5de2b8e
--- /dev/null
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/ResourcePaths.groovy
@@ -0,0 +1,41 @@
+/*
+ * 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.slider.funtest
+
+/**
+ * The various resources used for test runs
+ */
+interface ResourcePaths {
+
+ String SLIDER_CORE_TEST_SRC= "../slider-core/src/test"
+ String SLIDER_CORE_APP_PACKAGES = "$SLIDER_CORE_TEST_SRC/app_packages"
+ String COMMAND_LOG_RESOURCES = "$SLIDER_CORE_APP_PACKAGES/test_command_log/resources.json"
+ String COMMAND_LOG_RESOURCES_QUEUE_LABELS = "$SLIDER_CORE_APP_PACKAGES/test_command_log/resources_queue_labels.json"
+ String COMMAND_LOG_RESOURCES_NO_ROLE = "$SLIDER_CORE_APP_PACKAGES/test_command_log/resources_no_role.json"
+ String COMMAND_LOG_APPCONFIG_NO_HB = "$SLIDER_CORE_APP_PACKAGES/test_command_log/appConfig_no_hb.json"
+ String COMMAND_LOG_APPCONFIG_FAST_NO_REG = "$SLIDER_CORE_APP_PACKAGES/test_command_log/appConfig_fast_no_reg.json"
+
+ String PING_RESOURCES = "$SLIDER_CORE_APP_PACKAGES/test_min_pkg/nc_ping_cmd/resources.json"
+ String PING_META = "$SLIDER_CORE_APP_PACKAGES/test_min_pkg/nc_ping_cmd/metainfo.json"
+ String PING_APPCONFIG = "$SLIDER_CORE_APP_PACKAGES/test_min_pkg/nc_ping_cmd/appConfig.json"
+
+ String SLEEP_RESOURCES = "$SLIDER_CORE_APP_PACKAGES/test_min_pkg/sleep_cmd/resources.json"
+ String SLEEP_META = "$SLIDER_CORE_APP_PACKAGES/test_min_pkg/sleep_cmd/metainfo.json"
+ String SLEEP_APPCONFIG = "$SLIDER_CORE_APP_PACKAGES/test_min_pkg/sleep_cmd/appConfig.json"
+
+}
\ No newline at end of file
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/ClusterConnectivityIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/ClusterConnectivityIT.groovy
index 9826e97..5d069bc 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/ClusterConnectivityIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/ClusterConnectivityIT.groovy
@@ -37,7 +37,6 @@
*/
class ClusterConnectivityIT extends CommandTestBase {
-
public static final int CONNECT_TIMEOUT = 2000
@Test
@@ -60,7 +59,7 @@
tuples.each {
telnet(it.hostText, it.port)
}
-
+
}
@Test
@@ -73,7 +72,7 @@
telnet(rmAddr.hostName, rmAddr.port)
}
}
-
+
@Test
public void testRMBinding() throws Throwable {
SliderYarnClientImpl yarnClient = new SliderYarnClientImpl()
@@ -83,10 +82,10 @@
YarnConfiguration.RESOURCEMANAGER_CONNECT_MAX_WAIT_MS,5000)
SLIDER_CONFIG.setInt(
YarnConfiguration.RESOURCEMANAGER_CONNECT_RETRY_INTERVAL_MS,50)
-
+
yarnClient.init(SLIDER_CONFIG)
yarnClient.start();
- def instances = yarnClient.listInstances("")
+ def instances = yarnClient.listDeployedInstances("")
instances.each {it -> log.info("Instance $it.applicationId")}
} finally {
yarnClient.stop()
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/ComponentConfigsInAppConfigShowUpOnAgentIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/ComponentConfigsInAppConfigShowUpOnAgentIT.groovy
index cf74bbf..91797f9 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/ComponentConfigsInAppConfigShowUpOnAgentIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/ComponentConfigsInAppConfigShowUpOnAgentIT.groovy
@@ -23,9 +23,6 @@
import org.apache.slider.common.tools.SliderUtils
import org.apache.slider.funtest.framework.AgentCommandTestBase
-import org.apache.slider.common.params.SliderActions
-import org.apache.slider.client.SliderClient
-import org.apache.slider.common.SliderExitCodes
import org.apache.slider.funtest.framework.SliderShell
import org.junit.After
import org.junit.Before
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/SyspropsIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/SyspropsIT.groovy
index 728920e..e53c875 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/SyspropsIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/basic/SyspropsIT.groovy
@@ -36,11 +36,10 @@
@Slf4j
class SyspropsIT extends SliderTestUtils{
-
@Test
public void testDumpSysprops() throws Throwable {
def sysprops = System.properties
- TreeSet<String> sorted = new TreeSet<String>();
+ TreeSet<String> sorted = new TreeSet<>();
sysprops.keys().each { String it -> sorted.add(it)}
sorted.each { String key ->
log.info("$key=\"${sysprops[key]}\"")
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/CommandExitCodesIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/CommandExitCodesIT.groovy
index 73912e6..666342e 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/CommandExitCodesIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/CommandExitCodesIT.groovy
@@ -20,7 +20,6 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-import org.apache.slider.common.SliderExitCodes
import org.apache.slider.core.main.LauncherExitCodes
import org.apache.slider.funtest.framework.CommandTestBase
import org.junit.Test
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/ListCommandIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/ListCommandIT.groovy
index 916117c..b378110 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/ListCommandIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/ListCommandIT.groovy
@@ -22,7 +22,6 @@
import groovy.util.logging.Slf4j
import org.apache.slider.core.main.LauncherExitCodes
import org.apache.slider.funtest.framework.CommandTestBase
-import org.junit.BeforeClass
import org.junit.Test
@CompileStatic
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/SimpleCommandsIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/SimpleCommandsIT.groovy
index 75d0634..e22c5f2 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/SimpleCommandsIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/commands/SimpleCommandsIT.groovy
@@ -20,9 +20,7 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-import org.apache.bigtop.itest.shell.Shell
import org.apache.slider.funtest.framework.CommandTestBase
-import org.apache.slider.funtest.framework.SliderShell
import org.apache.slider.common.params.SliderActions
import org.junit.Test
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/coprocessors/ApplicationWithAddonPackagesIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/coprocessors/ApplicationWithAddonPackagesIT.groovy
index 43275e6..b32275e 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/coprocessors/ApplicationWithAddonPackagesIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/coprocessors/ApplicationWithAddonPackagesIT.groovy
@@ -18,28 +18,9 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-
-import org.apache.hadoop.security.UserGroupInformation
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.yarn.api.records.YarnApplicationState
-import org.apache.slider.api.ClusterDescription
-import org.apache.slider.api.StatusKeys
-import org.apache.slider.client.SliderClient
-import org.apache.slider.common.SliderExitCodes
-import org.apache.slider.common.SliderXmlConfKeys
import org.apache.slider.common.params.Arguments
-import org.apache.slider.common.params.SliderActions
import org.apache.slider.common.tools.SliderUtils
-import org.apache.slider.funtest.framework.AgentCommandTestBase
-import org.apache.slider.funtest.framework.FuntestProperties
import org.apache.slider.funtest.framework.SliderShell
-import org.apache.slider.funtest.framework.FileUploader
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-
import org.apache.slider.funtest.framework.AgentCommandTestBase
import org.apache.slider.funtest.framework.CommandTestBase
import org.junit.After
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AASleepIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AASleepIT.groovy
new file mode 100644
index 0000000..c42edf8
--- /dev/null
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AASleepIT.groovy
@@ -0,0 +1,161 @@
+/*
+ * 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.slider.funtest.lifecycle
+
+import groovy.transform.CompileStatic
+import groovy.util.logging.Slf4j
+import org.apache.hadoop.yarn.api.records.YarnApplicationState
+import org.apache.slider.api.ClusterDescription
+import org.apache.slider.api.ResourceKeys
+import org.apache.slider.api.RoleKeys
+import org.apache.slider.api.types.NodeEntryInformation
+import org.apache.slider.api.types.NodeInformation
+import org.apache.slider.api.types.NodeInformationList
+import org.apache.slider.common.SliderExitCodes
+import org.apache.slider.common.params.Arguments
+import org.apache.slider.common.params.SliderActions
+import org.apache.slider.core.launch.SerializedApplicationReport
+import org.apache.slider.funtest.ResourcePaths
+import org.apache.slider.funtest.framework.AgentCommandTestBase
+import org.apache.slider.funtest.framework.FuntestProperties
+import org.apache.slider.funtest.framework.SliderShell
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+
+@CompileStatic
+@Slf4j
+public class AASleepIT extends AgentCommandTestBase
+ implements FuntestProperties, Arguments, SliderExitCodes, SliderActions {
+
+ static String NAME = "test-aa-sleep"
+
+ static String TEST_RESOURCE = ResourcePaths.SLEEP_RESOURCES
+ static String TEST_METADATA = ResourcePaths.SLEEP_META
+ public static final String SLEEP_100 = "SLEEP_100"
+ public static final int SLEEP_LONG_PRIORITY = 3
+ public static final String SLEEP_LONG_PRIORITY_S = Integer.toString(SLEEP_LONG_PRIORITY)
+
+ public static final String SLEEP_LONG = "SLEEP_LONG"
+
+ @Before
+ public void prepareCluster() {
+ setupCluster(NAME)
+ }
+
+ @After
+ public void destroyCluster() {
+ cleanup(NAME)
+ }
+
+ @Test
+ public void testAASleepIt() throws Throwable {
+ describe("Test Anti-Affinity Placement")
+
+ describe "diagnostics"
+
+ slider([ACTION_DIAGNOSTICS, ARG_VERBOSE, ARG_CLIENT, ARG_YARN, ARG_CREDENTIALS]).dumpOutput()
+
+ describe "list nodes"
+
+ def healthyNodes = listNodes("", true)
+
+ def healthyNodeCount = healthyNodes.size()
+ describe("Cluster nodes : ${healthyNodeCount}")
+ log.info(NodeInformationList.createSerializer().toJson(healthyNodes))
+
+ File launchReportFile = createTempJsonFile();
+
+ int desired = buildDesiredCount(healthyNodeCount)
+
+ SliderShell shell = createSliderApplicationMinPkg(NAME,
+ TEST_METADATA,
+ TEST_RESOURCE,
+ ResourcePaths.SLEEP_APPCONFIG,
+ [
+ ARG_RES_COMP_OPT, SLEEP_LONG, ResourceKeys.COMPONENT_INSTANCES, Integer.toString( desired),
+ ARG_RES_COMP_OPT, SLEEP_LONG, ResourceKeys.COMPONENT_PRIORITY, SLEEP_LONG_PRIORITY_S
+ ],
+ launchReportFile)
+
+ logShell(shell)
+
+ def appId = ensureYarnApplicationIsUp(launchReportFile)
+
+ status(0, NAME)
+
+ def expected = buildExpectedCount(desired)
+ expectLiveContainerCountReached(NAME, SLEEP_100, expected,
+ CONTAINER_LAUNCH_TIMEOUT)
+
+ operations(NAME, loadAppReport(launchReportFile), desired, expected, healthyNodes)
+
+ //stop
+ freeze(0, NAME,
+ [
+ ARG_WAIT, Integer.toString(FREEZE_WAIT_TIME),
+ ARG_MESSAGE, "final-shutdown"
+ ])
+
+ assertInYarnState(appId, YarnApplicationState.FINISHED)
+ destroy(0, NAME)
+
+ //cluster now missing
+ exists(EXIT_UNKNOWN_INSTANCE, NAME)
+ }
+
+ protected int buildExpectedCount(int desired) {
+ desired - 1
+ }
+
+ protected int buildDesiredCount(int clustersize) {
+ clustersize + 1
+ }
+
+ protected void operations(String name,
+ SerializedApplicationReport appReport,
+ int desired,
+ int expected,
+ NodeInformationList healthyNodes) {
+
+ // now here await for the cluster size to grow: if it does, there's a problem
+ // spin for a while and fail if the number ever goes above it.
+ ClusterDescription cd = null
+ 5.times {
+ cd = assertContainersLive(NAME, SLEEP_LONG, expected)
+ sleep(1000 * 10)
+ }
+
+ // here cluster is still 1 below expected
+ def role = cd.getRole(SLEEP_LONG)
+ assert "1" == role.get(RoleKeys.ROLE_PENDING_AA_INSTANCES)
+
+ // look through the nodes
+ def currentNodes = listNodes(name)
+ // assert that there is no entry of the sleep long priority on any node
+ currentNodes.each { NodeInformation it ->
+ def entry = it.entries[SLEEP_LONG]
+ assert entry == null || entry.live <= 1
+ }
+
+ // now reduce the cluster size and assert that the size stays the same
+
+
+ }
+}
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMClientCertStoreRetrievalIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMClientCertStoreRetrievalIT.groovy
index 950dc68..05adebd 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMClientCertStoreRetrievalIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMClientCertStoreRetrievalIT.groovy
@@ -33,7 +33,6 @@
import org.apache.slider.funtest.framework.FuntestProperties
import org.apache.slider.funtest.framework.SliderShell
import org.junit.After
-import org.junit.Assert
import org.junit.Test
import javax.net.ssl.TrustManager
@@ -47,7 +46,6 @@
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import com.google.common.io.Files
-import java.io.File
@CompileStatic
@Slf4j
@@ -107,7 +105,8 @@
String password = "welcome";
// ensure file doesn't exist
- new File(filename).delete();
+ def keystoreFile = new File(filename)
+ keystoreFile.delete();
shell = slider(EXIT_SUCCESS,
[
@@ -118,7 +117,7 @@
ARG_PASSWORD, password
])
- assert new File(filename).exists()
+ assert keystoreFile.exists()
KeyStore keystore = loadKeystoreFromFile(filename, password.toCharArray())
@@ -126,7 +125,7 @@
filename = myTempDir.canonicalPath + File.separator + "test.truststore"
// ensure file doesn't exist
- new File(filename).delete();
+ keystoreFile.delete();
shell = slider(EXIT_SUCCESS,
[
@@ -137,7 +136,7 @@
ARG_PASSWORD, password
])
- assert new File(filename).exists()
+ assert keystoreFile.exists()
KeyStore truststore = loadKeystoreFromFile(filename, password.toCharArray())
@@ -164,7 +163,7 @@
log.info("Created credential provider $providerString for test")
// ensure file doesn't exist
- new File(filename).delete();
+ keystoreFile.delete();
shell = slider(EXIT_SUCCESS,
[
@@ -176,7 +175,7 @@
ARG_PROVIDER, providerString
])
- assert new File(filename).exists()
+ assert keystoreFile.exists()
keystore = loadKeystoreFromFile(filename, password.toCharArray())
@@ -184,7 +183,7 @@
filename = myTempDir.canonicalPath + File.separator + "test.truststore"
// ensure file doesn't exist
- new File(filename).delete();
+ keystoreFile.delete();
shell = slider(EXIT_SUCCESS,
[
@@ -196,7 +195,7 @@
ARG_PROVIDER, providerString
])
- assert new File(filename).exists()
+ assert keystoreFile.exists()
truststore = loadKeystoreFromFile(filename, password.toCharArray())
@@ -207,7 +206,7 @@
private static void validateKeystore(KeyStore keystore) {
Certificate certificate = keystore.getCertificate(
keystore.aliases().nextElement());
- Assert.assertNotNull(certificate);
+ assert certificate
String hostname = InetAddress.localHost.canonicalHostName;
@@ -217,9 +216,7 @@
// Get subject
Principal principal = x509cert.getSubjectDN();
String subjectDn = principal.getName();
- Assert.assertEquals("wrong DN",
- "CN=" + hostname + ", OU=" + APPLICATION_NAME + ", OU=client",
- subjectDn);
+ assert subjectDn == "CN=" + hostname + ", OU=" + APPLICATION_NAME + ", OU=client"
}
}
@@ -229,7 +226,7 @@
// obtain server cert
Certificate certificate = keystore.getCertificate(
keystore.aliases().nextElement());
- Assert.assertNotNull(certificate);
+ assert certificate
// validate keystore cert using trust store
TrustManagerFactory trustManagerFactory =
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentClientInstallIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentClientInstallIT.groovy
index deb2d97..6d1f759 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentClientInstallIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentClientInstallIT.groovy
@@ -21,19 +21,12 @@
import groovy.io.FileType
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-import org.apache.hadoop.yarn.api.records.YarnApplicationState
-import org.apache.slider.api.ClusterDescription
-import org.apache.slider.api.StatusKeys
-import org.apache.slider.client.SliderClient
import org.apache.slider.common.SliderExitCodes
-import org.apache.slider.common.SliderXmlConfKeys
import org.apache.slider.common.params.Arguments
import org.apache.slider.common.params.SliderActions
import org.apache.slider.funtest.framework.AgentCommandTestBase
import org.apache.slider.funtest.framework.FuntestProperties
import org.apache.slider.funtest.framework.SliderShell
-import org.junit.After
-import org.junit.Before
import org.junit.Test
@CompileStatic
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentClusterLifecycleIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentClusterLifecycleIT.groovy
index ca9f71b..faeb0a1 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentClusterLifecycleIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentClusterLifecycleIT.groovy
@@ -28,6 +28,7 @@
import org.apache.slider.common.SliderXmlConfKeys
import org.apache.slider.common.params.Arguments
import org.apache.slider.common.params.SliderActions
+import org.apache.slider.funtest.ResourcePaths
import org.apache.slider.funtest.framework.AgentCommandTestBase
import org.apache.slider.funtest.framework.FuntestProperties
import org.apache.slider.funtest.framework.SliderShell
@@ -43,7 +44,7 @@
static String CLUSTER = "test-agent-cluster-lifecycle"
- static String APP_RESOURCE2 = "../slider-core/src/test/app_packages/test_command_log/resources_no_role.json"
+ static String APP_RESOURCE2 = ResourcePaths.COMMAND_LOG_RESOURCES_NO_ROLE
@Before
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailures2IT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailures2IT.groovy
index 39b5d6c..d73eb76 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailures2IT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailures2IT.groovy
@@ -23,6 +23,7 @@
import org.apache.slider.common.SliderExitCodes
import org.apache.slider.common.params.Arguments
import org.apache.slider.common.params.SliderActions
+import org.apache.slider.funtest.ResourcePaths
import org.apache.slider.funtest.framework.AgentCommandTestBase
import org.apache.slider.funtest.framework.FuntestProperties
import org.apache.slider.funtest.framework.SliderShell
@@ -36,8 +37,7 @@
private static String COMMAND_LOGGER = "COMMAND_LOGGER"
private static String APPLICATION_NAME = "two-container-fail-heartbeat"
- private static String APP_TEMPLATE3 =
- "../slider-core/src/test/app_packages/test_command_log/appConfig_no_hb.json"
+ private static String APP_TEMPLATE3 = ResourcePaths.COMMAND_LOG_APPCONFIG_NO_HB
@After
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailuresIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailuresIT.groovy
index 7d1be89..cfdff75 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailuresIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailuresIT.groovy
@@ -23,6 +23,7 @@
import org.apache.slider.common.SliderExitCodes
import org.apache.slider.common.params.Arguments
import org.apache.slider.common.params.SliderActions
+import org.apache.slider.funtest.ResourcePaths
import org.apache.slider.funtest.framework.AgentCommandTestBase
import org.apache.slider.funtest.framework.FuntestProperties
import org.apache.slider.funtest.framework.SliderShell
@@ -36,8 +37,7 @@
private static String COMMAND_LOGGER = "COMMAND_LOGGER"
private static String APPLICATION_NAME = "one-container-fail-register"
- private static String APP_TEMPLATE2 =
- "../slider-core/src/test/app_packages/test_command_log/appConfig_fast_no_reg.json"
+ private static String APP_TEMPLATE2 = ResourcePaths.COMMAND_LOG_APPCONFIG_FAST_NO_REG
@After
public void destroyCluster() {
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentLaunchFailureIT_Disabled.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentLaunchFailureIT_Disabled.groovy
index 17eaf04..ee22360 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentLaunchFailureIT_Disabled.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentLaunchFailureIT_Disabled.groovy
@@ -21,6 +21,7 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.apache.slider.common.SliderXmlConfKeys
+import org.apache.slider.funtest.ResourcePaths
import org.apache.slider.server.appmaster.SliderAppMaster
import static org.apache.slider.api.InternalKeys.*
@@ -41,7 +42,7 @@
static String CLUSTER = "test-agent-launchfail"
- static String APP_RESOURCE2 = "../slider-core/src/test/app_packages/test_command_log/resources_no_role.json"
+ static String APP_RESOURCE2 = ResourcePaths.COMMAND_LOG_RESOURCES_NO_ROLE
@Before
public void prepareCluster() {
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentMinSleepIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentMinSleepIT.groovy
index e7b0454..779316b 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentMinSleepIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentMinSleepIT.groovy
@@ -20,18 +20,11 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-import org.apache.hadoop.registry.client.binding.RegistryUtils
-import org.apache.hadoop.registry.client.types.Endpoint
-import org.apache.hadoop.registry.client.types.ServiceRecord
import org.apache.hadoop.yarn.api.records.YarnApplicationState
import org.apache.slider.common.SliderExitCodes
-import org.apache.slider.common.SliderKeys
-import org.apache.slider.common.SliderXmlConfKeys
import org.apache.slider.common.params.Arguments
import org.apache.slider.common.params.SliderActions
-import org.apache.slider.test.Outcome
-
-import static org.apache.slider.core.registry.info.CustomRegistryConstants.*
+import org.apache.slider.funtest.ResourcePaths
import org.apache.slider.funtest.framework.AgentCommandTestBase
import org.apache.slider.funtest.framework.FuntestProperties
import org.apache.slider.funtest.framework.SliderShell
@@ -47,9 +40,8 @@
static String CLUSTER = "test-agent-sleep-100"
- static String APP_RESOURCE11 = "../slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/resources.json"
- static String APP_META11 = "../slider-core/src/test/app_packages/test_min_pkg/sleep_cmd/metainfo.json"
-
+ static String TEST_RESOURCE = ResourcePaths.SLEEP_RESOURCES
+ static String TEST_METADATA = ResourcePaths.SLEEP_META
@Before
public void prepareCluster() {
@@ -62,14 +54,14 @@
}
@Test
- public void testAgentRegistry() throws Throwable {
+ public void testAgentMinSleepIt() throws Throwable {
describe("Create a cluster using metainfo and resources only that executes sleep 100")
def clusterpath = buildClusterPath(CLUSTER)
File launchReportFile = createTempJsonFile();
SliderShell shell = createSliderApplicationMinPkg(CLUSTER,
- APP_META11,
- APP_RESOURCE11,
+ TEST_METADATA,
+ TEST_RESOURCE,
null,
[],
launchReportFile)
@@ -91,7 +83,7 @@
CONTAINER_LAUNCH_TIMEOUT)
// sleep for some manual test
- describe("You may quickly perform manual tests against the application instance " + CLUSTER)
+ describe("You may quickly perform manual tests against the application instance $CLUSTER")
sleep(1000 * 30)
//stop
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentPingSocketIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentPingSocketIT.groovy
index ce2ed92..b10e792 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentPingSocketIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentPingSocketIT.groovy
@@ -22,18 +22,11 @@
import groovy.util.logging.Slf4j
import groovy.json.*
import org.apache.hadoop.net.NetUtils
-import org.apache.hadoop.registry.client.binding.RegistryUtils
-import org.apache.hadoop.registry.client.types.Endpoint
-import org.apache.hadoop.registry.client.types.ServiceRecord
import org.apache.hadoop.yarn.api.records.YarnApplicationState
import org.apache.slider.common.SliderExitCodes
-import org.apache.slider.common.SliderKeys
-import org.apache.slider.common.SliderXmlConfKeys
import org.apache.slider.common.params.Arguments
import org.apache.slider.common.params.SliderActions
-import org.apache.slider.test.Outcome
-
-import static org.apache.slider.core.registry.info.CustomRegistryConstants.*
+import org.apache.slider.funtest.ResourcePaths
import org.apache.slider.funtest.framework.AgentCommandTestBase
import org.apache.slider.funtest.framework.FuntestProperties
import org.apache.slider.funtest.framework.SliderShell
@@ -49,9 +42,9 @@
static String CLUSTER = "test-agent-ping-port"
- static String APP_RESOURCE12 = "../slider-core/src/test/app_packages/test_min_pkg/nc_ping_cmd/resources.json"
- static String APP_META12 = "../slider-core/src/test/app_packages/test_min_pkg/nc_ping_cmd/metainfo.json"
- static String APP_TEMPLATE12 = "../slider-core/src/test/app_packages/test_min_pkg/nc_ping_cmd/appConfig.json"
+ static String APP_RESOURCE12 = ResourcePaths.PING_RESOURCES
+ static String APP_META12 = ResourcePaths.PING_META
+ static String APP_TEMPLATE12 = ResourcePaths.PING_APPCONFIG
@Before
@@ -68,7 +61,7 @@
public void testAgentRegistry() throws Throwable {
describe("Create a cluster using metainfo, resources, and appConfig that calls nc to listen on a port")
assumeNotWindows()
- def clusterpath = buildClusterPath(CLUSTER)
+ buildClusterPath(CLUSTER)
File launchReportFile = createTempJsonFile();
SliderShell shell = createSliderApplicationMinPkg(CLUSTER,
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentRegistryIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentRegistryIT.groovy
index ff5e57e..7a03a05 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentRegistryIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentRegistryIT.groovy
@@ -28,6 +28,7 @@
import org.apache.slider.common.SliderKeys
import org.apache.slider.common.params.Arguments
import org.apache.slider.common.params.SliderActions
+import org.apache.slider.funtest.ResourcePaths
import org.apache.slider.test.Outcome
import static org.apache.slider.core.registry.info.CustomRegistryConstants.*
@@ -46,8 +47,7 @@
static String CLUSTER = "test-agent-registry"
- static String APP_RESOURCE2 = "../slider-core/src/test/app_packages/test_command_log/resources_no_role.json"
-
+ static String APP_RESOURCE2 = ResourcePaths.COMMAND_LOG_RESOURCES_NO_ROLE
@Before
public void prepareCluster() {
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentWebPagesIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentWebPagesIT.groovy
index 62be615..d1f8f20 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentWebPagesIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentWebPagesIT.groovy
@@ -23,13 +23,9 @@
import groovy.util.logging.Slf4j
import org.apache.hadoop.registry.client.api.RegistryOperations
import org.apache.hadoop.security.UserGroupInformation
-import org.apache.hadoop.yarn.api.ApplicationClientProtocol
-import org.apache.hadoop.yarn.client.ClientRMProxy
-import org.apache.hadoop.yarn.webapp.ForbiddenException
import org.apache.slider.agent.rest.IpcApiClientTestDelegates
import org.apache.slider.agent.rest.JerseyTestDelegates
import org.apache.slider.agent.rest.AbstractRestTestDelegate
-import org.apache.slider.agent.rest.LowLevelRestTestDelegates
import org.apache.slider.agent.rest.RestAPIClientTestDelegates
import org.apache.slider.client.SliderClient
import org.apache.slider.client.ipc.SliderApplicationIpcClient
@@ -40,13 +36,13 @@
import org.apache.slider.common.params.Arguments
import org.apache.slider.common.params.SliderActions
import org.apache.slider.common.tools.ConfigHelper
+import org.apache.slider.funtest.ResourcePaths
import org.apache.slider.funtest.framework.AgentCommandTestBase
import org.apache.slider.funtest.framework.FuntestProperties
import org.apache.slider.funtest.framework.SliderShell
import org.apache.slider.server.appmaster.rpc.RpcBinder
import org.junit.After
import org.junit.Before
-import org.junit.Ignore
import org.junit.Test
import static org.apache.slider.server.appmaster.web.rest.RestPaths.SYSTEM_HEALTHCHECK
@@ -59,7 +55,7 @@
static String CLUSTER = "test-agent-web"
- static String APP_RESOURCE2 = "../slider-core/src/test/app_packages/test_command_log/resources_no_role.json"
+ static String APP_RESOURCE2 = ResourcePaths.COMMAND_LOG_RESOURCES_NO_ROLE
@Before
public void prepareCluster() {
@@ -72,12 +68,11 @@
}
@Test
- @Ignore("SLIDER-907")
public void testAgentWeb() throws Throwable {
describe("Web queries & REST operations against an AM")
// verify the ws/ path is open for all HTTP verbs
- def sliderConfiguration = ConfigHelper.loadSliderConfiguration();
+ ConfigHelper.loadSliderConfiguration();
/*
Is the back door required? If so, don't test complex verbs via the proxy
@@ -91,7 +86,7 @@
def directComplexVerbs = proxyComplexVerbs || SLIDER_CONFIG.getBoolean(
SliderXmlConfKeys.X_DEV_INSECURE_WS,
SliderXmlConfKeys.X_DEV_INSECURE_DEFAULT)
- def clusterpath = buildClusterPath(CLUSTER)
+ buildClusterPath(CLUSTER)
File launchReportFile = createTempJsonFile();
SliderShell shell = createTemplatedSliderApplication(CLUSTER,
APP_TEMPLATE,
@@ -110,77 +105,86 @@
def appId = ensureYarnApplicationIsUp(launchReportFile)
assert appId
awaitApplicationURLPublished(appId, instanceLaunchTime)
- File liveReportFile = createTempJsonFile();
- lookup(appId, liveReportFile)
- def report = loadAppReport(liveReportFile)
- assert report.url
+ def report = lookupApplication(appId)
+ assert report && report.url
def proxyAM = report.url
+ // decide whether or not to use https
+ def proxyTests = !proxyAM.toLowerCase(Locale.ENGLISH).startsWith("https:")
+
// here the URL has been published, but it may not be live yet, due to the time
// it takes the AM to build app state and boostrap the Web UI
def directAM = report.origTrackingUrl;
- describe "Proxy Jersey Tests"
-
Client jerseyClient = createUGIJerseyClient()
- JerseyTestDelegates proxyJerseyTests =
- new JerseyTestDelegates(proxyAM, jerseyClient, proxyComplexVerbs)
+ if (proxyTests) {
+ describe "Proxy Jersey Tests"
- // wait it coming up
- awaitRestEndpointLive(proxyJerseyTests, instanceLaunchTime)
+ JerseyTestDelegates proxyJerseyTests =
+ new JerseyTestDelegates(proxyAM, jerseyClient, proxyComplexVerbs)
- proxyJerseyTests.testSuiteGetOperations()
+ // wait it coming up
+ awaitRestEndpointLive(proxyJerseyTests, instanceLaunchTime)
+
+ proxyJerseyTests.testSuiteGetOperations()
+
+ describe "Proxy SliderRestClient Tests"
+ RestAPIClientTestDelegates proxySliderRestAPI =
+ new RestAPIClientTestDelegates(proxyAM, jerseyClient, proxyComplexVerbs)
+ proxySliderRestAPI.testSuiteAll()
+
+
+ if (UserGroupInformation.securityEnabled) {
+ describe "Insecure Proxy Tests against a secure cluster"
+
+ // these tests use the Jersey client without the Hadoop-specific
+ // SPNEGO
+ JerseyTestDelegates basicJerseyClientTests =
+ new JerseyTestDelegates(proxyAM, createBasicJerseyClient())
+ basicJerseyClientTests.testSuiteGetOperations()
+ }
+
+ // create the Rest client via the registry
+
+ //get a slider client against the cluster
+
+ SliderClient sliderClient = bondToCluster(SLIDER_CONFIG, CLUSTER)
+ RegistryOperations operations = sliderClient.registryOperations;
+ def restClientFactory = new RestClientFactory(
+ operations, jerseyClient,
+ "~", SliderKeys.APP_TYPE, CLUSTER)
+ def sliderApplicationApi = restClientFactory.createSliderAppApiClient();
+ sliderApplicationApi.desiredModel
+ sliderApplicationApi.resolvedModel
+ if (proxyComplexVerbs) {
+ sliderApplicationApi.ping("registry located")
+ }
+
+ } else {
+ describe "skipping tests against HTTPS RM proxy $proxyAM"
+ }
+
describe "Direct Jersey Tests"
JerseyTestDelegates directJerseyTests =
new JerseyTestDelegates(directAM, jerseyClient, directComplexVerbs)
directJerseyTests.testSuiteAll()
- describe "Proxy SliderRestClient Tests"
- RestAPIClientTestDelegates proxySliderRestAPI =
- new RestAPIClientTestDelegates(proxyAM, jerseyClient, proxyComplexVerbs)
- proxySliderRestAPI.testSuiteAll()
-
describe "Direct SliderRestClient Tests"
RestAPIClientTestDelegates directSliderRestAPI =
new RestAPIClientTestDelegates(directAM, jerseyClient, directComplexVerbs)
directSliderRestAPI.testSuiteAll()
- if (UserGroupInformation.securityEnabled) {
- describe "Insecure Proxy Tests against a secure cluster"
-
- // these tests use the Jersey client without the Hadoop-specific
- // SPNEGO
- JerseyTestDelegates basicJerseyClientTests =
- new JerseyTestDelegates(proxyAM, createBasicJerseyClient())
- basicJerseyClientTests.testSuiteGetOperations()
- }
-
- // create the Rest client via the registry
-
- //get a slider client against the cluster
-
- SliderClient sliderClient = bondToCluster(SLIDER_CONFIG, CLUSTER)
- RegistryOperations operations = sliderClient.registryOperations;
- def restClientFactory = new RestClientFactory(
- operations, jerseyClient,
- "~", SliderKeys.APP_TYPE, CLUSTER)
- def sliderApplicationApi = restClientFactory.createSliderAppApiClient();
- sliderApplicationApi.desiredModel
- sliderApplicationApi.resolvedModel
- if (proxyComplexVerbs) {
- sliderApplicationApi.ping("registry located")
- }
// maybe execute IPC operations.
// these are skipped when security is enabled, until
// there's some code set up to do the tokens properly
- if (!UserGroupInformation.isSecurityEnabled()) {
+ if (!UserGroupInformation.securityEnabled) {
describe("IPC equivalent operations")
def sliderClusterProtocol =
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy
index 0db775b..060af5d 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy
@@ -76,7 +76,8 @@
application,
ARG_COMPONENT,
COMMAND_LOGGER,
- "2"])
+ "2"
+ ])
// sleep till the new instance starts
sleep(1000 * 10)
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy
index 5758feb..666efff 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy
@@ -25,6 +25,7 @@
import org.apache.slider.common.SliderExitCodes
import org.apache.slider.common.params.Arguments
import org.apache.slider.common.params.SliderActions
+import org.apache.slider.funtest.ResourcePaths
import org.apache.slider.funtest.framework.AgentCommandTestBase
import org.apache.slider.funtest.framework.FuntestProperties
import org.apache.slider.funtest.framework.SliderShell
@@ -67,8 +68,7 @@
private static String COMMAND_LOGGER = "COMMAND_LOGGER"
private static String APPLICATION_NAME = "happy-path-with-queue-labels"
private static String TARGET_QUEUE = "labeled"
- private static String APP_RESOURCE4 =
- "../slider-core/src/test/app_packages/test_command_log/resources_queue_labels.json"
+ private static String APP_RESOURCE4 = ResourcePaths.COMMAND_LOG_RESOURCES_QUEUE_LABELS
@After
public void destroyCluster() {
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsUpgradeIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsUpgradeIT.groovy
index 9fc8e6a..fa8b7a5 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsUpgradeIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsUpgradeIT.groovy
@@ -25,6 +25,7 @@
import org.apache.slider.common.SliderExitCodes
import org.apache.slider.common.params.Arguments
import org.apache.slider.common.params.SliderActions
+import org.apache.slider.funtest.ResourcePaths
import org.apache.slider.funtest.framework.AgentCommandTestBase
import org.apache.slider.funtest.framework.FuntestProperties
import org.apache.slider.funtest.framework.SliderShell
@@ -49,8 +50,7 @@
implements FuntestProperties, Arguments, SliderExitCodes, SliderActions {
private static String COMMAND_LOGGER = "COMMAND_LOGGER"
private static String APPLICATION_NAME = "app-upgrade-happy-path"
- private static String APP_RESOURCE =
- "../slider-core/src/test/app_packages/test_command_log/resources.json"
+ private static String APP_RESOURCE = ResourcePaths.COMMAND_LOG_RESOURCES
@After
public void destroyCluster() {
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/ClusterBuildDestroyIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/ClusterBuildDestroyIT.groovy
index f03fb63..66bc10b 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/ClusterBuildDestroyIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/ClusterBuildDestroyIT.groovy
@@ -37,13 +37,10 @@
public class ClusterBuildDestroyIT extends AgentCommandTestBase
implements FuntestProperties, Arguments, SliderExitCodes, SliderActions {
-
static String CLUSTER = "test-cluster-build-destroy"
-
@BeforeClass
public static void prepareCluster() {
-
setupCluster(CLUSTER)
}
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentDemo.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/DemoAASleep.groovy
similarity index 60%
copy from slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentDemo.groovy
copy to slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/DemoAASleep.groovy
index 3dd7857..7d0ee46 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentDemo.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/DemoAASleep.groovy
@@ -20,26 +20,22 @@
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-import org.apache.slider.common.SliderExitCodes
-import org.apache.slider.common.params.Arguments
-import org.apache.slider.common.params.SliderActions
-import org.apache.slider.funtest.framework.AgentCommandTestBase
-import org.apache.slider.funtest.framework.FuntestProperties
-import org.apache.slider.funtest.framework.SliderShell
-import org.junit.Before
-import org.junit.Test
+import org.apache.slider.core.launch.SerializedApplicationReport
-/**
- * For a quick demo of a slider app; this starts the apps through agent test but
- * neglects to tear it down afterwards
- */
@CompileStatic
@Slf4j
-public class AppsThroughAgentDemo extends AppsThroughAgentIT {
+class DemoAASleep extends AASleepIT {
@Override
- void destroyCluster() {
-// super.destroyCluster()
+ protected void operations(
+ String name,
+ SerializedApplicationReport appReport,
+ int desired,
+ int expected) {
+ super.operations(name, appReport, desired, expected)
+
+ describe("cluster is live at ${appReport.url}")
+
+ sleep(10 * 60 * 1000)
}
-
}
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentDemo.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/DemoAppsThroughAgent.groovy
similarity index 93%
rename from slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentDemo.groovy
rename to slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/DemoAppsThroughAgent.groovy
index 3dd7857..ea10390 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentDemo.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/DemoAppsThroughAgent.groovy
@@ -35,11 +35,11 @@
*/
@CompileStatic
@Slf4j
-public class AppsThroughAgentDemo extends AppsThroughAgentIT {
+public class DemoAppsThroughAgent extends AppsThroughAgentIT {
@Override
void destroyCluster() {
-// super.destroyCluster()
+
}
-
+
}