You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@slider.apache.org by st...@apache.org on 2015/11/23 18:20:34 UTC

[22/50] incubator-slider git commit: SLIDER-979 AM web UI to show state of AA request

SLIDER-979 AM web UI to show state of AA request


Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/591ba99e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/591ba99e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/591ba99e

Branch: refs/heads/develop
Commit: 591ba99ecbcec2edc208cafec6b36cc84c6f23cf
Parents: 8efc4c2
Author: Steve Loughran <st...@apache.org>
Authored: Mon Nov 16 20:07:59 2015 +0000
Committer: Steve Loughran <st...@apache.org>
Committed: Mon Nov 16 20:07:59 2015 +0000

----------------------------------------------------------------------
 .../org/apache/slider/api/proto/Messages.java   | 191 ++++++++++++++-----
 .../slider/api/proto/RestTypeMarshalling.java   |   8 +-
 .../types/ApplicationLivenessInformation.java   |   6 +
 .../slider/api/types/ComponentInformation.java  |   4 +-
 .../apache/slider/api/types/RoleStatistics.java |  66 +++++++
 .../rest/SliderApplicationApiRestClient.java    |  14 ++
 .../appmaster/actions/ActionKillContainer.java  |   2 +-
 .../server/appmaster/actions/QueueService.java  |   8 +-
 .../slider/server/appmaster/state/AppState.java |  33 ++--
 .../appmaster/state/ProviderAppState.java       |   5 +
 .../server/appmaster/state/RoleStatus.java      |  20 ++
 .../state/StateAccessForProviders.java          |   7 +
 .../web/rest/AbstractSliderResource.java        |   7 +-
 .../server/appmaster/web/rest/RestPaths.java    |  11 ++
 .../web/view/ClusterSpecificationBlock.java     |  13 +-
 .../appmaster/web/view/ContainerStatsBlock.java |   9 +-
 .../server/appmaster/web/view/IndexBlock.java   |  84 ++++----
 .../server/appmaster/web/view/NavBlock.java     |  26 ++-
 .../appmaster/web/view/SliderHamletBlock.java   |  56 ++++++
 .../src/main/proto/SliderClusterMessages.proto  |   1 +
 .../agent/AgentMiniClusterTestBase.groovy       |   7 +-
 .../slider/agent/rest/TestStandaloneREST.groovy |   5 +-
 .../slider/providers/agent/AgentTestBase.groovy |   1 +
 .../providers/agent/DemoAgentAAEcho.groovy      |   8 +-
 .../providers/agent/TestAgentAAEcho.groovy      |  29 ++-
 .../slider/providers/agent/TestAgentEcho.groovy |   6 +-
 .../org/apache/slider/test/KeysForTests.groovy  |   3 +-
 slider-core/src/test/python/agent.py            |  25 ++-
 slider-core/src/test/python/agent/main.py       |  18 +-
 slider-core/src/test/python/echo.py             |  23 ++-
 slider-core/src/test/python/metainfo.xml        |   2 +-
 31 files changed, 529 insertions(+), 169 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/api/proto/Messages.java
----------------------------------------------------------------------
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..ed056f5 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 @@ public final class Messages {
      * <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 @@ public final class Messages {
               pendingAntiAffineRequestCount_ = input.readInt32();
               break;
             }
+            case 152: {
+              bitField0_ |= 0x00020000;
+              isAARequestOutstanding_ = input.readBool();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -15659,6 +15674,22 @@ public final class Messages {
       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 @@ public final class Messages {
       nodeFailed_ = 0;
       preempted_ = 0;
       pendingAntiAffineRequestCount_ = 0;
+      isAARequestOutstanding_ = false;
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -15745,6 +15777,9 @@ public final class Messages {
       if (((bitField0_ & 0x00010000) == 0x00010000)) {
         output.writeInt32(18, pendingAntiAffineRequestCount_);
       }
+      if (((bitField0_ & 0x00020000) == 0x00020000)) {
+        output.writeBool(19, isAARequestOutstanding_);
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -15831,6 +15866,10 @@ public final class Messages {
         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 @@ public final class Messages {
         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 @@ public final class Messages {
         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 @@ public final class Messages {
         bitField0_ = (bitField0_ & ~0x00010000);
         pendingAntiAffineRequestCount_ = 0;
         bitField0_ = (bitField0_ & ~0x00020000);
+        isAARequestOutstanding_ = false;
+        bitField0_ = (bitField0_ & ~0x00040000);
         return this;
       }
 
@@ -16278,6 +16328,10 @@ public final class Messages {
           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 @@ public final class Messages {
         if (other.hasPendingAntiAffineRequestCount()) {
           setPendingAntiAffineRequestCount(other.getPendingAntiAffineRequestCount());
         }
+        if (other.hasIsAARequestOutstanding()) {
+          setIsAARequestOutstanding(other.getIsAARequestOutstanding());
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -17122,6 +17179,39 @@ public final class Messages {
         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)
     }
 
@@ -34023,7 +34113,7 @@ public final class Messages {
       " \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 +34123,55 @@ public final class Messages {
       "(\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\"\325\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\"" +
+      "\334\001\n\024NodeInformationProto\022\020\n\010hostname\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\014heal" +
+      "thReport\030\006 \002(\t\022\023\n\013lastUpdated\030\007 \002(\003\022A\n\007e" +
+      "ntries\030\010 \003(\01320.org.apache.slider.api.Nod" +
+      "eEntryInformationProto\"\026\n\024GetModelReques",
+      "tProto\"\035\n\033GetModelDesiredRequestProto\"$\n" +
+      "\"GetModelDesiredAppconfRequestProto\"&\n$G" +
+      "etModelDesiredResourcesRequestProto\"%\n#G" +
+      "etModelResolvedAppconfRequestProto\"\'\n%Ge" +
+      "tModelResolvedResourcesRequestProto\"#\n!G" +
+      "etModelLiveResourcesRequestProto\"\037\n\035GetL" +
+      "iveContainersRequestProto\"u\n\036GetLiveCont" +
+      "ainersResponseProto\022\r\n\005names\030\001 \003(\t\022D\n\nco" +
+      "ntainers\030\002 \003(\01320.org.apache.slider.api.C" +
+      "ontainerInformationProto\"3\n\034GetLiveConta",
+      "inerRequestProto\022\023\n\013containerId\030\001 \002(\t\"\037\n" +
+      "\035GetLiveComponentsRequestProto\"u\n\036GetLiv" +
+      "eComponentsResponseProto\022\r\n\005names\030\001 \003(\t\022" +
+      "D\n\ncomponents\030\002 \003(\01320.org.apache.slider." +
+      "api.ComponentInformationProto\",\n\034GetLive" +
+      "ComponentRequestProto\022\014\n\004name\030\001 \002(\t\"$\n\"G" +
+      "etApplicationLivenessRequestProto\"\023\n\021Emp" +
+      "tyPayloadProto\" \n\020WrappedJsonProto\022\014\n\004js" +
+      "on\030\001 \002(\t\"h\n\037GetCertificateStoreRequestPr" +
+      "oto\022\020\n\010hostname\030\001 \001(\t\022\023\n\013requesterId\030\002 \002",
+      "(\t\022\020\n\010password\030\003 \002(\t\022\014\n\004type\030\004 \002(\t\"1\n Ge" +
+      "tCertificateStoreResponseProto\022\r\n\005store\030" +
+      "\001 \002(\014\"\032\n\030GetLiveNodesRequestProto\"f\n\031Get" +
+      "LiveNodesResponseProto\022\r\n\005names\030\001 \003(\t\022:\n" +
+      "\005nodes\030\002 \003(\0132+.org.apache.slider.api.Nod" +
+      "eInformationProto\"\'\n\027GetLiveNodeRequestP" +
+      "roto\022\014\n\004name\030\001 \002(\tB-\n\033org.apache.slider." +
+      "api.protoB\010Messages\210\001\001\240\001\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -34236,7 +34327,7 @@ public final class Messages {
           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

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/api/proto/RestTypeMarshalling.java
----------------------------------------------------------------------
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 85a8358..8dcf65f 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
@@ -86,7 +86,12 @@ public class RestTypeMarshalling {
     if (wire.hasFailureMessage()) {
       info.failureMessage = wire.getFailureMessage();
     }
-    info.pendingAntiAffineRequestCount = wire.getPendingAntiAffineRequestCount();
+    if (wire.hasPendingAntiAffineRequestCount()) {
+      info.pendingAntiAffineRequestCount = wire.getPendingAntiAffineRequestCount();
+    }
+    if (wire.hasIsAARequestOutstanding()) {
+      info.isAARequestOutstanding = wire.getIsAARequestOutstanding();
+    }
     return info;
   }
 
@@ -137,6 +142,7 @@ public class RestTypeMarshalling {
       builder.addAllContainers(info.containers);
     }
     builder.setPendingAntiAffineRequestCount(info.pendingAntiAffineRequestCount);
+    builder.setIsAARequestOutstanding(info.isAARequestOutstanding);
     return builder.build();
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/api/types/ApplicationLivenessInformation.java
----------------------------------------------------------------------
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 @@ import org.codehaus.jackson.map.annotate.JsonSerialize;
 @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 =

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/api/types/ComponentInformation.java
----------------------------------------------------------------------
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 9d8a4ee..3771988 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
@@ -53,6 +53,7 @@ public class ComponentInformation {
   public int failed, started, startFailed, completed, totalRequested;
   public int nodeFailed, failedRecently, preempted;
   public int pendingAntiAffineRequestCount;
+  public boolean isAARequestOutstanding;
 
   public String failureMessage;
   public List<String> containers;
@@ -84,12 +85,13 @@ public class ComponentInformation {
         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);

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/api/types/RoleStatistics.java
----------------------------------------------------------------------
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;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/client/rest/SliderApplicationApiRestClient.java
----------------------------------------------------------------------
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..54c60d1 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
@@ -25,6 +25,7 @@ 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;
+import com.sun.jersey.api.client.filter.LoggingFilter;
 import com.sun.jersey.api.representation.Form;
 import org.apache.commons.lang.StringUtils;
 import org.apache.slider.api.types.ApplicationLivenessInformation;
@@ -68,6 +69,19 @@ public class SliderApplicationApiRestClient extends BaseRestClient
     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 =

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/actions/ActionKillContainer.java
----------------------------------------------------------------------
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 class ActionKillContainer extends AsyncAction {
   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

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/actions/QueueService.java
----------------------------------------------------------------------
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 @@ implements Runnable, QueueAccess {
    * 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
    */

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppState.java
----------------------------------------------------------------------
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 4152a89..2da5d36 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
@@ -46,6 +46,7 @@ import org.apache.slider.api.RoleKeys;
 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;
@@ -250,12 +251,6 @@ public class AppState {
   private final LongGauge outstandingContainerRequests = new LongGauge();
 
   /**
-   * Track the number of pending (not yet active) requests
-   * Important: this does not include AA requests which are yet to be issued.
-   */
-  private final LongGauge pendingAARequests = new LongGauge();
-
-  /**
    * Map of requested nodes. This records the command used to start it,
    * resources, etc. When container started callback is received,
    * the node is promoted from here to the containerMap
@@ -382,10 +377,6 @@ public class AppState {
     startFailedContainerCount.inc();
   }
 
-  public long getTotalOutstandingRequests() {
-    return outstandingContainerRequests.get() +
-        pendingAARequests.get();
-  }
   public AtomicInteger getCompletionOfNodeNotInLiveListEvent() {
     return completionOfNodeNotInLiveListEvent;
   }
@@ -1777,9 +1768,11 @@ public class AppState {
    */  
   public ApplicationLivenessInformation getApplicationLivenessInformation() {
     ApplicationLivenessInformation li = new ApplicationLivenessInformation();
-    int outstanding = outstandingContainerRequests.intValue();
+    RoleStatistics stats = getRoleStatistics();
+    int outstanding = (int)(stats.desired - stats.actual);
     li.requestsOutstanding = outstanding;
     li.allRequestsSatisfied = outstanding <= 0;
+    li.activeRequests = (int)stats.requested;
     return li;
   }
 
@@ -1808,6 +1801,18 @@ public class AppState {
   }
 
   /**
+   * 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 
@@ -1817,8 +1822,7 @@ public class AppState {
   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()) {
@@ -2372,9 +2376,10 @@ public class AppState {
     sb.append(", startFailedContainerCount=").append(startFailedContainerCount);
     sb.append(", surplusContainers=").append(surplusContainers);
     sb.append(", failedContainerCount=").append(failedContainerCount);
-    sb.append(", outstandingContainerRequests=")
+    sb.append(", outstanding non-AA Container Requests=")
         .append(outstandingContainerRequests);
     sb.append('}');
     return sb.toString();
   }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ProviderAppState.java
----------------------------------------------------------------------
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..1d96a1c 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.ClusterNode;
 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;
@@ -298,4 +299,8 @@ public class ProviderAppState implements StateAccessForProviders {
     return appState.getRoleHistory().getNodeInformation(hostname);
   }
 
+  @Override
+  public RoleStatistics getRoleStatistics() {
+    return appState.getRoleStatistics();
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleStatus.java
----------------------------------------------------------------------
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 b530d18..0fc3dc2 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
@@ -21,6 +21,7 @@ package org.apache.slider.server.appmaster.state;
 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.LongGauge;
@@ -441,6 +442,7 @@ public final class RoleStatus implements Cloneable {
     info.nodeFailed = nodeFailed.intValue();
     info.preempted = preempted.intValue();
     info.pendingAntiAffineRequestCount = pendingAntiAffineRequests.intValue();
+    info.isAARequestOutstanding = isAARequestOutstanding();
     return info;
   }
 
@@ -494,4 +496,22 @@ public final class RoleStatus implements Cloneable {
     resource.setVirtualCores(resourceRequirements.getVirtualCores());
     return resource;
   }
+
+  public synchronized RoleStatistics getStatistics() {
+    RoleStatistics stats = new RoleStatistics();
+    stats.activeAA = isAARequestOutstanding() ? 1: 0;
+    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;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/state/StateAccessForProviders.java
----------------------------------------------------------------------
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.StatusKeys;
 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 @@ public interface StateAccessForProviders {
    * @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();
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/AbstractSliderResource.java
----------------------------------------------------------------------
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 @@ public abstract class AbstractSliderResource {
   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 @@ public abstract class AbstractSliderResource {
   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 @@ public abstract class AbstractSliderResource {
   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 @@ public abstract class AbstractSliderResource {
   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 @@ public abstract class AbstractSliderResource {
   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

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/RestPaths.java
----------------------------------------------------------------------
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 class RestPaths {
   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;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/ClusterSpecificationBlock.java
----------------------------------------------------------------------
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 @@ package org.apache.slider.server.appmaster.web.view;
 
 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 @@ public class ClusterSpecificationBlock extends HtmlBlock {
         pre().
           _(getJson())._()._();
   }
-  
+
   /**
    * Get the JSON, catching any exceptions and returning error text instead
    * @return

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/ContainerStatsBlock.java
----------------------------------------------------------------------
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 65d8b39..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.DIV;
 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,7 +43,7 @@ import java.util.Map.Entry;
 /**
  * 
  */
-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/";
 
@@ -54,11 +52,9 @@ public class ContainerStatsBlock extends HtmlBlock {
   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);
   }
 
   /**
@@ -93,7 +89,6 @@ public class ContainerStatsBlock extends HtmlBlock {
 
   @Override
   protected void render(Block html) {
-    StateAccessForProviders appState = slider.getAppState();
     final Map<String,RoleInstance> containerInstances = getContainerInstances(
         appState.cloneOwnedContainerList());
 

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/IndexBlock.java
----------------------------------------------------------------------
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 41e1c01..8152f27 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,28 +21,28 @@ import com.google.inject.Inject;
 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.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;
+
 /**
  * 
  */
-public class IndexBlock extends HtmlBlock {
+public class IndexBlock extends SliderHamletBlock {
   private static final Logger log = LoggerFactory.getLogger(IndexBlock.class);
 
   /**
@@ -52,13 +52,9 @@ public class IndexBlock extends HtmlBlock {
    */
   public static final String ALL_CONTAINERS_ALLOCATED = "all containers allocated";
 
-  private StateAccessForProviders appView;
-  private ProviderService providerService;
-
   @Inject
   public IndexBlock(WebAppApi slider) {
-    this.appView = slider.getAppState();
-    this.providerService = slider.getProviderService();
+    super(slider);
   }
 
   @Override
@@ -71,7 +67,8 @@ public class IndexBlock extends HtmlBlock {
   // 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();
+    RoleStatistics roleStats = appState.getRoleStatistics();
     String name = clusterStatus.name;
     if (name != null && (name.startsWith(" ") || name.endsWith(" "))) {
       name = "'" + name + "'";
@@ -81,9 +78,8 @@ public class IndexBlock extends HtmlBlock {
                               "Application: " + name);
 
     ApplicationLivenessInformation liveness =
-        appView.getApplicationLivenessInformation();
-    String livestatus =
-        liveness.allRequestsSatisfied
+        appState.getApplicationLivenessInformation();
+    String livestatus = liveness.allRequestsSatisfied
         ? ALL_CONTAINERS_ALLOCATED
         : String.format("Awaiting %d containers", liveness.requestsOutstanding);
     Hamlet.TABLE<DIV<Hamlet>> table1 = div.table();
@@ -93,7 +89,7 @@ public class IndexBlock extends HtmlBlock {
           ._();
     table1.tr()
           .td("Total number of containers")
-          .td(Integer.toString(appView.getNumOwnedContainers()))
+          .td(Integer.toString(appState.getNumOwnedContainers()))
           ._();
     table1.tr()
           .td("Create time: ")
@@ -121,26 +117,40 @@ public class IndexBlock extends HtmlBlock {
     html.div("container_instances").h3("Component Instances");
 
     Hamlet.TABLE<DIV<Hamlet>> table = div.table();
-    table.tr()
-         .td("Component")
-         .td("Desired")
-         .td("Actual")
-         .td("Outstanding Requests")
-         .td("Failed")
-         .td("Failed to start")
-         ._();
-
-    List<RoleStatus> roleStatuses = appView.cloneRoleStatusList();
+    Hamlet.TR<Hamlet.THEAD<Hamlet.TABLE<DIV<Hamlet>>>> tr = table.thead().tr();
+    trb(tr, "Component");
+    trb(tr, "Desired");
+    trb(tr, "Actual");
+    trb(tr, "Outstanding Requests");
+    trb(tr, "Failed");
+    trb(tr, "Failed to start");
+    trb(tr, "Placement");
+    tr._()._();
+
+    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()) {
+        int outstanding = status.isAARequestOutstanding() ? 1: 0;
+        int pending = (int)status.getPendingAntiAffineRequests();
+        aatext = String.format("Anti-affine: %d outstanding %s, %d pending %s",
+          outstanding, plural(outstanding, "request"),
+          pending, plural(pending, "request"));
+      } else {
+        aatext = "";
+      }
       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._()._();
@@ -155,12 +165,21 @@ public class IndexBlock extends HtmlBlock {
     ul._()._();
   }
 
+  private String plural(int n, String text) {
+    return n == 1 ? text : (text + "s");
+  }
+
+  private void trb(Hamlet.TR<Hamlet.THEAD<Hamlet.TABLE<DIV<Hamlet>>>> tr,
+      String text) {
+    tr.td().b(text)._();
+  }
+
   private String getProviderName() {
     return providerService.getHumanName();
   }
 
   private String getInfoAvoidingNulls(String key) {
-    String createTime = appView.getClusterStatus().getInfo(key);
+    String createTime = appState.getClusterStatus().getInfo(key);
 
     return null == createTime ? "N/A" : createTime;
   }
@@ -183,4 +202,5 @@ public class IndexBlock extends HtmlBlock {
     }
   }
 
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/NavBlock.java
----------------------------------------------------------------------
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..515b1a3 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) {
@@ -48,20 +53,11 @@ public class NavBlock extends HtmlBlock {
           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);
-  }
-  
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/SliderHamletBlock.java
----------------------------------------------------------------------
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);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/main/proto/SliderClusterMessages.proto
----------------------------------------------------------------------
diff --git a/slider-core/src/main/proto/SliderClusterMessages.proto b/slider-core/src/main/proto/SliderClusterMessages.proto
index 50c10e4..2836454 100644
--- a/slider-core/src/main/proto/SliderClusterMessages.proto
+++ b/slider-core/src/main/proto/SliderClusterMessages.proto
@@ -258,6 +258,7 @@ message ComponentInformationProto {
   optional int32 nodeFailed =     16;
   optional int32 preempted =      17;
   optional int32 pendingAntiAffineRequestCount = 18;
+  optional bool isAARequestOutstanding = 19;
 }
 
 /*

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/test/groovy/org/apache/slider/agent/AgentMiniClusterTestBase.groovy
----------------------------------------------------------------------
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..41bb7b1 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.commons.io.FileUtils
 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 @@ import org.slf4j.LoggerFactory
 @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

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/test/groovy/org/apache/slider/agent/rest/TestStandaloneREST.groovy
----------------------------------------------------------------------
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 7cb1837..0bd1df0 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.common.params.Arguments
 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,7 +40,7 @@ import static org.apache.slider.server.appmaster.web.rest.RestPaths.*
 
 @CompileStatic
 @Slf4j
-class TestStandaloneREST extends AgentMiniClusterTestBase {
+class TestStandaloneREST extends AgentMiniClusterTestBase  {
 
   @Test
   public void testStandaloneREST() throws Throwable {
@@ -88,7 +89,7 @@ class TestStandaloneREST extends AgentMiniClusterTestBase {
     // this should be from AM launch itself
     awaitGaugeValue(
         appendToURL(proxyAM, SYSTEM_METRICS_JSON),
-        "org.apache.slider.server.appmaster.state.RoleHistory.nodes-updated.flag",
+        NODES_UPDATED_FLAG_METRIC,
         1,
         WEB_STARTUP_TIME  * 2, 500)
 

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/test/groovy/org/apache/slider/providers/agent/AgentTestBase.groovy
----------------------------------------------------------------------
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 0e5cd00..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
@@ -136,6 +136,7 @@ public abstract class AgentTestBase extends YarnZKMiniClusterTestBase {
       boolean create,
       boolean blockUntilRunning) {
 
+    YarnConfiguration conf = testConfiguration
     def clusterOps = [:]
 
     return createOrBuildCluster(

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/test/groovy/org/apache/slider/providers/agent/DemoAgentAAEcho.groovy
----------------------------------------------------------------------
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
index 6f21006..8606417 100644
--- 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
@@ -18,7 +18,6 @@
 
 package org.apache.slider.providers.agent
 
-import org.apache.hadoop.yarn.api.records.ApplicationReport
 import org.apache.slider.client.SliderClient
 
 /**
@@ -37,7 +36,12 @@ class DemoAgentAAEcho extends TestAgentAAEcho {
     def applicationReport = sliderClient.applicationReport
     def url = applicationReport.trackingUrl
     // spin repeating the URl in the logs so YARN chatter doesn't lose it
-    1..5.each {
+    describe("Web UI is at $url")
+
+    // run the superclass rest tests
+  //  queryRestAPI(sliderClient, roles)
+
+    5.times {
       describe("Web UI is at $url")
       sleep(60 *1000)
     }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestAgentAAEcho.groovy
----------------------------------------------------------------------
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
index 3835330..f2f38e0 100644
--- 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
@@ -20,8 +20,11 @@ package org.apache.slider.providers.agent
 
 import groovy.transform.CompileStatic
 import groovy.util.logging.Slf4j
+import org.apache.slider.agent.rest.RestAPIClientTestDelegates
 import org.apache.slider.api.ResourceKeys
+import org.apache.slider.api.types.ComponentInformation
 import org.apache.slider.client.SliderClient
+import org.apache.slider.client.rest.SliderApplicationApiRestClient
 import org.apache.slider.common.SliderXmlConfKeys
 import org.apache.slider.core.main.ServiceLauncher
 import org.apache.slider.providers.PlacementPolicy
@@ -29,6 +32,8 @@ 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
 
 /**
  * Tests an echo command
@@ -38,10 +43,12 @@ import static org.apache.slider.providers.agent.AgentKeys.*
 class TestAgentAAEcho extends TestAgentEcho {
 
   @Test
-  public void testEchoOperation() throws Throwable {
+  public void testAgentEcho() throws Throwable {
     assumeValidServerEnv()
-
-    String clustername = createMiniCluster("",
+    def conf = configuration
+    conf.setBoolean(METRICS_LOGGING_ENABLED, true)
+    conf.setInt(METRICS_LOGGING_LOG_INTERVAL, 1)
+    String clustername = createMiniCluster("testaaecho",
         configuration,
         1,
         1,
@@ -73,7 +80,6 @@ class TestAgentAAEcho extends TestAgentEcho {
         true, true,
         true)
     postLaunchActions(launcher.service, clustername, echo, roles)
-
   }
 
   /**
@@ -105,6 +111,7 @@ class TestAgentAAEcho extends TestAgentEcho {
     //expect the role count to be the same
     waitForRoleCount(sliderClient, onlyOneEcho, 1000)
 
+    queryRestAPI(sliderClient, roles)
     // flex size
     // while running, ask for many more, expect them to still be outstanding
     sleep(5000)
@@ -117,4 +124,18 @@ class TestAgentAAEcho extends TestAgentEcho {
     waitForRoleCount(sliderClient, onlyOneEcho, 1000)
 
   }
+
+  protected void queryRestAPI(SliderClient sliderClient, Map<String, Integer> roles) {
+    initHttpTestSupport(sliderClient.config)
+    def applicationReport = sliderClient.applicationReport
+    def proxyAM = applicationReport.trackingUrl
+    GET(proxyAM)
+    describe "Proxy SliderRestClient Tests"
+    SliderApplicationApiRestClient restAPI =
+        new SliderApplicationApiRestClient(createUGIJerseyClient(), proxyAM)
+    def echoInfo = restAPI.getComponent(ECHO)
+    assert echoInfo.pendingAntiAffineRequestCount == 3
+    // no active requests ... there's no capacity
+    assert !echoInfo.isAARequestOutstanding
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestAgentEcho.groovy
----------------------------------------------------------------------
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 f14fc43..4ceeca0 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
@@ -40,6 +40,7 @@ import static org.apache.slider.providers.agent.AgentKeys.*
 @Slf4j
 class TestAgentEcho extends AgentTestBase {
 
+  protected static final String ECHO = "echo"
   File slider_core
   String echo_py
   File echo_py_path
@@ -59,7 +60,6 @@ class TestAgentEcho extends AgentTestBase {
     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 +68,7 @@ class TestAgentEcho extends AgentTestBase {
   }
 
   @Test
-  public void testEchoOperation() throws Throwable {
+  public void testAgentEcho() throws Throwable {
     assumeValidServerEnv()
 
     String clustername = createMiniCluster("",
@@ -81,7 +81,7 @@ class TestAgentEcho extends AgentTestBase {
 
     validatePaths()
 
-    def role = "echo"
+    def role = ECHO
     Map<String, Integer> roles = [
         (role): 2,
     ];

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/test/groovy/org/apache/slider/test/KeysForTests.groovy
----------------------------------------------------------------------
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 @@ public interface KeysForTests extends SliderKeys, SliderXMLConfKeysForTesting {
   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

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/test/python/agent.py
----------------------------------------------------------------------
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 @@ import time
 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 @@ def main():
 
   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())

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/test/python/agent/main.py
----------------------------------------------------------------------
diff --git a/slider-core/src/test/python/agent/main.py b/slider-core/src/test/python/agent/main.py
index 116d179..1e851bb 100755
--- a/slider-core/src/test/python/agent/main.py
+++ b/slider-core/src/test/python/agent/main.py
@@ -26,7 +26,7 @@ import os
 
 
 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 @@ def main():
   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 @@ def main():
 
   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())

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/test/python/echo.py
----------------------------------------------------------------------
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 @@ import os
 
 
 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 @@ def main():
 
   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())

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/591ba99e/slider-core/src/test/python/metainfo.xml
----------------------------------------------------------------------
diff --git a/slider-core/src/test/python/metainfo.xml b/slider-core/src/test/python/metainfo.xml
index 7f9cd23..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>