You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by di...@apache.org on 2016/01/11 20:15:45 UTC

[09/13] ambari git commit: AMBARI-12885: Dynamic stack extensions - install and upgrade support for custom services (tthorpe via dili)

http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionArtifactResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionArtifactResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionArtifactResourceProvider.java
new file mode 100644
index 0000000..2a0379b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionArtifactResourceProvider.java
@@ -0,0 +1,658 @@
+/**
+ * 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 com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.inject.Inject;
+import com.rits.cloning.Cloner;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.StackAccessException;
+import org.apache.ambari.server.StaticallyInject;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.ambari.server.state.ExtensionInfo;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
+import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptorFactory;
+import org.apache.ambari.server.state.stack.Metric;
+import org.apache.ambari.server.state.stack.MetricDefinition;
+import org.apache.ambari.server.state.stack.WidgetLayout;
+import org.apache.commons.lang.StringUtils;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Provider for extension and extension service artifacts.
+ * Artifacts contain an artifact name as the PK and artifact data in the form of
+ * a map which is the content of the artifact.
+ * <p>
+ * An example of an artifact is a kerberos descriptor.
+ * <p>
+ * Extension artifacts are part of the extension definition and therefore can't
+ * be created, updated or deleted.
+ */
+@StaticallyInject
+public class ExtensionArtifactResourceProvider extends AbstractControllerResourceProvider {
+  /**
+   * extension name
+   */
+  public static final String EXTENSION_NAME_PROPERTY_ID =
+      PropertyHelper.getPropertyId("Artifacts", "extension_name");
+
+  /**
+   * extension version
+   */
+  public static final String EXTENSION_VERSION_PROPERTY_ID =
+      PropertyHelper.getPropertyId("Artifacts", "extension_version");
+
+  /**
+   * extension service name
+   */
+  public static final String EXTENSION_SERVICE_NAME_PROPERTY_ID =
+      PropertyHelper.getPropertyId("Artifacts", "service_name");
+
+  /**
+   * extension service name
+   */
+  public static final String EXTENSION_COMPONENT_NAME_PROPERTY_ID =
+    PropertyHelper.getPropertyId("Artifacts", "component_name");
+
+  /**
+   * artifact name
+   */
+  public static final String ARTIFACT_NAME_PROPERTY_ID =
+      PropertyHelper.getPropertyId("Artifacts", "artifact_name");
+
+  /**
+   * artifact data
+   */
+  public static final String ARTIFACT_DATA_PROPERTY_ID = "artifact_data";
+
+  /**
+   * primary key fields
+   */
+  public static Set<String> pkPropertyIds = new HashSet<String>();
+
+  /**
+   * map of resource type to fk field
+   */
+  public static Map<Resource.Type, String> keyPropertyIds =
+      new HashMap<Resource.Type, String>();
+
+  /**
+   * resource properties
+   */
+  public static Set<String> propertyIds = new HashSet<String>();
+
+  /**
+   * name of the kerberos descriptor artifact.
+   */
+  public static final String KERBEROS_DESCRIPTOR_NAME = "kerberos_descriptor";
+
+  /**
+   * name of the metrics descriptor artifact.
+   */
+  public static final String METRICS_DESCRIPTOR_NAME = "metrics_descriptor";
+
+  /**
+   * name of the widgets descriptor artifact.
+   */
+  public static final String WIDGETS_DESCRIPTOR_NAME = "widgets_descriptor";
+
+  /**
+   * KerberosDescriptorFactory used to create KerberosDescriptor instances
+   */
+  @Inject
+  private static KerberosDescriptorFactory kerberosDescriptorFactory;
+
+  /**
+   * KerberosServiceDescriptorFactory used to create KerberosServiceDescriptor instances
+   */
+  @Inject
+  private static KerberosServiceDescriptorFactory kerberosServiceDescriptorFactory;
+
+  Type widgetLayoutType = new TypeToken<Map<String, List<WidgetLayout>>>(){}.getType();
+  Gson gson = new Gson();
+
+  /**
+   * set resource properties, pk and fk's
+   */
+  static {
+    // resource properties
+    propertyIds.add(EXTENSION_NAME_PROPERTY_ID);
+    propertyIds.add(EXTENSION_VERSION_PROPERTY_ID);
+    propertyIds.add(EXTENSION_SERVICE_NAME_PROPERTY_ID);
+    propertyIds.add(ARTIFACT_NAME_PROPERTY_ID);
+    propertyIds.add(ARTIFACT_DATA_PROPERTY_ID);
+
+    // pk property
+    pkPropertyIds.add(ARTIFACT_NAME_PROPERTY_ID);
+
+    // fk properties
+    keyPropertyIds.put(Resource.Type.ExtensionArtifact, ARTIFACT_NAME_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.Extension, EXTENSION_NAME_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.ExtensionVersion, EXTENSION_VERSION_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.ExtensionService, EXTENSION_SERVICE_NAME_PROPERTY_ID);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param managementController ambari controller
+   */
+  protected ExtensionArtifactResourceProvider(AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException,
+             UnsupportedPropertyException,
+             NoSuchResourceException,
+             NoSuchParentResourceException {
+
+    Set<Resource> resources = new HashSet<Resource>();
+
+    resources.addAll(getKerberosDescriptors(request, predicate));
+    resources.addAll(getMetricsDescriptors(request, predicate));
+    resources.addAll(getWidgetsDescriptors(request, predicate));
+    // add other artifacts types here
+
+    if (resources.isEmpty()) {
+      throw new NoSuchResourceException(
+          "The requested resource doesn't exist: Artifact not found, " + predicate);
+    }
+
+    return resources;
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+  @Override
+  public RequestStatus createResources(Request request)
+      throws SystemException,
+      UnsupportedPropertyException,
+      ResourceAlreadyExistsException,
+      NoSuchParentResourceException {
+
+    throw new UnsupportedOperationException("Creating extension artifacts is not supported");
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException,
+             UnsupportedPropertyException,
+             NoSuchResourceException,
+             NoSuchParentResourceException {
+
+    throw new UnsupportedOperationException("Updating of extension artifacts is not supported");
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException,
+             UnsupportedPropertyException,
+             NoSuchResourceException,
+             NoSuchParentResourceException {
+
+    throw new UnsupportedOperationException("Deletion of extension artifacts is not supported");
+  }
+
+  /**
+   * Get all extension and extension service kerberos descriptor resources.
+   *
+   * @param request    user request
+   * @param predicate  request predicate
+   *
+   * @return set of all extension related kerberos descriptor resources; will not return null
+   *
+   * @throws SystemException                if an unexpected exception occurs
+   * @throws UnsupportedPropertyException   if an unsupported property was requested
+   * @throws NoSuchParentResourceException  if a specified parent resource doesn't exist
+   * @throws NoSuchResourceException        if the requested resource doesn't exist
+   */
+  private Set<Resource> getKerberosDescriptors(Request request, Predicate predicate)
+      throws SystemException,
+             UnsupportedPropertyException,
+             NoSuchParentResourceException,
+             NoSuchResourceException {
+
+    Set<Resource> resources = new HashSet<Resource>();
+
+    for (Map<String, Object> properties : getPropertyMaps(predicate)) {
+      String artifactName = (String) properties.get(ARTIFACT_NAME_PROPERTY_ID);
+      if (artifactName == null || artifactName.equals(KERBEROS_DESCRIPTOR_NAME)) {
+        String extensionName = (String) properties.get(EXTENSION_NAME_PROPERTY_ID);
+        String extensionVersion = (String) properties.get(EXTENSION_VERSION_PROPERTY_ID);
+        String extensionService = (String) properties.get(EXTENSION_SERVICE_NAME_PROPERTY_ID);
+
+        Map<String, Object> descriptor;
+        try {
+          descriptor = getKerberosDescriptor(extensionName, extensionVersion, extensionService);
+        } catch (IOException e) {
+          LOG.error("Unable to process Kerberos Descriptor. Properties: " + properties, e);
+          throw new SystemException("An internal exception occurred while attempting to build a Kerberos Descriptor " +
+              "artifact. See ambari server logs for more information", e);
+        }
+
+        if (descriptor != null) {
+          Resource resource = new ResourceImpl(Resource.Type.ExtensionArtifact);
+          Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+          setResourceProperty(resource, ARTIFACT_NAME_PROPERTY_ID, KERBEROS_DESCRIPTOR_NAME, requestedIds);
+          setResourceProperty(resource, ARTIFACT_DATA_PROPERTY_ID, descriptor, requestedIds);
+          setResourceProperty(resource, EXTENSION_NAME_PROPERTY_ID, extensionName, requestedIds);
+          setResourceProperty(resource, EXTENSION_VERSION_PROPERTY_ID, extensionVersion, requestedIds);
+          if (extensionService != null) {
+            setResourceProperty(resource, EXTENSION_SERVICE_NAME_PROPERTY_ID, extensionService, requestedIds);
+          }
+          resources.add(resource);
+        }
+      }
+    }
+    return resources;
+  }
+
+  /**
+   * Get all extension and extension service metrics descriptor resources.
+   *
+   * @param request    user request
+   * @param predicate  request predicate
+   *
+   * @return set of all extension related kerberos descriptor resources; will not return null
+   *
+   * @throws SystemException                if an unexpected exception occurs
+   * @throws UnsupportedPropertyException   if an unsupported property was requested
+   * @throws NoSuchParentResourceException  if a specified parent resource doesn't exist
+   * @throws NoSuchResourceException        if the requested resource doesn't exist
+   */
+  private Set<Resource> getMetricsDescriptors(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+           NoSuchParentResourceException, NoSuchResourceException {
+
+    Set<Resource> resources = new HashSet<Resource>();
+
+    for (Map<String, Object> properties : getPropertyMaps(predicate)) {
+      String artifactName = (String) properties.get(ARTIFACT_NAME_PROPERTY_ID);
+      if (artifactName == null || artifactName.equals(METRICS_DESCRIPTOR_NAME)) {
+        String extensionName = (String) properties.get(EXTENSION_NAME_PROPERTY_ID);
+        String extensionVersion = (String) properties.get(EXTENSION_VERSION_PROPERTY_ID);
+        String extensionService = (String) properties.get(EXTENSION_SERVICE_NAME_PROPERTY_ID);
+        String componentName = (String) properties.get(EXTENSION_COMPONENT_NAME_PROPERTY_ID);
+
+        Map<String, Object> descriptor;
+        AmbariMetaInfo metaInfo = getManagementController().getAmbariMetaInfo();
+
+        try {
+          List<MetricDefinition> componentMetrics;
+          Map<String, Map<String, List<MetricDefinition>>> serviceMetrics;
+          if (extensionService != null) {
+            if (componentName == null) {
+              // Service
+              serviceMetrics = removeAggregateFunctions(metaInfo.getExtensionServiceMetrics(extensionName,
+                      extensionVersion, extensionService));
+              descriptor = Collections.singletonMap(extensionService, (Object) serviceMetrics);
+            } else {
+              // Component
+              componentMetrics = removeAggregateFunctions(metaInfo.getExtensionMetrics(extensionName,
+                      extensionVersion, extensionService, componentName, Resource.Type.Component.name()));
+              descriptor = Collections.singletonMap(componentName, (Object) componentMetrics);
+            }
+          } else {
+            // Cluster
+            Map<String, Map<String, PropertyInfo>> clusterMetrics =
+              PropertyHelper.getMetricPropertyIds(Resource.Type.Cluster);
+            // Host
+            Map<String, Map<String, PropertyInfo>> hostMetrics =
+              PropertyHelper.getMetricPropertyIds(Resource.Type.Host);
+
+            descriptor = new HashMap<String, Object>();
+            descriptor.put(Resource.Type.Cluster.name(), clusterMetrics);
+            descriptor.put(Resource.Type.Host.name(), hostMetrics);
+          }
+
+
+        } catch (IOException e) {
+          LOG.error("Unable to process Metrics Descriptor. Properties: " + properties, e);
+          throw new SystemException("An internal exception occurred while attempting to build a Metrics Descriptor " +
+            "artifact. See ambari server logs for more information", e);
+        }
+
+        Resource resource = new ResourceImpl(Resource.Type.ExtensionArtifact);
+        Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+        setResourceProperty(resource, ARTIFACT_NAME_PROPERTY_ID, METRICS_DESCRIPTOR_NAME, requestedIds);
+        setResourceProperty(resource, ARTIFACT_DATA_PROPERTY_ID, descriptor, requestedIds);
+        setResourceProperty(resource, EXTENSION_NAME_PROPERTY_ID, extensionName, requestedIds);
+        setResourceProperty(resource, EXTENSION_VERSION_PROPERTY_ID, extensionVersion, requestedIds);
+        if (extensionService != null) {
+          setResourceProperty(resource, EXTENSION_SERVICE_NAME_PROPERTY_ID, extensionService, requestedIds);
+        }
+        resources.add(resource);
+      }
+    }
+    return resources;
+  }
+
+  private Set<Resource> getWidgetsDescriptors(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+             NoSuchParentResourceException, NoSuchResourceException {
+
+    Set<Resource> resources = new HashSet<Resource>();
+
+    for (Map<String, Object> properties : getPropertyMaps(predicate)) {
+      String artifactName = (String) properties.get(ARTIFACT_NAME_PROPERTY_ID);
+      if (artifactName == null || artifactName.equals(WIDGETS_DESCRIPTOR_NAME)) {
+        String extensionName = (String) properties.get(EXTENSION_NAME_PROPERTY_ID);
+        String extensionVersion = (String) properties.get(EXTENSION_VERSION_PROPERTY_ID);
+        String extensionService = (String) properties.get(EXTENSION_SERVICE_NAME_PROPERTY_ID);
+
+        Map<String, Object> descriptor;
+        try {
+          descriptor = getWidgetsDescriptor(extensionName, extensionVersion, extensionService);
+        } catch (IOException e) {
+          LOG.error("Unable to process Widgets Descriptor. Properties: " + properties, e);
+          throw new SystemException("An internal exception occurred while attempting to build a Widgets Descriptor " +
+            "artifact. See ambari server logs for more information", e);
+        }
+
+        if (descriptor != null) {
+          Resource resource = new ResourceImpl(Resource.Type.ExtensionArtifact);
+          Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+          setResourceProperty(resource, ARTIFACT_NAME_PROPERTY_ID, WIDGETS_DESCRIPTOR_NAME, requestedIds);
+          setResourceProperty(resource, ARTIFACT_DATA_PROPERTY_ID, descriptor, requestedIds);
+          setResourceProperty(resource, EXTENSION_NAME_PROPERTY_ID, extensionName, requestedIds);
+          setResourceProperty(resource, EXTENSION_VERSION_PROPERTY_ID, extensionVersion, requestedIds);
+          if (extensionService != null) {
+            setResourceProperty(resource, EXTENSION_SERVICE_NAME_PROPERTY_ID, extensionService, requestedIds);
+          }
+          resources.add(resource);
+        }
+      }
+    }
+    return resources;
+  }
+
+  private Map<String, Object> getWidgetsDescriptor(String extensionName,
+      String extensionVersion, String serviceName)
+        throws NoSuchParentResourceException, IOException {
+
+    AmbariManagementController controller = getManagementController();
+    ExtensionInfo extensionInfo;
+    try {
+      extensionInfo = controller.getAmbariMetaInfo().getExtension(extensionName, extensionVersion);
+    } catch (StackAccessException e) {
+      throw new NoSuchParentResourceException(String.format(
+        "Parent extension resource doesn't exist: extensionName='%s', extensionVersion='%s'", extensionName, extensionVersion));
+    }
+
+    if (StringUtils.isEmpty(serviceName)) {
+      return getWidgetsDescriptorForCluster(extensionInfo);
+    } else {
+      return getWidgetsDescriptorForService(extensionInfo, serviceName);
+    }
+  }
+
+  public Map<String, Object> getWidgetsDescriptorForService(ExtensionInfo extensionInfo, String serviceName)
+      throws NoSuchParentResourceException, IOException {
+
+    Map<String, Object> widgetDescriptor = null;
+
+    ServiceInfo serviceInfo = extensionInfo.getService(serviceName);
+    if (serviceInfo == null) {
+      throw new NoSuchParentResourceException("Service not found. serviceName" + " = " + serviceName);
+    }
+
+    File widgetDescriptorFile = serviceInfo.getWidgetsDescriptorFile();
+    if (widgetDescriptorFile != null && widgetDescriptorFile.exists()) {
+      widgetDescriptor = gson.fromJson(new FileReader(widgetDescriptorFile), widgetLayoutType);
+    }
+
+    return widgetDescriptor;
+  }
+
+  public Map<String, Object> getWidgetsDescriptorForCluster(ExtensionInfo extensionInfo)
+      throws NoSuchParentResourceException, IOException {
+
+    Map<String, Object> widgetDescriptor = null;
+
+    String widgetDescriptorFileLocation = extensionInfo.getWidgetsDescriptorFileLocation();
+    if (widgetDescriptorFileLocation != null) {
+      File widgetDescriptorFile = new File(widgetDescriptorFileLocation);
+      if (widgetDescriptorFile.exists()) {
+        widgetDescriptor = gson.fromJson(new FileReader(widgetDescriptorFile), widgetLayoutType);
+      }
+    }
+
+    return widgetDescriptor;
+  }
+
+  /**
+   * Get a kerberos descriptor.
+   *
+   * @param extensionName     extension name
+   * @param extensionVersion  extension version
+   * @param serviceName   service name
+   *
+   * @return map of kerberos descriptor data or null if no descriptor exists
+   *
+   * @throws IOException if unable to parse the associated kerberos descriptor file
+   * @throws NoSuchParentResourceException if the parent extension or extension service doesn't exist
+   */
+  private Map<String, Object> getKerberosDescriptor(String extensionName, String extensionVersion, String serviceName)
+      throws NoSuchParentResourceException, IOException {
+
+      return serviceName == null ?
+          buildExtensionDescriptor(extensionName, extensionVersion) :
+          getServiceDescriptor(extensionName, extensionVersion, serviceName);
+  }
+
+  /**
+   * Build a kerberos descriptor for the specified extension. This descriptor is for the entire extension version
+   * and will contain both the extension descriptor as well as all service descriptors.
+   *
+   * @return map of kerberos descriptor data or null if no descriptor exists
+   *
+   * @throws IOException     if unable to read the kerberos descriptor file
+   * @throws AmbariException if unable to parse the kerberos descriptor file json
+   * @throws NoSuchParentResourceException if the parent extension doesn't exist
+   */
+  private Map<String, Object> buildExtensionDescriptor(String extensionName, String extensionVersion)
+      throws NoSuchParentResourceException, IOException {
+
+    KerberosDescriptor kerberosDescriptor = null;
+
+    AmbariManagementController controller = getManagementController();
+    ExtensionInfo extensionInfo;
+    try {
+      extensionInfo = controller.getAmbariMetaInfo().getExtension(extensionName, extensionVersion);
+    } catch (StackAccessException e) {
+      throw new NoSuchParentResourceException(String.format(
+          "Parent extension resource doesn't exist: extensionName='%s', extensionVersion='%s'", extensionName, extensionVersion));
+    }
+
+    Collection<KerberosServiceDescriptor> serviceDescriptors = getServiceDescriptors(extensionInfo);
+
+    String kerberosFileLocation = extensionInfo.getKerberosDescriptorFileLocation();
+    if (kerberosFileLocation != null) {
+      kerberosDescriptor = kerberosDescriptorFactory.createInstance(new File(kerberosFileLocation));
+    } else if (! serviceDescriptors.isEmpty()) {
+      // service descriptors present with no extension descriptor,
+      // create an empty extension descriptor to hold services
+      kerberosDescriptor = new KerberosDescriptor();
+    }
+
+    if (kerberosDescriptor != null) {
+      for (KerberosServiceDescriptor descriptor : serviceDescriptors) {
+        kerberosDescriptor.putService(descriptor);
+      }
+      return kerberosDescriptor.toMap();
+    } else {
+      return null;
+    }
+  }
+
+  /**
+   * Get the kerberos descriptor for the specified extension service.
+   *
+   * @param extensionName     extension name
+   * @param extensionVersion  extension version
+   * @param serviceName   service name
+   *
+   * @return map of kerberos descriptor data or null if no descriptor exists
+   *
+   * @throws IOException if unable to read or parse the kerberos descriptor file
+   * @throws NoSuchParentResourceException if the parent extension or extension service doesn't exist
+   */
+  private Map<String, Object> getServiceDescriptor(
+      String extensionName, String extensionVersion, String serviceName) throws NoSuchParentResourceException, IOException {
+
+    AmbariManagementController controller = getManagementController();
+
+    ServiceInfo serviceInfo;
+    try {
+      serviceInfo = controller.getAmbariMetaInfo().getExtensionService(extensionName, extensionVersion, serviceName);
+    } catch (StackAccessException e) {
+      throw new NoSuchParentResourceException(String.format(
+          "Parent extension/service resource doesn't exist: extensionName='%s', extensionVersion='%s', serviceName='%s'",
+          extensionName, extensionVersion, serviceName));
+    }
+    File kerberosFile = serviceInfo.getKerberosDescriptorFile();
+
+    if (kerberosFile != null) {
+      KerberosServiceDescriptor serviceDescriptor =
+          kerberosServiceDescriptorFactory.createInstance(kerberosFile, serviceName);
+
+      if (serviceDescriptor != null) {
+        return serviceDescriptor.toMap();
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Get a collection of all service descriptors for the specified extension.
+   *
+   * @param extension  extension name
+   *
+   * @return collection of all service descriptors for the extension; will not return null
+   *
+   * @throws IOException if unable to read or parse a descriptor file
+   */
+  private Collection<KerberosServiceDescriptor> getServiceDescriptors(ExtensionInfo extension) throws IOException {
+    Collection<KerberosServiceDescriptor> serviceDescriptors = new ArrayList<KerberosServiceDescriptor>();
+    for (ServiceInfo service : extension.getServices()) {
+      File descriptorFile = service.getKerberosDescriptorFile();
+      if (descriptorFile != null) {
+        KerberosServiceDescriptor descriptor =
+            kerberosServiceDescriptorFactory.createInstance(descriptorFile, service.getName());
+
+        if (descriptor != null) {
+          serviceDescriptors.add(descriptor);
+        }
+      }
+    }
+    return serviceDescriptors;
+  }
+
+  private Map<String, Map<String, List<MetricDefinition>>> removeAggregateFunctions(
+          Map<String, Map<String, List<MetricDefinition>>> serviceMetrics  ) {
+    Map<String, Map<String, List<MetricDefinition>>> filteredServiceMetrics = null;
+    if (serviceMetrics != null) {
+      Cloner cloner = new Cloner();
+      filteredServiceMetrics = cloner.deepClone(serviceMetrics);
+      // For every Component
+      for (Map<String, List<MetricDefinition>> componentMetricDef :  filteredServiceMetrics.values()) {
+        // For every Component / HostComponent category
+        for (Map.Entry<String, List<MetricDefinition>> metricDefEntry : componentMetricDef.entrySet()) {
+          //For every metric definition
+          for (MetricDefinition metricDefinition : metricDefEntry.getValue()) {
+            // Metrics System metrics only
+            if (metricDefinition.getType().equals("ganglia")) {
+              // Create a new map for each category
+              for (Map<String, Metric> metricByCategory : metricDefinition.getMetricsByCategory().values()) {
+                Iterator<Map.Entry<String, Metric>> iterator = metricByCategory.entrySet().iterator();
+                while (iterator.hasNext()) {
+                  Map.Entry<String, Metric> entry = iterator.next();
+                  String metricName = entry.getKey();
+                  if (PropertyHelper.hasAggregateFunctionSuffix(metricName)) {
+                    iterator.remove();
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    return filteredServiceMetrics;
+  }
+
+  private List<MetricDefinition> removeAggregateFunctions(List<MetricDefinition> componentMetrics) {
+    List<MetricDefinition> filteredComponentMetrics = null;
+    if (componentMetrics != null) {
+      Cloner cloner = new Cloner();
+      filteredComponentMetrics = cloner.deepClone(componentMetrics);
+      // For every metric definition
+      for (MetricDefinition metricDefinition : filteredComponentMetrics) {
+        // Metrics System metrics only
+        if (metricDefinition.getType().equals("ganglia")) {
+          // Create a new map for each category
+          for (Map<String, Metric> metricByCategory : metricDefinition.getMetricsByCategory().values()) {
+            Iterator<Map.Entry<String, Metric>> iterator = metricByCategory.entrySet().iterator();
+            while (iterator.hasNext()) {
+              Map.Entry<String, Metric> entry = iterator.next();
+              String metricName = entry.getKey();
+              if (PropertyHelper.hasAggregateFunctionSuffix(metricName)) {
+                iterator.remove();
+              }
+            }
+          }
+        }
+      }
+    }
+    return  filteredComponentMetrics;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionConfigurationDependencyResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionConfigurationDependencyResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionConfigurationDependencyResourceProvider.java
new file mode 100644
index 0000000..e26a7cc
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionConfigurationDependencyResourceProvider.java
@@ -0,0 +1,143 @@
+/**
+ * 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 org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ExtensionConfigurationDependencyRequest;
+import org.apache.ambari.server.controller.ExtensionConfigurationDependencyResponse;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Resource.Type;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class ExtensionConfigurationDependencyResourceProvider extends
+    ReadOnlyResourceProvider {
+
+  public static final String EXTENSION_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurationDependency", "extension_name");
+
+  public static final String EXTENSION_VERSION_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurationDependency", "extension_version");
+
+  public static final String SERVICE_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurationDependency", "service_name");
+
+  public static final String PROPERTY_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurationDependency", "property_name");
+
+  public static final String DEPENDENCY_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurationDependency", "dependency_name");
+
+  public static final String DEPENDENCY_TYPE_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurationDependency", "dependency_type");
+
+  private static Set<String> pkPropertyIds = new HashSet<String>(
+      Arrays.asList(new String[] { EXTENSION_NAME_PROPERTY_ID,
+          EXTENSION_VERSION_PROPERTY_ID, SERVICE_NAME_PROPERTY_ID,
+          PROPERTY_NAME_PROPERTY_ID, DEPENDENCY_NAME_PROPERTY_ID }));
+
+  protected ExtensionConfigurationDependencyResourceProvider(Set<String> propertyIds,
+                                                         Map<Type, String> keyPropertyIds,
+                                                         AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  @Override
+  public Set<Resource> getResources(final Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ExtensionConfigurationDependencyRequest> requests =
+      new HashSet<ExtensionConfigurationDependencyRequest>();
+
+    if (predicate == null) {
+      requests.add(getRequest(Collections.<String, Object>emptyMap()));
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+    }
+
+    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+
+    Set<ExtensionConfigurationDependencyResponse> responses = getResources(new Command<Set<ExtensionConfigurationDependencyResponse>>() {
+      @Override
+      public Set<ExtensionConfigurationDependencyResponse> invoke() throws AmbariException {
+        return getManagementController().getExtensionConfigurationDependencies(requests);
+      }
+    });
+
+    Set<Resource> resources = new HashSet<Resource>();
+
+    for (ExtensionConfigurationDependencyResponse response : responses) {
+      Resource resource = new ResourceImpl(Type.ExtensionConfigurationDependency);
+
+      setResourceProperty(resource, EXTENSION_NAME_PROPERTY_ID,
+          response.getExtensionName(), requestedIds);
+
+      setResourceProperty(resource, EXTENSION_VERSION_PROPERTY_ID,
+          response.getExtensionVersion(), requestedIds);
+
+      setResourceProperty(resource, SERVICE_NAME_PROPERTY_ID,
+          response.getServiceName(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_NAME_PROPERTY_ID,
+          response.getPropertyName(), requestedIds);
+
+      setResourceProperty(resource, DEPENDENCY_NAME_PROPERTY_ID,
+          response.getDependencyName(), requestedIds);
+
+      setResourceProperty(resource, DEPENDENCY_TYPE_PROPERTY_ID,
+          response.getDependencyType(), requestedIds);
+
+
+      resources.add(resource);
+    }
+
+    return resources;
+  }
+
+  private ExtensionConfigurationDependencyRequest getRequest(Map<String, Object> properties) {
+    return new ExtensionConfigurationDependencyRequest(
+        (String) properties.get(EXTENSION_NAME_PROPERTY_ID),
+        (String) properties.get(EXTENSION_VERSION_PROPERTY_ID),
+        (String) properties.get(SERVICE_NAME_PROPERTY_ID),
+        (String) properties.get(PROPERTY_NAME_PROPERTY_ID),
+        (String) properties.get(DEPENDENCY_NAME_PROPERTY_ID));
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionConfigurationResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionConfigurationResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionConfigurationResourceProvider.java
new file mode 100644
index 0000000..d3107cb
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionConfigurationResourceProvider.java
@@ -0,0 +1,194 @@
+/**
+ * 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.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ExtensionConfigurationRequest;
+import org.apache.ambari.server.controller.ExtensionConfigurationResponse;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Resource.Type;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.commons.lang.StringUtils;
+
+public class ExtensionConfigurationResourceProvider extends
+    ReadOnlyResourceProvider {
+
+  public static final String EXTENSION_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "extension_name");
+
+  public static final String EXTENSION_VERSION_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "extension_version");
+
+  public static final String SERVICE_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "service_name");
+
+  public static final String PROPERTY_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "property_name");
+
+  public static final String PROPERTY_VALUE_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "property_value");
+
+  public static final String PROPERTY_VALUE_ATTRIBUTES_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "property_value_attributes");
+
+  public static final String PROPERTY_DEPENDS_ON_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "property_depends_on");
+
+  public static final String PROPERTY_DESCRIPTION_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "property_description");
+
+  public static final String PROPERTY_DISPLAY_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "property_display_name");
+
+  public static final String PROPERTY_PROPERTY_TYPE_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "property_type");
+
+  public static final String PROPERTY_TYPE_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "type");
+
+  public static final String PROPERTY_FINAL_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionConfigurations", "final");
+
+
+  private static Set<String> pkPropertyIds = new HashSet<String>(
+      Arrays.asList(new String[] { EXTENSION_NAME_PROPERTY_ID,
+          EXTENSION_VERSION_PROPERTY_ID, SERVICE_NAME_PROPERTY_ID, PROPERTY_NAME_PROPERTY_ID }));
+
+  protected ExtensionConfigurationResourceProvider(Set<String> propertyIds,
+      Map<Type, String> keyPropertyIds,
+      AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ExtensionConfigurationRequest> requests = new HashSet<ExtensionConfigurationRequest>();
+
+    if (predicate == null) {
+      requests.add(getRequest(Collections.<String, Object>emptyMap()));
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+    }
+
+    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+
+    Set<ExtensionConfigurationResponse> responses = getResources(new Command<Set<ExtensionConfigurationResponse>>() {
+      @Override
+      public Set<ExtensionConfigurationResponse> invoke() throws AmbariException {
+        return getManagementController().getExtensionConfigurations(requests);
+      }
+    });
+
+    Set<Resource> resources = new HashSet<Resource>();
+
+    for (ExtensionConfigurationResponse response : responses) {
+      Resource resource = new ResourceImpl(Resource.Type.ExtensionConfiguration);
+
+      setResourceProperty(resource, EXTENSION_NAME_PROPERTY_ID,
+          response.getExtensionName(), requestedIds);
+
+      setResourceProperty(resource, EXTENSION_VERSION_PROPERTY_ID,
+          response.getExtensionVersion(), requestedIds);
+
+      setResourceProperty(resource, SERVICE_NAME_PROPERTY_ID,
+          response.getServiceName(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_NAME_PROPERTY_ID,
+          response.getPropertyName(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_VALUE_PROPERTY_ID,
+          response.getPropertyValue(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_VALUE_ATTRIBUTES_PROPERTY_ID,
+          response.getPropertyValueAttributes(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_DEPENDS_ON_PROPERTY_ID,
+          response.getDependsOnProperties(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_DESCRIPTION_PROPERTY_ID,
+          response.getPropertyDescription(), requestedIds);
+
+      //should not be returned if empty
+      if (StringUtils.isNotEmpty(response.getPropertyDisplayName())) {
+        setResourceProperty(resource, PROPERTY_DISPLAY_NAME_PROPERTY_ID,
+            response.getPropertyDisplayName(), requestedIds);
+      }
+
+      setResourceProperty(resource, PROPERTY_PROPERTY_TYPE_PROPERTY_ID,
+          response.getPropertyType(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_TYPE_PROPERTY_ID,
+          response.getType(), requestedIds);
+
+      setDefaultPropertiesAttributes(resource, requestedIds);
+
+      for (Map.Entry<String, String> attribute : response.getPropertyAttributes().entrySet()) {
+        setResourceProperty(resource, PropertyHelper.getPropertyId("ExtensionConfigurations", attribute.getKey()),
+            attribute.getValue(), requestedIds);
+      }
+
+      resources.add(resource);
+    }
+
+    return resources;
+  }
+
+  /**
+   * Set default values for properties attributes before applying original ones
+   * to prevent absence in case of empty attributes map
+   */
+  private void setDefaultPropertiesAttributes(Resource resource, Set<String> requestedIds) {
+    setResourceProperty(resource, PROPERTY_FINAL_PROPERTY_ID,
+        "false", requestedIds);
+  }
+
+  private ExtensionConfigurationRequest getRequest(Map<String, Object> properties) {
+    return new ExtensionConfigurationRequest(
+        (String) properties.get(EXTENSION_NAME_PROPERTY_ID),
+        (String) properties.get(EXTENSION_VERSION_PROPERTY_ID),
+        (String) properties.get(SERVICE_NAME_PROPERTY_ID),
+        (String) properties.get(PROPERTY_NAME_PROPERTY_ID));
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionDependencyResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionDependencyResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionDependencyResourceProvider.java
new file mode 100644
index 0000000..c1fb27d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionDependencyResourceProvider.java
@@ -0,0 +1,254 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.internal;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.state.AutoDeployInfo;
+import org.apache.ambari.server.state.DependencyInfo;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Resource provider for Extension Dependency resource.
+ */
+public class ExtensionDependencyResourceProvider extends AbstractResourceProvider {
+
+  // ----- Property ID constants ---------------------------------------------
+
+  protected static final String EXTENSION_NAME_ID =
+      PropertyHelper.getPropertyId("Dependencies", "extension_name");
+  protected static final String EXTENSION_VERSION_ID =
+      PropertyHelper.getPropertyId("Dependencies", "extension_version");
+  protected static final String DEPENDENT_SERVICE_NAME_ID =
+      PropertyHelper.getPropertyId("Dependencies", "dependent_service_name");
+  protected static final String DEPENDENT_COMPONENT_NAME_ID =
+      PropertyHelper.getPropertyId("Dependencies", "dependent_component_name");
+  protected static final String SERVICE_NAME_ID =
+      PropertyHelper.getPropertyId("Dependencies", "service_name");
+  protected static final String COMPONENT_NAME_ID =
+      PropertyHelper.getPropertyId("Dependencies", "component_name");
+  protected static final String SCOPE_ID =
+      PropertyHelper.getPropertyId("Dependencies", "scope");
+  protected static final String AUTO_DEPLOY_ENABLED_ID = PropertyHelper
+      .getPropertyId("auto_deploy", "enabled");
+  protected static final String AUTO_DEPLOY_LOCATION_ID = PropertyHelper
+      .getPropertyId("auto_deploy", "location");
+
+  // Primary Key Fields
+  private static Set<String> pkPropertyIds =
+      new HashSet<String>(Arrays.asList(new String[]{
+          SERVICE_NAME_ID, COMPONENT_NAME_ID}));
+
+  /**
+   * Provides extension information
+   */
+  private static AmbariMetaInfo ambariMetaInfo;
+
+
+  // ----- Constructors ----------------------------------------------------
+
+  /**
+   * Constructor.
+   *
+   * @param propertyIds    the property ids
+   * @param keyPropertyIds the key property ids
+   */
+  protected ExtensionDependencyResourceProvider(Set<String> propertyIds,
+                                            Map<Resource.Type, String> keyPropertyIds) {
+    super(propertyIds, keyPropertyIds);
+  }
+
+  /**
+   * Static initialization.
+   *
+   * @param metaInfo meta info instance
+   */
+  public static void init(AmbariMetaInfo metaInfo) {
+    ambariMetaInfo = metaInfo;
+  }
+
+
+  // ----- ResourceProvider ------------------------------------------------
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+             NoSuchResourceException, NoSuchParentResourceException {
+
+    Set<Resource> resources = new HashSet<Resource>();
+    Set<Map<String, Object>> requestProps = getPropertyMaps(predicate);
+
+    for (Map<String, Object> properties : requestProps) {
+      try {
+        resources.addAll(getDependencyResources(properties,
+            getRequestPropertyIds(request, predicate)));
+      } catch (NoSuchResourceException e) {
+        if (requestProps.size() == 1) {
+          throw e;
+        }
+      } catch (NoSuchParentResourceException e) {
+        if (requestProps.size() == 1) {
+          throw e;
+        }
+      }
+    }
+    return resources;
+  }
+
+  @Override
+  public RequestStatus createResources(Request request)
+      throws SystemException, UnsupportedPropertyException,
+      ResourceAlreadyExistsException, NoSuchParentResourceException {
+
+    // should not get here as service doesn't allow POST and should return 405
+    throw new SystemException("Extension resources are read only");
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    // should not get here as service doesn't allow PUT and should return 405
+    throw new SystemException("Extension resources are read only");
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    // should not get here as service doesn't allow DELETE and should return 405
+    throw new SystemException("Extension resources are read only");
+  }
+
+
+  // ----- Instance Methods ------------------------------------------------
+
+  /**
+   * Get dependencies resources.
+   *
+   * @param properties    request properties
+   * @param requestedIds  requested id's
+   *
+   * @return collection of dependency resources
+   *
+   * @throws SystemException an internal error occurred
+   * @throws NoSuchParentResourceException parent resource not found
+   * @throws NoSuchResourceException dependency resource not found
+   */
+  private Collection<Resource> getDependencyResources(Map<String, Object> properties, Set<String> requestedIds)
+      throws SystemException, NoSuchParentResourceException, NoSuchResourceException {
+
+    final String extensionName = (String) properties.get(EXTENSION_NAME_ID);
+    final String version = (String) properties.get(EXTENSION_VERSION_ID);
+    final String dependentService = (String) properties.get(DEPENDENT_SERVICE_NAME_ID);
+    final String dependentComponent = (String)  properties.get(DEPENDENT_COMPONENT_NAME_ID);
+    final String dependencyName = (String) properties.get(COMPONENT_NAME_ID);
+
+    List<DependencyInfo> dependencies = new ArrayList<DependencyInfo>();
+    if (dependencyName != null) {
+      dependencies.add(getResources(new Command<DependencyInfo>() {
+        @Override
+        public DependencyInfo invoke() throws AmbariException {
+          return ambariMetaInfo.getExtensionComponentDependency(extensionName, version, dependentService,
+              dependentComponent, dependencyName);
+        }
+      }));
+    } else {
+      dependencies.addAll(getResources(new Command<List<DependencyInfo>>() {
+        @Override
+        public List<DependencyInfo> invoke() throws AmbariException {
+          return ambariMetaInfo.getExtensionComponentDependencies(extensionName, version,
+              dependentService, dependentComponent);
+        }
+      }));
+    }
+
+    Collection<Resource> resources = new ArrayList<Resource>();
+    for (DependencyInfo dependency : dependencies) {
+      if (dependency != null) {
+        resources.add(toResource(dependency, extensionName, version, dependentService,
+            dependentComponent, requestedIds));
+      }
+    }
+    return resources;
+  }
+
+  /**
+   * Create a resource instance with dependency information.
+   *
+   * @param dependency          dependency name
+   * @param extensionName       extension name
+   * @param version             extension version
+   * @param dependentService    dependent service
+   * @param dependentComponent  dependent component
+   * @param requestedIds        requested id's
+   *
+   * @return a new Resource instance for the dependency
+   */
+  private Resource toResource(DependencyInfo dependency, String extensionName,
+                              String version, String dependentService,
+                              String dependentComponent, Set<String> requestedIds) {
+
+    Resource resource = new ResourceImpl(Resource.Type.ExtensionServiceComponentDependency);
+
+    setResourceProperty(resource, SERVICE_NAME_ID, dependency.getServiceName(), requestedIds);
+    setResourceProperty(resource, COMPONENT_NAME_ID, dependency.getComponentName(), requestedIds);
+    setResourceProperty(resource, EXTENSION_NAME_ID, extensionName, requestedIds);
+    setResourceProperty(resource, EXTENSION_VERSION_ID, version, requestedIds);
+    setResourceProperty(resource, DEPENDENT_SERVICE_NAME_ID, dependentService, requestedIds);
+    setResourceProperty(resource, DEPENDENT_COMPONENT_NAME_ID, dependentComponent, requestedIds);
+    setResourceProperty(resource, SCOPE_ID, dependency.getScope(), requestedIds);
+
+    AutoDeployInfo autoDeployInfo = dependency.getAutoDeploy();
+    if (autoDeployInfo != null) {
+      setResourceProperty(resource, AUTO_DEPLOY_ENABLED_ID,
+          autoDeployInfo.isEnabled(), requestedIds);
+
+      if (autoDeployInfo.getCoLocate() != null) {
+        setResourceProperty(resource, AUTO_DEPLOY_LOCATION_ID,
+            autoDeployInfo.getCoLocate(), requestedIds);
+      }
+    }
+    return resource;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionLevelConfigurationResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionLevelConfigurationResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionLevelConfigurationResourceProvider.java
new file mode 100644
index 0000000..97afc9f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionLevelConfigurationResourceProvider.java
@@ -0,0 +1,177 @@
+/**
+ * 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.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ExtensionConfigurationResponse;
+import org.apache.ambari.server.controller.ExtensionLevelConfigurationRequest;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Resource.Type;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+
+public class ExtensionLevelConfigurationResourceProvider extends
+    ReadOnlyResourceProvider {
+
+  public static final String EXTENSION_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLevelConfigurations", "extension_name");
+
+  public static final String EXTENSION_VERSION_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLevelConfigurations", "extension_version");
+
+  public static final String PROPERTY_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLevelConfigurations", "property_name");
+
+  public static final String PROPERTY_VALUE_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLevelConfigurations", "property_value");
+
+  public static final String PROPERTY_VALUE_ATTRIBUTES_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLevelConfigurations", "property_value_attributes");
+
+  public static final String DEPENDS_ON_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLevelConfigurations", "property_depends_on");
+
+  public static final String PROPERTY_DESCRIPTION_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLevelConfigurations", "property_description");
+
+  public static final String PROPERTY_PROPERTY_TYPE_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLevelConfigurations", "property_type");
+
+  public static final String PROPERTY_TYPE_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLevelConfigurations", "type");
+
+  public static final String PROPERTY_FINAL_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLevelConfigurations", "final");
+
+
+  private static Set<String> pkPropertyIds = new HashSet<String>(
+      Arrays.asList(new String[] { EXTENSION_NAME_PROPERTY_ID,
+          EXTENSION_VERSION_PROPERTY_ID, PROPERTY_NAME_PROPERTY_ID }));
+
+  protected ExtensionLevelConfigurationResourceProvider(Set<String> propertyIds,
+      Map<Type, String> keyPropertyIds,
+      AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ExtensionLevelConfigurationRequest> requests = new HashSet<ExtensionLevelConfigurationRequest>();
+
+    if (predicate == null) {
+      requests.add(getRequest(Collections.<String, Object>emptyMap()));
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+    }
+
+    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+
+    Set<ExtensionConfigurationResponse> responses = getResources(new Command<Set<ExtensionConfigurationResponse>>() {
+      @Override
+      public Set<ExtensionConfigurationResponse> invoke() throws AmbariException {
+        return getManagementController().getExtensionLevelConfigurations(requests);
+      }
+    });
+
+    Set<Resource> resources = new HashSet<Resource>();
+
+    for (ExtensionConfigurationResponse response : responses) {
+      Resource resource = new ResourceImpl(Resource.Type.ExtensionLevelConfiguration);
+
+      setResourceProperty(resource, EXTENSION_NAME_PROPERTY_ID,
+          response.getExtensionName(), requestedIds);
+
+      setResourceProperty(resource, EXTENSION_VERSION_PROPERTY_ID,
+          response.getExtensionVersion(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_NAME_PROPERTY_ID,
+          response.getPropertyName(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_VALUE_PROPERTY_ID,
+          response.getPropertyValue(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_VALUE_ATTRIBUTES_PROPERTY_ID,
+          response.getPropertyValueAttributes(), requestedIds);
+
+      setResourceProperty(resource, DEPENDS_ON_PROPERTY_ID,
+          response.getDependsOnProperties(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_DESCRIPTION_PROPERTY_ID,
+          response.getPropertyDescription(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_PROPERTY_TYPE_PROPERTY_ID,
+          response.getPropertyType(), requestedIds);
+
+      setResourceProperty(resource, PROPERTY_TYPE_PROPERTY_ID,
+          response.getType(), requestedIds);
+
+      setDefaultPropertiesAttributes(resource, requestedIds);
+
+      for (Map.Entry<String, String> attribute : response.getPropertyAttributes().entrySet()) {
+        setResourceProperty(resource, PropertyHelper.getPropertyId("ExtensionLevelConfigurations", attribute.getKey()),
+            attribute.getValue(), requestedIds);
+      }
+
+      resources.add(resource);
+    }
+
+    return resources;
+  }
+
+  /**
+   * Set default values for properties attributes before applying original ones
+   * to prevent absence in case of empty attributes map
+   */
+  private void setDefaultPropertiesAttributes(Resource resource, Set<String> requestedIds) {
+    setResourceProperty(resource, PROPERTY_FINAL_PROPERTY_ID,
+        "false", requestedIds);
+  }
+
+  private ExtensionLevelConfigurationRequest getRequest(Map<String, Object> properties) {
+    return new ExtensionLevelConfigurationRequest(
+        (String) properties.get(EXTENSION_NAME_PROPERTY_ID),
+        (String) properties.get(EXTENSION_VERSION_PROPERTY_ID),
+        (String) properties.get(PROPERTY_NAME_PROPERTY_ID));
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionLinkResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionLinkResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionLinkResourceProvider.java
new file mode 100644
index 0000000..f65b331
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionLinkResourceProvider.java
@@ -0,0 +1,261 @@
+/**
+ * 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.util.*;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.StaticallyInject;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ExtensionLinkRequest;
+import org.apache.ambari.server.controller.RequestStatusResponse;
+import org.apache.ambari.server.controller.spi.*;
+import org.apache.ambari.server.controller.spi.Resource.Type;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.orm.dao.ExtensionLinkDAO;
+import org.apache.ambari.server.orm.entities.ExtensionLinkEntity;
+
+import com.google.inject.Inject;
+
+@StaticallyInject
+public class ExtensionLinkResourceProvider extends AbstractControllerResourceProvider {
+
+  public static final String LINK_ID_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLink", "link_id");
+
+  public static final String STACK_NAME_PROPERTY_ID = PropertyHelper
+	      .getPropertyId("ExtensionLink", "stack_name");
+
+  public static final String STACK_VERSION_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLink", "stack_version");
+
+  public static final String EXTENSION_NAME_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLink", "extension_name");
+
+  public static final String EXTENSION_VERSION_PROPERTY_ID = PropertyHelper
+      .getPropertyId("ExtensionLink", "extension_version");
+
+  private static Set<String> pkPropertyIds = new HashSet<String>(
+      Arrays.asList(new String[] { LINK_ID_PROPERTY_ID, STACK_NAME_PROPERTY_ID, STACK_VERSION_PROPERTY_ID, EXTENSION_NAME_PROPERTY_ID, EXTENSION_VERSION_PROPERTY_ID }));
+
+  @Inject
+  private static ExtensionLinkDAO dao;
+
+  protected ExtensionLinkResourceProvider(Set<String> propertyIds,
+      Map<Type, String> keyPropertyIds,
+      AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  @Override
+  public RequestStatus createResources(Request request)
+	        throws SystemException, UnsupportedPropertyException,
+	        NoSuchParentResourceException, ResourceAlreadyExistsException {
+
+    final Set<ExtensionLinkRequest> requests = new HashSet<ExtensionLinkRequest>();
+    for (Map<String, Object> propertyMap : request.getProperties()) {
+      requests.add(getRequest(propertyMap));
+    }
+
+    createResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException {
+        for (ExtensionLinkRequest extensionLinkRequest : requests) {
+          getManagementController().createExtensionLink(extensionLinkRequest);
+        }
+        return null;
+      }
+    });
+
+    if (requests.size() > 0) {
+      //Need to reread the stacks/extensions directories so the latest information is available
+      try {
+        getManagementController().updateStacks();
+      } catch (AmbariException e) {
+        throw new SystemException(e.getMessage(), e);
+      }
+
+      notifyCreate(Resource.Type.ExtensionLink, request);
+    }
+
+    return getRequestStatus(null);
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+        throws SystemException, UnsupportedPropertyException,
+        NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ExtensionLinkRequest> requests = new HashSet<ExtensionLinkRequest>();
+    if (predicate == null) {
+      requests.add(getRequest(Collections.<String, Object>emptyMap()));
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+    }
+
+    RequestStatusResponse response = modifyResources(new Command<RequestStatusResponse>() {
+      @Override
+      public RequestStatusResponse invoke() throws AmbariException {
+        for (ExtensionLinkRequest extensionLinkRequest : requests) {
+          getManagementController().deleteExtensionLink(extensionLinkRequest);
+        }
+        return null;
+      }
+    });
+
+    //Need to reread the stacks/extensions directories so the latest information is available
+    try {
+      getManagementController().updateStacks();
+    } catch (AmbariException e) {
+      throw new SystemException(e.getMessage(), e);
+    }
+
+    notifyDelete(Resource.Type.ExtensionLink, predicate);
+
+    return getRequestStatus(response);
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+        throws SystemException, UnsupportedPropertyException,
+        NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<Resource> resources = new HashSet<Resource>();
+    final Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+
+    final Set<ExtensionLinkRequest> requests = new HashSet<ExtensionLinkRequest>();
+    if (predicate == null) {
+      requests.add(getRequest(Collections.<String, Object>emptyMap()));
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+    }
+
+    Set<ExtensionLinkEntity> entities = new HashSet<ExtensionLinkEntity>();
+
+    for (ExtensionLinkRequest extensionLinkRequest : requests) {
+      verifyStackAndExtensionExist(extensionLinkRequest);
+      entities.addAll(dao.find(extensionLinkRequest));
+    }
+
+    for (ExtensionLinkEntity entity : entities) {
+      Resource resource = new ResourceImpl(Resource.Type.ExtensionLink);
+      setResourceProperty(resource, LINK_ID_PROPERTY_ID,
+		  entity.getLinkId(), requestedIds);
+      setResourceProperty(resource, STACK_NAME_PROPERTY_ID,
+	  entity.getStack().getStackName(), requestedIds);
+      setResourceProperty(resource, STACK_VERSION_PROPERTY_ID,
+          entity.getStack().getStackVersion(), requestedIds);
+      setResourceProperty(resource, EXTENSION_NAME_PROPERTY_ID,
+          entity.getExtension().getExtensionName(), requestedIds);
+      setResourceProperty(resource, EXTENSION_VERSION_PROPERTY_ID,
+          entity.getExtension().getExtensionVersion(), requestedIds);
+
+      resources.add(resource);
+    }
+    return resources;
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+        throws SystemException, UnsupportedPropertyException,
+        NoSuchResourceException, NoSuchParentResourceException {
+
+    /*boolean updated = false;
+
+    if (predicate == null) {
+      List<ExtensionLinkEntity> entities = dao.findAll();
+      for (ExtensionLinkEntity entity : entities) {
+        try {
+          getManagementController().updateExtensionLink(entity);
+          updated = true;
+        } catch (AmbariException e) {
+          throw new SystemException(e.getMessage(), e);
+        }
+      }
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        ExtensionLinkRequest extensionLinkRequest = getRequest(propertyMap);
+        try {
+          getManagementController().updateExtensionLink(extensionLinkRequest);
+          updated = true;
+	} catch (AmbariException e) {
+          throw new SystemException(e.getMessage(), e);
+	}
+      }
+    }*/
+
+    //if (updated) {
+
+    //Need to reread the stacks/extensions directories so the latest information is available
+	//This also regenerates the stacks' services folders for extension services
+    try {
+      getManagementController().updateStacks();
+    } catch (AmbariException e) {
+      throw new SystemException(e.getMessage(), e);
+    }
+
+    notifyUpdate(Resource.Type.ExtensionLink, request, predicate);
+    //}
+    return getRequestStatus(null);
+  }
+
+  private void verifyStackAndExtensionExist(ExtensionLinkRequest request) throws NoSuchParentResourceException {
+    try {
+      if (request.getStackName() != null && request.getStackVersion() != null) {
+        getManagementController().getAmbariMetaInfo().getStack(request.getStackName(), request.getStackVersion());
+      }
+      if (request.getExtensionName() != null && request.getExtensionVersion() != null) {
+        getManagementController().getAmbariMetaInfo().getExtension(request.getExtensionName(), request.getExtensionVersion());
+      }
+    }
+    catch (AmbariException ambariException) {
+      throw new NoSuchParentResourceException(ambariException.getMessage());
+    }
+  }
+
+  private ExtensionLinkRequest getRequest(Map<String, Object> properties) {
+    return new ExtensionLinkRequest(
+        (String) properties.get(LINK_ID_PROPERTY_ID),
+        (String) properties.get(STACK_NAME_PROPERTY_ID),
+        (String) properties.get(STACK_VERSION_PROPERTY_ID),
+        (String) properties.get(EXTENSION_NAME_PROPERTY_ID),
+        (String) properties.get(EXTENSION_VERSION_PROPERTY_ID));
+  }
+
+  private ExtensionLinkRequest createExtensionLinkRequest(ExtensionLinkEntity entity) {
+    if (entity == null) {
+      return null;
+    }
+
+    return new ExtensionLinkRequest(String.valueOf(entity.getLinkId()),
+        entity.getStack().getStackName(),
+        entity.getStack().getStackVersion(),
+        entity.getExtension().getExtensionName(),
+        entity.getExtension().getExtensionVersion());
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/647929db/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionOperatingSystemResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionOperatingSystemResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionOperatingSystemResourceProvider.java
new file mode 100644
index 0000000..b2ae0c7
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ExtensionOperatingSystemResourceProvider.java
@@ -0,0 +1,147 @@
+/**
+ * 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.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.ExtensionOperatingSystemRequest;
+import org.apache.ambari.server.controller.ExtensionOperatingSystemResponse;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.Resource.Type;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+
+public class ExtensionOperatingSystemResourceProvider extends ReadOnlyResourceProvider {
+
+  public static final String OPERATING_SYSTEM_EXTENSION_NAME_PROPERTY_ID        = PropertyHelper.getPropertyId("OperatingSystems", "extension_name");
+  public static final String OPERATING_SYSTEM_EXTENSION_VERSION_PROPERTY_ID     = PropertyHelper.getPropertyId("OperatingSystems", "extension_version");
+  public static final String OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID               = PropertyHelper.getPropertyId("OperatingSystems", "os_type");
+  public static final String OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID = PropertyHelper.getPropertyId("OperatingSystems", "repository_version_id");
+
+  @SuppressWarnings("serial")
+  private static Set<String> pkPropertyIds = new HashSet<String>() {
+    {
+      add(OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID);
+      add(OPERATING_SYSTEM_EXTENSION_NAME_PROPERTY_ID);
+      add(OPERATING_SYSTEM_EXTENSION_VERSION_PROPERTY_ID);
+    }
+  };
+
+  @SuppressWarnings("serial")
+  public static Set<String> propertyIds = new HashSet<String>() {
+    {
+      add(OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID);
+      add(OPERATING_SYSTEM_EXTENSION_NAME_PROPERTY_ID);
+      add(OPERATING_SYSTEM_EXTENSION_VERSION_PROPERTY_ID);
+      add(OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID);
+    }
+  };
+
+  @SuppressWarnings("serial")
+  public static Map<Type, String> keyPropertyIds = new HashMap<Type, String>() {
+    {
+      put(Resource.Type.OperatingSystem, OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID);
+      put(Resource.Type.Extension, OPERATING_SYSTEM_EXTENSION_NAME_PROPERTY_ID);
+      put(Resource.Type.ExtensionVersion, OPERATING_SYSTEM_EXTENSION_VERSION_PROPERTY_ID);
+      put(Resource.Type.RepositoryVersion, OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID);
+      put(Resource.Type.CompatibleRepositoryVersion, OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID);
+    }
+  };
+
+  protected ExtensionOperatingSystemResourceProvider(AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ExtensionOperatingSystemRequest> requests = new HashSet<ExtensionOperatingSystemRequest>();
+
+    if (predicate == null) {
+      requests.add(getRequest(Collections.<String, Object>emptyMap()));
+    } else {
+      for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+    }
+
+    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+
+    Set<ExtensionOperatingSystemResponse> responses = getResources(new Command<Set<ExtensionOperatingSystemResponse>>() {
+      @Override
+      public Set<ExtensionOperatingSystemResponse> invoke() throws AmbariException {
+        return getManagementController().getExtensionOperatingSystems(requests);
+      }
+    });
+
+    Set<Resource> resources = new HashSet<Resource>();
+
+    for (ExtensionOperatingSystemResponse response : responses) {
+      Resource resource = new ResourceImpl(Resource.Type.OperatingSystem);
+
+      setResourceProperty(resource, OPERATING_SYSTEM_EXTENSION_NAME_PROPERTY_ID,
+          response.getExtensionName(), requestedIds);
+
+      setResourceProperty(resource, OPERATING_SYSTEM_EXTENSION_VERSION_PROPERTY_ID,
+          response.getExtensionVersion(), requestedIds);
+
+      setResourceProperty(resource, OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID,
+          response.getOsType(), requestedIds);
+
+      if (response.getRepositoryVersionId() != null) {
+        setResourceProperty(resource, OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID,
+            response.getRepositoryVersionId(), requestedIds);
+      }
+
+      resources.add(resource);
+    }
+
+    return resources;
+  }
+
+  private ExtensionOperatingSystemRequest getRequest(Map<String, Object> properties) {
+    final ExtensionOperatingSystemRequest request = new ExtensionOperatingSystemRequest(
+        (String) properties.get(OPERATING_SYSTEM_EXTENSION_NAME_PROPERTY_ID),
+        (String) properties.get(OPERATING_SYSTEM_EXTENSION_VERSION_PROPERTY_ID),
+        (String) properties.get(OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID));
+    if (properties.containsKey(OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID)) {
+      request.setRepositoryVersionId(Long.parseLong(properties.get(OPERATING_SYSTEM_REPOSITORY_VERSION_ID_PROPERTY_ID).toString()));
+    }
+    return request;
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+}