SLIDER-319 codahale metrics integration, including web view and tests for it
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 9530bc0..1bafe4b 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
@@ -19,6 +19,7 @@
 package org.apache.slider.server.appmaster;
 
 import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.health.HealthCheckRegistry;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.protobuf.BlockingService;
@@ -123,6 +124,8 @@
 import org.apache.slider.server.appmaster.actions.ResetFailureWindow;
 import org.apache.slider.server.appmaster.actions.ReviewAndFlexApplicationSize;
 import org.apache.slider.server.appmaster.actions.UnregisterComponentInstance;
+import org.apache.slider.server.appmaster.management.MetricsAndMonitoring;
+import org.apache.slider.server.appmaster.management.YarnServiceHealthCheck;
 import org.apache.slider.server.appmaster.monkey.ChaosKillAM;
 import org.apache.slider.server.appmaster.monkey.ChaosKillContainer;
 import org.apache.slider.server.appmaster.monkey.ChaosMonkeyService;
@@ -149,7 +152,7 @@
 import org.apache.slider.server.services.security.CertificateManager;
 import org.apache.slider.server.services.security.FsDelegationTokenManager;
 import org.apache.slider.server.services.utility.AbstractSliderLaunchedService;
-import org.apache.slider.server.services.utility.MetricsBindingService;
+import org.apache.slider.server.appmaster.management.MetricsBindingService;
 import org.apache.slider.server.services.utility.WebAppService;
 import org.apache.slider.server.services.workflow.ServiceThreadFactory;
 import org.apache.slider.server.services.workflow.WorkflowExecutorService;
@@ -209,9 +212,13 @@
   public static final int NUM_RPC_HANDLERS = 5;
 
   /**
-   * Singleton of metrics registry
+   * Metrics and monitoring services
    */
-  public static final MetricRegistry metrics = new MetricRegistry();
+  private final MetricsAndMonitoring metricsAndMonitoring = new MetricsAndMonitoring(); 
+  /**
+   * metrics registry
+   */
+  public MetricRegistry metrics;
   public static final String E_TRIGGERED_LAUNCH_FAILURE =
       "Chaos monkey triggered launch failure";
 
@@ -270,8 +277,8 @@
    * Ongoing state of the cluster: containers, nodes they
    * live on, etc.
    */
-  private final AppState appState = new AppState(new ProtobufRecordFactory(),
-      metrics);
+  private final AppState appState =
+      new AppState(new ProtobufRecordFactory(), metricsAndMonitoring);
 
   private final ProviderAppState stateForProviders =
       new ProviderAppState("undefined", appState);
@@ -436,6 +443,11 @@
             false);
     SliderUtils.validateSliderServerEnvironment(log, dependencyChecks);
 
+    // create app state and monitoring
+    addService(metricsAndMonitoring);
+    metrics = metricsAndMonitoring.getMetrics();
+
+    
     executorService = new WorkflowExecutorService<ExecutorService>("AmExecutor",
         Executors.newFixedThreadPool(2,
             new ServiceThreadFactory("AmExecutor", true)));
@@ -443,8 +455,6 @@
 
     addService(actionQueues);
     
-    addService(new MetricsBindingService("MetricsBindingService",
-        metrics));
     //init all child services
     super.serviceInit(conf);
   }
@@ -452,6 +462,8 @@
   @Override
   protected void serviceStart() throws Exception {
     super.serviceStart();
+    HealthCheckRegistry health = metricsAndMonitoring.getHealth();
+    health.register("AM Health", new YarnServiceHealthCheck(this));
   }
 
   /**
@@ -708,7 +720,7 @@
           providerService,
           certificateManager,
           registryOperations,
-          metrics);
+          metricsAndMonitoring);
       webApp = new SliderAMWebApp(webAppApi);
       WebApps.$for(SliderAMWebApp.BASE_PATH, WebAppApi.class,
                    webAppApi,
@@ -1005,10 +1017,11 @@
                          providerService,
                          certificateManager,
                          registryOperations,
-                         metrics),
+                         metricsAndMonitoring),
                      RestPaths.AGENT_WS_CONTEXT)
         .withComponentConfig(getInstanceDefinition().getAppConfOperations()
-                                 .getComponent(SliderKeys.COMPONENT_AM))
+                                                    .getComponent(
+                                                        SliderKeys.COMPONENT_AM))
         .start();
     agentOpsUrl =
         "https://" + appMasterHostname + ":" + agentWebApp.getSecuredPort();
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
new file mode 100644
index 0000000..77204d6
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsAndMonitoring.java
@@ -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.management;
+
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.health.HealthCheckRegistry;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.service.AbstractService;
+import org.apache.hadoop.service.CompositeService;
+
+/**
+ * Class for all metrics and monitoring
+ */
+public class MetricsAndMonitoring extends CompositeService {
+
+  public MetricsAndMonitoring(String name) {
+    super(name);
+  }
+  
+  public MetricsAndMonitoring() {
+    super("MetricsAndMonitoring");
+  }
+  
+  /**
+   * Singleton of metrics registry
+   */
+  final MetricRegistry metrics = new MetricRegistry();
+
+  final HealthCheckRegistry health = new HealthCheckRegistry();
+
+  public MetricRegistry getMetrics() {
+    return metrics;
+  }
+
+  public HealthCheckRegistry getHealth() {
+    return health;
+  }
+
+  @Override
+  protected void serviceInit(Configuration conf) throws Exception {
+    addService(new MetricsBindingService("MetricsBindingService",
+        metrics));
+    super.serviceInit(conf);
+
+  }
+}
diff --git a/slider-core/src/main/java/org/apache/slider/server/services/utility/MetricsBindingService.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsBindingService.java
similarity index 98%
rename from slider-core/src/main/java/org/apache/slider/server/services/utility/MetricsBindingService.java
rename to slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsBindingService.java
index afd2c1a..b49cf30 100644
--- a/slider-core/src/main/java/org/apache/slider/server/services/utility/MetricsBindingService.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/MetricsBindingService.java
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-package org.apache.slider.server.services.utility;
+package org.apache.slider.server.appmaster.management;
 
 import com.codahale.metrics.MetricRegistry;
 import com.codahale.metrics.ScheduledReporter;
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/management/YarnServiceHealthCheck.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/YarnServiceHealthCheck.java
new file mode 100644
index 0000000..936563c
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/management/YarnServiceHealthCheck.java
@@ -0,0 +1,38 @@
+/*
+ * 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.health.HealthCheck;
+import org.apache.hadoop.service.Service;
+
+public class YarnServiceHealthCheck extends HealthCheck {
+  
+  private final Service service;
+
+  public YarnServiceHealthCheck(Service service) {
+    this.service = service;
+  }
+
+  @Override
+  protected Result check() throws Exception {
+    return service.isInState(Service.STATE.STARTED)
+           ? Result.healthy()
+           : Result.unhealthy("Service is not running: %s", service);
+  }
+}
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 348a063..ddba5e2 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,7 +18,6 @@
 
 package org.apache.slider.server.appmaster.state;
 
-import com.codahale.metrics.MetricRegistry;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import org.apache.hadoop.conf.Configuration;
@@ -61,6 +60,7 @@
 import org.apache.slider.core.exceptions.TriggerClusterTeardownException;
 import org.apache.slider.providers.PlacementPolicy;
 import org.apache.slider.providers.ProviderRole;
+import org.apache.slider.server.appmaster.management.MetricsAndMonitoring;
 import org.apache.slider.server.appmaster.operations.AbstractRMOperation;
 import org.apache.slider.server.appmaster.operations.CancelRequestOperation;
 import org.apache.slider.server.appmaster.operations.ContainerReleaseOperation;
@@ -98,6 +98,8 @@
   
   private final AbstractRecordFactory recordFactory;
 
+  private final MetricsAndMonitoring metricsAndMonitoring;
+
   /**
    * Flag set to indicate the application is live -this only happens
    * after the buildInstance operation
@@ -262,16 +264,14 @@
   
   private ContainerReleaseSelector containerReleaseSelector;
 
-  private MetricRegistry metrics;
-
   /**
    * Create an instance
    * @param recordFactory factory for YARN records
-   * @param metrics metrics registry or null if a new one 
+   * @param metricsAndMonitoring metrics and monitoring services
    */
-  public AppState(AbstractRecordFactory recordFactory, MetricRegistry metrics) {
+  public AppState(AbstractRecordFactory recordFactory, MetricsAndMonitoring metricsAndMonitoring) {
     this.recordFactory = recordFactory;
-    this.metrics = metrics; 
+    this.metricsAndMonitoring = metricsAndMonitoring; 
   }
 
   public int getFailedCountainerCount() {
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 18c1a46..f2fc903 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
@@ -16,6 +16,7 @@
  */
 package org.apache.slider.server.appmaster.web;
 
+import com.codahale.metrics.MetricRegistry;
 import com.codahale.metrics.servlets.HealthCheckServlet;
 import com.codahale.metrics.servlets.MetricsServlet;
 import com.codahale.metrics.servlets.PingServlet;
@@ -25,10 +26,10 @@
 import com.sun.jersey.api.core.ResourceConfig;
 import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
 import com.sun.jersey.spi.container.servlet.ServletContainer;
-import org.apache.hadoop.registry.client.api.RegistryOperations;
 import org.apache.hadoop.yarn.webapp.Dispatcher;
 import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
 import org.apache.hadoop.yarn.webapp.WebApp;
+import org.apache.slider.server.appmaster.management.MetricsAndMonitoring;
 import org.apache.slider.server.appmaster.web.rest.AMWadlGeneratorConfig;
 import org.apache.slider.server.appmaster.web.rest.AMWebServices;
 import static org.apache.slider.server.appmaster.web.rest.RestPaths.*;
@@ -82,10 +83,12 @@
     }
 
     // metrics
-//    serve(SYSTEM_HEALTHCHECK).with(new HealthCheckServlet());
-    serve(SYSTEM_METRICS).with(new MetricsServlet(webAppApi.getMetrics()));
-//    serve(SYSTEM_PING).with(PingServlet.class);
-//    serve(SYSTEM_THREADS).with(ThreadDumpServlet.class);
+    MetricsAndMonitoring monitoring =
+        webAppApi.getMetricsAndMonitoring();
+    serve(SYSTEM_HEALTHCHECK).with(new HealthCheckServlet(monitoring.getHealth()));
+    serve(SYSTEM_METRICS).with(new MetricsServlet(monitoring.getMetrics()));
+    serve(SYSTEM_PING).with(new PingServlet());
+    serve(SYSTEM_THREADS).with(new ThreadDumpServlet());
 
     String regex = "(?!/ws)";
     serveRegex(regex).with(SliderDefaultWrapperServlet.class); 
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/WebAppApi.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/WebAppApi.java
index 43f8cf6..6aa24c4 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/WebAppApi.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/WebAppApi.java
@@ -16,10 +16,10 @@
  */
 package org.apache.slider.server.appmaster.web;
 
-import com.codahale.metrics.MetricRegistry;
 import org.apache.hadoop.registry.client.api.RegistryOperations;
 import org.apache.slider.api.SliderClusterProtocol;
 import org.apache.slider.providers.ProviderService;
+import org.apache.slider.server.appmaster.management.MetricsAndMonitoring;
 import org.apache.slider.server.appmaster.state.AppState;
 import org.apache.slider.server.appmaster.state.RoleStatus;
 import org.apache.slider.server.appmaster.state.StateAccessForProviders;
@@ -68,5 +68,5 @@
 
   RegistryOperations getRegistryOperations();
 
-  MetricRegistry getMetrics();
+  MetricsAndMonitoring getMetricsAndMonitoring();
 }
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/WebAppApiImpl.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/WebAppApiImpl.java
index 81e6564..36d4a8f 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/WebAppApiImpl.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/WebAppApiImpl.java
@@ -16,10 +16,10 @@
  */
 package org.apache.slider.server.appmaster.web;
 
-import com.codahale.metrics.MetricRegistry;
 import org.apache.hadoop.registry.client.api.RegistryOperations;
 import org.apache.slider.api.SliderClusterProtocol;
 import org.apache.slider.providers.ProviderService;
+import org.apache.slider.server.appmaster.management.MetricsAndMonitoring;
 import org.apache.slider.server.appmaster.state.RoleStatus;
 import org.apache.slider.server.appmaster.state.StateAccessForProviders;
 import org.apache.slider.server.appmaster.web.rest.agent.AgentRestOperations;
@@ -44,14 +44,14 @@
   protected final ProviderService provider;
   protected final CertificateManager certificateManager;
   private final RegistryOperations registryOperations;
-  private final MetricRegistry metrics;
+  private final MetricsAndMonitoring metricsAndMonitoring;
 
   public WebAppApiImpl(SliderClusterProtocol clusterProto,
       StateAccessForProviders appState,
       ProviderService provider,
       CertificateManager certificateManager,
       RegistryOperations registryOperations,
-      MetricRegistry metrics) {
+      MetricsAndMonitoring metricsAndMonitoring) {
     this.registryOperations = registryOperations;
     checkNotNull(clusterProto);
     checkNotNull(appState);
@@ -61,7 +61,7 @@
     this.appState = appState;
     this.provider = provider;
     this.certificateManager = certificateManager;
-    this.metrics = metrics;
+    this.metricsAndMonitoring = metricsAndMonitoring;
   }
 
   @Override
@@ -106,7 +106,7 @@
   }
 
   @Override
-  public MetricRegistry getMetrics() {
-    return metrics;
+  public MetricsAndMonitoring getMetricsAndMonitoring() {
+    return metricsAndMonitoring;
   }
 }
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 75788f9..9efd93b 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
@@ -65,7 +65,7 @@
 
   public static final String SLIDER_CLASSPATH = "classpath";
   public static final String SYSTEM = "/system";
-  public static final String SYSTEM_HEALTHCHECK = SYSTEM + "/healthcheck";
+  public static final String SYSTEM_HEALTHCHECK = SYSTEM + "/health";
   public static final String SYSTEM_METRICS = SYSTEM + "/metrics";
   public static final String SYSTEM_PING = SYSTEM + "/ping";
   public static final String SYSTEM_THREADS = SYSTEM + "/threads";
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/AgentWebApp.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/AgentWebApp.java
index f8d7b88..f9ea06d 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/AgentWebApp.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/AgentWebApp.java
@@ -115,7 +115,6 @@
       AgentWebApp webApp = new AgentWebApp();
       webApp.setPort(getConnectorPort(agentServer, 0));
       webApp.setSecuredPort(getConnectorPort(agentServer, 1));
-
       return webApp;
 
     }
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 d367d18..cf5e3ae 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
@@ -18,6 +18,7 @@
 
 import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
 import org.apache.slider.server.appmaster.web.SliderAMWebApp;
+import org.apache.slider.server.appmaster.web.rest.RestPaths;
 
 /**
  * 
@@ -32,6 +33,15 @@
         ul().
           li().a(this.prefix(), "Overview")._().
           li().a(this.prefix() + SliderAMWebApp.CONTAINER_STATS, "Statistics")._().
-          li().a(this.prefix() + SliderAMWebApp.CLUSTER_SPEC, "Specification")._()._()._();
+          li().a(this.prefix() + SliderAMWebApp.CLUSTER_SPEC, "Specification")._().
+          li().a(rootPath(RestPaths.SYSTEM_METRICS), "Metrics")._().
+          li().a(rootPath(RestPaths.SYSTEM_HEALTHCHECK), "Health")._().
+          li().a(rootPath(RestPaths.SYSTEM_THREADS), "Threads")._()
+        ._()
+      ._();
+  }
+
+  private String rootPath(String absolutePath) {
+    return root_url(absolutePath);
   }
 }
diff --git a/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneAgentWeb.groovy b/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneAgentWeb.groovy
index 458c921..e868b8f 100644
--- a/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneAgentWeb.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneAgentWeb.groovy
@@ -71,8 +71,9 @@
 
     GET(appmaster)
 
-//    GET(appmaster, RestPaths.SYSTEM_HEALTHCHECK)
-//    GET(appmaster, RestPaths.SYSTEM_PING)
+    log.info GET(appmaster, RestPaths.SYSTEM_PING)
+    log.info GET(appmaster, RestPaths.SYSTEM_THREADS)
+    log.info GET(appmaster, RestPaths.SYSTEM_HEALTHCHECK)
     
   }
 
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 7abb123..2cc13c2 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
@@ -17,8 +17,8 @@
 
 package org.apache.slider.server.appmaster.model.mock
 
-import com.codahale.metrics.MetricRegistry
 import org.apache.slider.providers.ProviderRole
+import org.apache.slider.server.appmaster.management.MetricsAndMonitoring
 import org.apache.slider.server.appmaster.state.AbstractRecordFactory
 import org.apache.slider.server.appmaster.state.AppState
 
@@ -28,7 +28,7 @@
 class MockAppState extends AppState {
 
   public MockAppState(AbstractRecordFactory recordFactory) {
-    super(recordFactory, new MetricRegistry());
+    super(recordFactory, new MetricsAndMonitoring());
   }
 
   long time = 0;
@@ -37,7 +37,7 @@
    * Instance with a mock record factory
    */
   public MockAppState() {
-    super(new MockRecordFactory(), new MetricRegistry());
+    super(new MockRecordFactory(), new MetricsAndMonitoring());
   }
 
   public Map<String, ProviderRole> getRoleMap() {
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/monkey/TestMockMonkey.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/monkey/TestMockMonkey.groovy
index e4a42fc..82192b9 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/monkey/TestMockMonkey.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/monkey/TestMockMonkey.groovy
@@ -54,7 +54,7 @@
     def configuration = new YarnConfiguration()
     queues = new QueueService();
     queues.init(configuration)
-    monkey = new ChaosMonkeyService(metricRegistry, queues)
+    monkey = new ChaosMonkeyService(metrics.metrics, queues)
     monkey.init(configuration)
   }
   
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/web/view/TestContainerStatsBlock.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/web/view/TestContainerStatsBlock.groovy
index 4f1d52d..669c00e 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/web/view/TestContainerStatsBlock.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/web/view/TestContainerStatsBlock.groovy
@@ -64,7 +64,7 @@
         providerAppState,
         providerService,
         null,
-        null, metricRegistry);
+        null, metrics);
 
     Injector injector = Guice.createInjector(new AbstractModule() {
           @Override
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 ff24b82..82e36f5 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
@@ -56,7 +56,7 @@
         providerAppState,
         providerService,
         null,
-        null, metricRegistry);
+        null, metrics);
 
     Injector injector = Guice.createInjector(new AbstractModule() {
           @Override
diff --git a/slider-core/src/test/groovy/org/apache/slider/test/SliderTestBase.groovy b/slider-core/src/test/groovy/org/apache/slider/test/SliderTestBase.groovy
index e0798a4..7be7869 100644
--- a/slider-core/src/test/groovy/org/apache/slider/test/SliderTestBase.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/test/SliderTestBase.groovy
@@ -22,6 +22,7 @@
 import groovy.transform.CompileStatic
 import org.apache.hadoop.fs.FileUtil
 import org.apache.slider.common.SliderXMLConfKeysForTesting
+import org.apache.slider.server.appmaster.management.MetricsAndMonitoring
 import org.junit.Before
 import org.junit.BeforeClass
 import org.junit.Rule
@@ -41,7 +42,7 @@
   /**
    * Singleton metric registry
    */
-  public static final MetricRegistry metricRegistry = new MetricRegistry()
+  public static final MetricsAndMonitoring metrics = new MetricsAndMonitoring()
   
   @Rule
   public TestName methodName = new TestName();
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 db8223a..f2a7569 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
@@ -18,7 +18,6 @@
 
 package org.apache.slider.server.appmaster.web.rest.agent;
 
-import com.codahale.metrics.MetricRegistry;
 import com.sun.jersey.api.client.Client;
 import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.api.client.WebResource;
@@ -34,6 +33,7 @@
 import org.apache.slider.common.SliderKeys;
 import org.apache.slider.common.tools.SliderUtils;
 import org.apache.slider.core.conf.MapOperations;
+import org.apache.slider.server.appmaster.management.MetricsAndMonitoring;
 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.MockRecordFactory;
@@ -122,7 +122,7 @@
           historyPath =
           new org.apache.hadoop.fs.Path(historyWorkDir.toURI());
       fs.delete(historyPath, true);
-      appState = new AppState(new MockRecordFactory(), new MetricRegistry());
+      appState = new AppState(new MockRecordFactory(), new MetricsAndMonitoring());
       appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES);
       appState.buildInstance(
           factory.newInstanceDefinition(0, 0, 0),
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 9bfcd25..0776afc 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
@@ -18,7 +18,6 @@
 
 package org.apache.slider.server.appmaster.web.rest.management;
 
-import com.codahale.metrics.MetricRegistry;
 import com.google.inject.Guice;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
@@ -40,6 +39,7 @@
 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.MockFactory;
 import org.apache.slider.server.appmaster.model.mock.MockProviderService;
 import org.apache.slider.server.appmaster.model.mock.MockRecordFactory;
@@ -168,7 +168,7 @@
               historyPath =
               new org.apache.hadoop.fs.Path(historyWorkDir.toURI());
           fs.delete(historyPath, true);
-          appState = new AppState(new MockRecordFactory(), new MetricRegistry());
+          appState = new AppState(new MockRecordFactory(), new MetricsAndMonitoring());
           appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES);
           appState.buildInstance(
               factory.newInstanceDefinition(0, 0, 0),
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 b3959af..4757d77 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
@@ -1225,6 +1225,7 @@
       fail(errorText + "\n" + outfile.text)
     }
   }
+ 
   /**
    * Is the registry accessible for an application?
    * @param args argument map containing <code>"application"</code>
@@ -1262,4 +1263,54 @@
     assert f.exists()
     return Outcome.fromBool(f.text.contains(text))
   }
+
+  /**
+   * Probe callback for is the the app root web page up
+   * @param args map where 'applicationId' must be set
+   * @return the outcome
+   */
+  protected static Outcome isRootWebPageUp(
+      Map<String, String> args) {
+    assert args['applicationId'] != null
+    String applicationId = args['applicationId'];
+    def sar = lookupApplication(applicationId)
+    assert sar != null;
+    if (!sar.url) {
+      return Outcome.Retry;
+    }
+    try {
+      GET(sar.url)
+      return Outcome.Success
+    } catch (Exception e) {
+      return Outcome.Retry;
+    }
+  }
+
+  /**
+   * Await for the root web page of an app to come up
+   * @param applicationId app ID
+   * @param launch_timeout launch timeout
+   */
+  void expectRootWebPageUp(
+      String applicationId,
+      int launch_timeout) {
+
+    repeatUntilSuccess(
+        "await root web page",
+        this.&isRootWebPageUp,
+        launch_timeout,
+        PROBE_SLEEP_TIME,
+        [
+         applicationId: applicationId
+        ],
+        false,
+        "web page not up") {
+
+      def sar = lookupApplication(applicationId)
+      assert sar != null;
+      assert sar.url
+      // this is the final failure cause
+      GET(sar.url)
+    }
+  }
 }
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
new file mode 100644
index 0000000..416fa11
--- /dev/null
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentWebPagesIT.groovy
@@ -0,0 +1,92 @@
+/*
+ * 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.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.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.apache.slider.server.appmaster.web.rest.RestPaths
+import org.apache.slider.test.Outcome
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+
+import static org.apache.slider.core.registry.info.CustomRegistryConstants.*
+
+@CompileStatic
+@Slf4j
+public class AgentWebPagesIT extends AgentCommandTestBase
+    implements FuntestProperties, Arguments, SliderExitCodes, SliderActions {
+
+
+  static String CLUSTER = "test-agent-web"
+
+  static String APP_RESOURCE2 = "../slider-core/src/test/app_packages/test_command_log/resources_no_role.json"
+
+
+  @Before
+  public void prepareCluster() {
+    setupCluster(CLUSTER)
+  }
+
+  @After
+  public void destroyCluster() {
+    cleanup(CLUSTER)
+  }
+
+  @Test
+  public void testAgentWeb() throws Throwable {
+    describe("Create a 0-role cluster and make web queries against it")
+    def clusterpath = buildClusterPath(CLUSTER)
+    File launchReportFile = createTempJsonFile();
+    SliderShell shell = createTemplatedSliderApplication(CLUSTER,
+        APP_TEMPLATE,
+        APP_RESOURCE2,
+        [],
+        launchReportFile)
+
+    logShell(shell)
+
+    def appId = ensureYarnApplicationIsUp(launchReportFile)
+    assert appId
+    expectRootWebPageUp(appId, instanceLaunchTime)
+    File liveReportFile = createTempJsonFile();
+
+    lookup(appId,liveReportFile)
+    def report = loadAppReport(liveReportFile)
+    assert report.url
+
+    def root = report.url
+    log.info GET(root, RestPaths.SYSTEM_METRICS)
+    GET(root, RestPaths.SYSTEM_THREADS)
+    log.info GET(root, RestPaths.SYSTEM_HEALTHCHECK)
+    log.info GET(root, RestPaths.SYSTEM_PING)
+  }
+
+}
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/AppsThroughAgentDemo.groovy
index 0f940cf..3dd7857 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/AppsThroughAgentDemo.groovy
@@ -39,7 +39,7 @@
 
   @Override
   void destroyCluster() {
-    super.destroyCluster()
+//    super.destroyCluster()
   }
   
 }