ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lpus...@apache.org
Subject [14/50] [abbrv] ambari git commit: AMBARI-21602. Pre-configure services when Kerberos is enabled to reduce number of core service restarts when services are added (rlevas)
Date Tue, 29 Aug 2017 13:25:17 GMT
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/_HOST@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) {


Mime
View raw message