Repository: ambari
Updated Branches:
  refs/heads/trunk c313023bd -> 954b96e1e


AMBARI-9852. Kerberos: Kerberos Service Check needs to generate and destroy 
it's own unique identity for testing (rlevas)


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

Branch: refs/heads/trunk
Commit: 954b96e1edf8fc313ce06d57928b3e26e714770a
Parents: c313023
Author: Robert Levas <rle...@hortonworks.com>
Authored: Tue Mar 3 09:59:50 2015 -0500
Committer: Robert Levas <rle...@hortonworks.com>
Committed: Tue Mar 3 09:59:59 2015 -0500

----------------------------------------------------------------------
 .../AmbariManagementControllerImpl.java         |  51 +-
 .../server/controller/KerberosHelper.java       | 636 ++++++++++++++-----
 .../1.10.3-10/package/scripts/params.py         |   9 +-
 .../1.10.3-10/package/scripts/service_check.py  |  46 +-
 .../server/controller/KerberosHelperTest.java   | 393 ++++++++++++
 5 files changed, 946 insertions(+), 189 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/954b96e1/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 2bf0cbf..dcbbed2 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
@@ -40,7 +40,6 @@ import java.io.IOException;
 import java.net.InetAddress;
 import java.text.MessageFormat;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumMap;
@@ -55,6 +54,7 @@ import java.util.Set;
 import java.util.TreeMap;
 import java.util.concurrent.TimeUnit;
 
+import com.google.gson.reflect.TypeToken;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ClusterNotFoundException;
 import org.apache.ambari.server.DuplicateResourceException;
@@ -2902,23 +2902,30 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
         actionManager,
         actionRequest);
 
+    ExecuteCommandJson jsons = 
customCommandExecutionHelper.getCommandJson(actionExecContext, cluster);
+    String commandParamsForStage = jsons.getCommandParamsForStage();
+
     // 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())) {
+    boolean kerberosServiceCheck = 
Role.KERBEROS_SERVICE_CHECK.name().equals(actionRequest.getCommandName());
+    if (kerberosServiceCheck) {
+      // Parse the command parameters into a map so that additional values may 
be added to it
+      Map<String, String> commandParamsStage = 
gson.fromJson(commandParamsForStage,
+          new TypeToken<Map<String, String>>() {
+          }.getType());
+
       try {
-        requestStageContainer = kerberosHelper.ensureIdentities(cluster,
-            Collections.<String, 
Collection<String>>singletonMap(Service.Type.KERBEROS.name(), null),
-            Collections.singleton("/smokeuser"), requestStageContainer);
+        requestStageContainer = kerberosHelper.createTestIdentity(cluster, 
commandParamsStage, requestStageContainer);
       } catch (KerberosOperationException e) {
         throw new IllegalArgumentException(e.getMessage(), e);
       }
-    }
 
-    ExecuteCommandJson jsons = customCommandExecutionHelper.getCommandJson(
-        actionExecContext, cluster);
+      // Recreate commandParamsForStage with the added values
+      commandParamsForStage = gson.toJson(commandParamsStage);
+    }
 
     Stage stage = createNewStage(requestStageContainer.getLastStageId(), 
cluster, requestId, requestContext,
-        jsons.getClusterHostInfo(), jsons.getCommandParamsForStage(), 
jsons.getHostParamsForStage());
+        jsons.getClusterHostInfo(), commandParamsForStage, 
jsons.getHostParamsForStage());
 
     if (actionRequest.isCommand()) {
       
customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, 
stage, requestProperties, false);
@@ -2938,18 +2945,28 @@ public class AmbariManagementControllerImpl implements 
AmbariManagementControlle
     List<Stage> stages = rg.getStages();
 
     if (stages != null && !stages.isEmpty()) {
+      // If this is a Kerberos service check, set the service check stage(s) 
to be skip-able so that
+      // the clean up stages will still be triggered in the event of a failure.
+      if (kerberosServiceCheck) {
+        for (Stage s : stages) {
+          s.setSkippable(true);
+        }
+      }
+
       requestStageContainer.addStages(stages);
     }
 
-    // If the request is to perform the Kerberos service check and (Kerberos) 
security is not enabled,
-    // delete that the (cluster-level) smoke user principal and keytab that 
was created for the
-    // service check
-    if 
(Role.KERBEROS_SERVICE_CHECK.name().equals(actionRequest.getCommandName()) &&
-        !kerberosHelper.isClusterKerberosEnabled(cluster)) {
+    // If the request is to perform the Kerberos service check, delete the 
test-specific principal
+    // and keytab that was created for this service check
+    if (kerberosServiceCheck) {
+      // Parse the command parameters into a map so that existing values may 
be accessed and
+      // additional values may be added to it.
+      Map<String, String> commandParamsStage = 
gson.fromJson(commandParamsForStage,
+          new TypeToken<Map<String, String>>() {
+          }.getType());
+
       try {
-        requestStageContainer = kerberosHelper.deleteIdentities(cluster,
-            Collections.<String, 
Collection<String>>singletonMap(Service.Type.KERBEROS.name(), null),
-            Collections.singleton("/smokeuser"), requestStageContainer);
+        requestStageContainer = kerberosHelper.deleteTestIdentity(cluster, 
commandParamsStage, requestStageContainer);
       } catch (KerberosOperationException e) {
         throw new IllegalArgumentException(e.getMessage(), e);
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/954b96e1/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 8dd6c4d..c4a5f4f 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
@@ -107,6 +107,7 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Random;
 import java.util.Set;
 
 public class KerberosHelper {
@@ -124,6 +125,12 @@ public class KerberosHelper {
    */
   private static final String SECURITY_ENABLED_PROPERTY_NAME = 
"security_enabled";
 
+  /**
+   * name of the property used to hold the service check identifier value, 
used when creating and
+   * destroying the (unique) service check identity.
+   */
+  private static final String SERVICE_CHECK_IDENTIFIER = 
"_kerberos_internal_service_check_identifier";
+
   @Inject
   private AmbariCustomCommandExecutionHelper customCommandExecutionHelper;
 
@@ -262,7 +269,6 @@ public class KerberosHelper {
     return requestStageContainer;
   }
 
-
   /**
    * Ensures the set of filtered principals and keytabs exist on the cluster.
    * <p/>
@@ -400,6 +406,133 @@ public class KerberosHelper {
   }
 
   /**
+   * Create a unique identity to use for testing the general Kerberos 
configuration.
+   *
+   * @param cluster               the relevant Cluster
+   * @param commandParamsStage    the command parameters map that will be sent 
to the agent side command
+   * @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.
+   */
+  public RequestStageContainer createTestIdentity(Cluster cluster, Map<String, 
String> commandParamsStage,
+                                                  RequestStageContainer 
requestStageContainer)
+      throws KerberosOperationException, AmbariException {
+    return handleTestIdentity(cluster, getKerberosDetails(cluster), 
commandParamsStage, requestStageContainer, new 
CreatePrincipalsAndKeytabsHandler(false));
+  }
+
+  /**
+   * Deletes the unique identity to use for testing the general Kerberos 
configuration.
+   *
+   * @param cluster               the relevant Cluster
+   * @param commandParamsStage    the command parameters map that will be sent 
to the agent side command
+   * @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.
+   */
+  public RequestStageContainer deleteTestIdentity(Cluster cluster, Map<String, 
String> commandParamsStage,
+                                                  RequestStageContainer 
requestStageContainer)
+      throws KerberosOperationException, AmbariException {
+    requestStageContainer = handleTestIdentity(cluster, 
getKerberosDetails(cluster), commandParamsStage, requestStageContainer, new 
DeletePrincipalsAndKeytabsHandler());
+
+    // Clear the Kerberos service check identifier
+    setKerberosServiceCheckIdentifier(cluster, null);
+
+    return requestStageContainer;
+  }
+
+  /**
+   * Validate the KDC admin credentials.
+   *
+   * @param cluster associated cluster
+   *
+   * @throws AmbariException if any other error occurs while trying to 
validate the credentials
+   */
+  public void validateKDCCredentials(Cluster cluster) throws 
KerberosMissingAdminCredentialsException,
+      KerberosAdminAuthenticationException,
+      KerberosInvalidConfigurationException,
+      AmbariException {
+    String credentials = getEncryptedAdministratorCredentials(cluster);
+    if (credentials == null) {
+      throw new KerberosMissingAdminCredentialsException(
+          "Missing KDC administrator credentials.\n" +
+              "The KDC administrator credentials must be set in session by 
updating the relevant Cluster resource." +
+              "This may be done by issuing a PUT to the 
api/v1/clusters/(cluster name) API entry point with the following payload:\n" +
+              "{\n" +
+              "  \"session_attributes\" : {\n" +
+              "    \"kerberos_admin\" : {\"principal\" : \"(PRINCIPAL)\", 
\"password\" : \"(PASSWORD)\"}\n" +
+              "  }\n" +
+              "}"
+      );
+    } else {
+      KerberosDetails kerberosDetails = getKerberosDetails(cluster);
+      KerberosOperationHandler operationHandler = 
kerberosOperationHandlerFactory.getKerberosOperationHandler(kerberosDetails.getKdcType());
+
+      if (operationHandler == null) {
+        throw new AmbariException("Failed to get an appropriate Kerberos 
operation handler.");
+      } else {
+        byte[] key = Integer.toHexString(cluster.hashCode()).getBytes();
+        KerberosCredential kerberosCredentials = 
KerberosCredential.decrypt(credentials, key);
+
+        boolean missingCredentials = false;
+        try {
+          operationHandler.open(kerberosCredentials, 
kerberosDetails.getDefaultRealm(), kerberosDetails.getKerberosEnvProperties());
+          // todo: this is really odd that open doesn't throw an exception if 
the credentials are missing
+          missingCredentials = ! 
operationHandler.testAdministratorCredentials();
+        } catch (KerberosAdminAuthenticationException e) {
+          throw new KerberosAdminAuthenticationException(
+              "Invalid KDC administrator credentials.\n" +
+                  "The KDC administrator credentials must be set in session by 
updating the relevant Cluster resource." +
+                  "This may be done by issuing a PUT to the 
api/v1/clusters/(cluster name) API entry point with the following payload:\n" +
+                  "{\n" +
+                  "  \"session_attributes\" : {\n" +
+                  "    \"kerberos_admin\" : {\"principal\" : \"(PRINCIPAL)\", 
\"password\" : \"(PASSWORD)\"}\n" +
+                  "  }\n" +
+                  "}", e);
+        } catch (KerberosKDCConnectionException e) {
+          throw new KerberosInvalidConfigurationException(
+              "Failed to connect to KDC - " + e.getMessage() + "\n" +
+                  "Update the KDC settings in krb5-conf and kerberos-env 
configurations to correct this issue.",
+              e);
+        } catch (KerberosRealmException e) {
+          throw new KerberosInvalidConfigurationException(
+              "Failed to find a KDC for the specified realm - " + 
e.getMessage() + "\n" +
+                  "Update the KDC settings in krb5-conf and kerberos-env 
configurations to correct this issue.",
+              e);
+        } catch (KerberosLDAPContainerException e) {
+          throw new KerberosInvalidConfigurationException(
+              "The principal container was not specified\n" +
+                  "Set the 'container_dn' value in the kerberos-env 
configuration to correct this issue.",
+              e);
+        } catch (KerberosOperationException e) {
+          throw new AmbariException(e.getMessage(), e);
+        } finally {
+          try {
+            operationHandler.close();
+          } catch (KerberosOperationException e) {
+            // Ignore this...
+          }
+        }
+
+        // need to throw this outside of the try/catch so it isn't caught
+        if (missingCredentials) {
+          throw new KerberosMissingAdminCredentialsException(
+              "Invalid KDC administrator credentials.\n" +
+                  "The KDC administrator credentials must be set in session by 
updating the relevant Cluster resource." +
+                  "This may be done by issuing a PUT to the 
api/v1/clusters/(cluster name) API entry point with the following payload:\n" +
+                  "{\n" +
+                  "  \"session_attributes\" : {\n" +
+                  "    \"kerberos_admin\" : {\"principal\" : \"(PRINCIPAL)\", 
\"password\" : \"(PASSWORD)\"}\n" +
+                  "  }\n" +
+                  "}"
+          );
+        }
+      }
+    }
+  }
+
+  /**
    * Sets the relevant auth-to-local rule configuration properties using the 
services installed on
    * the cluster and their relevant Kerberos descriptors to determine the 
rules to be created.
    *
@@ -534,7 +667,6 @@ public class KerberosHelper {
 
       if ((hosts != null) && !hosts.isEmpty()) {
         List<ServiceComponentHost> serviceComponentHostsToProcess = new 
ArrayList<ServiceComponentHost>();
-        File indexFile;
         KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster);
         KerberosActionDataFileBuilder kerberosActionDataFileBuilder = null;
         Map<String, String> kerberosDescriptorProperties = 
kerberosDescriptor.getProperties();
@@ -549,17 +681,10 @@ public class KerberosHelper {
         // such as which principals and keytabs files to create as well as 
what configurations need
         // to be update are stored in data files in this directory. Any keytab 
files are stored in
         // this directory until they are distributed to their appropriate 
hosts.
-        File dataDirectory;
-        try {
-          dataDirectory = createTemporaryDirectory();
-        } catch (IOException e) {
-          String message = "Failed to create the temporary data directory.";
-          LOG.error(message, e);
-          throw new AmbariException(message, e);
-        }
+        File dataDirectory = createTemporaryDirectory();
 
         // Create the file used to store details about principals and keytabs 
to create
-        indexFile = new File(dataDirectory, 
KerberosActionDataFile.DATA_FILE_NAME);
+        File indexFile = new File(dataDirectory, 
KerberosActionDataFile.DATA_FILE_NAME);
 
         try {
           // Iterate over the hosts in the cluster to find the components 
installed in each.  For each
@@ -711,25 +836,8 @@ public class KerberosHelper {
             requestStageContainer, serviceComponentHostsToProcess, 
hostsWithValidKerberosClient);
 
         // Add the cleanup stage...
-        Map<String, String> commandParameters = new HashMap<String, String>();
-        commandParameters.put(KerberosServerAction.AUTHENTICATED_USER_NAME, 
ambariManagementController.getAuthName());
-        commandParameters.put(KerberosServerAction.DATA_DIRECTORY, 
dataDirectory.getAbsolutePath());
-
-        Stage stage = 
createServerActionStage(requestStageContainer.getLastStageId(),
-            cluster,
-            requestStageContainer.getId(),
-            "Finalize Operations",
-            clusterHostInfoJson,
-            "{}",
-            hostParamsJson,
-            FinalizeKerberosServerAction.class,
-            event,
-            commandParameters,
-            "Finalize Operations", 300);
-
-        RoleGraph roleGraph = new RoleGraph(roleCommandOrder);
-        roleGraph.build(stage);
-        requestStageContainer.addStages(roleGraph.getStages());
+        handler.addFinalizeOperationStage(cluster, clusterHostInfoJson, 
hostParamsJson, event,
+            dataDirectory, roleCommandOrder, requestStageContainer);
 
         // If all goes well, set the appropriate states on the relevant 
ServiceComponentHosts
         for (ServiceComponentHost sch : serviceComponentHostsToProcess) {
@@ -763,95 +871,218 @@ public class KerberosHelper {
   }
 
   /**
-   * Validate the KDC admin credentials.
+   * Performs operations needed to process Kerberos related tasks to manage a 
(unique) test identity
+   * on the relevant cluster.
    *
-   * @param cluster associated cluster
-   *
-   * @throws AmbariException if any other error occurs while trying to 
validate the credentials
+   * @param cluster               the relevant Cluster
+   * @param kerberosDetails       a KerberosDetails containing information 
about relevant Kerberos
+   *                              configuration
+   * @param commandParameters     the command parameters map used to read 
and/or write attributes
+   *                              related to this operation
+   * @param requestStageContainer a RequestStageContainer to place generated 
stages, if needed -
+   *                              if null a new RequestStageContainer will be 
created.
+   * @param handler               a Handler to use to provide guidance and set 
up stages
+   *                              to perform the work needed to complete the 
relative action
+   * @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
+   * @throws KerberosOperationException
    */
-  public void validateKDCCredentials(Cluster cluster) throws 
KerberosMissingAdminCredentialsException,
-                                                             
KerberosAdminAuthenticationException,
-                                                             
KerberosInvalidConfigurationException,
-                                                             AmbariException {
-    String credentials = getEncryptedAdministratorCredentials(cluster);
-    if (credentials == null) {
-      throw new KerberosMissingAdminCredentialsException(
-          "Missing KDC administrator credentials.\n" +
-              "The KDC administrator credentials must be set in session by 
updating the relevant Cluster resource." +
-              "This may be done by issuing a PUT to the 
api/v1/clusters/(cluster name) API entry point with the following payload:\n" +
-              "{\n" +
-              "  \"session_attributes\" : {\n" +
-              "    \"kerberos_admin\" : {\"principal\" : \"(PRINCIPAL)\", 
\"password\" : \"(PASSWORD)\"}\n" +
-              "  }\n" +
-              "}"
-      );
-    } else {
-      KerberosDetails kerberosDetails = getKerberosDetails(cluster);
-      KerberosOperationHandler operationHandler = 
kerberosOperationHandlerFactory.getKerberosOperationHandler(kerberosDetails.getKdcType());
+  private RequestStageContainer handleTestIdentity(Cluster cluster,
+                                                   KerberosDetails 
kerberosDetails,
+                                                   Map<String, String> 
commandParameters, RequestStageContainer requestStageContainer,
+                                                   Handler handler) throws 
AmbariException, KerberosOperationException {
 
-      if (operationHandler == null) {
-        throw new AmbariException("Failed to get an appropriate Kerberos 
operation handler.");
-      } else {
-        byte[] key = Integer.toHexString(cluster.hashCode()).getBytes();
-        KerberosCredential kerberosCredentials = 
KerberosCredential.decrypt(credentials, key);
+    if(commandParameters == null) {
+      throw new AmbariException("The properties map must not be null.  It is 
needed to store data related to the service check identity");
+    }
+
+    Map<String, Service> services = cluster.getServices();
+
+    if ((services != null) && !services.isEmpty()) {
+      String clusterName = cluster.getClusterName();
+      Map<String, Host> hosts = clusters.getHostsForCluster(clusterName);
+
+      if ((hosts != null) && !hosts.isEmpty()) {
+        List<ServiceComponentHost> serviceComponentHostsToProcess = new 
ArrayList<ServiceComponentHost>();
+        KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster);
+        KerberosActionDataFileBuilder kerberosActionDataFileBuilder = null;
+        Map<String, String> kerberosDescriptorProperties = 
kerberosDescriptor.getProperties();
+
+        // While iterating over all the ServiceComponentHosts find hosts that 
have KERBEROS_CLIENT
+        // components in the INSTALLED state and add them to the 
hostsWithValidKerberosClient Set.
+        // This is needed to help determine which hosts to perform actions for 
and create tasks for.
+        Set<String> hostsWithValidKerberosClient = new HashSet<String>();
+
+        // Create a temporary directory to store metadata needed to complete 
this task.  Information
+        // such as which principals and keytabs files to create as well as 
what configurations need
+        // to be update are stored in data files in this directory. Any keytab 
files are stored in
+        // this directory until they are distributed to their appropriate 
hosts.
+        File dataDirectory = createTemporaryDirectory();
+
+        // Create the file used to store details about principals and keytabs 
to create
+        File indexFile = new File(dataDirectory, 
KerberosActionDataFile.DATA_FILE_NAME);
+
+        // Create a special identity for the test user
+        KerberosIdentityDescriptor identity = new 
KerberosIdentityDescriptor(new HashMap<String, Object>() {
+          {
+            put("principal",
+                new HashMap<String, Object>() {
+                  {
+                    put("value", 
"${cluster-env/smokeuser}_${service_check_id}@${realm}");
+                    put("type", "user");
+                  }
+                });
+            put("keytab",
+                new HashMap<String, Object>() {
+                  {
+                    put("file", 
"${keytab_dir}/kerberos.service_check.${service_check_id}.keytab");
+
+                    put("owner", new HashMap<String, Object>() {{
+                      put("name", "${cluster-env/smokeuser}");
+                      put("access", "rw");
+                    }});
+
+                    put("group", new HashMap<String, Object>() {{
+                      put("name", "${cluster-env/user_group}");
+                      put("access", "r");
+                    }});
+                  }
+                });
+          }
+        });
+
+        // Get or create the unique service check identifier
+        String serviceCheckId = getKerberosServiceCheckIdentifier(cluster, 
true);
 
-        boolean missingCredentials = false;
         try {
-          operationHandler.open(kerberosCredentials, 
kerberosDetails.getDefaultRealm(), kerberosDetails.getKerberosEnvProperties());
-          // todo: this is really odd that open doesn't throw an exception if 
the credentials are missing
-          missingCredentials = ! 
operationHandler.testAdministratorCredentials();
-        } catch (KerberosAdminAuthenticationException e) {
-          throw new KerberosAdminAuthenticationException(
-              "Invalid KDC administrator credentials.\n" +
-                  "The KDC administrator credentials must be set in session by 
updating the relevant Cluster resource." +
-                  "This may be done by issuing a PUT to the 
api/v1/clusters/(cluster name) API entry point with the following payload:\n" +
-                  "{\n" +
-                  "  \"session_attributes\" : {\n" +
-                  "    \"kerberos_admin\" : {\"principal\" : \"(PRINCIPAL)\", 
\"password\" : \"(PASSWORD)\"}\n" +
-                  "  }\n" +
-                  "}", e);
-        } catch (KerberosKDCConnectionException e) {
-          throw new KerberosInvalidConfigurationException(
-              "Failed to connect to KDC - " + e.getMessage() + "\n" +
-                  "Update the KDC settings in krb5-conf and kerberos-env 
configurations to correct this issue.",
-              e);
-        } catch (KerberosRealmException e) {
-          throw new KerberosInvalidConfigurationException(
-              "Failed to find a KDC for the specified realm - " + 
e.getMessage() + "\n" +
-                  "Update the KDC settings in krb5-conf and kerberos-env 
configurations to correct this issue.",
-              e);
-        } catch (KerberosLDAPContainerException e) {
-          throw new KerberosInvalidConfigurationException(
-              "The principal container was not specified\n" +
-                  "Set the 'container_dn' value in the kerberos-env 
configuration to correct this issue.",
-              e);
-        } catch (KerberosOperationException e) {
-          throw new AmbariException(e.getMessage(), e);
+          // 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.values()) {
+            String hostname = host.getHostName();
+
+            // Get a list of components on the current host
+            List<ServiceComponentHost> serviceComponentHosts = 
cluster.getServiceComponentHosts(hostname);
+
+            if ((serviceComponentHosts != null) && 
!serviceComponentHosts.isEmpty()) {
+              // Calculate the current host-specific configurations. These 
will be used to replace
+              // variables within the Kerberos descriptor data
+              Map<String, Map<String, String>> configurations = 
calculateConfigurations(cluster, hostname, kerberosDescriptorProperties);
+
+              // Set the unique service check identifier
+              configurations.get("").put("service_check_id", serviceCheckId);
+
+              // 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 the current ServiceComponentHost represents the 
KERBEROS/KERBEROS_CLIENT and
+                // indicates that the KERBEROS_CLIENT component is in the 
INSTALLED state, add the
+                // current host to the set of hosts that should be handled...
+                if(Service.Type.KERBEROS.name().equals(serviceName) &&
+                    Role.KERBEROS_CLIENT.name().equals(componentName) &&
+                    (sch.getState() == State.INSTALLED)) {
+                  hostsWithValidKerberosClient.add(hostname);
+
+                  int identitiesAdded = 0;
+
+                  // Lazily create the KerberosActionDataFileBuilder 
instance...
+                  if (kerberosActionDataFileBuilder == null) {
+                    kerberosActionDataFileBuilder = new 
KerberosActionDataFileBuilder(indexFile);
+                  }
+
+                  // Add service-level principals (and keytabs)
+                  identitiesAdded += 
addIdentities(kerberosActionDataFileBuilder, Collections.singleton(identity),
+                      null, hostname, serviceName, componentName, 
configurations);
+
+                  if (identitiesAdded > 0) {
+                    // Add the relevant principal name and keytab file data to 
the command params state
+                    if(!commandParameters.containsKey("principal_name") || 
!commandParameters.containsKey("keytab_file")) {
+                      commandParameters.put("principal_name",
+                          
KerberosDescriptor.replaceVariables(identity.getPrincipalDescriptor().getValue(),
 configurations));
+                      commandParameters.put("keytab_file",
+                          
KerberosDescriptor.replaceVariables(identity.getKeytabDescriptor().getFile(), 
configurations));
+                    }
+
+                    serviceComponentHostsToProcess.add(sch);
+                  }
+                }
+              }
+            }
+          }
+        } catch (IOException e) {
+          String message = String.format("Failed to write index file - %s", 
indexFile.getAbsolutePath());
+          LOG.error(message);
+          throw new AmbariException(message, e);
         } finally {
+          if (kerberosActionDataFileBuilder != null) {
+            // Make sure the data file is closed
+            try {
+              kerberosActionDataFileBuilder.close();
+            } catch (IOException e) {
+              LOG.warn("Failed to close the index file writer", e);
+            }
+          }
+        }
+
+        // If there are ServiceComponentHosts to process, make sure the 
administrator credentials
+        // are available
+        if (!serviceComponentHostsToProcess.isEmpty()) {
           try {
-            operationHandler.close();
+            validateKDCCredentials(cluster);
           } catch (KerberosOperationException e) {
-            // Ignore this...
+            try {
+              FileUtils.deleteDirectory(dataDirectory);
+            } catch (Throwable t) {
+              LOG.warn(String.format("The data directory (%s) was not deleted 
due to an error condition - {%s}",
+                  dataDirectory.getAbsolutePath(), t.getMessage()), t);
+            }
+
+            throw e;
           }
         }
 
-        // need to throw this outside of the try/catch so it isn't caught
-        if (missingCredentials) {
-          throw new KerberosMissingAdminCredentialsException(
-              "Invalid KDC administrator credentials.\n" +
-                  "The KDC administrator credentials must be set in session by 
updating the relevant Cluster resource." +
-                  "This may be done by issuing a PUT to the 
api/v1/clusters/(cluster name) API entry point with the following payload:\n" +
-                  "{\n" +
-                  "  \"session_attributes\" : {\n" +
-                  "    \"kerberos_admin\" : {\"principal\" : \"(PRINCIPAL)\", 
\"password\" : \"(PASSWORD)\"}\n" +
-                  "  }\n" +
-                  "}"
-          );
+        // Always set up the necessary stages to perform the tasks needed to 
complete the operation.
+        // Some stages may be no-ops, this is expected.
+        // Gather data needed to create stages and tasks...
+        Map<String, Set<String>> clusterHostInfo = 
StageUtils.getClusterHostInfo(hosts, cluster);
+        String clusterHostInfoJson = 
StageUtils.getGson().toJson(clusterHostInfo);
+        Map<String, String> hostParams = 
customCommandExecutionHelper.createDefaultHostParams(cluster);
+        String hostParamsJson = StageUtils.getGson().toJson(hostParams);
+        String ambariServerHostname = StageUtils.getHostName();
+        ServiceComponentHostServerActionEvent event = new 
ServiceComponentHostServerActionEvent(
+            "AMBARI_SERVER",
+            ambariServerHostname, // TODO: Choose a random hostname from the 
cluster. All tasks for the AMBARI_SERVER service will be executed on this 
Ambari server
+            System.currentTimeMillis());
+        RoleCommandOrder roleCommandOrder = 
ambariManagementController.getRoleCommandOrder(cluster);
+
+        // If a RequestStageContainer does not already exist, create a new 
one...
+        if (requestStageContainer == null) {
+          requestStageContainer = new RequestStageContainer(
+              actionManager.getNextRequestId(),
+              null,
+              requestFactory,
+              actionManager);
         }
+
+        // Use the handler implementation to setup the relevant stages.
+        handler.createStages(cluster, hosts, Collections.<String, Map<String, 
String>>emptyMap(),
+            clusterHostInfoJson, hostParamsJson, event, roleCommandOrder, 
kerberosDetails,
+            dataDirectory, requestStageContainer, 
serviceComponentHostsToProcess, hostsWithValidKerberosClient);
+
+        handler.addFinalizeOperationStage(cluster, clusterHostInfoJson, 
hostParamsJson, event,
+            dataDirectory, roleCommandOrder, requestStageContainer);
       }
     }
+
+    return requestStageContainer;
   }
 
+
   /**
    * Gathers the Kerberos-related data from configurations and stores it in a 
new KerberosDetails
    * instance.
@@ -1028,41 +1259,47 @@ public class KerberosHelper {
     // -------------------------------
   }
 
-
   /**
    * Creates a temporary directory within the system temporary directory
    * <p/>
    * The resulting directory is to be removed by the caller when desired.
    *
    * @return a File pointing to the new temporary directory, or null if one 
was not created
-   * @throws java.io.IOException if a new temporary directory cannot be created
+   * @throws AmbariException if a new temporary directory cannot be created
    */
-  private File createTemporaryDirectory() throws IOException {
+  private File createTemporaryDirectory() throws AmbariException {
     String tempDirectoryPath = System.getProperty("java.io.tmpdir");
-    if (tempDirectoryPath == null) {
-      throw new IOException("The System property 'java.io.tmpdir' does not 
specify a temporary directory");
-    }
+    try {
+      if (tempDirectoryPath == null) {
+        throw new IOException("The System property 'java.io.tmpdir' does not 
specify a temporary directory");
+      }
 
-    File directory;
-    int tries = 0;
-    long now = System.currentTimeMillis();
+      File directory;
+      int tries = 0;
+      long now = System.currentTimeMillis();
 
-    do {
-      directory = new File(tempDirectoryPath, String.format("%s%d-%d.d",
-          KerberosServerAction.DATA_DIRECTORY_PREFIX, now, tries));
+      do {
+        directory = new File(tempDirectoryPath, String.format("%s%d-%d.d",
+            KerberosServerAction.DATA_DIRECTORY_PREFIX, now, tries));
 
-      if ((directory.exists()) || !directory.mkdirs()) {
-        directory = null; // Rest and try again...
-      } else {
-        LOG.debug("Created temporary directory: {}", 
directory.getAbsolutePath());
+        if ((directory.exists()) || !directory.mkdirs()) {
+          directory = null; // Rest and try again...
+        } else {
+          LOG.debug("Created temporary directory: {}", 
directory.getAbsolutePath());
+        }
+      } while ((directory == null) && (++tries < 100));
+
+      if (directory == null) {
+        throw new IOException(String.format("Failed to create a temporary 
directory in %s", tempDirectoryPath));
       }
-    } while ((directory == null) && (++tries < 100));
 
-    if (directory == null) {
-      throw new IOException(String.format("Failed to create a temporary 
directory in %s", tempDirectoryPath));
+      return directory;
+    }
+    catch (IOException e) {
+      String message = "Failed to create the temporary data directory.";
+      LOG.error(message, e);
+      throw new AmbariException(message, e);
     }
-
-    return directory;
   }
 
   /**
@@ -1420,6 +1657,60 @@ public class KerberosHelper {
   }
 
   /**
+   * Using the session data from the relevant Cluster object, gets the 
previously stored
+   * Kerberos service check identifier value or creates a new one if indicated 
to do so.
+   * <p/>
+   * This value is used intended to be used by the KerberosHelper to manage 
uniquely crated
+   * principals for use in service checks.
+   *
+   * @param cluster the relevant Cluster
+   * @return the previously stored Kerberos service check identifier value, or 
null if
+   * not previously stored
+   */
+  private String getKerberosServiceCheckIdentifier(Cluster cluster, boolean 
createIfNull) {
+    Map<String, Object> sessionAttributes = cluster.getSessionAttributes();
+    Object value = (sessionAttributes == null) ? null : 
sessionAttributes.get(SERVICE_CHECK_IDENTIFIER);
+    String serviceCheckIdentifier = (value instanceof String) ? (String) value 
: null;
+
+    if ((serviceCheckIdentifier == null) && createIfNull) {
+      // Create a new (ideally) unique(ish) identifier
+      Random random = new Random(System.currentTimeMillis());
+      char[] chars = new char[8];
+
+      for (int i = 0; i < 8; i++) {
+        chars[i] = (char) ((int) 'a' + random.nextInt(26));
+      }
+
+      serviceCheckIdentifier = String.valueOf(chars);
+      setKerberosServiceCheckIdentifier(cluster, serviceCheckIdentifier);
+    }
+
+    return serviceCheckIdentifier;
+  }
+
+  /**
+   * Stores the Kerberos service check identifier value into the session data 
from the
+   * relevant Cluster object.
+   * <p/>
+   * This value is used intended to be used by the KerberosHelper to manage 
uniquely crated
+   * principals for use in service checks.
+   *
+   * @param cluster the relevant Cluster
+   * @param value   the Kerberos service check identifier to store or null to 
clear any previously set value
+   */
+  private void setKerberosServiceCheckIdentifier(Cluster cluster, String 
value) {
+    Map<String, Object> sessionAttributes = cluster.getSessionAttributes();
+
+    if (sessionAttributes != null) {
+      if (value == null) {
+        sessionAttributes.remove(SERVICE_CHECK_IDENTIFIER);
+      } else {
+        sessionAttributes.put(SERVICE_CHECK_IDENTIFIER, value);
+      }
+    }
+  }
+
+  /**
    * Given a Collection of ServiceComponentHosts generates a unique list of 
hosts.
    *
    * @param serviceComponentHosts a Collection of ServiceComponentHosts from 
which to to retrieve host names
@@ -1707,17 +1998,6 @@ public class KerberosHelper {
                                               Set<String> 
hostsWithValidKerberosClient)
         throws AmbariException {
 
-      Iterator<ServiceComponentHost> iterator = new 
HashSet<ServiceComponentHost>(serviceComponentHosts).iterator();
-      //Filter out ServiceComponentHosts not ready for processing from 
serviceComponentHostsToProcess
-      // by pruning off the ones that on hosts that are not in 
hostsWithValidKerberosClient
-      while(iterator.hasNext()) {
-        ServiceComponentHost sch = iterator.next();
-
-        if(!hostsWithValidKerberosClient.contains(sch.getHostName())) {
-          iterator.remove();
-        }
-      }
-
       Stage stage = createNewStage(requestStageContainer.getLastStageId(),
           cluster,
           requestStageContainer.getId(),
@@ -1726,8 +2006,11 @@ public class KerberosHelper {
           StageUtils.getGson().toJson(commandParameters),
           hostParamsJson);
 
-      if (!serviceComponentHosts.isEmpty()) {
-        List<String> hostsToUpdate = 
createUniqueHostList(serviceComponentHosts, 
Collections.singleton(HostState.HEALTHY));
+      Collection<ServiceComponentHost> filteredComponents = 
filterServiceComponentHostsForHosts(
+          new ArrayList<ServiceComponentHost>(serviceComponentHosts), 
hostsWithValidKerberosClient);
+
+      if (!filteredComponents.isEmpty()) {
+        List<String> hostsToUpdate = createUniqueHostList(filteredComponents, 
Collections.singleton(HostState.HEALTHY));
         Map<String, String> requestParams = new HashMap<String, String>();
         List<RequestResourceFilter> requestResourceFilters = new 
ArrayList<RequestResourceFilter>();
         RequestResourceFilter reqResFilter = new 
RequestResourceFilter(Service.Type.KERBEROS.name(), 
Role.KERBEROS_CLIENT.name(), hostsToUpdate);
@@ -1746,12 +2029,40 @@ public class KerberosHelper {
       requestStageContainer.addStages(roleGraph.getStages());
     }
 
+    /**
+     * Filter out ServiceComponentHosts that are on on hosts in the specified 
set of host names.
+     * <p/>
+     * It is expected that the supplied collection is modifiable. It will be 
modified inplace.
+     *
+     * @param serviceComponentHosts a collection of ServiceComponentHost items 
to test
+     * @param hosts                 a set of host names indicating valid hosts
+     * @return a collection of filtered ServiceComponentHost items
+     */
+    private Collection<ServiceComponentHost> 
filterServiceComponentHostsForHosts(Collection<ServiceComponentHost> 
serviceComponentHosts,
+                                                                               
  Set<String> hosts) {
+
+      if ((serviceComponentHosts != null) && (hosts != null)) {
+        Iterator<ServiceComponentHost> iterator = 
serviceComponentHosts.iterator();
+        while (iterator.hasNext()) {
+          ServiceComponentHost sch = iterator.next();
+
+          if (!hosts.contains(sch.getHostName())) {
+            iterator.remove();
+          }
+        }
+      }
+
+      return serviceComponentHosts;
+    }
+
     public void addDeleteKeytabFilesStage(Cluster cluster, 
List<ServiceComponentHost> serviceComponentHosts,
-                                              String clusterHostInfoJson, 
String hostParamsJson,
-                                              Map<String, String> 
commandParameters,
-                                              RoleCommandOrder 
roleCommandOrder,
-                                              RequestStageContainer 
requestStageContainer)
+                                          String clusterHostInfoJson, String 
hostParamsJson,
+                                          Map<String, String> 
commandParameters,
+                                          RoleCommandOrder roleCommandOrder,
+                                          RequestStageContainer 
requestStageContainer,
+                                          Set<String> 
hostsWithValidKerberosClient)
         throws AmbariException {
+
       Stage stage = createNewStage(requestStageContainer.getLastStageId(),
           cluster,
           requestStageContainer.getId(),
@@ -1760,8 +2071,11 @@ public class KerberosHelper {
           StageUtils.getGson().toJson(commandParameters),
           hostParamsJson);
 
-      if (!serviceComponentHosts.isEmpty()) {
-        List<String> hostsToUpdate = 
createUniqueHostList(serviceComponentHosts, 
Collections.singleton(HostState.HEALTHY));
+      Collection<ServiceComponentHost> filteredComponents = 
filterServiceComponentHostsForHosts(
+          new ArrayList<ServiceComponentHost>(serviceComponentHosts), 
hostsWithValidKerberosClient);
+
+      if (!filteredComponents.isEmpty()) {
+        List<String> hostsToUpdate = createUniqueHostList(filteredComponents, 
Collections.singleton(HostState.HEALTHY));
         Map<String, String> requestParams = new HashMap<String, String>();
         List<RequestResourceFilter> requestResourceFilters = new 
ArrayList<RequestResourceFilter>();
         RequestResourceFilter reqResFilter = new 
RequestResourceFilter("KERBEROS", "KERBEROS_CLIENT", hostsToUpdate);
@@ -1802,6 +2116,34 @@ public class KerberosHelper {
       roleGraph.build(stage);
       requestStageContainer.addStages(roleGraph.getStages());
     }
+
+    public void addFinalizeOperationStage(Cluster cluster, String 
clusterHostInfoJson,
+                                          String hostParamsJson, 
ServiceComponentHostServerActionEvent event,
+                                          File dataDirectory,
+                                          RoleCommandOrder roleCommandOrder, 
RequestStageContainer requestStageContainer)
+        throws AmbariException {
+
+      // Add the cleanup stage...
+      Map<String, String> commandParameters = new HashMap<String, String>();
+      commandParameters.put(KerberosServerAction.AUTHENTICATED_USER_NAME, 
ambariManagementController.getAuthName());
+      commandParameters.put(KerberosServerAction.DATA_DIRECTORY, 
dataDirectory.getAbsolutePath());
+
+      Stage stage = 
createServerActionStage(requestStageContainer.getLastStageId(),
+          cluster,
+          requestStageContainer.getId(),
+          "Finalize Operations",
+          clusterHostInfoJson,
+          "{}",
+          hostParamsJson,
+          FinalizeKerberosServerAction.class,
+          event,
+          commandParameters,
+          "Finalize Operations", 300);
+
+      RoleGraph roleGraph = new RoleGraph(roleCommandOrder);
+      roleGraph.build(stage);
+      requestStageContainer.addStages(roleGraph.getStages());
+    }
   }
 
   /**
@@ -2082,7 +2424,7 @@ public class KerberosHelper {
       // *****************************************************************
       // Create stage to delete keytabs
       addDeleteKeytabFilesStage(cluster, serviceComponentHosts, 
clusterHostInfoJson,
-          hostParamsJson, commandParameters, roleCommandOrder, 
requestStageContainer);
+          hostParamsJson, commandParameters, roleCommandOrder, 
requestStageContainer, hostsWithValidKerberosClient);
 
       return requestStageContainer.getLastStageId();
     }
@@ -2199,7 +2541,6 @@ public class KerberosHelper {
    * <li>remove keytab files</li>
    * </ol>
    */
-
   private class DeletePrincipalsAndKeytabsHandler extends Handler {
 
     @Override
@@ -2260,14 +2601,12 @@ public class KerberosHelper {
       // *****************************************************************
       // Create stage to delete keytabs
       addDeleteKeytabFilesStage(cluster, serviceComponentHosts, 
clusterHostInfoJson,
-          hostParamsJson, commandParameters, roleCommandOrder, 
requestStageContainer);
+          hostParamsJson, commandParameters, roleCommandOrder, 
requestStageContainer, hostsWithValidKerberosClient);
 
       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.
@@ -2310,5 +2649,4 @@ public class KerberosHelper {
       return securityType;
     }
   }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/954b96e1/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/params.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/params.py
 
b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/params.py
index 3705cfe..3ccbc3e 100644
--- 
a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/params.py
+++ 
b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/params.py
@@ -40,6 +40,7 @@ kadm5_acl_file = 'kadm5.acl'
 kadm5_acl_path = kadm5_acl_dir + '/' + kadm5_acl_file
 
 config = Script.get_config()
+tmp_dir = Script.get_tmp_dir()
 
 command_params = None
 configurations = None
@@ -68,6 +69,8 @@ if config is not None:
   command_params = get_property_value(config, 'commandParams')
   if command_params is not None:
     keytab_details = get_unstructured_data(command_params, 'keytab')
+    smoke_test_principal = get_property_value(command_params, 
'principal_name', None, True, None)
+    smoke_test_keytab_file = get_property_value(command_params, 'keytab_file', 
None, True, None)
 
   kerberos_command_params = get_property_value(config, 'kerberosCommandParams')
 
@@ -76,8 +79,10 @@ if config is not None:
     cluster_env = get_property_value(configurations, 'cluster-env')
 
     if cluster_env is not None:
-      smoke_test_principal = get_property_value(cluster_env, 
'smokeuser_principal_name', None, True, None)
-      smoke_test_keytab_file = get_property_value(cluster_env, 
'smokeuser_keytab', None, True, None)
+      if smoke_test_principal is None:
+        smoke_test_principal = get_property_value(cluster_env, 
'smokeuser_principal_name', None, True, None)
+      if smoke_test_keytab_file is None:
+        smoke_test_keytab_file = get_property_value(cluster_env, 
'smokeuser_keytab', None, True, None)
 
       default_group = get_property_value(cluster_env, 'user_group')
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/954b96e1/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/service_check.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/service_check.py
 
b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/service_check.py
index ee4a4c3..53ab52f 100644
--- 
a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/service_check.py
+++ 
b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/service_check.py
@@ -22,36 +22,40 @@ Ambari Agent
 from kerberos_common import *
 from resource_management import *
 
+# hashlib is supplied as of Python 2.5 as the replacement interface for md5
+# and other secure hashes.  In 2.6, md5 is deprecated.  Import hashlib if
+# available, avoiding a deprecation warning under 2.6.  Import md5 otherwise,
+# preserving 2.4 compatibility.
+try:
+  import hashlib
+  _md5 = hashlib.md5
+except ImportError:
+  import md5
+  _md5 = md5.new
+
 class KerberosServiceCheck(KerberosScript):
   def service_check(self, env):
     import params
 
-    if params.smoke_test_principal is None:
-      params.smoke_test_principal = params.smoke_user
-
-    # First attempt to test using the smoke test user, if data is available
     if ((params.smoke_test_principal is not None) and
           (params.smoke_test_keytab_file is not None) and
           os.path.isfile(params.smoke_test_keytab_file)):
-      print "Performing kinit using smoke test user: %s" % 
params.smoke_test_principal
-      code, out = self.test_kinit({
-        'principal': params.smoke_test_principal,
-        'keytab_file': params.smoke_test_keytab_file
-      }, user=params.smoke_user)
-      test_performed = True
+      print "Performing kinit using %s" % params.smoke_test_principal
 
+      ccache_file_name = 
_md5("{0}|{1}".format(params.smoke_test_principal,params.smoke_test_keytab_file)).hexdigest()
+      ccache_file_path = 
"{0}{1}kerberos_service_check_cc_{2}".format(params.tmp_dir, os.sep, 
ccache_file_name)
+
+      kinit_path_local = functions.get_kinit_path()
+      kinit_command = "{0} -c {1} -kt {2} {3}".format(kinit_path_local, 
ccache_file_path, params.smoke_test_keytab_file, params.smoke_test_principal)
+
+      try:
+        # kinit
+        Execute(kinit_command)
+      finally:
+        os.remove(ccache_file_path)
     else:
-      code = -1
-      out = 'No principal or keytab found'
-      test_performed = False
-
-    if test_performed:
-      if code == 0:
-        print "Test executed successfully."
-      else:
-        print "Test failed with error code %d: %s." % (code, out)
-    else:
-      print "Test not performed - no test principal was available"
+      err_msg = Logger.filter_text("Failed to execute kinit test due to 
principal or keytab not found or available")
+      raise Fail(err_msg)
 
 if __name__ == "__main__":
   KerberosServiceCheck().execute()

http://git-wip-us.apache.org/repos/asf/ambari/blob/954b96e1/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
index e16f22f..8e1c0e8 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
@@ -358,6 +358,16 @@ public class KerberosHelperTest extends EasyMockSupport {
     testDisableKerberos(new KerberosCredential("principal", "password", 
"keytab"), false, true);
   }
 
+  @Test
+  public void testCreateTestIdentity() throws Exception {
+    testCreateTestIdentity(new KerberosCredential("principal", "password", 
"keytab"));
+  }
+
+  @Test
+  public void testDeleteTestIdentity() throws Exception {
+    testDeleteTestIdentity(new KerberosCredential("principal", "password", 
"keytab"));
+  }
+
   private void testEnableKerberos(final KerberosCredential kerberosCredential,
                                   boolean getClusterDescriptor,
                                   boolean getStackDescriptor) throws Exception 
{
@@ -1835,4 +1845,387 @@ public class KerberosHelperTest extends EasyMockSupport 
{
 
     verifyAll();
   }
+
+  private void testCreateTestIdentity(final KerberosCredential 
kerberosCredential) throws Exception {
+    KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class);
+
+    final ServiceComponentHost schKerberosClient = 
createMock(ServiceComponentHost.class);
+    
expect(schKerberosClient.getServiceName()).andReturn(Service.Type.KERBEROS.name()).anyTimes();
+    
expect(schKerberosClient.getServiceComponentName()).andReturn(Role.KERBEROS_CLIENT.name()).anyTimes();
+    expect(schKerberosClient.getHostName()).andReturn("host1").anyTimes();
+    expect(schKerberosClient.getState()).andReturn(State.INSTALLED).anyTimes();
+
+    final ServiceComponentHost sch1 = createMock(ServiceComponentHost.class);
+    expect(sch1.getServiceName()).andReturn("SERVICE1").anyTimes();
+    expect(sch1.getServiceComponentName()).andReturn("COMPONENT1").anyTimes();
+    expect(sch1.getHostName()).andReturn("host1").anyTimes();
+
+    final ServiceComponentHost sch2 = 
createStrictMock(ServiceComponentHost.class);
+    expect(sch2.getServiceName()).andReturn("SERVICE2").anyTimes();
+    expect(sch2.getServiceComponentName()).andReturn("COMPONENT3").anyTimes();
+
+    final ServiceComponentHost sch3 = 
createStrictMock(ServiceComponentHost.class);
+    expect(sch3.getServiceName()).andReturn("SERVICE3").anyTimes();
+    expect(sch3.getServiceComponentName()).andReturn("COMPONENT3").anyTimes();
+    expect(sch3.getHostName()).andReturn("host1").anyTimes();
+
+    final Host host = createNiceMock(Host.class);
+    expect(host.getHostName()).andReturn("host1").anyTimes();
+    expect(host.getState()).andReturn(HostState.HEALTHY).anyTimes();
+
+    final ServiceComponent serviceComponentKerberosClient = 
createNiceMock(ServiceComponent.class);
+    
expect(serviceComponentKerberosClient.getName()).andReturn(Role.KERBEROS_CLIENT.name()).anyTimes();
+    
expect(serviceComponentKerberosClient.getServiceComponentHosts()).andReturn(Collections.singletonMap("host1",
 schKerberosClient)).anyTimes();
+
+    final Service serviceKerberos = createStrictMock(Service.class);
+    
expect(serviceKerberos.getName()).andReturn(Service.Type.KERBEROS.name()).anyTimes();
+    expect(serviceKerberos.getServiceComponents())
+        .andReturn(Collections.singletonMap(Role.KERBEROS_CLIENT.name(), 
serviceComponentKerberosClient))
+        .times(2);
+
+    final Service service1 = createStrictMock(Service.class);
+    expect(service1.getName()).andReturn("SERVICE1").anyTimes();
+    expect(service1.getServiceComponents())
+        .andReturn(Collections.<String, ServiceComponent>emptyMap())
+        .times(2);
+
+    final Service service2 = createStrictMock(Service.class);
+    expect(service2.getName()).andReturn("SERVICE2").anyTimes();
+    expect(service2.getServiceComponents())
+        .andReturn(Collections.<String, ServiceComponent>emptyMap())
+        .times(2);
+
+    final Map<String, String> kerberosEnvProperties = 
createNiceMock(Map.class);
+    
expect(kerberosEnvProperties.get("kdc_type")).andReturn("mit-kdc").anyTimes();
+    
expect(kerberosEnvProperties.get("realm")).andReturn("FOOBAR.COM").anyTimes();
+
+    final Config kerberosEnvConfig = createNiceMock(Config.class);
+    
expect(kerberosEnvConfig.getProperties()).andReturn(kerberosEnvProperties).anyTimes();
+
+    final Map<String, String> krb5ConfProperties = createNiceMock(Map.class);
+
+    final Config krb5ConfConfig = createNiceMock(Config.class);
+    
expect(krb5ConfConfig.getProperties()).andReturn(krb5ConfProperties).anyTimes();
+
+    final Cluster cluster = createNiceMock(Cluster.class);
+    
expect(cluster.getDesiredConfigByType("krb5-conf")).andReturn(krb5ConfConfig).anyTimes();
+    
expect(cluster.getDesiredConfigByType("kerberos-env")).andReturn(kerberosEnvConfig).anyTimes();
+    expect(cluster.getClusterName()).andReturn("c1").anyTimes();
+    expect(cluster.getServices())
+        .andReturn(new HashMap<String, Service>() {
+          {
+            put(Service.Type.KERBEROS.name(), serviceKerberos);
+            put("SERVICE1", service1);
+            put("SERVICE2", service2);
+          }
+        })
+        .anyTimes();
+    expect(cluster.getServiceComponentHosts("host1"))
+        .andReturn(new ArrayList<ServiceComponentHost>() {
+          {
+            add(sch1);
+            add(sch2);
+            add(sch3);
+            add(schKerberosClient);
+          }
+        })
+        .once();
+    expect(cluster.getCurrentStackVersion())
+        .andReturn(new StackId("HDP", "2.2"))
+        .anyTimes();
+    expect(cluster.getSessionAttributes()).andReturn(new HashMap<String, 
Object>() {{
+      if (kerberosCredential != null) {
+        put("kerberos_admin/" + KerberosCredential.KEY_NAME_PRINCIPAL, 
kerberosCredential.getPrincipal());
+        put("kerberos_admin/" + KerberosCredential.KEY_NAME_PASSWORD, 
kerberosCredential.getPassword());
+        put("kerberos_admin/" + KerberosCredential.KEY_NAME_KEYTAB, 
kerberosCredential.getKeytab());
+      }
+    }}).anyTimes();
+
+    final Clusters clusters = injector.getInstance(Clusters.class);
+    expect(clusters.getHostsForCluster("c1"))
+        .andReturn(new HashMap<String, Host>() {
+          {
+            put("host1", host);
+          }
+        })
+        .once();
+    expect(clusters.getHost("host1"))
+        .andReturn(host)
+        .once();
+
+    final AmbariManagementController ambariManagementController = 
injector.getInstance(AmbariManagementController.class);
+    
expect(ambariManagementController.findConfigurationTagsWithOverrides(cluster, 
"host1"))
+        .andReturn(Collections.<String, Map<String, String>>emptyMap())
+        .once();
+    
expect(ambariManagementController.findConfigurationTagsWithOverrides(cluster, 
null))
+        .andReturn(Collections.<String, Map<String, String>>emptyMap())
+        .once();
+    expect(ambariManagementController.getRoleCommandOrder(cluster))
+        .andReturn(createNiceMock(RoleCommandOrder.class))
+        .once();
+
+    final ConfigHelper configHelper = injector.getInstance(ConfigHelper.class);
+    expect(configHelper.getEffectiveConfigProperties(anyObject(Cluster.class), 
anyObject(Map.class)))
+        .andReturn(new HashMap<String, Map<String, String>>() {
+          {
+            put("cluster-env", new HashMap<String, String>() {{
+              put("kerberos_domain", "FOOBAR.COM");
+            }});
+          }
+        })
+        .times(1);
+
+    final KerberosDescriptor kerberosDescriptor = 
createStrictMock(KerberosDescriptor.class);
+    expect(kerberosDescriptor.getProperties()).andReturn(null).once();
+
+    setupGetDescriptorFromCluster(kerberosDescriptor);
+
+    final StageFactory stageFactory = injector.getInstance(StageFactory.class);
+    expect(stageFactory.createNew(anyLong(), anyObject(String.class), 
anyObject(String.class),
+        anyLong(), anyObject(String.class), anyObject(String.class), 
anyObject(String.class),
+        anyObject(String.class)))
+        .andAnswer(new IAnswer<Stage>() {
+          @Override
+          public Stage answer() throws Throwable {
+            Stage stage = createNiceMock(Stage.class);
+
+            expect(stage.getHostRoleCommands())
+                .andReturn(Collections.<String, Map<String, 
HostRoleCommand>>emptyMap())
+                .anyTimes();
+            replay(stage);
+            return stage;
+          }
+        })
+        .anyTimes();
+
+    // This is a STRICT mock to help ensure that the end result is what we 
want.
+    final RequestStageContainer requestStageContainer = 
createStrictMock(RequestStageContainer.class);
+    // Create Principals Stage
+    expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes();
+    expect(requestStageContainer.getId()).andReturn(1L).once();
+    requestStageContainer.addStages(anyObject(List.class));
+    expectLastCall().once();
+    // Create Keytabs Stage
+    expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes();
+    expect(requestStageContainer.getId()).andReturn(1L).once();
+    requestStageContainer.addStages(anyObject(List.class));
+    expectLastCall().once();
+    // Distribute Keytabs Stage
+    expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes();
+    expect(requestStageContainer.getId()).andReturn(1L).once();
+    requestStageContainer.addStages(anyObject(List.class));
+    expectLastCall().once();
+    // Clean-up/Finalize Stage
+    expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes();
+    expect(requestStageContainer.getId()).andReturn(1L).once();
+    requestStageContainer.addStages(anyObject(List.class));
+    expectLastCall().once();
+
+    replayAll();
+
+    // Needed by infrastructure
+    injector.getInstance(AmbariMetaInfo.class).init();
+
+    Map<String, String> commandParamsStage = new HashMap<String, String>();
+    kerberosHelper.createTestIdentity(cluster, commandParamsStage, 
requestStageContainer);
+
+    verifyAll();
+
+    String serviceCheckID = 
(String)cluster.getSessionAttributes().get("_kerberos_internal_service_check_identifier");
+    Assert.assertNotNull(serviceCheckID);
+
+    Assert.assertTrue(commandParamsStage.containsKey("principal_name"));
+    Assert.assertEquals("${cluster-env/smokeuser}_" + serviceCheckID + 
"@${realm}", commandParamsStage.get("principal_name"));
+
+    Assert.assertTrue(commandParamsStage.containsKey("keytab_file"));
+    Assert.assertEquals("${keytab_dir}/kerberos.service_check." + 
serviceCheckID + ".keytab", commandParamsStage.get("keytab_file"));
+  }
+
+  private void testDeleteTestIdentity(final KerberosCredential 
kerberosCredential) throws Exception {
+    KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class);
+
+    final ServiceComponentHost schKerberosClient = 
createMock(ServiceComponentHost.class);
+    
expect(schKerberosClient.getServiceName()).andReturn(Service.Type.KERBEROS.name()).anyTimes();
+    
expect(schKerberosClient.getServiceComponentName()).andReturn(Role.KERBEROS_CLIENT.name()).anyTimes();
+    expect(schKerberosClient.getHostName()).andReturn("host1").anyTimes();
+    expect(schKerberosClient.getState()).andReturn(State.INSTALLED).anyTimes();
+
+    final ServiceComponentHost sch1 = createMock(ServiceComponentHost.class);
+    expect(sch1.getServiceName()).andReturn("SERVICE1").anyTimes();
+    expect(sch1.getServiceComponentName()).andReturn("COMPONENT1").anyTimes();
+    expect(sch1.getHostName()).andReturn("host1").anyTimes();
+
+    final ServiceComponentHost sch2 = 
createStrictMock(ServiceComponentHost.class);
+    expect(sch2.getServiceName()).andReturn("SERVICE2").anyTimes();
+    expect(sch2.getServiceComponentName()).andReturn("COMPONENT3").anyTimes();
+
+    final ServiceComponentHost sch3 = 
createStrictMock(ServiceComponentHost.class);
+    expect(sch3.getServiceName()).andReturn("SERVICE3").anyTimes();
+    expect(sch3.getServiceComponentName()).andReturn("COMPONENT3").anyTimes();
+    expect(sch3.getHostName()).andReturn("host1").anyTimes();
+
+    final Host host = createNiceMock(Host.class);
+    expect(host.getHostName()).andReturn("host1").anyTimes();
+    expect(host.getState()).andReturn(HostState.HEALTHY).anyTimes();
+
+    final ServiceComponent serviceComponentKerberosClient = 
createNiceMock(ServiceComponent.class);
+    
expect(serviceComponentKerberosClient.getName()).andReturn(Role.KERBEROS_CLIENT.name()).anyTimes();
+    
expect(serviceComponentKerberosClient.getServiceComponentHosts()).andReturn(Collections.singletonMap("host1",
 schKerberosClient)).anyTimes();
+
+    final Service serviceKerberos = createStrictMock(Service.class);
+    
expect(serviceKerberos.getName()).andReturn(Service.Type.KERBEROS.name()).anyTimes();
+    expect(serviceKerberos.getServiceComponents())
+        .andReturn(Collections.singletonMap(Role.KERBEROS_CLIENT.name(), 
serviceComponentKerberosClient))
+        .times(2);
+
+    final Service service1 = createStrictMock(Service.class);
+    expect(service1.getName()).andReturn("SERVICE1").anyTimes();
+    expect(service1.getServiceComponents())
+        .andReturn(Collections.<String, ServiceComponent>emptyMap())
+        .times(2);
+
+    final Service service2 = createStrictMock(Service.class);
+    expect(service2.getName()).andReturn("SERVICE2").anyTimes();
+    expect(service2.getServiceComponents())
+        .andReturn(Collections.<String, ServiceComponent>emptyMap())
+        .times(2);
+
+    final Map<String, String> kerberosEnvProperties = 
createNiceMock(Map.class);
+    
expect(kerberosEnvProperties.get("kdc_type")).andReturn("mit-kdc").anyTimes();
+    
expect(kerberosEnvProperties.get("realm")).andReturn("FOOBAR.COM").anyTimes();
+
+    final Config kerberosEnvConfig = createNiceMock(Config.class);
+    
expect(kerberosEnvConfig.getProperties()).andReturn(kerberosEnvProperties).anyTimes();
+
+    final Map<String, String> krb5ConfProperties = createNiceMock(Map.class);
+
+    final Config krb5ConfConfig = createNiceMock(Config.class);
+    
expect(krb5ConfConfig.getProperties()).andReturn(krb5ConfProperties).anyTimes();
+
+    final Cluster cluster = createNiceMock(Cluster.class);
+    
expect(cluster.getDesiredConfigByType("krb5-conf")).andReturn(krb5ConfConfig).anyTimes();
+    
expect(cluster.getDesiredConfigByType("kerberos-env")).andReturn(kerberosEnvConfig).anyTimes();
+    expect(cluster.getClusterName()).andReturn("c1").anyTimes();
+    expect(cluster.getServices())
+        .andReturn(new HashMap<String, Service>() {
+          {
+            put(Service.Type.KERBEROS.name(), serviceKerberos);
+            put("SERVICE1", service1);
+            put("SERVICE2", service2);
+          }
+        })
+        .anyTimes();
+    expect(cluster.getServiceComponentHosts("host1"))
+        .andReturn(new ArrayList<ServiceComponentHost>() {
+          {
+            add(sch1);
+            add(sch2);
+            add(sch3);
+            add(schKerberosClient);
+          }
+        })
+        .once();
+    expect(cluster.getCurrentStackVersion())
+        .andReturn(new StackId("HDP", "2.2"))
+        .anyTimes();
+    expect(cluster.getSessionAttributes()).andReturn(new HashMap<String, 
Object>() {{
+      if (kerberosCredential != null) {
+        put("kerberos_admin/" + KerberosCredential.KEY_NAME_PRINCIPAL, 
kerberosCredential.getPrincipal());
+        put("kerberos_admin/" + KerberosCredential.KEY_NAME_PASSWORD, 
kerberosCredential.getPassword());
+        put("kerberos_admin/" + KerberosCredential.KEY_NAME_KEYTAB, 
kerberosCredential.getKeytab());
+      }
+    }}).anyTimes();
+
+    final Clusters clusters = injector.getInstance(Clusters.class);
+    expect(clusters.getHostsForCluster("c1"))
+        .andReturn(new HashMap<String, Host>() {
+          {
+            put("host1", host);
+          }
+        })
+        .once();
+    expect(clusters.getHost("host1"))
+        .andReturn(host)
+        .once();
+
+    final AmbariManagementController ambariManagementController = 
injector.getInstance(AmbariManagementController.class);
+    
expect(ambariManagementController.findConfigurationTagsWithOverrides(cluster, 
"host1"))
+        .andReturn(Collections.<String, Map<String, String>>emptyMap())
+        .once();
+    
expect(ambariManagementController.findConfigurationTagsWithOverrides(cluster, 
null))
+        .andReturn(Collections.<String, Map<String, String>>emptyMap())
+        .once();
+    expect(ambariManagementController.getRoleCommandOrder(cluster))
+        .andReturn(createNiceMock(RoleCommandOrder.class))
+        .once();
+
+    final ConfigHelper configHelper = injector.getInstance(ConfigHelper.class);
+    expect(configHelper.getEffectiveConfigProperties(anyObject(Cluster.class), 
anyObject(Map.class)))
+        .andReturn(new HashMap<String, Map<String, String>>() {
+          {
+            put("cluster-env", new HashMap<String, String>() {{
+              put("kerberos_domain", "FOOBAR.COM");
+            }});
+          }
+        })
+        .times(1);
+
+    final KerberosDescriptor kerberosDescriptor = 
createStrictMock(KerberosDescriptor.class);
+    expect(kerberosDescriptor.getProperties()).andReturn(null).once();
+
+    setupGetDescriptorFromCluster(kerberosDescriptor);
+
+    final StageFactory stageFactory = injector.getInstance(StageFactory.class);
+    expect(stageFactory.createNew(anyLong(), anyObject(String.class), 
anyObject(String.class),
+        anyLong(), anyObject(String.class), anyObject(String.class), 
anyObject(String.class),
+        anyObject(String.class)))
+        .andAnswer(new IAnswer<Stage>() {
+          @Override
+          public Stage answer() throws Throwable {
+            Stage stage = createNiceMock(Stage.class);
+
+            expect(stage.getHostRoleCommands())
+                .andReturn(Collections.<String, Map<String, 
HostRoleCommand>>emptyMap())
+                .anyTimes();
+            replay(stage);
+            return stage;
+          }
+        })
+        .anyTimes();
+
+    // This is a STRICT mock to help ensure that the end result is what we 
want.
+    final RequestStageContainer requestStageContainer = 
createStrictMock(RequestStageContainer.class);
+    // Delete  Principals Stage
+    expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes();
+    expect(requestStageContainer.getId()).andReturn(1L).once();
+    requestStageContainer.addStages(anyObject(List.class));
+    expectLastCall().once();
+    // Delete Keytabs Stage
+    expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes();
+    expect(requestStageContainer.getId()).andReturn(1L).once();
+    requestStageContainer.addStages(anyObject(List.class));
+    expectLastCall().once();
+    // Clean-up/Finalize Stage
+    expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes();
+    expect(requestStageContainer.getId()).andReturn(1L).once();
+    requestStageContainer.addStages(anyObject(List.class));
+    expectLastCall().once();
+
+    replayAll();
+
+    // Needed by infrastructure
+    injector.getInstance(AmbariMetaInfo.class).init();
+
+    String serviceCheckID = "some_random_value";
+
+    
cluster.getSessionAttributes().put("_kerberos_internal_service_check_identifier",
 serviceCheckID);
+
+    Map<String, String> commandParamsStage = new HashMap<String, String>();
+    commandParamsStage.put("principal_name", "${cluster-env/smokeuser}_" + 
serviceCheckID + "@${realm}");
+    commandParamsStage.put("keytab_file", 
"${keytab_dir}/kerberos.service_check." + serviceCheckID + ".keytab");
+
+    kerberosHelper.deleteTestIdentity(cluster, commandParamsStage, 
requestStageContainer);
+
+    verifyAll();
+  }
 }

Reply via email to