This is an automated email from the ASF dual-hosted git repository.
hapylestat pushed a commit to branch branch-2.6
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/branch-2.6 by this push:
new 2616503 AMBARI-25443. Create principal/keytab operation with multi
threaded (dgrinenko)
2616503 is described below
commit 26165032d50ff1059229424bbe3c16b36b77ce4e
Author: Dmitry Grinenko <[email protected]>
AuthorDate: Mon Dec 9 09:18:29 2019 +0200
AMBARI-25443. Create principal/keytab operation with multi threaded
(dgrinenko)
---
.../ambari/server/configuration/Configuration.java | 34 ++++
.../server/controller/KerberosHelperImpl.java | 3 +-
.../HostKerberosIdentityResourceProvider.java | 8 +-
.../ConfigureAmbariIdentitiesServerAction.java | 41 +++--
.../kerberos/CreateKeytabFilesServerAction.java | 203 +++++++++++----------
.../kerberos/CreatePrincipalsServerAction.java | 35 +++-
.../kerberos/DestroyPrincipalsServerAction.java | 98 +++++-----
.../kerberos/FinalizeKerberosServerAction.java | 18 +-
.../kerberos/KerberosServerAction.java | 81 ++++++--
.../HostKerberosIdentityResourceProviderTest.java | 18 +-
.../AbstractPrepareKerberosServerActionTest.java | 25 +--
.../ConfigureAmbariIdentitiesServerActionTest.java | 2 +
.../kerberos/FinalizeKerberosServerActionTest.java | 2 +
.../server/view/HttpImpersonatorImplTest.java | 1 -
14 files changed, 380 insertions(+), 189 deletions(-)
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index f553905..67c6967 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -2736,6 +2736,20 @@ public class Configuration {
public static final ConfigurationProperty<Integer> TLS_EPHEMERAL_DH_KEY_SIZE
= new ConfigurationProperty<>(
"security.server.tls.ephemeral_dh_key_size", 2048);
+ /**
+ * The number of threads to use when executing server-side Kerberos
commands, such as generate keytabs.
+ */
+ @Markdown(description = "The number of threads to use when executing
server-side Kerberos commands, such as generate keytabs.")
+ public static final ConfigurationProperty<Integer>
KERBEROS_SERVER_ACTION_THREADPOOL_SIZE = new ConfigurationProperty<>(
+ "server.kerberos.action.threadpool.size", 1);
+
+ /**
+ * The timeout, in seconds, when finalizing Kerberos
enable/disable/regenerate commands.
+ */
+ @Markdown(description = "The timeout, in seconds, when finalizing Kerberos
enable/disable/regenerate commands.")
+ public static final ConfigurationProperty<Integer>
KERBEROS_SERVER_ACTION_FINALIZE_SECONDS = new ConfigurationProperty<>(
+ "server.kerberos.finalize.timeout", 600);
+
private static final Logger LOG = LoggerFactory.getLogger(
Configuration.class);
@@ -5619,6 +5633,26 @@ public class Configuration {
}
/**
+ * Gets the number of threads to use when executing server-side Kerberos
+ * commands, such as generate keytabs.
+ *
+ * @return the threadpool size, defaulting to 1
+ */
+ public int getKerberosServerActionThreadpoolSize() {
+ return
Integer.parseInt(getProperty(KERBEROS_SERVER_ACTION_THREADPOOL_SIZE));
+ }
+
+ /**
+ * Get the timeout, in seconds, when finalizing Kerberos
+ * enable/disable/regenerate commands.
+ *
+ * @return the timeout, in seconds, defaulting to 600.
+ */
+ public int getKerberosServerActionFinalizeTimeout() {
+ return
Integer.parseInt(getProperty(KERBEROS_SERVER_ACTION_FINALIZE_SECONDS));
+ }
+
+ /**
* Generates a markdown table which includes:
* <ul>
* <li>Property key name</li>
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
index 4402d4e..0e3560b 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
@@ -3637,6 +3637,7 @@ public class KerberosHelperImpl implements KerberosHelper
{
commandParameters.put(KerberosServerAction.DATA_DIRECTORY,
dataDirectory.getAbsolutePath());
}
+ int timeout = configuration.getKerberosServerActionFinalizeTimeout();
Stage stage =
createServerActionStage(requestStageContainer.getLastStageId(),
cluster,
requestStageContainer.getId(),
@@ -3646,7 +3647,7 @@ public class KerberosHelperImpl implements KerberosHelper
{
FinalizeKerberosServerAction.class,
event,
commandParameters,
- "Finalize Operations", 300);
+ "Finalize Operations", timeout);
RoleGraph roleGraph = roleGraphFactory.createNew(roleCommandOrder);
roleGraph.build(stage);
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProvider.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProvider.java
index 5ed5f35..ef25b39 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProvider.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProvider.java
@@ -34,6 +34,9 @@ import org.apache.ambari.server.orm.dao.HostDAO;
import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO;
import org.apache.ambari.server.orm.dao.KerberosPrincipalHostDAO;
import org.apache.ambari.server.orm.entities.HostEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor;
@@ -158,10 +161,13 @@ public class HostKerberosIdentityResourceProvider extends
ReadOnlyResourceProvid
for (Map<String, Object> propertyMap : propertyMaps) {
String clusterName = (String)
propertyMap.get(KERBEROS_IDENTITY_CLUSTER_NAME_PROPERTY_ID);
String hostName = (String)
propertyMap.get(KERBEROS_IDENTITY_HOST_NAME_PROPERTY_ID);
+ Clusters clusters = getManagementController().getClusters();
+ Cluster cluster = clusters.getCluster(clusterName);
+ KerberosDescriptor kerberosDescriptor =
kerberosHelper.getKerberosDescriptor(cluster, false);
// Retrieve the active identities for the cluster filtered and grouped
by hostname
Map<String, Collection<KerberosIdentityDescriptor>> hostDescriptors =
- kerberosHelper.getActiveIdentities(clusterName, hostName, null,
null, true);
+ kerberosHelper.getActiveIdentities(clusterName, hostName, null,
null,true);
if (hostDescriptors != null) {
for (Map.Entry<String, Collection<KerberosIdentityDescriptor>> entry
: hostDescriptors.entrySet()) {
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
index 2c660fd..63a1d55 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
@@ -22,8 +22,8 @@ import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.Lock;
-import com.google.inject.Inject;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.actionmanager.HostRoleStatus;
import org.apache.ambari.server.agent.CommandReport;
@@ -40,6 +40,9 @@ import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.util.concurrent.Striped;
+import com.google.inject.Inject;
+
/**
* ConfigureAmbariIdentitiesServerAction is a ServerAction implementation that
creates keytab files as
* instructed.
@@ -65,6 +68,11 @@ public class ConfigureAmbariIdentitiesServerAction extends
KerberosServerAction
private HostDAO hostDAO;
/**
+ * Used to prevent multiple threads from working with the same keytab.
+ */
+ private Striped<Lock> m_locksByKeytab = Striped.lazyWeakLock(25);
+
+ /**
* Called to execute this action. Upon invocation, calls
* {@link KerberosServerAction#processIdentities(Map)} )}
* to iterate through the Kerberos identity metadata and call
@@ -118,29 +126,34 @@ public class ConfigureAmbariIdentitiesServerAction
extends KerberosServerAction
LOG.error(message);
commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}",
actionLog.getStdOut(), actionLog.getStdErr());
} else {
-
String hostName =
identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME);
if (hostName != null &&
hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME)) {
String destKeytabFilePath =
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH);
File hostDirectory = new File(dataDirectory, hostName);
File srcKeytabFile = new File(hostDirectory,
DigestUtils.sha1Hex(destKeytabFilePath));
- if (srcKeytabFile.exists()) {
- String ownerAccess =
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_OWNER_ACCESS);
- boolean ownerWritable = "w".equalsIgnoreCase(ownerAccess) ||
"rw".equalsIgnoreCase(ownerAccess);
- boolean ownerReadable = "r".equalsIgnoreCase(ownerAccess) ||
"rw".equalsIgnoreCase(ownerAccess);
- String groupAccess =
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_OWNER_ACCESS);
- boolean groupWritable = "w".equalsIgnoreCase(groupAccess) ||
"rw".equalsIgnoreCase(groupAccess);
- boolean groupReadable = "r".equalsIgnoreCase(groupAccess) ||
"rw".equalsIgnoreCase(groupAccess);
-
- installAmbariServerIdentity(evaluatedPrincipal,
srcKeytabFile.getAbsolutePath(), destKeytabFilePath,
+ Lock lock = m_locksByKeytab.get(destKeytabFilePath);
+ lock.lock();
+ try {
+ if (srcKeytabFile.exists()) {
+ String ownerAccess =
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_OWNER_ACCESS);
+ boolean ownerWritable = "w".equalsIgnoreCase(ownerAccess) ||
"rw".equalsIgnoreCase(ownerAccess);
+ boolean ownerReadable = "r".equalsIgnoreCase(ownerAccess) ||
"rw".equalsIgnoreCase(ownerAccess);
+ String groupAccess =
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_OWNER_ACCESS);
+ boolean groupWritable = "w".equalsIgnoreCase(groupAccess) ||
"rw".equalsIgnoreCase(groupAccess);
+ boolean groupReadable = "r".equalsIgnoreCase(groupAccess) ||
"rw".equalsIgnoreCase(groupAccess);
+
+ installAmbariServerIdentity(evaluatedPrincipal,
srcKeytabFile.getAbsolutePath(), destKeytabFilePath,
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_OWNER_NAME),
ownerReadable, ownerWritable,
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_GROUP_NAME),
groupReadable, groupWritable, actionLog);
- if
("AMBARI_SERVER_SELF".equals(identityRecord.get(KerberosIdentityDataFileReader.COMPONENT)))
{
- // Create/update the JAASFile...
- configureJAAS(evaluatedPrincipal, destKeytabFilePath, actionLog);
+ if
("AMBARI_SERVER_SELF".equals(identityRecord.get(KerberosIdentityDataFileReader.COMPONENT)))
{
+ // Create/update the JAASFile...
+ configureJAAS(evaluatedPrincipal, destKeytabFilePath,
actionLog);
+ }
}
+ } finally {
+ lock.unlock();
}
}
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
index d2488b6..836beaa 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
@@ -18,7 +18,10 @@
package org.apache.ambari.server.serveraction.kerberos;
+import com.google.common.util.concurrent.Striped;
import com.google.inject.Inject;
+import com.sun.jersey.client.impl.CopyOnWriteHashMap;
+
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.actionmanager.HostRoleStatus;
import org.apache.ambari.server.agent.CommandReport;
@@ -42,7 +45,9 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.Lock;
/**
* CreateKeytabFilesServerAction is a ServerAction implementation that creates
keytab files as
@@ -82,10 +87,15 @@ public class CreateKeytabFilesServerAction extends
KerberosServerAction {
private HostDAO hostDAO;
/**
+ * Used to prevent multiple threads from working with the same keytab.
+ */
+ private Striped<Lock> m_locksByKeytab = Striped.lazyWeakLock(25);
+
+ /**
* A map of data used to track what has been processed in order to optimize
the creation of keytabs
* such as knowing when to create a cached keytab file or use a cached
keytab file.
*/
- Map<String, Set<String>> visitedIdentities = new HashMap<String,
Set<String>>();
+ Map<String, Set<String>> visitedIdentities = new ConcurrentHashMap<>();
/**
* Called to execute this action. Upon invocation, calls
@@ -180,118 +190,125 @@ public class CreateKeytabFilesServerAction extends
KerberosServerAction {
String keytabFilePath =
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH);
if ((hostName != null) && !hostName.isEmpty() && (keytabFilePath !=
null) && !keytabFilePath.isEmpty()) {
- Set<String> visitedPrincipalKeys =
visitedIdentities.get(evaluatedPrincipal);
- String visitationKey = String.format("%s|%s", hostName,
keytabFilePath);
-
- if ((visitedPrincipalKeys == null) ||
!visitedPrincipalKeys.contains(visitationKey)) {
- // Look up the current evaluatedPrincipal's password.
- // If found create the keytab file, else try to find it in the
cache.
- String password = principalPasswordMap.get(evaluatedPrincipal);
- Integer keyNumber =
principalKeyNumberMap.get(evaluatedPrincipal);
-
- message = String.format("Creating keytab file for %s on host
%s", evaluatedPrincipal, hostName);
- LOG.info(message);
- actionLog.writeStdOut(message);
-
auditEventBuilder.withPrincipal(evaluatedPrincipal).withHostName(hostName).withKeyTabFilePath(keytabFilePath);
-
- // Determine where to store the keytab file. It should go into
a host-specific
- // directory under the previously determined data directory.
- File hostDirectory = new File(dataDirectory, hostName);
-
- // Ensure the host directory exists...
- if (!hostDirectory.exists() && hostDirectory.mkdirs()) {
- // Make sure only Ambari has access to this directory.
- ensureAmbariOnlyAccess(hostDirectory);
- }
+ Lock lock = m_locksByKeytab.get(keytabFilePath);
+ lock.lock();
+
+ try {
+ Set<String> visitedPrincipalKeys =
visitedIdentities.get(evaluatedPrincipal);
+ String visitationKey = String.format("%s|%s", hostName,
keytabFilePath);
+
+ if ((visitedPrincipalKeys == null) ||
!visitedPrincipalKeys.contains(visitationKey)) {
+ // Look up the current evaluatedPrincipal's password.
+ // If found create the keytab file, else try to find it in the
cache.
+ String password = principalPasswordMap.get(evaluatedPrincipal);
+ Integer keyNumber =
principalKeyNumberMap.get(evaluatedPrincipal);
+
+ message = String.format("Creating keytab file for %s on host
%s", evaluatedPrincipal, hostName);
+ LOG.info(message);
+ actionLog.writeStdOut(message);
+
auditEventBuilder.withPrincipal(evaluatedPrincipal).withHostName(hostName).withKeyTabFilePath(keytabFilePath);
+
+ // Determine where to store the keytab file. It should go
into a host-specific
+ // directory under the previously determined data directory.
+ File hostDirectory = new File(dataDirectory, hostName);
+
+ // Ensure the host directory exists...
+ if (!hostDirectory.exists() && hostDirectory.mkdirs()) {
+ // Make sure only Ambari has access to this directory.
+ ensureAmbariOnlyAccess(hostDirectory);
+ }
- if (hostDirectory.exists()) {
- File destinationKeytabFile = new File(hostDirectory,
DigestUtils.sha1Hex(keytabFilePath));
- HostEntity hostEntity = hostDAO.findByName(hostName);
- // in case of ambari-server identity there's no host entity for
ambari_server host
- if (hostEntity == null &&
!hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME)) {
- message = "Failed to find HostEntity for hostname = " +
hostName;
- actionLog.writeStdErr(message);
- LOG.error(message);
- commandReport = createCommandReport(1, HostRoleStatus.FAILED,
"{}", actionLog.getStdOut(), actionLog.getStdErr());
- return commandReport;
- }
+ if (hostDirectory.exists()) {
+ File destinationKeytabFile = new File(hostDirectory,
DigestUtils.sha1Hex(keytabFilePath));
+ HostEntity hostEntity = hostDAO.findByName(hostName);
+ // in case of ambari-server identity there's no host entity
for ambari_server host
+ if (hostEntity == null &&
!hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME)) {
+ message = "Failed to find HostEntity for hostname = " +
hostName;
+ actionLog.writeStdErr(message);
+ LOG.error(message);
+ commandReport = createCommandReport(1,
HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+ return commandReport;
+ }
- boolean canCache =
"true".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_IS_CACHABLE));
- boolean regenerateKeytabs =
"true".equalsIgnoreCase(getCommandParameterValue(getCommandParameters(),
REGENERATE_ALL));
- boolean onlyKeytabWrite =
"true".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.ONLY_KEYTAB_WRITE));
- boolean grabKeytabFromCache = regenerateKeytabs &&
onlyKeytabWrite;
+ boolean canCache =
"true".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_IS_CACHABLE));
+ boolean regenerateKeytabs =
"true".equalsIgnoreCase(getCommandParameterValue(getCommandParameters(),
REGENERATE_ALL));
+ boolean onlyKeytabWrite =
"true".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.ONLY_KEYTAB_WRITE));
+ boolean grabKeytabFromCache = regenerateKeytabs &&
onlyKeytabWrite;
- if (password == null) { // if canCache=true we will try to get
keytab from cache and send to agent.
- if (!grabKeytabFromCache &&
(hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME) ||
kerberosPrincipalHostDAO
- .exists(evaluatedPrincipal, hostEntity.getHostId()))) {
- // There is nothing to do for this since it must already
exist and we don't want to
- // regenerate the keytab
- message = String.format("Skipping keytab file for %s,
missing password indicates nothing to do", evaluatedPrincipal);
- LOG.debug(message);
- } else {
- KerberosPrincipalEntity principalEntity =
kerberosPrincipalDAO.find(evaluatedPrincipal);
- String cachedKeytabPath = (principalEntity == null) ? null :
principalEntity.getCachedKeytabPath();
-
- if (cachedKeytabPath == null) {
- message = String.format("Failed to create keytab for %s,
missing cached file", evaluatedPrincipal);
- actionLog.writeStdErr(message);
- LOG.error(message);
- commandReport = createCommandReport(1,
HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+ if (password == null) { // if canCache=true we will try to
get keytab from cache and send to agent.
+ if (!grabKeytabFromCache &&
(hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME) ||
kerberosPrincipalHostDAO
+ .exists(evaluatedPrincipal, hostEntity.getHostId()))) {
+ // There is nothing to do for this since it must already
exist and we don't want to
+ // regenerate the keytab
+ message = String.format("Skipping keytab file for %s,
missing password indicates nothing to do", evaluatedPrincipal);
+ LOG.debug(message);
} else {
- try {
- operationHandler.createKeytabFile(new
File(cachedKeytabPath), destinationKeytabFile);
- } catch (KerberosOperationException e) {
- message = String.format("Failed to create keytab file
for %s - %s", evaluatedPrincipal, e.getMessage());
+ KerberosPrincipalEntity principalEntity =
kerberosPrincipalDAO.find(evaluatedPrincipal);
+ String cachedKeytabPath = (principalEntity == null) ?
null : principalEntity.getCachedKeytabPath();
+
+ if (cachedKeytabPath == null) {
+ message = String.format("Failed to create keytab for
%s, missing cached file", evaluatedPrincipal);
actionLog.writeStdErr(message);
- LOG.error(message, e);
+ LOG.error(message);
commandReport = createCommandReport(1,
HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+ } else {
+ try {
+ operationHandler.createKeytabFile(new
File(cachedKeytabPath), destinationKeytabFile);
+ } catch (KerberosOperationException e) {
+ message = String.format("Failed to create keytab
file for %s - %s", evaluatedPrincipal, e.getMessage());
+ actionLog.writeStdErr(message);
+ LOG.error(message, e);
+ commandReport = createCommandReport(1,
HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+ }
}
}
- }
- } else {
- Keytab keytab = createKeytab(evaluatedPrincipal, password,
keyNumber, operationHandler, visitedPrincipalKeys != null, canCache, actionLog);
-
- if (keytab != null) {
- try {
- if (operationHandler.createKeytabFile(keytab,
destinationKeytabFile)) {
- ensureAmbariOnlyAccess(destinationKeytabFile);
+ } else {
+ Keytab keytab = createKeytab(evaluatedPrincipal, password,
keyNumber, operationHandler, visitedPrincipalKeys != null, canCache, actionLog);
- message = String.format("Successfully created keytab
file for %s at %s", evaluatedPrincipal,
destinationKeytabFile.getAbsolutePath());
- LOG.debug(message);
-
auditEventBuilder.withPrincipal(evaluatedPrincipal).withHostName(hostName).withKeyTabFilePath(destinationKeytabFile.getAbsolutePath());
- } else {
- message = String.format("Failed to create keytab file
for %s at %s", evaluatedPrincipal, destinationKeytabFile.getAbsolutePath());
+ if (keytab != null) {
+ try {
+ if (operationHandler.createKeytabFile(keytab,
destinationKeytabFile)) {
+ ensureAmbariOnlyAccess(destinationKeytabFile);
+
+ message = String.format("Successfully created keytab
file for %s at %s", evaluatedPrincipal,
destinationKeytabFile.getAbsolutePath());
+ LOG.debug(message);
+
auditEventBuilder.withPrincipal(evaluatedPrincipal).withHostName(hostName).withKeyTabFilePath(destinationKeytabFile.getAbsolutePath());
+ } else {
+ message = String.format("Failed to create keytab
file for %s at %s", evaluatedPrincipal,
destinationKeytabFile.getAbsolutePath());
+ actionLog.writeStdErr(message);
+ LOG.error(message);
+ commandReport = createCommandReport(1,
HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+ }
+ } catch (KerberosOperationException e) {
+ message = String.format("Failed to create keytab file
for %s - %s", evaluatedPrincipal, e.getMessage());
actionLog.writeStdErr(message);
- LOG.error(message);
+ LOG.error(message, e);
commandReport = createCommandReport(1,
HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
}
- } catch (KerberosOperationException e) {
- message = String.format("Failed to create keytab file
for %s - %s", evaluatedPrincipal, e.getMessage());
- actionLog.writeStdErr(message);
- LOG.error(message, e);
+ } else {
commandReport = createCommandReport(1,
HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
}
- } else {
- commandReport = createCommandReport(1,
HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
- }
- if (visitedPrincipalKeys == null) {
- visitedPrincipalKeys = new HashSet<String>();
- visitedIdentities.put(evaluatedPrincipal,
visitedPrincipalKeys);
- }
+ if (visitedPrincipalKeys == null) {
+ visitedPrincipalKeys = new HashSet<String>();
+ visitedIdentities.put(evaluatedPrincipal,
visitedPrincipalKeys);
+ }
- visitedPrincipalKeys.add(visitationKey);
+ visitedPrincipalKeys.add(visitationKey);
+ }
+ } else {
+ message = String.format("Failed to create keytab file for
%s, the container directory does not exist: %s",
+ evaluatedPrincipal, hostDirectory.getAbsolutePath());
+ actionLog.writeStdErr(message);
+ LOG.error(message);
+ commandReport = createCommandReport(1,
HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
}
} else {
- message = String.format("Failed to create keytab file for %s,
the container directory does not exist: %s",
- evaluatedPrincipal, hostDirectory.getAbsolutePath());
- actionLog.writeStdErr(message);
- LOG.error(message);
- commandReport = createCommandReport(1, HostRoleStatus.FAILED,
"{}", actionLog.getStdOut(), actionLog.getStdErr());
+ LOG.debug(String.format("Skipping previously processed keytab
for %s on host %s", evaluatedPrincipal, hostName));
}
- } else {
- LOG.debug(String.format("Skipping previously processed keytab
for %s on host %s", evaluatedPrincipal, hostName));
+ } finally {
+ lock.unlock();
}
}
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
index 3825602..38e4832 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
@@ -18,6 +18,7 @@
package org.apache.ambari.server.serveraction.kerberos;
+import com.google.common.util.concurrent.Striped;
import com.google.inject.Inject;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.actionmanager.HostRoleStatus;
@@ -29,6 +30,7 @@ import
org.apache.ambari.server.orm.entities.KerberosPrincipalEntity;
import org.apache.ambari.server.security.SecurePasswordHelper;
import org.apache.ambari.server.serveraction.ActionLog;
import org.apache.commons.lang.StringUtils;
+import org.eclipse.jetty.util.ConcurrentHashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,6 +38,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.Lock;
/**
* CreatePrincipalsServerAction is a ServerAction implementation that creates
principals as instructed.
@@ -61,6 +64,11 @@ public class CreatePrincipalsServerAction extends
KerberosServerAction {
private KerberosPrincipalHostDAO kerberosPrincipalHostDAO;
/**
+ * Used to prevent multiple threads from working with the same principal.
+ */
+ private Striped<Lock> locksByPrincipal = Striped.lazyWeakLock(25);
+
+ /**
* SecurePasswordHelper used to generate secure passwords for newly created
principals
*/
@Inject
@@ -70,7 +78,7 @@ public class CreatePrincipalsServerAction extends
KerberosServerAction {
* A set of visited principal names used to prevent unnecessary processing
on already processed
* principal names
*/
- private Set<String> seenPrincipals = new HashSet<String>();
+ private Set<String> seenPrincipals = new ConcurrentHashSet<>();
/**
* Called to execute this action. Upon invocation, calls
@@ -154,20 +162,27 @@ public class CreatePrincipalsServerAction extends
KerberosServerAction {
if (processPrincipal) {
Map<String, String> principalPasswordMap =
getPrincipalPasswordMap(requestSharedDataContext);
+ Lock lock = locksByPrincipal.get(evaluatedPrincipal);
+ lock.lock();
+
String password = principalPasswordMap.get(evaluatedPrincipal);
- if (password == null) {
- boolean servicePrincipal =
"service".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.PRINCIPAL_TYPE));
- CreatePrincipalResult result = createPrincipal(evaluatedPrincipal,
servicePrincipal, kerberosConfiguration, operationHandler, regenerateKeytabs,
actionLog);
+ try {
+ if (password == null) {
+ boolean servicePrincipal =
"service".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.PRINCIPAL_TYPE));
+ CreatePrincipalResult result = createPrincipal(evaluatedPrincipal,
servicePrincipal, kerberosConfiguration, operationHandler, regenerateKeytabs,
actionLog);
- if (result == null) {
- commandReport = createCommandReport(1, HostRoleStatus.FAILED,
"{}", actionLog.getStdOut(), actionLog.getStdErr());
- } else {
- Map<String, Integer> principalKeyNumberMap =
getPrincipalKeyNumberMap(requestSharedDataContext);
+ if (result == null) {
+ commandReport = createCommandReport(1, HostRoleStatus.FAILED,
"{}", actionLog.getStdOut(), actionLog.getStdErr());
+ } else {
+ Map<String, Integer> principalKeyNumberMap =
getPrincipalKeyNumberMap(requestSharedDataContext);
- principalPasswordMap.put(evaluatedPrincipal, result.getPassword());
- principalKeyNumberMap.put(evaluatedPrincipal,
result.getKeyNumber());
+ principalPasswordMap.put(evaluatedPrincipal,
result.getPassword());
+ principalKeyNumberMap.put(evaluatedPrincipal,
result.getKeyNumber());
+ }
}
+ } finally {
+ lock.unlock();
}
}
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java
index a25357c..d2fa207 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java
@@ -18,6 +18,7 @@
package org.apache.ambari.server.serveraction.kerberos;
+import com.google.common.util.concurrent.Striped;
import com.google.inject.Inject;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.agent.CommandReport;
@@ -26,15 +27,16 @@ import org.apache.ambari.server.controller.KerberosHelper;
import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO;
import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity;
import org.apache.ambari.server.utils.ShellCommandUtil;
+import org.eclipse.jetty.util.ConcurrentHashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.Lock;
/**
* DestroyPrincipalsServerAction is a ServerAction implementation that
destroys principals as instructed.
@@ -52,10 +54,16 @@ public class DestroyPrincipalsServerAction extends
KerberosServerAction {
private KerberosPrincipalDAO kerberosPrincipalDAO;
/**
+ * Used to prevent multiple threads from working with the same keytab.
+ */
+ private Striped<Lock> m_locksByPrincipal = Striped.lazyWeakLock(25);
+
+
+ /**
* A set of visited principal names used to prevent unnecessary processing
on already processed
* principal names
*/
- private Set<String> seenPrincipals = new HashSet<String>();
+ private Set<String> seenPrincipals = new ConcurrentHashSet<>();
/**
* Called to execute this action. Upon invocation, calls
@@ -100,66 +108,72 @@ public class DestroyPrincipalsServerAction extends
KerberosServerAction {
// Only process this principal if we haven't already processed it
if (!seenPrincipals.contains(evaluatedPrincipal)) {
- seenPrincipals.add(evaluatedPrincipal);
+ Lock lock = m_locksByPrincipal.get(evaluatedPrincipal);
+ lock.lock();
+ try {
+ seenPrincipals.add(evaluatedPrincipal);
- String message = String.format("Destroying identity, %s",
evaluatedPrincipal);
- LOG.info(message);
- actionLog.writeStdOut(message);
-
DestroyPrincipalKerberosAuditEvent.DestroyPrincipalKerberosAuditEventBuilder
auditEventBuilder = DestroyPrincipalKerberosAuditEvent.builder()
+ String message = String.format("Destroying identity, %s",
evaluatedPrincipal);
+ LOG.info(message);
+ actionLog.writeStdOut(message);
+
DestroyPrincipalKerberosAuditEvent.DestroyPrincipalKerberosAuditEventBuilder
auditEventBuilder = DestroyPrincipalKerberosAuditEvent.builder()
.withTimestamp(System.currentTimeMillis())
.withRequestId(getHostRoleCommand().getRequestId())
.withTaskId(getHostRoleCommand().getTaskId())
.withPrincipal(evaluatedPrincipal);
- try {
try {
- operationHandler.removePrincipal(evaluatedPrincipal);
- } catch (KerberosOperationException e) {
- message = String.format("Failed to remove identity for %s from the
KDC - %s", evaluatedPrincipal, e.getMessage());
- LOG.warn(message);
- actionLog.writeStdErr(message);
- auditEventBuilder.withReasonOfFailure(message);
- }
+ try {
+ operationHandler.removePrincipal(evaluatedPrincipal);
+ } catch (KerberosOperationException e) {
+ message = String.format("Failed to remove identity for %s from the
KDC - %s", evaluatedPrincipal, e.getMessage());
+ LOG.warn(message);
+ actionLog.writeStdErr(message);
+ auditEventBuilder.withReasonOfFailure(message);
+ }
- try {
- KerberosPrincipalEntity principalEntity =
kerberosPrincipalDAO.find(evaluatedPrincipal);
+ try {
+ KerberosPrincipalEntity principalEntity =
kerberosPrincipalDAO.find(evaluatedPrincipal);
- if (principalEntity != null) {
- String cachedKeytabPath = principalEntity.getCachedKeytabPath();
+ if (principalEntity != null) {
+ String cachedKeytabPath = principalEntity.getCachedKeytabPath();
- kerberosPrincipalDAO.remove(principalEntity);
+ kerberosPrincipalDAO.remove(principalEntity);
- // If a cached keytabs file exists for this principal, delete it.
- if (cachedKeytabPath != null) {
- if (!new File(cachedKeytabPath).delete()) {
- LOG.debug(String.format("Failed to remove cached keytab for
%s", evaluatedPrincipal));
+ // If a cached keytabs file exists for this principal, delete
it.
+ if (cachedKeytabPath != null) {
+ if (!new File(cachedKeytabPath).delete()) {
+ LOG.debug(String.format("Failed to remove cached keytab for
%s", evaluatedPrincipal));
+ }
}
}
- }
- // delete Ambari server keytab
- String hostName =
identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME);
- if (hostName != null &&
hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME)) {
- String keytabFilePath =
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH);
- if (keytabFilePath != null) {
- try {
- ShellCommandUtil.Result result =
ShellCommandUtil.delete(keytabFilePath, true, true);
- if (!result.isSuccessful()) {
- LOG.warn("Failed to remove ambari keytab for {} due to {}",
evaluatedPrincipal, result.getStderr());
+ // delete Ambari server keytab
+ String hostName =
identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME);
+ if (hostName != null &&
hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME)) {
+ String keytabFilePath =
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH);
+ if (keytabFilePath != null) {
+ try {
+ ShellCommandUtil.Result result =
ShellCommandUtil.delete(keytabFilePath, true, true);
+ if (!result.isSuccessful()) {
+ LOG.warn("Failed to remove ambari keytab for {} due to
{}", evaluatedPrincipal, result.getStderr());
+ }
+ } catch (IOException | InterruptedException e) {
+ LOG.warn("Failed to remove ambari keytab for " +
evaluatedPrincipal, e);
}
- } catch (IOException|InterruptedException e) {
- LOG.warn("Failed to remove ambari keytab for " +
evaluatedPrincipal, e);
}
}
+ } catch (Throwable t) {
+ message = String.format("Failed to remove identity for %s from the
Ambari database - %s", evaluatedPrincipal, t.getMessage());
+ LOG.warn(message);
+ actionLog.writeStdErr(message);
+ auditEventBuilder.withReasonOfFailure(message);
}
- } catch (Throwable t) {
- message = String.format("Failed to remove identity for %s from the
Ambari database - %s", evaluatedPrincipal, t.getMessage());
- LOG.warn(message);
- actionLog.writeStdErr(message);
- auditEventBuilder.withReasonOfFailure(message);
+ } finally {
+ auditLog(auditEventBuilder.build());
}
} finally {
- auditLog(auditEventBuilder.build());
+ lock.unlock();
}
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
index 0b845d9..54a869f 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
@@ -40,11 +40,19 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.Lock;
+
+import com.google.common.util.concurrent.Striped;
public class FinalizeKerberosServerAction extends KerberosServerAction {
private final static Logger LOG =
LoggerFactory.getLogger(FinalizeKerberosServerAction.class);
/**
+ * Used to prevent multiple threads from working with the same keytab.
+ */
+ private Striped<Lock> m_locksByKeytab = Striped.lazyWeakLock(25);
+
+ /**
* Processes an identity as necessary.
* <p/>
* This implementation ensures that keytab files for the Ambari identities
have the correct
@@ -86,7 +94,13 @@ public class FinalizeKerberosServerAction extends
KerberosServerAction {
String keytabFilePath =
identityRecord.get(KerberosIdentityDataFile.KEYTAB_FILE_PATH);
- if (!StringUtils.isEmpty(keytabFilePath)) {
+ if (StringUtils.isEmpty(keytabFilePath)) {
+ return null;
+ }
+
+ Lock lock = m_locksByKeytab.get(keytabFilePath);
+ lock.lock();
+ try {
Set<String> visited = (Set<String>)
requestSharedDataContext.get(this.getClass().getName() + "_visited");
if (!visited.contains(keytabFilePath)) {
@@ -149,6 +163,8 @@ public class FinalizeKerberosServerAction extends
KerberosServerAction {
visited.add(keytabFilePath);
}
+ } finally {
+ lock.unlock();
}
}
}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
index 9a3c4ed..138e494 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
@@ -18,11 +18,13 @@
package org.apache.ambari.server.serveraction.kerberos;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.inject.Inject;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.actionmanager.HostRoleStatus;
import org.apache.ambari.server.agent.CommandReport;
import org.apache.ambari.server.agent.ExecutionCommand;
+import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.KerberosHelper;
import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
import org.apache.ambari.server.serveraction.AbstractServerAction;
@@ -36,8 +38,18 @@ import static
org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDat
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
/**
* KerberosServerAction is an abstract class to be implemented by
Kerberos-related
@@ -165,6 +177,12 @@ public abstract class KerberosServerAction extends
AbstractServerAction {
@Inject
private KerberosHelper kerberosHelper;
+ @Inject
+ /**
+ * Ambari configuration
+ */
+ private Configuration configuration;
+
/**
* Given a (command parameter) Map and a property name, attempts to safely
retrieve the requested
* data.
@@ -350,7 +368,7 @@ public abstract class KerberosServerAction extends
AbstractServerAction {
* @return a CommandReport indicating the result of this operation
* @throws AmbariException
*/
- protected CommandReport processIdentities(Map<String, Object>
requestSharedDataContext)
+ protected CommandReport processIdentities(final Map<String, Object>
requestSharedDataContext)
throws AmbariException {
CommandReport commandReport = null;
Map<String, String> commandParameters = getCommandParameters();
@@ -361,7 +379,7 @@ public abstract class KerberosServerAction extends
AbstractServerAction {
if (commandParameters != null) {
// Grab the relevant data from this action's command parameters map
PrincipalKeyCredential administratorCredential =
kerberosHelper.getKDCAdministratorCredentials(getClusterName());
- String defaultRealm = getDefaultRealm(commandParameters);
+ final String defaultRealm = getDefaultRealm(commandParameters);
KDCType kdcType = getKDCType(commandParameters);
String dataDirectoryPath = getDataDirectoryPath(commandParameters);
@@ -390,7 +408,7 @@ public abstract class KerberosServerAction extends
AbstractServerAction {
throw new AmbariException(message);
}
- KerberosOperationHandler handler =
kerberosOperationHandlerFactory.getKerberosOperationHandler(kdcType);
+ final KerberosOperationHandler handler =
kerberosOperationHandlerFactory.getKerberosOperationHandler(kdcType);
if (handler == null) {
String message = String.format("Failed to process the
identities, a KDC operation handler was not found for the KDC type of : %s",
kdcType.toString());
@@ -399,7 +417,7 @@ public abstract class KerberosServerAction extends
AbstractServerAction {
throw new AmbariException(message);
}
- Map<String, String> kerberosConfiguration =
getConfiguration("kerberos-env");
+ final Map<String, String> kerberosConfiguration =
getConfiguration("kerberos-env");
try {
handler.open(administratorCredential, defaultRealm,
kerberosConfiguration);
@@ -413,16 +431,51 @@ public abstract class KerberosServerAction extends
AbstractServerAction {
// Create the data file reader to parse and iterate through the
records
KerberosIdentityDataFileReader reader = null;
+ ExecutorService executorService = null;
try {
+ // create the thread factory, executor, and completion service
for
+ // running the identity processing in parallel
+ ExecutionCommand executionCommand = getExecutionCommand();
+ int threadCount =
configuration.getKerberosServerActionThreadpoolSize();
+ String factoryName = (executionCommand == null)
+ ? "process-identity-%d"
+ : "process-identity-task-" + executionCommand.getTaskId() +
"-thread-%d";
+ ThreadFactory threadFactory = new
ThreadFactoryBuilder().setNameFormat(factoryName).build();
+ executorService = Executors.newFixedThreadPool(threadCount,
threadFactory);
+ CompletionService<CommandReport> completionService = new
ExecutorCompletionService<>(executorService);
+
+ List<Future<CommandReport>> futures = new ArrayList<>();
reader =
kerberosIdentityDataFileReaderFactory.createKerberosIdentityDataFileReader(identityDataFile);
- for (Map<String, String> record : reader) {
- // Process the current record
- commandReport = processRecord(record, defaultRealm, handler,
kerberosConfiguration, requestSharedDataContext);
-
- // If the principal processor returns a CommandReport, than it
is time to stop since
- // an error condition has probably occurred, else all is
assumed to be well.
- if (commandReport != null) {
- break;
+ try {
+ for (final Map<String, String> record : reader) {
+ Future<CommandReport> future = completionService.submit(new
Callable<CommandReport>() {
+ @Override
+ public CommandReport call() throws Exception {
+ return processRecord(record, defaultRealm, handler,
kerberosConfiguration, requestSharedDataContext);
+ }
+ });
+ futures.add(future);
+ }
+
+ LOG.info("Processing {} identities concurrently with {}
thread(s)...", futures.size(), threadCount);
+ for (int i = 0; i < futures.size(); i++) {
+ Future<CommandReport> future = completionService.take();
+
+ // If the principal processor returns a CommandReport, than
it is time to stop since
+ // an error condition has probably occurred, else all is
assumed to be well.
+ commandReport = future.get();
+ if (commandReport != null) {
+ break;
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("Unable to process identities asynchronously", e);
+ return createCommandReport(0, HostRoleStatus.FAILED, "{}",
actionLog.getStdOut(),actionLog.getStdErr());
+ } finally {
+ for (Future<CommandReport> future: futures){
+ if (!future.isCancelled() &!future.isDone()) {
+ future.cancel(true);
+ }
}
}
} catch (AmbariException e) {
@@ -453,6 +506,10 @@ public abstract class KerberosServerAction extends
AbstractServerAction {
} catch (KerberosOperationException e) {
// Ignore this...
}
+
+ if (executorService != null) {
+ executorService.shutdown();
+ }
}
}
}
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProviderTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProviderTest.java
index f3e1046..1be7660 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProviderTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostKerberosIdentityResourceProviderTest.java
@@ -30,10 +30,14 @@ import org.apache.ambari.server.orm.dao.HostDAO;
import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO;
import org.apache.ambari.server.orm.dao.KerberosPrincipalHostDAO;
import org.apache.ambari.server.orm.entities.HostEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosPrincipalType;
+import org.easymock.EasyMock;
import org.easymock.EasyMockSupport;
import org.junit.Assert;
import org.junit.Test;
@@ -130,8 +134,11 @@ public class HostKerberosIdentityResourceProviderTest
extends EasyMockSupport {
@Test
public void testGetResources() throws Exception {
+ Clusters clusters = createNiceMock(Clusters.class);
+
expect(clusters.getCluster(EasyMock.anyString())).andReturn(createNiceMock(Cluster.class)).once();
AmbariManagementController managementController =
createMock(AmbariManagementController.class);
+
expect(managementController.getClusters()).andReturn(clusters).atLeastOnce();
KerberosPrincipalDescriptor principalDescriptor1 =
createStrictMock(KerberosPrincipalDescriptor.class);
expect(principalDescriptor1.getValue()).andReturn("[email protected]");
@@ -209,9 +216,14 @@ public class HostKerberosIdentityResourceProviderTest
extends EasyMockSupport {
activeIdentities.put("Host100", identities);
KerberosHelper kerberosHelper = createStrictMock(KerberosHelper.class);
- expect(kerberosHelper.getActiveIdentities("Cluster100", "Host100", null,
null, true))
- .andReturn(activeIdentities)
- .times(1);
+ KerberosDescriptor kerberosDescriptor =
createNiceMock(KerberosDescriptor.class);
+ expect(kerberosHelper.getKerberosDescriptor(
+ EasyMock.anyObject(Cluster.class),
+ EasyMock.eq(false))).andReturn(kerberosDescriptor).atLeastOnce();
+
+ expect(kerberosHelper.getActiveIdentities("Cluster100", "Host100",
null,null, true))
+ .andReturn(activeIdentities)
+ .once();
// replay
replayAll();
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerActionTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerActionTest.java
index 5522132..01d7a60 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerActionTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerActionTest.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.serveraction.kerberos;
import static org.easymock.EasyMock.anyBoolean;
import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
@@ -44,6 +45,7 @@ import org.apache.ambari.server.state.ServiceComponentHost;
import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
+import org.apache.ambari.server.state.stack.OsFamily;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Before;
@@ -65,10 +67,10 @@ public class AbstractPrepareKerberosServerActionTest {
private Injector injector;
private final PrepareKerberosServerAction prepareKerberosServerAction = new
PrepareKerberosServerAction();
- private final AuditLogger auditLogger =
EasyMock.createNiceMock(AuditLogger.class);
- private final Clusters clusters = EasyMock.createNiceMock(Clusters.class);
- private final KerberosHelper kerberosHelper =
EasyMock.createNiceMock(KerberosHelper.class);
- private final KerberosIdentityDataFileWriterFactory
kerberosIdentityDataFileWriterFactory =
EasyMock.createNiceMock(KerberosIdentityDataFileWriterFactory.class);
+ private final AuditLogger auditLogger = createNiceMock(AuditLogger.class);
+ private final Clusters clusters = createNiceMock(Clusters.class);
+ private final KerberosHelper kerberosHelper =
createNiceMock(KerberosHelper.class);
+ private final KerberosIdentityDataFileWriterFactory
kerberosIdentityDataFileWriterFactory =
createNiceMock(KerberosIdentityDataFileWriterFactory.class);
@Before
public void setUp() throws Exception {
@@ -78,6 +80,7 @@ public class AbstractPrepareKerberosServerActionTest {
bind(KerberosHelper.class).toInstance(kerberosHelper);
bind(KerberosIdentityDataFileWriterFactory.class).toInstance(kerberosIdentityDataFileWriterFactory);
bind(Clusters.class).toInstance(clusters);
+ bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class));
bind(AuditLogger.class).toInstance(auditLogger);
}
});
@@ -94,13 +97,13 @@ public class AbstractPrepareKerberosServerActionTest {
@Test
@SuppressWarnings("unchecked")
public void testProcessServiceComponentHosts() throws Exception {
- final Cluster cluster = EasyMock.createNiceMock(Cluster.class);
- final KerberosIdentityDataFileWriter kerberosIdentityDataFileWriter =
EasyMock.createNiceMock(KerberosIdentityDataFileWriter.class);
- final KerberosDescriptor kerberosDescriptor =
EasyMock.createNiceMock(KerberosDescriptor.class);
- final ServiceComponentHost serviceComponentHostHDFS =
EasyMock.createNiceMock(ServiceComponentHost.class);
- final ServiceComponentHost serviceComponentHostZK =
EasyMock.createNiceMock(ServiceComponentHost.class);
- final KerberosServiceDescriptor serviceDescriptor =
EasyMock.createNiceMock(KerberosServiceDescriptor.class);
- final KerberosComponentDescriptor componentDescriptor =
EasyMock.createNiceMock(KerberosComponentDescriptor.class);
+ final Cluster cluster = createNiceMock(Cluster.class);
+ final KerberosIdentityDataFileWriter kerberosIdentityDataFileWriter =
createNiceMock(KerberosIdentityDataFileWriter.class);
+ final KerberosDescriptor kerberosDescriptor =
createNiceMock(KerberosDescriptor.class);
+ final ServiceComponentHost serviceComponentHostHDFS =
createNiceMock(ServiceComponentHost.class);
+ final ServiceComponentHost serviceComponentHostZK =
createNiceMock(ServiceComponentHost.class);
+ final KerberosServiceDescriptor serviceDescriptor =
createNiceMock(KerberosServiceDescriptor.class);
+ final KerberosComponentDescriptor componentDescriptor =
createNiceMock(KerberosComponentDescriptor.class);
final String hdfsService = "HDFS";
final String zookeeperService = "ZOOKEEPER";
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerActionTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerActionTest.java
index 439bcae..e49beb9 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerActionTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerActionTest.java
@@ -30,6 +30,7 @@ import
org.apache.ambari.server.orm.dao.KerberosPrincipalHostDAO;
import org.apache.ambari.server.orm.entities.HostEntity;
import org.apache.ambari.server.serveraction.ActionLog;
import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.stack.OsFamily;
import org.apache.ambari.server.utils.StageUtils;
import org.apache.commons.io.FileUtils;
import org.easymock.EasyMockSupport;
@@ -194,6 +195,7 @@ public class ConfigureAmbariIdentitiesServerActionTest
extends EasyMockSupport {
bind(AuditLogger.class).toInstance(createNiceMock(AuditLogger.class));
bind(Clusters.class).toInstance(createNiceMock(Clusters.class));
bind(KerberosHelper.class).toInstance(createNiceMock(KerberosHelper.class));
+ bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class));
bind(HostDAO.class).toInstance(createMock(HostDAO.class));
bind(KerberosPrincipalHostDAO.class).toInstance(createMock(KerberosPrincipalHostDAO.class));
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerActionTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerActionTest.java
index 9404480..3061a36 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerActionTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerActionTest.java
@@ -46,6 +46,7 @@ import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.Host;
import org.apache.ambari.server.state.SecurityState;
import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.stack.OsFamily;
import org.easymock.EasyMockSupport;
import org.junit.Rule;
import org.junit.Test;
@@ -198,6 +199,7 @@ public class FinalizeKerberosServerActionTest extends
EasyMockSupport {
protected void configure() {
bind(KerberosHelper.class).toInstance(createMock(KerberosHelper.class));
bind(Clusters.class).toInstance(clusters);
+ bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class));
bind(AuditLogger.class).toInstance(createNiceMock(AuditLogger.class));
}
});
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/view/HttpImpersonatorImplTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/view/HttpImpersonatorImplTest.java
index e1df325..b0d2dba 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/view/HttpImpersonatorImplTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/view/HttpImpersonatorImplTest.java
@@ -27,7 +27,6 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
-import sun.nio.cs.StandardCharsets;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;