http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java
index 60523cd..178d129 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java
@@ -78,7 +78,7 @@ public class PrepareDisableKerberosServerAction extends 
AbstractPrepareKerberosS
 
     KerberosHelper kerberosHelper = getKerberosHelper();
 
-    KerberosDescriptor kerberosDescriptor = 
kerberosHelper.getKerberosDescriptor(cluster);
+    KerberosDescriptor kerberosDescriptor = 
kerberosHelper.getKerberosDescriptor(cluster, false);
     Collection<String> identityFilter = getIdentityFilter();
     List<ServiceComponentHost> schToProcess = 
kerberosHelper.getServiceComponentHostsToProcess(cluster,
         kerberosDescriptor,

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java
index ca15695..da83a74 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java
@@ -32,6 +32,10 @@ import org.apache.ambari.server.controller.KerberosHelper;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.ServiceComponentHost;
 import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * PrepareEnableKerberosServerAction is a ServerAction implementation that 
prepares metadata needed
@@ -39,6 +43,8 @@ import 
org.apache.ambari.server.state.kerberos.KerberosDescriptor;
  */
 public class PrepareEnableKerberosServerAction extends 
PrepareKerberosIdentitiesServerAction {
 
+  private final static Logger LOG = 
LoggerFactory.getLogger(PrepareEnableKerberosServerAction.class);
+
   /**
    * Called to execute this action.  Upon invocation, calls
    * {@link KerberosServerAction#processIdentities(Map)}
@@ -62,11 +68,33 @@ public class PrepareEnableKerberosServerAction extends 
PrepareKerberosIdentities
       throw new AmbariException("Missing cluster object");
     }
 
-    KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster);
+    Map<String, String> commandParameters = getCommandParameters();
+
+    String preconfigureServices = getCommandParameterValue(commandParameters, 
PRECONFIGURE_SERVICES);
+    PreconfigureServiceType type = null;
+    if (!StringUtils.isEmpty(preconfigureServices)) {
+      try {
+        type = 
PreconfigureServiceType.valueOf(preconfigureServices.toUpperCase());
+      } catch (Throwable t) {
+        LOG.warn("Invalid preconfigure_services value, assuming DEFAULT: {}", 
preconfigureServices);
+        type = PreconfigureServiceType.DEFAULT;
+      }
+    }
+
+    KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster, 
type != PreconfigureServiceType.NONE);
+    if (type == PreconfigureServiceType.ALL) {
+      // Force all services to be flagged for pre-configuration...
+      Map<String, KerberosServiceDescriptor> serviceDescriptors = 
kerberosDescriptor.getServices();
+      if (serviceDescriptors != null) {
+        for (KerberosServiceDescriptor serviceDescriptor : 
serviceDescriptors.values()) {
+          serviceDescriptor.setPreconfigure(true);
+        }
+      }
+    }
+
     Collection<String> identityFilter = getIdentityFilter();
     List<ServiceComponentHost> schToProcess = 
getServiceComponentHostsToProcess(cluster, kerberosDescriptor, identityFilter);
 
-    Map<String, String> commandParameters = getCommandParameters();
     String dataDirectory = getCommandParameterValue(commandParameters, 
DATA_DIRECTORY);
     Map<String, Map<String, String>> kerberosConfigurations = new HashMap<>();
 
@@ -92,10 +120,14 @@ public class PrepareEnableKerberosServerAction extends 
PrepareKerberosIdentities
     processServiceComponentHosts(cluster, kerberosDescriptor, schToProcess, 
identityFilter, dataDirectory,
         configurations, kerberosConfigurations, true, propertiesToIgnore);
 
+    // Calculate the set of configurations to update and replace any variables
+    // using the previously calculated Map of configurations for the host.
+    kerberosConfigurations = 
kerberosHelper.processPreconfiguredServiceConfigurations(kerberosConfigurations,
 configurations, cluster, kerberosDescriptor);
+
     kerberosHelper.applyStackAdvisorUpdates(cluster, services, configurations, 
kerberosConfigurations,
           propertiesToIgnore, propertiesToRemove, true);
 
-    processAuthToLocalRules(cluster, kerberosDescriptor, schToProcess, 
kerberosConfigurations, getDefaultRealm(commandParameters));
+    processAuthToLocalRules(cluster, configurations, kerberosDescriptor, 
schToProcess, kerberosConfigurations, getDefaultRealm(commandParameters), true);
 
     // Ensure the cluster-env/security_enabled flag is set properly
     Map<String, String> clusterEnvProperties = 
kerberosConfigurations.get(KerberosHelper.SECURITY_ENABLED_CONFIG_TYPE);

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
index f239cff..581067f 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
@@ -66,7 +66,7 @@ public class PrepareKerberosIdentitiesServerAction extends 
AbstractPrepareKerber
       throw new AmbariException("Missing cluster object");
     }
 
-    KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster);
+    KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster, 
false);
     Collection<String> identityFilter = getIdentityFilter();
     List<ServiceComponentHost> schToProcess = 
getServiceComponentHostsToProcess(cluster, kerberosDescriptor, identityFilter);
 
@@ -98,10 +98,11 @@ public class PrepareKerberosIdentitiesServerAction extends 
AbstractPrepareKerber
         configurations, kerberosConfigurations, includeAmbariIdentity, 
propertiesToIgnore);
 
     kerberosHelper.applyStackAdvisorUpdates(cluster, services, configurations, 
kerberosConfigurations,
-        propertiesToIgnore,  propertiesToRemove, true);
+        propertiesToIgnore, propertiesToRemove, true);
 
     if ("true".equalsIgnoreCase(getCommandParameterValue(commandParameters, 
UPDATE_CONFIGURATIONS))) {
-      processAuthToLocalRules(cluster, kerberosDescriptor, schToProcess, 
kerberosConfigurations, getDefaultRealm(commandParameters));
+      Map<String, Map<String, String>> calculatedConfigurations = 
kerberosHelper.calculateConfigurations(cluster, null, 
kerberosDescriptor.getProperties());
+      processAuthToLocalRules(cluster, calculatedConfigurations, 
kerberosDescriptor, schToProcess, kerberosConfigurations, 
getDefaultRealm(commandParameters), false);
       processConfigurationChanges(dataDirectory, kerberosConfigurations, 
propertiesToRemove);
     }
 
@@ -147,34 +148,38 @@ public class PrepareKerberosIdentitiesServerAction 
extends AbstractPrepareKerber
   }
 
   /**
-   * Calls {@link KerberosHelper#getKerberosDescriptor(Cluster)}
+   * Calls {@link KerberosHelper#getKerberosDescriptor(Cluster, boolean)}
    *
-   * @param cluster cluster instance
+   * @param cluster                 cluster instance
+   * @param includePreconfigureData <code>true</code> to include the 
preconfigure data; <code>false</code> otherwise
    * @return the kerberos descriptor associated with the specified cluster
    * @throws AmbariException if unable to obtain the descriptor
-   * @see KerberosHelper#getKerberosDescriptor(Cluster)
+   * @see KerberosHelper#getKerberosDescriptor(Cluster, boolean)
    */
-  protected KerberosDescriptor getKerberosDescriptor(Cluster cluster)
+  protected KerberosDescriptor getKerberosDescriptor(Cluster cluster, boolean 
includePreconfigureData)
       throws AmbariException {
-    return getKerberosHelper().getKerberosDescriptor(cluster);
+    return getKerberosHelper().getKerberosDescriptor(cluster, 
includePreconfigureData);
   }
 
   /**
-   * Conditionally calls {@link 
KerberosHelper#setAuthToLocalRules(KerberosDescriptor, String, Map, Map, Map)}
+   * Conditionally calls {@link KerberosHelper#setAuthToLocalRules(Cluster, 
KerberosDescriptor, String, Map, Map, Map, boolean)}
    * if there are ServiceComponentHosts to process
    *
-   * @param cluster                cluster instance
-   * @param kerberosDescriptor     the current Kerberos descriptor
-   * @param schToProcess           a list of ServiceComponentHosts to process
-   * @param kerberosConfigurations the Kerberos-specific configuration map
-   * @param defaultRealm           the default realm
+   * @param cluster                  the cluster
+   * @param calculatedConfiguration  the configurations for the current 
cluster, used for replacements
+   * @param kerberosDescriptor       the current Kerberos descriptor
+   * @param schToProcess             a list of ServiceComponentHosts to process
+   * @param kerberosConfigurations   the Kerberos-specific configuration map
+   * @param defaultRealm             the default realm
+   * @param includePreconfiguredData true to include services flagged to be 
pre-configured; false otherwise
    * @throws AmbariException
-   * @see KerberosHelper#setAuthToLocalRules(KerberosDescriptor, String, Map, 
Map, Map)
+   * @see KerberosHelper#setAuthToLocalRules(Cluster, KerberosDescriptor, 
String, Map, Map, Map, boolean)
    */
-  protected void processAuthToLocalRules(Cluster cluster, KerberosDescriptor 
kerberosDescriptor,
-                                         List<ServiceComponentHost> 
schToProcess,
-                                         Map<String, Map<String, String>> 
kerberosConfigurations,
-                                         String defaultRealm)
+  void processAuthToLocalRules(Cluster cluster, Map<String, Map<String, 
String>> calculatedConfiguration,
+                               KerberosDescriptor kerberosDescriptor,
+                               List<ServiceComponentHost> schToProcess,
+                               Map<String, Map<String, String>> 
kerberosConfigurations,
+                               String defaultRealm, boolean 
includePreconfiguredData)
       throws AmbariException {
     if (!schToProcess.isEmpty()) {
       actionLog.writeStdOut("Creating auth-to-local rules");
@@ -191,9 +196,8 @@ public class PrepareKerberosIdentitiesServerAction extends 
AbstractPrepareKerber
       }
 
       KerberosHelper kerberosHelper = getKerberosHelper();
-      kerberosHelper.setAuthToLocalRules(kerberosDescriptor, defaultRealm, 
services,
-          kerberosHelper.calculateConfigurations(cluster, null, 
kerberosDescriptor.getProperties()),
-          kerberosConfigurations);
+      kerberosHelper.setAuthToLocalRules(cluster, kerberosDescriptor, 
defaultRealm, services,
+          calculatedConfiguration, kerberosConfigurations, 
includePreconfiguredData);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java
index 78aaa77..8640600 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpgradeUserKerberosDescriptor.java
@@ -116,7 +116,7 @@ public class UpgradeUserKerberosDescriptor extends 
AbstractUpgradeServerAction {
           logErrorMessage(messages, errorMessages, "The new stack version 
information was not found.");
         } else {
           logMessage(messages, String.format("Obtaining new stack Kerberos 
descriptor for %s.", targetStackId.toString()));
-          newDescriptor = 
ambariMetaInfo.getKerberosDescriptor(targetStackId.getStackName(), 
targetStackId.getStackVersion());
+          newDescriptor = 
ambariMetaInfo.getKerberosDescriptor(targetStackId.getStackName(), 
targetStackId.getStackVersion(), false);
 
           if (newDescriptor == null) {
             logErrorMessage(messages, errorMessages, String.format("The 
Kerberos descriptor for the new stack version, %s, was not found.", 
targetStackId.toString()));
@@ -127,7 +127,7 @@ public class UpgradeUserKerberosDescriptor extends 
AbstractUpgradeServerAction {
           logErrorMessage(messages, errorMessages, "The previous stack version 
information was not found.");
         } else {
           logMessage(messages, String.format("Obtaining previous stack 
Kerberos descriptor for %s.", originalStackId.toString()));
-          previousDescriptor = 
ambariMetaInfo.getKerberosDescriptor(originalStackId.getStackName(), 
originalStackId.getStackVersion());
+          previousDescriptor = 
ambariMetaInfo.getKerberosDescriptor(originalStackId.getStackName(), 
originalStackId.getStackVersion(), false);
 
           if (newDescriptor == null) {
             logErrorMessage(messages, errorMessages, String.format("The 
Kerberos descriptor for the previous stack version, %s, was not found.", 
originalStackId.toString()));

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/stack/ConfigurationDirectory.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/ConfigurationDirectory.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/ConfigurationDirectory.java
index 4b6e9a8..cf5a678 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/ConfigurationDirectory.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/ConfigurationDirectory.java
@@ -30,7 +30,6 @@ import javax.xml.bind.JAXBException;
 import javax.xml.bind.UnmarshalException;
 import javax.xml.namespace.QName;
 
-import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.state.stack.ConfigurationXml;
@@ -94,10 +93,10 @@ public class ConfigurationDirectory extends 
StackDefinitionDirectory {
    * Parse the configuration directory.
    */
   private void parsePath() {
-    File[] configFiles = directory.listFiles(AmbariMetaInfo.FILENAME_FILTER);
+    File[] configFiles = directory.listFiles(StackDirectory.FILENAME_FILTER);
     if (configFiles != null) {
       for (File configFile : configFiles) {
-        if 
(configFile.getName().endsWith(AmbariMetaInfo.SERVICE_CONFIG_FILE_NAME_POSTFIX))
 {
+        if 
(configFile.getName().endsWith(StackDirectory.SERVICE_CONFIG_FILE_NAME_POSTFIX))
 {
           String configType = 
ConfigHelper.fileNameToConfigType(configFile.getName());
           ConfigurationXml config = null;
           try {

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/stack/ExtensionDirectory.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/ExtensionDirectory.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/ExtensionDirectory.java
index 131318b..3dda699 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/ExtensionDirectory.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/ExtensionDirectory.java
@@ -24,7 +24,6 @@ import java.util.Collection;
 import java.util.HashSet;
 
 import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.state.stack.ExtensionMetainfoXml;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -158,7 +157,7 @@ public class ExtensionDirectory extends 
StackDefinitionDirectory {
     if (subDirs.contains(ServiceDirectory.SERVICES_FOLDER_NAME)) {
       String servicesDir = getAbsolutePath() + File.separator + 
ServiceDirectory.SERVICES_FOLDER_NAME;
       File baseServiceDir = new File(servicesDir);
-      File[] serviceFolders = 
baseServiceDir.listFiles(AmbariMetaInfo.FILENAME_FILTER);
+      File[] serviceFolders = 
baseServiceDir.listFiles(StackDirectory.FILENAME_FILTER);
       if (serviceFolders != null) {
         for (File d : serviceFolders) {
           if (d.isDirectory()) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java
index abad7ed..ae59b3f 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceDirectory.java
@@ -24,7 +24,6 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.stack.ServiceMetainfoXml;
 import org.apache.ambari.server.state.stack.StackRoleCommandOrder;
@@ -257,13 +256,13 @@ public abstract class ServiceDirectory extends 
StackDefinitionDirectory {
     calculateDirectories(getStack(), getService());
     parseMetaInfoFile();
 
-    File af = new File(directory, AmbariMetaInfo.SERVICE_ALERT_FILE_NAME);
+    File af = new File(directory, StackDirectory.SERVICE_ALERT_FILE_NAME);
     alertsFile = af.exists() ? af : null;
 
-    File kdf = new File(directory, 
AmbariMetaInfo.KERBEROS_DESCRIPTOR_FILE_NAME);
+    File kdf = new File(directory, 
StackDirectory.KERBEROS_DESCRIPTOR_FILE_NAME);
     kerberosDescriptorFile = kdf.exists() ? kdf : null;
 
-    File rco = new File(directory, AmbariMetaInfo.RCO_FILE_NAME);
+    File rco = new File(directory, StackDirectory.RCO_FILE_NAME);
     if (rco.exists()) {
       rcoFile = rco;
       parseRoleCommandOrder();
@@ -279,13 +278,10 @@ public abstract class ServiceDirectory extends 
StackDefinitionDirectory {
       }
     }
 
-    File advFile = new File(directory, 
AmbariMetaInfo.SERVICE_ADVISOR_FILE_NAME);
+    File advFile = new File(directory, 
StackDirectory.SERVICE_ADVISOR_FILE_NAME);
     advisorFile = advFile.exists() ? advFile : null;
 
-    File themeFile = new File(directory, 
AmbariMetaInfo.SERVICE_THEME_FILE_NAME);
-    this.themeFile = themeFile.exists() ? themeFile : null;
-
-    File checksFile = new File(directory, 
AmbariMetaInfo.SERVICE_THEME_FILE_NAME);
+    File themeFile = new File(directory, 
StackDirectory.SERVICE_THEME_FILE_NAME);
     this.themeFile = themeFile.exists() ? themeFile : null;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/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 74120b6..3b3d52c 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
@@ -405,7 +405,7 @@ public class ServiceModule extends 
BaseModule<ServiceModule, ServiceInfo> implem
    */
   private void populateConfigurationModules() {
     ConfigurationDirectory configDirectory = 
serviceDirectory.getConfigurationDirectory(
-        serviceInfo.getConfigDir(), 
AmbariMetaInfo.SERVICE_PROPERTIES_FOLDER_NAME);
+        serviceInfo.getConfigDir(), 
StackDirectory.SERVICE_PROPERTIES_FOLDER_NAME);
 
     if (configDirectory != null) {
       for (ConfigurationModule config : 
configDirectory.getConfigurationModules()) {
@@ -438,7 +438,7 @@ public class ServiceModule extends 
BaseModule<ServiceModule, ServiceInfo> implem
   private void populateThemeModules() {
 
     if (serviceInfo.getThemesDir() == null) {
-      serviceInfo.setThemesDir(AmbariMetaInfo.SERVICE_THEMES_FOLDER_NAME);
+      serviceInfo.setThemesDir(StackDirectory.SERVICE_THEMES_FOLDER_NAME);
     }
 
     String themesDir = serviceDirectory.getAbsolutePath() + File.separator + 
serviceInfo.getThemesDir();
@@ -482,7 +482,7 @@ public class ServiceModule extends 
BaseModule<ServiceModule, ServiceInfo> implem
 
   private void populateQuickLinksConfigurationModules(){
     if (serviceInfo.getQuickLinksConfigurationsDir() == null) {
-      
serviceInfo.setQuickLinksConfigurationsDir(AmbariMetaInfo.SERVICE_QUICKLINKS_CONFIGURATIONS_FOLDER_NAME);
+      
serviceInfo.setQuickLinksConfigurationsDir(StackDirectory.SERVICE_QUICKLINKS_CONFIGURATIONS_FOLDER_NAME);
     }
 
     String quickLinksConfigurationsDir = serviceDirectory.getAbsolutePath() + 
File.separator + serviceInfo.getQuickLinksConfigurationsDir();

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java
index 23fd0a9..0e59c95 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.stack;
 
 import java.io.File;
+import java.io.FilenameFilter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -28,7 +29,6 @@ import java.util.HashSet;
 import java.util.Map;
 
 import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.state.stack.ConfigUpgradePack;
 import org.apache.ambari.server.state.stack.RepositoryXml;
 import org.apache.ambari.server.state.stack.StackMetainfoXml;
@@ -47,6 +47,31 @@ import org.slf4j.LoggerFactory;
 //todo: Currently some are relative and some are absolute.
 //todo: Current values were dictated by the StackInfo expectations.
 public class StackDirectory extends StackDefinitionDirectory {
+  public static final String SERVICE_CONFIG_FOLDER_NAME = "configuration";
+  public static final String SERVICE_PROPERTIES_FOLDER_NAME = "properties";
+  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";
+  public static final String SERVICE_ALERT_FILE_NAME = "alerts.json";
+  public static final String SERVICE_ADVISOR_FILE_NAME = "service_advisor.py";
+  /**
+   * The filename for a Kerberos descriptor file at either the stack or 
service level
+   */
+  public static final String KERBEROS_DESCRIPTOR_FILE_NAME = "kerberos.json";
+  /**
+   * The filename for a Widgets descriptor file at either the stack or service 
level
+   */
+  public static final String WIDGETS_DESCRIPTOR_FILE_NAME = "widgets.json";
+  /**
+   * The filename for a Kerberos descriptor preconfigure file at either the 
stack or service level
+   */
+  public static final String KERBEROS_DESCRIPTOR_PRECONFIGURE_FILE_NAME = 
"kerberos_preconfigure.json";
+  /**
+   * Filename for theme file at service layer
+   */
+  public static final String SERVICE_THEME_FILE_NAME = "theme.json";
   /**
    * hooks directory path
    */
@@ -68,7 +93,12 @@ public class StackDirectory extends StackDefinitionDirectory 
{
   private String kerberosDescriptorFilePath;
 
   /**
-   * kerberos descriptor file path
+   * kerberos descriptor (preconfigure) file path
+   */
+  private String kerberosDescriptorPreconfigureFilePath;
+
+  /**
+   * widgets descriptor file path
    */
   private String widgetsDescriptorFilePath;
 
@@ -116,6 +146,13 @@ public class StackDirectory extends 
StackDefinitionDirectory {
    * name of the hooks directory
    */
   public static final String HOOKS_FOLDER_NAME = "hooks";
+  public static final FilenameFilter FILENAME_FILTER = new FilenameFilter() {
+    @Override
+    public boolean accept(File dir, String s) {
+      return !(s.equals(".svn") || s.equals(".git") ||
+          s.equals(HOOKS_FOLDER_NAME));
+    }
+  };
 
   /**
    * repository directory name
@@ -151,7 +188,7 @@ public class StackDirectory extends 
StackDefinitionDirectory {
   /**
    * Constructor.
    *
-   * @param directory  stack directory
+   * @param directory stack directory
    * @throws AmbariException if unable to parse the stack directory
    */
   public StackDirectory(String directory) throws AmbariException {
@@ -205,6 +242,15 @@ public class StackDirectory extends 
StackDefinitionDirectory {
   }
 
   /**
+   * Obtain the path to the (stack-level) Kerberos descriptor 
pre-configuration file
+   *
+   * @return the path to the (stack-level) Kerberos descriptor 
pre-configuration file
+   */
+  public String getKerberosDescriptorPreconfigureFilePath() {
+    return kerberosDescriptorPreconfigureFilePath;
+  }
+
+  /**
    * Obtain the path to the (stack-level) widgets descriptor file
    *
    * @return the path to the (stack-level) widgets descriptor file
@@ -289,19 +335,24 @@ public class StackDirectory extends 
StackDefinitionDirectory {
       LOG.debug("Hooks folder {}{}" + HOOKS_FOLDER_NAME + " does not exist", 
getAbsolutePath(), File.separator);
     }
 
-    if (subDirs.contains(AmbariMetaInfo.RCO_FILE_NAME)) {
+    if (subDirs.contains(RCO_FILE_NAME)) {
       // rcoFile is expected to be absolute
-      rcoFilePath = getAbsolutePath() + File.separator + 
AmbariMetaInfo.RCO_FILE_NAME;
+      rcoFilePath = getAbsolutePath() + File.separator + RCO_FILE_NAME;
     }
 
 
-    if (subDirs.contains(AmbariMetaInfo.KERBEROS_DESCRIPTOR_FILE_NAME)) {
+    if (subDirs.contains(KERBEROS_DESCRIPTOR_FILE_NAME)) {
       // kerberosDescriptorFilePath is expected to be absolute
-      kerberosDescriptorFilePath = getAbsolutePath() + File.separator + 
AmbariMetaInfo.KERBEROS_DESCRIPTOR_FILE_NAME;
+      kerberosDescriptorFilePath = getAbsolutePath() + File.separator + 
KERBEROS_DESCRIPTOR_FILE_NAME;
+    }
+
+    if (subDirs.contains(KERBEROS_DESCRIPTOR_PRECONFIGURE_FILE_NAME)) {
+      // kerberosDescriptorPreconfigureFilePath is expected to be absolute
+      kerberosDescriptorPreconfigureFilePath = getAbsolutePath() + 
File.separator + KERBEROS_DESCRIPTOR_PRECONFIGURE_FILE_NAME;
     }
 
-    if (subDirs.contains(AmbariMetaInfo.WIDGETS_DESCRIPTOR_FILE_NAME)) {
-      widgetsDescriptorFilePath = getAbsolutePath() + File.separator + 
AmbariMetaInfo.WIDGETS_DESCRIPTOR_FILE_NAME;
+    if (subDirs.contains(WIDGETS_DESCRIPTOR_FILE_NAME)) {
+      widgetsDescriptorFilePath = getAbsolutePath() + File.separator + 
WIDGETS_DESCRIPTOR_FILE_NAME;
     }
 
     parseUpgradePacks(subDirs);
@@ -350,7 +401,7 @@ public class StackDirectory extends 
StackDefinitionDirectory {
         metaInfoXml = new StackMetainfoXml();
         metaInfoXml.setValid(false);
         String msg = "Unable to parse stack metainfo.xml file at location: " +
-                     stackMetaInfoFile.getAbsolutePath();
+            stackMetaInfoFile.getAbsolutePath();
         metaInfoXml.addError(msg);
         LOG.warn(msg);
       }
@@ -360,8 +411,8 @@ public class StackDirectory extends 
StackDefinitionDirectory {
   /**
    * Parse the stacks service directories.
    *
-   * @param subDirs  stack sub directories
-   * @throws AmbariException  if unable to parse the service directories
+   * @param subDirs stack sub directories
+   * @throws AmbariException if unable to parse the service directories
    */
   private void parseServiceDirectories(Collection<String> subDirs) throws 
AmbariException {
     Collection<ServiceDirectory> dirs = new HashSet<>();
@@ -369,7 +420,7 @@ public class StackDirectory extends 
StackDefinitionDirectory {
     if (subDirs.contains(ServiceDirectory.SERVICES_FOLDER_NAME)) {
       String servicesDir = getAbsolutePath() + File.separator + 
ServiceDirectory.SERVICES_FOLDER_NAME;
       File baseServiceDir = new File(servicesDir);
-      File[] serviceFolders = 
baseServiceDir.listFiles(AmbariMetaInfo.FILENAME_FILTER);
+      File[] serviceFolders = baseServiceDir.listFiles(FILENAME_FILTER);
       if (serviceFolders != null) {
         for (File d : serviceFolders) {
           if (d.isDirectory()) {
@@ -411,12 +462,10 @@ public class StackDirectory extends 
StackDefinitionDirectory {
           if 
(upgradeFile.getName().toLowerCase().startsWith(CONFIG_UPGRADE_XML_FILENAME_PREFIX))
 {
             if (configUpgradePack == null) {
               configUpgradePack = parseConfigUpgradePack(upgradeFile);
-            }
-            else { // If user messed things up with lower/upper case filenames
+            } else { // If user messed things up with lower/upper case 
filenames
               throw new AmbariException(String.format("There are multiple 
files with name like %s" + upgradeFile.getAbsolutePath()));
             }
-          }
-          else {
+          } else {
             String upgradePackName = 
FilenameUtils.removeExtension(upgradeFile.getName());
             UpgradePack pack = parseUpgradePack(upgradePackName, upgradeFile);
             pack.setName(upgradePackName);
@@ -449,8 +498,7 @@ public class StackDirectory extends 
StackDefinitionDirectory {
     try {
       pack = unmarshaller.unmarshal(UpgradePack.class, upgradeFile);
       pack.setName(packName);
-    }
-    catch (Exception e) {
+    } catch (Exception e) {
       if (upgradeFile == null) {
         throw new AmbariException("Null upgrade pack");
       }
@@ -463,8 +511,7 @@ public class StackDirectory extends 
StackDefinitionDirectory {
     ConfigUpgradePack pack = null;
     try {
       pack = unmarshaller.unmarshal(ConfigUpgradePack.class, upgradeFile);
-    }
-    catch (Exception e) {
+    } catch (Exception e) {
       if (upgradeFile == null) {
         throw new AmbariException("Null config upgrade pack");
       }
@@ -480,7 +527,8 @@ public class StackDirectory extends 
StackDefinitionDirectory {
     HashMap<String, Object> result = null;
     ObjectMapper mapper = new ObjectMapper();
     try {
-      TypeReference<Map<String, Object>> rcoElementTypeReference = new 
TypeReference<Map<String, Object>>() {};
+      TypeReference<Map<String, Object>> rcoElementTypeReference = new 
TypeReference<Map<String, Object>>() {
+      };
       if (rcoFilePath != null) {
         File file = new File(rcoFilePath);
         result = mapper.readValue(file, rcoElementTypeReference);

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java
index 245e623..b11ecab 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackManager.java
@@ -35,7 +35,6 @@ import javax.xml.validation.SchemaFactory;
 import javax.xml.validation.Validator;
 
 import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.AmbariManagementHelper;
 import org.apache.ambari.server.metadata.ActionMetadata;
@@ -564,12 +563,12 @@ public class StackManager {
     Map<String, ServiceModule> commonServiceModules = new HashMap<>();
 
     if(commonServicesRoot != null) {
-      File[] commonServiceFiles = 
commonServicesRoot.listFiles(AmbariMetaInfo.FILENAME_FILTER);
+      File[] commonServiceFiles = 
commonServicesRoot.listFiles(StackDirectory.FILENAME_FILTER);
       for (File commonService : commonServiceFiles) {
         if (commonService.isFile()) {
           continue;
         }
-        for (File serviceFolder : 
commonService.listFiles(AmbariMetaInfo.FILENAME_FILTER)) {
+        for (File serviceFolder : 
commonService.listFiles(StackDirectory.FILENAME_FILTER)) {
           String serviceName = serviceFolder.getParentFile().getName();
           String serviceVersion = serviceFolder.getName();
           ServiceDirectory serviceDirectory = new 
CommonServiceDirectory(serviceFolder.getPath());
@@ -606,12 +605,12 @@ public class StackManager {
   private Map<String, StackModule> parseStackDirectory(File stackRoot) throws 
AmbariException {
     Map<String, StackModule> stackModules = new HashMap<>();
 
-    File[] stackFiles = stackRoot.listFiles(AmbariMetaInfo.FILENAME_FILTER);
+    File[] stackFiles = stackRoot.listFiles(StackDirectory.FILENAME_FILTER);
     for (File stack : stackFiles) {
       if (stack.isFile()) {
         continue;
       }
-      for (File stackFolder : stack.listFiles(AmbariMetaInfo.FILENAME_FILTER)) 
{
+      for (File stackFolder : stack.listFiles(StackDirectory.FILENAME_FILTER)) 
{
         if (stackFolder.isFile()) {
           continue;
         }
@@ -652,12 +651,12 @@ public class StackManager {
     if (extensionRoot == null || !extensionRoot.exists())
       return extensionModules;
 
-    File[] extensionFiles = 
extensionRoot.listFiles(AmbariMetaInfo.FILENAME_FILTER);
+    File[] extensionFiles = 
extensionRoot.listFiles(StackDirectory.FILENAME_FILTER);
     for (File extensionNameFolder : extensionFiles) {
       if (extensionNameFolder.isFile()) {
         continue;
       }
-      for (File extensionVersionFolder : 
extensionNameFolder.listFiles(AmbariMetaInfo.FILENAME_FILTER)) {
+      for (File extensionVersionFolder : 
extensionNameFolder.listFiles(StackDirectory.FILENAME_FILTER)) {
         if (extensionVersionFolder.isFile()) {
           continue;
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
index ff1d378..3688727 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java
@@ -30,7 +30,6 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.state.BulkCommandDefinition;
 import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.ConfigHelper;
@@ -292,6 +291,11 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
       
stackInfo.setKerberosDescriptorFileLocation(parentStack.getModuleInfo().getKerberosDescriptorFileLocation());
     }
 
+    // grab stack level kerberos_preconfigure.json from parent stack
+    if (stackInfo.getKerberosDescriptorPreConfigurationFileLocation() == null) 
{
+      
stackInfo.setKerberosDescriptorPreConfigurationFileLocation(parentStack.getModuleInfo().getKerberosDescriptorPreConfigurationFileLocation());
+    }
+
     if (stackInfo.getWidgetsDescriptorFileLocation() == null) {
       
stackInfo.setWidgetsDescriptorFileLocation(parentStack.getModuleInfo().getWidgetsDescriptorFileLocation());
     }
@@ -571,6 +575,7 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
       stackInfo.setStackHooksFolder(stackDirectory.getHooksDir());
       stackInfo.setRcoFileLocation(stackDirectory.getRcoFilePath());
       
stackInfo.setKerberosDescriptorFileLocation(stackDirectory.getKerberosDescriptorFilePath());
+      
stackInfo.setKerberosDescriptorPreConfigurationFileLocation(stackDirectory.getKerberosDescriptorPreconfigureFilePath());
       
stackInfo.setWidgetsDescriptorFileLocation(stackDirectory.getWidgetsDescriptorFilePath());
       stackInfo.setUpgradesFolder(stackDirectory.getUpgradesDir());
       stackInfo.setUpgradePacks(stackDirectory.getUpgradePacks());
@@ -652,7 +657,7 @@ public class StackModule extends BaseModule<StackModule, 
StackInfo> implements V
   private void populateConfigurationModules() {
     //todo: can't exclude types in stack config
     ConfigurationDirectory configDirectory = 
stackDirectory.getConfigurationDirectory(
-        AmbariMetaInfo.SERVICE_CONFIG_FOLDER_NAME, 
AmbariMetaInfo.SERVICE_PROPERTIES_FOLDER_NAME);
+        StackDirectory.SERVICE_CONFIG_FOLDER_NAME, 
StackDirectory.SERVICE_PROPERTIES_FOLDER_NAME);
 
     if (configDirectory != null) {
       for (ConfigurationModule config : 
configDirectory.getConfigurationModules()) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java 
b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
index cb98dd2..bb7fcbe 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigHelper.java
@@ -36,6 +36,7 @@ import 
org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
 import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity;
+import org.apache.ambari.server.stack.StackDirectory;
 import org.apache.ambari.server.state.PropertyInfo.PropertyType;
 import org.apache.ambari.server.state.configgroup.ConfigGroup;
 import org.apache.ambari.server.utils.SecretReference;
@@ -1409,7 +1410,7 @@ public class ConfigHelper {
   }
 
   public static String fileNameToConfigType(String filename) {
-    int extIndex = 
filename.indexOf(AmbariMetaInfo.SERVICE_CONFIG_FILE_NAME_POSTFIX);
+    int extIndex = 
filename.indexOf(StackDirectory.SERVICE_CONFIG_FILE_NAME_POSTFIX);
     return filename.substring(0, extIndex);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/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 573a197..ef18bd9 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
@@ -41,6 +41,7 @@ import javax.xml.bind.annotation.XmlEnumValue;
 import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.stack.StackDirectory;
 import org.apache.ambari.server.stack.Validable;
 import org.apache.ambari.server.state.stack.MetricDefinition;
 import org.apache.ambari.server.state.stack.StackRoleCommandOrder;
@@ -133,10 +134,10 @@ public class ServiceInfo implements Validable{
   private String parent;
 
   @XmlElement(name = "widgetsFileName")
-  private String widgetsFileName = AmbariMetaInfo.WIDGETS_DESCRIPTOR_FILE_NAME;
+  private String widgetsFileName = StackDirectory.WIDGETS_DESCRIPTOR_FILE_NAME;
 
   @XmlElement(name = "metricsFileName")
-  private String metricsFileName = AmbariMetaInfo.SERVICE_METRIC_FILE_NAME;
+  private String metricsFileName = StackDirectory.SERVICE_METRIC_FILE_NAME;
 
   @XmlTransient
   private volatile Map<String, PropertyInfo> requiredProperties;
@@ -233,11 +234,11 @@ public class ServiceInfo implements Validable{
 
   @JsonIgnore
   @XmlElement(name="configuration-dir")
-  private String configDir = AmbariMetaInfo.SERVICE_CONFIG_FOLDER_NAME;
+  private String configDir = StackDirectory.SERVICE_CONFIG_FOLDER_NAME;
 
   @JsonIgnore
   @XmlElement(name = "themes-dir")
-  private String themesDir = AmbariMetaInfo.SERVICE_THEMES_FOLDER_NAME;
+  private String themesDir = StackDirectory.SERVICE_THEMES_FOLDER_NAME;
 
   @JsonIgnore
   @XmlElementWrapper(name = "themes")
@@ -249,7 +250,7 @@ public class ServiceInfo implements Validable{
 
   @JsonIgnore
   @XmlElement(name = "quickLinksConfigurations-dir")
-  private String quickLinksConfigurationsDir = 
AmbariMetaInfo.SERVICE_QUICKLINKS_CONFIGURATIONS_FOLDER_NAME;
+  private String quickLinksConfigurationsDir = 
StackDirectory.SERVICE_QUICKLINKS_CONFIGURATIONS_FOLDER_NAME;
 
   @JsonIgnore
   @XmlElementWrapper(name = "quickLinksConfigurations")

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java 
b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
index 350611d..6184b94 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java
@@ -52,6 +52,7 @@ public class StackInfo implements Comparable<StackInfo>, 
Validable {
   private boolean active;
   private String rcoFileLocation;
   private String kerberosDescriptorFileLocation;
+  private String kerberosDescriptorPreConfigurationFileLocation;
   private String widgetsDescriptorFileLocation;
   private List<RepositoryInfo> repositories;
   private Collection<ServiceInfo> services;
@@ -410,6 +411,25 @@ public class StackInfo implements Comparable<StackInfo>, 
Validable {
     this.kerberosDescriptorFileLocation = kerberosDescriptorFileLocation;
   }
 
+  /**
+   * Gets the path to the stack-level Kerberos descriptor pre-configuration 
file
+   *
+   * @return a String containing the path to the stack-level Kerberos 
descriptor pre-configuration file
+   */
+  public String getKerberosDescriptorPreConfigurationFileLocation() {
+    return kerberosDescriptorPreConfigurationFileLocation;
+  }
+
+  /**
+   * Sets the path to the stack-level Kerberos descriptor file
+   *
+   * @param kerberosDescriptorPreConfigurationFileLocation a String containing 
the path to the stack-level Kerberos
+   *                                                       descriptor file
+   */
+  public void setKerberosDescriptorPreConfigurationFileLocation(String 
kerberosDescriptorPreConfigurationFileLocation) {
+    this.kerberosDescriptorPreConfigurationFileLocation = 
kerberosDescriptorPreConfigurationFileLocation;
+  }
+
   public String getWidgetsDescriptorFileLocation() {
     return widgetsDescriptorFileLocation;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
index 7f53daa..0d1da9c 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
@@ -24,6 +24,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
+import org.apache.commons.lang.StringUtils;
+
 /**
  * AbstractKerberosDescriptor is the base class for all Kerberos*Descriptor 
and associated classes.
  * <p/>
@@ -154,6 +156,38 @@ public abstract class AbstractKerberosDescriptor {
   }
 
   /**
+   * Safely retrieves the requested value (converted to a Boolean) from the 
supplied Map
+   * <p/>
+   * The found value will be converted to a Boolean using {@link 
Boolean#valueOf(String)}.
+   * If not found, <code>null</code> will be returned
+   *
+   * @param map a Map containing the relevant data
+   * @param key a String declaring the item to retrieve
+   * @return a Boolean representing the requested data; or null if not found
+   * @see Boolean#valueOf(String)
+   * @see #getBooleanValue(Map, String, Boolean)
+   */
+  protected static Boolean getBooleanValue(Map<?, ?> map, String key) {
+    return getBooleanValue(map, key, null);
+  }
+
+  /**
+   * Safely retrieves the requested value (converted to a Boolean) from the 
supplied Map
+   * <p/>
+   * The found value will be converted to a Boolean using {@link 
Boolean#valueOf(String)}.
+   *
+   * @param map          a Map containing the relevant data
+   * @param key          a String declaring the item to retrieve
+   * @param defaultValue a Boolean value to return if the data is not found
+   * @return a Boolean representing the requested data; or the specified 
default value if not found
+   * @see Boolean#valueOf(String)
+   */
+  protected static Boolean getBooleanValue(Map<?, ?> map, String key, Boolean 
defaultValue) {
+    String value = getStringValue(map, key);
+    return (StringUtils.isEmpty(value)) ? defaultValue : 
Boolean.valueOf(value);
+  }
+
+  /**
    * Gets the requested AbstractKerberosDescriptor implementation using a type 
name and a relevant
    * descriptor name.
    * <p/>
@@ -192,7 +226,7 @@ public abstract class AbstractKerberosDescriptor {
     return list == null ? Collections.emptyList() : list;
   }
 
-  public static <K,V> Map<K,V> nullToEmpty(Map<K,V> collection) {
+  public static <K, V> Map<K, V> nullToEmpty(Map<K, V> collection) {
     return collection == null ? Collections.emptyMap() : collection;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
index eba1b3a..0eb3733 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
@@ -181,10 +181,11 @@ public class KerberosDescriptor extends 
AbstractKerberosDescriptorContainer {
   }
 
   /**
-   * Adds or replaces a KerberosServiceDescriptor
+   * Adds, replaces, or updates a KerberosServiceDescriptor
    * <p/>
-   * If a KerberosServiceDescriptor with the same name already exists in the 
services Map, it will
-   * be replaced; else a new entry will be made.
+   * If a KerberosServiceDescriptor with the same name does not exist in the 
services Map, a new
+   * entry will be added; else if it one already exists and 
<code>overwrite</code> is
+   * <code>true</code>, it will be replaced; else the exsting entry will be 
updated.
    *
    * @param service the KerberosServiceDescriptor to put
    */
@@ -197,13 +198,17 @@ public class KerberosDescriptor extends 
AbstractKerberosDescriptorContainer {
       }
 
       if (services == null) {
-        services = new TreeMap<>();
+        services = new TreeMap<String, KerberosServiceDescriptor>();
       }
 
-      services.put(name, service);
-
-      // Set the service's parent to this KerberosDescriptor
-      service.setParent(this);
+      KerberosServiceDescriptor existing = services.get(name);
+      if (existing == null) {
+        services.put(name, service);
+        // Set the service's parent to this KerberosDescriptor
+        service.setParent(this);
+      } else {
+        existing.update(service);
+      }
     }
   }
 
@@ -269,12 +274,7 @@ public class KerberosDescriptor extends 
AbstractKerberosDescriptorContainer {
       Map<String, KerberosServiceDescriptor> updatedServiceDescriptors = 
updates.getServices();
       if (updatedServiceDescriptors != null) {
         for (Map.Entry<String, KerberosServiceDescriptor> entry : 
updatedServiceDescriptors.entrySet()) {
-          KerberosServiceDescriptor existing = getService(entry.getKey());
-          if (existing == null) {
-            putService(entry.getValue());
-          } else {
-            existing.update(entry.getValue());
-          }
+          putService(entry.getValue());
         }
       }
 
@@ -425,17 +425,17 @@ public class KerberosDescriptor extends 
AbstractKerberosDescriptorContainer {
 
   /**
    * Get a map of principals, where the key is the principal path 
(SERVICE/COMPONENT/principal_name or SERVICE/principal_name) and the value is 
the principal.
-   *
+   * <p>
    * For example if the kerberos principal of the HISTORYSERVER is defined in 
the kerberos.json:
    * "name": "history_server_jhs",
-   *   "principal": {
-   *   "value": "jhs/_HOST@${realm}",
-   *   "type" : "service",
+   * "principal": {
+   * "value": "jhs/_HOST@${realm}",
+   * "type" : "service",
    * },
    * Then "jhs/_h...@example.com" will be put into the map under the 
"MAPREDUCE2/HISTORYSERVER/history_server_jhs" key.
    */
   public Map<String, String> principals() throws AmbariException {
-    Map<String,String> result = new HashMap<>();
+    Map<String, String> result = new HashMap<>();
     for (AbstractKerberosDescriptorContainer each : 
nullToEmpty(getChildContainers())) {
       if ((each instanceof KerberosServiceDescriptor)) {
         collectFromComponents(each.getName(), 
nullToEmpty(((KerberosServiceDescriptor) each).getComponents()).values(), 
result);
@@ -455,8 +455,8 @@ public class KerberosDescriptor extends 
AbstractKerberosDescriptorContainer {
     for (KerberosIdentityDescriptor each : identities) {
       if (each.getPrincipalDescriptor() != null && 
!each.getReferencedServiceName().isPresent() && 
!each.getName().startsWith("/")) {
         String path = StringUtils.isBlank(component)
-          ? String.format("%s/%s", service, each.getName())
-          : String.format("%s/%s/%s", service, component, each.getName());
+            ? String.format("%s/%s", service, each.getName())
+            : String.format("%s/%s/%s", service, component, each.getName());
         result.put(path, each.getPrincipalDescriptor().getName());
       }
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
index 771a23c..5da3399 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
@@ -24,24 +24,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
-/**
- * Represents information required to configure Kerberos for a particular 
service.
- * <p/>
- * The data map is expected to have the following properties:
- * <ul>
- * <li>name</li>
- * <li>components</li>
- * <li>identities</li>
- * <li>configurations</li>
- * </ul>
- * Example:
- * <pre>
- *  "name" => "SERVICE",
- *  "identities" => Collection&lt;Map&lt;String, Object&gt;&gt;
- *  "components" => Collection&lt;Map&lt;String, Object&gt;&gt;
- *  "configurations" => Collection&lt;Map&lt;String, Object&gt;&gt;
- * </pre>
- */
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
 
 /**
  * KerberosServiceDescriptor is an implementation of an 
AbstractKerberosDescriptorContainer that
@@ -107,6 +91,11 @@ public class KerberosServiceDescriptor extends 
AbstractKerberosDescriptorContain
   private Map<String, KerberosComponentDescriptor> components;
 
   /**
+   * A Boolean value indicating whether this service should be pre-configured 
(true) or not.
+   */
+  private Boolean preconfigure = null;
+
+  /**
    * Creates a new KerberosServiceDescriptor
    * <p/>
    * See {@link 
org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor} for the JSON
@@ -157,6 +146,8 @@ public class KerberosServiceDescriptor extends 
AbstractKerberosDescriptorContain
           }
         }
       }
+
+      setPreconfigure(getBooleanValue(data, "preconfigure"));
     }
   }
 
@@ -230,6 +221,24 @@ public class KerberosServiceDescriptor extends 
AbstractKerberosDescriptorContain
   }
 
   /**
+   * Indicate whether this service should be preconfigured when determining 
configurations.
+   *
+   * @return true, to preconfigure; false, otherwise
+   */
+  public boolean shouldPreconfigure() {
+    return Boolean.TRUE.equals(preconfigure);
+  }
+
+  /**
+   * Sets whether this service should be preconfigured when determining 
configurations or not.
+   *
+   * @param preconfigure true, to preconfigure; false, otherwise
+   */
+  public void setPreconfigure(Boolean preconfigure) {
+    this.preconfigure = preconfigure;
+  }
+
+  /**
    * Gets the requested AbstractKerberosDescriptor implementation using a type 
name and a relevant
    * descriptor name.
    * <p/>
@@ -269,41 +278,44 @@ public class KerberosServiceDescriptor extends 
AbstractKerberosDescriptorContain
       map.put(Type.COMPONENT.getDescriptorPluralName(), list);
     }
 
+    if (preconfigure != null) {
+      map.put("preProcess", preconfigure.toString());
+    }
+
     return map;
   }
 
   public List<KerberosIdentityDescriptor> getComponentIdentities(String 
componentName) {
     return getComponent(componentName) != null
-      ? nullToEmpty(getComponent(componentName).getIdentities())
-      : Collections.emptyList();
+        ? nullToEmpty(getComponent(componentName).getIdentities())
+        : Collections.emptyList();
   }
 
   @Override
   public int hashCode() {
-    return super.hashCode() +
-        ((getComponents() == null)
-            ? 0
-            : getComponents().hashCode());
+    return new HashCodeBuilder()
+        .appendSuper(super.hashCode())
+        .append(components)
+        .append(preconfigure)
+        .toHashCode();
   }
 
   @Override
   public boolean equals(Object object) {
-    if (object == null) {
-      return false;
-    } else if (object == this) {
+    if (object == this) {
       return true;
-    } else if (object.getClass() == KerberosServiceDescriptor.class) {
-      KerberosServiceDescriptor descriptor = (KerberosServiceDescriptor) 
object;
-      return super.equals(object) &&
-          (
-              (getComponents() == null)
-                  ? (descriptor.getComponents() == null)
-                  : getComponents().equals(descriptor.getComponents())
-          );
-    } else {
+    }
+
+    if (!(object instanceof KerberosServiceDescriptor)) {
       return false;
     }
-  }
 
+    KerberosServiceDescriptor that = (KerberosServiceDescriptor) object;
+    return new EqualsBuilder()
+        .appendSuper(super.equals(object))
+        .append(components, components)
+        .append(preconfigure, that.preconfigure)
+        .isEquals();
+  }
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
index 1f10d7e..a2e2f6f 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/AbstractUpgradeCatalog.java
@@ -783,7 +783,7 @@ public abstract class AbstractUpgradeCatalog implements 
UpgradeCatalog {
         comment = "can only take the first stack we find until we can support 
multiple with Kerberos")
     StackId stackId = getStackId(cluster);
 
-    KerberosDescriptor defaultDescriptor = 
ambariMetaInfo.getKerberosDescriptor(stackId.getStackName(), 
stackId.getStackVersion());
+    KerberosDescriptor defaultDescriptor = 
ambariMetaInfo.getKerberosDescriptor(stackId.getStackName(), 
stackId.getStackVersion(), false);
 
     // Get the User-set Kerberos Descriptor
     ArtifactDAO artifactDAO = injector.getInstance(ArtifactDAO.class);

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
 
b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
index e07e28e..0a08121 100644
--- 
a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
+++ 
b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
@@ -393,4 +393,31 @@
     </value-attributes>
     <on-ambari-upgrade add="true"/>
   </property>
+  <property>
+    <name>preconfigure_services</name>
+    <display-name>Pre-configure services</display-name>
+    <description>
+      Indicates whether to pre-configure services or not. If pre-configuring 
services, indicates
+      whether to pre-configure all or those explicitly flagged to be 
pre-configured.  Possible values
+      are DEFAULT, NONE, or ALL
+    </description>
+    <value>DEFAULT</value>
+    <value-attributes>
+      <overridable>false</overridable>
+      <type>value-list</type>
+      <selection-cardinality>1</selection-cardinality>
+      <entries>
+        <entry>
+          <value>NONE</value>
+        </entry>
+        <entry>
+          <value>DEFAULT</value>
+        </entry>
+        <entry>
+          <value>ALL</value>
+        </entry>
+      </entries>
+    </value-attributes>
+    <on-ambari-upgrade add="true"/>
+  </property>
 </configuration>

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/resources/stacks/HDP/2.6/kerberos_preconfigure.json
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/stacks/HDP/2.6/kerberos_preconfigure.json 
b/ambari-server/src/main/resources/stacks/HDP/2.6/kerberos_preconfigure.json
new file mode 100644
index 0000000..c9d8c91
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.6/kerberos_preconfigure.json
@@ -0,0 +1,24 @@
+{
+  "services": [
+    {
+      "name": "KNOX",
+      "preconfigure" : true
+    },
+    {
+      "name": "BEACON",
+      "preconfigure" : true,
+      "configurations": {
+      },
+      "identities": [
+        {
+          "name": "beacon_server",
+          "principal": {
+            "value": "beacon/_HOST@${realm}",
+            "type": "service",
+            "local_username": "beacon"
+          }
+        }
+      ]
+    }
+  ]
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java
index 6be9f32..b47a25d 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java
@@ -178,7 +178,7 @@ public class ClusterBlueprintRendererTest {
     expect(clusters.getCluster("clusterName")).andReturn(cluster).anyTimes();
     
expect(controller.getKerberosHelper()).andReturn(kerberosHelper).anyTimes();
     expect(controller.getClusters()).andReturn(clusters).anyTimes();
-    
expect(kerberosHelper.getKerberosDescriptor(cluster)).andReturn(kerberosDescriptor).anyTimes();
+    expect(kerberosHelper.getKerberosDescriptor(cluster, 
false)).andReturn(kerberosDescriptor).anyTimes();
     Set<String> properties = new HashSet<>();
     properties.add("core-site/hadoop.security.auth_to_local");
     
expect(kerberosDescriptor.getAllAuthToLocalProperties()).andReturn(properties).anyTimes();

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
index 9ea0ae1..2b88bf0 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
@@ -1838,8 +1838,30 @@ public class AmbariMetaInfoTest {
   }
 
   @Test
+  public void testReadKerberosDescriptorFromFile() throws AmbariException {
+    StackInfo stackInfo = metaInfo.getStack(STACK_NAME_HDP, "2.0.8");
+    String path = stackInfo.getKerberosDescriptorFileLocation();
+    KerberosDescriptor descriptor = 
metaInfo.readKerberosDescriptorFromFile(path);
+
+    Assert.assertNotNull(descriptor);
+    Assert.assertNotNull(descriptor.getProperties());
+    Assert.assertEquals(3, descriptor.getProperties().size());
+
+    Assert.assertNotNull(descriptor.getIdentities());
+    Assert.assertEquals(1, descriptor.getIdentities().size());
+    Assert.assertEquals("spnego", descriptor.getIdentities().get(0).getName());
+
+    Assert.assertNotNull(descriptor.getConfigurations());
+    Assert.assertEquals(1, descriptor.getConfigurations().size());
+    Assert.assertNotNull(descriptor.getConfigurations().get("core-site"));
+    Assert.assertNotNull(descriptor.getConfiguration("core-site"));
+
+    Assert.assertNull(descriptor.getServices());
+  }
+
+  @Test
   public void testGetKerberosDescriptor() throws AmbariException {
-    KerberosDescriptor descriptor = 
metaInfo.getKerberosDescriptor(STACK_NAME_HDP, "2.0.8");
+    KerberosDescriptor descriptor = 
metaInfo.getKerberosDescriptor(STACK_NAME_HDP, "2.0.8", false);
 
     Assert.assertNotNull(descriptor);
     Assert.assertNotNull(descriptor.getProperties());
@@ -1858,6 +1880,37 @@ public class AmbariMetaInfoTest {
     Assert.assertEquals(1, descriptor.getServices().size());
     Assert.assertNotNull(descriptor.getServices().get("HDFS"));
     Assert.assertNotNull(descriptor.getService("HDFS"));
+    Assert.assertFalse(descriptor.getService("HDFS").shouldPreconfigure());
+  }
+
+  @Test
+  public void testGetKerberosDescriptorWithPreconfigure() throws 
AmbariException {
+    KerberosDescriptor descriptor = 
metaInfo.getKerberosDescriptor(STACK_NAME_HDP, "2.0.8", true);
+
+    Assert.assertNotNull(descriptor);
+    Assert.assertNotNull(descriptor.getProperties());
+    Assert.assertEquals(3, descriptor.getProperties().size());
+
+    Assert.assertNotNull(descriptor.getIdentities());
+    Assert.assertEquals(1, descriptor.getIdentities().size());
+    Assert.assertEquals("spnego", descriptor.getIdentities().get(0).getName());
+
+    Assert.assertNotNull(descriptor.getConfigurations());
+    Assert.assertEquals(1, descriptor.getConfigurations().size());
+    Assert.assertNotNull(descriptor.getConfigurations().get("core-site"));
+    Assert.assertNotNull(descriptor.getConfiguration("core-site"));
+
+    Assert.assertNotNull(descriptor.getServices());
+    Assert.assertEquals(2, descriptor.getServices().size());
+    Assert.assertNotNull(descriptor.getServices().get("HDFS"));
+    Assert.assertNotNull(descriptor.getService("HDFS"));
+    Assert.assertTrue(descriptor.getService("HDFS").shouldPreconfigure());
+    Assert.assertNotNull(descriptor.getServices().get("HDFS"));
+    Assert.assertNotNull(descriptor.getService("HDFS"));
+    Assert.assertTrue(descriptor.getService("HDFS").shouldPreconfigure());
+    Assert.assertNotNull(descriptor.getServices().get("NEW_SERVICE"));
+    Assert.assertNotNull(descriptor.getService("NEW_SERVICE"));
+    
Assert.assertTrue(descriptor.getService("NEW_SERVICE").shouldPreconfigure());
   }
 
   private File getStackRootTmp(String buildDir) {

Reply via email to