/*
* 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.api.services.stackadvisor;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.ambari.server.api.services.stackadvisor.recommendations.RecommendationResponse;
import org.apache.ambari.server.controller.internal.ConfigurationTopologyException;
import org.apache.ambari.server.controller.internal.Stack;
import org.apache.ambari.server.state.ValueAttributesInfo;
import org.apache.ambari.server.topology.AdvisedConfiguration;
import org.apache.ambari.server.topology.BlueprintImpl;
import org.apache.ambari.server.topology.ClusterTopology;
import org.apache.ambari.server.topology.ConfigRecommendationStrategy;
import org.apache.ambari.server.topology.Configuration;
import org.apache.ambari.server.topology.HostGroup;
import org.apache.ambari.server.topology.HostGroupInfo;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.google.common.collect.Maps;
public class StackAdvisorBlueprintProcessorTest {
private StackAdvisorBlueprintProcessor underTest = new StackAdvisorBlueprintProcessor();
private ClusterTopology clusterTopology = createMock(ClusterTopology.class);
private BlueprintImpl blueprint = createMock(BlueprintImpl.class);
private Stack stack = createMock(Stack.class);
private HostGroup hostGroup = createMock(HostGroup.class);
private Configuration configuration = createMock(Configuration.class);
private static StackAdvisorHelper stackAdvisorHelper = createMock(StackAdvisorHelper.class);
@BeforeClass
public static void initClass() {
StackAdvisorBlueprintProcessor.init(stackAdvisorHelper);
}
@Before
public void setUp() {
reset(clusterTopology, blueprint, stack, stackAdvisorHelper);
}
@Test
public void testAdviseConfiguration() throws StackAdvisorException, ConfigurationTopologyException {
// GIVEN
Map<String, Map<String, String>> props = createProps();
Map<String, AdvisedConfiguration> advisedConfigurations = new HashMap<>();
expect(clusterTopology.getBlueprint()).andReturn(blueprint).anyTimes();
expect(clusterTopology.getHostGroupInfo()).andReturn(createHostGroupInfo()).anyTimes();
expect(clusterTopology.getAdvisedConfigurations()).andReturn(advisedConfigurations).anyTimes();
expect(clusterTopology.getConfiguration()).andReturn(configuration).anyTimes();
expect(clusterTopology.isClusterKerberosEnabled()).andReturn(false).anyTimes();
expect(clusterTopology.getConfigRecommendationStrategy()).andReturn(ConfigRecommendationStrategy.ALWAYS_APPLY).anyTimes();
expect(blueprint.getStack()).andReturn(stack).anyTimes();
expect(stack.getVersion()).andReturn("2.3").anyTimes();
expect(stack.getName()).andReturn("HDP").anyTimes();
expect(stack.getConfiguration(Arrays.asList("HDFS", "YARN", "HIVE"))).andReturn(createStackDefaults()).anyTimes();
expect(blueprint.getServices()).andReturn(Arrays.asList("HDFS", "YARN", "HIVE")).anyTimes();
expect(blueprint.getHostGroups()).andReturn(createHostGroupMap()).anyTimes();
expect(blueprint.isValidConfigType("core-site")).andReturn(true).anyTimes();
expect(hostGroup.getComponentNames()).andReturn(Arrays.asList("comp1", "comp2")).anyTimes();
expect(stackAdvisorHelper.recommend(anyObject(StackAdvisorRequest.class))).andReturn(createRecommendationResponse());
expect(configuration.getFullProperties()).andReturn(props).anyTimes();
replay(clusterTopology, blueprint, stack, hostGroup, configuration, stackAdvisorHelper);
// WHEN
underTest.adviseConfiguration(clusterTopology, props);
// THEN
assertTrue(advisedConfigurations.get("core-site").getProperties().containsKey("dummyKey1"));
assertTrue(advisedConfigurations.get("core-site").getProperties().containsKey("dummyKey3"));
assertTrue(advisedConfigurations.get("core-site").getPropertyValueAttributes().containsKey("dummyKey2"));
assertTrue(advisedConfigurations.get("core-site").getPropertyValueAttributes().containsKey("dummyKey3"));
assertEquals("dummyValue", advisedConfigurations.get("core-site").getProperties().get("dummyKey1"));
assertEquals(Boolean.toString(true), advisedConfigurations.get("core-site")
.getPropertyValueAttributes().get("dummyKey2").getDelete());
}
@Test
public void testAdviseConfigurationWithOnlyStackDefaultsApply() throws StackAdvisorException, ConfigurationTopologyException {
// GIVEN
Map<String, Map<String, String>> props = createProps();
Map<String, AdvisedConfiguration> advisedConfigurations = new HashMap<>();
expect(clusterTopology.getBlueprint()).andReturn(blueprint).anyTimes();
expect(clusterTopology.getHostGroupInfo()).andReturn(createHostGroupInfo()).anyTimes();
expect(clusterTopology.getAdvisedConfigurations()).andReturn(advisedConfigurations).anyTimes();
expect(clusterTopology.getConfiguration()).andReturn(configuration).anyTimes();
expect(clusterTopology.isClusterKerberosEnabled()).andReturn(false).anyTimes();
expect(clusterTopology.getConfigRecommendationStrategy()).andReturn(ConfigRecommendationStrategy.ONLY_STACK_DEFAULTS_APPLY);
expect(blueprint.getStack()).andReturn(stack).anyTimes();
expect(stack.getVersion()).andReturn("2.3").anyTimes();
expect(stack.getName()).andReturn("HDP").anyTimes();
expect(stack.getConfiguration(Arrays.asList("HDFS", "YARN", "HIVE"))).andReturn(createStackDefaults()).anyTimes();
expect(blueprint.getServices()).andReturn(Arrays.asList("HDFS", "YARN", "HIVE")).anyTimes();
expect(blueprint.getHostGroups()).andReturn(createHostGroupMap()).anyTimes();
expect(blueprint.isValidConfigType("core-site")).andReturn(true).anyTimes();
expect(hostGroup.getComponentNames()).andReturn(Arrays.asList("comp1", "comp2")).anyTimes();
expect(stackAdvisorHelper.recommend(anyObject(StackAdvisorRequest.class))).andReturn(createRecommendationResponse());
expect(configuration.getFullProperties()).andReturn(props).anyTimes();
replay(clusterTopology, blueprint, stack, hostGroup, configuration, stackAdvisorHelper);
// WHEN
underTest.adviseConfiguration(clusterTopology, props);
// THEN
assertTrue(advisedConfigurations.get("core-site").getProperties().containsKey("dummyKey1"));
assertFalse(advisedConfigurations.get("core-site").getProperties().containsKey("dummyKey3"));
assertTrue(advisedConfigurations.get("core-site").getPropertyValueAttributes().containsKey("dummyKey2"));
assertFalse(advisedConfigurations.get("core-site").getPropertyValueAttributes().containsKey("dummyKey3"));
assertEquals("dummyValue", advisedConfigurations.get("core-site").getProperties().get("dummyKey1"));
assertEquals(Boolean.toString(true), advisedConfigurations.get("core-site")
.getPropertyValueAttributes().get("dummyKey2").getDelete());
}
@Test
public void testAdviseConfigurationWithOnlyStackDefaultsApplyWhenNoUserInputForDefault() throws StackAdvisorException, ConfigurationTopologyException {
// GIVEN
Map<String, Map<String, String>> props = createProps();
props.get("core-site").put("dummyKey3", "stackDefaultValue");
Map<String, AdvisedConfiguration> advisedConfigurations = new HashMap<>();
expect(clusterTopology.getBlueprint()).andReturn(blueprint).anyTimes();
expect(clusterTopology.getHostGroupInfo()).andReturn(createHostGroupInfo()).anyTimes();
expect(clusterTopology.getAdvisedConfigurations()).andReturn(advisedConfigurations).anyTimes();
expect(clusterTopology.getConfiguration()).andReturn(configuration).anyTimes();
expect(clusterTopology.isClusterKerberosEnabled()).andReturn(false).anyTimes();
expect(clusterTopology.getConfigRecommendationStrategy()).andReturn(ConfigRecommendationStrategy.ONLY_STACK_DEFAULTS_APPLY);
expect(blueprint.getStack()).andReturn(stack).anyTimes();
expect(stack.getVersion()).andReturn("2.3").anyTimes();
expect(stack.getName()).andReturn("HDP").anyTimes();
expect(stack.getConfiguration(Arrays.asList("HDFS", "YARN", "HIVE"))).andReturn(createStackDefaults()).anyTimes();
expect(blueprint.getServices()).andReturn(Arrays.asList("HDFS", "YARN", "HIVE")).anyTimes();
expect(blueprint.getHostGroups()).andReturn(createHostGroupMap()).anyTimes();
expect(blueprint.isValidConfigType("core-site")).andReturn(true).anyTimes();
expect(hostGroup.getComponentNames()).andReturn(Arrays.asList("comp1", "comp2")).anyTimes();
expect(stackAdvisorHelper.recommend(anyObject(StackAdvisorRequest.class))).andReturn(createRecommendationResponse());
expect(configuration.getFullProperties()).andReturn(props).anyTimes();
replay(clusterTopology, blueprint, stack, hostGroup, configuration, stackAdvisorHelper);
// WHEN
underTest.adviseConfiguration(clusterTopology, props);
// THEN
assertTrue(advisedConfigurations.get("core-site").getProperties().containsKey("dummyKey1"));
assertTrue(advisedConfigurations.get("core-site").getPropertyValueAttributes().containsKey("dummyKey2"));
assertEquals("dummyValue", advisedConfigurations.get("core-site").getProperties().get("dummyKey1"));
assertEquals(Boolean.toString(true), advisedConfigurations.get("core-site")
.getPropertyValueAttributes().get("dummyKey2").getDelete());
}
@Test
public void testAdviseConfigurationWith_ALWAYS_APPLY_DONT_OVERRIDE_CUSTOM_VALUES() throws StackAdvisorException,
ConfigurationTopologyException {
// GIVEN
Map<String, Map<String, String>> props = createProps();
Map<String, AdvisedConfiguration> advisedConfigurations = new HashMap<>();
expect(clusterTopology.getBlueprint()).andReturn(blueprint).anyTimes();
expect(clusterTopology.getHostGroupInfo()).andReturn(createHostGroupInfo()).anyTimes();
expect(clusterTopology.getAdvisedConfigurations()).andReturn(advisedConfigurations).anyTimes();
expect(clusterTopology.getConfiguration()).andReturn(configuration).anyTimes();
expect(clusterTopology.isClusterKerberosEnabled()).andReturn(false).anyTimes();
expect(clusterTopology.getConfigRecommendationStrategy()).andReturn(ConfigRecommendationStrategy.ALWAYS_APPLY_DONT_OVERRIDE_CUSTOM_VALUES).anyTimes();
expect(blueprint.getStack()).andReturn(stack).anyTimes();
expect(stack.getVersion()).andReturn("2.3").anyTimes();
expect(stack.getName()).andReturn("HDP").anyTimes();
expect(stack.getConfiguration(Arrays.asList("HDFS", "YARN", "HIVE"))).andReturn(createStackDefaults()).anyTimes();
expect(blueprint.getServices()).andReturn(Arrays.asList("HDFS", "YARN", "HIVE")).anyTimes();
expect(blueprint.getHostGroups()).andReturn(createHostGroupMap()).anyTimes();
expect(blueprint.isValidConfigType("core-site")).andReturn(true).anyTimes();
expect(hostGroup.getComponentNames()).andReturn(Arrays.asList("comp1", "comp2")).anyTimes();
expect(stackAdvisorHelper.recommend(anyObject(StackAdvisorRequest.class))).andReturn(createRecommendationResponse());
expect(configuration.getFullProperties()).andReturn(props).anyTimes();
replay(clusterTopology, blueprint, stack, hostGroup, configuration, stackAdvisorHelper);
// WHEN
underTest.adviseConfiguration(clusterTopology, props);
// THEN
assertTrue(advisedConfigurations.get("core-site").getProperties().containsKey("dummyKey1"));
assertTrue(advisedConfigurations.get("core-site").getPropertyValueAttributes().containsKey("dummyKey2"));
assertEquals("dummyValue", advisedConfigurations.get("core-site").getProperties().get("dummyKey1"));
assertEquals(Boolean.toString(true), advisedConfigurations.get("core-site")
.getPropertyValueAttributes().get("dummyKey2").getDelete());
}
@Test
public void testAdviseConfigurationWhenConfigurationRecommendFails() throws StackAdvisorException, ConfigurationTopologyException {
// GIVEN
Map<String, Map<String, String>> props = createProps();
Map<String, AdvisedConfiguration> advisedConfigurations = new HashMap<>();
expect(clusterTopology.getBlueprint()).andReturn(blueprint).anyTimes();
expect(clusterTopology.getHostGroupInfo()).andReturn(createHostGroupInfo()).anyTimes();
expect(clusterTopology.getAdvisedConfigurations()).andReturn(advisedConfigurations).anyTimes();
expect(clusterTopology.getConfiguration()).andReturn(configuration).anyTimes();
expect(clusterTopology.isClusterKerberosEnabled()).andReturn(false).anyTimes();
expect(blueprint.getStack()).andReturn(stack).anyTimes();
expect(stack.getVersion()).andReturn("2.3").anyTimes();
expect(stack.getName()).andReturn("HDP").anyTimes();
expect(blueprint.getHostGroups()).andReturn(createHostGroupMap()).anyTimes();
expect(hostGroup.getComponentNames()).andReturn(Arrays.asList("comp1", "comp2")).anyTimes();
expect(blueprint.getServices()).andReturn(Arrays.asList("HDFS", "YARN", "HIVE")).anyTimes();
expect(stackAdvisorHelper.recommend(anyObject(StackAdvisorRequest.class))).andThrow(new StackAdvisorException("ex"));
expect(configuration.getFullProperties()).andReturn(props);
replay(clusterTopology, blueprint, stack, hostGroup, configuration, stackAdvisorHelper);
// WHEN
try {
underTest.adviseConfiguration(clusterTopology, props);
fail("Invalid state");
} catch (ConfigurationTopologyException e) {
assertEquals(StackAdvisorBlueprintProcessor.RECOMMENDATION_FAILED, e.getMessage());
}
}
@Test
public void testAdviseConfigurationWhenConfigurationRecommendHasInvalidResponse() throws StackAdvisorException, ConfigurationTopologyException {
// GIVEN
Map<String, Map<String, String>> props = createProps();
Map<String, AdvisedConfiguration> advisedConfigurations = new HashMap<>();
expect(clusterTopology.getBlueprint()).andReturn(blueprint).anyTimes();
expect(clusterTopology.getHostGroupInfo()).andReturn(createHostGroupInfo()).anyTimes();
expect(clusterTopology.getAdvisedConfigurations()).andReturn(advisedConfigurations).anyTimes();
expect(clusterTopology.getConfiguration()).andReturn(configuration).anyTimes();
expect(clusterTopology.isClusterKerberosEnabled()).andReturn(false).anyTimes();
expect(blueprint.getStack()).andReturn(stack).anyTimes();
expect(stack.getVersion()).andReturn("2.3").anyTimes();
expect(stack.getName()).andReturn("HDP").anyTimes();
expect(blueprint.getServices()).andReturn(Arrays.asList("HDFS", "YARN", "HIVE")).anyTimes();
expect(blueprint.getHostGroups()).andReturn(createHostGroupMap()).anyTimes();
expect(hostGroup.getComponentNames()).andReturn(Arrays.asList("comp1", "comp2")).anyTimes();
expect(stackAdvisorHelper.recommend(anyObject(StackAdvisorRequest.class))).andReturn(new RecommendationResponse());
expect(configuration.getFullProperties()).andReturn(props);
replay(clusterTopology, blueprint, stack, hostGroup, configuration, stackAdvisorHelper);
// WHEN
try {
underTest.adviseConfiguration(clusterTopology, props);
fail("Invalid state");
} catch (ConfigurationTopologyException e) {
assertEquals(StackAdvisorBlueprintProcessor.INVALID_RESPONSE, e.getMessage());
}
}
private Map<String, Map<String, String>> createProps() {
Map<String, Map<String, String>> props = Maps.newHashMap();
Map<String, String> siteProps = Maps.newHashMap();
siteProps.put("myprop", "myvalue");
siteProps.put("dummyKey3", "userinput");
props.put("core-site", siteProps);
return props;
}
private Map<String, HostGroup> createHostGroupMap() {
Map<String, HostGroup> hgMap = Maps.newHashMap();
hgMap.put("hg1", hostGroup);
hgMap.put("hg2", hostGroup);
hgMap.put("hg3", hostGroup);
return hgMap;
}
private Map<String, HostGroupInfo> createHostGroupInfo() {
Map<String, HostGroupInfo> hostGroupInfoMap = new HashMap<>();
HostGroupInfo hgi1 = new HostGroupInfo("hostGroup1");
HostGroupInfo hgi2 = new HostGroupInfo("hostGroup2");
hostGroupInfoMap.put("hg1", hgi1);
hostGroupInfoMap.put("hg2", hgi2);
return hostGroupInfoMap;
}
private Configuration createStackDefaults() {
Map<String, Map<String, String>> stackDefaultProps =
new HashMap<>();
Map<String, String> coreSiteDefault = new HashMap<>();
coreSiteDefault.put("dummyKey3", "stackDefaultValue");
stackDefaultProps.put("core-site", coreSiteDefault);
Map<String, Map<String, Map<String, String>>> stackDefaultAttributes =
new HashMap<>();
return new Configuration(stackDefaultProps, stackDefaultAttributes);
}
private RecommendationResponse createRecommendationResponse() {
RecommendationResponse response = new RecommendationResponse();
RecommendationResponse.Recommendation recommendations = new RecommendationResponse.Recommendation();
RecommendationResponse.Blueprint blueprint = new RecommendationResponse.Blueprint();
Map<String, RecommendationResponse.BlueprintConfigurations> blueprintConfigurationsMap =
new HashMap<>();
RecommendationResponse.BlueprintConfigurations blueprintConfig =
new RecommendationResponse.BlueprintConfigurations();
Map<String, String> properties = new HashMap<>();
properties.put("dummyKey1", "dummyValue");
properties.put("dummyKey3", "dummyValue-override");
blueprintConfig.setProperties(properties);
Map<String, ValueAttributesInfo> propAttributes = new HashMap<>();
ValueAttributesInfo valueAttributesInfo1 = new ValueAttributesInfo();
ValueAttributesInfo valueAttributesInfo2 = new ValueAttributesInfo();
valueAttributesInfo1.setDelete("true");
valueAttributesInfo2.setDelete("true");
propAttributes.put("dummyKey2", valueAttributesInfo1);
propAttributes.put("dummyKey3", valueAttributesInfo2);
blueprintConfig.setPropertyAttributes(propAttributes);
blueprintConfigurationsMap.put("core-site", blueprintConfig);
blueprint.setConfigurations(blueprintConfigurationsMap);
recommendations.setBlueprint(blueprint);
response.setRecommendations(recommendations);
return response;
}
}