Repository: ambari Updated Branches: refs/heads/branch-2.2 7228c76fb -> b1149fa7e
AMBARI-14251. Blueprints fix stale configs and kerberos-env stack defaults are not being applied during cluster deployment. (Sandor Magyari via rnettleton) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/b1149fa7 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/b1149fa7 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/b1149fa7 Branch: refs/heads/branch-2.2 Commit: b1149fa7e827c94ab929a25b9b7f9bc6165b8605 Parents: 7228c76 Author: Bob Nettleton <rnettle...@hortonworks.com> Authored: Tue Dec 8 17:51:23 2015 -0500 Committer: Bob Nettleton <rnettle...@hortonworks.com> Committed: Tue Dec 8 17:51:23 2015 -0500 ---------------------------------------------------------------------- .../controller/AmbariManagementController.java | 6 + .../AmbariManagementControllerImpl.java | 5 + .../topology/ClusterConfigurationRequest.java | 38 ++++ .../ambari/server/topology/TopologyManager.java | 24 ++- .../ClusterConfigurationRequestTest.java | 172 +++++++++++++++++++ 5 files changed, 236 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/b1149fa7/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java index ea7603f..2d11265 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java @@ -772,5 +772,11 @@ public interface AmbariManagementController { Set<StackConfigurationDependencyResponse> getStackConfigurationDependencies(Set<StackConfigurationDependencyRequest> requests) throws AmbariException; TimelineMetricCacheProvider getTimelineMetricCacheProvider(); + + /** + * Returns KerberosHelper instance + * @return + */ + KerberosHelper getKerberosHelper(); } http://git-wip-us.apache.org/repos/asf/ambari/blob/b1149fa7/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java index d0cbd20..3dae467 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java @@ -4395,6 +4395,11 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle return injector.getInstance(TimelineMetricCacheProvider.class); } + @Override + public KerberosHelper getKerberosHelper() { + return kerberosHelper; + } + /** * Queries the CredentialStoreService to gather properties about it. * <p/> http://git-wip-us.apache.org/repos/asf/ambari/blob/b1149fa7/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterConfigurationRequest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterConfigurationRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterConfigurationRequest.java index 1a650ee..6e8b8a3 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterConfigurationRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/ClusterConfigurationRequest.java @@ -26,6 +26,8 @@ import org.apache.ambari.server.controller.internal.BlueprintConfigurationProces import org.apache.ambari.server.controller.internal.ClusterResourceProvider; import org.apache.ambari.server.controller.internal.ConfigurationTopologyException; import org.apache.ambari.server.controller.internal.Stack; +import org.apache.ambari.server.serveraction.kerberos.KerberosInvalidConfigurationException; +import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.SecurityType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +35,7 @@ import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -50,6 +53,7 @@ public class ClusterConfigurationRequest { private BlueprintConfigurationProcessor configurationProcessor; private StackAdvisorBlueprintProcessor stackAdvisorBlueprintProcessor; private Stack stack; + private boolean configureSecurity = false; public ClusterConfigurationRequest(AmbariContext ambariContext, ClusterTopology clusterTopology, boolean setInitial, StackAdvisorBlueprintProcessor stackAdvisorBlueprintProcessor) { @@ -65,6 +69,11 @@ public class ClusterConfigurationRequest { } } + public ClusterConfigurationRequest(AmbariContext ambariContext, ClusterTopology topology, boolean setInitial, StackAdvisorBlueprintProcessor stackAdvisorBlueprintProcessor, boolean configureSecurity) { + this(ambariContext, topology, setInitial, stackAdvisorBlueprintProcessor); + this.configureSecurity = configureSecurity; + } + // get names of required host groups public Collection<String> getRequiredHostGroups() { return configurationProcessor.getRequiredHostGroups(); @@ -79,6 +88,11 @@ public class ClusterConfigurationRequest { if (!ConfigRecommendationStrategy.NEVER_APPLY.equals(this.clusterTopology.getConfigRecommendationStrategy())) { stackAdvisorBlueprintProcessor.adviseConfiguration(this.clusterTopology); } + + if (configureSecurity) { + configureKerberos(); + } + updatedConfigTypes = configurationProcessor.doUpdateForClusterCreate(); } catch (ConfigurationTopologyException e) { @@ -89,6 +103,30 @@ public class ClusterConfigurationRequest { setConfigurationsOnCluster(clusterTopology, TopologyManager.TOPOLOGY_RESOLVED_TAG, updatedConfigTypes); } + private void configureKerberos() throws AmbariException { + String clusterName = ambariContext.getClusterName(clusterTopology.getClusterId()); + Cluster cluster = AmbariContext.getController().getClusters().getCluster(clusterName); + Blueprint blueprint = clusterTopology.getBlueprint(); + Configuration clusterConfiguration = clusterTopology.getConfiguration(); + + try { + Map<String, Map<String, String>> updatedConfigs = AmbariContext.getController().getKerberosHelper() + .getServiceConfigurationUpdates(cluster, clusterConfiguration.getFullProperties(), + new HashSet<String>(blueprint.getServices())); + for (String configType : updatedConfigs.keySet()) { + Map<String, String> propertyMap = updatedConfigs.get(configType); + for (String property : propertyMap.keySet()) { + LOG.debug("Update Kerberos related config property: {} {} {}", configType, property, propertyMap.get + (property)); + clusterConfiguration.setProperty(configType, property, propertyMap.get(property)); + } + } + + } catch (KerberosInvalidConfigurationException e) { + LOG.error("An exception occurred while doing Kerberos related configuration update: " + e, e); + } + } + /** * Set all configurations on the cluster resource. * @param clusterTopology cluster topology http://git-wip-us.apache.org/repos/asf/ambari/blob/b1149fa7/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyManager.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyManager.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyManager.java index 960915f..4b45806 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyManager.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyManager.java @@ -18,16 +18,20 @@ package org.apache.ambari.server.topology; +import com.google.inject.Injector; import com.google.inject.Singleton; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.actionmanager.HostRoleCommand; import org.apache.ambari.server.actionmanager.Request; import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorBlueprintProcessor; +import org.apache.ambari.server.controller.ClusterRequest; +import org.apache.ambari.server.controller.KerberosHelper; import org.apache.ambari.server.controller.RequestStatusResponse; import org.apache.ambari.server.controller.internal.ArtifactResourceProvider; import org.apache.ambari.server.controller.internal.CredentialResourceProvider; import org.apache.ambari.server.controller.internal.ProvisionClusterRequest; import org.apache.ambari.server.controller.internal.RequestImpl; +import org.apache.ambari.server.controller.internal.RequestStageContainer; import org.apache.ambari.server.controller.internal.ScaleClusterRequest; import org.apache.ambari.server.controller.internal.Stack; import org.apache.ambari.server.controller.spi.NoSuchParentResourceException; @@ -40,6 +44,8 @@ import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; import org.apache.ambari.server.orm.dao.HostRoleCommandStatusSummaryDTO; import org.apache.ambari.server.orm.entities.StageEntity; import org.apache.ambari.server.security.encryption.CredentialStoreService; +import org.apache.ambari.server.serveraction.kerberos.KerberosOperationException; +import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.SecurityType; import org.apache.ambari.server.state.host.HostImpl; import org.apache.ambari.server.utils.RetryHelper; @@ -99,10 +105,6 @@ public class TopologyManager { @Inject private SecurityConfigurationFactory securityConfigurationFactory; - @Inject - private CredentialStoreService credentialStoreService; - - /** * A boolean not cached thread-local (volatile) to prevent double-checked * locking on the synchronized keyword. @@ -141,14 +143,20 @@ public class TopologyManager { // get the id prior to creating ambari resources which increments the counter Long provisionId = ambariContext.getNextRequestId(); + final Stack stack = topology.getBlueprint().getStack(); + boolean configureSecurity = false; SecurityConfiguration securityConfiguration = processSecurityConfiguration(request); if (securityConfiguration != null && securityConfiguration.getType() == SecurityType.KERBEROS) { - + configureSecurity = true; addKerberosClient(topology); + // refresh default stack config after adding KERBEROS_CLIENT component to topology + topology.getBlueprint().getConfiguration().setParentConfiguration(stack.getConfiguration(topology.getBlueprint + ().getServices())); + // create Cluster resource with security_type = KERBEROS, this will trigger cluster Kerberization // upon host install task execution - ambariContext.createAmbariResources(topology, clusterName, securityConfiguration.getType()); + ambariContext.createAmbariResources(topology, clusterName, SecurityType.KERBEROS); if (securityConfiguration.getDescriptor() != null) { submitKerberosDescriptorAsArtifact(clusterName, securityConfiguration.getDescriptor()); } @@ -177,10 +185,8 @@ public class TopologyManager { clusterTopologyMap.put(clusterId, topology); - final Stack stack = topology.getBlueprint().getStack(); - addClusterConfigRequest(topology, new ClusterConfigurationRequest( - ambariContext, topology, true, stackAdvisorBlueprintProcessor)); + ambariContext, topology, true, stackAdvisorBlueprintProcessor, configureSecurity)); LogicalRequest logicalRequest = processRequest(persistedRequest, topology, provisionId); //todo: this should be invoked as part of a generic lifecycle event which could possibly http://git-wip-us.apache.org/repos/asf/ambari/blob/b1149fa7/ambari-server/src/test/java/org/apache/ambari/server/topology/ClusterConfigurationRequestTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/ClusterConfigurationRequestTest.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/ClusterConfigurationRequestTest.java new file mode 100644 index 0000000..df32684 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/ClusterConfigurationRequestTest.java @@ -0,0 +1,172 @@ +/** + * 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.topology; + +import java.lang.reflect.Field; +import java.util.ArrayList; +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.concurrent.ExecutorService; +import java.util.concurrent.Future; + +import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorBlueprintProcessor; +import org.apache.ambari.server.controller.AmbariManagementController; +import org.apache.ambari.server.controller.ClusterRequest; +import org.apache.ambari.server.controller.ConfigurationRequest; +import org.apache.ambari.server.controller.KerberosHelper; +import org.apache.ambari.server.controller.RequestStatusResponse; +import org.apache.ambari.server.controller.internal.ProvisionClusterRequest; +import org.apache.ambari.server.controller.internal.Stack; +import org.apache.ambari.server.controller.spi.ClusterController; +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.controller.spi.ResourceProvider; +import org.apache.ambari.server.security.encryption.CredentialStoreService; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.SecurityType; +import org.easymock.Capture; +import org.easymock.EasyMock; +import org.easymock.EasyMockRule; +import org.easymock.EasyMockSupport; +import org.easymock.Mock; +import org.easymock.MockType; +import org.easymock.TestSubject; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.easymock.PowerMock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.anyString; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.eq; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.isA; +import static org.easymock.EasyMock.isNull; +import static org.easymock.EasyMock.newCapture; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reset; +import static org.easymock.EasyMock.verify; + +/** + * ClusterConfigurationRequest unit tests + */ + +@RunWith(PowerMockRunner.class) +@PrepareForTest({AmbariContext.class}) +public class ClusterConfigurationRequestTest { + + @Rule + public EasyMockRule mocks = new EasyMockRule(this); + + @Mock(type = MockType.NICE) + private Blueprint blueprint; + + @Mock(type = MockType.NICE) + private AmbariContext ambariContext; + + @Mock(type = MockType.NICE) + private Cluster cluster; + + @Mock(type = MockType.NICE) + private Clusters clusters; + + @Mock(type = MockType.NICE) + private ClusterTopology topology; + + @Mock(type = MockType.NICE) + private StackAdvisorBlueprintProcessor stackAdvisorBlueprintProcessor; + + @Mock(type = MockType.NICE) + private Stack stack; + + @Mock(type = MockType.NICE) + private AmbariManagementController controller; + + @Mock(type = MockType.NICE) + private KerberosHelper kerberosHelper; + + @Test + public void testProcessClusterConfigRequestIncludeKererosConfigs() throws Exception { + + Map<String, Map<String, String>> existingConfig = new HashMap<String, Map<String, String>>(); + Configuration stackConfig = new Configuration(existingConfig, + new HashMap<String, Map<String, Map<String, String>>>()); + + PowerMock.mockStatic(AmbariContext.class); + AmbariContext.getController(); + expectLastCall().andReturn(controller).anyTimes(); + + expect(controller.getClusters()).andReturn(clusters).anyTimes(); + expect(controller.getKerberosHelper()).andReturn(kerberosHelper).once(); + + expect(clusters.getCluster("testCluster")).andReturn(cluster).anyTimes(); + + expect(blueprint.getStack()).andReturn(stack).anyTimes(); + expect(stack.getAllConfigurationTypes(anyString())).andReturn(Collections.<String>singletonList("testConfigType") + ).anyTimes(); + expect(stack.getExcludedConfigurationTypes(anyString())).andReturn(Collections.<String>emptySet()).anyTimes(); + expect(stack.getConfigurationPropertiesWithMetadata(anyString(), anyString())).andReturn(Collections.<String, + Stack.ConfigProperty>emptyMap()).anyTimes(); + + Set<String> services = new HashSet<>(); + services.add("HDFS"); + services.add("KERBEROS"); + services.add("ZOOKEPER"); + expect(blueprint.getServices()).andReturn(services).anyTimes(); + expect(topology.getConfigRecommendationStrategy()).andReturn(ConfigRecommendationStrategy.NEVER_APPLY).anyTimes(); + expect(topology.getBlueprint()).andReturn(blueprint).anyTimes(); + expect(topology.getConfiguration()).andReturn(stackConfig).anyTimes(); + expect(topology.getHostGroupInfo()).andReturn(Collections.<String, HostGroupInfo>emptyMap()); + expect(topology.getClusterId()).andReturn(Long.valueOf(1)).anyTimes(); + expect(ambariContext.getClusterName(Long.valueOf(1))).andReturn("testCluster").anyTimes(); + expect(ambariContext.createConfigurationRequests(anyObject(Map.class))).andReturn(Collections + .<ConfigurationRequest>emptyList()).anyTimes(); + + Map<String, Map<String, String>> kerberosConfig = new HashMap<String, Map<String, String>>(); + Map<String, String> properties = new HashMap<>(); + properties.put("testPorperty", "testValue"); + kerberosConfig.put("testConfigType", properties); + expect(kerberosHelper.getServiceConfigurationUpdates(anyObject(Cluster.class), anyObject(Map.class), anyObject + (Set.class))).andReturn(kerberosConfig).anyTimes(); + + PowerMock.replay(stack, blueprint, topology, controller, clusters, kerberosHelper, ambariContext, + AmbariContext + .class); + + ClusterConfigurationRequest clusterConfigurationRequest = new ClusterConfigurationRequest( + ambariContext, topology, false, stackAdvisorBlueprintProcessor, true); + clusterConfigurationRequest.process(); + + verify(blueprint, topology, ambariContext, controller, kerberosHelper); + + } + +}