This is an automated email from the ASF dual-hosted git repository. smolnar 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 4eee0f5 AMBARI-24866. Make sure we use stack advisor to apply relevant service recommendation upon LDAP configuration addition/change (#2592) 4eee0f5 is described below commit 4eee0f56d2fbfdfb0caace955339bc0c46a85a3c Author: Sandor Molnar <smol...@apache.org> AuthorDate: Sat Nov 10 12:34:02 2018 +0100 AMBARI-24866. Make sure we use stack advisor to apply relevant service recommendation upon LDAP configuration addition/change (#2592) --- .../services/stackadvisor/StackAdvisorHelper.java | 6 +- .../services/stackadvisor/StackAdvisorRequest.java | 1 + .../services/stackadvisor/StackAdvisorRunner.java | 7 +- .../commands/StackAdvisorCommandType.java | 2 + .../AmbariServerLDAPConfigurationHandler.java | 30 ++- .../AmbariServerSSOConfigurationHandler.java | 174 ++--------------- ...erverStackAdvisorAwareConfigurationHandler.java | 211 +++++++++++++++++++++ .../src/main/resources/scripts/stack_advisor.py | 6 + .../src/main/resources/stacks/service_advisor.py | 6 + .../src/main/resources/stacks/stack_advisor.py | 107 +++++++++++ .../stackadvisor/StackAdvisorHelperTest.java | 5 + .../stackadvisor/StackAdvisorRequestTypeTest.java | 5 + .../stackadvisor/StackAdvisorRunnerTest.java | 4 - .../AmbariServerConfigurationHandlerTest.java | 20 +- ...ComponentConfigurationResourceProviderTest.java | 9 +- 15 files changed, 401 insertions(+), 192 deletions(-) diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java index abdc375..d3f2072 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java @@ -47,7 +47,6 @@ public class StackAdvisorHelper { private File recommendationsDir; private String recommendationsArtifactsLifetime; private int recommendationsArtifactsRolloverMax; - public static String pythonStackAdvisorScript; private final AmbariMetaInfo metaInfo; private final AmbariServerConfigurationHandler ambariServerConfigurationHandler; @@ -61,8 +60,6 @@ public class StackAdvisorHelper { this.recommendationsDir = conf.getRecommendationsDir(); this.recommendationsArtifactsLifetime = conf.getRecommendationsArtifactsLifetime(); this.recommendationsArtifactsRolloverMax = conf.getRecommendationsArtifactsRolloverMax(); - - this.pythonStackAdvisorScript = conf.getStackAdvisorScript(); this.saRunner = saRunner; this.metaInfo = metaInfo; this.ambariServerConfigurationHandler = ambariServerConfigurationHandler; @@ -145,6 +142,9 @@ public class StackAdvisorHelper { } else if (requestType == StackAdvisorRequestType.SSO_CONFIGURATIONS) { command = new ConfigurationRecommendationCommand(StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS_FOR_SSO, recommendationsDir, recommendationsArtifactsLifetime, serviceAdvisorType, requestId, saRunner, metaInfo, ambariServerConfigurationHandler); + } else if (requestType == StackAdvisorRequestType.LDAP_CONFIGURATIONS) { + command = new ConfigurationRecommendationCommand(StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS_FOR_LDAP, recommendationsDir, recommendationsArtifactsLifetime, serviceAdvisorType, + requestId, saRunner, metaInfo, ambariServerConfigurationHandler); } else if (requestType == StackAdvisorRequestType.KERBEROS_CONFIGURATIONS) { command = new ConfigurationRecommendationCommand(StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS_FOR_KERBEROS, recommendationsDir, recommendationsArtifactsLifetime, serviceAdvisorType, requestId, saRunner, metaInfo, ambariServerConfigurationHandler); diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java index 83a9367..ea4a4e0 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java @@ -228,6 +228,7 @@ public class StackAdvisorRequest { public enum StackAdvisorRequestType { HOST_GROUPS("host_groups"), CONFIGURATIONS("configurations"), + LDAP_CONFIGURATIONS("ldap-configurations"), SSO_CONFIGURATIONS("sso-configurations"), KERBEROS_CONFIGURATIONS("kerberos-configurations"), CONFIGURATION_DEPENDENCIES("configuration-dependencies"); diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunner.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunner.java index 395200b..424feed 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunner.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunner.java @@ -27,6 +27,7 @@ import java.util.List; import org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommandType; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.state.ServiceInfo; +import org.apache.ambari.serviceadvisor.ServiceAdvisor; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -67,15 +68,13 @@ public class StackAdvisorRunner { switch (serviceAdvisorType) { case JAVA: - org.apache.ambari.serviceadvisor.ServiceAdvisor serviceAdvisor = new org.apache.ambari.serviceadvisor.ServiceAdvisor(); - LOG.info("StackAdvisorRunner.runScript(): Calling Java ServiceAdvisor's run method."); - stackAdvisorReturnCode = serviceAdvisor.run(saCommandType.toString(), hostsFile, servicesFile, outputFile, errorFile); + stackAdvisorReturnCode = ServiceAdvisor.run(saCommandType.toString(), hostsFile, servicesFile, outputFile, errorFile); LOG.info(String.format("StackAdvisorRunner.runScript(): Java ServiceAdvisor's return code: %d", stackAdvisorReturnCode)); break; case PYTHON: LOG.info("StackAdvisorRunner.runScript(): Calling Python Stack Advisor."); - ProcessBuilder builder = prepareShellCommand(ServiceInfo.ServiceAdvisorType.PYTHON, StackAdvisorHelper.pythonStackAdvisorScript, saCommandType, + ProcessBuilder builder = prepareShellCommand(ServiceInfo.ServiceAdvisorType.PYTHON, configs.getStackAdvisorScript(), saCommandType, actionDirectory, outputFile, errorFile); builder.environment().put("METADATA_DIR_PATH", configs.getProperty(Configuration.METADATA_DIR_PATH)); diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandType.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandType.java index 57924ee..553d0f2 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandType.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandType.java @@ -31,6 +31,8 @@ public enum StackAdvisorCommandType { RECOMMEND_CONFIGURATIONS_FOR_SSO("recommend-configurations-for-sso"), + RECOMMEND_CONFIGURATIONS_FOR_LDAP("recommend-configurations-for-ldap"), + RECOMMEND_CONFIGURATIONS_FOR_KERBEROS("recommend-configurations-for-kerberos"), RECOMMEND_CONFIGURATION_DEPENDENCIES("recommend-configuration-dependencies"), diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerLDAPConfigurationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerLDAPConfigurationHandler.java index bfb2e75..f08c1de 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerLDAPConfigurationHandler.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerLDAPConfigurationHandler.java @@ -18,19 +18,26 @@ package org.apache.ambari.server.controller.internal; +import static org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest.StackAdvisorRequestType.LDAP_CONFIGURATIONS; + import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; +import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorHelper; import org.apache.ambari.server.configuration.AmbariServerConfigurationCategory; import org.apache.ambari.server.configuration.Configuration; +import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.controller.spi.SystemException; import org.apache.ambari.server.events.publishers.AmbariEventPublisher; import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration; import org.apache.ambari.server.ldap.service.AmbariLdapException; import org.apache.ambari.server.ldap.service.LdapFacade; import org.apache.ambari.server.orm.dao.AmbariConfigurationDAO; +import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.ConfigHelper; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,17 +49,27 @@ import com.google.inject.Singleton; * AmbariServerLDAPConfigurationHandler handles Ambari server LDAP-specific configuration properties. */ @Singleton -public class AmbariServerLDAPConfigurationHandler extends AmbariServerConfigurationHandler { +public class AmbariServerLDAPConfigurationHandler extends AmbariServerStackAdvisorAwareConfigurationHandler { private static final Logger LOGGER = LoggerFactory.getLogger(AmbariServerLDAPConfigurationHandler.class); private final LdapFacade ldapFacade; @Inject - AmbariServerLDAPConfigurationHandler(LdapFacade ldapFacade, AmbariConfigurationDAO ambariConfigurationDAO, - AmbariEventPublisher publisher, Configuration ambariConfiguration) { - super(ambariConfigurationDAO, publisher, ambariConfiguration); + AmbariServerLDAPConfigurationHandler(Clusters clusters, ConfigHelper configHelper, AmbariManagementController managementController, + StackAdvisorHelper stackAdvisorHelper, AmbariConfigurationDAO ambariConfigurationDAO, AmbariEventPublisher publisher, Configuration ambariConfiguration, + LdapFacade ldapFacade) { + super(ambariConfigurationDAO, publisher, ambariConfiguration, clusters, configHelper, managementController, stackAdvisorHelper); this.ldapFacade = ldapFacade; } + + @Override + public void updateComponentCategory(String categoryName, Map<String, String> properties, boolean removePropertiesIfNotSpecified) throws AmbariException { + super.updateComponentCategory(categoryName, properties, removePropertiesIfNotSpecified); + final AmbariLdapConfiguration ldapConfiguration = new AmbariLdapConfiguration(getConfigurationProperties(AmbariServerConfigurationCategory.LDAP_CONFIGURATION.getCategoryName())); + if (ldapConfiguration.ldapEnabled()) { + processClusters(LDAP_CONFIGURATIONS); + } + } @Override public OperationResult performOperation(String categoryName, Map<String, String> properties, @@ -143,6 +160,11 @@ public class AmbariServerLDAPConfigurationHandler extends AmbariServerConfigurat } } + @Override + protected String getServiceVersionNote() { + return "Ambari managed LDAP configurations"; + } + enum OperationType { TEST_CONNECTION("test-connection"), TEST_ATTRIBUTES("test-attributes"), diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerSSOConfigurationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerSSOConfigurationHandler.java index dece520..39f0d5f 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerSSOConfigurationHandler.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerSSOConfigurationHandler.java @@ -20,34 +20,20 @@ import static org.apache.ambari.server.configuration.AmbariServerConfigurationKe import static org.apache.ambari.server.configuration.AmbariServerConfigurationKey.SSO_MANAGE_SERVICES; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.apache.ambari.server.AmbariException; -import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException; import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorHelper; -import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest; -import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.events.publishers.AmbariEventPublisher; import org.apache.ambari.server.orm.dao.AmbariConfigurationDAO; -import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; 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.StackId; -import org.apache.ambari.server.state.ValueAttributesInfo; import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -57,29 +43,12 @@ import com.google.inject.Singleton; * handing changes to the SSO configuration */ @Singleton -public class AmbariServerSSOConfigurationHandler extends AmbariServerConfigurationHandler { - private static final Logger LOGGER = LoggerFactory.getLogger(AmbariServerSSOConfigurationHandler.class); - - private final Clusters clusters; - - private final ConfigHelper configHelper; - - private final AmbariManagementController managementController; - - private final StackAdvisorHelper stackAdvisorHelper; +public class AmbariServerSSOConfigurationHandler extends AmbariServerStackAdvisorAwareConfigurationHandler { @Inject - public AmbariServerSSOConfigurationHandler(Clusters clusters, ConfigHelper configHelper, - AmbariManagementController managementController, - StackAdvisorHelper stackAdvisorHelper, - AmbariConfigurationDAO ambariConfigurationDAO, - AmbariEventPublisher publisher, - Configuration ambariConfiguration) { - super(ambariConfigurationDAO, publisher, ambariConfiguration); - this.clusters = clusters; - this.configHelper = configHelper; - this.managementController = managementController; - this.stackAdvisorHelper = stackAdvisorHelper; + public AmbariServerSSOConfigurationHandler(Clusters clusters, ConfigHelper configHelper, AmbariManagementController managementController, + StackAdvisorHelper stackAdvisorHelper, AmbariConfigurationDAO ambariConfigurationDAO, AmbariEventPublisher publisher, Configuration ambariConfiguration) { + super(ambariConfigurationDAO, publisher, ambariConfiguration, clusters, configHelper, managementController, stackAdvisorHelper); } @Override @@ -91,24 +60,11 @@ public class AmbariServerSSOConfigurationHandler extends AmbariServerConfigurati super.updateComponentCategory(categoryName, properties, removePropertiesIfNotSpecified); // Determine if Ambari is managing SSO configurations... - boolean manageSSOConfigurations; - - Map<String, String> ssoProperties = getConfigurationProperties(SSO_CONFIGURATION.getCategoryName()); - manageSSOConfigurations = (ssoProperties != null) && "true".equalsIgnoreCase(ssoProperties.get(SSO_MANAGE_SERVICES.key())); + final Map<String, String> ssoProperties = getConfigurationProperties(SSO_CONFIGURATION.getCategoryName()); + final boolean manageSSOConfigurations = (ssoProperties != null) && "true".equalsIgnoreCase(ssoProperties.get(SSO_MANAGE_SERVICES.key())); if (manageSSOConfigurations) { - Map<String, Cluster> clusterMap = clusters.getClusters(); - - if (clusterMap != null) { - for (Cluster cluster : clusterMap.values()) { - try { - LOGGER.info(String.format("Managing the SSO configuration for the cluster named '%s'", cluster.getClusterName())); - processCluster(cluster); - } catch (AmbariException | StackAdvisorException e) { - LOGGER.warn(String.format("Failed to update the the SSO configuration for the cluster named '%s': ", cluster.getClusterName()), e); - } - } - } + processClusters(SSO_CONFIGURATIONS); } } @@ -133,117 +89,9 @@ public class AmbariServerSSOConfigurationHandler extends AmbariServerConfigurati .collect(Collectors.toSet()); } } - - /** - * Build the stack advisor request, call the stack advisor, then automatically handle the recommendations. - * <p> - * Any recommendation coming back from the Stack/service advisor is expected to be only SSO-related - * configurations. - * <p> - * If there are no changes to the current configurations, no new configuration versions will be created. - * - * @param cluster the cluster to process - * @throws AmbariException - * @throws StackAdvisorException - */ - private void processCluster(Cluster cluster) throws AmbariException, StackAdvisorException { - StackId stackVersion = cluster.getCurrentStackVersion(); - List<String> hosts = cluster.getHosts().stream().map(Host::getHostName).collect(Collectors.toList()); - Set<String> serviceNames = cluster.getServices().values().stream().map(Service::getName).collect(Collectors.toSet()); - - // Build the StackAdvisor request for SSO-related configurations. it is expected that the stack - // advisor will abide by the configurations set in the Ambari sso-configurations to enable and - // disable SSO integration for the relevant services. - StackAdvisorRequest request = StackAdvisorRequest.StackAdvisorRequestBuilder. - forStack(stackVersion.getStackName(), stackVersion.getStackVersion()) - .ofType(SSO_CONFIGURATIONS) - .forHosts(hosts) - .forServices(serviceNames) - .withComponentHostsMap(cluster.getServiceComponentHostMap(null, null)) - .withConfigurations(calculateExistingConfigurations(cluster)) - .build(); - - // Execute the stack advisor - RecommendationResponse response = stackAdvisorHelper.recommend(request); - - // Process the recommendations and automatically apply them. Ideally this is what the user wanted - RecommendationResponse.Recommendation recommendation = (response == null) ? null : response.getRecommendations(); - RecommendationResponse.Blueprint blueprint = (recommendation == null) ? null : recommendation.getBlueprint(); - Map<String, RecommendationResponse.BlueprintConfigurations> configurations = (blueprint == null) ? null : blueprint.getConfigurations(); - - if (configurations != null) { - for (Map.Entry<String, RecommendationResponse.BlueprintConfigurations> configuration : configurations.entrySet()) { - processConfigurationType(cluster, configuration.getKey(), configuration.getValue()); - } - } - } - - /** - * Process the configuration to add, update, and remove properties as needed. - * - * @param cluster the cluster - * @param configType the configuration type - * @param configurations the recommended configuration values - * @throws AmbariException - */ - private void processConfigurationType(Cluster cluster, String configType, - RecommendationResponse.BlueprintConfigurations configurations) - throws AmbariException { - - Map<String, String> updates = new HashMap<>(); - Collection<String> removals = new HashSet<>(); - - // Gather the updates - Map<String, String> recommendedConfigProperties = configurations.getProperties(); - if (recommendedConfigProperties != null) { - updates.putAll(recommendedConfigProperties); - } - - // Determine if any properties need to be removed - Map<String, ValueAttributesInfo> recommendedConfigPropertyAttributes = configurations.getPropertyAttributes(); - if (recommendedConfigPropertyAttributes != null) { - for (Map.Entry<String, ValueAttributesInfo> entry : recommendedConfigPropertyAttributes.entrySet()) { - ValueAttributesInfo info = entry.getValue(); - - if ((info != null) && "true".equalsIgnoreCase(info.getDelete())) { - updates.remove(entry.getKey()); - removals.add(entry.getKey()); - } - } - } - - configHelper.updateConfigType(cluster, cluster.getCurrentStackVersion(), managementController, - configType, updates, removals, - "internal", "Ambari-managed single sign-on configurations"); - } - - /** - * Calculate the current configurations for all services - * - * @param cluster the cluster - * @return a map of services and their configurations - * @throws AmbariException - */ - private Map<String, Map<String, Map<String, String>>> calculateExistingConfigurations(Cluster cluster) throws AmbariException { - Map<String, Map<String, String>> configurationTags = configHelper.getEffectiveDesiredTags(cluster, null); - Map<String, Map<String, String>> effectiveConfigs = configHelper.getEffectiveConfigProperties(cluster, configurationTags); - - Map<String, Map<String, Map<String, String>>> requestConfigurations = new HashMap<>(); - if (effectiveConfigs != null) { - for (Map.Entry<String, Map<String, String>> configuration : effectiveConfigs.entrySet()) { - Map<String, Map<String, String>> properties = new HashMap<>(); - String configType = configuration.getKey(); - Map<String, String> configurationProperties = configuration.getValue(); - - if (configurationProperties == null) { - configurationProperties = Collections.emptyMap(); - } - - properties.put("properties", configurationProperties); - requestConfigurations.put(configType, properties); - } - } - - return requestConfigurations; + + @Override + protected String getServiceVersionNote() { + return "Ambari-managed single sign-on configurations"; } } diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerStackAdvisorAwareConfigurationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerStackAdvisorAwareConfigurationHandler.java new file mode 100644 index 0000000..e872de9 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AmbariServerStackAdvisorAwareConfigurationHandler.java @@ -0,0 +1,211 @@ +/* + * 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.internal; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException; +import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorHelper; +import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest; +import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse; +import org.apache.ambari.server.configuration.Configuration; +import org.apache.ambari.server.controller.AmbariManagementController; +import org.apache.ambari.server.events.publishers.AmbariEventPublisher; +import org.apache.ambari.server.orm.dao.AmbariConfigurationDAO; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.Clusters; +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.StackId; +import org.apache.ambari.server.state.ValueAttributesInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * AmbariServerStackAdvisorAwareConfigurationHandler handles Ambari server specific configuration properties using the stack advisor. + */ +class AmbariServerStackAdvisorAwareConfigurationHandler extends AmbariServerConfigurationHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(AmbariServerStackAdvisorAwareConfigurationHandler.class); + + private final Clusters clusters; + private final ConfigHelper configHelper; + private final AmbariManagementController managementController; + private final StackAdvisorHelper stackAdvisorHelper; + + AmbariServerStackAdvisorAwareConfigurationHandler(AmbariConfigurationDAO ambariConfigurationDAO, AmbariEventPublisher publisher, Configuration ambariConfiguration, + Clusters clusters, ConfigHelper configHelper, AmbariManagementController managementController, StackAdvisorHelper stackAdvisorHelper) { + super(ambariConfigurationDAO, publisher, ambariConfiguration); + this.clusters = clusters; + this.configHelper = configHelper; + this.managementController = managementController; + this.stackAdvisorHelper = stackAdvisorHelper; + } + + /** + * Build the stack advisor request, call the stack advisor, then automatically + * handle the recommendations on all clusters that managed by Ambari. + * + * @param stackAdvisorRequestType + * the stack advisor request type + */ + protected void processClusters(StackAdvisorRequest.StackAdvisorRequestType stackAdvisorRequestType) { + final Map<String, Cluster> clusterMap = clusters.getClusters(); + + if (clusterMap != null) { + for (Cluster cluster : clusterMap.values()) { + try { + LOGGER.info("Managing the {} configuration for the cluster named '{}'", stackAdvisorRequestType.toString(), cluster.getClusterName()); + processCluster(cluster, stackAdvisorRequestType); + } catch (AmbariException | StackAdvisorException e) { + LOGGER.warn("Failed to update the {} for the cluster named '{}': ", stackAdvisorRequestType.toString(), cluster.getClusterName(), e); + } + } + } + } + + /** + * Build the stack advisor request, call the stack advisor, then automatically + * handle the recommendations. + * <p> + * Any recommendation coming back from the Stack/service advisor is expected to + * be only related configurations of the given request type (LDAP/SSO) + * <p> + * If there are no changes to the current configurations, no new configuration + * versions will be created. + * + * @param cluster + * the cluster to process + * @param stackAdvisorRequestType + * the stack advisor request type + * @throws AmbariException + * @throws StackAdvisorException + */ + protected void processCluster(Cluster cluster, StackAdvisorRequest.StackAdvisorRequestType stackAdvisorRequestType) throws AmbariException, StackAdvisorException { + final StackId stackVersion = cluster.getCurrentStackVersion(); + final List<String> hosts = cluster.getHosts().stream().map(Host::getHostName).collect(Collectors.toList()); + final Set<String> serviceNames = cluster.getServices().values().stream().map(Service::getName).collect(Collectors.toSet()); + + final StackAdvisorRequest request = StackAdvisorRequest.StackAdvisorRequestBuilder + .forStack(stackVersion.getStackName(), stackVersion.getStackVersion()) + .ofType(stackAdvisorRequestType) + .forHosts(hosts) + .forServices(serviceNames) + .withComponentHostsMap(cluster.getServiceComponentHostMap(null, null)) + .withConfigurations(calculateExistingConfigurations(cluster)) + .build(); + + // Execute the stack advisor + final RecommendationResponse response = stackAdvisorHelper.recommend(request); + + // Process the recommendations and automatically apply them. Ideally this is what the user wanted + final RecommendationResponse.Recommendation recommendation = (response == null) ? null : response.getRecommendations(); + final RecommendationResponse.Blueprint blueprint = (recommendation == null) ? null : recommendation.getBlueprint(); + final Map<String, RecommendationResponse.BlueprintConfigurations> configurations = (blueprint == null) ? null : blueprint.getConfigurations(); + + if (configurations != null) { + for (Map.Entry<String, RecommendationResponse.BlueprintConfigurations> configuration : configurations.entrySet()) { + processConfigurationType(cluster, configuration.getKey(), configuration.getValue()); + } + } + } + + /** + * Process the configuration to add, update, and remove properties as needed. + * + * @param cluster + * the cluster + * @param configType + * the configuration type + * @param configurations + * the recommended configuration values + * @throws AmbariException + */ + private void processConfigurationType(Cluster cluster, String configType, RecommendationResponse.BlueprintConfigurations configurations) throws AmbariException { + Map<String, String> updates = new HashMap<>(); + Collection<String> removals = new HashSet<>(); + + // Gather the updates + Map<String, String> recommendedConfigProperties = configurations.getProperties(); + if (recommendedConfigProperties != null) { + updates.putAll(recommendedConfigProperties); + } + + // Determine if any properties need to be removed + Map<String, ValueAttributesInfo> recommendedConfigPropertyAttributes = configurations.getPropertyAttributes(); + if (recommendedConfigPropertyAttributes != null) { + for (Map.Entry<String, ValueAttributesInfo> entry : recommendedConfigPropertyAttributes.entrySet()) { + ValueAttributesInfo info = entry.getValue(); + + if ((info != null) && "true".equalsIgnoreCase(info.getDelete())) { + updates.remove(entry.getKey()); + removals.add(entry.getKey()); + } + } + } + + configHelper.updateConfigType(cluster, cluster.getCurrentStackVersion(), managementController, configType, updates, removals, "internal", + getServiceVersionNote()); + } + + protected String getServiceVersionNote() { + return "Ambari-managed configuration change"; + } + + /** + * Calculate the current configurations for all services + * + * @param cluster + * the cluster + * @return a map of services and their configurations + * @throws AmbariException + */ + private Map<String, Map<String, Map<String, String>>> calculateExistingConfigurations(Cluster cluster) throws AmbariException { + Map<String, Map<String, String>> configurationTags = configHelper.getEffectiveDesiredTags(cluster, null); + Map<String, Map<String, String>> effectiveConfigs = configHelper.getEffectiveConfigProperties(cluster, configurationTags); + + Map<String, Map<String, Map<String, String>>> requestConfigurations = new HashMap<>(); + if (effectiveConfigs != null) { + for (Map.Entry<String, Map<String, String>> configuration : effectiveConfigs.entrySet()) { + Map<String, Map<String, String>> properties = new HashMap<>(); + String configType = configuration.getKey(); + Map<String, String> configurationProperties = configuration.getValue(); + + if (configurationProperties == null) { + configurationProperties = Collections.emptyMap(); + } + + properties.put("properties", configurationProperties); + requestConfigurations.put(configType, properties); + } + } + + return requestConfigurations; + } + +} diff --git a/ambari-server/src/main/resources/scripts/stack_advisor.py b/ambari-server/src/main/resources/scripts/stack_advisor.py index b39a6e8..5ae2128 100755 --- a/ambari-server/src/main/resources/scripts/stack_advisor.py +++ b/ambari-server/src/main/resources/scripts/stack_advisor.py @@ -27,6 +27,7 @@ RECOMMEND_COMPONENT_LAYOUT_ACTION = 'recommend-component-layout' VALIDATE_COMPONENT_LAYOUT_ACTION = 'validate-component-layout' RECOMMEND_CONFIGURATIONS = 'recommend-configurations' RECOMMEND_CONFIGURATIONS_FOR_SSO = 'recommend-configurations-for-sso' +RECOMMEND_CONFIGURATIONS_FOR_LDAP = 'recommend-configurations-for-ldap' RECOMMEND_CONFIGURATIONS_FOR_KERBEROS = 'recommend-configurations-for-kerberos' RECOMMEND_CONFIGURATION_DEPENDENCIES = 'recommend-configuration-dependencies' VALIDATE_CONFIGURATIONS = 'validate-configurations' @@ -35,6 +36,7 @@ ALL_ACTIONS = [RECOMMEND_COMPONENT_LAYOUT_ACTION, VALIDATE_COMPONENT_LAYOUT_ACTION, RECOMMEND_CONFIGURATIONS, RECOMMEND_CONFIGURATIONS_FOR_SSO, + RECOMMEND_CONFIGURATIONS_FOR_LDAP, RECOMMEND_CONFIGURATIONS_FOR_KERBEROS, RECOMMEND_CONFIGURATION_DEPENDENCIES, VALIDATE_CONFIGURATIONS] @@ -125,6 +127,10 @@ def main(argv=None): services[ADVISOR_CONTEXT] = {CALL_TYPE : 'recommendConfigurationsForSSO'} result = stackAdvisor.recommendConfigurationsForSSO(services, hosts) result_file = os.path.join(actionDir, "configurations.json") + elif action == RECOMMEND_CONFIGURATIONS_FOR_LDAP: + services[ADVISOR_CONTEXT] = {CALL_TYPE : 'recommendConfigurationsForLDAP'} + result = stackAdvisor.recommendConfigurationsForLDAP(services, hosts) + result_file = os.path.join(actionDir, "configurations.json") elif action == RECOMMEND_CONFIGURATIONS_FOR_KERBEROS: services[ADVISOR_CONTEXT] = {CALL_TYPE : 'recommendConfigurationsForKerberos'} result = stackAdvisor.recommendConfigurationsForKerberos(services, hosts) diff --git a/ambari-server/src/main/resources/stacks/service_advisor.py b/ambari-server/src/main/resources/stacks/service_advisor.py index 43bbbab..e79e0dc 100644 --- a/ambari-server/src/main/resources/stacks/service_advisor.py +++ b/ambari-server/src/main/resources/stacks/service_advisor.py @@ -99,6 +99,12 @@ class ServiceAdvisor(DefaultStackAdvisor): """ pass + def getServiceConfigurationRecommendationsForLDAP(self, configurations, clusterSummary, services, hosts): + """ + Any LDAP related configuration recommendations for the service should be defined in this function. + """ + pass + def getServiceConfigurationRecommendationsForKerberos(self, configurations, clusterSummary, services, hosts): """ Any Kerberos-related configuration recommendations for the service should be defined in this function. diff --git a/ambari-server/src/main/resources/stacks/stack_advisor.py b/ambari-server/src/main/resources/stacks/stack_advisor.py index 7b53648..336ae75 100644 --- a/ambari-server/src/main/resources/stacks/stack_advisor.py +++ b/ambari-server/src/main/resources/stacks/stack_advisor.py @@ -341,6 +341,64 @@ class StackAdvisor(object): """ pass + def recommendConfigurationsForLDAP(self, services, hosts): + """ + Returns recommendation of LDAP related service configurations based on host-specific layout of components. + + This function takes as input all details about services being installed, and hosts + they are being installed into, to recommend host-specific configurations. + + @type services: dictionary + @param services: Dictionary containing all information about services and component layout selected by the user. + @type hosts: dictionary + @param hosts: Dictionary containing all information about hosts in this cluster + @rtype: dictionary + @return: Layout recommendation of service components on cluster hosts in Ambari Blueprints friendly format. + Example: { + "services": [ + "HIVE", + "TEZ", + "YARN" + ], + "recommendations": { + "blueprint": { + "host_groups": [], + "configurations": { + "yarn-site": { + "properties": { + "yarn.scheduler.minimum-allocation-mb": "682", + "yarn.scheduler.maximum-allocation-mb": "2048", + "yarn.nodemanager.resource.memory-mb": "2048" + } + }, + "tez-site": { + "properties": { + "tez.am.java.opts": "-server -Xmx546m -Djava.net.preferIPv4Stack=true -XX:+UseNUMA -XX:+UseParallelGC", + "tez.am.resource.memory.mb": "682" + } + }, + "hive-site": { + "properties": { + "hive.tez.container.size": "682", + "hive.tez.java.opts": "-server -Xmx546m -Djava.net.preferIPv4Stack=true -XX:NewRatio=8 -XX:+UseNUMA -XX:+UseParallelGC", + "hive.auto.convert.join.noconditionaltask.size": "238026752" + } + } + } + }, + "blueprint_cluster_binding": { + "host_groups": [] + } + }, + "hosts": [ + "c6401.ambari.apache.org", + "c6402.ambari.apache.org", + "c6403.ambari.apache.org" + ] + } + """ + pass + def recommendConfigurationsForKerberos(self, services, hosts): """ Returns recommendation of Kerberos-related service configurations based on host-specific layout @@ -1691,6 +1749,55 @@ class DefaultStackAdvisor(StackAdvisor): return recommendations + def recommendConfigurationsForLDAP(self, services, hosts): + self.services = services + + stackName = services["Versions"]["stack_name"] + stackVersion = services["Versions"]["stack_version"] + hostsList = [host["Hosts"]["host_name"] for host in hosts["items"]] + servicesList, componentsList = self.get_service_and_component_lists(services["services"]) + + clusterSummary = self.getConfigurationClusterSummary(servicesList, hosts, componentsList, services) + + recommendations = { + "Versions": {"stack_name": stackName, "stack_version": stackVersion}, + "hosts": hostsList, + "services": servicesList, + "recommendations": { + "blueprint": { + "configurations": {}, + "host_groups": [] + }, + "blueprint_cluster_binding": { + "host_groups": [] + } + } + } + + # If recommendation for config groups + if "config-groups" in services: + self.recommendConfigGroupsConfigurations(recommendations, services, componentsList, hosts, servicesList) + else: + configurations = recommendations["recommendations"]["blueprint"]["configurations"] + + # there can be dependencies between service recommendations which require special ordering + # for now, make sure custom services (that have service advisors) run after standard ones + serviceAdvisors = [] + recommenderDict = self.getServiceConfigurationRecommenderForSSODict() + for service in services["services"]: + serviceName = service["StackServices"]["service_name"] + calculation = recommenderDict.get(serviceName, None) + if calculation is not None: + calculation(configurations, clusterSummary, services, hosts) + else: + serviceAdvisor = self.getServiceAdvisor(serviceName) + if serviceAdvisor is not None: + serviceAdvisors.append(serviceAdvisor) + for serviceAdvisor in serviceAdvisors: + serviceAdvisor.getServiceConfigurationRecommendationsForLDAP(configurations, clusterSummary, services, hosts) + + return recommendations + def recommendConfigurationsForKerberos(self, services, hosts): self.services = services diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java index 2b3e6bb..8f85216 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java @@ -182,6 +182,11 @@ public class StackAdvisorHelperTest { } @Test + public void testCreateRecommendationCommand_returnsLDAPConfigurationRecommendationCommand() throws IOException, StackAdvisorException { + testCreateConfigurationRecommendationCommand(StackAdvisorRequestType.LDAP_CONFIGURATIONS, StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS_FOR_LDAP); + } + + @Test public void testCreateRecommendationCommand_returnsKerberosConfigurationRecommendationCommand() throws IOException, StackAdvisorException { testCreateConfigurationRecommendationCommand(StackAdvisorRequestType.KERBEROS_CONFIGURATIONS, StackAdvisorCommandType.RECOMMEND_CONFIGURATIONS_FOR_KERBEROS); } diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestTypeTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestTypeTest.java index cc0dac2..300ae00 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestTypeTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequestTypeTest.java @@ -45,6 +45,11 @@ public class StackAdvisorRequestTypeTest { } @Test + public void testFromString_returnsLDAPConfigurationsType() throws StackAdvisorException { + testFromString("ldap-configurations", StackAdvisorRequestType.LDAP_CONFIGURATIONS); + } + + @Test public void testFromString_returnsKerberosConfigurationsType() throws StackAdvisorException { testFromString("kerberos-configurations", StackAdvisorRequestType.KERBEROS_CONFIGURATIONS); } diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunnerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunnerTest.java index a4fea7c..c77c603 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunnerTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRunnerTest.java @@ -61,7 +61,6 @@ public class StackAdvisorRunnerTest { @Test(expected = StackAdvisorException.class) public void testRunScript_processStartThrowsException_returnFalse() throws Exception { - String script = "echo"; StackAdvisorCommandType saCommandType = StackAdvisorCommandType.RECOMMEND_COMPONENT_LAYOUT; File actionDirectory = temp.newFolder("actionDir"); ProcessBuilder processBuilder = createNiceMock(ProcessBuilder.class); @@ -78,7 +77,6 @@ public class StackAdvisorRunnerTest { @Test(expected = StackAdvisorRequestException.class) public void testRunScript_processExitCode1_returnFalse() throws Exception { - String script = "echo"; StackAdvisorCommandType saCommandType = StackAdvisorCommandType.RECOMMEND_COMPONENT_LAYOUT; File actionDirectory = temp.newFolder("actionDir"); ProcessBuilder processBuilder = createNiceMock(ProcessBuilder.class); @@ -97,7 +95,6 @@ public class StackAdvisorRunnerTest { @Test(expected = StackAdvisorException.class) public void testRunScript_processExitCode2_returnFalse() throws Exception { - String script = "echo"; StackAdvisorCommandType saCommandType = StackAdvisorCommandType.RECOMMEND_COMPONENT_LAYOUT; File actionDirectory = temp.newFolder("actionDir"); ProcessBuilder processBuilder = createNiceMock(ProcessBuilder.class); @@ -117,7 +114,6 @@ public class StackAdvisorRunnerTest { @Test public void testRunScript_processExitCodeZero_returnTrue() throws Exception { - String script = "echo"; StackAdvisorCommandType saCommandType = StackAdvisorCommandType.RECOMMEND_COMPONENT_LAYOUT; File actionDirectory = temp.newFolder("actionDir"); ProcessBuilder processBuilder = createNiceMock(ProcessBuilder.class); diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariServerConfigurationHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariServerConfigurationHandlerTest.java index 0a0d1a4..4c0082e 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariServerConfigurationHandlerTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariServerConfigurationHandlerTest.java @@ -70,10 +70,10 @@ public class AmbariServerConfigurationHandlerTest extends EasyMockSupport { AmbariEventPublisher publisher = createMock(AmbariEventPublisher.class); Configuration configuration = createMock(Configuration.class); - replayAll(); - AmbariServerConfigurationHandler handler = new AmbariServerConfigurationHandler(ambariConfigurationDAO, publisher, configuration); + replayAll(); + Map<String, RootServiceComponentConfiguration> allConfigurations = handler.getComponentConfigurations(null); Assert.assertEquals(2, allConfigurations.size()); Assert.assertTrue(allConfigurations.containsKey(SSO_CONFIGURATION.getCategoryName())); @@ -101,10 +101,10 @@ public class AmbariServerConfigurationHandlerTest extends EasyMockSupport { Configuration configuration = createMock(Configuration.class); - replayAll(); - AmbariServerConfigurationHandler handler = new AmbariServerConfigurationHandler(ambariConfigurationDAO, publisher, configuration); + replayAll(); + handler.removeComponentConfiguration(SSO_CONFIGURATION.getCategoryName()); handler.removeComponentConfiguration("invalid category"); @@ -129,10 +129,10 @@ public class AmbariServerConfigurationHandlerTest extends EasyMockSupport { Configuration configuration = createMock(Configuration.class); - replayAll(); - AmbariServerConfigurationHandler handler = new AmbariServerConfigurationHandler(ambariConfigurationDAO, publisher, configuration); + replayAll(); + handler.updateComponentCategory(SSO_CONFIGURATION.getCategoryName(), properties, false); handler.updateComponentCategory(SSO_CONFIGURATION.getCategoryName(), properties, true); @@ -163,10 +163,10 @@ public class AmbariServerConfigurationHandlerTest extends EasyMockSupport { AmbariEventPublisher publisher = createMock(AmbariEventPublisher.class); Configuration configuration = createMock(Configuration.class); - replayAll(); - AmbariServerConfigurationHandler handler = new AmbariServerConfigurationHandler(ambariConfigurationDAO, publisher, configuration); + replayAll(); + Map<String, Map<String, String>> allConfigurations = handler.getConfigurations(); Assert.assertEquals(2, allConfigurations.size()); Assert.assertTrue(allConfigurations.containsKey(SSO_CONFIGURATION.getCategoryName())); @@ -192,10 +192,10 @@ public class AmbariServerConfigurationHandlerTest extends EasyMockSupport { AmbariEventPublisher publisher = createMock(AmbariEventPublisher.class); Configuration configuration = createMock(Configuration.class); - replayAll(); - AmbariServerConfigurationHandler handler = new AmbariServerConfigurationHandler(ambariConfigurationDAO, publisher, configuration); + replayAll(); + Map<String, String> ssoConfigurations = handler.getConfigurationProperties(SSO_CONFIGURATION.getCategoryName()); Assert.assertEquals(2, ssoConfigurations.size()); Assert.assertTrue(ssoConfigurations.containsKey(SSO_ENABLED_SERVICES.key())); diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProviderTest.java index 17ef6ca..0576528 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RootServiceComponentConfigurationResourceProviderTest.java @@ -204,6 +204,7 @@ public class RootServiceComponentConfigurationResourceProviderTest extends EasyM expect(dao.reconcileCategory(eq(SSO_CONFIG_CATEGORY), capture(capturedProperties2), eq(true))) .andReturn(true) .once(); + expect(dao.findByCategory(LDAP_CONFIG_CATEGORY)).andReturn(Collections.emptyList()); expect(dao.findByCategory(eq(SSO_CONFIG_CATEGORY))) .andReturn(Collections.emptyList()) .once(); @@ -437,7 +438,7 @@ public class RootServiceComponentConfigurationResourceProviderTest extends EasyM expect(dao.reconcileCategory(eq(LDAP_CONFIG_CATEGORY), capture(capturedProperties1), eq(false))) .andReturn(true) .once(); - + expect(dao.findByCategory(LDAP_CONFIG_CATEGORY)).andReturn(Collections.emptyList()); publisher.publish(anyObject(AmbariConfigurationChangedEvent.class)); expectLastCall().times(1); } @@ -484,7 +485,6 @@ public class RootServiceComponentConfigurationResourceProviderTest extends EasyM propertySets.add(toRequestProperties(LDAP_CONFIG_CATEGORY, properties)); setupBasicExpectations(properties, propertySets); expect(configuration.isSecurityPasswordEncryptionEnabled()).andThrow(new AssertionFailedError()).anyTimes(); //this call should never have never been hit - replayAll(); resourceProvider.updateResources(request, predicate); verifyAll(); @@ -548,7 +548,7 @@ public class RootServiceComponentConfigurationResourceProviderTest extends EasyM private void setupBasicExpectations(Map<String, String> expectedProperties, Set<Map<String, Object>> propertySets) { expect(request.getProperties()).andReturn(propertySets).once(); expect(request.getRequestInfoProperties()).andReturn(new HashMap<>()); - expect(dao.findByCategory(LDAP_CONFIG_CATEGORY)).andReturn(createEntities(AmbariServerConfigurationCategory.LDAP_CONFIGURATION.getCategoryName(), expectedProperties)).times(2); + expect(dao.findByCategory(LDAP_CONFIG_CATEGORY)).andReturn(createEntities(AmbariServerConfigurationCategory.LDAP_CONFIGURATION.getCategoryName(), expectedProperties)).times(3); expect(factory.getInstance(RootService.AMBARI.name(), RootComponent.AMBARI_SERVER.name(), LDAP_CONFIG_CATEGORY)).andReturn(ambariServerLDAPConfigurationHandler).once(); } @@ -626,7 +626,8 @@ public class RootServiceComponentConfigurationResourceProviderTest extends EasyM bind(AmbariServerConfigurationHandler.class).toInstance(new AmbariServerConfigurationHandler(ambariConfigurationDAO, publisher, configuration)); bind(AmbariServerSSOConfigurationHandler.class).toInstance(new AmbariServerSSOConfigurationHandler(clusters, configHelper, managementController, stackAdvisorHelper, ambariConfigurationDAO, publisher, configuration)); - bind(AmbariServerLDAPConfigurationHandler.class).toInstance(new AmbariServerLDAPConfigurationHandler(ldapFacade, ambariConfigurationDAO, publisher, configuration)); + bind(AmbariServerLDAPConfigurationHandler.class).toInstance(new AmbariServerLDAPConfigurationHandler(clusters, configHelper, managementController, + stackAdvisorHelper, ambariConfigurationDAO, publisher, configuration, ldapFacade)); bind(RootServiceComponentConfigurationHandlerFactory.class).toInstance(createMock(RootServiceComponentConfigurationHandlerFactory.class)); } });