You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2018/07/05 16:40:33 UTC
[ambari] branch trunk updated: [AMBARI-24229] Prevent Configuration
Changes During Keytab Regeneration in an Upgrade
This is an automated email from the ASF dual-hosted git repository.
rlevas pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/trunk by this push:
new a100a99 [AMBARI-24229] Prevent Configuration Changes During Keytab Regeneration in an Upgrade
a100a99 is described below
commit a100a99037d26cdf4e262eaf3ee03dd6581027f0
Author: Robert Levas <rl...@users.noreply.github.com>
AuthorDate: Thu Jul 5 12:40:30 2018 -0400
[AMBARI-24229] Prevent Configuration Changes During Keytab Regeneration in an Upgrade
Test failure is unrelated (ambari-web). :(
* [AMBARI-24229] Prevent Configuration Changes During Keytab Regeneration in an Upgrade
* [AMBARI-24229] Prevent Configuration Changes During Keytab Regeneration in an Upgrade
---
.../api/resources/ClusterResourceDefinition.java | 1 +
.../ambari/server/controller/KerberosHelper.java | 18 +-
.../server/controller/KerberosHelperImpl.java | 106 ++++--
.../controller/UpdateConfigurationPolicy.java | 116 ++++++
.../internal/UpgradeResourceProvider.java | 2 +
.../AbstractPrepareKerberosServerAction.java | 168 ++++++++-
.../kerberos/KerberosServerAction.java | 31 +-
.../PrepareDisableKerberosServerAction.java | 2 +-
.../PrepareEnableKerberosServerAction.java | 2 +-
.../PrepareKerberosIdentitiesServerAction.java | 27 +-
.../internal/UpgradeResourceProviderTest.java | 89 ++---
.../AbstractPrepareKerberosServerActionTest.java | 397 +++++++++++++++++++--
12 files changed, 811 insertions(+), 148 deletions(-)
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
index 9d0c169..bc0e3ae 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java
@@ -88,6 +88,7 @@ public class ClusterResourceDefinition extends BaseResourceDefinition {
directives.add(KerberosHelper.DIRECTIVE_HOSTS);
directives.add(KerberosHelper.DIRECTIVE_COMPONENTS);
directives.add(KerberosHelper.DIRECTIVE_IGNORE_CONFIGS);
+ directives.add(KerberosHelper.DIRECTIVE_CONFIG_UPDATE_POLICY);
return directives;
}
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 79b2269..3c4d6b2 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
@@ -61,10 +61,26 @@ public interface KerberosHelper {
*/
String DIRECTIVE_COMPONENTS = "regenerate_components";
/**
- * directive used to pass host list to regenerate keytabs on
+ * directive used to indicate configurations are not to be updated (if set to "true") when regenerating
+ * keytab files
+ * @deprecated use {@link #DIRECTIVE_CONFIG_UPDATE_POLICY}
*/
String DIRECTIVE_IGNORE_CONFIGS = "ignore_config_updates";
/**
+ * directive used to indicate how to handle configuration updates when regenerating keytab files
+ *
+ * expected values:
+ * <ul>
+ * <li>none</li>
+ * <li>identities_only</li>
+ * <li>new_and_identities</li>
+ * <li>all</li>
+ * </ul>
+ *
+ * @see UpdateConfigurationPolicy
+ */
+ String DIRECTIVE_CONFIG_UPDATE_POLICY = "config_update_policy";
+ /**
* directive used to indicate that the enable Kerberos operation should proceed even if the
* cluster's security type is not changing
*/
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 ad4d411..5521a29 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
@@ -279,36 +279,49 @@ public class KerberosHelperImpl implements KerberosHelper {
throw new AmbariException(String.format("Custom operation %s can only be requested with the security type cluster property: %s", operation.name(), SecurityType.KERBEROS.name()));
}
+ KerberosServerAction.OperationType operationType;
+ if ("true".equalsIgnoreCase(value) || "all".equalsIgnoreCase(value)) {
+ operationType = KerberosServerAction.OperationType.RECREATE_ALL;
+ } else if ("missing".equalsIgnoreCase(value)) {
+ operationType = KerberosServerAction.OperationType.CREATE_MISSING;
+ } else {
+ throw new AmbariException(String.format("Unexpected directive value: %s", value));
+ }
+
boolean retryAllowed = false;
if (requestProperties.containsKey(ALLOW_RETRY)) {
String allowRetryString = requestProperties.get(ALLOW_RETRY);
retryAllowed = Boolean.parseBoolean(allowRetryString);
}
- CreatePrincipalsAndKeytabsHandler handler = null;
-
Set<String> hostFilter = parseHostFilter(requestProperties);
Map<String, Set<String>> serviceComponentFilter = parseComponentFilter(requestProperties);
- boolean updateConfigurations = !requestProperties.containsKey(DIRECTIVE_IGNORE_CONFIGS)
- || !"true".equalsIgnoreCase(requestProperties.get(DIRECTIVE_IGNORE_CONFIGS));
+ UpdateConfigurationPolicy updateConfigurationsPolicy = UpdateConfigurationPolicy.ALL;
+ if(requestProperties.containsKey(DIRECTIVE_CONFIG_UPDATE_POLICY)) {
+ String policyValue = requestProperties.get(DIRECTIVE_CONFIG_UPDATE_POLICY);
+ updateConfigurationsPolicy = UpdateConfigurationPolicy.translate(policyValue);
- boolean forceAllHosts = (hostFilter == null) || (hostFilter.contains("*"));
-
- if ("true".equalsIgnoreCase(value) || "all".equalsIgnoreCase(value)) {
- handler = new CreatePrincipalsAndKeytabsHandler(KerberosServerAction.OperationType.RECREATE_ALL, updateConfigurations, forceAllHosts, true);
- } else if ("missing".equalsIgnoreCase(value)) {
- handler = new CreatePrincipalsAndKeytabsHandler(KerberosServerAction.OperationType.CREATE_MISSING, updateConfigurations, forceAllHosts, true);
+ if(updateConfigurationsPolicy== null) {
+ throw new AmbariException(String.format("Unexpected comfiguration policy value: %s", policyValue));
+ }
+ }
+ else if(requestProperties.containsKey(DIRECTIVE_IGNORE_CONFIGS)) {
+ if("true".equalsIgnoreCase(requestProperties.get(DIRECTIVE_IGNORE_CONFIGS))) {
+ // This really means to no update existing properties. However, we need to ensure
+ // that Kerberos identity specific configurations are updated or added to make
+ // sure all is consistent.
+ updateConfigurationsPolicy = UpdateConfigurationPolicy.NEW_AND_IDENTITIES;
+ }
}
- if (handler != null) {
- handler.setRetryAllowed(retryAllowed);
+ boolean forceAllHosts = (hostFilter == null) || (hostFilter.contains("*"));
- requestStageContainer = handle(cluster, getKerberosDetails(cluster, manageIdentities),
+ CreatePrincipalsAndKeytabsHandler handler = new CreatePrincipalsAndKeytabsHandler(operationType, updateConfigurationsPolicy, forceAllHosts, true);
+ handler.setRetryAllowed(retryAllowed);
+
+ requestStageContainer = handle(cluster, getKerberosDetails(cluster, manageIdentities),
serviceComponentFilter, hostFilter, null, null, requestStageContainer, handler);
- } else {
- throw new AmbariException(String.format("Unexpected directive value: %s", value));
- }
break;
@@ -368,9 +381,17 @@ public class KerberosHelperImpl implements KerberosHelper {
Set<String> hostFilter, Collection<String> identityFilter, Set<String> hostsToForceKerberosOperations,
RequestStageContainer requestStageContainer, Boolean manageIdentities)
throws AmbariException, KerberosOperationException {
- return handle(cluster, getKerberosDetails(cluster, manageIdentities), serviceComponentFilter, hostFilter, identityFilter,
- hostsToForceKerberosOperations, requestStageContainer, new CreatePrincipalsAndKeytabsHandler(KerberosServerAction.OperationType.DEFAULT, false, false,
- false));
+ return handle(cluster,
+ getKerberosDetails(cluster, manageIdentities),
+ serviceComponentFilter,
+ hostFilter,
+ identityFilter,
+ hostsToForceKerberosOperations,
+ requestStageContainer,
+ new CreatePrincipalsAndKeytabsHandler(KerberosServerAction.OperationType.DEFAULT,
+ UpdateConfigurationPolicy.NONE,
+ false,
+ false));
}
@Override
@@ -1112,8 +1133,14 @@ public class KerberosHelperImpl implements KerberosHelper {
public RequestStageContainer createTestIdentity(Cluster cluster, Map<String, String> commandParamsStage,
RequestStageContainer requestStageContainer)
throws KerberosOperationException, AmbariException {
- return handleTestIdentity(cluster, getKerberosDetails(cluster, null), commandParamsStage, requestStageContainer,
- new CreatePrincipalsAndKeytabsHandler(KerberosServerAction.OperationType.DEFAULT, false, false, false));
+ return handleTestIdentity(cluster,
+ getKerberosDetails(cluster, null),
+ commandParamsStage,
+ requestStageContainer,
+ new CreatePrincipalsAndKeytabsHandler(KerberosServerAction.OperationType.DEFAULT,
+ UpdateConfigurationPolicy.NONE,
+ false,
+ false));
}
@Override
@@ -3891,7 +3918,7 @@ public class KerberosHelperImpl implements KerberosHelper {
Map<String, String> commandParameters = new HashMap<>();
commandParameters.put(KerberosServerAction.AUTHENTICATED_USER_NAME, ambariManagementController.getAuthName());
commandParameters.put(KerberosServerAction.UPDATE_CONFIGURATION_NOTE, "Enabling Kerberos");
- commandParameters.put(KerberosServerAction.UPDATE_CONFIGURATIONS, "true");
+ commandParameters.put(KerberosServerAction.UPDATE_CONFIGURATION_POLICY, UpdateConfigurationPolicy.ALL.name());
commandParameters.put(KerberosServerAction.DEFAULT_REALM, kerberosDetails.getDefaultRealm());
commandParameters.put(KerberosServerAction.INCLUDE_AMBARI_IDENTITY, (kerberosDetails.createAmbariPrincipal()) ? "true" : "false");
commandParameters.put(KerberosServerAction.PRECONFIGURE_SERVICES, kerberosDetails.getPreconfigureServices());
@@ -3987,7 +4014,7 @@ public class KerberosHelperImpl implements KerberosHelper {
Map<String, String> commandParameters = new HashMap<>();
commandParameters.put(KerberosServerAction.AUTHENTICATED_USER_NAME, ambariManagementController.getAuthName());
commandParameters.put(KerberosServerAction.UPDATE_CONFIGURATION_NOTE, "Disabling Kerberos");
- commandParameters.put(KerberosServerAction.UPDATE_CONFIGURATIONS, "true");
+ commandParameters.put(KerberosServerAction.UPDATE_CONFIGURATION_POLICY, UpdateConfigurationPolicy.ALL.name());
commandParameters.put(KerberosServerAction.DEFAULT_REALM, kerberosDetails.getDefaultRealm());
if (dataDirectory != null) {
commandParameters.put(KerberosServerAction.DATA_DIRECTORY, dataDirectory.getAbsolutePath());
@@ -4084,10 +4111,9 @@ public class KerberosHelperImpl implements KerberosHelper {
private KerberosServerAction.OperationType operationType;
/**
- * A boolean value indicating whether to update service configurations (<code>true</code>)
- * or ignore any potential configuration changes (<code>false</code>).
+ * A UpdateConfigurationPolicy indicating how to handle configuration changes.
*/
- private boolean updateConfigurations;
+ private UpdateConfigurationPolicy updateConfigurationPolicy;
/**
* A boolean value indicating whether to include all hosts (<code>true</code>) when setting up
@@ -4107,19 +4133,20 @@ public class KerberosHelperImpl implements KerberosHelper {
* CreatePrincipalsAndKeytabsHandler constructor to set whether this instance should be used to
* regenerate all keytabs or just the ones that have not been distributed
*
- * @param operationType The type of Kerberos operation being performed
- * @param updateConfigurations A boolean value indicating whether to update service configurations
- * (<code>true</code>) or ignore any potential configuration changes
- * @param forceAllHosts A boolean value indicating whether to include all hosts (<code>true</code>)
- * when setting up agent-side tasks or to select only the hosts found to be
- * relevant (<code>false</code>)
- * @param includeAmbariIdentity A boolean value indicating whether to include Ambari server
- * identity (<code>true</code>) or ignore it (<code>false</code>)
+ * @param operationType The type of Kerberos operation being performed
+ * @param updateConfigurationPolicy The policy to use when updating configurations
+ * (<code>true</code>) or ignore any potential configuration changes
+ * @param forceAllHosts A boolean value indicating whether to include all hosts (<code>true</code>)
+ * when setting up agent-side tasks or to select only the hosts found to be
+ * relevant (<code>false</code>)
+ * @param includeAmbariIdentity A boolean value indicating whether to include Ambari server
+ * identity (<code>true</code>) or ignore it (<code>false</code>)
*/
- CreatePrincipalsAndKeytabsHandler(KerberosServerAction.OperationType operationType, boolean updateConfigurations,
+ CreatePrincipalsAndKeytabsHandler(KerberosServerAction.OperationType operationType,
+ UpdateConfigurationPolicy updateConfigurationPolicy,
boolean forceAllHosts, boolean includeAmbariIdentity) {
this.operationType = operationType;
- this.updateConfigurations = updateConfigurations;
+ this.updateConfigurationPolicy = updateConfigurationPolicy;
this.forceAllHosts = forceAllHosts;
this.includeAmbariIdentity = includeAmbariIdentity;
}
@@ -4176,9 +4203,9 @@ public class KerberosHelperImpl implements KerberosHelper {
commandParameters.put(KerberosServerAction.OPERATION_TYPE, (operationType == null) ? KerberosServerAction.OperationType.DEFAULT.name() : operationType.name());
commandParameters.put(KerberosServerAction.INCLUDE_AMBARI_IDENTITY, (processAmbariIdentity) ? "true" : "false");
- if (updateConfigurations) {
+ if (updateConfigurationPolicy != UpdateConfigurationPolicy.NONE) {
commandParameters.put(KerberosServerAction.UPDATE_CONFIGURATION_NOTE, "Updated Kerberos-related configurations");
- commandParameters.put(KerberosServerAction.UPDATE_CONFIGURATIONS, "true");
+ commandParameters.put(KerberosServerAction.UPDATE_CONFIGURATION_POLICY, updateConfigurationPolicy.name());
}
List<String> hostsToInclude = calculateHosts(cluster, serviceComponentHosts, hostsWithValidKerberosClient, forceAllHosts);
@@ -4219,7 +4246,7 @@ public class KerberosHelperImpl implements KerberosHelper {
roleCommandOrder, requestStageContainer, hostsToInclude);
}
- if (updateConfigurations) {
+ if (updateConfigurationPolicy != UpdateConfigurationPolicy.NONE) {
// *****************************************************************
// Create stage to update configurations of services
addUpdateConfigurationsStage(cluster, clusterHostInfoJson, hostParamsJson, event, commandParameters,
@@ -4353,6 +4380,7 @@ public class KerberosHelperImpl implements KerberosHelper {
}
commandParameters.put(KerberosServerAction.KDC_TYPE, kerberosDetails.getKdcType().name());
+ commandParameters.put(KerberosServerAction.UPDATE_CONFIGURATION_POLICY, UpdateConfigurationPolicy.ALL.name());
// *****************************************************************
// Create stage to create principals
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/UpdateConfigurationPolicy.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/UpdateConfigurationPolicy.java
new file mode 100644
index 0000000..52f3e58
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/UpdateConfigurationPolicy.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller;
+
+/**
+ * The update configuration policies
+ * <ul>
+ * <li>NONE - No configurations will be updated</li>
+ * <li>IDENTITIES_ONLY - New and updated configurations related to Kerberos identity information - principal, keytab file, and auth-to-local rule properties</li>
+ * <li>NEW_AND_IDENTITIES - Only new configurations declared by the Kerberos descriptor and stack advisor as well as the identity-related changes</li>
+ * <li>ALL - All configuration changes (default)</li>
+ * </ul>
+ */
+public enum UpdateConfigurationPolicy {
+ /**
+ * No configurations will be updated
+ */
+ NONE(false, false, false, false),
+
+ /**
+ * New and updated configurations related to Kerberos identity information - principal, keytab
+ * file, and auth-to-local rule properties
+ */
+ IDENTITIES_ONLY(false, true, false, false),
+
+ /**
+ * Only new configurations declared by the Kerberos descriptor and stack advisor as well as the
+ * identity-related changes
+ */
+ NEW_AND_IDENTITIES(true, true, true, false),
+
+ /**
+ * All configuration changes (default)
+ */
+ ALL(true, true, true, true);
+
+ private final boolean invokeStackAdvisor;
+ private final boolean applyIdentityChanges;
+ private final boolean applyAdditions;
+ private final boolean applyOtherChanges;
+
+ UpdateConfigurationPolicy(boolean invokeStackAdvisor, boolean applyIdentityChanges, boolean applyAdditions, boolean applyOtherChanges) {
+ this.invokeStackAdvisor = invokeStackAdvisor;
+ this.applyIdentityChanges = applyIdentityChanges;
+ this.applyAdditions = applyAdditions;
+ this.applyOtherChanges = applyOtherChanges;
+ }
+
+ public boolean invokeStackAdvisor() {
+ return invokeStackAdvisor;
+ }
+
+ public boolean applyIdentityChanges() {
+ return applyIdentityChanges;
+ }
+
+ public boolean applyAdditions() {
+ return applyAdditions;
+ }
+
+ public boolean applyOtherChanges() {
+ return applyOtherChanges;
+ }
+
+ /**
+ * Safely translates a {@link UpdateConfigurationPolicy} value to a {@link String} of all
+ * lowercase characters.
+ *
+ * @param value the value to translate
+ * @return <code>null</code> if the input is <code>null</code>; otherwise the String value of
+ * the policy enum converted to lowercase characters.
+ */
+ public static String translate(UpdateConfigurationPolicy value) {
+ return (value == null) ? null : value.name().toLowerCase();
+ }
+
+ /**
+ * Safely translates a {@link String} value to an {@link UpdateConfigurationPolicy}.
+ * <p>
+ * The input value will be trimmed and converted to all uppercase characters. If "-"'s are used
+ * instead of "_"'s, they will be converted.
+ *
+ * @param stringValue the String to translate
+ * @return The translated {@link UpdateConfigurationPolicy} value; or <code>null</code> if a translation cannot be made
+ */
+ public static UpdateConfigurationPolicy translate(String stringValue) {
+ if (stringValue != null) {
+ stringValue = stringValue.trim().toUpperCase();
+
+ if (!stringValue.isEmpty()) {
+ try {
+ return valueOf(stringValue.replace('-', '_'));
+ } catch (IllegalArgumentException e) {
+ // ignore this and return null later...
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
index 322c0f9..287e1a5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java
@@ -52,6 +52,7 @@ import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.ExecuteCommandJson;
import org.apache.ambari.server.controller.KerberosHelper;
import org.apache.ambari.server.controller.KerberosHelperImpl.SupportedCustomOperation;
+import org.apache.ambari.server.controller.UpdateConfigurationPolicy;
import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
import org.apache.ambari.server.controller.spi.NoSuchResourceException;
import org.apache.ambari.server.controller.spi.Predicate;
@@ -857,6 +858,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider
Map<String, String> requestProperties = new HashMap<>();
requestProperties.put(SupportedCustomOperation.REGENERATE_KEYTABS.name().toLowerCase(), "missing");
requestProperties.put(KerberosHelper.ALLOW_RETRY, Boolean.TRUE.toString().toLowerCase());
+ requestProperties.put(KerberosHelper.DIRECTIVE_CONFIG_UPDATE_POLICY, UpdateConfigurationPolicy.NEW_AND_IDENTITIES.name());
// add stages to the upgrade which will regenerate missing keytabs only
req = s_kerberosHelper.get().executeCustomOperations(cluster, requestProperties, req, null);
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
index bcace83..ce1d808 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
@@ -34,15 +34,19 @@ import org.apache.ambari.server.agent.CommandReport;
import org.apache.ambari.server.controller.KerberosHelper;
import org.apache.ambari.server.controller.RootComponent;
import org.apache.ambari.server.controller.RootService;
+import org.apache.ambari.server.controller.UpdateConfigurationPolicy;
import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosKeytab;
import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal;
import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.kerberos.AbstractKerberosDescriptorContainer;
import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
import org.apache.ambari.server.utils.StageUtils;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -64,6 +68,9 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
@Inject
private KerberosConfigDataFileWriterFactory kerberosConfigDataFileWriterFactory;
+ @Inject
+ private ConfigHelper configHelper;
+
@Override
protected CommandReport processIdentity(ResolvedKerberosPrincipal resolvedPrincipal, KerberosOperationHandler operationHandler, Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) throws AmbariException {
throw new UnsupportedOperationException();
@@ -74,12 +81,12 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
}
public void processServiceComponentHosts(Cluster cluster, KerberosDescriptor kerberosDescriptor,
- List<ServiceComponentHost> schToProcess,
- Collection<String> identityFilter, String dataDirectory,
- Map<String, Map<String, String>> currentConfigurations,
- Map<String, Map<String, String>> kerberosConfigurations,
- boolean includeAmbariIdentity,
- Map<String, Set<String>> propertiesToBeIgnored) throws AmbariException {
+ List<ServiceComponentHost> schToProcess,
+ Collection<String> identityFilter, String dataDirectory,
+ Map<String, Map<String, String>> currentConfigurations,
+ Map<String, Map<String, String>> kerberosConfigurations,
+ boolean includeAmbariIdentity,
+ Map<String, Set<String>> propertiesToBeIgnored) throws AmbariException {
List<Component> components = new ArrayList<>();
for (ServiceComponentHost each : schToProcess) {
components.add(Component.fromServiceComponentHost(each));
@@ -266,15 +273,19 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
* If work is to be done, a data file containing the details is created so it they changes may be
* processed in the appropriate stage.
*
- * @param dataDirectory the directory in which to write the configuration changes data file
- * @param kerberosConfigurations the Kerberos-specific configuration map
- * @param propertiesToBeRemoved a map of properties to be removed from the current configuration,
- * grouped by configuration type.
+ * @param dataDirectory the directory in which to write the configuration changes data file
+ * @param kerberosConfigurations the Kerberos-specific configuration map
+ * @param propertiesToBeRemoved a map of properties to be removed from the current configuration,
+ * grouped by configuration type.
+ * @param kerberosDescriptor the Kerberos descriptor
+ * @param updateConfigurationPolicy the policy used to determine which configurations to update
* @throws AmbariException
*/
protected void processConfigurationChanges(String dataDirectory,
Map<String, Map<String, String>> kerberosConfigurations,
- Map<String, Set<String>> propertiesToBeRemoved)
+ Map<String, Set<String>> propertiesToBeRemoved,
+ KerberosDescriptor kerberosDescriptor,
+ UpdateConfigurationPolicy updateConfigurationPolicy)
throws AmbariException {
actionLog.writeStdOut("Determining configuration changes");
@@ -287,6 +298,12 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
throw new AmbariException(message);
}
+ // Determine what the relevant Kerberos identity-related properties are...
+ Map<String, Set<String>> kerberosIdentityProperties = getIdentityProperties(kerberosDescriptor, null);
+
+ // Determine what the existing properties are...
+ Map<String, Map<String, String>> existingProperties = configHelper.getEffectiveConfigProperties(getClusterName(), null);
+
File configFile = new File(dataDirectory, KerberosConfigDataFileWriter.DATA_FILE_NAME);
KerberosConfigDataFileWriter kerberosConfDataFileWriter = null;
@@ -300,10 +317,15 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
if (properties != null) {
for (Map.Entry<String, String> configTypeEntry : properties.entrySet()) {
- kerberosConfDataFileWriter.addRecord(type,
- configTypeEntry.getKey(),
- configTypeEntry.getValue(),
- KerberosConfigDataFileWriter.OPERATION_TYPE_SET);
+
+ // Determine if this configuration should be written or not...
+ String propertyName = configTypeEntry.getKey();
+ if (includeConfiguration(type, propertyName, updateConfigurationPolicy, existingProperties, kerberosIdentityProperties)) {
+ kerberosConfDataFileWriter.addRecord(type,
+ propertyName,
+ configTypeEntry.getValue(),
+ KerberosConfigDataFileWriter.OPERATION_TYPE_SET);
+ }
}
}
}
@@ -343,4 +365,120 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
}
}
}
+
+ /**
+ * Determine of the configuration should be included in the set of configurations to update.
+ *
+ * @param configType
+ * @param propertyName
+ * @param updateConfigurationPolicy
+ * @param existingProperties
+ * @param kerberosIdentityProperties
+ * @return
+ */
+ private boolean includeConfiguration(String configType, String propertyName,
+ UpdateConfigurationPolicy updateConfigurationPolicy,
+ Map<String, Map<String, String>> existingProperties,
+ Map<String, Set<String>> kerberosIdentityProperties) {
+
+ // Determine if the property represents a Kerberos identity-related property
+ boolean isIdentity;
+ if (kerberosIdentityProperties == null) {
+ isIdentity = false;
+ } else {
+ Set<String> propertyNames = kerberosIdentityProperties.get(configType);
+ isIdentity = !CollectionUtils.isEmpty(propertyNames) && propertyNames.contains(propertyName);
+ }
+
+ if (isIdentity) {
+ return updateConfigurationPolicy.applyIdentityChanges();
+ }
+
+ // Determine if the property is a new property
+ boolean isNew;
+ if (existingProperties == null) {
+ isNew = true;
+ } else {
+ Map<String, String> propertyNames = existingProperties.get(configType);
+ isNew = (propertyNames == null) || !propertyNames.containsKey(propertyName);
+ }
+
+ if (isNew) {
+ return updateConfigurationPolicy.applyAdditions();
+ }
+
+ // All other properties...
+ return updateConfigurationPolicy.applyOtherChanges();
+ }
+
+ /**
+ * Recursively processes a Kerberos descriptor container and it children to find the
+ * Kerberos identity-related properties.
+ * <p>
+ * Kerberos identity-related properties are those that contain the following information:
+ * <ul>
+ * <li>principal names</li>
+ * <li>keytab file paths</li>
+ * <li>auth-to-local rules</li>
+ * </ul>
+ *
+ * @param container the AbstractKerberosDescriptorContainer to process
+ * @param identityProperties a map of config-types to sets of property names to append data
+ * @return a map of config-types to sets of property names
+ */
+ private Map<String, Set<String>> getIdentityProperties(AbstractKerberosDescriptorContainer container, Map<String, Set<String>> identityProperties) {
+ if (container != null) {
+ if (identityProperties == null) {
+ identityProperties = new HashMap<>();
+ }
+
+ // Process the Kerberos identities - principal and keytab file properties.
+ List<KerberosIdentityDescriptor> identityDescriptors;
+ try {
+ // There is no need to resolve references since we just need to get the set of configurations that can be changed.
+ identityDescriptors = container.getIdentities(false, null);
+ } catch (AmbariException e) {
+ LOG.error("An exception occurred getting the Kerberos identity descriptors. No configurations will be identified.", e);
+ identityDescriptors = null;
+ }
+
+ if (identityDescriptors != null) {
+ Map<String, Map<String, String>> identityConfigurations = kerberosHelper.getIdentityConfigurations(identityDescriptors);
+
+ if (identityConfigurations != null) {
+ for (Map.Entry<String, Map<String, String>> entry : identityConfigurations.entrySet()) {
+ Map<String, String> properties = entry.getValue();
+ if (properties != null) {
+ Set<String> configProperties = identityProperties.computeIfAbsent(entry.getKey(), k -> new HashSet<>());
+ configProperties.addAll(properties.keySet());
+ }
+ }
+ }
+ }
+
+ // Process any auth-to-local rule properties
+ Map<String, Set<String>> authToLocalProperties = kerberosHelper.translateConfigurationSpecifications(container.getAuthToLocalProperties());
+ if (authToLocalProperties != null) {
+ for (Map.Entry<String, Set<String>> entry : authToLocalProperties.entrySet()) {
+ String configType = entry.getKey();
+ Set<String> propertyNames = entry.getValue();
+
+ if (propertyNames != null) {
+ Set<String> configProperties = identityProperties.computeIfAbsent(configType, k -> new HashSet<>());
+ configProperties.addAll(propertyNames);
+ }
+ }
+ }
+
+ // Process the children...
+ Collection<? extends AbstractKerberosDescriptorContainer> childContainers = container.getChildContainers();
+ if (childContainers != null) {
+ for (AbstractKerberosDescriptorContainer childContainer : childContainers) {
+ getIdentityProperties(childContainer, identityProperties);
+ }
+ }
+ }
+
+ return identityProperties;
+ }
}
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 2c9aa8c..904fd01 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
@@ -31,6 +31,7 @@ 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.controller.KerberosHelper;
+import org.apache.ambari.server.controller.UpdateConfigurationPolicy;
import org.apache.ambari.server.orm.dao.HostDAO;
import org.apache.ambari.server.orm.entities.HostEntity;
import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
@@ -100,10 +101,20 @@ public abstract class KerberosServerAction extends AbstractServerAction {
public static final String KDC_TYPE = "kdc_type";
/**
- * A (command parameter) property name used to hold a boolean value indicating whether configurations
- * should be process to see if they need to be updated
+ * A (command parameter) property name used to hold the value indicating how to process
+ * configurations updates. One of the of the following values is expected:
+ * <dl>
+ * <dt>none</dt>
+ * <dd>No configurations will be updated</dd>
+ * <dt>identities_only</dt>
+ * <dd>New and updated configurations related to Kerberos identity information - principal, keytab file, and auth-to-local rule properties</dd>
+ * <dt>new_and_identities</dt>
+ * <dd>Only new configurations declared by the Kerberos descriptor and stack advisor as well as the identity-related changes</dd>
+ * <dt>all</dt>
+ * <dd>All configuration changes (default)</dd>
+ * </dl>
*/
- public static final String UPDATE_CONFIGURATIONS = "update_configurations";
+ public static final String UPDATE_CONFIGURATION_POLICY = "update_configuration_policy";
/**
* A (command parameter) property name used to hold the note to set when applying any
@@ -197,6 +208,20 @@ public abstract class KerberosServerAction extends AbstractServerAction {
}
/**
+ * Given a (command parameter) Map, attempts to safely retrieve the "update_configuration_policy" property.
+ *
+ * @param commandParameters a Map containing the dictionary of data to interrogate
+ * @return a UpdateConfigurationPolicy
+ */
+ protected static UpdateConfigurationPolicy getUpdateConfigurationPolicy(Map<String, String> commandParameters) {
+ String stringValue = getCommandParameterValue(commandParameters, UPDATE_CONFIGURATION_POLICY);
+ UpdateConfigurationPolicy value = UpdateConfigurationPolicy.translate(stringValue);
+
+ // Return UpdateConfigurationPolicy.ALL as a default value
+ return (value == null) ? UpdateConfigurationPolicy.ALL : value;
+ }
+
+ /**
* Given a (command parameter) Map, attempts to safely retrieve the "default_realm" property.
*
* @param commandParameters a Map containing the dictionary of data to interrogate
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java
index b9381b4..80b901b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareDisableKerberosServerAction.java
@@ -203,7 +203,7 @@ public class PrepareDisableKerberosServerAction extends AbstractPrepareKerberosS
kerberosHelper.applyStackAdvisorUpdates(cluster, services, configurations, kerberosConfigurations,
propertiesToIgnore, configurationsToRemove, false);
- processConfigurationChanges(dataDirectory, kerberosConfigurations, configurationsToRemove);
+ processConfigurationChanges(dataDirectory, kerberosConfigurations, configurationsToRemove, kerberosDescriptor, getUpdateConfigurationPolicy(commandParameters));
}
return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java
index 2d29bdc..f9b9717 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java
@@ -128,7 +128,7 @@ public class PrepareEnableKerberosServerAction extends PrepareKerberosIdentities
}
clusterEnvProperties.put(KerberosHelper.SECURITY_ENABLED_PROPERTY_NAME, "true");
- processConfigurationChanges(dataDirectory, kerberosConfigurations, propertiesToRemove);
+ processConfigurationChanges(dataDirectory, kerberosConfigurations, propertiesToRemove, kerberosDescriptor, getUpdateConfigurationPolicy(commandParameters));
return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
}
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
index c7f2003..b6638fa 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java
@@ -32,6 +32,7 @@ import org.apache.ambari.server.agent.CommandReport;
import org.apache.ambari.server.controller.KerberosHelper;
import org.apache.ambari.server.controller.RootComponent;
import org.apache.ambari.server.controller.RootService;
+import org.apache.ambari.server.controller.UpdateConfigurationPolicy;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.ServiceComponentHost;
import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
@@ -113,9 +114,9 @@ public class PrepareKerberosIdentitiesServerAction extends AbstractPrepareKerber
// If we are including the Ambari identity; then ensure that if a service/component filter is set,
// it contains the AMBARI/AMBARI_SERVER component; else do not include the Ambari service identity.
includeAmbariIdentity &= (serviceComponentFilter.get(RootService.AMBARI.name()) != null)
- && serviceComponentFilter.get(RootService.AMBARI.name()).contains(RootComponent.AMBARI_SERVER.name());
+ && serviceComponentFilter.get(RootService.AMBARI.name()).contains(RootComponent.AMBARI_SERVER.name());
- if((operationType != OperationType.DEFAULT)) {
+ if ((operationType != OperationType.DEFAULT)) {
// Update the identity filter, if necessary
identityFilter = updateIdentityFilter(kerberosDescriptor, identityFilter, serviceComponentFilter);
}
@@ -128,13 +129,22 @@ public class PrepareKerberosIdentitiesServerAction extends AbstractPrepareKerber
processServiceComponentHosts(cluster, kerberosDescriptor, schToProcess, identityFilter, dataDirectory,
configurations, kerberosConfigurations, includeAmbariIdentity, propertiesToIgnore);
- kerberosHelper.applyStackAdvisorUpdates(cluster, services, configurations, kerberosConfigurations,
- propertiesToIgnore, propertiesToRemove, true);
+ UpdateConfigurationPolicy updateConfigurationPolicy = getUpdateConfigurationPolicy(commandParameters);
- if ("true".equalsIgnoreCase(getCommandParameterValue(commandParameters, UPDATE_CONFIGURATIONS))) {
+ if (updateConfigurationPolicy != UpdateConfigurationPolicy.NONE) {
+ if (updateConfigurationPolicy.invokeStackAdvisor()) {
+ kerberosHelper.applyStackAdvisorUpdates(cluster, services, configurations, kerberosConfigurations,
+ propertiesToIgnore, propertiesToRemove, true);
+ }
+
+ // TODO: Determine if we need to do this again since it is done a few lines above.
Map<String, Map<String, String>> calculatedConfigurations = kerberosHelper.calculateConfigurations(cluster, null, kerberosDescriptor, false, false);
- processAuthToLocalRules(cluster, calculatedConfigurations, kerberosDescriptor, schToProcess, kerberosConfigurations, getDefaultRealm(commandParameters), false);
- processConfigurationChanges(dataDirectory, kerberosConfigurations, propertiesToRemove);
+
+ if (updateConfigurationPolicy.applyIdentityChanges()) {
+ processAuthToLocalRules(cluster, calculatedConfigurations, kerberosDescriptor, schToProcess, kerberosConfigurations, getDefaultRealm(commandParameters), false);
+ }
+
+ processConfigurationChanges(dataDirectory, kerberosConfigurations, propertiesToRemove, kerberosDescriptor, updateConfigurationPolicy);
}
return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
@@ -247,7 +257,8 @@ public class PrepareKerberosIdentitiesServerAction extends AbstractPrepareKerber
/**
* Add the path of each identity in the collection of identities to the supplied identity filter
* if that identity is not a reference to another identity or if references are allowed.
- * @param identityDescriptors the collection of identity descriptors to process
+ *
+ * @param identityDescriptors the collection of identity descriptors to process
* @param identityFilter the identity filter to modify
* @param skipReferences
*/
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
index def2a9c..40ee9d8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UpgradeResourceProviderTest.java
@@ -58,7 +58,9 @@ import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.AmbariServer;
import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.controller.KerberosHelperImpl;
import org.apache.ambari.server.controller.ResourceProviderFactory;
+import org.apache.ambari.server.controller.UpdateConfigurationPolicy;
import org.apache.ambari.server.controller.spi.Predicate;
import org.apache.ambari.server.controller.spi.Request;
import org.apache.ambari.server.controller.spi.RequestStatus;
@@ -120,6 +122,7 @@ import org.apache.ambari.server.view.ViewRegistry;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
+import org.easymock.Capture;
import org.easymock.EasyMock;
import org.easymock.EasyMockSupport;
import org.junit.After;
@@ -188,7 +191,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
expect(
configHelper.getDefaultProperties(EasyMock.anyObject(StackId.class),
EasyMock.anyString())).andReturn(
- new HashMap<>()).anyTimes();
+ new HashMap<>()).anyTimes();
expect(
configHelper.getChangedConfigTypes(EasyMock.anyObject(Cluster.class), EasyMock.anyObject(ServiceConfigEntity.class),
@@ -322,10 +325,11 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
/**
* Obtain request id from the {@code RequestStatus}
+ *
* @param requestStatus reqult of the {@code createResources}
* @return id of the request
*/
- private long getRequestId(RequestStatus requestStatus){
+ private long getRequestId(RequestStatus requestStatus) {
assertEquals(1, requestStatus.getAssociatedResources().size());
Resource r = requestStatus.getAssociatedResources().iterator().next();
String id = r.getPropertyValue("Upgrade/request_id").toString();
@@ -507,9 +511,9 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
propertyIds.add("Upgrade");
Predicate predicate = new PredicateBuilder()
- .property(UpgradeResourceProvider.UPGRADE_REQUEST_ID).equals("1").and()
- .property(UpgradeResourceProvider.UPGRADE_CLUSTER_NAME).equals("c1")
- .toPredicate();
+ .property(UpgradeResourceProvider.UPGRADE_REQUEST_ID).equals("1").and()
+ .property(UpgradeResourceProvider.UPGRADE_CLUSTER_NAME).equals("c1")
+ .toPredicate();
Request request = PropertyHelper.getReadRequest(propertyIds);
ResourceProvider upgradeResourceProvider = createProvider(amc);
@@ -529,9 +533,9 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
propertyIds.add("UpgradeGroup");
predicate = new PredicateBuilder()
- .property(UpgradeGroupResourceProvider.UPGRADE_REQUEST_ID).equals("1").and()
- .property(UpgradeGroupResourceProvider.UPGRADE_CLUSTER_NAME).equals("c1")
- .toPredicate();
+ .property(UpgradeGroupResourceProvider.UPGRADE_REQUEST_ID).equals("1").and()
+ .property(UpgradeGroupResourceProvider.UPGRADE_CLUSTER_NAME).equals("c1")
+ .toPredicate();
request = PropertyHelper.getReadRequest(propertyIds);
ResourceProvider upgradeGroupResourceProvider = new UpgradeGroupResourceProvider(amc);
@@ -550,10 +554,10 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
propertyIds.add("UpgradeItem");
predicate = new PredicateBuilder()
- .property(UpgradeItemResourceProvider.UPGRADE_GROUP_ID).equals("1").and()
- .property(UpgradeItemResourceProvider.UPGRADE_REQUEST_ID).equals("1").and()
- .property(UpgradeItemResourceProvider.UPGRADE_CLUSTER_NAME).equals("c1")
- .toPredicate();
+ .property(UpgradeItemResourceProvider.UPGRADE_GROUP_ID).equals("1").and()
+ .property(UpgradeItemResourceProvider.UPGRADE_REQUEST_ID).equals("1").and()
+ .property(UpgradeItemResourceProvider.UPGRADE_CLUSTER_NAME).equals("c1")
+ .toPredicate();
request = PropertyHelper.getReadRequest(propertyIds);
ResourceProvider upgradeItemResourceProvider = new UpgradeItemResourceProvider(amc);
@@ -569,10 +573,10 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
propertyIds.add("UpgradeItem");
predicate = new PredicateBuilder()
- .property(UpgradeItemResourceProvider.UPGRADE_GROUP_ID).equals("3").and()
- .property(UpgradeItemResourceProvider.UPGRADE_REQUEST_ID).equals("1").and()
- .property(UpgradeItemResourceProvider.UPGRADE_CLUSTER_NAME).equals("c1")
- .toPredicate();
+ .property(UpgradeItemResourceProvider.UPGRADE_GROUP_ID).equals("3").and()
+ .property(UpgradeItemResourceProvider.UPGRADE_REQUEST_ID).equals("1").and()
+ .property(UpgradeItemResourceProvider.UPGRADE_CLUSTER_NAME).equals("c1")
+ .toPredicate();
request = PropertyHelper.getReadRequest(propertyIds);
upgradeItemResourceProvider = new UpgradeItemResourceProvider(amc);
@@ -622,9 +626,9 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
propertyIds.add("Upgrade");
Predicate predicate = new PredicateBuilder()
- .property(UpgradeResourceProvider.UPGRADE_REQUEST_ID).equals("1").and()
- .property(UpgradeResourceProvider.UPGRADE_CLUSTER_NAME).equals("c1")
- .toPredicate();
+ .property(UpgradeResourceProvider.UPGRADE_REQUEST_ID).equals("1").and()
+ .property(UpgradeResourceProvider.UPGRADE_CLUSTER_NAME).equals("c1")
+ .toPredicate();
request = PropertyHelper.getReadRequest(propertyIds);
Set<Resource> resources = upgradeResourceProvider.getResources(request, predicate);
@@ -812,7 +816,6 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
}
-
/**
* Test Downgrade from the partially completed upgrade
*/
@@ -851,10 +854,10 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
boolean isZKGroupFound = false;
// look only for testing groups
- for (UpgradeGroupEntity group: groups) {
+ for (UpgradeGroupEntity group : groups) {
if (group.getName().equalsIgnoreCase("hive")) {
isHiveGroupFound = true;
- } else if (group.getName().equalsIgnoreCase("zookeeper")){
+ } else if (group.getName().equalsIgnoreCase("zookeeper")) {
isZKGroupFound = true;
}
}
@@ -883,10 +886,10 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
RequestStatus status = upgradeResourceProvider.createResources(request);
UpgradeEntity upgradeEntity = upgradeDao.findUpgradeByRequestId(getRequestId(status));
- for (UpgradeGroupEntity group: upgradeEntity.getUpgradeGroups()) {
+ for (UpgradeGroupEntity group : upgradeEntity.getUpgradeGroups()) {
if (group.getName().equalsIgnoreCase("hive")) {
isHiveGroupFound = true;
- } else if (group.getName().equalsIgnoreCase("zookeeper")){
+ } else if (group.getName().equalsIgnoreCase("zookeeper")) {
isZKGroupFound = true;
}
}
@@ -1141,7 +1144,6 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
}
-
@Test
public void testPercents() throws Exception {
RequestStatus status = testCreateResources();
@@ -1291,11 +1293,11 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
List<StageEntity> stageEntities = stageDAO.findByRequestId(entity.getRequestId());
Gson gson = new Gson();
for (StageEntity se : stageEntities) {
- Map<String, String> map = gson.<Map<String, String>> fromJson(se.getCommandParamsStage(),Map.class);
+ Map<String, String> map = gson.<Map<String, String>>fromJson(se.getCommandParamsStage(), Map.class);
assertTrue(map.containsKey("upgrade_direction"));
assertEquals("upgrade", map.get("upgrade_direction"));
- if(map.containsKey("upgrade_type")){
+ if (map.containsKey("upgrade_type")) {
assertEquals("rolling_upgrade", map.get("upgrade_type"));
}
}
@@ -1541,7 +1543,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
try {
upgradeResourceProvider.createResources(request);
Assert.fail("The request should have failed due to the missing Upgrade/host_order property");
- } catch( SystemException systemException ){
+ } catch (SystemException systemException) {
// expected
}
@@ -1679,7 +1681,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
requestProps.put(UpgradeResourceProvider.UPGRADE_REPO_VERSION_ID, String.valueOf(repoVersionEntity2200.getId()));
requestProps.put(UpgradeResourceProvider.UPGRADE_PACK, "upgrade_test_host_ordered");
requestProps.put(UpgradeResourceProvider.UPGRADE_TYPE, UpgradeType.HOST_ORDERED.toString());
- requestProps.put(UpgradeResourceProvider.UPGRADE_SKIP_PREREQUISITE_CHECKS,Boolean.TRUE.toString());
+ requestProps.put(UpgradeResourceProvider.UPGRADE_SKIP_PREREQUISITE_CHECKS, Boolean.TRUE.toString());
requestProps.put(UpgradeResourceProvider.UPGRADE_DIRECTION, Direction.UPGRADE.name());
requestProps.put(UpgradeResourceProvider.UPGRADE_HOST_ORDERED_HOSTS, hostsOrder);
@@ -1726,8 +1728,8 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
List<UpgradeHistoryEntity> histories = upgrade.getHistory();
assertEquals(2, histories.size());
- for( UpgradeHistoryEntity history : histories){
- assertEquals( "ZOOKEEPER", history.getServiceName() );
+ for (UpgradeHistoryEntity history : histories) {
+ assertEquals("ZOOKEEPER", history.getServiceName());
assertEquals(repoVersionEntity2110, history.getFromReposistoryVersion());
assertEquals(repoVersionEntity2200, history.getTargetRepositoryVersion());
}
@@ -1830,7 +1832,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
@Override
public String apply(UpgradeHistoryEntity input) {
return input.getServiceName() + "/" + input.getComponentName();
- };
+ }
};
for (UpgradeEntity upgrade : upgrades) {
@@ -1874,7 +1876,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
Map<String, Object> requestProps = new HashMap<>();
requestProps.put(UpgradeResourceProvider.UPGRADE_CLUSTER_NAME, "c1");
- requestProps.put(UpgradeResourceProvider.UPGRADE_REPO_VERSION_ID,String.valueOf(repoVersionEntity2112.getId()));
+ requestProps.put(UpgradeResourceProvider.UPGRADE_REPO_VERSION_ID, String.valueOf(repoVersionEntity2112.getId()));
requestProps.put(UpgradeResourceProvider.UPGRADE_PACK, "upgrade_test");
requestProps.put(UpgradeResourceProvider.UPGRADE_SKIP_PREREQUISITE_CHECKS, "true");
requestProps.put(UpgradeResourceProvider.UPGRADE_DIRECTION, Direction.UPGRADE.name());
@@ -1984,7 +1986,6 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
assertTrue(foundConfigTask);
-
// !!! test that a regular upgrade will pick up the config change
cluster.setUpgradeEntity(null);
repoVersionEntity2112.setType(RepositoryType.STANDARD);
@@ -2017,8 +2018,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
}
-
- private String parseSingleMessage(String msgStr){
+ private String parseSingleMessage(String msgStr) {
JsonParser parser = new JsonParser();
JsonArray msgArray = (JsonArray) parser.parse(msgStr);
JsonObject msg = (JsonObject) msgArray.get(0);
@@ -2110,7 +2110,7 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
if (command.getRole().equals(Role.ZOOKEEPER_SERVER) && command.getRoleCommand().equals(RoleCommand.CUSTOM_COMMAND)) {
Map<String, String> commandParams = wrapper.getExecutionCommand().getCommandParams();
assertTrue(commandParams.containsKey(KeyNames.COMMAND_TIMEOUT));
- assertEquals("824",commandParams.get(KeyNames.COMMAND_TIMEOUT));
+ assertEquals("824", commandParams.get(KeyNames.COMMAND_TIMEOUT));
found = true;
}
}
@@ -2178,6 +2178,8 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
*/
@Test
public void testCreateRegenerateKeytabStages() throws Exception {
+ Capture<Map<String, String>> requestPropertyMapCapture = EasyMock.newCapture();
+
Map<String, Object> requestProps = new HashMap<>();
requestProps.put(UpgradeResourceProvider.UPGRADE_CLUSTER_NAME, "c1");
requestProps.put(UpgradeResourceProvider.UPGRADE_REPO_VERSION_ID, String.valueOf(repoVersionEntity2200.getId()));
@@ -2190,9 +2192,9 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
RequestStageContainer requestStageContainer = createNiceMock(RequestStageContainer.class);
expect(requestStageContainer.getStages()).andReturn(Lists.newArrayList()).once();
- expect(kerberosHelperMock.executeCustomOperations(eq(cluster), EasyMock.anyObject(),
+ expect(kerberosHelperMock.executeCustomOperations(eq(cluster), EasyMock.capture(requestPropertyMapCapture),
EasyMock.anyObject(RequestStageContainer.class), eq(null))).andReturn(
- requestStageContainer).once();
+ requestStageContainer).once();
replayAll();
@@ -2207,6 +2209,11 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
}
verifyAll();
+
+ Map<String, String> requestPropertyMap = requestPropertyMapCapture.getValue();
+ assertEquals("true", requestPropertyMap.get(KerberosHelper.ALLOW_RETRY));
+ assertEquals("missing", requestPropertyMap.get(KerberosHelperImpl.SupportedCustomOperation.REGENERATE_KEYTABS.name().toLowerCase()));
+ assertEquals(UpdateConfigurationPolicy.NEW_AND_IDENTITIES.name(), requestPropertyMap.get(KerberosHelper.DIRECTIVE_CONFIG_UPDATE_POLICY.toLowerCase()));
}
/**
@@ -2214,8 +2221,8 @@ public class UpgradeResourceProviderTest extends EasyMockSupport {
*/
private class MockModule implements Module {
/**
- *
- */
+ *
+ */
@Override
public void configure(Binder binder) {
binder.bind(ConfigHelper.class).toInstance(configHelper);
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 d580e6a..47ccef5 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,14 +20,17 @@ 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.capture;
+import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.newCapture;
import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -36,78 +39,215 @@ import java.util.concurrent.ConcurrentMap;
import javax.persistence.EntityManager;
-import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.actionmanager.ActionDBAccessor;
+import org.apache.ambari.server.actionmanager.ActionManager;
+import org.apache.ambari.server.actionmanager.HostRoleCommandFactory;
+import org.apache.ambari.server.actionmanager.RequestFactory;
+import org.apache.ambari.server.actionmanager.StageFactory;
import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.controller.AbstractRootServiceResponseFactory;
+import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.controller.KerberosHelperImpl;
+import org.apache.ambari.server.controller.UpdateConfigurationPolicy;
+import org.apache.ambari.server.hooks.HookContextFactory;
+import org.apache.ambari.server.hooks.HookService;
+import org.apache.ambari.server.metadata.RoleCommandOrderProvider;
+import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
+import org.apache.ambari.server.scheduler.ExecutionScheduler;
+import org.apache.ambari.server.security.encryption.CredentialStoreService;
+import org.apache.ambari.server.stack.StackManagerFactory;
+import org.apache.ambari.server.stageplanner.RoleGraphFactory;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.ConfigFactory;
+import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.Host;
import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponentFactory;
import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.ServiceComponentHostFactory;
+import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
-import org.easymock.EasyMock;
+import org.apache.ambari.server.state.scheduler.RequestExecutionFactory;
+import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.ambari.server.topology.PersistedState;
+import org.apache.ambari.server.topology.tasks.ConfigureClusterTaskFactory;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
+import org.easymock.EasyMockSupport;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.springframework.security.crypto.password.PasswordEncoder;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Provider;
-public class AbstractPrepareKerberosServerActionTest {
- private class PrepareKerberosServerAction extends AbstractPrepareKerberosServerAction{
+public class AbstractPrepareKerberosServerActionTest extends EasyMockSupport {
+ private static final String KERBEROS_DESCRIPTOR_JSON = "" +
+ "{" +
+ " \"identities\": [" +
+ " {" +
+ " \"keytab\": {" +
+ " \"file\": \"${keytab_dir}/spnego.service.keytab\"," +
+ " \"group\": {" +
+ " \"access\": \"r\"," +
+ " \"name\": \"${cluster-env/user_group}\"" +
+ " }," +
+ " \"owner\": {" +
+ " \"access\": \"r\"," +
+ " \"name\": \"root\"" +
+ " }" +
+ " }," +
+ " \"name\": \"spnego\"," +
+ " \"principal\": {" +
+ " \"configuration\": null," +
+ " \"local_username\": null," +
+ " \"type\": \"service\"," +
+ " \"value\": \"HTTP/_HOST@${realm}\"" +
+ " }" +
+ " }" +
+ " ]," +
+ " \"services\": [" +
+ " {" +
+ " \"components\": [" +
+ " {" +
+ " \"identities\": [" +
+ " {" +
+ " \"name\": \"service_master_spnego_identity\"," +
+ " \"reference\": \"/spnego\"" +
+ " }" +
+ " ]," +
+ " \"name\": \"SERVICE_MASTER\"" +
+ " }" +
+ " ]," +
+ " \"configurations\": [" +
+ " {" +
+ " \"service-site\": {" +
+ " \"property1\": \"property1_updated_value\"," +
+ " \"property2\": \"property2_updated_value\"" +
+ " }" +
+ " }" +
+ " ]," +
+ " \"identities\": [" +
+ " {" +
+ " \"name\": \"service_identity\"," +
+ " \"keytab\": {" +
+ " \"configuration\": \"service-site/keytab_file_path\"," +
+ " \"file\": \"${keytab_dir}/service.service.keytab\"," +
+ " \"group\": {" +
+ " \"access\": \"r\"," +
+ " \"name\": \"${cluster-env/user_group}\"" +
+ " }," +
+ " \"owner\": {" +
+ " \"access\": \"r\"," +
+ " \"name\": \"${service-env/service_user}\"" +
+ " }" +
+ " }," +
+ " \"principal\": {" +
+ " \"configuration\": \"service-site/principal_name\"," +
+ " \"local_username\": \"${service-env/service_user}\"," +
+ " \"type\": \"service\"," +
+ " \"value\": \"${service-env/service_user}/_HOST@${realm}\"" +
+ " }" +
+ " }" +
+ " ]," +
+ " \"name\": \"SERVICE\"" +
+ " }" +
+ " ]," +
+ " \"properties\": {" +
+ " \"additional_realms\": \"\"," +
+ " \"keytab_dir\": \"/etc/security/keytabs\"," +
+ " \"principal_suffix\": \"-${cluster_name|toLower()}\"," +
+ " \"realm\": \"${kerberos-env/realm}\"" +
+ " }" +
+ "}";
+
+ private class TestKerberosServerAction extends AbstractPrepareKerberosServerAction {
+
+ @Override
+ protected String getClusterName() {
+ return "c1";
+ }
@Override
- public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext) throws AmbariException, InterruptedException {
+ public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext) {
return null;
}
}
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 AbstractPrepareKerberosServerAction testKerberosServerAction = new TestKerberosServerAction();
@Before
public void setUp() throws Exception {
injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
- bind(KerberosHelper.class).toInstance(kerberosHelper);
- bind(KerberosIdentityDataFileWriterFactory.class).toInstance(kerberosIdentityDataFileWriterFactory);
- bind(Clusters.class).toInstance(clusters);
- bind(AuditLogger.class).toInstance(auditLogger);
- Provider<EntityManager> entityManagerProvider = EasyMock.createNiceMock(Provider.class);
+ bind(AmbariMetaInfo.class).toInstance(createNiceMock(AmbariMetaInfo.class));
+ bind(KerberosHelper.class).to(KerberosHelperImpl.class);
+ bind(KerberosIdentityDataFileWriterFactory.class).toInstance(createNiceMock(KerberosIdentityDataFileWriterFactory.class));
+ bind(KerberosConfigDataFileWriterFactory.class).toInstance(createNiceMock(KerberosConfigDataFileWriterFactory.class));
+ bind(Clusters.class).toInstance(createNiceMock(Clusters.class));
+ bind(AuditLogger.class).toInstance(createNiceMock(AuditLogger.class));
+ bind(ConfigHelper.class).toInstance(createNiceMock(ConfigHelper.class));
+ bind(HostRoleCommandDAO.class).toInstance(createNiceMock(HostRoleCommandDAO.class));
+ bind(ActionManager.class).toInstance(createNiceMock(ActionManager.class));
+ bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class));
+ bind(ExecutionScheduler.class).toInstance(createNiceMock(ExecutionScheduler.class));
+ bind(AmbariManagementController.class).toInstance(createNiceMock(AmbariManagementController.class));
+ bind(ActionDBAccessor.class).toInstance(createNiceMock(ActionDBAccessor.class));
+ bind(StackManagerFactory.class).toInstance(createNiceMock(StackManagerFactory.class));
+ bind(ConfigFactory.class).toInstance(createNiceMock(ConfigFactory.class));
+ bind(ConfigGroupFactory.class).toInstance(createNiceMock(ConfigGroupFactory.class));
+ bind(CredentialStoreService.class).toInstance(createNiceMock(CredentialStoreService.class));
+ bind(RequestExecutionFactory.class).toInstance(createNiceMock(RequestExecutionFactory.class));
+ bind(RequestFactory.class).toInstance(createNiceMock(RequestFactory.class));
+ bind(RoleCommandOrderProvider.class).toInstance(createNiceMock(RoleCommandOrderProvider.class));
+ bind(RoleGraphFactory.class).toInstance(createNiceMock(RoleGraphFactory.class));
+ bind(AbstractRootServiceResponseFactory.class).toInstance(createNiceMock(AbstractRootServiceResponseFactory.class));
+ bind(ServiceComponentFactory.class).toInstance(createNiceMock(ServiceComponentFactory.class));
+ bind(ServiceComponentHostFactory.class).toInstance(createNiceMock(ServiceComponentHostFactory.class));
+ bind(StageFactory.class).toInstance(createNiceMock(StageFactory.class));
+ bind(HostRoleCommandFactory.class).toInstance(createNiceMock(HostRoleCommandFactory.class));
+ bind(HookContextFactory.class).toInstance(createNiceMock(HookContextFactory.class));
+ bind(HookService.class).toInstance(createNiceMock(HookService.class));
+ bind(PasswordEncoder.class).toInstance(createNiceMock(PasswordEncoder.class));
+ bind(PersistedState.class).toInstance(createNiceMock(PersistedState.class));
+ bind(ConfigureClusterTaskFactory.class).toInstance(createNiceMock(ConfigureClusterTaskFactory.class));
+ Provider<EntityManager> entityManagerProvider = createNiceMock(Provider.class);
bind(EntityManager.class).toProvider(entityManagerProvider);
}
});
- injector.injectMembers(prepareKerberosServerAction);
+ injector.injectMembers(testKerberosServerAction);
}
/**
* Test checks that {@code KerberosHelper.applyStackAdvisorUpdates} would be called with
* full list of the services and not only list of services with KerberosDescriptior.
* In this test HDFS service will have KerberosDescriptor, while Zookeeper not.
+ *
* @throws Exception
*/
@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";
@@ -118,20 +258,20 @@ public class AbstractPrepareKerberosServerActionTest {
Collection<String> identityFilter = new ArrayList<>();
Map<String, Map<String, String>> kerberosConfigurations = new HashMap<>();
Map<String, Set<String>> propertiesToIgnore = new HashMap<>();
- Map<String, String> descriptorProperties = new HashMap<>();
Map<String, Map<String, String>> configurations = new HashMap<>();
List<ServiceComponentHost> serviceComponentHosts = new ArrayList<ServiceComponentHost>() {{
add(serviceComponentHostHDFS);
add(serviceComponentHostZK);
}};
- Map<String, Service> clusterServices = new HashMap<String, Service>(){{
+ Map<String, Service> clusterServices = new HashMap<String, Service>() {{
put(hdfsService, null);
put(zookeeperService, null);
}};
- expect(kerberosDescriptor.getProperties()).andReturn(descriptorProperties).atLeastOnce();
- expect(kerberosIdentityDataFileWriterFactory.createKerberosIdentityDataFileWriter((File)anyObject())).andReturn(kerberosIdentityDataFileWriter);
+ KerberosIdentityDataFileWriterFactory kerberosIdentityDataFileWriterFactory = injector.getInstance(KerberosIdentityDataFileWriterFactory.class);
+ expect(kerberosIdentityDataFileWriterFactory.createKerberosIdentityDataFileWriter(anyObject(File.class))).andReturn(kerberosIdentityDataFileWriter);
+
// it's important to pass a copy of clusterServices
expect(cluster.getServices()).andReturn(new HashMap<>(clusterServices)).atLeastOnce();
@@ -150,22 +290,201 @@ public class AbstractPrepareKerberosServerActionTest {
expect(serviceDescriptor.getComponent(hdfsComponent)).andReturn(componentDescriptor).once();
expect(componentDescriptor.getConfigurations(anyBoolean())).andReturn(null);
- replay(kerberosDescriptor, kerberosHelper, kerberosIdentityDataFileWriterFactory,
- cluster, serviceComponentHostHDFS, serviceComponentHostZK, serviceDescriptor, componentDescriptor);
+ replayAll();
- prepareKerberosServerAction.processServiceComponentHosts(cluster,
- kerberosDescriptor,
- serviceComponentHosts,
- identityFilter,
- "",
+ injector.getInstance(AmbariMetaInfo.class).init();
+
+ testKerberosServerAction.processServiceComponentHosts(cluster,
+ kerberosDescriptor,
+ serviceComponentHosts,
+ identityFilter,
+ "",
configurations, kerberosConfigurations,
false, propertiesToIgnore);
- verify(kerberosHelper);
+ verifyAll();
// Ensure the host and hostname values were set in the configuration context
Assert.assertEquals("host1", configurations.get("").get("host"));
Assert.assertEquals("host1", configurations.get("").get("hostname"));
}
+ @Test
+ public void testProcessConfigurationChanges() throws Exception {
+ // Existing property map....
+ Map<String, String> serviceSiteProperties = new HashMap<>();
+ serviceSiteProperties.put("property1", "property1_value");
+ serviceSiteProperties.put("principal_name", "principal_name_value");
+ serviceSiteProperties.put("keytab_file_path", "keytab_file_path_value");
+
+ Map<String, Map<String, String>> effectiveProperties = new HashMap<>();
+ effectiveProperties.put("service-site", serviceSiteProperties);
+
+ // Updated property map....
+ Map<String, String> updatedServiceSiteProperties = new HashMap<>();
+ updatedServiceSiteProperties.put("property1", "property1_updated_value");
+ updatedServiceSiteProperties.put("property2", "property2_updated_value");
+ updatedServiceSiteProperties.put("principal_name", "principal_name_updated_value");
+ updatedServiceSiteProperties.put("keytab_file_path", "keytab_file_path_updated_value");
+
+ Map<String, Map<String, String>> kerberosConfigurations = new HashMap<>();
+ kerberosConfigurations.put("service-site", updatedServiceSiteProperties);
+
+ KerberosDescriptor kerberosDescriptor = new KerberosDescriptorFactory().createInstance(KERBEROS_DESCRIPTOR_JSON);
+
+ ConfigHelper configHelper = injector.getInstance(ConfigHelper.class);
+ expect(configHelper.getEffectiveConfigProperties(eq("c1"), eq(null)))
+ .andReturn(effectiveProperties).anyTimes();
+
+ KerberosConfigDataFileWriterFactory factory = injector.getInstance(KerberosConfigDataFileWriterFactory.class);
+
+ ConfigWriterData dataCaptureAll = setupConfigWriter(factory);
+ ConfigWriterData dataCaptureIdentitiesOnly = setupConfigWriter(factory);
+ ConfigWriterData dataCaptureNewAndIdentities = setupConfigWriter(factory);
+ ConfigWriterData dataCaptureNone = setupConfigWriter(factory);
+
+ replayAll();
+
+ injector.getInstance(AmbariMetaInfo.class).init();
+
+ Map<String, String> expectedProperties;
+
+ // Update all configurations
+ testKerberosServerAction.processConfigurationChanges("test_directory",
+ kerberosConfigurations, Collections.emptyMap(), kerberosDescriptor, UpdateConfigurationPolicy.ALL);
+
+ expectedProperties = new HashMap<>();
+ expectedProperties.put("property1", "property1_updated_value");
+ expectedProperties.put("property2", "property2_updated_value");
+ expectedProperties.put("principal_name", "principal_name_updated_value");
+ expectedProperties.put("keytab_file_path", "keytab_file_path_updated_value");
+
+ verifyDataCapture(dataCaptureAll, Collections.singletonMap("service-site", expectedProperties));
+
+ // Update only identity configurations
+ testKerberosServerAction.processConfigurationChanges("test_directory",
+ kerberosConfigurations, Collections.emptyMap(), kerberosDescriptor, UpdateConfigurationPolicy.IDENTITIES_ONLY);
+
+ expectedProperties = new HashMap<>();
+ expectedProperties.put("principal_name", "principal_name_updated_value");
+ expectedProperties.put("keytab_file_path", "keytab_file_path_updated_value");
+
+ verifyDataCapture(dataCaptureIdentitiesOnly, Collections.singletonMap("service-site", expectedProperties));
+
+ // Update new and identity configurations
+ testKerberosServerAction.processConfigurationChanges("test_directory",
+ kerberosConfigurations, Collections.emptyMap(), kerberosDescriptor, UpdateConfigurationPolicy.NEW_AND_IDENTITIES);
+
+ expectedProperties = new HashMap<>();
+ expectedProperties.put("property2", "property2_updated_value");
+ expectedProperties.put("principal_name", "principal_name_updated_value");
+ expectedProperties.put("keytab_file_path", "keytab_file_path_updated_value");
+
+ verifyDataCapture(dataCaptureNewAndIdentities, Collections.singletonMap("service-site", expectedProperties));
+
+ // Update no configurations
+ testKerberosServerAction.processConfigurationChanges("test_directory",
+ kerberosConfigurations, Collections.emptyMap(), kerberosDescriptor, UpdateConfigurationPolicy.NONE);
+
+ verifyDataCapture(dataCaptureNone, Collections.emptyMap());
+
+ verifyAll();
+
+ }
+
+ private void verifyDataCapture(ConfigWriterData configWriterData, Map<String, Map<String, String>> expectedConfigurations) {
+
+ int expectedCaptures = 0;
+ Collection<Map<String, String>> expectedValuesCollection = expectedConfigurations.values();
+ for (Map<String, String> expectedValues : expectedValuesCollection) {
+ expectedCaptures += expectedValues.size();
+ }
+
+ Capture<String> captureConfigType = configWriterData.getCaptureConfigType();
+ if (expectedCaptures > 0) {
+ Assert.assertTrue(captureConfigType.hasCaptured());
+ List<String> valuesConfigType = captureConfigType.getValues();
+ Assert.assertEquals(expectedCaptures, valuesConfigType.size());
+ } else {
+ Assert.assertFalse(captureConfigType.hasCaptured());
+ }
+
+ Capture<String> capturePropertyName = configWriterData.getCapturePropertyName();
+ if (expectedCaptures > 0) {
+ Assert.assertTrue(capturePropertyName.hasCaptured());
+ List<String> valuesPropertyName = capturePropertyName.getValues();
+ Assert.assertEquals(expectedCaptures, valuesPropertyName.size());
+ } else {
+ Assert.assertFalse(capturePropertyName.hasCaptured());
+ }
+
+ Capture<String> capturePropertyValue = configWriterData.getCapturePropertyValue();
+ if (expectedCaptures > 0) {
+ Assert.assertTrue(capturePropertyValue.hasCaptured());
+ List<String> valuesPropertyValue = capturePropertyValue.getValues();
+ Assert.assertEquals(expectedCaptures, valuesPropertyValue.size());
+ } else {
+ Assert.assertFalse(capturePropertyValue.hasCaptured());
+ }
+
+ if (expectedCaptures > 0) {
+ int i = 0;
+ List<String> valuesConfigType = captureConfigType.getValues();
+ List<String> valuesPropertyName = capturePropertyName.getValues();
+ List<String> valuesPropertyValue = capturePropertyValue.getValues();
+
+ for (Map.Entry<String, Map<String, String>> entry : expectedConfigurations.entrySet()) {
+ String configType = entry.getKey();
+ Map<String, String> properties = entry.getValue();
+
+ for(Map.Entry<String, String> property:properties.entrySet()) {
+ Assert.assertEquals(configType, valuesConfigType.get(i));
+ Assert.assertEquals(property.getKey(), valuesPropertyName.get(i));
+ Assert.assertEquals(property.getValue(), valuesPropertyValue.get(i));
+ i++;
+ }
+ }
+ }
+
+ }
+
+ private ConfigWriterData setupConfigWriter(KerberosConfigDataFileWriterFactory factory) throws IOException {
+ Capture<String> captureConfigType = newCapture(CaptureType.ALL);
+ Capture<String> capturePropertyName = newCapture(CaptureType.ALL);
+ Capture<String> capturePropertyValue = newCapture(CaptureType.ALL);
+
+ KerberosConfigDataFileWriter mockWriter = createMock(KerberosConfigDataFileWriter.class);
+ mockWriter.addRecord(capture(captureConfigType), capture(capturePropertyName), capture(capturePropertyValue), eq(KerberosConfigDataFileWriter.OPERATION_TYPE_SET));
+ expectLastCall().anyTimes();
+ mockWriter.close();
+ expectLastCall().anyTimes();
+
+ expect(factory.createKerberosConfigDataFileWriter(anyObject(File.class))).andReturn(mockWriter).once();
+
+ return new ConfigWriterData(captureConfigType, capturePropertyName, capturePropertyValue);
+ }
+
+ private class ConfigWriterData {
+ private final Capture<String> captureConfigType;
+ private final Capture<String> capturePropertyName;
+ private final Capture<String> capturePropertyValue;
+
+ private ConfigWriterData(Capture<String> captureConfigType, Capture<String> capturePropertyName, Capture<String> capturePropertyValue) {
+ this.captureConfigType = captureConfigType;
+ this.capturePropertyName = capturePropertyName;
+ this.capturePropertyValue = capturePropertyValue;
+ }
+
+ Capture<String> getCaptureConfigType() {
+ return captureConfigType;
+ }
+
+ Capture<String> getCapturePropertyName() {
+ return capturePropertyName;
+ }
+
+ Capture<String> getCapturePropertyValue() {
+ return capturePropertyValue;
+ }
+ }
}