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 2015/12/16 15:28:12 UTC

[2/2] ambari git commit: AMBARI-11268: Making the quick links stack driven with quicklinks.json file in each servcie's stack file directory (dili)

AMBARI-11268: Making the quick links stack driven with quicklinks.json file in each servcie's stack file directory (dili)


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

Branch: refs/heads/trunk
Commit: eca979132c7da114e6a6e0537d92b024b0b45a9d
Parents: 92c054b
Author: Di Li <di...@apache.org>
Authored: Wed Dec 16 06:25:49 2015 -0800
Committer: Di Li <di...@apache.org>
Committed: Wed Dec 16 06:25:49 2015 -0800

----------------------------------------------------------------------
 .../resources/ResourceInstanceFactoryImpl.java  |   4 +
 .../StackServiceResourceDefinition.java         |   1 +
 .../server/api/services/AmbariMetaInfo.java     |   1 +
 .../server/api/services/StacksService.java      |  36 ++
 .../AbstractControllerResourceProvider.java     |   2 +
 .../QuickLinkArtifactResourceProvider.java      | 201 +++++++++
 .../ambari/server/controller/spi/Resource.java  |   2 +
 .../stack/QuickLinksConfigurationModule.java    | 139 ++++++
 .../ambari/server/stack/ServiceModule.java      |  44 +-
 .../state/QuickLinksConfigurationInfo.java      |  87 ++++
 .../apache/ambari/server/state/ServiceInfo.java |  48 ++
 .../ambari/server/state/quicklinks/Check.java   |  60 +++
 .../ambari/server/state/quicklinks/Link.java    | 127 ++++++
 .../ambari/server/state/quicklinks/Port.java    | 116 +++++
 .../server/state/quicklinks/Protocol.java       |  51 +++
 .../server/state/quicklinks/QuickLinks.java     |  78 ++++
 .../quicklinks/QuickLinksConfiguration.java     |  91 ++++
 .../FALCON/0.5.0.2.1/metainfo.xml               |   6 +
 .../FALCON/0.5.0.2.1/quicklinks/quicklinks.json |  28 ++
 .../STORM/0.9.1.2.1/metainfo.xml                |   6 +
 .../STORM/0.9.1.2.1/quicklinks/quicklinks.json  |  28 ++
 .../HDP/2.0.6/services/OOZIE/metainfo.xml       |   7 +
 .../services/OOZIE/quicklinks/quicklinks.json   |  45 ++
 .../stacks/HDP/2.2/services/RANGER/metainfo.xml |   6 +
 .../services/RANGER/quicklinks/quicklinks.json  |  35 ++
 .../stacks/HDP/2.2/services/SPARK/metainfo.xml  |   6 +
 .../services/SPARK/quicklinks/quicklinks.json   |  28 ++
 .../HDP/2.3/services/ACCUMULO/metainfo.xml      |   7 +-
 .../ACCUMULO/quicklinks/quicklinks.json         |  40 ++
 .../stacks/HDP/2.3/services/ATLAS/metainfo.xml  |   6 +
 .../services/ATLAS/quicklinks/quicklinks.json   |  35 ++
 .../stacks/HDP/2.3/services/HBASE/metainfo.xml  |   6 +
 .../services/HBASE/quicklinks/quicklinks.json   | 103 +++++
 .../stacks/HDP/2.3/services/HDFS/metainfo.xml   |   7 +-
 .../services/HDFS/quicklinks/quicklinks.json    |  80 ++++
 .../stacks/HDP/2.3/services/OOZIE/metainfo.xml  |   7 +-
 .../services/OOZIE/quicklinks/quicklinks.json   |  45 ++
 .../stacks/HDP/2.3/services/RANGER/metainfo.xml |   6 +
 .../services/RANGER/quicklinks/quicklinks.json  |  40 ++
 .../stacks/HDP/2.3/services/SPARK/metainfo.xml  |   6 +
 .../services/SPARK/quicklinks/quicklinks.json   |  28 ++
 .../stacks/HDP/2.3/services/YARN/metainfo.xml   |  13 +
 .../YARN/quicklinks-mapred/quicklinks.json      |  80 ++++
 .../services/YARN/quicklinks/quicklinks.json    |  80 ++++
 .../StackServiceResourceDefinitionTest.java     |   2 +-
 .../QuickLinksConfigurationModuleTest.java      | 128 ++++++
 .../resources/child_quicklinks_to_inherit.json  |   7 +
 .../resources/child_quicklinks_to_merge.json    |  65 +++
 .../resources/child_quicklinks_to_override.json |  90 ++++
 .../src/test/resources/parent_quicklinks.json   |  80 ++++
 .../assets/data/configurations/quicklinks.json  | 102 +++++
 .../configurations/quicklinks_services.json     | 112 +++++
 ambari-web/app/mappers.js                       |   1 +
 ambari-web/app/mappers/quicklinks_mapper.js     |  50 +++
 ambari-web/app/models.js                        |   1 +
 .../app/models/quicklinks/quick_links_config.js |  35 ++
 ambari-web/app/templates/main/service/item.hbs  |   8 +-
 ambari-web/app/utils/ajax/ajax.js               |  12 +
 .../app/views/common/quick_view_link_view.js    | 418 +++++++++++-------
 .../test/views/common/quick_link_view_test.js   | 436 +++++++++++++------
 60 files changed, 3122 insertions(+), 297 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index 27609e7..c7c5d61 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -372,6 +372,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new SimpleResourceDefinition(Resource.Type.Theme, "theme", "themes");
         break;
 
+      case QuickLink:
+        resourceDefinition = new SimpleResourceDefinition(Resource.Type.QuickLink, "quicklink", "quicklinks");
+        break;
+
       case Widget:
         resourceDefinition = new WidgetResourceDefinition();
         break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackServiceResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackServiceResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackServiceResourceDefinition.java
index 45302ff..8b05423 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackServiceResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/StackServiceResourceDefinition.java
@@ -52,6 +52,7 @@ public class StackServiceResourceDefinition extends BaseResourceDefinition {
     setChildren.add(new SubResourceDefinition(Resource.Type.StackServiceComponent));
     setChildren.add(new SubResourceDefinition(Type.StackArtifact));
     setChildren.add(new SubResourceDefinition(Resource.Type.Theme));
+    setChildren.add(new SubResourceDefinition(Resource.Type.QuickLink));
 
     return setChildren;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/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 e35e7ac..81aced4 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
@@ -93,6 +93,7 @@ import static org.apache.ambari.server.controller.utilities.PropertyHelper.AGGRE
 public class AmbariMetaInfo {
   public static final String SERVICE_CONFIG_FOLDER_NAME = "configuration";
   public static final String SERVICE_THEMES_FOLDER_NAME = "themes";
+  public static final String SERVICE_QUICKLINKS_CONFIGURATIONS_FOLDER_NAME = "quicklinks";
   public static final String SERVICE_CONFIG_FILE_NAME_POSTFIX = ".xml";
   public static final String RCO_FILE_NAME = "role_command_order.json";
   public static final String SERVICE_METRIC_FILE_NAME = "metrics.json";

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
index 76397fb..557ce98 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java
@@ -191,6 +191,31 @@ public class StacksService extends BaseService {
   }
 
   @GET
+  @Path("{stackName}/versions/{stackVersion}/services/{serviceName}/quicklinks")
+  @Produces("text/plain")
+  public Response getStackServiceQuickLinksConfigurations(String body, @Context HttpHeaders headers,
+                                           @Context UriInfo ui, @PathParam("stackName") String stackName,
+                                           @PathParam("stackVersion") String stackVersion,
+                                           @PathParam("serviceName") String serviceName) {
+
+    return handleRequest(headers, body, ui, Request.Type.GET,
+      createStackServiceQuickLinksResource(stackName, stackVersion, serviceName, null));
+  }
+
+  @GET
+  @Path("{stackName}/versions/{stackVersion}/services/{serviceName}/quicklinks/{quickLinksConfigurationName}")
+  @Produces("text/plain")
+  public Response getStackServiceQuickLinksConfiguration(String body, @Context HttpHeaders headers,
+                                           @Context UriInfo ui, @PathParam("stackName") String stackName,
+                                           @PathParam("stackVersion") String stackVersion,
+                                           @PathParam("serviceName") String serviceName,
+                                           @PathParam("quickLinksConfigurationName") String quickLinksConfigurationName) {
+
+    return handleRequest(headers, body, ui, Request.Type.GET,
+      createStackServiceQuickLinksResource(stackName, stackVersion, serviceName, quickLinksConfigurationName));
+  }
+
+  @GET
   @Path("{stackName}/versions/{stackVersion}/services/{serviceName}/artifacts/{artifactName}")
   @Produces("text/plain")
   public Response getStackServiceArtifact(String body, @Context HttpHeaders headers,
@@ -455,6 +480,17 @@ public class StacksService extends BaseService {
     return createResource(Resource.Type.Theme, mapIds);
   }
 
+  ResourceInstance createStackServiceQuickLinksResource(String stackName, String stackVersion, String serviceName,
+      String quickLinksConfigurationName) {
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.Stack, stackName);
+    mapIds.put(Resource.Type.StackVersion, stackVersion);
+    mapIds.put(Resource.Type.StackService, serviceName);
+    mapIds.put(Resource.Type.QuickLink, quickLinksConfigurationName);
+
+    return createResource(Resource.Type.QuickLink, mapIds);
+  }
+
   ResourceInstance createStackResource(String stackName) {
 
     return createResource(Resource.Type.Stack,

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
index d47d8d3..a29f151 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java
@@ -177,6 +177,8 @@ public abstract class AbstractControllerResourceProvider extends AbstractAuthori
         return new StackArtifactResourceProvider(managementController);
       case Theme:
         return new ThemeArtifactResourceProvider(managementController);
+      case QuickLink:
+        return new QuickLinkArtifactResourceProvider(managementController);
       case ActiveWidgetLayout:
         return new ActiveWidgetLayoutResourceProvider(managementController);
       case WidgetLayout:

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/QuickLinkArtifactResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/QuickLinkArtifactResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/QuickLinkArtifactResourceProvider.java
new file mode 100644
index 0000000..ed64342
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/QuickLinkArtifactResourceProvider.java
@@ -0,0 +1,201 @@
+/*
+ * 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.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.QuickLinksConfigurationInfo;
+import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.ambari.server.state.StackInfo;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class QuickLinkArtifactResourceProvider extends AbstractControllerResourceProvider {
+
+  public static final String STACK_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("QuickLinkInfo", "stack_name");
+  public static final String STACK_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("QuickLinkInfo", "stack_version");
+  public static final String STACK_SERVICE_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("QuickLinkInfo", "service_name");
+  public static final String QUICKLINK_DEFAULT_PROPERTY_ID = PropertyHelper.getPropertyId("QuickLinkInfo", "default");
+  public static final String QUICKLINK_FILE_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("QuickLinkInfo", "file_name");
+  public static final String QUICKLINK_DATA_PROPERTY_ID = PropertyHelper.getPropertyId("QuickLinkInfo", "quicklink_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>();
+
+  static {
+    keyPropertyIds.put(Resource.Type.QuickLink, QUICKLINK_FILE_NAME_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.Stack, STACK_NAME_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.StackVersion, STACK_VERSION_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.StackService, STACK_SERVICE_NAME_PROPERTY_ID);
+
+    pkPropertyIds.add(QUICKLINK_FILE_NAME_PROPERTY_ID);
+
+    // resource properties
+    propertyIds.add(STACK_NAME_PROPERTY_ID);
+    propertyIds.add(STACK_VERSION_PROPERTY_ID);
+    propertyIds.add(STACK_SERVICE_NAME_PROPERTY_ID);
+    propertyIds.add(QUICKLINK_FILE_NAME_PROPERTY_ID);
+    propertyIds.add(QUICKLINK_DATA_PROPERTY_ID);
+    propertyIds.add(QUICKLINK_DEFAULT_PROPERTY_ID);
+  }
+
+  /**
+   * Create a  new resource provider for the given management controller.
+   *
+   * @param managementController the management controller
+   */
+  protected QuickLinkArtifactResourceProvider(AmbariManagementController managementController) {
+    super(propertyIds, keyPropertyIds, managementController);
+  }
+
+  @Override
+  public RequestStatus createResources(Request request) throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException,
+      NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Creating of quick links is not supported");
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException,
+      NoSuchParentResourceException {
+
+    Set<Resource> resources = new LinkedHashSet<Resource>();
+
+    resources.addAll(getQuickLinks(request, predicate));
+    // add other artifacts types here
+
+    if (resources.isEmpty()) {
+      throw new NoSuchResourceException(
+        "The requested resource doesn't exist: QuickLink not found, " + predicate);
+    }
+
+    return resources;
+
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException,
+      NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Updating of quick links is not supported");
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Deleting of quick links is not supported");
+  }
+
+  private Set<Resource> getQuickLinks(Request request, Predicate predicate) throws NoSuchParentResourceException,
+    NoSuchResourceException, UnsupportedPropertyException, SystemException {
+
+    Set<Resource> resources = new LinkedHashSet<Resource>();
+    for (Map<String, Object> properties : getPropertyMaps(predicate)) {
+      String quickLinksFileName = (String) properties.get(QUICKLINK_FILE_NAME_PROPERTY_ID);
+      String stackName = (String) properties.get(STACK_NAME_PROPERTY_ID);
+      String stackVersion = (String) properties.get(STACK_VERSION_PROPERTY_ID);
+      String stackService = (String) properties.get(STACK_SERVICE_NAME_PROPERTY_ID);
+
+      StackInfo stackInfo;
+      try {
+        stackInfo = getManagementController().getAmbariMetaInfo().getStack(stackName, stackVersion);
+      } catch (AmbariException e) {
+        throw new NoSuchParentResourceException(String.format(
+          "Parent stack resource doesn't exist: stackName='%s', stackVersion='%s'", stackName, stackVersion));
+      }
+
+      List<ServiceInfo> serviceInfoList = new ArrayList<ServiceInfo>();
+
+      if (stackService == null) {
+        serviceInfoList.addAll(stackInfo.getServices());
+      } else {
+        ServiceInfo service = stackInfo.getService(stackService);
+        if (service == null) {
+          throw new NoSuchParentResourceException(String.format(
+            "Parent stack/service resource doesn't exist: stackName='%s', stackVersion='%s', serviceName='%s'",
+            stackName, stackVersion, stackService));
+        }
+        serviceInfoList.add(service);
+      }
+
+      for (ServiceInfo serviceInfo : serviceInfoList) {
+        List<QuickLinksConfigurationInfo> serviceQuickLinks = new ArrayList<QuickLinksConfigurationInfo>();
+        if (quickLinksFileName != null) {
+          LOG.debug("Getting quick links from service {}, quick links = {}", serviceInfo.getName(), serviceInfo.getQuickLinksConfigurationsMap());
+          serviceQuickLinks.add(serviceInfo.getQuickLinksConfigurationsMap().get(quickLinksFileName));
+        } else {
+          for (QuickLinksConfigurationInfo quickLinksConfigurationInfo : serviceInfo.getQuickLinksConfigurationsMap().values()) {
+            if (quickLinksConfigurationInfo.getIsDefault()) {
+              serviceQuickLinks.add(0, quickLinksConfigurationInfo );
+            } else {
+              serviceQuickLinks.add(quickLinksConfigurationInfo );
+            }
+          }
+        }
+
+        List<Resource> serviceResources = new ArrayList<Resource>();
+        for (QuickLinksConfigurationInfo quickLinksConfigurationInfo : serviceQuickLinks) {
+          Resource resource = new ResourceImpl(Resource.Type.QuickLink);
+          Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+          setResourceProperty(resource, QUICKLINK_FILE_NAME_PROPERTY_ID, quickLinksConfigurationInfo.getFileName(), requestedIds);
+          setResourceProperty(resource, QUICKLINK_DATA_PROPERTY_ID, quickLinksConfigurationInfo.getQuickLinksConfigurationMap(), requestedIds);
+          setResourceProperty(resource, QUICKLINK_DEFAULT_PROPERTY_ID, quickLinksConfigurationInfo.getIsDefault(), requestedIds);
+          setResourceProperty(resource, STACK_NAME_PROPERTY_ID, stackName, requestedIds);
+          setResourceProperty(resource, STACK_VERSION_PROPERTY_ID, stackVersion, requestedIds);
+          setResourceProperty(resource, STACK_SERVICE_NAME_PROPERTY_ID, serviceInfo.getName(), requestedIds);
+          serviceResources.add(resource);
+        }
+
+        resources.addAll(serviceResources);
+
+      }
+    }
+    return resources;
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index 55816a3..e367afe 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -144,6 +144,7 @@ public interface Resource {
     WidgetLayout,
     ActiveWidgetLayout,
     Theme,
+    QuickLink,
     HostKerberosIdentity,
     Credential,
     KerberosDescriptor,
@@ -250,6 +251,7 @@ public interface Resource {
     public static final Type StackArtifact = InternalType.StackArtifact.getType();
     public static final Type Artifact = InternalType.Artifact.getType();
     public static final Type Theme = InternalType.Theme.getType();
+    public static final Type QuickLink = InternalType.QuickLink.getType();
     public static final Type Widget = InternalType.Widget.getType();
     public static final Type WidgetLayout = InternalType.WidgetLayout.getType();
     public static final Type ActiveWidgetLayout = InternalType.ActiveWidgetLayout.getType();

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/stack/QuickLinksConfigurationModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/QuickLinksConfigurationModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/QuickLinksConfigurationModule.java
new file mode 100644
index 0000000..f5e670d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/QuickLinksConfigurationModule.java
@@ -0,0 +1,139 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.stack;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.state.QuickLinksConfigurationInfo;
+import org.apache.ambari.server.state.quicklinks.QuickLinks;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class QuickLinksConfigurationModule extends BaseModule<QuickLinksConfigurationModule, QuickLinksConfigurationInfo> implements Validable {
+
+  private static final Logger LOG = LoggerFactory.getLogger(QuickLinksConfigurationModule.class);
+  private static final ObjectMapper mapper = new ObjectMapper();
+
+  public static final String QUICKLINKS_CONFIGURATION_KEY = "QuickLinksConfiguration";
+
+  static {
+  }
+
+
+  private QuickLinksConfigurationInfo moduleInfo;
+  private boolean valid = true;
+  private Set<String> errors = new HashSet<String>();
+
+  public QuickLinksConfigurationModule(File quickLinksConfigurationFile) {
+    this(quickLinksConfigurationFile, new QuickLinksConfigurationInfo());
+  }
+
+  public QuickLinksConfigurationModule(File quickLinksConfigurationFile, QuickLinksConfigurationInfo moduleInfo) {
+    this.moduleInfo = moduleInfo;
+    if (!moduleInfo.isDeleted() && quickLinksConfigurationFile != null) {
+      LOG.debug("Looking for quicklinks in {}", quickLinksConfigurationFile.getAbsolutePath());
+      FileReader reader = null;
+      try {
+        reader = new FileReader(quickLinksConfigurationFile);
+      } catch (FileNotFoundException e) {
+        LOG.error("Quick links file not found");
+      }
+      try {
+        QuickLinks quickLinksConfig = mapper.readValue(reader, QuickLinks.class);
+        Map<String, QuickLinks> map = new HashMap<String, QuickLinks>();
+        map.put(QUICKLINKS_CONFIGURATION_KEY, quickLinksConfig);
+        moduleInfo.setQuickLinksConfigurationMap(map);
+        LOG.debug("Loaded quicklinks configuration: {}", moduleInfo);
+      } catch (IOException e) {
+        String errorMessage = String.format("Unable to parse quicklinks configuration file %s", quickLinksConfigurationFile.getAbsolutePath());
+        LOG.error(errorMessage,  e);
+        setValid(false);
+        setErrors(errorMessage);
+      }
+    }
+  }
+
+  public QuickLinksConfigurationModule(QuickLinksConfigurationInfo moduleInfo) {
+    this.moduleInfo = moduleInfo;
+  }
+
+  @Override
+  public void resolve(QuickLinksConfigurationModule parent, Map<String, StackModule> allStacks, Map<String, ServiceModule> commonServices) throws AmbariException {
+    QuickLinksConfigurationInfo parentModuleInfo = parent.getModuleInfo();
+
+    if (parent.getModuleInfo() != null && !moduleInfo.isDeleted()) {
+      if (moduleInfo.getQuickLinksConfigurationMap() == null || moduleInfo.getQuickLinksConfigurationMap().isEmpty()) {
+        moduleInfo.setQuickLinksConfigurationMap(parentModuleInfo.getQuickLinksConfigurationMap());
+      } else if(parentModuleInfo.getQuickLinksConfigurationMap() != null && !parentModuleInfo.getQuickLinksConfigurationMap().isEmpty()) {
+        QuickLinks child = moduleInfo.getQuickLinksConfigurationMap().get(QUICKLINKS_CONFIGURATION_KEY);
+        QuickLinks parentConfig= parentModuleInfo.getQuickLinksConfigurationMap().get(QUICKLINKS_CONFIGURATION_KEY);
+        child.mergeWithParent(parentConfig);
+      }
+    }
+  }
+
+  @Override
+  public QuickLinksConfigurationInfo getModuleInfo() {
+    return moduleInfo;
+  }
+
+  @Override
+  public boolean isDeleted() {
+    return false;
+  }
+
+  @Override
+  public String getId() {
+    return moduleInfo.getFileName();
+  }
+
+  @Override
+  public boolean isValid() {
+    return valid;
+  }
+
+  @Override
+  public void setValid(boolean valid) {
+    this.valid = valid;
+  }
+
+  @Override
+  public void setErrors(String error) {
+    errors.add(error);
+  }
+
+  @Override
+  public void setErrors(Collection<String> error) {
+    errors.addAll(error);
+  }
+
+  @Override
+  public Collection<String> getErrors() {
+    return errors;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java
index c2a2a0c..0c7faea 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java
@@ -23,19 +23,20 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
 import com.google.common.collect.Sets;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.CustomCommandDefinition;
 import org.apache.ambari.server.state.PropertyInfo;
+import org.apache.ambari.server.state.QuickLinksConfigurationInfo;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.ServicePropertyInfo;
 import org.apache.ambari.server.state.ThemeInfo;
 
 import javax.annotation.Nullable;
+
 import java.io.File;
 import java.util.Collection;
 import java.util.Collections;
@@ -79,6 +80,11 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem
   private Map<String, ThemeModule> themeModules = new HashMap<String, ThemeModule>();
 
   /**
+   * Map of quicklinks, single value currently
+   */
+  private Map<String, QuickLinksConfigurationModule> quickLinksConfigurationModules = new HashMap<String, QuickLinksConfigurationModule>();
+
+  /**
    * Encapsulates IO operations on service directory
    */
   private ServiceDirectory serviceDirectory;
@@ -129,6 +135,7 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem
     populateComponentModules();
     populateConfigurationModules();
     populateThemeModules();
+    populateQuickLinksConfigurationModules();
 
     validateServiceInfo();
   }
@@ -204,6 +211,7 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem
     mergeComponents(parentModule, allStacks, commonServices);
     mergeConfigurations(parentModule, allStacks, commonServices);
     mergeThemes(parentModule, allStacks, commonServices);
+    mergeQuickLinksConfigurations(parentModule, allStacks, commonServices);
     mergeExcludedConfigTypes(parent);
 
 
@@ -384,9 +392,41 @@ public class ServiceModule extends BaseModule<ServiceModule, ServiceInfo> implem
       } else {
         serviceInfo.getThemesMap().remove(moduleInfo.getFileName());
       }
+    }
+  }
 
+  private void populateQuickLinksConfigurationModules(){
+    if (serviceInfo.getQuickLinksConfigurationsDir() == null) {
+      serviceInfo.setQuickLinksConfigurationsDir(AmbariMetaInfo.SERVICE_QUICKLINKS_CONFIGURATIONS_FOLDER_NAME);
     }
 
+    String quickLinksConfigurationsDir = serviceDirectory.getAbsolutePath() + File.separator + serviceInfo.getQuickLinksConfigurationsDir();
+
+    if (serviceInfo.getQuickLinksConfigurations() != null) {
+      for (QuickLinksConfigurationInfo quickLinksConfigurationInfo: serviceInfo.getQuickLinksConfigurations()) {
+        File file = new File(quickLinksConfigurationsDir + File.separator + quickLinksConfigurationInfo.getFileName());
+        QuickLinksConfigurationModule module = new QuickLinksConfigurationModule(file, quickLinksConfigurationInfo);
+        quickLinksConfigurationModules.put(module.getId(), module);
+      }
+    }    //Not fail if quicklinks.json file contains errors
+  }
+
+  /**
+   * Merge theme modules.
+   */
+  private void mergeQuickLinksConfigurations(ServiceModule parent, Map<String, StackModule> allStacks,
+                           Map<String, ServiceModule> commonServices) throws AmbariException {
+    Collection<QuickLinksConfigurationModule> mergedModules = mergeChildModules(allStacks, commonServices, quickLinksConfigurationModules, parent.quickLinksConfigurationModules);
+
+    for (QuickLinksConfigurationModule mergedModule : mergedModules) {
+      quickLinksConfigurationModules.put(mergedModule.getId(), mergedModule);
+      QuickLinksConfigurationInfo moduleInfo = mergedModule.getModuleInfo();
+      if (!moduleInfo.isDeleted()) {
+        serviceInfo.getQuickLinksConfigurationsMap().put(moduleInfo.getFileName(), moduleInfo);
+      } else {
+        serviceInfo.getQuickLinksConfigurationsMap().remove(moduleInfo.getFileName());
+      }
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/state/QuickLinksConfigurationInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/QuickLinksConfigurationInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/QuickLinksConfigurationInfo.java
new file mode 100644
index 0000000..86fc002
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/QuickLinksConfigurationInfo.java
@@ -0,0 +1,87 @@
+/**
+ * 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;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import org.apache.ambari.server.state.quicklinks.QuickLinks;
+
+import java.util.Map;
+
+/**
+ * Wrapper for quickLinksConfiguration description
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+public class QuickLinksConfigurationInfo {
+
+  private String fileName;
+  @XmlElement(name = "default")
+  private Boolean isDefault = false;
+  private Boolean deleted = false;
+
+  @XmlTransient
+  private Map<String, QuickLinks> quickLinksConfigurationMap = null;
+
+  public QuickLinksConfigurationInfo() {
+  }
+
+  public Map<String, QuickLinks> getQuickLinksConfigurationMap() {
+    return quickLinksConfigurationMap;
+  }
+
+  public void setQuickLinksConfigurationMap(Map<String, QuickLinks> quickLinksConfigurationMap) {
+    this.quickLinksConfigurationMap = quickLinksConfigurationMap;
+  }
+
+  @Override
+  public String toString() {
+    return "QuickLinksConfigurationInfo{" +
+      "deleted=" + deleted +
+      ", fileName='" + fileName + '\'' +
+      ", isDefault=" + isDefault +
+      ", quickLinksConfigurationMap=" + quickLinksConfigurationMap +
+      '}';
+  }
+
+  public String getFileName() {
+    return fileName;
+  }
+
+  public void setFileName(String fileName) {
+    this.fileName = fileName;
+  }
+
+  public Boolean getIsDefault() {
+    return isDefault;
+  }
+
+  public void setIsDefault(Boolean isDefault) {
+    this.isDefault = isDefault;
+  }
+
+  public Boolean isDeleted() {
+    return deleted;
+  }
+
+  public void setDeleted(Boolean deleted) {
+    this.deleted = deleted;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/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 a58cda3..db95fec 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
@@ -210,6 +210,17 @@ public class ServiceInfo implements Validable{
   @XmlTransient
   private volatile Map<String, ThemeInfo> themesMap;
 
+  @JsonIgnore
+  @XmlElement(name = "quickLinksConfigurations-dir")
+  private String quickLinksConfigurationsDir = AmbariMetaInfo.SERVICE_QUICKLINKS_CONFIGURATIONS_FOLDER_NAME;
+
+  @JsonIgnore
+  @XmlElementWrapper(name = "quickLinksConfigurations")
+  @XmlElements(@XmlElement(name = "quickLinksConfiguration"))
+  private List<QuickLinksConfigurationInfo> quickLinksConfigurations;
+
+  @XmlTransient
+  private volatile Map<String, QuickLinksConfigurationInfo> quickLinksConfigurationsMap;
 
   /**
    * Map of of os-specific details that is exposed (and initialised from list)
@@ -769,6 +780,43 @@ public String getVersion() {
     this.themesMap = themesMap;
   }
 
+  //Quick links configurations
+  public String getQuickLinksConfigurationsDir() {
+    return quickLinksConfigurationsDir;
+  }
+
+  public void setQuickLinksConfigurationsDir(String quickLinksConfigurationsDir) {
+    this.quickLinksConfigurationsDir = quickLinksConfigurationsDir;
+  }
+
+  public List<QuickLinksConfigurationInfo> getQuickLinksConfigurations() {
+    return quickLinksConfigurations;
+  }
+
+  public void setQuickLinksConfigurations(List<QuickLinksConfigurationInfo> quickLinksConfigurations) {
+    this.quickLinksConfigurations = quickLinksConfigurations;
+  }
+
+  public Map<String, QuickLinksConfigurationInfo> getQuickLinksConfigurationsMap() {
+    if (quickLinksConfigurationsMap == null) {
+      synchronized (this) {
+      }
+      if (quickLinksConfigurationsMap == null) {
+        Map<String, QuickLinksConfigurationInfo> tmp = new TreeMap<String, QuickLinksConfigurationInfo>();
+        if (quickLinksConfigurations != null) {
+          for (QuickLinksConfigurationInfo quickLinksConfiguration : quickLinksConfigurations) {
+            tmp.put(quickLinksConfiguration.getFileName(), quickLinksConfiguration);
+          }
+        }
+        quickLinksConfigurationsMap = tmp;
+      }
+    }
+    return quickLinksConfigurationsMap;
+  }
+
+  public void setQuickLinksConfigurationsMap(Map<String, QuickLinksConfigurationInfo> quickLinksConfigurationsMap) {
+    this.quickLinksConfigurationsMap = quickLinksConfigurationsMap;
+  }
 
   public List<ServicePropertyInfo> getServicePropertyList() {
     return servicePropertyList;

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Check.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Check.java b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Check.java
new file mode 100644
index 0000000..7b68920
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Check.java
@@ -0,0 +1,60 @@
+/*
+ * 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.quicklinks;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Check{
+  @JsonProperty("property")
+  private String property;
+
+  @JsonProperty("desired")
+  private String desired;
+
+  @JsonProperty("site")
+  private String site;
+
+  public String getProperty() {
+    return property;
+  }
+
+  public void setProperty(String property) {
+    this.property = property;
+  }
+
+  public String getDesired() {
+    return desired;
+  }
+
+  public void setDesired(String desired) {
+    this.desired = desired;
+  }
+
+  public String getSite() {
+    return site;
+  }
+
+  public void setSite(String site) {
+    this.site = site;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Link.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Link.java b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Link.java
new file mode 100644
index 0000000..a0890f1
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Link.java
@@ -0,0 +1,127 @@
+/*
+ * 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.quicklinks;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Link{
+  @JsonProperty("name")
+  private String name;
+
+  @JsonProperty("label")
+  private String label;
+
+  @JsonProperty("requires_user_name")
+  private String requiresUserName;
+
+  @JsonProperty("url")
+  private String url;
+
+  @JsonProperty("template")
+  private String template;
+
+  @JsonProperty("port")
+  private Port port;
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getLabel() {
+    return label;
+  }
+
+  public void setLabel(String label) {
+    this.label = label;
+  }
+
+  public String getUrl() {
+    return url;
+  }
+
+  public void setUrl(String url) {
+    this.url = url;
+  }
+
+  public String getTemplate() {
+    return template;
+  }
+
+  public void setTemplate(String template) {
+    this.template = template;
+  }
+
+  public String getRequiresUserName() {
+    return requiresUserName;
+  }
+
+  public void setRequiresUserName(String requiresUserName) {
+    this.requiresUserName = requiresUserName;
+  }
+
+  public Port getPort() {
+    return port;
+  }
+
+  public void setPort(Port port) {
+    this.port = port;
+  }
+
+  public boolean isRemoved(){
+    //treat a link as removed if the section only contains a name
+    return (null == port && null == url && null == template && null == label && null == requiresUserName);
+  }
+
+  public void mergeWithParent(Link parentLink) {
+    if (null == parentLink)
+        return;
+
+    /* merge happens when a child link has some infor but not all of them.
+     * If a child link has nothing but a name, it's treated as being removed from the link list
+     */
+    if(null == template && null != parentLink.getTemplate())
+      template = parentLink.getTemplate();
+
+    if(null == label && null != parentLink.getLabel())
+      label = parentLink.getLabel();
+
+    if(null == url && null != parentLink.getUrl())
+      url = parentLink.getUrl();
+
+    if(null == template && null != parentLink.getTemplate())
+      template = parentLink.getTemplate();
+
+    if(null == requiresUserName && null != parentLink.getRequiresUserName())
+      requiresUserName = parentLink.getRequiresUserName();
+
+    if(null == port){
+        port = parentLink.getPort();
+    } else {
+      port.mergetWithParent(parentLink.getPort());
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Port.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Port.java b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Port.java
new file mode 100644
index 0000000..7bd4b81
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Port.java
@@ -0,0 +1,116 @@
+/*
+ * 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.quicklinks;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Port{
+  @JsonProperty("http_property")
+  private String httpProperty;
+
+  @JsonProperty("http_default_port")
+  private String httpDefaultPort;
+
+  @JsonProperty("https_property")
+  private String httpsProperty;
+
+  @JsonProperty("https_default_port")
+  private String httpsDefaultPort;
+
+  @JsonProperty("regex")
+  private String regex;
+
+  @JsonProperty("site")
+  private String site;
+
+  public String getHttpProperty() {
+    return httpProperty;
+  }
+
+  public void setHttpProperty(String httpProperty) {
+    this.httpProperty = httpProperty;
+  }
+
+  public String getHttpDefaultPort() {
+    return httpDefaultPort;
+  }
+
+  public void setHttpDefaultPort(String httpDefaultPort) {
+    this.httpDefaultPort = httpDefaultPort;
+  }
+
+  public String getHttpsProperty() {
+    return httpsProperty;
+  }
+
+  public void setHttpsProperty(String httpsProperty) {
+    this.httpsProperty = httpsProperty;
+  }
+
+  public String getHttpsDefaultPort() {
+    return httpsDefaultPort;
+  }
+
+  public void setHttpsDefaultPort(String httpsDefaultPort) {
+    this.httpsDefaultPort = httpsDefaultPort;
+  }
+
+  public String getRegex() {
+    return regex;
+  }
+
+  public void setRegex(String regex) {
+    this.regex = regex;
+  }
+
+  public String getSite() {
+    return site;
+  }
+
+  public void setSite(String site) {
+    this.site = site;
+  }
+
+  public void mergetWithParent(Port parentPort){
+    if(null == parentPort)
+      return;
+
+    if(null == httpProperty && null != parentPort.getHttpProperty())
+      httpProperty = parentPort.getHttpProperty();
+
+    if(null == httpDefaultPort && null != parentPort.getHttpDefaultPort())
+      httpDefaultPort = parentPort.getHttpDefaultPort();
+
+    if(null == httpsProperty && null != parentPort.getHttpsProperty())
+      httpsProperty = parentPort.getHttpsProperty();
+
+    if(null == httpsDefaultPort && null != parentPort.getHttpsDefaultPort())
+      httpsDefaultPort = parentPort.getHttpsDefaultPort();
+
+    if(null == regex && null != parentPort.getRegex())
+      regex = parentPort.getRegex();
+
+    if(null == site && null != parentPort.getSite())
+      site = parentPort.getSite();
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Protocol.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Protocol.java b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Protocol.java
new file mode 100644
index 0000000..d45d26f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/Protocol.java
@@ -0,0 +1,51 @@
+/*
+ * 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.quicklinks;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.util.List;
+
+@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Protocol{
+  @JsonProperty("type")
+  private String type;
+
+  @JsonProperty("checks")
+  private List<Check> checks;
+
+  public String getType() {
+    return type;
+  }
+
+  public void setType(String type) {
+    this.type = type;
+  }
+
+  public List<Check> getChecks() {
+    return checks;
+  }
+
+  public void setChecks(List<Check> checks) {
+    this.checks = checks;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/QuickLinks.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/QuickLinks.java b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/QuickLinks.java
new file mode 100644
index 0000000..a91b53c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/QuickLinks.java
@@ -0,0 +1,78 @@
+/*
+ * 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.quicklinks;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class QuickLinks{
+  @JsonProperty("description")
+  private String description;
+  @JsonProperty("name")
+  private String name;
+  @JsonProperty("configuration")
+  private QuickLinksConfiguration quickLinksConfiguration;
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(String description) {
+    this.description = description;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public QuickLinksConfiguration getQuickLinksConfiguration() {
+    return quickLinksConfiguration;
+  }
+
+  public void setQuickLinksConfiguration(QuickLinksConfiguration quickLinksConfiguration) {
+    this.quickLinksConfiguration = quickLinksConfiguration;
+  }
+
+  public void mergeWithParent(QuickLinks parent) {
+    if (parent == null) {
+      return;
+    }
+
+    if (name == null) {
+      name = parent.name;
+    }
+
+    if (description == null) {
+      description = parent.description;
+    }
+
+    if (quickLinksConfiguration == null) {
+      quickLinksConfiguration = parent.quickLinksConfiguration;
+    } else {
+      quickLinksConfiguration.mergeWithParent(parent.quickLinksConfiguration);
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/QuickLinksConfiguration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/QuickLinksConfiguration.java b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/QuickLinksConfiguration.java
new file mode 100644
index 0000000..c53ee5b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/quicklinks/QuickLinksConfiguration.java
@@ -0,0 +1,91 @@
+/*
+ * 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.quicklinks;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class QuickLinksConfiguration{
+  @JsonProperty("protocol")
+  private Protocol protocol;
+
+  @JsonProperty("links")
+  private List<Link> links;
+
+  public Protocol getProtocol() {
+    return protocol;
+  }
+
+  public void setProtocol(Protocol protocol) {
+    this.protocol = protocol;
+  }
+
+  public List<Link> getLinks() {
+    return links;
+  }
+
+  public void setLinks(List<Link> links) {
+    this.links = links;
+  }
+
+  public void mergeWithParent(QuickLinksConfiguration parent) {
+    if (parent == null) {
+      return;
+    }
+
+    //protocol uses override merge, if the child has it, then use it
+    if(protocol == null)
+      protocol = parent.getProtocol();
+
+    if (links == null) {
+      links = parent.getLinks();
+    } else if (parent.getLinks() != null) {
+      links = mergeLinks(parent.getLinks(), links);
+    }
+  }
+
+  private List<Link> mergeLinks(List<Link> parentLinks, List<Link> childLinks) {
+    Map<String, Link> mergedLinks = new HashMap<String, Link>();
+
+    for (Link parentLink : parentLinks) {
+      mergedLinks.put(parentLink.getName(), parentLink);
+    }
+
+    for (Link childLink : childLinks) {
+      if (childLink.getName() != null) {
+        if(childLink.isRemoved()){
+          mergedLinks.remove(childLink.getName());
+        } else {
+          Link parentLink = mergedLinks.get(childLink.getName());
+          childLink.mergeWithParent(parentLink);
+          mergedLinks.put(childLink.getName(), childLink);
+        }
+      }
+    }
+    return new ArrayList<Link>(mergedLinks.values());
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/metainfo.xml b/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/metainfo.xml
index ae58b5c..80a563c 100644
--- a/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/metainfo.xml
+++ b/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/metainfo.xml
@@ -114,6 +114,12 @@
         <config-type>oozie-site</config-type>
       </excluded-config-types>
 
+      <quickLinksConfigurations>
+        <quickLinksConfiguration>
+          <fileName>quicklinks.json</fileName>
+          <default>true</default>
+        </quickLinksConfiguration>
+      </quickLinksConfigurations>
     </service>
   </services>
 </metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/quicklinks/quicklinks.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/quicklinks/quicklinks.json b/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/quicklinks/quicklinks.json
new file mode 100644
index 0000000..bbea282
--- /dev/null
+++ b/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/quicklinks/quicklinks.json
@@ -0,0 +1,28 @@
+{
+  "name": "default",
+  "description": "default quick links configuration",
+  "configuration": {
+    "protocol":
+    {
+      "type":"HTTP_ONLY"
+    },
+
+    "links": [
+      {
+        "name": "falcon_web_ui",
+        "label": "Falcon Web UI",
+        "requires_user_name": "true",
+        "url":"%@://%@:%@/index.html?user.name=%@",
+        "template":"%@://%@:%@/index.html?user.name=%@",
+        "port":{
+          "http_property": "falcon_port",
+          "http_default_port": "15000",
+          "https_property": "falcon_port",
+          "https_default_port": "15000",
+          "regex": "^(\\d+)$",
+          "site": "falcon-env"
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/metainfo.xml b/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/metainfo.xml
index 515f385..1468a2f 100644
--- a/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/metainfo.xml
+++ b/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/metainfo.xml
@@ -135,6 +135,12 @@
         <config-type>zookeeper-env</config-type>
         <config-type>zoo.cfg</config-type>
       </configuration-dependencies>
+      <quickLinksConfigurations>
+        <quickLinksConfiguration>
+          <fileName>quicklinks.json</fileName>
+          <default>true</default>
+        </quickLinksConfiguration>
+      </quickLinksConfigurations>
     </service>
   </services>
 </metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/quicklinks/quicklinks.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/quicklinks/quicklinks.json b/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/quicklinks/quicklinks.json
new file mode 100644
index 0000000..dd17275
--- /dev/null
+++ b/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/quicklinks/quicklinks.json
@@ -0,0 +1,28 @@
+{
+  "name": "default",
+  "description": "default quick links configuration",
+  "configuration": {
+    "protocol":
+    {
+      "type":"HTTP_ONLY"
+    },
+
+    "links": [
+      {
+        "name": "storm_ui",
+        "label": "Storm UI",
+        "requires_user_name": "false",
+        "url":"%@://%@:%@/",
+        "template":"%@://%@:%@/",
+        "port":{
+          "http_property": "ui.port",
+          "http_default_port": "8744",
+          "https_property": "ui.port",
+          "https_default_port": "8744",
+          "regex": "^(\\d+)$",
+          "site": "storm-site"
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/OOZIE/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/OOZIE/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/OOZIE/metainfo.xml
index dad6dc1..8b24091 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/OOZIE/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/OOZIE/metainfo.xml
@@ -22,5 +22,12 @@
       <name>OOZIE</name>
       <extends>common-services/OOZIE/4.0.0.2.0</extends>
     </service>
+
+    <quickLinksConfigurations>
+        <quickLinksConfiguration>
+          <fileName>quicklinks.json</fileName>
+          <default>true</default>
+        </quickLinksConfiguration>
+      </quickLinksConfigurations>
   </services>
 </metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/OOZIE/quicklinks/quicklinks.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/OOZIE/quicklinks/quicklinks.json b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/OOZIE/quicklinks/quicklinks.json
new file mode 100644
index 0000000..e7c23a4
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/services/OOZIE/quicklinks/quicklinks.json
@@ -0,0 +1,45 @@
+{
+  "name": "default",
+  "description": "default quick links configuration",
+  "configuration": {
+    "protocol":
+    {
+      "type":"https",
+      "checks":[
+        {
+          "property":"oozie.https.port",
+          "desired":"EXISTS",
+          "site":"oozie-site"
+        },
+        {
+          "property":"oozie.https.keystore.file",
+          "desired":"EXISTS",
+          "site":"oozie-site"
+        },
+        {
+          "property":"oozie.https.keystore.pass",
+          "desired":"EXISTS",
+          "site":"oozie-site"
+        }
+      ]
+    },
+
+    "links": [
+      {
+        "name": "resourcemanager_ui",
+        "label": "Oozie Web UI",
+        "requires_user_name": "true",
+        "url":"%@://%@:%@/oozie?user.name=%@",
+        "template":"%@://%@:%@/oozie?user.name=%@",
+        "port":{
+          "http_property": "oozie.base.url",
+          "http_default_port": "11000",
+          "https_property": "oozie.base.url",
+          "https_default_port": "11443",
+          "regex": "\\w*:(\\d+)",
+          "site": "oozie-site"
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.2/services/RANGER/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/RANGER/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/RANGER/metainfo.xml
index 4d1b305..0c457f7 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/RANGER/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/RANGER/metainfo.xml
@@ -54,6 +54,12 @@
           </packages>
         </osSpecific>
       </osSpecifics>
+      <quickLinksConfigurations>
+        <quickLinksConfiguration>
+          <fileName>quicklinks.json</fileName>
+          <default>true</default>
+        </quickLinksConfiguration>
+      </quickLinksConfigurations>
     </service>
   </services>
 </metainfo>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.2/services/RANGER/quicklinks/quicklinks.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/RANGER/quicklinks/quicklinks.json b/ambari-server/src/main/resources/stacks/HDP/2.2/services/RANGER/quicklinks/quicklinks.json
new file mode 100644
index 0000000..7e2ba25
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/RANGER/quicklinks/quicklinks.json
@@ -0,0 +1,35 @@
+{
+  "name": "default",
+  "description": "default quick links configuration",
+  "configuration": {
+    "protocol":
+    {
+      "type":"https",
+      "checks":[
+        {
+          "property":"https.enabled",
+          "desired":"true",
+          "site":"ranger-site"
+        }
+      ]
+    },
+
+    "links": [
+      {
+        "name": "ranger_admin_ui",
+        "label": "Ranger Admin UI",
+        "requires_user_name": "false",
+        "url": "%@://%@:%@",
+        "template": "%@://%@:%@",
+        "port":{
+          "http_property": "http.service.port",
+          "http_default_port": "6080",
+          "https_property": "https.service.port",
+          "https_default_port": "6182",
+          "regex": "(\\d*)+",
+          "site": "ranger-site"
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.2/services/SPARK/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/SPARK/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/SPARK/metainfo.xml
index db11d05..5cb598e 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.2/services/SPARK/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/SPARK/metainfo.xml
@@ -49,6 +49,12 @@
           </packages>
         </osSpecific>
       </osSpecifics>
+      <quickLinksConfigurations>
+        <quickLinksConfiguration>
+          <fileName>quicklinks.json</fileName>
+          <default>true</default>
+        </quickLinksConfiguration>
+      </quickLinksConfigurations>
     </service>
   </services>
 </metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.2/services/SPARK/quicklinks/quicklinks.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/SPARK/quicklinks/quicklinks.json b/ambari-server/src/main/resources/stacks/HDP/2.2/services/SPARK/quicklinks/quicklinks.json
new file mode 100644
index 0000000..c3e51e6
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/SPARK/quicklinks/quicklinks.json
@@ -0,0 +1,28 @@
+{
+  "name": "default",
+  "description": "default quick links configuration",
+  "configuration": {
+    "protocol":
+    {
+      "type":"HTTP_ONLY"
+    },
+
+    "links": [
+      {
+        "name": "spark_history_server_ui",
+        "label": "Spark History Server UI",
+        "requires_user_name": "false",
+        "url": "%@://%@:%@",
+        "template": "%@://%@:%@",
+        "port":{
+          "http_property": "spark.history.ui.port",
+          "http_default_port": "18080",
+          "https_property": "spark.history.ui.port",
+          "https_default_port": "18080",
+          "regex": "^(\\d+)$",
+          "site": "spark-defaults"
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/metainfo.xml
index 352341b..b19aac1 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/metainfo.xml
@@ -40,7 +40,12 @@
           </packages>
         </osSpecific>
       </osSpecifics>
-
+      <quickLinksConfigurations>
+        <quickLinksConfiguration>
+          <fileName>quicklinks.json</fileName>
+          <default>true</default>
+        </quickLinksConfiguration>
+      </quickLinksConfigurations>
     </service>
   </services>
 </metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/quicklinks/quicklinks.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/quicklinks/quicklinks.json b/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/quicklinks/quicklinks.json
new file mode 100644
index 0000000..21c5e54
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/quicklinks/quicklinks.json
@@ -0,0 +1,40 @@
+{
+  "name": "default",
+  "description": "default quick links configuration",
+  "configuration": {
+    "protocol":
+    {
+      "type":"https",
+      "checks":[
+        {
+          "property":"monitor.ssl.keyStore",
+          "desired":"EXIST",
+          "site":"accumulo-site"
+        },
+        {
+          "property":"monitor.ssl.trustStore",
+          "desired":"EXIST",
+          "site":"accumulo-site"
+        }
+      ]
+    },
+
+    "links": [
+      {
+        "name": "accumulo_monitor_ui",
+        "label": "Accumulo Monitor UI",
+        "requires_user_name": "false",
+        "url": "%@://%@:%@/",
+        "template": "%@://%@:%@/",
+        "port":{
+          "http_property": "monitor.port.client",
+          "http_default_port": "50095",
+          "https_property": "monitor.port.client",
+          "https_default_port": "50095",
+          "regex": "^(\\d+)$",
+          "site": "accumulo-site"
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.3/services/ATLAS/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/ATLAS/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/ATLAS/metainfo.xml
index fee10d3..c3a3c81 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/ATLAS/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/ATLAS/metainfo.xml
@@ -40,6 +40,12 @@
           </packages>
         </osSpecific>
       </osSpecifics>
+      <quickLinksConfigurations>
+        <quickLinksConfiguration>
+          <fileName>quicklinks.json</fileName>
+          <default>true</default>
+        </quickLinksConfiguration>
+      </quickLinksConfigurations>
     </service>
   </services>
 </metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.3/services/ATLAS/quicklinks/quicklinks.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/ATLAS/quicklinks/quicklinks.json b/ambari-server/src/main/resources/stacks/HDP/2.3/services/ATLAS/quicklinks/quicklinks.json
new file mode 100644
index 0000000..dd67ec0
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/ATLAS/quicklinks/quicklinks.json
@@ -0,0 +1,35 @@
+{
+  "name": "default",
+  "description": "default quick links configuration",
+  "configuration": {
+    "protocol":
+    {
+      "type":"https",
+      "checks":[
+        {
+          "property":"metadata.enableTLS",
+          "desired":"true",
+          "site":"application-properties"
+        }
+      ]
+    },
+
+    "links": [
+      {
+        "name": "atlas_dashboard",
+        "label": "Atlas Dashboard",
+        "requires_user_name": "true",
+        "url": "%@://%@:%@/#!/search?user.name=%@",
+        "template": "%@://%@:%@/#!/search?user.name=%@",
+        "port":{
+          "http_property": "atlas.server.http.port",
+          "http_default_port": "21000",
+          "https_property": "atlas.server.https.port",
+          "https_default_port": "21443",
+          "regex": "^(\\d+)$",
+          "site": "application-properties"
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/metainfo.xml
index 90a31f5..a37378c 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/metainfo.xml
@@ -68,6 +68,12 @@
         </theme>
       </themes>
 
+      <quickLinksConfigurations>
+        <quickLinksConfiguration>
+          <fileName>quicklinks.json</fileName>
+          <default>true</default>
+        </quickLinksConfiguration>
+      </quickLinksConfigurations>
     </service>
   </services>
 </metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/quicklinks/quicklinks.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/quicklinks/quicklinks.json b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/quicklinks/quicklinks.json
new file mode 100644
index 0000000..b52af55
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/quicklinks/quicklinks.json
@@ -0,0 +1,103 @@
+{
+  "name": "default",
+  "description": "default quick links configuration",
+  "configuration": {
+    "protocol":
+    {
+      "type":"http"
+    },
+
+    "links": [
+      {
+        "name": "hbase_master_ui",
+        "label": "HBase Master UI",
+        "url":"%@://%@:%@/master-status",
+        "requires_user_name": "false",
+        "template":"%@://%@:%@/master-status",
+        "port":{
+          "http_property": "hbase.master.info.port",
+          "http_default_port": "60010",
+          "https_property": "hbase.master.info.port",
+          "https_default_port": "60443",
+          "regex": "",
+          "site": "hbase-site"
+        }
+      },
+      {
+        "name": "hbase_logs",
+        "label": "HBase Logs",
+        "url":"%@://%@:%@/logs",
+        "requires_user_name": "false",
+        "template":"%@://%@:%@/logs",
+        "port":{
+          "http_property": "hbase.master.info.port",
+          "http_default_port": "60010",
+          "https_property": "hbase.master.info.port",
+          "https_default_port": "60443",
+          "regex": "",
+          "site": "hbase-site"
+        }
+      },
+      {
+        "name": "zookeeper_info",
+        "label": "Zookeeper Info",
+        "url":"%@://%@:%@/zk.jsp",
+        "requires_user_name": "false",
+        "template":"%@://%@:%@/zk.jsp",
+        "port":{
+          "http_property": "hbase.master.info.port",
+          "http_default_port": "60010",
+          "https_property": "hbase.master.info.port",
+          "https_default_port": "60443",
+          "regex": "",
+          "site": "hbase-site"
+        }
+      },
+      {
+        "name": "hbase_master_jmx",
+        "label": "HBase Master JMX",
+        "url":"%@://%@:%@/jmx",
+        "requires_user_name": "false",
+        "template":"%@://%@:%@/jmx",
+        "port":{
+          "http_property": "hbase.master.info.port",
+          "http_default_port": "60010",
+          "https_property": "hbase.master.info.port",
+          "https_default_port": "60443",
+          "regex": "",
+          "site": "hbase-site"
+        }
+      },
+      {
+        "name": "debug_dump",
+        "label": "Debug Dump",
+        "url":"%@://%@:%@/dump",
+        "requires_user_name": "false",
+        "template":"%@://%@:%@/dump",
+        "port":{
+          "http_property": "hbase.master.info.port",
+          "http_default_port": "60010",
+          "https_property": "hbase.master.info.port",
+          "https_default_port": "60443",
+          "regex": "",
+          "site": "hbase-site"
+        }
+      },
+      {
+        "name": "thread_stacks",
+        "label": "Thread Stacks",
+        "url":"%@://%@:%@/stacks",
+        "requires_user_name": "false",
+        "template":"%@://%@:%@/stacks",
+        "port":{
+          "http_property": "hbase.master.info.port",
+          "http_default_port": "60010",
+          "https_property": "hbase.master.info.port",
+          "https_default_port": "60443",
+          "regex": "",
+          "site": "hbase-site"
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
index ca69195..d103caf 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/metainfo.xml
@@ -117,7 +117,12 @@
           </packages>
         </osSpecific>
       </osSpecifics>
-
+      <quickLinksConfigurations>
+        <quickLinksConfiguration>
+          <fileName>quicklinks.json</fileName>
+          <default>true</default>
+        </quickLinksConfiguration>
+      </quickLinksConfigurations>
     </service>
   </services>
 </metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/quicklinks/quicklinks.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/quicklinks/quicklinks.json b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/quicklinks/quicklinks.json
new file mode 100644
index 0000000..9fb97d0
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HDFS/quicklinks/quicklinks.json
@@ -0,0 +1,80 @@
+{
+  "name": "default",
+  "description": "default quick links configuration",
+  "configuration": {
+    "protocol":
+    {
+      "type":"https",
+      "checks":[
+        {
+          "property":"dfs.http.policy",
+          "desired":"HTTPS_ONLY",
+          "site":"hdfs-site"
+        }
+      ]
+    },
+
+    "links": [
+      {
+        "name": "namenode_ui",
+        "label": "NameNode UI",
+        "url":"%@://%@:%@",
+        "requires_user_name": "false",
+        "template":"%@://%@:%@",
+        "port":{
+          "http_property": "dfs.namenode.http-address",
+          "http_default_port": "50070",
+          "https_property": "dfs.namenode.https-address",
+          "https_default_port": "50470",
+          "regex": "\\w*:(\\d+)",
+          "site": "hdfs-site"
+        }
+      },
+      {
+        "name": "namenode_logs",
+        "label": "NameNode Logs",
+        "url":"%@://%@:%@/logs",
+        "requires_user_name": "false",
+        "template":"%@://%@:%@/logs",
+        "port":{
+          "http_property": "dfs.namenode.http-address",
+          "http_default_port": "50070",
+          "https_property": "dfs.namenode.https-address",
+          "https_default_port": "50470",
+          "regex": "\\w*:(\\d+)",
+          "site": "hdfs-site"
+        }
+      },
+      {
+        "name": "namenode_jmx",
+        "label": "NameNode JMX",
+        "url":"%@://%@:%@/jmx",
+        "requires_user_name": "false",
+        "template":"%@://%@:%@/jmx",
+        "port":{
+          "http_property": "dfs.namenode.http-address",
+          "http_default_port": "50070",
+          "https_property": "dfs.namenode.https-address",
+          "https_default_port": "50470",
+          "regex": "\\w*:(\\d+)",
+          "site": "hdfs-site"
+        }
+      },
+      {
+        "name": "Thread Stacks",
+        "label": "Thread Stacks",
+        "url":"%@://%@:%@/stacks",
+        "requires_user_name": "false",
+        "template":"%@://%@:%@/stacks",
+        "port":{
+          "http_property": "dfs.namenode.http-address",
+          "http_default_port": "50070",
+          "https_property": "dfs.namenode.https-address",
+          "https_default_port": "50470",
+          "regex": "\\w*:(\\d+)",
+          "site": "hdfs-site"
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.3/services/OOZIE/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/OOZIE/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/OOZIE/metainfo.xml
index ccf5de3..2fe0ed0 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/OOZIE/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/OOZIE/metainfo.xml
@@ -65,8 +65,13 @@
             </package>
           </packages>
         </osSpecific>
-
       </osSpecifics>
+      <quickLinksConfigurations>
+        <quickLinksConfiguration>
+          <fileName>quicklinks.json</fileName>
+          <default>true</default>
+        </quickLinksConfiguration>
+      </quickLinksConfigurations>
     </service>
   </services>
 </metainfo>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.3/services/OOZIE/quicklinks/quicklinks.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/OOZIE/quicklinks/quicklinks.json b/ambari-server/src/main/resources/stacks/HDP/2.3/services/OOZIE/quicklinks/quicklinks.json
new file mode 100644
index 0000000..e7c23a4
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/OOZIE/quicklinks/quicklinks.json
@@ -0,0 +1,45 @@
+{
+  "name": "default",
+  "description": "default quick links configuration",
+  "configuration": {
+    "protocol":
+    {
+      "type":"https",
+      "checks":[
+        {
+          "property":"oozie.https.port",
+          "desired":"EXISTS",
+          "site":"oozie-site"
+        },
+        {
+          "property":"oozie.https.keystore.file",
+          "desired":"EXISTS",
+          "site":"oozie-site"
+        },
+        {
+          "property":"oozie.https.keystore.pass",
+          "desired":"EXISTS",
+          "site":"oozie-site"
+        }
+      ]
+    },
+
+    "links": [
+      {
+        "name": "resourcemanager_ui",
+        "label": "Oozie Web UI",
+        "requires_user_name": "true",
+        "url":"%@://%@:%@/oozie?user.name=%@",
+        "template":"%@://%@:%@/oozie?user.name=%@",
+        "port":{
+          "http_property": "oozie.base.url",
+          "http_default_port": "11000",
+          "https_property": "oozie.base.url",
+          "https_default_port": "11443",
+          "regex": "\\w*:(\\d+)",
+          "site": "oozie-site"
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/eca97913/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml
index 2fb8a9a..bc52e85 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/RANGER/metainfo.xml
@@ -64,6 +64,12 @@
         <config-type>ranger-ugsync-site</config-type>
       </configuration-dependencies>
 
+      <quickLinksConfigurations>
+        <quickLinksConfiguration>
+          <fileName>quicklinks.json</fileName>
+          <default>true</default>
+        </quickLinksConfiguration>
+      </quickLinksConfigurations>
     </service>
   </services>
 </metainfo>
\ No newline at end of file