ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rle...@apache.org
Subject [3/4] 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 Thu, 24 Aug 2017 21:01:25 GMT
http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
index 8d0fd0f..d86433f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
@@ -24,6 +24,7 @@ import java.io.File;
 import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -35,6 +36,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.TreeSet;
 import java.util.regex.Matcher;
 
 import org.apache.ambari.annotations.Experimental;
@@ -48,6 +50,7 @@ import org.apache.ambari.server.actionmanager.RequestFactory;
 import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.actionmanager.StageFactory;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorHelper;
 import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
 import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
@@ -92,14 +95,17 @@ import org.apache.ambari.server.stageplanner.RoleGraph;
 import org.apache.ambari.server.stageplanner.RoleGraphFactory;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.ComponentInfo;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigHelper;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.HostState;
+import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.state.SecurityType;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.ValueAttributesInfo;
@@ -359,16 +365,16 @@ public class KerberosHelperImpl implements KerberosHelper {
     RoleCommandOrder roleCommandOrder = ambariManagementController.getRoleCommandOrder(cluster);
     DeleteIdentityHandler handler = new DeleteIdentityHandler(customCommandExecutionHelper, configuration.getDefaultServerTaskTimeout(), stageFactory, ambariManagementController);
     DeleteIdentityHandler.CommandParams commandParameters = new DeleteIdentityHandler.CommandParams(
-      components,
-      identities,
-      ambariManagementController.getAuthName(),
-      dataDirectory,
-      kerberosDetails.getDefaultRealm(),
-      kerberosDetails.getKdcType());
+        components,
+        identities,
+        ambariManagementController.getAuthName(),
+        dataDirectory,
+        kerberosDetails.getDefaultRealm(),
+        kerberosDetails.getKdcType());
     OrderedRequestStageContainer stageContainer = new OrderedRequestStageContainer(
-      roleGraphFactory,
-      roleCommandOrder,
-      new RequestStageContainer(actionManager.getNextRequestId(), null, requestFactory, actionManager));
+        roleGraphFactory,
+        roleCommandOrder,
+        new RequestStageContainer(actionManager.getNextRequestId(), null, requestFactory, actionManager));
     handler.addDeleteIdentityStages(cluster, stageContainer, commandParameters, kerberosDetails.manageIdentities());
     stageContainer.getRequestStageContainer().persist();
   }
@@ -376,45 +382,43 @@ public class KerberosHelperImpl implements KerberosHelper {
   @Override
   public void configureServices(Cluster cluster, Map<String, Collection<String>> serviceFilter)
       throws AmbariException, KerberosInvalidConfigurationException {
-    Map<String, Map<String, String>> existingConfigurations = calculateExistingConfigurations(cluster, null);
-    Map<String, Set<String>> installedServices = new HashMap<>();
-    Set<String> previouslyExistingServices = new HashSet<>();
-
-    // Calculate the map of installed services to installed components
-    Map<String, Service> clusterServices = cluster.getServices();
-    if(clusterServices != null) {
-      for (Service clusterService : clusterServices.values()) {
-        Set<String> installedComponents = installedServices.get(clusterService.getName());
-        if (installedComponents == null) {
-          installedComponents = new HashSet<>();
-          installedServices.put(clusterService.getName(), installedComponents);
-        }
+    final Map<String, Set<String>> installedServices = new HashMap<>();
+    final Set<String> previouslyExistingServices = new HashSet<>();
+
+    // Calculate the map of installed services to installed components.
+    // We can create the map in the "shouldIncludeCommand" Command to avoid having to iterate
+    // over the returned ServiceComponentHost List.
+    getServiceComponentHosts(cluster,
+        new Command<Boolean, ServiceComponentHost>() {
+          @Override
+          public Boolean invoke(ServiceComponentHost sch) throws AmbariException {
+            if (sch != null) {
+              String serviceName = sch.getServiceName();
+
+              Set<String> installedComponents = installedServices.get(serviceName);
+              if (installedComponents == null) {
+                installedComponents = new HashSet<>();
+                installedServices.put(serviceName, installedComponents);
+              }
+              installedComponents.add(sch.getServiceComponentName());
 
-        Map<String, ServiceComponent> clusterServiceComponents = clusterService.getServiceComponents();
-        if (clusterServiceComponents != null) {
-          for (ServiceComponent clusterServiceComponent : clusterServiceComponents.values()) {
-            installedComponents.add(clusterServiceComponent.getName());
-
-            // Determine if this component was PREVIOUSLY installed, which implies that its containing service was PREVIOUSLY installed
-            if (!previouslyExistingServices.contains(clusterService.getName())) {
-              Map<String, ServiceComponentHost> clusterServiceComponentHosts = clusterServiceComponent.getServiceComponentHosts();
-              if (clusterServiceComponentHosts != null) {
-                for (ServiceComponentHost clusterServiceComponentHost : clusterServiceComponentHosts.values()) {
-                  if (PREVIOUSLY_INSTALLED_STATES.contains(clusterServiceComponentHost.getState())) {
-                    previouslyExistingServices.add(clusterService.getName());
-                    break;
-                  }
-                }
+              // Determine if this component was PREVIOUSLY installed, which implies that its containing service was PREVIOUSLY installed
+              if (!previouslyExistingServices.contains(serviceName) && PREVIOUSLY_INSTALLED_STATES.contains(sch.getState())) {
+                previouslyExistingServices.add(serviceName);
               }
+
+              return true;
             }
+
+            return false;
           }
-        }
-      }
-    }
+        });
 
+    Map<String, Map<String, String>> existingConfigurations = calculateExistingConfigurations(cluster, null);
     Map<String, Map<String, String>> updates = getServiceConfigurationUpdates(cluster,
         existingConfigurations, installedServices, serviceFilter, previouslyExistingServices, true, true);
 
+    // Store the updates...
     for (Map.Entry<String, Map<String, String>> entry : updates.entrySet()) {
       configHelper.updateConfigType(cluster, cluster.getDesiredStackVersion(),
           ambariManagementController, entry.getKey(), entry.getValue(), null,
@@ -434,7 +438,7 @@ public class KerberosHelperImpl implements KerberosHelper {
 
     Map<String, Map<String, String>> kerberosConfigurations = new HashMap<>();
     KerberosDetails kerberosDetails = getKerberosDetails(cluster, null);
-    KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster);
+    KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster, false);
 
     Map<String, String> kerberosDescriptorProperties = kerberosDescriptor.getProperties();
     Map<String, Map<String, String>> configurations = addAdditionalConfigurations(cluster,
@@ -442,10 +446,10 @@ public class KerberosHelperImpl implements KerberosHelper {
 
     Map<String, Set<String>> propertiesToIgnore = new HashMap<>();
 
-    // If Ambari is managing it own identities then add AMBARI to the set of installed servcie so
+    // If Ambari is managing it own identities then add AMBARI to the set of installed service so
     // that its Kerberos descriptor entries will be included.
-    if (createAmbariIdentities(existingConfigurations.get("kerberos-env"))) {
-      installedServices = new HashMap<>(installedServices);
+    if (createAmbariIdentities(existingConfigurations.get(KERBEROS_ENV))) {
+      installedServices = new HashMap<String, Set<String>>(installedServices);
       installedServices.put("AMBARI", Collections.singleton("AMBARI_SERVER"));
     }
 
@@ -482,7 +486,7 @@ public class KerberosHelperImpl implements KerberosHelper {
                   processIdentityConfigurations(identityConfigurations, kerberosConfigurations, configurations, propertiesToIgnore);
 
                   mergeConfigurations(kerberosConfigurations,
-                      componentDescriptor.getConfigurations(!servicePreviouslyExisted), configurations);
+                      componentDescriptor.getConfigurations(!servicePreviouslyExisted), configurations, null);
                 }
               }
             }
@@ -491,14 +495,134 @@ public class KerberosHelperImpl implements KerberosHelper {
       }
     }
 
-    setAuthToLocalRules(kerberosDescriptor, kerberosDetails.getDefaultRealm(), installedServices, configurations, kerberosConfigurations);
+    setAuthToLocalRules(cluster, kerberosDescriptor, kerberosDetails.getDefaultRealm(), installedServices, configurations, kerberosConfigurations, false);
 
     return (applyStackAdvisorUpdates)
         ? applyStackAdvisorUpdates(cluster, installedServices.keySet(), configurations, kerberosConfigurations, propertiesToIgnore,
-      new HashMap<>(), kerberosEnabled)
+        new HashMap<>(), kerberosEnabled)
         : kerberosConfigurations;
   }
 
+  /**
+   * Adds host assignments, recommended by the Stack Advisor, to the configuration map (clusterHostInfo)
+   * for the components specified in the component filter <code>componentFilter</code> (or all if the
+   * component filter is <code>null</code>).
+   *
+   * @param cluster         the cluster
+   * @param services        the relevant services to consider
+   * @param componentFilter the set of components to add to the clusterHostInfo structure
+   * @param configurations  the configurations map to update
+   * @throws AmbariException if an error occurs
+   */
+  private void applyStackAdvisorHostRecommendations(Cluster cluster,
+                                                    Set<String> services,
+                                                    Set<String> componentFilter,
+                                                    Map<String, Map<String, String>> configurations)
+      throws AmbariException {
+    StackId stackVersion = cluster.getCurrentStackVersion();
+    List<String> hostNames = new ArrayList<>();
+
+    Collection<Host> hosts = cluster.getHosts();
+    if (hosts != null) {
+      for (Host host : hosts) {
+        hostNames.add(host.getHostName());
+      }
+    }
+
+    StackAdvisorRequest request = StackAdvisorRequest.StackAdvisorRequestBuilder
+        .forStack(stackVersion.getStackName(), stackVersion.getStackVersion())
+        .forServices(services)
+        .forHosts(hostNames)
+        .withComponentHostsMap(cluster.getServiceComponentHostMap(null, services))
+        .ofType(StackAdvisorRequest.StackAdvisorRequestType.HOST_GROUPS)
+        .build();
+
+    try {
+      RecommendationResponse response = stackAdvisorHelper.recommend(request);
+
+      RecommendationResponse.Recommendation recommendation = (response == null) ? null : response.getRecommendations();
+      RecommendationResponse.Blueprint blueprint = (recommendation == null) ? null : recommendation.getBlueprint();
+      Set<RecommendationResponse.HostGroup> hostGroups = (blueprint == null) ? null : blueprint.getHostGroups();
+
+
+      if (hostGroups != null) {
+        RecommendationResponse.BlueprintClusterBinding blueprintBinding = recommendation.getBlueprintClusterBinding();
+        Map<String, RecommendationResponse.BindingHostGroup> bindingMap = new HashMap<>();
+        if (blueprintBinding != null) {
+          Set<RecommendationResponse.BindingHostGroup> bindingHostGroups = blueprintBinding.getHostGroups();
+          if (bindingHostGroups != null) {
+            for (RecommendationResponse.BindingHostGroup bindingHostGroup : bindingHostGroups) {
+              bindingMap.put(bindingHostGroup.getName(), bindingHostGroup);
+            }
+          }
+        }
+
+        // Get (and created if needed) the clusterHostInfo map
+        Map<String, String> clusterHostInfoMap = configurations.get("clusterHostInfo");
+        if (clusterHostInfoMap == null) {
+          clusterHostInfoMap = new HashMap<>();
+          configurations.put("clusterHostInfo", clusterHostInfoMap);
+        }
+
+        Map<String, String> componentToClusterInfoMap = StageUtils.getComponentToClusterInfoKeyMap();
+
+        // Iterate through the recommendations to find the recommended host assignments
+        for (RecommendationResponse.HostGroup hostGroup : hostGroups) {
+          Set<Map<String, String>> components = hostGroup.getComponents();
+
+          if (components != null) {
+            RecommendationResponse.BindingHostGroup binding = bindingMap.get(hostGroup.getName());
+
+            if (binding != null) {
+              Set<Map<String, String>> hostGroupHosts = binding.getHosts();
+
+              if (hostGroupHosts != null) {
+                for (Map<String, String> component : components) {
+                  String componentName = component.get("name");
+
+                  // If the component filter is null or the current component is found in the filter,
+                  // include it in the map
+                  if ((componentFilter == null) || componentFilter.contains(componentName)) {
+                    String key = componentToClusterInfoMap.get(componentName);
+
+                    if (StringUtils.isEmpty(key)) {
+                      // If not found in the componentToClusterInfoMap, then keys are assumed to be
+                      // in the form of <component_name>_hosts (lowercase)
+                      key = componentName.toLowerCase() + "_hosts";
+                    }
+
+                    Set<String> fqdns = new TreeSet<>();
+
+                    // Values are a comma-delimited list of hosts.
+                    // If a value exists, split it and add the tokens to the set
+                    if (!StringUtils.isEmpty(clusterHostInfoMap.get(key))) {
+                      fqdns.addAll(Arrays.asList(clusterHostInfoMap.get(key).split(",")));
+                    }
+
+                    // Add the set of hosts for the current host group
+                    for (Map<String, String> hostGroupHost : hostGroupHosts) {
+                      String fqdn = hostGroupHost.get("fqdn");
+
+                      if (!StringUtils.isEmpty(fqdn)) {
+                        fqdns.add(fqdn);
+                      }
+                    }
+
+                    // create the comma-delimited list of hosts
+                    clusterHostInfoMap.put(key, StringUtils.join(fqdns, ','));
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    } catch (StackAdvisorException e) {
+      LOG.error("Failed to obtain the recommended host groups for the preconfigured components.", e);
+      throw new AmbariException(e.getMessage(), e);
+    }
+  }
+
   @Override
   public Map<String, Map<String, String>> applyStackAdvisorUpdates(Cluster cluster, Set<String> services,
                                                                    Map<String, Map<String, String>> existingConfigurations,
@@ -568,9 +692,16 @@ public class KerberosHelperImpl implements KerberosHelper {
       }
 
       Set<StackId> visitedStacks = new HashSet<>();
+      Map<String, Service> installedServices = cluster.getServices();
 
       for (String serviceName : services) {
-        Service service = cluster.getService(serviceName);
+        Service service = installedServices.get(serviceName);
+
+        // Skip services that are not really installed
+        if (service == null) {
+          continue;
+        }
+
         StackId stackId = service.getDesiredStackId();
 
         if (visitedStacks.contains(stackId)) {
@@ -579,7 +710,7 @@ public class KerberosHelperImpl implements KerberosHelper {
 
         StackAdvisorRequest request = StackAdvisorRequest.StackAdvisorRequestBuilder
             .forStack(stackId.getStackName(), stackId.getStackVersion())
-            .forServices(new ArrayList<>(services))
+            .forServices(services)
             .forHosts(hostNames)
             .withComponentHostsMap(cluster.getServiceComponentHostMap(null, services))
             .withConfigurations(requestConfigurations)
@@ -647,7 +778,7 @@ public class KerberosHelperImpl implements KerberosHelper {
                     "\n\tConfigType: {}\n\tProperty: {}\n\tValue: {}",
                 configType, propertyName, recommendedValue);
 
-            if(kerberosConfigProperties == null) {
+            if (kerberosConfigProperties == null) {
               kerberosConfigProperties = new HashMap<>();
               kerberosConfigurations.put(configType, kerberosConfigProperties);
             }
@@ -723,7 +854,7 @@ public class KerberosHelperImpl implements KerberosHelper {
 
     // Only perform this task if Ambari manages Kerberos identities
     if (kerberosDetails.manageIdentities()) {
-      KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster);
+      KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster, false);
 
       Map<String, String> kerberosDescriptorProperties = kerberosDescriptor.getProperties();
       Map<String, Map<String, String>> configurations = addAdditionalConfigurations(cluster,
@@ -947,16 +1078,18 @@ public class KerberosHelperImpl implements KerberosHelper {
   }
 
   @Override
-  public void setAuthToLocalRules(KerberosDescriptor kerberosDescriptor, String realm,
+  public void setAuthToLocalRules(Cluster cluster,
+                                  KerberosDescriptor kerberosDescriptor, String realm,
                                   Map<String, Set<String>> installedServices,
                                   Map<String, Map<String, String>> existingConfigurations,
-                                  Map<String, Map<String, String>> kerberosConfigurations)
+                                  Map<String, Map<String, String>> kerberosConfigurations,
+                                  boolean includePreconfigureData)
       throws AmbariException {
 
     boolean processAuthToLocalRules = true;
-    Map<String, String> kerberosEnvProperties = existingConfigurations.get("kerberos-env");
-    if (kerberosEnvProperties.containsKey("manage_auth_to_local")) {
-      processAuthToLocalRules = Boolean.valueOf(kerberosEnvProperties.get("manage_auth_to_local"));
+    Map<String, String> kerberosEnvProperties = existingConfigurations.get(KERBEROS_ENV);
+    if (kerberosEnvProperties.containsKey(MANAGE_AUTH_TO_LOCAL_RULES)) {
+      processAuthToLocalRules = Boolean.valueOf(kerberosEnvProperties.get(MANAGE_AUTH_TO_LOCAL_RULES));
     }
 
     if (kerberosDescriptor != null && processAuthToLocalRules) {
@@ -966,7 +1099,7 @@ public class KerberosHelperImpl implements KerberosHelper {
 
       // a flag to be used by the AuthToLocalBuilder marking whether the default realm rule should contain the //L option, indicating username case insensitive behaviour
       // the 'kerberos-env' structure is expected to be available here as it was previously validated
-      boolean caseInsensitiveUser = Boolean.valueOf(existingConfigurations.get("kerberos-env").get("case_insensitive_username_rules"));
+      boolean caseInsensitiveUser = Boolean.valueOf(existingConfigurations.get(KERBEROS_ENV).get(CASE_INSENSITIVE_USERNAME_RULES));
 
       // Additional realms that need to be handled according to the Kerberos Descriptor
       String additionalRealms = kerberosDescriptor.getProperty("additional_realms");
@@ -976,43 +1109,69 @@ public class KerberosHelperImpl implements KerberosHelper {
       filterContext.put("configurations", existingConfigurations);
       filterContext.put("services", installedServices.keySet());
 
-      // Determine which properties need to be set
       AuthToLocalBuilder authToLocalBuilder = new AuthToLocalBuilder(realm, additionalRealms, caseInsensitiveUser);
-      addIdentities(authToLocalBuilder, kerberosDescriptor.getIdentities(true, filterContext), null, existingConfigurations);
 
+      // Add in the default configurations for the services that need to be preconfigured. These
+      // configurations may be needed while calculating the auth-to-local rules.
+      Map<String, Map<String, String>> replacements = (includePreconfigureData)
+          ? addConfigurationsForPreProcessedServices(deepCopy(existingConfigurations), cluster, kerberosDescriptor, false)
+          : existingConfigurations;
+
+      // Process top-level identities
+      addIdentities(authToLocalBuilder, kerberosDescriptor.getIdentities(true, filterContext), null, replacements);
+
+      // Determine which properties need to be set
       authToLocalProperties = kerberosDescriptor.getAuthToLocalProperties();
       if (authToLocalProperties != null) {
         authToLocalPropertiesToSet.addAll(authToLocalProperties);
       }
 
-      for(Map.Entry<String, Set<String>> installedService: installedServices.entrySet()) {
-        String serviceName = installedService.getKey();
+      // Iterate through the services in the Kerberos descriptor. If a found service is installed
+      // or marked to be preconfigured, add the relevant data to the auth-to-local rules.
+      Map<String, KerberosServiceDescriptor> serviceDescriptors = kerberosDescriptor.getServices();
+      if (serviceDescriptors != null) {
+        for (KerberosServiceDescriptor serviceDescriptor : serviceDescriptors.values()) {
+          String serviceName = serviceDescriptor.getName();
+          boolean preconfigure = includePreconfigureData && serviceDescriptor.shouldPreconfigure();
+          boolean explicitlyAdded = installedServices.containsKey(serviceName);
+
+          // Add this service's identities if we are implicitly preconfigurring the service or if the
+          // service has been explicitly added to the cluster
+          if (preconfigure || explicitlyAdded) {
+            LOG.info("Adding identities for service {} to auth to local mapping [{}]",
+                serviceName,
+                (explicitlyAdded) ? "explicit" : "preconfigured");
 
-        KerberosServiceDescriptor serviceDescriptor = kerberosDescriptor.getService(serviceName);
-        if(serviceDescriptor != null) {
-          LOG.info("Adding identities for service {} to auth to local mapping", installedService);
+            // Process the service-level Kerberos descriptor
+            addIdentities(authToLocalBuilder, serviceDescriptor.getIdentities(true, filterContext), null, replacements);
 
-          // Process the service-level Kerberos descriptor
-          addIdentities(authToLocalBuilder, serviceDescriptor.getIdentities(true, filterContext), null, existingConfigurations);
+            authToLocalProperties = serviceDescriptor.getAuthToLocalProperties();
+            if (authToLocalProperties != null) {
+              authToLocalPropertiesToSet.addAll(authToLocalProperties);
+            }
 
-          authToLocalProperties = serviceDescriptor.getAuthToLocalProperties();
-          if (authToLocalProperties != null) {
-            authToLocalPropertiesToSet.addAll(authToLocalProperties);
-          }
+            // Process the relevant component-level Kerberos descriptors
+            Map<String, KerberosComponentDescriptor> componentDescriptors = serviceDescriptor.getComponents();
+            if (componentDescriptors != null) {
+              Set<String> installedServiceComponents = installedServices.get(serviceName);
+              // Ensure installedComponents is not null....
+              if (installedServiceComponents == null) {
+                installedServiceComponents = Collections.emptySet();
+              }
 
-          // Process the relevant component-level Kerberos descriptors
-          Set<String> installedComponents = installedService.getValue();
-          if(installedComponents != null) {
-            for (String installedComponent : installedComponents) {
-              KerberosComponentDescriptor componentDescriptor = serviceDescriptor.getComponent(installedComponent);
+              for (KerberosComponentDescriptor componentDescriptor : componentDescriptors.values()) {
+                String componentName = componentDescriptor.getName();
 
-              if (componentDescriptor != null) {
-                LOG.info("Adding identities for component {} to auth to local mapping", installedComponent);
-                addIdentities(authToLocalBuilder, componentDescriptor.getIdentities(true, filterContext), null, existingConfigurations);
+                // Add this component's identities if we are implicitly preconfiguring the parent
+                // service or if the component has been explicitly added to the cluster
+                if (preconfigure || (installedServiceComponents.contains(componentName))) {
+                  LOG.info("Adding identities for component {} to auth to local mapping", componentName);
+                  addIdentities(authToLocalBuilder, componentDescriptor.getIdentities(true, filterContext), null, replacements);
 
-                authToLocalProperties = componentDescriptor.getAuthToLocalProperties();
-                if (authToLocalProperties != null) {
-                  authToLocalPropertiesToSet.addAll(authToLocalProperties);
+                  authToLocalProperties = componentDescriptor.getAuthToLocalProperties();
+                  if (authToLocalProperties != null) {
+                    authToLocalPropertiesToSet.addAll(authToLocalProperties);
+                  }
                 }
               }
             }
@@ -1065,63 +1224,82 @@ public class KerberosHelperImpl implements KerberosHelper {
 
 
   @Override
-  public List<ServiceComponentHost> getServiceComponentHostsToProcess(Cluster cluster,
-                                                                      KerberosDescriptor kerberosDescriptor,
-                                                                      Map<String, ? extends Collection<String>> serviceComponentFilter,
-                                                                      Collection<String> hostFilter, Collection<String> identityFilter,
-                                                                      Command<Boolean, ServiceComponentHost> shouldProcessCommand)
+  public List<ServiceComponentHost> getServiceComponentHostsToProcess(final Cluster cluster,
+                                                                      final KerberosDescriptor kerberosDescriptor,
+                                                                      final Map<String, ? extends Collection<String>> serviceComponentFilter,
+                                                                      final Collection<String> hostFilter, Collection<String> identityFilter,
+                                                                      final Command<Boolean, ServiceComponentHost> shouldProcessCommand)
       throws AmbariException {
-    List<ServiceComponentHost> serviceComponentHostsToProcess = new ArrayList<>();
-    Map<String, Service> services = cluster.getServices();
-
-    if ((services != null) && !services.isEmpty()) {
-      Collection<Host> hosts = cluster.getHosts();
-
-      if ((hosts != null) && !hosts.isEmpty()) {
-        // Iterate over the hosts in the cluster to find the components installed in each.  For each
-        // component (aka service component host - sch) determine the configuration updates and
-        // and the principals an keytabs to create.
-        for (Host host : hosts) {
-          String hostname = host.getHostName();
-
-          // Filter hosts as needed....
-          if ((hostFilter == null) || hostFilter.contains(hostname)) {
-            // Get a list of components on the current host
-            List<ServiceComponentHost> serviceComponentHosts = cluster.getServiceComponentHosts(hostname);
-
-            if ((serviceComponentHosts != null) && !serviceComponentHosts.isEmpty()) {
-
-              // Iterate over the components installed on the current host to get the service and
-              // component-level Kerberos descriptors in order to determine which principals,
-              // keytab files, and configurations need to be created or updated.
-              for (ServiceComponentHost sch : serviceComponentHosts) {
-                String serviceName = sch.getServiceName();
-                String componentName = sch.getServiceComponentName();
-
-                // If there is no filter or the filter contains the current service name...
-                if ((serviceComponentFilter == null) || serviceComponentFilter.containsKey(serviceName)) {
-                  Collection<String> componentFilter = (serviceComponentFilter == null) ? null : serviceComponentFilter.get(serviceName);
-                  KerberosServiceDescriptor serviceDescriptor = kerberosDescriptor.getService(serviceName);
-
-                  if (serviceDescriptor != null) {
-                    // If there is no filter or the filter contains the current component name,
-                    // test to see if this component should be processed by querying the handler...
-                    if (((componentFilter == null) || componentFilter.contains(componentName)) && shouldProcessCommand.invoke(sch)) {
-                      serviceComponentHostsToProcess.add(sch);
-                    }
-                  }
-                }
+    return getServiceComponentHosts(cluster, new Command<Boolean, ServiceComponentHost>() {
+      @Override
+      public Boolean invoke(ServiceComponentHost sch) throws AmbariException {
+        if (sch != null) {
+          // Check the host filter
+          if ((hostFilter == null) || hostFilter.contains(sch.getHostName())) {
+            String serviceName = sch.getServiceName();
+
+            // Check the service filter
+            if ((serviceComponentFilter == null) || serviceComponentFilter.containsKey(serviceName)) {
+              KerberosServiceDescriptor serviceDescriptor = kerberosDescriptor.getService(serviceName);
+
+              if (serviceDescriptor != null) {
+                Collection<String> componentFilter = (serviceComponentFilter == null) ? null : serviceComponentFilter.get(serviceName);
+
+                // Check the service/component filter and the shouldProcessCommand
+                return (((componentFilter == null) || componentFilter.contains(sch.getServiceComponentName())) &&
+                    ((shouldProcessCommand == null) || shouldProcessCommand.invoke(sch)));
               }
             }
           }
         }
+
+        return false;
+      }
+    });
+  }
+
+  /**
+   * Find the {@link ServiceComponentHost}s for the cluster, filtering using the
+   * supplied "should include" command (<code>shouldIncludeCommand</code>).
+   * <p>
+   * If <code>shouldIncludeCommand</code> is <code>null/code>, no filtering will be performed causing
+   * all found {@link ServiceComponentHost}s to be returned.
+   *
+   * @param cluster              the cluster
+   * @param shouldIncludeCommand the filtering logic
+   * @return a list of (filtered) {@link ServiceComponentHost}s
+   * @throws AmbariException if an error occurs
+   */
+  private List<ServiceComponentHost> getServiceComponentHosts(Cluster cluster,
+                                                              Command<Boolean, ServiceComponentHost> shouldIncludeCommand)
+      throws AmbariException {
+    List<ServiceComponentHost> serviceComponentHostsToProcess = new ArrayList<>();
+    // Get the hosts in the cluster
+    Collection<Host> hosts = cluster.getHosts();
+
+    if ((hosts != null) && !hosts.isEmpty()) {
+      // Iterate over the hosts in the cluster to find the components installed in each.
+      for (Host host : hosts) {
+        String hostname = host.getHostName();
+
+        // Get a list of components on the current host
+        List<ServiceComponentHost> serviceComponentHosts = cluster.getServiceComponentHosts(hostname);
+
+        if ((serviceComponentHosts != null) && !serviceComponentHosts.isEmpty()) {
+          // Iterate over the components installed on the current host and execute the shouldIncludeCommand
+          // Command (if supplied) to get the desired ServiceComponentHost instances.
+          for (ServiceComponentHost sch : serviceComponentHosts) {
+            if ((shouldIncludeCommand == null) || shouldIncludeCommand.invoke(sch)) {
+              serviceComponentHostsToProcess.add(sch);
+            }
+          }
+        }
       }
     }
 
     return serviceComponentHostsToProcess;
   }
 
-
   @Override
   public Set<String> getHostsWithValidKerberosClient(Cluster cluster)
       throws AmbariException {
@@ -1140,41 +1318,30 @@ public class KerberosHelperImpl implements KerberosHelper {
   }
 
   @Override
-  public KerberosDescriptor getKerberosDescriptor(Cluster cluster) throws AmbariException {
-    return getKerberosDescriptor(KerberosDescriptorType.COMPOSITE, cluster, false, null);
+  public KerberosDescriptor getKerberosDescriptor(Cluster cluster, boolean includePreconfigureData) throws AmbariException {
+    return getKerberosDescriptor(KerberosDescriptorType.COMPOSITE, cluster, false, null, includePreconfigureData);
   }
 
   @Override
   public KerberosDescriptor getKerberosDescriptor(KerberosDescriptorType kerberosDescriptorType, Cluster cluster,
-                                                  boolean evaluateWhenClauses, Collection<String> additionalServices)
+                                                  boolean evaluateWhenClauses, Collection<String> additionalServices,
+                                                  boolean includePreconfigureData)
       throws AmbariException {
-    KerberosDescriptor kerberosDescriptor;
 
     KerberosDescriptor stackDescriptor = (kerberosDescriptorType == KerberosDescriptorType.STACK || kerberosDescriptorType == KerberosDescriptorType.COMPOSITE)
-        ? getKerberosDescriptorFromStack(cluster)
+        ? getKerberosDescriptorFromStack(cluster, includePreconfigureData)
         : null;
 
     KerberosDescriptor userDescriptor = (kerberosDescriptorType == KerberosDescriptorType.USER || kerberosDescriptorType == KerberosDescriptorType.COMPOSITE)
         ? getKerberosDescriptorUpdates(cluster)
         : null;
 
-    if (stackDescriptor == null) {
-      if (userDescriptor == null) {
-        return new KerberosDescriptor();  // return an empty Kerberos descriptor since we have no data
-      } else {
-        kerberosDescriptor = userDescriptor;
-      }
-    } else {
-      if (userDescriptor != null) {
-        stackDescriptor.update(userDescriptor);
-      }
-      kerberosDescriptor = stackDescriptor;
-    }
+    KerberosDescriptor kerberosDescriptor = combineKerberosDescriptors(stackDescriptor, userDescriptor);
 
     if (evaluateWhenClauses) {
       Set<String> services = new HashSet<>(cluster.getServices().keySet());
 
-      if(additionalServices != null) {
+      if (additionalServices != null) {
         services.addAll(additionalServices);
       }
 
@@ -1220,7 +1387,8 @@ public class KerberosHelperImpl implements KerberosHelper {
   @Override
   public Map<String, Map<String, String>> mergeConfigurations(Map<String, Map<String, String>> configurations,
                                                               Map<String, KerberosConfigurationDescriptor> updates,
-                                                              Map<String, Map<String, String>> replacements)
+                                                              Map<String, Map<String, String>> replacements,
+                                                              Set<String> configurationTypeFilter)
       throws AmbariException {
 
     if ((updates != null) && !updates.isEmpty()) {
@@ -1230,11 +1398,59 @@ public class KerberosHelperImpl implements KerberosHelper {
 
       for (Map.Entry<String, KerberosConfigurationDescriptor> entry : updates.entrySet()) {
         String type = entry.getKey();
-        KerberosConfigurationDescriptor configurationDescriptor = entry.getValue();
 
-        if (configurationDescriptor != null) {
-          Map<String, String> updatedProperties = configurationDescriptor.getProperties();
-          mergeConfigurations(configurations, type, updatedProperties, replacements);
+        if ((configurationTypeFilter == null) || (configurationTypeFilter.contains(type))) {
+          KerberosConfigurationDescriptor configurationDescriptor = entry.getValue();
+
+          if (configurationDescriptor != null) {
+            Map<String, String> updatedProperties = configurationDescriptor.getProperties();
+            mergeConfigurations(configurations, type, updatedProperties, replacements);
+          }
+        }
+      }
+    }
+
+    return configurations;
+  }
+
+  @Override
+  public Map<String, Map<String, String>> processPreconfiguredServiceConfigurations(Map<String, Map<String, String>> configurations,
+                                                                                    Map<String, Map<String, String>> replacements,
+                                                                                    Cluster cluster,
+                                                                                    KerberosDescriptor kerberosDescriptor)
+      throws AmbariException {
+
+    // Ensure the Kerberos descriptor exists....
+    if (kerberosDescriptor == null) {
+      kerberosDescriptor = getKerberosDescriptor(cluster, true);
+    }
+
+    Map<String, KerberosServiceDescriptor> serviceDescriptors = kerberosDescriptor.getServices();
+
+    if (serviceDescriptors != null) {
+      if (configurations == null) {
+        configurations = new HashMap<>();
+      }
+
+      // Add in the default configurations for the services that need to be preconfigured. These
+      // configurations may be needed while calculating the auth-to-local rules.
+      Map<String, Map<String, String>> replacementsWithDefaults = addConfigurationsForPreProcessedServices(deepCopy(replacements), cluster, kerberosDescriptor, true);
+
+      Map<String, Service> existingServices = cluster.getServices();
+
+      for (KerberosServiceDescriptor serviceDescriptor : serviceDescriptors.values()) {
+        String serviceName = serviceDescriptor.getName();
+        boolean shouldPreconfigure = serviceDescriptor.shouldPreconfigure();
+
+        if (!existingServices.containsKey(serviceName) && shouldPreconfigure) {
+          configurations = mergeConfigurations(configurations, serviceDescriptor.getConfigurations(), replacementsWithDefaults, replacements.keySet());
+
+          Map<String, KerberosComponentDescriptor> componentDescriptors = serviceDescriptor.getComponents();
+          if (componentDescriptors != null) {
+            for (KerberosComponentDescriptor componentDescriptor : componentDescriptors.values()) {
+              configurations = mergeConfigurations(configurations, componentDescriptor.getConfigurations(), replacementsWithDefaults, replacements.keySet());
+            }
+          }
         }
       }
     }
@@ -1318,16 +1534,15 @@ public class KerberosHelperImpl implements KerberosHelper {
   @Override
   public Map<String, Map<String, String>> calculateConfigurations(Cluster cluster, String hostname,
                                                                   Map<String, String> kerberosDescriptorProperties)
-      throws AmbariException
-  {
+      throws AmbariException {
     return addAdditionalConfigurations(cluster,
-      calculateExistingConfigurations(cluster, hostname),
-      hostname, kerberosDescriptorProperties);
+        calculateExistingConfigurations(cluster, hostname),
+        hostname, kerberosDescriptorProperties);
   }
 
   private Map<String, String> principalNames(Cluster cluster, Map<String, Map<String, String>> configuration) throws AmbariException {
     Map<String, String> result = new HashMap<>();
-    for (Map.Entry<String, String> each : getKerberosDescriptor(cluster).principals().entrySet()) {
+    for (Map.Entry<String, String> each : getKerberosDescriptor(cluster, false).principals().entrySet()) {
       result.put(each.getKey(), variableReplacementHelper.replaceVariables(each.getValue(), configuration));
     }
     return result;
@@ -1355,12 +1570,11 @@ public class KerberosHelperImpl implements KerberosHelper {
 
     // Only calculate the active identities if the kerberos-env configurtaion is available.  Else
     // important information like the realm will be missing (kerberos-env/realm)
-    Config kerberosEnvConfig = cluster.getDesiredConfigByType("kerberos-env");
-    if(kerberosEnvConfig == null) {
+    Config kerberosEnvConfig = cluster.getDesiredConfigByType(KERBEROS_ENV);
+    if (kerberosEnvConfig == null) {
       LOG.debug("Calculating the active identities for {} is being skipped since the kerberos-env configuration is not available",
           clusterName, cluster.getSecurityType().name(), SecurityType.KERBEROS.name());
-    }
-    else {
+    } else {
       Collection<String> hosts;
       String ambariServerHostname = StageUtils.getHostName();
 
@@ -1383,7 +1597,7 @@ public class KerberosHelperImpl implements KerberosHelper {
       }
 
       if (!hosts.isEmpty()) {
-        KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster);
+        KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster, false);
 
         if (kerberosDescriptor != null) {
           Map<String, String> kerberosDescriptorProperties = kerberosDescriptor.getProperties();
@@ -1410,7 +1624,7 @@ public class KerberosHelperImpl implements KerberosHelper {
             if (hostname.equals(ambariServerHostname)) {
               // Determine if we should _calculate_ the Ambari service identities.
               // If kerberos-env/create_ambari_principal is not set to false the identity should be calculated.
-              if(createAmbariIdentities(kerberosEnvConfig.getProperties())) {
+              if (createAmbariIdentities(kerberosEnvConfig.getProperties())) {
                 List<KerberosIdentityDescriptor> ambariIdentities = getAmbariServerIdentities(kerberosDescriptor);
                 if (ambariIdentities != null) {
                   identities.addAll(ambariIdentities);
@@ -1743,7 +1957,7 @@ public class KerberosHelperImpl implements KerberosHelper {
                                final Handler handler)
       throws AmbariException, KerberosOperationException {
 
-    final KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster);
+    final KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster, false);
 
     List<ServiceComponentHost> schToProcess = getServiceComponentHostsToProcess(
         cluster,
@@ -1751,7 +1965,7 @@ public class KerberosHelperImpl implements KerberosHelper {
         serviceComponentFilter,
         hostFilter,
         identityFilter,
-      arg -> true);
+        arg -> true);
 
 
     // While iterating over all the ServiceComponentHosts find hosts that have KERBEROS_CLIENT
@@ -1791,7 +2005,7 @@ public class KerberosHelperImpl implements KerberosHelper {
     Map<String, Set<String>> clusterHostInfo = StageUtils.getClusterHostInfo(cluster);
     String clusterHostInfoJson = StageUtils.getGson().toJson(clusterHostInfo);
 
-    @Experimental(feature=ExperimentalFeature.MULTI_SERVICE, comment="The cluster stack id is deprecated")
+    @Experimental(feature = ExperimentalFeature.MULTI_SERVICE, comment = "The cluster stack id is deprecated")
     Map<String, String> hostParams = customCommandExecutionHelper.createDefaultHostParams(cluster, cluster.getDesiredStackVersion());
     String hostParamsJson = StageUtils.getGson().toJson(hostParams);
     String ambariServerHostname = StageUtils.getHostName();
@@ -1855,7 +2069,7 @@ public class KerberosHelperImpl implements KerberosHelper {
       }
 
       List<ServiceComponentHost> serviceComponentHostsToProcess = new ArrayList<>();
-      KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster);
+      KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster, false);
       KerberosIdentityDataFileWriter kerberosIdentityDataFileWriter = null;
 
       Map<String, String> kerberosDescriptorProperties = kerberosDescriptor.getProperties();
@@ -1965,7 +2179,7 @@ public class KerberosHelperImpl implements KerberosHelper {
       Map<String, Set<String>> clusterHostInfo = StageUtils.getClusterHostInfo(cluster);
       String clusterHostInfoJson = StageUtils.getGson().toJson(clusterHostInfo);
 
-      @Experimental(feature=ExperimentalFeature.MULTI_SERVICE, comment="The cluster stack id is deprecated")
+      @Experimental(feature = ExperimentalFeature.MULTI_SERVICE, comment = "The cluster stack id is deprecated")
       Map<String, String> hostParams = customCommandExecutionHelper.createDefaultHostParams(cluster, cluster.getDesiredStackVersion());
       String hostParamsJson = StageUtils.getGson().toJson(hostParams);
       String ambariServerHostname = StageUtils.getHostName();
@@ -2037,7 +2251,7 @@ public class KerberosHelperImpl implements KerberosHelper {
       throw new AmbariException(message);
     }
 
-    Config configKerberosEnv = cluster.getDesiredConfigByType("kerberos-env");
+    Config configKerberosEnv = cluster.getDesiredConfigByType(KERBEROS_ENV);
     if (configKerberosEnv == null) {
       String message = "The 'kerberos-env' configuration is not available";
       LOG.error(message);
@@ -2052,14 +2266,14 @@ public class KerberosHelperImpl implements KerberosHelper {
     }
 
     kerberosDetails.setSecurityType(cluster.getSecurityType());
-    kerberosDetails.setDefaultRealm(kerberosEnvProperties.get("realm"));
+    kerberosDetails.setDefaultRealm(kerberosEnvProperties.get(DEFAULT_REALM));
 
     kerberosDetails.setKerberosEnvProperties(kerberosEnvProperties);
 
     // If set, override the manage identities behavior
     kerberosDetails.setManageIdentities(manageIdentities);
 
-    String kdcTypeProperty = kerberosEnvProperties.get("kdc_type");
+    String kdcTypeProperty = kerberosEnvProperties.get(KDC_TYPE);
     if ((kdcTypeProperty == null) && kerberosDetails.manageIdentities()) {
       String message = "The 'kerberos-env/kdc_type' value must be set to a valid KDC type";
       LOG.error(message);
@@ -2253,12 +2467,12 @@ public class KerberosHelperImpl implements KerberosHelper {
   /**
    * Creates a new stage
    *
-   * @param id              the new stage's id
-   * @param cluster         the relevant Cluster
-   * @param requestId       the relevant request Id
-   * @param requestContext  a String describing the stage
-   * @param commandParams   JSON-encoded command parameters
-   * @param hostParams      JSON-encoded host parameters
+   * @param id             the new stage's id
+   * @param cluster        the relevant Cluster
+   * @param requestId      the relevant request Id
+   * @param requestContext a String describing the stage
+   * @param commandParams  JSON-encoded command parameters
+   * @param hostParams     JSON-encoded host parameters
    * @return a newly created Stage
    */
   private Stage createNewStage(long id, Cluster cluster, long requestId,
@@ -2302,7 +2516,7 @@ public class KerberosHelperImpl implements KerberosHelper {
                                         Map<String, String> commandParameters, String commandDetail,
                                         Integer timeout) throws AmbariException {
 
-    Stage stage = createNewStage(id, cluster, requestId, requestContext,  commandParams, hostParams);
+    Stage stage = createNewStage(id, cluster, requestId, requestContext, commandParams, hostParams);
     stage.addServerActionCommand(actionClass.getName(), null, Role.AMBARI_SERVER_ACTION,
         RoleCommand.EXECUTE, cluster.getClusterName(), event, commandParameters, commandDetail,
         ambariManagementController.findConfigurationTagsWithOverrides(cluster, null), timeout,
@@ -2628,11 +2842,12 @@ public class KerberosHelperImpl implements KerberosHelper {
    * Get the default Kerberos descriptor from the stack, which is the same as the value from
    * <code>stacks/:stackName/versions/:version/artifacts/kerberos_descriptor</code>
    *
-   * @param cluster the cluster
+   * @param cluster                 the cluster
+   * @param includePreconfigureData <code>true</code> to include the preconfigure data; otherwise false
    * @return a Kerberos Descriptor
    * @throws AmbariException if an error occurs while retrieving the Kerberos descriptor
    */
-  private KerberosDescriptor getKerberosDescriptorFromStack(Cluster cluster) throws AmbariException {
+  private KerberosDescriptor getKerberosDescriptorFromStack(Cluster cluster, boolean includePreconfigureData) throws AmbariException {
     // !!! FIXME in a per-service view, what does this become?
     Set<StackId> stackIds = new HashSet<>();
 
@@ -2649,14 +2864,14 @@ public class KerberosHelperImpl implements KerberosHelper {
     // -------------------------------
     // Get the default Kerberos descriptor from the stack, which is the same as the value from
     // stacks/:stackName/versions/:version/artifacts/kerberos_descriptor
-    return ambariMetaInfo.getKerberosDescriptor(stackId.getStackName(), stackId.getStackVersion());
+    return ambariMetaInfo.getKerberosDescriptor(stackId.getStackName(), stackId.getStackVersion(), includePreconfigureData);
     // -------------------------------
   }
 
   /**
    * Recursively walk the Kerberos descriptor tree to find all Kerberos identity definitions and
    * determine which should be filtered out.
-   *
+   * <p>
    * No actual filtering is performed while processing since any referenced Kerberos identities need
    * to be accessible throughout the process. So a map of container path to a list of identities is
    * created an returned
@@ -2668,14 +2883,14 @@ public class KerberosHelperImpl implements KerberosHelper {
    * @return
    * @throws AmbariException
    */
-  private Map<String,Set<String>> processWhenClauses(String currentPath, AbstractKerberosDescriptorContainer container, Map<String, Object> context, Map<String,Set<String>> identitiesToRemove) throws AmbariException {
+  private Map<String, Set<String>> processWhenClauses(String currentPath, AbstractKerberosDescriptorContainer container, Map<String, Object> context, Map<String, Set<String>> identitiesToRemove) throws AmbariException {
 
     // Get the list of this container's identities.
     // Do not filter these identities using KerberosIdentityDescriptor#shouldInclude since we will do
     // that later.
     List<KerberosIdentityDescriptor> identities = container.getIdentities(true, null);
 
-    if((identities != null) && !identities.isEmpty()) {
+    if ((identities != null) && !identities.isEmpty()) {
       Set<String> set = null;
 
       for (KerberosIdentityDescriptor identity : identities) {
@@ -2691,8 +2906,8 @@ public class KerberosHelperImpl implements KerberosHelper {
     }
 
     Collection<? extends AbstractKerberosDescriptorContainer> children = container.getChildContainers();
-    if(children != null) {
-      for(AbstractKerberosDescriptorContainer child: children) {
+    if (children != null) {
+      for (AbstractKerberosDescriptorContainer child : children) {
         identitiesToRemove = processWhenClauses(currentPath + "/" + child.getName(), child, context, identitiesToRemove);
       }
     }
@@ -2749,6 +2964,142 @@ public class KerberosHelperImpl implements KerberosHelper {
 
   }
 
+  /**
+   * Gathers the Kerberos-related configurations for services not yet installed, but flagged to be
+   * preconfigured.
+   * <p>
+   * Only existing configuration types will be updated, new types will not be added since they are
+   * expected only when the relevant service has been installed. This is to help reduce the number
+   * of service restarts when new services are added to clusters where Kerberos has been enabled.
+   * <p>
+   * If desired, the Stack Advisor will be invoked to request recommended hosts for the component.
+   * This is needed to fill out the clusterHostInfo structure in the configuration map. For example,
+   * <code>clusterHostInfo/knox_gateway_hosts</code>
+   *
+   * @param configurations           the existing configurations (updated in-place)
+   * @param cluster                  the cluster
+   * @param kerberosDescriptor       the kerberos descriptor
+   * @param calculateClusterHostInfo true, to query the Stack Advisor for recommended hosts for the
+   *                                 preconfigured services and components; false, otherwise
+   * @return the updated configuration map
+   * @throws AmbariException if an error occurs
+   */
+  private Map<String, Map<String, String>> addConfigurationsForPreProcessedServices(Map<String, Map<String, String>> configurations,
+                                                                                    Cluster cluster,
+                                                                                    KerberosDescriptor kerberosDescriptor,
+                                                                                    boolean calculateClusterHostInfo)
+      throws AmbariException {
+
+    Map<String, KerberosServiceDescriptor> serviceDescriptorMap = kerberosDescriptor.getServices();
+
+    if (serviceDescriptorMap != null) {
+      Map<String, Service> existingServices = cluster.getServices();
+      Set<String> allServices = new HashSet<>(existingServices.keySet());
+      Set<String> componentFilter = new HashSet<>();
+      StackId stackVersion = cluster.getCurrentStackVersion();
+
+      for (KerberosServiceDescriptor serviceDescriptor : serviceDescriptorMap.values()) {
+        String serviceName = serviceDescriptor.getName();
+        boolean shouldPreconfigure = serviceDescriptor.shouldPreconfigure();
+
+        if (shouldPreconfigure && !existingServices.containsKey(serviceName)) {
+          if (ambariMetaInfo.isValidService(stackVersion.getStackName(), stackVersion.getStackVersion(), serviceName)) {
+            ServiceInfo serviceInfo = ambariMetaInfo.getService(stackVersion.getStackName(), stackVersion.getStackVersion(), serviceName);
+
+            Collection<PropertyInfo> servicePropertiesInfos = serviceInfo.getProperties();
+            if (servicePropertiesInfos != null) {
+              Map<String, Map<String, String>> propertiesToAdd = new HashMap<>();
+
+              for (PropertyInfo propertyInfo : servicePropertiesInfos) {
+                String type = ConfigHelper.fileNameToConfigType(propertyInfo.getFilename());
+
+                Map<String, String> map = propertiesToAdd.get(type);
+                if (map == null) {
+                  map = new HashMap<>();
+                  propertiesToAdd.put(type, map);
+                }
+                map.put(propertyInfo.getName(), propertyInfo.getValue());
+              }
+
+              for (Map.Entry<String, Map<String, String>> entry : propertiesToAdd.entrySet()) {
+                if (!configurations.containsKey(entry.getKey())) {
+                  configurations.put(entry.getKey(), entry.getValue());
+                }
+              }
+            }
+
+            // This is only needed if the Stack Advisor is being called to get recommended host
+            // for components
+            if (calculateClusterHostInfo) {
+              // Add the service to preconfigure to the all services set for use later
+              allServices.add(serviceName);
+
+              // Add the components for the service to preconfigure to the component filter
+              List<ComponentInfo> componentInfos = serviceInfo.getComponents();
+              if (componentInfos != null) {
+                for (ComponentInfo componentInfo : componentInfos) {
+                  componentFilter.add(componentInfo.getName());
+                }
+              }
+            }
+          }
+        }
+      }
+
+      if (calculateClusterHostInfo && (allServices.size() > existingServices.size())) {
+        applyStackAdvisorHostRecommendations(cluster, allServices, componentFilter, configurations);
+      }
+    }
+
+    return configurations;
+  }
+
+  /**
+   * Combines a stack-level Kerberos descriptor with a user-suppled Kerberos descriptor to creae a
+   * composite {@link KerberosDescriptor} using the following logic:
+   * <p>
+   * <ul>
+   * <li>
+   * If both the stack-level and the user-supplied Kerberos descriptors are <code>null</code>,
+   * return an empty {@link KerberosDescriptor}.
+   * </li>
+   * <li>
+   * If the stack-level Kerberos descriptor is <code>null</code> and the user-supplied Kerberos
+   * descriptor is <code>non-null</code>, return the user-supplied Kerberos descriptor.
+   * </li>
+   * <li>
+   * If the stack-level Kerberos descriptor is <code>non-null</code> and the user-supplied
+   * Kerberos descriptor is <code>null</code>, return the stack-level Kerberos descriptor.
+   * </li>
+   * <li>
+   * If neither the stack-level nor the user-supplied Kerberos descriptors are <code>null</code>,
+   * return the stack-level Kerberos descriptor that has been updated using data from the
+   * user-supplied Kerberos descriptor.
+   * </li>
+   * </ul>
+   *
+   * @param stackDescriptor the stack-level Keberos descriptor
+   * @param userDescriptor  the user-supplied Kerberos descriptor
+   * @return a KerberosDescriptor
+   */
+  private KerberosDescriptor combineKerberosDescriptors(KerberosDescriptor stackDescriptor, KerberosDescriptor userDescriptor) {
+    KerberosDescriptor kerberosDescriptor;
+    if (stackDescriptor == null) {
+      if (userDescriptor == null) {
+        return new KerberosDescriptor();  // return an empty Kerberos descriptor since we have no data
+      } else {
+        kerberosDescriptor = userDescriptor;
+      }
+    } else {
+      if (userDescriptor != null) {
+        stackDescriptor.update(userDescriptor);
+      }
+      kerberosDescriptor = stackDescriptor;
+    }
+
+    return kerberosDescriptor;
+  }
+
   /* ********************************************************************************************
    * Helper classes and enums
    * ******************************************************************************************** *\
@@ -2994,7 +3345,7 @@ public class KerberosHelperImpl implements KerberosHelper {
           hostParamsJson);
 
       Collection<ServiceComponentHost> filteredComponents = filterServiceComponentHostsForHosts(
-        new ArrayList<>(serviceComponentHosts), hostsWithValidKerberosClient);
+          new ArrayList<>(serviceComponentHosts), hostsWithValidKerberosClient);
 
       if (!filteredComponents.isEmpty()) {
         List<String> hostsToUpdate = createUniqueHostList(filteredComponents, Collections.singleton(HostState.HEALTHY));
@@ -3005,7 +3356,7 @@ public class KerberosHelperImpl implements KerberosHelper {
 
         ActionExecutionContext actionExecContext = new ActionExecutionContext(
             cluster.getClusterName(),
-          SET_KEYTAB,
+            SET_KEYTAB,
             requestResourceFilters,
             requestParams);
         customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, stage,
@@ -3024,14 +3375,14 @@ public class KerberosHelperImpl implements KerberosHelper {
      */
     public void addCheckMissingKeytabsStage(Cluster cluster, String clusterHostInfoJson, String hostParamsJson, ServiceComponentHostServerActionEvent event, Map<String, String> commandParameters, RoleCommandOrder roleCommandOrder, RequestStageContainer requestStageContainer, List<ServiceComponentHost> serviceComponentHosts) throws AmbariException {
       Stage stage = createNewStage(requestStageContainer.getLastStageId(),
-        cluster,
-        requestStageContainer.getId(),
-        "Checking keytabs",
-        StageUtils.getGson().toJson(commandParameters),
-        hostParamsJson);
+          cluster,
+          requestStageContainer.getId(),
+          "Checking keytabs",
+          StageUtils.getGson().toJson(commandParameters),
+          hostParamsJson);
 
       Collection<ServiceComponentHost> filteredComponents = filterServiceComponentHostsForHosts(
-        new ArrayList<>(serviceComponentHosts), getHostsWithValidKerberosClient(cluster));
+          new ArrayList<>(serviceComponentHosts), getHostsWithValidKerberosClient(cluster));
 
       List<String> hostsToUpdate = createUniqueHostList(filteredComponents, Collections.singleton(HostState.HEALTHY));
       Map<String, String> requestParams = new HashMap<>();
@@ -3040,10 +3391,10 @@ public class KerberosHelperImpl implements KerberosHelper {
       requestResourceFilters.add(reqResFilter);
 
       ActionExecutionContext actionExecContext = new ActionExecutionContext(
-        cluster.getClusterName(),
-        CHECK_KEYTABS,
-        requestResourceFilters,
-        requestParams);
+          cluster.getClusterName(),
+          CHECK_KEYTABS,
+          requestResourceFilters,
+          requestParams);
       customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, stage, requestParams, null);
       RoleGraph roleGraph = roleGraphFactory.createNew(roleCommandOrder);
       roleGraph.build(stage);
@@ -3079,19 +3430,18 @@ public class KerberosHelperImpl implements KerberosHelper {
     }
 
     void addDisableSecurityHookStage(Cluster cluster,
-                                            String clusterHostInfoJson,
-                                            String hostParamsJson,
-                                            Map<String, String> commandParameters,
-                                            RoleCommandOrder roleCommandOrder,
-                                            RequestStageContainer requestStageContainer)
-      throws AmbariException
-    {
+                                     String clusterHostInfoJson,
+                                     String hostParamsJson,
+                                     Map<String, String> commandParameters,
+                                     RoleCommandOrder roleCommandOrder,
+                                     RequestStageContainer requestStageContainer)
+        throws AmbariException {
       Stage stage = createNewStage(requestStageContainer.getLastStageId(),
-        cluster,
-        requestStageContainer.getId(),
-        "Disable security",
-        StageUtils.getGson().toJson(commandParameters),
-        hostParamsJson);
+          cluster,
+          requestStageContainer.getId(),
+          "Disable security",
+          StageUtils.getGson().toJson(commandParameters),
+          hostParamsJson);
       addDisableSecurityCommandToAllServices(cluster, stage);
       RoleGraph roleGraph = roleGraphFactory.createNew(roleCommandOrder);
       roleGraph.build(stage);
@@ -3103,27 +3453,26 @@ public class KerberosHelperImpl implements KerberosHelper {
     private void addDisableSecurityCommandToAllServices(Cluster cluster, Stage stage) throws AmbariException {
       for (Service service : cluster.getServices().values()) {
         for (ServiceComponent component : service.getServiceComponents().values()) {
-            if (!component.getServiceComponentHosts().isEmpty()) {
-              String firstHost = component.getServiceComponentHosts().keySet().iterator().next(); // it is only necessary to send it to one host
-              ActionExecutionContext exec = new ActionExecutionContext(
+          if (!component.getServiceComponentHosts().isEmpty()) {
+            String firstHost = component.getServiceComponentHosts().keySet().iterator().next(); // it is only necessary to send it to one host
+            ActionExecutionContext exec = new ActionExecutionContext(
                 cluster.getClusterName(),
                 "DISABLE_SECURITY",
                 singletonList(new RequestResourceFilter(service.getName(), component.getName(), singletonList(firstHost))),
                 Collections.emptyMap());
-              customCommandExecutionHelper.addExecutionCommandsToStage(exec, stage, Collections.emptyMap(), null);
+            customCommandExecutionHelper.addExecutionCommandsToStage(exec, stage, Collections.emptyMap(), null);
           }
         }
       }
     }
 
     void addStopZookeeperStage(Cluster cluster,
-                                      String clusterHostInfoJson,
-                                      String hostParamsJson,
-                                      Map<String, String> commandParameters,
-                                      RoleCommandOrder roleCommandOrder,
-                                      RequestStageContainer requestStageContainer)
-      throws AmbariException
-    {
+                               String clusterHostInfoJson,
+                               String hostParamsJson,
+                               Map<String, String> commandParameters,
+                               RoleCommandOrder roleCommandOrder,
+                               RequestStageContainer requestStageContainer)
+        throws AmbariException {
       Service zookeeper;
       try {
         zookeeper = cluster.getService("ZOOKEEPER");
@@ -3131,19 +3480,19 @@ public class KerberosHelperImpl implements KerberosHelper {
         return;
       }
       Stage stage = createNewStage(requestStageContainer.getLastStageId(),
-        cluster,
-        requestStageContainer.getId(),
-        "Stopping ZooKeeper",
-        StageUtils.getGson().toJson(commandParameters),
-        hostParamsJson);
+          cluster,
+          requestStageContainer.getId(),
+          "Stopping ZooKeeper",
+          StageUtils.getGson().toJson(commandParameters),
+          hostParamsJson);
       for (ServiceComponent component : zookeeper.getServiceComponents().values()) {
-          Set<String> hosts = component.getServiceComponentHosts().keySet();
-          ActionExecutionContext exec = new ActionExecutionContext(
+        Set<String> hosts = component.getServiceComponentHosts().keySet();
+        ActionExecutionContext exec = new ActionExecutionContext(
             cluster.getClusterName(),
             "STOP",
             singletonList(new RequestResourceFilter(zookeeper.getName(), component.getName(), new ArrayList<>(hosts))),
             Collections.emptyMap());
-          customCommandExecutionHelper.addExecutionCommandsToStage(exec, stage, Collections.emptyMap(), null);
+        customCommandExecutionHelper.addExecutionCommandsToStage(exec, stage, Collections.emptyMap(), null);
       }
       RoleGraph roleGraph = roleGraphFactory.createNew(roleCommandOrder);
       roleGraph.build(stage);
@@ -3168,7 +3517,7 @@ public class KerberosHelperImpl implements KerberosHelper {
           hostParamsJson);
 
       Collection<ServiceComponentHost> filteredComponents = filterServiceComponentHostsForHosts(
-        new ArrayList<>(serviceComponentHosts), hostsWithValidKerberosClient);
+          new ArrayList<>(serviceComponentHosts), hostsWithValidKerberosClient);
 
       if (!filteredComponents.isEmpty()) {
         List<String> hostsToUpdate = createUniqueHostList(filteredComponents, Collections.singleton(HostState.HEALTHY));
@@ -3181,7 +3530,7 @@ public class KerberosHelperImpl implements KerberosHelper {
 
           ActionExecutionContext actionExecContext = new ActionExecutionContext(
               cluster.getClusterName(),
-            REMOVE_KEYTAB,
+              REMOVE_KEYTAB,
               requestResourceFilters,
               requestParams);
           customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, stage,
@@ -3325,6 +3674,7 @@ public class KerberosHelperImpl implements KerberosHelper {
       commandParameters.put(KerberosServerAction.UPDATE_CONFIGURATIONS, "true");
       commandParameters.put(KerberosServerAction.DEFAULT_REALM, kerberosDetails.getDefaultRealm());
       commandParameters.put(KerberosServerAction.INCLUDE_AMBARI_IDENTITY, (kerberosDetails.createAmbariPrincipal()) ? "true" : "false");
+      commandParameters.put(KerberosServerAction.PRECONFIGURE_SERVICES, kerberosDetails.getPreconfigureServices());
 
       if (dataDirectory != null) {
         commandParameters.put(KerberosServerAction.DATA_DIRECTORY, dataDirectory.getAbsolutePath());
@@ -3431,10 +3781,10 @@ public class KerberosHelperImpl implements KerberosHelper {
       }
 
       addDisableSecurityHookStage(cluster, clusterHostInfoJson, hostParamsJson, commandParameters,
-        roleCommandOrder, requestStageContainer);
+          roleCommandOrder, requestStageContainer);
 
       addStopZookeeperStage(cluster, clusterHostInfoJson, hostParamsJson, commandParameters,
-        roleCommandOrder, requestStageContainer);
+          roleCommandOrder, requestStageContainer);
 
       // *****************************************************************
       // Create stage to prepare operations
@@ -3580,7 +3930,7 @@ public class KerberosHelperImpl implements KerberosHelper {
 
         if (!regenerateAllKeytabs) {
           addCheckMissingKeytabsStage(cluster, clusterHostInfoJson, hostParamsJson, event,
-            commandParameters, roleCommandOrder, requestStageContainer, serviceComponentHosts);
+              commandParameters, roleCommandOrder, requestStageContainer, serviceComponentHosts);
         }
 
         // *****************************************************************
@@ -3752,5 +4102,9 @@ public class KerberosHelperImpl implements KerberosHelper {
       return (kerberosEnvProperties == null) ||
           !"false".equalsIgnoreCase(kerberosEnvProperties.get(CREATE_AMBARI_PRINCIPAL));
     }
+
+    public String getPreconfigureServices() {
+      return (kerberosEnvProperties == null) ? "" : kerberosEnvProperties.get(PRECONFIGURE_SERVICES);
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
index 91a84ea..b4e1027 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
@@ -538,7 +538,7 @@ public class BlueprintConfigurationProcessor {
       String clusterName = clusterTopology.getAmbariContext().getClusterName(clusterTopology.getClusterId());
       Cluster cluster = clusterTopology.getAmbariContext().getController().getClusters().getCluster(clusterName);
       authToLocalPerClusterMap = new HashMap<>();
-      authToLocalPerClusterMap.put(Long.valueOf(clusterTopology.getClusterId()), clusterTopology.getAmbariContext().getController().getKerberosHelper().getKerberosDescriptor(cluster).getAllAuthToLocalProperties());
+      authToLocalPerClusterMap.put(Long.valueOf(clusterTopology.getClusterId()), clusterTopology.getAmbariContext().getController().getKerberosHelper().getKerberosDescriptor(cluster, false).getAllAuthToLocalProperties());
       } catch (AmbariException e) {
         LOG.error("Error while getting authToLocal properties. ", e);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterKerberosDescriptorResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterKerberosDescriptorResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterKerberosDescriptorResourceProvider.java
index 59bd96a..2678d55 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterKerberosDescriptorResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterKerberosDescriptorResourceProvider.java
@@ -158,7 +158,8 @@ public class ClusterKerberosDescriptorResourceProvider extends ReadOnlyResourceP
           kerberosDescriptor = kerberosHelper.getKerberosDescriptor(kerberosDescriptorType,
               cluster,
               getEvaluateWhen(requestInfoProperties),
-              getAdditionalServices(requestInfoProperties));
+              getAdditionalServices(requestInfoProperties),
+              false);
         } catch (AmbariException e) {
           throw new SystemException("An unexpected error occurred building the cluster's composite Kerberos Descriptor", e);
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
index 64ead40..094c75b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StackVersionResourceProvider.java
@@ -19,10 +19,7 @@
 
 package org.apache.ambari.server.controller.internal;
 
-import java.io.File;
-import java.io.IOException;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Map;
@@ -42,12 +39,6 @@ import org.apache.ambari.server.controller.spi.Resource.Type;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
-import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
-import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
-import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
-import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptorFactory;
-
-import com.google.inject.Inject;
 
 @StaticallyInject
 public class StackVersionResourceProvider extends ReadOnlyResourceProvider {
@@ -67,18 +58,6 @@ public class StackVersionResourceProvider extends ReadOnlyResourceProvider {
   private static Set<String> pkPropertyIds = new HashSet<>(
     Arrays.asList(new String[]{STACK_NAME_PROPERTY_ID, STACK_VERSION_PROPERTY_ID}));
 
-  /**
-   * KerberosDescriptorFactory used to create KerberosDescriptor instances
-   */
-  @Inject
-  private static KerberosDescriptorFactory kerberosDescriptorFactory;
-
-  /**
-   * KerberosServiceDescriptorFactory used to create KerberosServiceDescriptor instances
-   */
-  @Inject
-  private static KerberosServiceDescriptorFactory kerberosServiceDescriptorFactory;
-
   protected StackVersionResourceProvider(Set<String> propertyIds,
       Map<Type, String> keyPropertyIds,
       AmbariManagementController managementController) {
@@ -153,51 +132,6 @@ public class StackVersionResourceProvider extends ReadOnlyResourceProvider {
     return resources;
   }
 
-  /**
-   * Given data from a StackVersionResponse build a complete Kerberos descriptor hierarchy.
-   *
-   * @param stackVersionResponse the StackVersionResponse instance containing the details of the
-   *                             stack and the relevant Kerberos descriptor files
-   * @return a KerberosDescriptor containing the complete hierarchy for the stack
-   * @throws IOException     if the specified File is not found or not a readable
-   * @throws AmbariException if the specified File does not contain valid JSON-encoded Kerberos
-   *                         descriptor
-   */
-  private KerberosDescriptor buildKerberosDescriptor(StackVersionResponse stackVersionResponse)
-      throws IOException {
-    KerberosDescriptor kerberosDescriptor = null;
-
-    // Process the stack-level Kerberos descriptor file
-    File stackKerberosDescriptorFile = stackVersionResponse.getStackKerberosDescriptorFile();
-    if (stackKerberosDescriptorFile != null) {
-      kerberosDescriptor = kerberosDescriptorFactory.createInstance(stackKerberosDescriptorFile);
-    }
-
-    // Process the service-level Kerberos descriptor files
-    Collection<File> serviceDescriptorFiles = stackVersionResponse.getServiceKerberosDescriptorFiles();
-    if ((serviceDescriptorFiles != null) && !serviceDescriptorFiles.isEmpty()) {
-      // Make sure kerberosDescriptor is not null. This will be the case if there is no stack-level
-      // Kerberos descriptor file.
-      if (kerberosDescriptor == null) {
-        kerberosDescriptor = new KerberosDescriptor();
-      }
-
-      // For each service-level Kerberos descriptor file, parse into an array of KerberosServiceDescriptors
-      // and then append each to the KerberosDescriptor hierarchy.
-      for (File file : serviceDescriptorFiles) {
-        KerberosServiceDescriptor[] serviceDescriptors = kerberosServiceDescriptorFactory.createInstances(file);
-
-        if (serviceDescriptors != null) {
-          for (KerberosServiceDescriptor serviceDescriptor : serviceDescriptors) {
-            kerberosDescriptor.putService(serviceDescriptor);
-          }
-        }
-      }
-    }
-
-    return kerberosDescriptor;
-  }
-
   private StackVersionRequest getRequest(Map<String, Object> properties) {
     return new StackVersionRequest(
         (String) properties.get(STACK_NAME_PROPERTY_ID),

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/RemovableIdentities.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/RemovableIdentities.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/RemovableIdentities.java
index d4bb501..66bf7b3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/RemovableIdentities.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/RemovableIdentities.java
@@ -58,7 +58,7 @@ public class RemovableIdentities {
     if (cluster.getSecurityType() != SecurityType.KERBEROS) {
       return RemovableIdentities.none();
     }
-    KerberosServiceDescriptor serviceDescriptor = kerberosHelper.getKerberosDescriptor(cluster).getService(event.getServiceName());
+    KerberosServiceDescriptor serviceDescriptor = kerberosHelper.getKerberosDescriptor(cluster, false).getService(event.getServiceName());
     if (serviceDescriptor == null) {
       return RemovableIdentities.none();
     }
@@ -77,7 +77,7 @@ public class RemovableIdentities {
     if (cluster.getSecurityType() != SecurityType.KERBEROS) {
       return RemovableIdentities.none();
     }
-    KerberosServiceDescriptor serviceDescriptor = kerberosHelper.getKerberosDescriptor(cluster).getService(event.getServiceName());
+    KerberosServiceDescriptor serviceDescriptor = kerberosHelper.getKerberosDescriptor(cluster, false).getService(event.getServiceName());
     if (serviceDescriptor == null) {
       return RemovableIdentities.none();
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/UsedIdentities.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/UsedIdentities.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/UsedIdentities.java
index 46f5642..2f0974e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/UsedIdentities.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/UsedIdentities.java
@@ -50,7 +50,7 @@ public class UsedIdentities {
    */
   public static UsedIdentities populate(Cluster cluster, ServiceExclude serviceExclude, ComponentExclude componentExclude, KerberosHelper kerberosHelper) throws AmbariException {
     List<KerberosIdentityDescriptor> result = new ArrayList<>();
-    KerberosDescriptor root = kerberosHelper.getKerberosDescriptor(cluster);
+    KerberosDescriptor root = kerberosHelper.getKerberosDescriptor(cluster, false);
     result.addAll(nullToEmpty(root.getIdentities()));
     for (Service service : cluster.getServices().values()) {
       if (serviceExclude.shouldExclude(service.getName())) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionManager.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionManager.java b/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionManager.java
index 1f2d26f..dde2647 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionManager.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/customactions/ActionDefinitionManager.java
@@ -34,8 +34,8 @@ import javax.xml.bind.Unmarshaller;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.ActionType;
 import org.apache.ambari.server.actionmanager.TargetHostType;
-import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.security.authorization.RoleAuthorization;
+import org.apache.ambari.server.stack.StackDirectory;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -93,7 +93,7 @@ public class ActionDefinitionManager {
     }
 
     File[] customActionDefinitionFiles
-        = customActionDefinitionRoot.listFiles(AmbariMetaInfo.FILENAME_FILTER);
+        = customActionDefinitionRoot.listFiles(StackDirectory.FILENAME_FILTER);
 
     if (customActionDefinitionFiles != null) {
       for (File definitionFile : customActionDefinitionFiles) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
index dd2b223..d6b8ffc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
@@ -152,7 +152,7 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
               // Calculate the set of configurations to update and replace any variables
               // using the previously calculated Map of configurations for the host.
               kerberosHelper.mergeConfigurations(kerberosConfigurations,
-                  componentDescriptor.getConfigurations(true), currentConfigurations);
+                  componentDescriptor.getConfigurations(true), currentConfigurations, null);
 
               // Add component-level principals (and keytabs)
               kerberosHelper.addIdentities(kerberosIdentityDataFileWriter, componentIdentities,

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
index 2e331bb..c86ffa3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
@@ -135,6 +135,12 @@ public abstract class KerberosServerAction extends AbstractServerAction {
   */
   public static final String INCLUDE_AMBARI_IDENTITY = "include_ambari_identity";
 
+  /**
+   * Keys used in CommandParams from ExecutionCommand to declare how to pre-configure services.
+   * Expected values are, "ALL", "DEFAULT", and "NONE".
+   */
+  public static final String PRECONFIGURE_SERVICES = "preconfigure_services";
+
   private static final Logger LOG = LoggerFactory.getLogger(KerberosServerAction.class);
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bce5782/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PreconfigureServiceType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PreconfigureServiceType.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PreconfigureServiceType.java
new file mode 100644
index 0000000..c843b14
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PreconfigureServiceType.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.serveraction.kerberos;
+
+/**
+ * PreconfigureServiceType enumerates the ways in which services may be pre-configured.
+ */
+public enum PreconfigureServiceType {
+  /**
+   * Preconfigure services that have been explicitly flagged.
+   * <p>
+   * For example, in the Kerberos descriptor using
+   * <code>
+   * "preconfigure" : true
+   * </code>
+   * <p>
+   * For example, declared in the stack-specific kerberos_preconfigure.json file
+   */
+  DEFAULT,
+
+  /**
+   * Preconfigure all services, flagged or not.
+   */
+  ALL,
+
+  /**
+   * Do not preconfiure any services, even if flagged.
+   */
+  NONE
+}


Mime
View raw message