You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2013/11/20 02:12:27 UTC

[7/7] git commit: AMBARI-3818. Define metrics with stack definition. (ncole)

AMBARI-3818. Define metrics with stack definition. (ncole)


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

Branch: refs/heads/trunk
Commit: a1058b555c5ee7537f749a447f20a416795f80b5
Parents: 029c91d
Author: Nate Cole <nc...@hortonworks.com>
Authored: Tue Nov 19 15:58:07 2013 -0500
Committer: Nate Cole <nc...@hortonworks.com>
Committed: Tue Nov 19 20:11:47 2013 -0500

----------------------------------------------------------------------
 .../server/api/services/AmbariMetaInfo.java     |    63 +-
 .../server/api/util/StackExtensionHelper.java   |    14 +-
 .../ambari/server/controller/AmbariServer.java  |     8 +-
 .../internal/AbstractProviderModule.java        |    48 +-
 .../internal/StackDefinedPropertyProvider.java  |   253 +
 .../apache/ambari/server/state/ServiceInfo.java |    34 +
 .../ambari/server/state/stack/Metric.java       |    37 +
 .../server/state/stack/MetricDefinition.java    |    54 +
 .../HDP/2.0.6/services/HBASE/metrics.json       | 13625 +++++++++++++++++
 .../stacks/HDP/2.0.6/services/HDFS/metrics.json |  7790 ++++++++++
 .../HDP/2.0.6/services/MAPREDUCE2/metrics.json  |   383 +
 .../stacks/HDP/2.0.6/services/YARN/metrics.json |  2494 +++
 .../server/api/services/AmbariMetaInfoTest.java |    35 +-
 .../AmbariManagementControllerTest.java         |     4 +-
 .../ganglia/GangliaPropertyProviderTest.java    |     2 +-
 .../StackDefinedPropertyProviderTest.java       |   266 +
 .../controller/jmx/JMXPropertyProviderTest.java |     4 +-
 .../stacks/HDP/2.0.5/services/HDFS/metrics.json |  1988 +++
 18 files changed, 27074 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/a1058b55/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index e881fb6..942be70 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -19,9 +19,12 @@
 package org.apache.ambari.server.api.services;
 
 import java.io.File;
+import java.io.FileReader;
 import java.io.FilenameFilter;
 import java.io.IOException;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -45,13 +48,15 @@ import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.Stack;
 import org.apache.ambari.server.state.StackInfo;
+import org.apache.ambari.server.state.stack.MetricDefinition;
 import org.apache.ambari.server.state.stack.RepositoryXml;
 import org.apache.ambari.server.state.stack.RepositoryXml.Os;
 import org.apache.ambari.server.state.stack.RepositoryXml.Repo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import java.util.Arrays;
 
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
@@ -74,11 +79,11 @@ public class AmbariMetaInfo {
   private static final String REPOSITORY_FOLDER_NAME = "repos";
   private static final String REPOSITORY_XML_PROPERTY_BASEURL = "baseurl";
   // all the supported OS'es
-  private static final ArrayList<String> ALL_SUPPORTED_OS = new
-    ArrayList<String>(
-    Arrays.asList("centos5", "redhat5", "centos6", "redhat6", "oraclelinux5",
-      "oraclelinux6", "suse11", "sles11", "ubuntu12")
-  );
+  private static final List<String> ALL_SUPPORTED_OS = Arrays.asList(
+      "centos5", "redhat5", "centos6", "redhat6", "oraclelinux5",
+      "oraclelinux6", "suse11", "sles11", "ubuntu12");
+  
+  public static final String SERVICE_METRIC_FILE_NAME = "metrics.json";
 
   public static final FilenameFilter FILENAME_FILTER = new FilenameFilter() {
     @Override
@@ -754,5 +759,51 @@ public class AmbariMetaInfo {
   public File getStackRoot() {
     return stackRoot;
   }
+  
+  /**
+   * Gets the metrics for a Role (component).
+   * @return the list of defined metrics.
+   */
+  public List<MetricDefinition> getMetrics(String stackName, String stackVersion,
+      String serviceName, String componentName, String metricType)
+  throws AmbariException {
+    
+    ServiceInfo svc = getService(stackName, stackVersion, serviceName);
+    
+    if (null == svc.getMetricsFile() || !svc.getMetricsFile().exists()) {
+      LOG.debug("Metrics file for " + stackName + "/" + stackVersion + "/" + serviceName + " not found.");
+      return null;
+    }
+    
+    Map<String, Map<String, List<MetricDefinition>>> map = svc.getMetrics();
+    
+    // check for cached
+    if (null == map) {
+      // data layout:
+      // "DATANODE" -> "Component" -> [ MetricDefinition, MetricDefinition, ... ]
+      //           \-> "HostComponent" -> [ MetricDefinition, ... ]
+      Type type = new TypeToken<Map<String, Map<String, List<MetricDefinition>>>>(){}.getType();
+      
+      Gson gson = new Gson();
+
+      try {
+        map = gson.fromJson(new FileReader(svc.getMetricsFile()), type);
+    
+        svc.setMetrics(map);
+        
+      } catch (Exception e) {
+        LOG.error ("Could not read the metrics file", e);
+        throw new AmbariException("Could not read metrics file", e);
+      }
+    }
+    
+    if (map.containsKey(componentName)) {
+      if (map.get(componentName).containsKey(metricType)) {
+        return map.get(componentName).get(metricType);
+      }
+    }
+	  
+	  return null;
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/a1058b55/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
index 93f93bc..6307db3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/util/StackExtensionHelper.java
@@ -96,6 +96,11 @@ public class StackExtensionHelper {
     mergedServiceInfo.setUser(childService.getUser());
     mergedServiceInfo.setVersion(childService.getVersion());
     mergedServiceInfo.setConfigDependencies(childService.getConfigDependencies());
+    
+    // metrics
+    if (null == childService.getMetricsFile() && null != parentService.getMetricsFile())
+      mergedServiceInfo.setMetricsFile(parentService.getMetricsFile());
+    
     // Add all child components to service
     List<String> deleteList = new ArrayList<String>();
     List<String> appendList = new ArrayList<String>();
@@ -203,8 +208,15 @@ public class StackExtensionHelper {
           serviceInfo.setName(serviceFolder.getName());
           File metainfoFile = new File(serviceFolder.getAbsolutePath()
             + File.separator + AmbariMetaInfo.SERVICE_METAINFO_FILE_NAME);
-
+          
           setMetaInfo(metainfoFile, serviceInfo);
+          
+          // get metrics file, if it exists
+          File metricsJson = new File(serviceFolder.getAbsolutePath()
+              + File.separator + AmbariMetaInfo.SERVICE_METRIC_FILE_NAME);
+          if (metricsJson.exists())
+            serviceInfo.setMetricsFile(metricsJson);
+          
           // Add now to be removed while iterating extension graph
           services.add(serviceInfo);
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/a1058b55/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 24e09bc..ea5a017 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -20,10 +20,11 @@ package org.apache.ambari.server.controller;
 
 
 import java.io.File;
-import javax.crypto.BadPaddingException;
 import java.net.BindException;
 import java.util.Map;
 
+import javax.crypto.BadPaddingException;
+
 import org.apache.ambari.eventdb.webservice.WorkflowJsonService;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.ActionManager;
@@ -37,8 +38,10 @@ import org.apache.ambari.server.api.services.KeyService;
 import org.apache.ambari.server.api.services.PersistKeyValueImpl;
 import org.apache.ambari.server.api.services.PersistKeyValueService;
 import org.apache.ambari.server.bootstrap.BootStrapImpl;
-import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.internal.ClusterControllerImpl;
+import org.apache.ambari.server.controller.internal.StackDefinedPropertyProvider;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.PersistenceType;
 import org.apache.ambari.server.orm.dao.MetainfoDAO;
@@ -439,6 +442,7 @@ public class AmbariServer {
     WorkflowJsonService.setDBProperties(
         injector.getInstance(Configuration.class));
     SecurityFilter.init(injector.getInstance(Configuration.class));
+    StackDefinedPropertyProvider.init(injector);
   }
 
   public static void main(String[] args) throws Exception {

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/a1058b55/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
index d025f48..de9e5f8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractProviderModule.java
@@ -357,8 +357,9 @@ public abstract class AbstractProviderModule implements ProviderModule, Resource
             PropertyHelper.getPropertyId("Hosts", "host_name")
         ));
         break;
-      case Component :
-        providers.add(createJMXPropertyProvider(
+      case Component : {
+        // TODO as we fill out stack metric definitions, these can be phased out
+        PropertyProvider jpp = createJMXPropertyProvider(
             type,
             streamProvider,
             this,
@@ -366,18 +367,32 @@ public abstract class AbstractProviderModule implements ProviderModule, Resource
             null,
             PropertyHelper.getPropertyId("ServiceComponentInfo", "component_name"),
             PropertyHelper.getPropertyId("ServiceComponentInfo", "state"),
-            Collections.singleton("STARTED")));
+            Collections.singleton("STARTED"));
 
-        providers.add(createGangliaComponentPropertyProvider(
+        PropertyProvider gpp = createGangliaComponentPropertyProvider(
             type,
             streamProvider,
             ComponentSSLConfiguration.instance(),
             this,
             PropertyHelper.getPropertyId("ServiceComponentInfo", "cluster_name"),
-            PropertyHelper.getPropertyId("ServiceComponentInfo", "component_name")));
+            PropertyHelper.getPropertyId("ServiceComponentInfo", "component_name"));
+        
+        providers.add(new StackDefinedPropertyProvider(
+            type,
+            this,
+            this,
+            streamProvider,
+            PropertyHelper.getPropertyId("ServiceComponentInfo", "cluster_name"),
+            PropertyHelper.getPropertyId("ServiceComponentInfo", "host_name"),
+            PropertyHelper.getPropertyId("ServiceComponentInfo", "component_name"),
+            PropertyHelper.getPropertyId("ServiceComponentInfo", "state"),
+            jpp,
+            gpp));
+        }
         break;
-      case HostComponent:
-        providers.add(createJMXPropertyProvider(
+      case HostComponent: {
+        // TODO as we fill out stack metric definitions, these can be phased out
+        PropertyProvider jpp = createJMXPropertyProvider(
             type,
             streamProvider,
             this,
@@ -385,17 +400,29 @@ public abstract class AbstractProviderModule implements ProviderModule, Resource
             PropertyHelper.getPropertyId("HostRoles", "host_name"),
             PropertyHelper.getPropertyId("HostRoles", "component_name"),
             PropertyHelper.getPropertyId("HostRoles", "state"),
-            Collections.singleton("STARTED")));
+            Collections.singleton("STARTED"));
 
-        providers.add(createGangliaHostComponentPropertyProvider(
+        PropertyProvider gpp = createGangliaHostComponentPropertyProvider(
             type,
             streamProvider,
             ComponentSSLConfiguration.instance(),
             this,
             PropertyHelper.getPropertyId("HostRoles", "cluster_name"),
             PropertyHelper.getPropertyId("HostRoles", "host_name"),
-            PropertyHelper.getPropertyId("HostRoles", "component_name")));
+            PropertyHelper.getPropertyId("HostRoles", "component_name"));
         
+        providers.add(new StackDefinedPropertyProvider(
+            type,
+            this,
+            this,
+            streamProvider,
+            PropertyHelper.getPropertyId("HostRoles", "cluster_name"),
+            PropertyHelper.getPropertyId("HostRoles", "host_name"),
+            PropertyHelper.getPropertyId("HostRoles", "component_name"),
+            PropertyHelper.getPropertyId("HostRoles", "state"),
+            jpp,
+            gpp));
+        }
         break;
       default :
         break;
@@ -693,6 +720,7 @@ public abstract class AbstractProviderModule implements ProviderModule, Resource
     return new VersioningPropertyProvider(clusterVersionsMap, providers, lastProvider, clusterNamePropertyId);
   }
 
+
   /**
    * Create the Ganglia host component property provider for the given type.
    */

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/a1058b55/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackDefinedPropertyProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackDefinedPropertyProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackDefinedPropertyProvider.java
new file mode 100644
index 0000000..51c7565
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackDefinedPropertyProvider.java
@@ -0,0 +1,253 @@
+/**
+ * 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.ambari.server.controller.internal;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
+import org.apache.ambari.server.controller.ganglia.GangliaComponentPropertyProvider;
+import org.apache.ambari.server.controller.ganglia.GangliaHostComponentPropertyProvider;
+import org.apache.ambari.server.controller.ganglia.GangliaHostProvider;
+import org.apache.ambari.server.controller.ganglia.GangliaPropertyProvider;
+import org.apache.ambari.server.controller.jmx.JMXHostProvider;
+import org.apache.ambari.server.controller.jmx.JMXPropertyProvider;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.PropertyProvider;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.utilities.StreamProvider;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.stack.Metric;
+import org.apache.ambari.server.state.stack.MetricDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
+/**
+ * This class analyzes a service's metrics to determine if additional
+ * metrics should be fetched.  It's okay to maintain state here since these
+ * are done per-request.
+ *
+ */
+public class StackDefinedPropertyProvider implements PropertyProvider {
+  private static final Logger LOG = LoggerFactory.getLogger(StackDefinedPropertyProvider.class);
+  
+  @Inject
+  private static Clusters clusters = null;
+  @Inject
+  private static AmbariMetaInfo metaInfo = null;
+  
+  private Resource.Type type = null;
+  private String clusterNamePropertyId = null;
+  private String hostNamePropertyId = null;
+  private String componentNamePropertyId = null;
+  private String jmxStatePropertyId = null;
+  private ComponentSSLConfiguration sslConfig = null;
+  private StreamProvider streamProvider = null;
+  private JMXHostProvider jmxHostProvider;
+  private GangliaHostProvider gangliaHostProvider;
+  private PropertyProvider defaultJmx = null;
+  private PropertyProvider defaultGanglia = null;
+  
+  @Inject
+  public static void init(Injector injector) {
+    clusters = injector.getInstance(Clusters.class);
+    metaInfo = injector.getInstance(AmbariMetaInfo.class);
+  }
+  
+  public StackDefinedPropertyProvider(Resource.Type type,
+      JMXHostProvider jmxHostProvider,
+      GangliaHostProvider gangliaHostProvider,
+      StreamProvider streamProvider,
+      String clusterPropertyId,
+      String hostPropertyId,
+      String componentPropertyId,
+      String jmxStatePropertyId,
+      PropertyProvider defaultJmxPropertyProvider,
+      PropertyProvider defaultGangliaPropertyProvider
+      ) {
+    
+    if (null == clusterPropertyId)
+      throw new NullPointerException("Cluster name property id cannot be null");
+    if (null == componentPropertyId)
+      throw new NullPointerException("Component name property id cannot be null");
+    
+    this.type = type;
+    
+    clusterNamePropertyId = clusterPropertyId;
+    hostNamePropertyId = hostPropertyId;
+    componentNamePropertyId = componentPropertyId;
+    this.jmxStatePropertyId = jmxStatePropertyId;
+    this.jmxHostProvider = jmxHostProvider;
+    this.gangliaHostProvider = gangliaHostProvider;
+    sslConfig = ComponentSSLConfiguration.instance();
+    this.streamProvider = streamProvider;
+    defaultJmx = defaultJmxPropertyProvider;
+    defaultGanglia = defaultGangliaPropertyProvider;
+  }
+      
+  
+  @Override
+  public Set<Resource> populateResources(Set<Resource> resources,
+      Request request, Predicate predicate) throws SystemException {
+
+    // only arrange for one instance of Ganglia and JMX instantiation
+    Map<String, Map<String, PropertyInfo>> gangliaMap = new HashMap<String, Map<String,PropertyInfo>>();
+    Map<String, Map<String, PropertyInfo>> jmxMap = new HashMap<String, Map<String, PropertyInfo>>();
+
+    List<PropertyProvider> additional = new ArrayList<PropertyProvider>();
+    
+    try {
+      for (Resource r : resources) {
+        String clusterName = r.getPropertyValue(clusterNamePropertyId).toString();
+        String componentName = r.getPropertyValue(componentNamePropertyId).toString();
+        
+        Cluster cluster = clusters.getCluster(clusterName);
+        StackId stack = cluster.getDesiredStackVersion();
+        String svc = metaInfo.getComponentToService(stack.getStackName(),
+            stack.getStackVersion(), componentName);
+        
+        List<MetricDefinition> defs = metaInfo.getMetrics(
+            stack.getStackName(), stack.getStackVersion(), svc, componentName, type.name());
+        
+        if (null == defs || 0 == defs.size())
+          continue;
+        
+        for (MetricDefinition m : defs) {
+          if (m.getType().equals("ganglia")) {
+            gangliaMap.put(componentName, getPropertyInfo(m));
+          } else if (m.getType().equals("jmx")) {
+            jmxMap.put(componentName, getPropertyInfo(m));
+          } else {
+            PropertyProvider pp = getDelegate(m);
+            if (null != pp)
+              additional.add(pp);
+          }
+        }
+      }
+        
+      if (gangliaMap.size() > 0) {
+        GangliaPropertyProvider gpp = type.equals (Resource.Type.Component) ?
+          new GangliaComponentPropertyProvider(gangliaMap,
+              streamProvider, sslConfig, gangliaHostProvider,
+              clusterNamePropertyId, componentNamePropertyId) :
+          new GangliaHostComponentPropertyProvider(gangliaMap,
+              streamProvider, sslConfig, gangliaHostProvider,
+              clusterNamePropertyId, hostNamePropertyId, componentNamePropertyId);
+          
+          gpp.populateResources(resources, request, predicate);
+      } else {
+        defaultGanglia.populateResources(resources, request, predicate);
+      }
+      
+      if (jmxMap.size() > 0) {
+        JMXPropertyProvider jpp = new JMXPropertyProvider(jmxMap, streamProvider,
+            jmxHostProvider, clusterNamePropertyId, hostNamePropertyId,
+            componentNamePropertyId, jmxStatePropertyId, Collections.singleton("STARTED"));
+        
+        jpp.populateResources(resources, request, predicate);
+      } else {
+        defaultJmx.populateResources(resources, request, predicate);
+      }
+      
+      for (PropertyProvider pp : additional) {
+        pp.populateResources(resources, request, predicate);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw new SystemException("Error loading deferred resources", e);
+    }
+    
+    return resources;
+  }
+
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+    return Collections.emptySet();
+  }
+  
+  /**
+   * @param def the metric definition
+   * @return the converted Map required for JMX or Ganglia execution
+   */
+  private  Map<String, PropertyInfo> getPropertyInfo(MetricDefinition def) {
+    Map<String, PropertyInfo> defs = new HashMap<String, PropertyInfo>();
+    
+    for (Entry<String,Metric> entry : def.getMetrics().entrySet()) {
+      Metric metric = entry.getValue();
+      defs.put(entry.getKey(), new PropertyInfo(
+          metric.getName(), metric.isTemporal(), metric.isPointInTime()));
+    }
+    
+    return defs;
+  }
+  
+  /**
+   * @param the metric definition for a component and resource type combination
+   * @return the custom property provider
+   */
+  private PropertyProvider getDelegate(MetricDefinition definition) {
+      try {
+        Class<?> clz = Class.forName(definition.getType());
+
+        // singleton/factory
+        try {
+          Method m = clz.getMethod("getInstance", Map.class, Map.class);
+          Object o = m.invoke(null, definition.getProperties(), definition.getMetrics());
+          return PropertyProvider.class.cast(o);
+        } catch (Exception e) {
+          LOG.info("Could not load singleton or factory method for type '" +
+              definition.getType());
+        }
+        
+        // try maps constructor        
+        try {
+          Constructor<?> ct = clz.getConstructor(Map.class, Map.class);
+          Object o = ct.newInstance(definition.getProperties(), definition.getMetrics());
+          return PropertyProvider.class.cast(o);
+        } catch (Exception e) {
+          LOG.info("Could not find contructor for type '" +
+              definition.getType());
+        }
+        
+        // just new instance
+        return PropertyProvider.class.cast(clz.newInstance());
+
+      } catch (Exception e) {
+        LOG.error("Could not load class " + definition.getType());
+        return null;
+      }
+  }
+  
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/a1058b55/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
index 238c388..fcc3c37 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.state;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -28,6 +29,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.ambari.server.controller.StackServiceResponse;
+import org.apache.ambari.server.state.stack.MetricDefinition;
 import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.map.annotate.JsonFilter;
 
@@ -43,6 +45,9 @@ public class ServiceInfo {
   @JsonIgnore
   private volatile Map<String, Set<String>> configLayout = null;
   private List<String> configDependencies;
+  
+  private File metricsFile = null;
+  private Map<String, Map<String, List<MetricDefinition>>> metrics = null;
 
   public boolean isDeleted() {
     return isDeleted;
@@ -213,4 +218,33 @@ public class ServiceInfo {
   public void setConfigDependencies(List<String> configDependencies) {
     this.configDependencies = configDependencies;
   }
+
+  /**
+   * @param file the file containing the metrics definitions
+   */
+  public void setMetricsFile(File file) {
+    metricsFile = file;
+  }
+  
+  /**
+   * @return the metrics file, or <code>null</code> if none exists
+   */
+  public File getMetricsFile() {
+    return metricsFile;
+  }
+
+  /**
+   * @return the metrics defined for this service
+   */
+  public Map<String, Map<String, List<MetricDefinition>>> getMetrics() {
+    return metrics;
+  }
+  
+  /**
+   * @param map the metrics for this service
+   */
+  public void setMetrics(Map<String, Map<String, List<MetricDefinition>>> map) {
+    metrics = map;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/a1058b55/ambari-server/src/main/java/org/apache/ambari/server/state/stack/Metric.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/Metric.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/Metric.java
new file mode 100644
index 0000000..403ea80
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/Metric.java
@@ -0,0 +1,37 @@
+/**
+ * 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.ambari.server.state.stack;
+
+public class Metric {
+	private String metric = null;
+	private boolean pointInTime = false;
+	private boolean temporal  = false;
+
+	public String getName() {
+		return metric;
+	}
+	
+	public boolean isPointInTime() {
+		return pointInTime;
+	}
+	
+	public boolean isTemporal() {
+		return temporal;
+	}
+	
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/a1058b55/ambari-server/src/main/java/org/apache/ambari/server/state/stack/MetricDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/MetricDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/MetricDefinition.java
new file mode 100644
index 0000000..d0f517b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/MetricDefinition.java
@@ -0,0 +1,54 @@
+/**
+ * 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.ambari.server.state.stack;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Used to represent metrics for a stack component.
+ */
+public class MetricDefinition {
+  private String type = null;
+  private Map<String, String> properties = null;
+  private Map<String, Metric> metrics = null;
+  
+  public String getType() {
+    return type;
+  }
+  
+  public Map<String, String> getProperties() {
+    return properties;
+  }
+  
+  public Map<String, Metric> getMetrics() {
+    return metrics;
+  }
+  
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("{type=").append(type);
+    sb.append(";properties=").append(properties);
+    sb.append(";metric_count=").append(metrics.size());
+    sb.append('}');
+    
+    return sb.toString();
+  }
+  
+}