AMBARI-9149. Test principal and keytab required for service check should be 
created as part of kerberos service check action (rlevas)


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

Branch: refs/heads/trunk
Commit: 6a464426a7d96b2e3e733b48b79078adced82eb6
Parents: 9c8650b
Author: Robert Levas <rle...@hortonworks.com>
Authored: Tue Jan 20 05:57:44 2015 -0500
Committer: Robert Levas <rle...@hortonworks.com>
Committed: Tue Jan 20 05:57:50 2015 -0500

----------------------------------------------------------------------
 .../AmbariManagementControllerImpl.java         |  33 +-
 .../server/controller/KerberosHelper.java       | 876 ++++++++++++-------
 .../internal/RequestStageContainer.java         |  20 +-
 .../AmbariCustomCommandExecutionHelperTest.java |  49 +-
 .../BackgroundCustomCommandExecutionTest.java   |  16 +-
 .../server/controller/KerberosHelperTest.java   | 326 ++++++-
 6 files changed, 972 insertions(+), 348 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6a464426/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 512ffdb..a1da3f0 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -2823,12 +2823,31 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
       actionExecutionHelper.validateAction(actionRequest);
     }
 
+    long requestId = actionManager.getNextRequestId();
+    RequestStageContainer requestStageContainer = new RequestStageContainer(
+        requestId,
+        null,
+        requestFactory,
+        actionManager,
+        actionRequest);
+
+    // If the request is to perform the Kerberos service check, set up the 
stages to
+    // ensure that the (cluster-level) smoke user principal and keytab is 
available on all hosts
+    if 
(Role.KERBEROS_SERVICE_CHECK.name().equals(actionRequest.getCommandName())) {
+      Map<String, Collection<String>> serviceComponentFilter = new 
HashMap<String, Collection<String>>();
+      Collection<String> identityFilter = Arrays.asList("/smokeuser");
+
+      serviceComponentFilter.put("KERBEROS", null);
+
+      requestStageContainer = kerberosHelper.ensureIdentities(cluster, null, 
serviceComponentFilter,
+          identityFilter, requestStageContainer);
+    }
+
     ExecuteCommandJson jsons = customCommandExecutionHelper.getCommandJson(
         actionExecContext, cluster);
 
-    Stage stage = createNewStage(0, cluster, actionManager.getNextRequestId(), 
requestContext,
-      jsons.getClusterHostInfo(), jsons.getCommandParamsForStage(),
-        jsons.getHostParamsForStage());
+    Stage stage = createNewStage(requestStageContainer.getLastStageId(), 
cluster, requestId, requestContext,
+        jsons.getClusterHostInfo(), jsons.getCommandParamsForStage(), 
jsons.getHostParamsForStage());
 
     if (actionRequest.isCommand()) {
       
customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, 
stage, requestProperties, false);
@@ -2848,11 +2867,11 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
     List<Stage> stages = rg.getStages();
 
     if (stages != null && !stages.isEmpty()) {
-      actionManager.sendActions(stages, actionRequest);
-      return getRequestStatusResponse(stage.getRequestId());
-    } else {
-      throw new AmbariException("Stage was not created");
+      requestStageContainer.addStages(stages);
     }
+
+    requestStageContainer.persist();
+    return requestStageContainer.getRequestStatusResponse();
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/6a464426/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
index a425e95..18c8e09 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
@@ -115,6 +115,10 @@ public class KerberosHelper {
    */
   private Handler disableKerberosHandler = new DisableKerberosHandler();
 
+  /**
+   * The Handler implementation that provides the logic to ensure the 
existence of principals and keytabs
+   */
+  private Handler createPrincipalsAndKeytabsHandler = new 
CreatePrincipalsAndKeytabsHandler();
 
   /**
    * Toggles Kerberos security to enable it or remove it depending on the 
state of the cluster.
@@ -144,98 +148,49 @@ public class KerberosHelper {
                                               RequestStageContainer 
requestStageContainer)
       throws AmbariException {
 
-    if (cluster == null) {
-      String message = "The cluster object is not available";
-      LOG.error(message);
-      throw new AmbariException(message);
-    }
-
-    Config configClusterEnv = cluster.getDesiredConfigByType("cluster-env");
-    if (configClusterEnv == null) {
-      String message = "The 'cluster-env' configuration is not available";
-      LOG.error(message);
-      throw new AmbariException(message);
-    }
-
-    Map<String, String> clusterEnvProperties = 
configClusterEnv.getProperties();
-    if (clusterEnvProperties == null) {
-      String message = "The 'cluster-env' configuration properties are not 
available";
-      LOG.error(message);
-      throw new AmbariException(message);
-    }
+    KerberosDetails kerberosDetails = getKerberosDetails(cluster);
 
-    String securityEnabled = clusterEnvProperties.get("security_enabled");
-    if ((securityEnabled == null) || securityEnabled.isEmpty()) {
-      LOG.warn("Missing 'securityEnabled' property of cluster-env, unable to 
determine the cluster's security state. This may be ok.");
+    if (kerberosDetails.isSecurityEnabled()) {
+      LOG.info("Configuring Kerberos for realm {} on cluster, {}", 
kerberosDetails.getDefaultRealm(), cluster.getClusterName());
+      requestStageContainer = handle(cluster, kerberosDescriptor, 
kerberosDetails, null, null, requestStageContainer, enableKerberosHandler);
     } else {
-      String defaultRealm = clusterEnvProperties.get("kerberos_domain");
-
-      Config configKrb5Conf = cluster.getDesiredConfigByType("krb5-conf");
-      if (configKrb5Conf == null) {
-        String message = "The 'krb5-conf' configuration is not available";
-        LOG.error(message);
-        throw new AmbariException(message);
-      }
-
-      Map<String, String> krb5ConfProperties = configKrb5Conf.getProperties();
-      if (krb5ConfProperties == null) {
-        String message = "The 'krb5-conf' configuration properties are not 
available";
-        LOG.error(message);
-        throw new AmbariException(message);
-      }
-
-      Config configKerberosEnv = 
cluster.getDesiredConfigByType("kerberos-env");
-      if (configKerberosEnv == null) {
-        String message = "The 'kerberos-env' configuration is not available";
-        LOG.error(message);
-        throw new AmbariException(message);
-      }
-
-      Map<String, String> kerberosEnvProperties = 
configKerberosEnv.getProperties();
-      if (kerberosEnvProperties == null) {
-        String message = "The 'kerberos-env' configuration properties are not 
available";
-        LOG.error(message);
-        throw new AmbariException(message);
-      }
-
-      KDCType kdcType = null;
-      String kdcTypeProperty = kerberosEnvProperties.get("kdc_type");
-      if (kdcTypeProperty == null) {
-        // TODO: (rlevas) Only pull from kerberos-env, this is only for 
transitional purposes (AMBARI 9121)
-        kdcTypeProperty = krb5ConfProperties.get("kdc_type");
-      }
-      if (kdcTypeProperty != null) {
-        try {
-          kdcType = KDCType.translate(kdcTypeProperty);
-        } catch (IllegalArgumentException e) {
-          String message = String.format("Invalid 'kdc_type' value: %s", 
kdcTypeProperty);
-          LOG.error(message);
-          throw new AmbariException(message);
-        }
-      }
-
-      if (kdcType == null) {
-        // Set the KDCType to the the MIT_KDC as a fallback.
-        kdcType = KDCType.MIT_KDC;
-      }
-
-      if ("true".equalsIgnoreCase(securityEnabled)) {
-        LOG.info("Configuring Kerberos for realm {} on cluster, {}", 
defaultRealm, cluster.getClusterName());
-        requestStageContainer = handle(cluster, kerberosDescriptor, 
defaultRealm, kdcType, kerberosEnvProperties, requestStageContainer, 
enableKerberosHandler);
-      } else if ("false".equalsIgnoreCase(securityEnabled)) {
-        LOG.info("Disabling Kerberos from cluster, {}", 
cluster.getClusterName());
-        requestStageContainer = handle(cluster, kerberosDescriptor, 
defaultRealm, kdcType, kerberosEnvProperties, requestStageContainer, 
disableKerberosHandler);
-      } else {
-        String message = String.format("Invalid value for `security_enabled` 
property of cluster-env: %s", securityEnabled);
-        LOG.error(message);
-        throw new AmbariException(message);
-      }
+      LOG.info("Disabling Kerberos from cluster, {}", 
cluster.getClusterName());
+      requestStageContainer = handle(cluster, kerberosDescriptor, 
kerberosDetails, null, null, requestStageContainer, disableKerberosHandler);
     }
 
     return requestStageContainer;
   }
 
   /**
+   * Ensures the set of filtered principals and keytabs exist on the cluster.
+   * <p/>
+   * No configurations will be altered as a result of this operation, however 
principals and keytabs
+   * may be updated or created.
+   *
+   * @param cluster                the relevant Cluster
+   * @param kerberosDescriptor     a KerberosDescriptor containing updates to 
the descriptor already
+   *                               configured for the cluster
+   * @param serviceComponentFilter a Map of service names to component names 
indicating the relevant
+   *                               set of services and components - if null, 
no filter is relevant;
+   *                               if empty, the filter indicates no relevant 
services or components
+   * @param identityFilter         a Collection of identity names indicating 
the relevant identities -
+   *                               if null, no filter is relevant; if empty, 
the filter indicates no
+   *                               relevant identities
+   * @param requestStageContainer  a RequestStageContainer to place generated 
stages, if needed -
+   *                               if null a new RequestStageContainer will be 
created.
+   * @return the updated or a new RequestStageContainer containing the stages 
that need to be
+   * executed to complete this task; or null if no stages need to be executed.
+   * @throws AmbariException
+   */
+  public RequestStageContainer ensureIdentities(Cluster cluster, 
KerberosDescriptor kerberosDescriptor,
+                                                Map<String, 
Collection<String>> serviceComponentFilter,
+                                                Collection<String> 
identityFilter,
+                                                RequestStageContainer 
requestStageContainer) throws AmbariException {
+    return handle(cluster, kerberosDescriptor, getKerberosDetails(cluster), 
serviceComponentFilter, identityFilter,
+        requestStageContainer, createPrincipalsAndKeytabsHandler);
+  }
+
+  /**
    * Performs operations needed to enable to disable Kerberos on the relevant 
cluster.
    * <p/>
    * Iterates through the components installed on the relevant cluster and 
attempts to enable or
@@ -244,13 +199,17 @@ public class KerberosHelper {
    * The supplied Handler instance handles the logic on whether this process 
enables or disables
    * Kerberos.
    *
-   * @param cluster               the relevant Cluster
-   * @param kerberosDescriptor    the (derived) KerberosDescriptor
-   * @param realm                 the default Kerberos realm for the Cluster
-   * @param kdcType               a KDCType declaring the type of the relevant 
KDC
-   * @param kerberosEnvProperties a MAp of key/value pairs from the 
kerberos-env configuration
-   * @param requestStageContainer a RequestStageContainer to place generated 
stages, if needed -
-   *                              if null a new RequestStageContainer will be 
created.
+   * @param cluster                the relevant Cluster
+   * @param kerberosDescriptor     the (derived) KerberosDescriptor
+   * @param kerberosDetails        a KerberosDetails containing information 
about relevant Kerberos configuration
+   * @param serviceComponentFilter a Map of service names to component names 
indicating the relevant
+   *                               set of services and components - if null, 
no filter is relevant;
+   *                               if empty, the filter indicates no relevant 
services or components
+   * @param identityFilter         a Collection of identity names indicating 
the relevant identities -
+   *                               if null, no filter is relevant; if empty, 
the filter indicates no
+   *                               relevant identities
+   * @param requestStageContainer  a RequestStageContainer to place generated 
stages, if needed -
+   *                               if null a new RequestStageContainer will be 
created.
    * @return the updated or a new RequestStageContainer containing the stages 
that need to be
    * executed to complete this task; or null if no stages need to be executed.
    * @throws AmbariException
@@ -258,8 +217,10 @@ public class KerberosHelper {
   @Transactional
   private RequestStageContainer handle(Cluster cluster,
                                        KerberosDescriptor kerberosDescriptor,
-                                       String realm, KDCType kdcType,
-                                       Map<String, String> 
kerberosEnvProperties, RequestStageContainer requestStageContainer,
+                                       KerberosDetails kerberosDetails,
+                                       Map<String, Collection<String>> 
serviceComponentFilter,
+                                       Collection<String> identityFilter,
+                                       RequestStageContainer 
requestStageContainer,
                                        Handler handler) throws AmbariException 
{
 
     Map<String, Service> services = cluster.getServices();
@@ -330,6 +291,7 @@ public class KerberosHelper {
                 // Add the current hostname under "host" and "hostname"
                 generalProperties.put("host", hostname);
                 generalProperties.put("hostname", hostname);
+                generalProperties.put("cluster_name", clusterName);
 
                 if (configurations.get("") == null) {
                   configurations.put("", generalProperties);
@@ -342,47 +304,55 @@ public class KerberosHelper {
                 // keytab files, and configurations need to be created or 
updated.
                 for (ServiceComponentHost sch : serviceComponentHosts) {
                   String serviceName = sch.getServiceName();
-                  KerberosServiceDescriptor serviceDescriptor = 
kerberosDescriptor.getService(serviceName);
-
-                  if (serviceDescriptor != null) {
-                    KerberosComponentDescriptor componentDescriptor = 
serviceDescriptor.getComponent(sch.getServiceComponentName());
-                    List<KerberosIdentityDescriptor> serviceIdentities = 
serviceDescriptor.getIdentities(true);
-
-                    if (componentDescriptor != null) {
-                      List<KerberosIdentityDescriptor> componentIdentities = 
componentDescriptor.getIdentities(true);
-                      int identitiesAdded = 0;
-
-                      // Test to see if this component should be process by 
querying the handler
-                      if (handler.shouldProcess(desiredSecurityState, sch)) {
-                        // Calculate the set of configurations to update and 
replace any variables
-                        // using the previously calculated Map of 
configurations for the host.
-                        mergeConfigurations(kerberosConfigurations,
-                            componentDescriptor.getConfigurations(true), 
configurations);
-
-                        // Lazily create the KerberosActionDataFileBuilder 
instance...
-                        if (kerberosActionDataFileBuilder == null) {
-                          kerberosActionDataFileBuilder = new 
KerberosActionDataFileBuilder(indexFile);
-                        }
 
-                        // Add service-level principals (and keytabs)
-                        identitiesAdded += 
addIdentities(kerberosActionDataFileBuilder,
-                            serviceIdentities, sch, configurations);
+                  // 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) {
+                      String componentName = sch.getServiceComponentName();
+
+                      // If there is no filter or the filter contains the 
current component name,
+                      // test to see if this component should be process by 
querying the handler...
+                      if (((componentFilter == null) || 
componentFilter.contains(componentName)) && 
handler.shouldProcess(desiredSecurityState, sch)) {
+                        KerberosComponentDescriptor componentDescriptor = 
serviceDescriptor.getComponent(componentName);
+                        List<KerberosIdentityDescriptor> serviceIdentities = 
serviceDescriptor.getIdentities(true);
+
+                        if (componentDescriptor != null) {
+                          List<KerberosIdentityDescriptor> componentIdentities 
= componentDescriptor.getIdentities(true);
+                          int identitiesAdded = 0;
+
+                          // Calculate the set of configurations to update and 
replace any variables
+                          // using the previously calculated Map of 
configurations for the host.
+                          mergeConfigurations(kerberosConfigurations,
+                              componentDescriptor.getConfigurations(true), 
configurations);
+
+                          // Lazily create the KerberosActionDataFileBuilder 
instance...
+                          if (kerberosActionDataFileBuilder == null) {
+                            kerberosActionDataFileBuilder = new 
KerberosActionDataFileBuilder(indexFile);
+                          }
+
+                          // Add service-level principals (and keytabs)
+                          identitiesAdded += 
addIdentities(kerberosActionDataFileBuilder, serviceIdentities,
+                              identityFilter, hostname, serviceName, 
componentName, configurations);
+
+                          // Add component-level principals (and keytabs)
+                          identitiesAdded += 
addIdentities(kerberosActionDataFileBuilder, componentIdentities,
+                              identityFilter, hostname, serviceName, 
componentName, configurations);
 
-                        // Add component-level principals (and keytabs)
-                        identitiesAdded += 
addIdentities(kerberosActionDataFileBuilder,
-                            componentIdentities, sch, configurations);
+                          if (identitiesAdded > 0) {
+                            serviceComponentHostsToProcess.add(sch);
+                          }
 
-                        if (identitiesAdded > 0) {
-                          serviceComponentHostsToProcess.add(sch);
+                          // Add component-level principals to auth_to_local 
builder
+                          addIdentities(authToLocalBuilder, 
componentIdentities, identityFilter, configurations);
                         }
-                      }
 
-                      // Add component-level principals to auth_to_local 
builder
-                      addIdentities(authToLocalBuilder, componentIdentities, 
configurations);
+                        // Add service-level principals to auth_to_local 
builder
+                        addIdentities(authToLocalBuilder, serviceIdentities, 
identityFilter, configurations);
+                      }
                     }
-
-                    // Add service-level principals to auth_to_local builder
-                    addIdentities(authToLocalBuilder, serviceIdentities, 
configurations);
                   }
                 }
               }
@@ -420,7 +390,7 @@ public class KerberosHelper {
                       "}"
               );
             } else {
-              KerberosOperationHandler operationHandler = 
kerberosOperationHandlerFactory.getKerberosOperationHandler(kdcType);
+              KerberosOperationHandler operationHandler = 
kerberosOperationHandlerFactory.getKerberosOperationHandler(kerberosDetails.getKdcType());
 
               if (operationHandler == null) {
                 throw new AmbariException("Failed to get an appropriate 
Kerberos operation handler.");
@@ -429,7 +399,7 @@ public class KerberosHelper {
                 KerberosCredential kerberosCredentials = 
KerberosCredential.decrypt(credentials, key);
 
                 try {
-                  operationHandler.open(kerberosCredentials, realm, 
kerberosEnvProperties);
+                  operationHandler.open(kerberosCredentials, 
kerberosDetails.getDefaultRealm(), kerberosDetails.getKerberosEnvProperties());
                   if (!operationHandler.testAdministratorCredentials()) {
                     throw new IllegalArgumentException(
                         "Invalid KDC administrator credentials.\n" +
@@ -487,7 +457,7 @@ public class KerberosHelper {
             for (Map.Entry<String, String> entry : configuration.entrySet()) {
               if ("_AUTH_TO_LOCAL_RULES".equals(entry.getValue())) {
                 if (authToLocal == null) {
-                  authToLocal = authToLocalBuilder.generate(realm);
+                  authToLocal = 
authToLocalBuilder.generate(kerberosDetails.getDefaultRealm());
                 }
 
                 entry.setValue(authToLocal);
@@ -520,16 +490,15 @@ public class KerberosHelper {
         }
 
         // Use the handler implementation to setup the relevant stages.
-        int lastStageId = handler.createStages(cluster, hosts, 
kerberosConfigurations,
-            clusterHostInfoJson, hostParamsJson, event, roleCommandOrder, 
realm, kdcType,
-            dataDirectory, requestStageContainer, 
serviceComponentHostsToProcess);
+        handler.createStages(cluster, hosts, kerberosConfigurations, 
clusterHostInfoJson,
+            hostParamsJson, event, roleCommandOrder, kerberosDetails, 
dataDirectory,
+            requestStageContainer, serviceComponentHostsToProcess);
 
         // Add the cleanup stage...
-
         Map<String, String> commandParameters = new HashMap<String, String>();
         commandParameters.put(KerberosServerAction.DATA_DIRECTORY, 
dataDirectory.getAbsolutePath());
 
-        Stage stage = createServerActionStage(++lastStageId,
+        Stage stage = 
createServerActionStage(requestStageContainer.getLastStageId(),
             cluster,
             requestStageContainer.getId(),
             "Finalize Operations",
@@ -549,14 +518,25 @@ public class KerberosHelper {
         for (ServiceComponentHost sch : serviceComponentHostsToProcess) {
           // Update the desired and current states for the ServiceComponentHost
           // using new state information from the the handler implementation
-          sch.setDesiredSecurityState(handler.getNewDesiredSCHSecurityState());
-          sch.setSecurityState(handler.getNewSCHSecurityState());
+          SecurityState newSecurityState;
+
+          newSecurityState = handler.getNewDesiredSCHSecurityState();
+          if (newSecurityState != null) {
+            sch.setDesiredSecurityState(newSecurityState);
+          }
+
+          newSecurityState = handler.getNewSCHSecurityState();
+          if (newSecurityState != null) {
+            sch.setSecurityState(newSecurityState);
+          }
         }
       }
 
       // If all goes well, set all services to _desire_ to be secured or 
unsecured, depending on handler
-      for (Service service : services.values()) {
-        service.setSecurityState(desiredSecurityState);
+      if (desiredSecurityState != null) {
+        for (Service service : services.values()) {
+          service.setSecurityState(desiredSecurityState);
+        }
       }
     }
 
@@ -564,6 +544,108 @@ public class KerberosHelper {
   }
 
   /**
+   * Gathers the Kerberos-related data from configurations and stores it in a 
new KerberosDetails
+   * instance.
+   *
+   * @param cluster the relevant Cluster
+   * @return a new KerberosDetails with the collected configuration data
+   * @throws AmbariException
+   */
+  private KerberosDetails getKerberosDetails(Cluster cluster) throws 
AmbariException {
+    KerberosDetails kerberosDetails = new KerberosDetails();
+
+    if (cluster == null) {
+      String message = "The cluster object is not available";
+      LOG.error(message);
+      throw new AmbariException(message);
+    }
+
+    Config configClusterEnv = cluster.getDesiredConfigByType("cluster-env");
+    if (configClusterEnv == null) {
+      String message = "The 'cluster-env' configuration is not available";
+      LOG.error(message);
+      throw new AmbariException(message);
+    }
+
+    Map<String, String> clusterEnvProperties = 
configClusterEnv.getProperties();
+    if (clusterEnvProperties == null) {
+      String message = "The 'cluster-env' configuration properties are not 
available";
+      LOG.error(message);
+      throw new AmbariException(message);
+    }
+
+    String securityEnabled = clusterEnvProperties.get("security_enabled");
+    if ((securityEnabled == null) || securityEnabled.isEmpty()) {
+      String message = "Missing 'securityEnabled' property of cluster-env, 
unable to determine the cluster's security state";
+      LOG.error(message);
+      throw new AmbariException(message);
+    }
+
+    if ("true".equalsIgnoreCase(securityEnabled)) {
+      kerberosDetails.setSecurityEnabled(true);
+    } else if ("false".equalsIgnoreCase(securityEnabled)) {
+      kerberosDetails.setSecurityEnabled(false);
+    } else {
+      String message = String.format("Invalid value for `security_enabled` 
property of cluster-env: %s", securityEnabled);
+      LOG.error(message);
+      throw new AmbariException(message);
+    }
+
+    Config configKrb5Conf = cluster.getDesiredConfigByType("krb5-conf");
+    if (configKrb5Conf == null) {
+      String message = "The 'krb5-conf' configuration is not available";
+      LOG.error(message);
+      throw new AmbariException(message);
+    }
+
+    Map<String, String> krb5ConfProperties = configKrb5Conf.getProperties();
+    if (krb5ConfProperties == null) {
+      String message = "The 'krb5-conf' configuration properties are not 
available";
+      LOG.error(message);
+      throw new AmbariException(message);
+    }
+
+    Config configKerberosEnv = cluster.getDesiredConfigByType("kerberos-env");
+    if (configKerberosEnv == null) {
+      String message = "The 'kerberos-env' configuration is not available";
+      LOG.error(message);
+      throw new AmbariException(message);
+    }
+
+    Map<String, String> kerberosEnvProperties = 
configKerberosEnv.getProperties();
+    if (kerberosEnvProperties == null) {
+      String message = "The 'kerberos-env' configuration properties are not 
available";
+      LOG.error(message);
+      throw new AmbariException(message);
+    }
+
+    KDCType kdcType = null;
+    String kdcTypeProperty = kerberosEnvProperties.get("kdc_type");
+    if (kdcTypeProperty == null) {
+      // TODO: (rlevas) Only pull from kerberos-env, this is only for 
transitional purposes (AMBARI 9121)
+      kdcTypeProperty = krb5ConfProperties.get("kdc_type");
+    }
+    if (kdcTypeProperty != null) {
+      try {
+        kdcType = KDCType.translate(kdcTypeProperty);
+      } catch (IllegalArgumentException e) {
+        String message = String.format("Invalid 'kdc_type' value: %s", 
kdcTypeProperty);
+        LOG.error(message);
+        throw new AmbariException(message);
+      }
+    }
+
+    
kerberosDetails.setDefaultRealm(clusterEnvProperties.get("kerberos_domain"));
+
+    // Set the KDCType to the the MIT_KDC as a fallback.
+    kerberosDetails.setKdcType((kdcType == null) ? KDCType.MIT_KDC : kdcType);
+
+    kerberosDetails.setKerberosEnvProperties(kerberosEnvProperties);
+
+    return kerberosDetails;
+  }
+
+  /**
    * Creates a temporary directory within the system temporary directory
    * <p/>
    * The resulting directory is to be removed by the caller when desired.
@@ -684,63 +766,74 @@ public class KerberosHelper {
    *                                      records
    * @param identities                    a List of 
KerberosIdentityDescriptors to add to the data
    *                                      file
-   * @param sch                           the relevant ServiceComponentHost
+   * @param identityFilter                a Collection of identity names 
indicating the relevant identities -
+   *                                      if null, no filter is relevant; if 
empty, the filter indicates no
+   *                                      relevant identities
+   * @param hostname                      the relevant hostname
+   * @param serviceName                   the relevant service name
+   * @param componentName                 the relevant component name
    * @param configurations                a Map of configurations to use a 
replacements for variables
    *                                      in identity fields
    * @return an integer indicating the number of identities added to the data 
file
    * @throws java.io.IOException if an error occurs while writing a record to 
the data file
    */
   private int addIdentities(KerberosActionDataFileBuilder 
kerberosActionDataFileBuilder,
-                            List<KerberosIdentityDescriptor> identities, 
ServiceComponentHost sch,
-                            Map<String, Map<String, String>> configurations) 
throws IOException {
+                            Collection<KerberosIdentityDescriptor> identities,
+                            Collection<String> identityFilter, String 
hostname, String serviceName,
+                            String componentName, Map<String, Map<String, 
String>> configurations)
+      throws IOException {
     int identitiesAdded = 0;
 
     if (identities != null) {
       for (KerberosIdentityDescriptor identity : identities) {
-        KerberosPrincipalDescriptor principalDescriptor = 
identity.getPrincipalDescriptor();
-        String principal = null;
-        String principalType = null;
-        String principalConfiguration = null;
-
-        if (principalDescriptor != null) {
-          principal = 
KerberosDescriptor.replaceVariables(principalDescriptor.getValue(), 
configurations);
-          principalType = principalDescriptor.getType().name().toLowerCase();
-          principalConfiguration = 
KerberosDescriptor.replaceVariables(principalDescriptor.getConfiguration(), 
configurations);
-        }
-
-        if (principal != null) {
-          KerberosKeytabDescriptor keytabDescriptor = 
identity.getKeytabDescriptor();
-          String keytabFilePath = null;
-          String keytabFileOwnerName = null;
-          String keytabFileOwnerAccess = null;
-          String keytabFileGroupName = null;
-          String keytabFileGroupAccess = null;
-          String keytabFileConfiguration = null;
-
-          if (keytabDescriptor != null) {
-            keytabFilePath = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getFile(), configurations);
-            keytabFileOwnerName = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getOwnerName(), 
configurations);
-            keytabFileOwnerAccess = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getOwnerAccess(), 
configurations);
-            keytabFileGroupName = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getGroupName(), 
configurations);
-            keytabFileGroupAccess = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getGroupAccess(), 
configurations);
-            keytabFileConfiguration = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getConfiguration(), 
configurations);
+        // If there is no filter or the filter contains the current identity's 
name...
+        if ((identityFilter == null) || 
identityFilter.contains(identity.getName())) {
+          KerberosPrincipalDescriptor principalDescriptor = 
identity.getPrincipalDescriptor();
+          String principal = null;
+          String principalType = null;
+          String principalConfiguration = null;
+
+          if (principalDescriptor != null) {
+            principal = 
KerberosDescriptor.replaceVariables(principalDescriptor.getValue(), 
configurations);
+            principalType = principalDescriptor.getType().name().toLowerCase();
+            principalConfiguration = 
KerberosDescriptor.replaceVariables(principalDescriptor.getConfiguration(), 
configurations);
           }
 
-          // Append an entry to the action data file builder...
-          kerberosActionDataFileBuilder.addRecord(sch.getHostName(),
-              sch.getServiceName(),
-              sch.getServiceComponentName(),
-              principal,
-              principalType,
-              principalConfiguration,
-              keytabFilePath,
-              keytabFileOwnerName,
-              keytabFileOwnerAccess,
-              keytabFileGroupName,
-              keytabFileGroupAccess,
-              keytabFileConfiguration);
-
-          identitiesAdded++;
+          if (principal != null) {
+            KerberosKeytabDescriptor keytabDescriptor = 
identity.getKeytabDescriptor();
+            String keytabFilePath = null;
+            String keytabFileOwnerName = null;
+            String keytabFileOwnerAccess = null;
+            String keytabFileGroupName = null;
+            String keytabFileGroupAccess = null;
+            String keytabFileConfiguration = null;
+
+            if (keytabDescriptor != null) {
+              keytabFilePath = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getFile(), configurations);
+              keytabFileOwnerName = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getOwnerName(), 
configurations);
+              keytabFileOwnerAccess = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getOwnerAccess(), 
configurations);
+              keytabFileGroupName = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getGroupName(), 
configurations);
+              keytabFileGroupAccess = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getGroupAccess(), 
configurations);
+              keytabFileConfiguration = 
KerberosDescriptor.replaceVariables(keytabDescriptor.getConfiguration(), 
configurations);
+            }
+
+            // Append an entry to the action data file builder...
+            kerberosActionDataFileBuilder.addRecord(
+                hostname,
+                serviceName,
+                componentName,
+                principal,
+                principalType,
+                principalConfiguration,
+                keytabFilePath,
+                keytabFileOwnerName,
+                keytabFileOwnerAccess,
+                keytabFileGroupName,
+                keytabFileGroupAccess,
+                keytabFileConfiguration);
+
+            identitiesAdded++;
+          }
         }
       }
     }
@@ -753,20 +846,26 @@ public class KerberosHelper {
    *
    * @param authToLocalBuilder the AuthToLocalBuilder to use to build the 
auth_to_local mapping
    * @param identities         a List of KerberosIdentityDescriptors to process
+   * @param identityFilter     a Collection of identity names indicating the 
relevant identities -
+   *                           if null, no filter is relevant; if empty, the 
filter indicates no
+   *                           relevant identities
    * @param configurations     a Map of configurations to use a replacements 
for variables
    *                           in identity fields
    * @throws org.apache.ambari.server.AmbariException
    */
   private void addIdentities(AuthToLocalBuilder authToLocalBuilder,
-                             List<KerberosIdentityDescriptor> identities,
+                             List<KerberosIdentityDescriptor> identities, 
Collection<String> identityFilter,
                              Map<String, Map<String, String>> configurations) 
throws AmbariException {
     if (identities != null) {
       for (KerberosIdentityDescriptor identity : identities) {
-        KerberosPrincipalDescriptor principalDescriptor = 
identity.getPrincipalDescriptor();
-        if (principalDescriptor != null) {
-          authToLocalBuilder.append(
-              
KerberosDescriptor.replaceVariables(principalDescriptor.getValue(), 
configurations),
-              
KerberosDescriptor.replaceVariables(principalDescriptor.getLocalUsername(), 
configurations));
+        // If there is no filter or the filter contains the current identity's 
name...
+        if ((identityFilter == null) || 
identityFilter.contains(identity.getName())) {
+          KerberosPrincipalDescriptor principalDescriptor = 
identity.getPrincipalDescriptor();
+          if (principalDescriptor != null) {
+            authToLocalBuilder.append(
+                
KerberosDescriptor.replaceVariables(principalDescriptor.getValue(), 
configurations),
+                
KerberosDescriptor.replaceVariables(principalDescriptor.getLocalUsername(), 
configurations));
+          }
         }
       }
     }
@@ -961,7 +1060,7 @@ public class KerberosHelper {
    * Handler is an interface that needs to be implemented by toggle handler 
classes to do the
    * "right" thing for the task at hand.
    */
-  private interface Handler {
+  private abstract class Handler {
     /**
      * Tests the Service and ServiceComponentHost to see if they are in the 
appropriate security
      * state to be processed for the relevant task.
@@ -972,29 +1071,32 @@ public class KerberosHelper {
      * state to be processed; otherwise false
      * @throws AmbariException of an error occurs while testing
      */
-    boolean shouldProcess(SecurityState desiredSecurityState, 
ServiceComponentHost sch) throws AmbariException;
+    abstract boolean shouldProcess(SecurityState desiredSecurityState, 
ServiceComponentHost sch) throws AmbariException;
 
     /**
      * Returns the new SecurityState to be set as the ServiceComponentHost's 
_desired_ SecurityState.
      *
-     * @return a SecurityState to be set as the ServiceComponentHost's 
_desired_ SecurityState
+     * @return a SecurityState to be set as the ServiceComponentHost's 
_desired_ SecurityState;
+     * or null if no state change is desired
      */
-    SecurityState getNewDesiredSCHSecurityState();
+    abstract SecurityState getNewDesiredSCHSecurityState();
 
     /**
      * Returns the new SecurityState to be set as the ServiceComponentHost's 
_current_ SecurityState.
      *
-     * @return a SecurityState to be set as the ServiceComponentHost's 
_current_ SecurityState
+     * @return a SecurityState to be set as the ServiceComponentHost's 
_current_ SecurityState;
+     * or null if no state change is desired
      */
-    SecurityState getNewSCHSecurityState();
+    abstract SecurityState getNewSCHSecurityState();
 
 
     /**
      * Returns the new SecurityState to be set as the Service's SecurityState.
      *
-     * @return a SecurityState to be set as the Service's SecurityState
+     * @return a SecurityState to be set as the Service's SecurityState;
+     * or null if no state change is desired
      */
-    SecurityState getNewServiceSecurityState();
+    abstract SecurityState getNewServiceSecurityState();
 
     /**
      * Creates the necessary stages to complete the relevant task and stores 
them in the supplied
@@ -1012,8 +1114,7 @@ public class KerberosHelper {
      * @param hostParams             JSON-encoded host parameters
      * @param event                  a ServiceComponentHostServerActionEvent 
to pass to any created tasks
      * @param roleCommandOrder       the RoleCommandOrder to use to generate 
the RoleGraph for any newly created Stages
-     * @param realm                  a String declaring the cluster's Kerberos 
realm
-     * @param kdcType                a KDCType declaring the type of the 
relevant KDC
+     * @param kerberosDetails        a KerberosDetails containing the 
information about the relevant Kerberos configuration
      * @param dataDirectory          a File pointing to the (temporary) data 
directory
      * @param requestStageContainer  a RequestStageContainer to store the new 
stages in, if null a
      *                               new RequestStageContainer will be created
@@ -1021,16 +1122,119 @@ public class KerberosHelper {
      * @return the last stage id generated, or -1 if no stages were created
      * @throws AmbariException if an error occurs while creating the relevant 
stages
      */
-    int createStages(Cluster cluster, Map<String, Host> hosts,
-                     Map<String, Map<String, String>> kerberosConfigurations,
-                     String clusterHostInfo, String hostParams,
-                     ServiceComponentHostServerActionEvent event,
-                     RoleCommandOrder roleCommandOrder,
-                     String realm, KDCType kdcType, File dataDirectory,
-                     RequestStageContainer requestStageContainer,
-                     List<ServiceComponentHost> serviceComponentHosts)
+    abstract long createStages(Cluster cluster, Map<String, Host> hosts,
+                               Map<String, Map<String, String>> 
kerberosConfigurations,
+                               String clusterHostInfo, String hostParams,
+                               ServiceComponentHostServerActionEvent event,
+                               RoleCommandOrder roleCommandOrder,
+                               KerberosDetails kerberosDetails, File 
dataDirectory,
+                               RequestStageContainer requestStageContainer,
+                               List<ServiceComponentHost> 
serviceComponentHosts)
         throws AmbariException;
 
+
+    public void addCreatePrincipalsStage(Cluster cluster, String 
clusterHostInfoJson,
+                                         String hostParamsJson, 
ServiceComponentHostServerActionEvent event,
+                                         Map<String, String> commandParameters,
+                                         RoleCommandOrder roleCommandOrder, 
RequestStageContainer requestStageContainer)
+        throws AmbariException {
+      Stage stage = 
createServerActionStage(requestStageContainer.getLastStageId(),
+          cluster,
+          requestStageContainer.getId(),
+          "Create Principals",
+          clusterHostInfoJson,
+          "{}",
+          hostParamsJson,
+          CreatePrincipalsServerAction.class,
+          event,
+          commandParameters,
+          "Create Principals",
+          1200);
+
+      RoleGraph roleGraph = new RoleGraph(roleCommandOrder);
+      roleGraph.build(stage);
+      requestStageContainer.addStages(roleGraph.getStages());
+    }
+
+    public void addCreateKeytabFilesStage(Cluster cluster, String 
clusterHostInfoJson,
+                                          String hostParamsJson, 
ServiceComponentHostServerActionEvent event,
+                                          Map<String, String> 
commandParameters,
+                                          RoleCommandOrder roleCommandOrder, 
RequestStageContainer requestStageContainer)
+        throws AmbariException {
+      Stage stage = 
createServerActionStage(requestStageContainer.getLastStageId(),
+          cluster,
+          requestStageContainer.getId(),
+          "Create Keytabs",
+          clusterHostInfoJson,
+          "{}",
+          hostParamsJson,
+          CreateKeytabFilesServerAction.class,
+          event,
+          commandParameters,
+          "Create Keytabs",
+          1200);
+
+      RoleGraph roleGraph = new RoleGraph(roleCommandOrder);
+      roleGraph.build(stage);
+      requestStageContainer.addStages(roleGraph.getStages());
+    }
+
+    public void addDistributeKeytabFilesStage(Cluster cluster, 
List<ServiceComponentHost> serviceComponentHosts,
+                                              String clusterHostInfoJson, 
String hostParamsJson,
+                                              Map<String, String> 
commandParameters,
+                                              RoleCommandOrder 
roleCommandOrder,
+                                              RequestStageContainer 
requestStageContainer)
+        throws AmbariException {
+      Stage stage = createNewStage(requestStageContainer.getLastStageId(),
+          cluster,
+          requestStageContainer.getId(),
+          "Distribute Keytabs",
+          clusterHostInfoJson,
+          StageUtils.getGson().toJson(commandParameters),
+          hostParamsJson);
+
+      if (!serviceComponentHosts.isEmpty()) {
+        List<String> hostsToUpdate = 
createUniqueHostList(serviceComponentHosts);
+        Map<String, String> requestParams = new HashMap<String, String>();
+        List<RequestResourceFilter> requestResourceFilters = new 
ArrayList<RequestResourceFilter>();
+        RequestResourceFilter reqResFilter = new 
RequestResourceFilter("KERBEROS", "KERBEROS_CLIENT", hostsToUpdate);
+        requestResourceFilters.add(reqResFilter);
+
+        ActionExecutionContext actionExecContext = new ActionExecutionContext(
+            cluster.getClusterName(),
+            "SET_KEYTAB",
+            requestResourceFilters,
+            requestParams);
+        
customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, 
stage, requestParams, false);
+      }
+
+      RoleGraph roleGraph = new RoleGraph(roleCommandOrder);
+      roleGraph.build(stage);
+      requestStageContainer.addStages(roleGraph.getStages());
+    }
+
+    public void addUpdateConfigurationsStage(Cluster cluster, String 
clusterHostInfoJson,
+                                             String hostParamsJson, 
ServiceComponentHostServerActionEvent event,
+                                             Map<String, String> 
commandParameters,
+                                             RoleCommandOrder 
roleCommandOrder, RequestStageContainer requestStageContainer)
+        throws AmbariException {
+      Stage stage = 
createServerActionStage(requestStageContainer.getLastStageId(),
+          cluster,
+          requestStageContainer.getId(),
+          "Update Configurations",
+          clusterHostInfoJson,
+          "{}",
+          hostParamsJson,
+          UpdateKerberosConfigsServerAction.class,
+          event,
+          commandParameters,
+          "Update Service Configurations",
+          1200);
+
+      RoleGraph roleGraph = new RoleGraph(roleCommandOrder);
+      roleGraph.build(stage);
+      requestStageContainer.addStages(roleGraph.getStages());
+    }
   }
 
   /**
@@ -1047,10 +1251,9 @@ public class KerberosHelper {
    * <li>create keytab files</li>
    * <li>distribute keytab files to the appropriate hosts</li>
    * <li>update relevant configurations</li>
-   * <li>restart services</li>
    * </ol>
    */
-  private class EnableKerberosHandler implements Handler {
+  private class EnableKerberosHandler extends Handler {
     @Override
     public boolean shouldProcess(SecurityState desiredSecurityState, 
ServiceComponentHost sch) throws AmbariException {
       return (desiredSecurityState == SecurityState.SECURED_KERBEROS) &&
@@ -1075,24 +1278,19 @@ public class KerberosHelper {
     }
 
     @Override
-    public int createStages(Cluster cluster, Map<String, Host> hosts,
-                            Map<String, Map<String, String>> 
kerberosConfigurations,
-                            String clusterHostInfoJson, String hostParamsJson,
-                            ServiceComponentHostServerActionEvent event,
-                            RoleCommandOrder roleCommandOrder, String realm, 
KDCType kdcType,
-                            File dataDirectory, RequestStageContainer 
requestStageContainer,
-                            List<ServiceComponentHost> serviceComponentHosts)
+    public long createStages(Cluster cluster, Map<String, Host> hosts,
+                             Map<String, Map<String, String>> 
kerberosConfigurations,
+                             String clusterHostInfoJson, String hostParamsJson,
+                             ServiceComponentHostServerActionEvent event,
+                             RoleCommandOrder roleCommandOrder, 
KerberosDetails kerberosDetails,
+                             File dataDirectory, RequestStageContainer 
requestStageContainer,
+                             List<ServiceComponentHost> serviceComponentHosts)
         throws AmbariException {
       // If there are principals, keytabs, and configurations to process, 
setup the following sages:
       //  1) generate principals
       //  2) generate keytab files
       //  3) distribute keytab files
       //  4) update configurations
-      //  4) restart services
-
-      RoleGraph roleGraph;
-      Stage stage;
-      int stageId = -1;
 
       // If a RequestStageContainer does not already exist, create a new one...
       if (requestStageContainer == null) {
@@ -1140,95 +1338,31 @@ public class KerberosHelper {
 
       Map<String, String> commandParameters = new HashMap<String, String>();
       commandParameters.put(KerberosServerAction.DATA_DIRECTORY, 
dataDirectory.getAbsolutePath());
-      commandParameters.put(KerberosServerAction.DEFAULT_REALM, realm);
-      commandParameters.put(KerberosServerAction.KDC_TYPE, kdcType.name());
+      commandParameters.put(KerberosServerAction.DEFAULT_REALM, 
kerberosDetails.getDefaultRealm());
+      commandParameters.put(KerberosServerAction.KDC_TYPE, 
kerberosDetails.getKdcType().name());
       commandParameters.put(KerberosServerAction.ADMINISTRATOR_CREDENTIAL, 
getEncryptedAdministratorCredentials(cluster));
 
       // *****************************************************************
       // Create stage to create principals
-      stage = createServerActionStage(++stageId,
-          cluster,
-          requestStageContainer.getId(),
-          "Create Principals",
-          clusterHostInfoJson,
-          "{}",
-          hostParamsJson,
-          CreatePrincipalsServerAction.class,
-          event,
-          commandParameters,
-          "Create Principals",
-          1200);
-
-      roleGraph = new RoleGraph(roleCommandOrder);
-      roleGraph.build(stage);
-      requestStageContainer.addStages(roleGraph.getStages());
+      addCreatePrincipalsStage(cluster, clusterHostInfoJson, hostParamsJson, 
event, commandParameters,
+          roleCommandOrder, requestStageContainer);
 
       // *****************************************************************
       // Create stage to generate keytabs
-      stage = createServerActionStage(++stageId,
-          cluster,
-          requestStageContainer.getId(),
-          "Create Keytabs",
-          clusterHostInfoJson,
-          "{}",
-          hostParamsJson,
-          CreateKeytabFilesServerAction.class,
-          event,
-          commandParameters,
-          "Create Keytabs",
-          1200);
-
-      roleGraph = new RoleGraph(roleCommandOrder);
-      roleGraph.build(stage);
-      requestStageContainer.addStages(roleGraph.getStages());
+      addCreateKeytabFilesStage(cluster, clusterHostInfoJson, hostParamsJson, 
event, commandParameters,
+          roleCommandOrder, requestStageContainer);
 
+      // *****************************************************************
       // Create stage to distribute keytabs
-      stage = createNewStage(++stageId,
-          cluster,
-          requestStageContainer.getId(),
-          "Distribute Keytabs",
-          clusterHostInfoJson,
-          StageUtils.getGson().toJson(commandParameters),
-          hostParamsJson);
-
-      if (!serviceComponentHosts.isEmpty()) {
-        List<String> hostsToUpdate = 
createUniqueHostList(serviceComponentHosts);
-        Map<String, String> requestParams = new HashMap<String, String>();
-        List<RequestResourceFilter> requestResourceFilters = new 
ArrayList<RequestResourceFilter>();
-        RequestResourceFilter reqResFilter = new 
RequestResourceFilter("KERBEROS", "KERBEROS_CLIENT", hostsToUpdate);
-        requestResourceFilters.add(reqResFilter);
-
-        ActionExecutionContext actionExecContext = new ActionExecutionContext(
-            cluster.getClusterName(),
-            "SET_KEYTAB",
-            requestResourceFilters,
-            requestParams);
-        
customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, 
stage, requestParams, false);
-      }
-
-      roleGraph = new RoleGraph(roleCommandOrder);
-      roleGraph.build(stage);
-      requestStageContainer.addStages(roleGraph.getStages());
+      addDistributeKeytabFilesStage(cluster, serviceComponentHosts, 
clusterHostInfoJson, hostParamsJson,
+          commandParameters, roleCommandOrder, requestStageContainer);
 
+      // *****************************************************************
       // Create stage to update configurations of services
-      stage = createServerActionStage(++stageId,
-          cluster,
-          requestStageContainer.getId(),
-          "Update Service Configurations",
-          clusterHostInfoJson,
-          "{}",
-          hostParamsJson,
-          UpdateKerberosConfigsServerAction.class,
-          event,
-          commandParameters,
-          "Update Service Configurations",
-          1200);
-
-      roleGraph = new RoleGraph(roleCommandOrder);
-      roleGraph.build(stage);
-      requestStageContainer.addStages(roleGraph.getStages());
+      addUpdateConfigurationsStage(cluster, clusterHostInfoJson, 
hostParamsJson, event, commandParameters,
+          roleCommandOrder, requestStageContainer);
 
-      return stageId;
+      return requestStageContainer.getLastStageId();
     }
 
   }
@@ -1249,7 +1383,7 @@ public class KerberosHelper {
    * <li>restart services</li>
    * </ol>
    */
-  private class DisableKerberosHandler implements Handler {
+  private class DisableKerberosHandler extends Handler {
     @Override
     public boolean shouldProcess(SecurityState desiredSecurityState, 
ServiceComponentHost sch) throws AmbariException {
       return (desiredSecurityState == SecurityState.UNSECURED) &&
@@ -1274,13 +1408,13 @@ public class KerberosHelper {
     }
 
     @Override
-    public int createStages(Cluster cluster, Map<String, Host> hosts,
-                            Map<String, Map<String, String>> 
kerberosConfigurations,
-                            String clusterHostInfoJson, String hostParamsJson,
-                            ServiceComponentHostServerActionEvent event,
-                            RoleCommandOrder roleCommandOrder, String realm, 
KDCType kdcType,
-                            File dataDirectory, RequestStageContainer 
requestStageContainer,
-                            List<ServiceComponentHost> serviceComponentHosts) {
+    public long createStages(Cluster cluster, Map<String, Host> hosts,
+                             Map<String, Map<String, String>> 
kerberosConfigurations,
+                             String clusterHostInfoJson, String hostParamsJson,
+                             ServiceComponentHostServerActionEvent event,
+                             RoleCommandOrder roleCommandOrder, 
KerberosDetails kerberosDetails,
+                             File dataDirectory, RequestStageContainer 
requestStageContainer,
+                             List<ServiceComponentHost> serviceComponentHosts) 
{
       // TODO (rlevas): If there are principals, keytabs, and configurations 
to process, setup the following sages:
       //  1) remove principals
       //  2) remove keytab files
@@ -1289,4 +1423,130 @@ public class KerberosHelper {
       return -1;
     }
   }
+
+  /**
+   * CreatePrincipalsAndKeytabsHandler is an implementation of the Handler 
interface used to create
+   * principals and keytabs and distribute them throughout the cluster.  This 
is similar to enabling
+   * Kerberos however no states or configurations will be updated.
+   * <p/>
+   * To complete the process, this implementation creates the following stages:
+   * <ol>
+   * <li>create principals</li>
+   * <li>create keytab files</li>
+   * <li>distribute keytab files to the appropriate hosts</li>
+   * </ol>
+   */
+  private class CreatePrincipalsAndKeytabsHandler extends Handler {
+    @Override
+    public boolean shouldProcess(SecurityState desiredSecurityState, 
ServiceComponentHost sch) throws AmbariException {
+      return (maintenanceStateHelper.getEffectiveState(sch) == 
MaintenanceState.OFF);
+    }
+
+    @Override
+    public SecurityState getNewDesiredSCHSecurityState() {
+      return null;
+    }
+
+    @Override
+    public SecurityState getNewSCHSecurityState() {
+      return null;
+    }
+
+    @Override
+    public SecurityState getNewServiceSecurityState() {
+      return null;
+    }
+
+    @Override
+    public long createStages(Cluster cluster, Map<String, Host> hosts,
+                             Map<String, Map<String, String>> 
kerberosConfigurations,
+                             String clusterHostInfoJson, String hostParamsJson,
+                             ServiceComponentHostServerActionEvent event,
+                             RoleCommandOrder roleCommandOrder, 
KerberosDetails kerberosDetails,
+                             File dataDirectory, RequestStageContainer 
requestStageContainer,
+                             List<ServiceComponentHost> serviceComponentHosts)
+        throws AmbariException {
+      // If there are principals and keytabs to process, setup the following 
sages:
+      //  1) generate principals
+      //  2) generate keytab files
+      //  3) distribute keytab files
+
+      // If a RequestStageContainer does not already exist, create a new one...
+      if (requestStageContainer == null) {
+        requestStageContainer = new RequestStageContainer(
+            actionManager.getNextRequestId(),
+            null,
+            requestFactory,
+            actionManager);
+      }
+
+      Map<String, String> commandParameters = new HashMap<String, String>();
+      commandParameters.put(KerberosServerAction.DATA_DIRECTORY, 
dataDirectory.getAbsolutePath());
+      commandParameters.put(KerberosServerAction.DEFAULT_REALM, 
kerberosDetails.getDefaultRealm());
+      commandParameters.put(KerberosServerAction.KDC_TYPE, 
kerberosDetails.getKdcType().name());
+      commandParameters.put(KerberosServerAction.ADMINISTRATOR_CREDENTIAL, 
getEncryptedAdministratorCredentials(cluster));
+
+      // *****************************************************************
+      // Create stage to create principals
+      super.addCreatePrincipalsStage(cluster, clusterHostInfoJson, 
hostParamsJson, event,
+          commandParameters, roleCommandOrder, requestStageContainer);
+
+      // *****************************************************************
+      // Create stage to generate keytabs
+      addCreateKeytabFilesStage(cluster, clusterHostInfoJson, hostParamsJson, 
event,
+          commandParameters, roleCommandOrder, requestStageContainer);
+
+      // Create stage to distribute keytabs
+      addDistributeKeytabFilesStage(cluster, serviceComponentHosts, 
clusterHostInfoJson,
+          hostParamsJson, commandParameters, roleCommandOrder, 
requestStageContainer);
+
+      return requestStageContainer.getLastStageId();
+    }
+  }
+
+
+  /**
+   * KerberosDetails is a helper class to hold the details of the relevant 
Kerberos-specific
+   * configurations so they may be passed around more easily.
+   */
+  private static class KerberosDetails {
+    private boolean securityEnabled;
+    private String defaultRealm;
+    private KDCType kdcType;
+    private Map<String, String> kerberosEnvProperties;
+
+
+    public void setSecurityEnabled(boolean securityEnabled) {
+      this.securityEnabled = securityEnabled;
+    }
+
+    public boolean isSecurityEnabled() {
+      return securityEnabled;
+    }
+
+    public void setDefaultRealm(String defaultRealm) {
+      this.defaultRealm = defaultRealm;
+    }
+
+    public String getDefaultRealm() {
+      return defaultRealm;
+    }
+
+    public void setKdcType(KDCType kdcType) {
+      this.kdcType = kdcType;
+    }
+
+    public KDCType getKdcType() {
+      return kdcType;
+    }
+
+    public void setKerberosEnvProperties(Map<String, String> 
kerberosEnvProperties) {
+      this.kerberosEnvProperties = kerberosEnvProperties;
+    }
+
+    public Map<String, String> getKerberosEnvProperties() {
+      return kerberosEnvProperties;
+    }
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6a464426/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestStageContainer.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestStageContainer.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestStageContainer.java
index 12b7f71..97ee9bd 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestStageContainer.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestStageContainer.java
@@ -25,6 +25,7 @@ import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.Request;
 import org.apache.ambari.server.actionmanager.RequestFactory;
 import org.apache.ambari.server.actionmanager.Stage;
+import org.apache.ambari.server.controller.ExecuteActionRequest;
 import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.ShortTaskStatus;
 import org.apache.ambari.server.state.State;
@@ -62,6 +63,8 @@ public class RequestStageContainer {
 
   private String requestContext = null;
 
+  private ExecuteActionRequest actionRequest = null;
+
   /**
    * Logger
    */
@@ -77,10 +80,25 @@ public class RequestStageContainer {
    * @param manager  action manager
    */
   public RequestStageContainer(Long id, List<Stage> stages, RequestFactory 
factory, ActionManager manager) {
+    this(id, stages, factory, manager, null);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param id            request id
+   * @param stages        stages
+   * @param factory       request factory
+   * @param manager       action manager
+   * @param actionRequest action request
+   */
+  public RequestStageContainer(Long id, List<Stage> stages, RequestFactory 
factory, ActionManager manager,
+                               ExecuteActionRequest actionRequest) {
     this.id = id;
     this.stages = stages == null ? new ArrayList<Stage>() : stages;
     this.requestFactory = factory;
     this.actionManager = manager;
+    this.actionRequest = actionRequest;
   }
 
   /**
@@ -193,7 +211,7 @@ public class RequestStageContainer {
         if (LOG.isDebugEnabled()) {
           LOG.debug(String.format("Triggering Action Manager, request=%s", 
request));
         }
-        actionManager.sendActions(request, null);
+        actionManager.sendActions(request, actionRequest);
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6a464426/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
index 5e933d2..6f2699b 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelperTest.java
@@ -32,6 +32,7 @@ import junit.framework.Assert;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.actionmanager.ExecutionCommandWrapper;
+import org.apache.ambari.server.actionmanager.Request;
 import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
@@ -61,7 +62,8 @@ import com.google.inject.Injector;
 import com.google.inject.persist.PersistService;
 
 @RunWith(MockitoJUnitRunner.class)
-public class AmbariCustomCommandExecutionHelperTest {
+public class
+    AmbariCustomCommandExecutionHelperTest {
   private Injector injector;
   private AmbariManagementController controller;
   private AmbariMetaInfo ambariMetaInfo;
@@ -70,7 +72,7 @@ public class AmbariCustomCommandExecutionHelperTest {
   
   private static final String REQUEST_CONTEXT_PROPERTY = "context";
   
-  @Captor ArgumentCaptor<List<Stage>> stagesCaptor;
+  @Captor ArgumentCaptor<Request> requestCapture;
   @Mock ActionManager am;
   
   @Before
@@ -123,12 +125,13 @@ public class AmbariCustomCommandExecutionHelperTest {
       
       controller.createAction(actionRequest, requestProperties);
       
-      Mockito.verify(am, Mockito.times(1)).sendActions(stagesCaptor.capture(), 
any(ExecuteActionRequest.class));
-      
-      
-      List<Stage> stages = stagesCaptor.getValue();
-      Assert.assertEquals(1, stages.size());
-      Stage stage = stages.get(0);
+      Mockito.verify(am, 
Mockito.times(1)).sendActions(requestCapture.capture(), 
any(ExecuteActionRequest.class));
+
+      Request request = requestCapture.getValue();
+      Assert.assertNotNull(request);
+      Assert.assertNotNull(request.getStages());
+      Assert.assertEquals(1, request.getStages().size());
+      Stage stage = request.getStages().iterator().next();
       
       Assert.assertEquals(1, stage.getHosts().size());
       
@@ -175,12 +178,14 @@ public class AmbariCustomCommandExecutionHelperTest {
 
       //clusters.getHost("c6402").setState(HostState.HEARTBEAT_LOST);
 
-      Mockito.verify(am, Mockito.times(1)).sendActions(stagesCaptor.capture(), 
any(ExecuteActionRequest.class));
+      Mockito.verify(am, 
Mockito.times(1)).sendActions(requestCapture.capture(), 
any(ExecuteActionRequest.class));
 
-      List<Stage> stages = stagesCaptor.getValue();
-      Assert.assertEquals(1, stages.size());
+      Request request = requestCapture.getValue();
+      Assert.assertNotNull(request);
+      Assert.assertNotNull(request.getStages());
+      Assert.assertEquals(1, request.getStages().size());
+      Stage stage = request.getStages().iterator().next();
 
-      Stage stage = stages.get(0);
        // Check if was generated command, one for each host
       Assert.assertEquals(2, stage.getHostRoleCommands().size());
     }catch (Exception e) {
@@ -217,12 +222,14 @@ public class AmbariCustomCommandExecutionHelperTest {
 
       controller.createAction(actionRequest, requestProperties);
 
-      Mockito.verify(am, Mockito.times(1)).sendActions(stagesCaptor.capture(), 
any(ExecuteActionRequest.class));
+      Mockito.verify(am, 
Mockito.times(1)).sendActions(requestCapture.capture(), 
any(ExecuteActionRequest.class));
 
-      List<Stage> stages = stagesCaptor.getValue();
-      Assert.assertEquals(1, stages.size());
+      Request request = requestCapture.getValue();
+      Assert.assertNotNull(request);
+      Assert.assertNotNull(request.getStages());
+      Assert.assertEquals(1, request.getStages().size());
+      Stage stage = request.getStages().iterator().next();
 
-      Stage stage = stages.get(0);
       // Check if was generated command for one health host
       Assert.assertEquals(1, stage.getHostRoleCommands().size());
     }catch (Exception e) {
@@ -260,12 +267,14 @@ public class AmbariCustomCommandExecutionHelperTest {
 
       controller.createAction(actionRequest, requestProperties);
 
-      Mockito.verify(am, Mockito.times(1)).sendActions(stagesCaptor.capture(), 
any(ExecuteActionRequest.class));
+      Mockito.verify(am, 
Mockito.times(1)).sendActions(requestCapture.capture(), 
any(ExecuteActionRequest.class));
 
-      List<Stage> stages = stagesCaptor.getValue();
-      Assert.assertEquals(1, stages.size());
+      Request request = requestCapture.getValue();
+      Assert.assertNotNull(request);
+      Assert.assertNotNull(request.getStages());
+      Assert.assertEquals(1, request.getStages().size());
+      Stage stage = request.getStages().iterator().next();
 
-      Stage stage = stages.get(0);
       // Check if was generated command for one health host
       Assert.assertEquals(1, stage.getHostRoleCommands().size());
     }catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/6a464426/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
index 2b00f40..a0e358a 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/BackgroundCustomCommandExecutionTest.java
@@ -31,6 +31,7 @@ import junit.framework.Assert;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.actionmanager.ExecutionCommandWrapper;
+import org.apache.ambari.server.actionmanager.Request;
 import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.agent.AgentCommand.AgentCommandType;
 import org.apache.ambari.server.agent.ExecutionCommand;
@@ -70,7 +71,7 @@ public class BackgroundCustomCommandExecutionTest {
   
   private static final String REQUEST_CONTEXT_PROPERTY = "context";
   
-  @Captor ArgumentCaptor<List<Stage>> stagesCaptor;
+  @Captor ArgumentCaptor<Request> requestCapture;
   @Mock ActionManager am;
   
   @Before
@@ -123,12 +124,13 @@ public class BackgroundCustomCommandExecutionTest {
       
       controller.createAction(actionRequest, requestProperties);
       
-      Mockito.verify(am, Mockito.times(1)).sendActions(stagesCaptor.capture(), 
any(ExecuteActionRequest.class));
-      
-      
-      List<Stage> stages = stagesCaptor.getValue();
-      Assert.assertEquals(1, stages.size());
-      Stage stage = stages.get(0);
+      Mockito.verify(am, 
Mockito.times(1)).sendActions(requestCapture.capture(), 
any(ExecuteActionRequest.class));
+
+      Request request = requestCapture.getValue();
+      Assert.assertNotNull(request);
+      Assert.assertNotNull(request.getStages());
+      Assert.assertEquals(1, request.getStages().size());
+      Stage stage = request.getStages().iterator().next();
       
       System.out.println(stage);
       

Reply via email to