You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2017/07/24 15:26:44 UTC
[18/50] [abbrv] ambari git commit: AMBARI-21442. Ambari updates
memory settings in blueprint incorrectly (amagyar)
AMBARI-21442. Ambari updates memory settings in blueprint incorrectly (amagyar)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/93fe8487
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/93fe8487
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/93fe8487
Branch: refs/heads/branch-feature-AMBARI-12556
Commit: 93fe8487a16fd2fe4f0c6a19bdc5d8a7c7b304a7
Parents: f92d121
Author: Attila Magyar <am...@hortonworks.com>
Authored: Mon Jul 17 10:19:38 2017 +0200
Committer: Attila Magyar <am...@hortonworks.com>
Committed: Mon Jul 17 10:19:38 2017 +0200
----------------------------------------------------------------------
.../BlueprintConfigurationProcessor.java | 64 +++-----
.../server/controller/internal/Stack.java | 2 +-
.../server/controller/internal/UnitUpdater.java | 150 +++++++++++++++++++
.../validators/TopologyValidatorFactory.java | 2 +-
.../validators/UnitValidatedProperty.java | 95 ++++++++++++
.../topology/validators/UnitValidator.java | 79 ++++++++++
.../controller/internal/UnitUpdaterTest.java | 114 ++++++++++++++
.../topology/validators/UnitValidatorTest.java | 114 ++++++++++++++
8 files changed, 571 insertions(+), 49 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/93fe8487/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
index 37284be..1daf76f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java
@@ -19,6 +19,8 @@
package org.apache.ambari.server.controller.internal;
+import static java.util.stream.Collectors.groupingBy;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -48,6 +50,7 @@ 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.apache.ambari.server.topology.validators.UnitValidatedProperty;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -2041,39 +2044,6 @@ public class BlueprintConfigurationProcessor {
}
/**
- * Updater which appends "m" to the original property value.
- * For example, "1024" would be updated to "1024m".
- */
- private static class MPropertyUpdater implements PropertyUpdater {
- /**
- * Append 'm' to the original property value if it doesn't already exist.
- *
- * @param propertyName property name
- * @param origValue original value of property
- * @param properties all properties
- * @param topology cluster topology
- *
- * @return property with 'm' appended
- */
- @Override
- public String updateForClusterCreate(String propertyName,
- String origValue,
- Map<String, Map<String, String>> properties,
- ClusterTopology topology) {
-
- return origValue.endsWith("m") ? origValue : origValue + 'm';
- }
-
- @Override
- public Collection<String> getRequiredHostGroups(String propertyName,
- String origValue,
- Map<String, Map<String, String>> properties,
- ClusterTopology topology) {
- return Collections.emptySet();
- }
- }
-
- /**
* Class to facilitate special formatting needs of property values.
*/
private abstract static class AbstractPropertyValueDecorator implements PropertyUpdater {
@@ -2784,20 +2754,7 @@ public class BlueprintConfigurationProcessor {
new MultipleHostTopologyUpdater("ZOOKEEPER_SERVER"));
// Required due to AMBARI-4933. These no longer seem to be required as the default values in the stack
// are now correct but are left here in case an existing blueprint still contains an old value.
- mHadoopEnvMap.put("namenode_heapsize", new MPropertyUpdater());
- mHadoopEnvMap.put("namenode_opt_newsize", new MPropertyUpdater());
- mHadoopEnvMap.put("namenode_opt_maxnewsize", new MPropertyUpdater());
- mHadoopEnvMap.put("namenode_opt_permsize", new MPropertyUpdater());
- mHadoopEnvMap.put("namenode_opt_maxpermsize", new MPropertyUpdater());
- mHadoopEnvMap.put("dtnode_heapsize", new MPropertyUpdater());
- mapredEnvMap.put("jtnode_opt_newsize", new MPropertyUpdater());
- mapredEnvMap.put("jtnode_opt_maxnewsize", new MPropertyUpdater());
- mapredEnvMap.put("jtnode_heapsize", new MPropertyUpdater());
- hbaseEnvMap.put("hbase_master_heapsize", new MPropertyUpdater());
- hbaseEnvMap.put("hbase_regionserver_heapsize", new MPropertyUpdater());
- oozieEnvHeapSizeMap.put("oozie_heapsize", new MPropertyUpdater());
- oozieEnvHeapSizeMap.put("oozie_permsize", new MPropertyUpdater());
- zookeeperEnvMap.put("zk_server_heapsize", new MPropertyUpdater());
+ addUnitPropertyUpdaters();
hawqSiteMap.put("hawq_master_address_host", new SingleHostTopologyUpdater("HAWQMASTER"));
hawqSiteMap.put("hawq_standby_address_host", new SingleHostTopologyUpdater("HAWQSTANDBY"));
@@ -2816,6 +2773,19 @@ public class BlueprintConfigurationProcessor {
});
}
+ private static void addUnitPropertyUpdaters() {
+ Map<String, List<UnitValidatedProperty>> propsPerConfigType = UnitValidatedProperty.ALL
+ .stream()
+ .collect(groupingBy(UnitValidatedProperty::getConfigType));
+ for (String configType : propsPerConfigType.keySet()) {
+ Map<String, PropertyUpdater> unitUpdaters = new HashMap<>();
+ for (UnitValidatedProperty each : propsPerConfigType.get(configType)) {
+ unitUpdaters.put(each.getPropertyName(), new UnitUpdater(each.getServiceName(), each.getConfigType()));
+ }
+ mPropertyUpdaters.put(configType, unitUpdaters);
+ }
+ }
+
private Collection<String> setupHDFSProxyUsers(Configuration configuration, Set<String> configTypesUpdated) {
// AMBARI-5206
final Map<String , String> userProps = new HashMap<>();
http://git-wip-us.apache.org/repos/asf/ambari/blob/93fe8487/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Stack.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Stack.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Stack.java
index e1ea1cd..a28a3b5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Stack.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/Stack.java
@@ -757,7 +757,7 @@ public class Stack {
private Set<PropertyDependencyInfo> dependsOnProperties =
Collections.emptySet();
- ConfigProperty(StackConfigurationResponse config) {
+ public ConfigProperty(StackConfigurationResponse config) {
this.name = config.getPropertyName();
this.value = config.getPropertyValue();
this.attributes = config.getPropertyAttributes();
http://git-wip-us.apache.org/repos/asf/ambari/blob/93fe8487/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UnitUpdater.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UnitUpdater.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UnitUpdater.java
new file mode 100644
index 0000000..8b7cb67
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UnitUpdater.java
@@ -0,0 +1,150 @@
+/*
+ * 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 static org.apache.commons.lang.StringUtils.isBlank;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.ambari.server.topology.ClusterTopology;
+import org.apache.ambari.server.topology.validators.UnitValidatedProperty;
+
+/**
+ * I append the stack defined unit to the original property value.
+ * For example, "1024" would be updated to "1024m" if the stack unit is MB
+ * Properties with any other unit than the stack defined unit are rejected.
+ */
+public class UnitUpdater implements BlueprintConfigurationProcessor.PropertyUpdater {
+ private final String serviceName;
+ private final String configType;
+
+ public UnitUpdater(String serviceName, String configType) {
+ this.serviceName = serviceName;
+ this.configType = configType;
+ }
+
+ /**
+ * @return property value with updated unit
+ */
+ @Override
+ public String updateForClusterCreate(String propertyName,
+ String origValue,
+ Map<String, Map<String, String>> properties,
+ ClusterTopology topology) {
+ PropertyUnit stackUnit = PropertyUnit.of(topology.getBlueprint().getStack(), serviceName, configType, propertyName);
+ PropertyValue value = PropertyValue.of(propertyName, origValue);
+ if (value.hasUnit(stackUnit)) {
+ return value.toString();
+ } else if (!value.hasAnyUnit()) {
+ return value.withUnit(stackUnit);
+ } else { // should not happen because of prevalidation in UnitValidator
+ throw new IllegalArgumentException("Property " + propertyName + "=" + origValue + " has an unsupported unit. Stack supported unit is: " + stackUnit + " or no unit");
+ }
+ }
+
+ @Override
+ public Collection<String> getRequiredHostGroups(String propertyName, String origValue, Map<String, Map<String, String>> properties, ClusterTopology topology) {
+ return Collections.emptySet();
+ }
+
+ public static class PropertyUnit {
+ private static final String DEFAULT_UNIT = "m";
+ private final String unit;
+
+ public static PropertyUnit of(Stack stack, UnitValidatedProperty property) {
+ return PropertyUnit.of(stack, property.getServiceName(), property.getConfigType(), property.getPropertyName());
+ }
+
+ public static PropertyUnit of(Stack stack, String serviceName, String configType, String propertyName) {
+ return new PropertyUnit(
+ stackUnit(stack, serviceName, configType, propertyName)
+ .map(PropertyUnit::toJvmUnit)
+ .orElse(DEFAULT_UNIT));
+ }
+
+ private static Optional<String> stackUnit(Stack stack, String serviceName, String configType, String propertyName) {
+ try {
+ return Optional.ofNullable(
+ stack.getConfigurationPropertiesWithMetadata(serviceName, configType)
+ .get(propertyName)
+ .getPropertyValueAttributes()
+ .getUnit());
+ } catch (NullPointerException e) {
+ return Optional.empty();
+ }
+ }
+
+ private static String toJvmUnit(String stackUnit) {
+ switch (stackUnit.toLowerCase()) {
+ case "mb" : return "m";
+ case "gb" : return "g";
+ case "b" :
+ case "bytes" : return "";
+ default: throw new IllegalArgumentException("Unsupported stack unit: " + stackUnit);
+ }
+ }
+
+ private PropertyUnit(String unit) {
+ this.unit = unit;
+ }
+
+ @Override
+ public String toString() {
+ return unit;
+ }
+ }
+
+ public static class PropertyValue {
+ private final String value;
+
+ public static PropertyValue of(String name, String value) {
+ return new PropertyValue(normalized(name, value));
+ }
+
+ private static String normalized(String name, String value) {
+ if (isBlank(value)) {
+ throw new IllegalArgumentException("Missing property value " + name);
+ }
+ return value.trim().toLowerCase();
+ }
+
+ private PropertyValue(String value) {
+ this.value = value;
+ }
+
+ public boolean hasUnit(PropertyUnit unit) {
+ return value.endsWith(unit.toString());
+ }
+
+ public boolean hasAnyUnit() {
+ return !Character.isDigit(value.charAt(value.length() -1));
+ }
+
+ public String withUnit(PropertyUnit unit) {
+ return value + unit;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/93fe8487/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/TopologyValidatorFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/TopologyValidatorFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/TopologyValidatorFactory.java
index 5a6f64e..bc76bff 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/TopologyValidatorFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/TopologyValidatorFactory.java
@@ -25,7 +25,7 @@ public class TopologyValidatorFactory {
public TopologyValidatorFactory() {
validators = ImmutableList.of(new RequiredConfigPropertiesValidator(), new RequiredPasswordValidator(), new HiveServiceValidator(),
- new StackConfigTypeValidator());
+ new StackConfigTypeValidator(), new UnitValidator(UnitValidatedProperty.ALL));
}
public TopologyValidator createConfigurationValidatorChain() {
http://git-wip-us.apache.org/repos/asf/ambari/blob/93fe8487/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/UnitValidatedProperty.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/UnitValidatedProperty.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/UnitValidatedProperty.java
new file mode 100644
index 0000000..61f01db
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/UnitValidatedProperty.java
@@ -0,0 +1,95 @@
+/*
+ * 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.validators;
+
+import java.util.Set;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Some configuration values need to have "m" appended to them to be valid values.
+ * Required due to AMBARI-4933.
+ */
+public class UnitValidatedProperty {
+ public static final Set<UnitValidatedProperty> ALL = ImmutableSet.<UnitValidatedProperty>builder()
+ .add(new UnitValidatedProperty("HDFS", "hadoop-env", "namenode_heapsize"))
+ .add(new UnitValidatedProperty("HDFS", "hadoop-env", "namenode_opt_newsize"))
+ .add(new UnitValidatedProperty("HDFS", "hadoop-env", "namenode_opt_maxnewsize"))
+ .add(new UnitValidatedProperty("HDFS", "hadoop-env", "namenode_opt_permsize"))
+ .add(new UnitValidatedProperty("HDFS", "hadoop-env", "namenode_opt_maxpermsize"))
+ .add(new UnitValidatedProperty("HDFS", "hadoop-env", "dtnode_heapsize"))
+ .add(new UnitValidatedProperty("MAPREDUCE2", "mapred-env","jtnode_opt_newsize"))
+ .add(new UnitValidatedProperty("MAPREDUCE2", "mapred-env","jtnode_opt_maxnewsize"))
+ .add(new UnitValidatedProperty("MAPREDUCE2", "mapred-env","jtnode_heapsize"))
+ .add(new UnitValidatedProperty("HBASE", "hbase-env", "hbase_master_heapsize"))
+ .add(new UnitValidatedProperty("HBASE", "hbase-env","hbase_regionserver_heapsize"))
+ .add(new UnitValidatedProperty("OOZIE", "oozie-env","oozie_heapsize"))
+ .add(new UnitValidatedProperty("OOZIE", "oozie-env", "oozie_permsize"))
+ .add(new UnitValidatedProperty("ZOOKEEPER", "zookeeper-env", "zk_server_heapsize"))
+ .build();
+
+ private final String configType;
+ private final String serviceName;
+ private final String propertyName;
+
+ public UnitValidatedProperty(String serviceName, String configType, String propertyName) {
+ this.configType = configType;
+ this.serviceName = serviceName;
+ this.propertyName = propertyName;
+ }
+
+ public boolean hasTypeAndName(String configType, String propertyName) {
+ return configType.equals(this.getConfigType()) && propertyName.equals(this.getPropertyName());
+ }
+
+ public String getConfigType() {
+ return configType;
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UnitValidatedProperty that = (UnitValidatedProperty) o;
+ return new EqualsBuilder()
+ .append(configType, that.configType)
+ .append(serviceName, that.serviceName)
+ .append(propertyName, that.propertyName)
+ .isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(17, 37)
+ .append(configType)
+ .append(serviceName)
+ .append(propertyName)
+ .toHashCode();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/93fe8487/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/UnitValidator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/UnitValidator.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/UnitValidator.java
new file mode 100644
index 0000000..e75ffa4
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/validators/UnitValidator.java
@@ -0,0 +1,79 @@
+/*
+ * 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.validators;
+
+import static org.apache.ambari.server.controller.internal.UnitUpdater.PropertyValue;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.internal.Stack;
+import org.apache.ambari.server.controller.internal.UnitUpdater.PropertyUnit;
+import org.apache.ambari.server.topology.ClusterTopology;
+import org.apache.ambari.server.topology.HostGroupInfo;
+import org.apache.ambari.server.topology.InvalidTopologyException;
+import org.apache.ambari.server.topology.TopologyValidator;
+
+/**
+ * I validate the unit of properties by checking if it matches to the stack defined unit.
+ * Properties with different unit than the stack defined unit are rejected.
+ */
+public class UnitValidator implements TopologyValidator {
+ private final Set<UnitValidatedProperty> relevantProps;
+
+ public UnitValidator(Set<UnitValidatedProperty> propertiesToBeValidated) {
+ this.relevantProps = propertiesToBeValidated;
+ }
+
+ @Override
+ public void validate(ClusterTopology topology) throws InvalidTopologyException {
+ Stack stack = topology.getBlueprint().getStack();
+ validateConfig(topology.getConfiguration().getFullProperties(), stack);
+ for (HostGroupInfo hostGroup : topology.getHostGroupInfo().values()) {
+ validateConfig(hostGroup.getConfiguration().getFullProperties(), stack);
+ }
+ }
+
+ private void validateConfig(Map<String, Map<String, String>> configuration, Stack stack) {
+ for (Map.Entry<String, Map<String, String>> each : configuration.entrySet()) {
+ validateConfigType(each.getKey(), each.getValue(), stack);
+ }
+ }
+
+ private void validateConfigType(String configType, Map<String, String> config, Stack stack) {
+ for (String propertyName : config.keySet()) {
+ validateProperty(configType, config, propertyName, stack);
+ }
+ }
+
+ private void validateProperty(String configType, Map<String, String> config, String propertyName, Stack stack) {
+ relevantProps.stream()
+ .filter(each -> each.hasTypeAndName(configType, propertyName))
+ .findFirst()
+ .ifPresent(relevantProperty -> checkUnit(config, stack, relevantProperty));
+ }
+
+ private void checkUnit(Map<String, String> configToBeValidated, Stack stack, UnitValidatedProperty prop) {
+ PropertyUnit stackUnit = PropertyUnit.of(stack, prop);
+ PropertyValue value = PropertyValue.of(prop.getPropertyName(), configToBeValidated.get(prop.getPropertyName()));
+ if (value.hasAnyUnit() && !value.hasUnit(stackUnit)) {
+ throw new IllegalArgumentException("Property " + prop.getPropertyName() + "=" + value + " has an unsupported unit. Stack supported unit is: " + stackUnit + " or no unit");
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/93fe8487/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UnitUpdaterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UnitUpdaterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UnitUpdaterTest.java
new file mode 100644
index 0000000..6de6cd1
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/UnitUpdaterTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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 static org.easymock.EasyMock.expect;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.ambari.server.controller.StackConfigurationResponse;
+import org.apache.ambari.server.state.ValueAttributesInfo;
+import org.apache.ambari.server.topology.Blueprint;
+import org.apache.ambari.server.topology.ClusterTopology;
+import org.apache.ambari.server.topology.InvalidTopologyException;
+import org.easymock.EasyMockRule;
+import org.easymock.EasyMockSupport;
+import org.easymock.Mock;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class UnitUpdaterTest extends EasyMockSupport {
+ public static final String HEAPSIZE = "oozie_heapsize";
+ @Rule public EasyMockRule mocks = new EasyMockRule(this);
+ public static final String OOZIE = "OOZIE";
+ public static final String OOZIE_ENV = "oozie-env";
+ private Map<String, Stack.ConfigProperty> stackConfigWithMetadata = new HashMap<>();
+ private UnitUpdater unitUpdater;
+ private @Mock ClusterTopology clusterTopology;
+ private @Mock Blueprint blueprint;
+ private @Mock Stack stack;
+
+ @Test
+ public void testStackUnitIsAppendedWhereUnitIsNotDefined() throws Exception {
+ stackUnitIs(HEAPSIZE, "GB");
+ assertEquals("1g", updateUnit(OOZIE, OOZIE_ENV, HEAPSIZE, "1"));
+ }
+
+ @Test
+ public void testDefaultMbStackUnitIsAppendedWhereUnitIsNotDefined() throws Exception {
+ assertEquals("4096m", updateUnit(OOZIE, OOZIE_ENV, HEAPSIZE, "4096"));
+ }
+
+ @Test
+ public void testNoUnitIsAppendedWhenPropertyAlreadyHasTheStackUnit() throws Exception {
+ stackUnitIs(HEAPSIZE, "MB");
+ assertEquals("128m", updateUnit(OOZIE, OOZIE_ENV, HEAPSIZE, "128m"));
+ }
+
+ @Test
+ public void testNoUnitIsAppendedIfStackUnitIsInBytes() throws Exception {
+ stackUnitIs(HEAPSIZE, "Bytes");
+ assertEquals("128", updateUnit(OOZIE, OOZIE_ENV, HEAPSIZE, "128"));
+ }
+
+ @Test
+ public void testUnitSuffixIsCaseInsenitiveAndWhiteSpaceTolerant() throws Exception {
+ stackUnitIs(HEAPSIZE, "GB");
+ assertEquals("1g", updateUnit(OOZIE, OOZIE_ENV, HEAPSIZE, " 1G "));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testRejectValuesWhereStackUnitDoesNotMatchToGiveUnit() throws Exception {
+ stackUnitIs(HEAPSIZE, "MB");
+ updateUnit(OOZIE, OOZIE_ENV, HEAPSIZE, "2g");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testRejectEmptyPropertyValue() throws Exception {
+ updateUnit(OOZIE, OOZIE_ENV, HEAPSIZE, "");
+ }
+
+ private void stackUnitIs(String name, String unit) {
+ ValueAttributesInfo propertyValueAttributes = new ValueAttributesInfo();
+ propertyValueAttributes.setUnit(unit);
+ stackConfigWithMetadata.put(name, new Stack.ConfigProperty(new StackConfigurationResponse(
+ name,
+ "any",
+ "any",
+ "any",
+ "any",
+ true,
+ Collections.emptySet(),
+ Collections.emptyMap(),
+ propertyValueAttributes,
+ Collections.emptySet()
+ )));
+ }
+
+ private String updateUnit(String serviceName, String configType, String propName, String propValue) throws InvalidTopologyException, ConfigurationTopologyException {
+ UnitUpdater updater = new UnitUpdater(serviceName, configType);
+ expect(clusterTopology.getBlueprint()).andReturn(blueprint).anyTimes();
+ expect(blueprint.getStack()).andReturn(stack).anyTimes();
+ expect(stack.getConfigurationPropertiesWithMetadata(serviceName, configType)).andReturn(stackConfigWithMetadata).anyTimes();
+ replayAll();
+ return updater.updateForClusterCreate(propName, propValue, Collections.emptyMap(), clusterTopology);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/93fe8487/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/UnitValidatorTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/UnitValidatorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/UnitValidatorTest.java
new file mode 100644
index 0000000..334ee4b
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/validators/UnitValidatorTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.validators;
+
+import static com.google.common.collect.Sets.newHashSet;
+import static java.util.Collections.emptyMap;
+import static org.easymock.EasyMock.expect;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.ambari.server.controller.StackConfigurationResponse;
+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.Blueprint;
+import org.apache.ambari.server.topology.ClusterTopology;
+import org.apache.ambari.server.topology.Configuration;
+import org.apache.ambari.server.topology.InvalidTopologyException;
+import org.easymock.EasyMockRule;
+import org.easymock.EasyMockSupport;
+import org.easymock.Mock;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+
+public class UnitValidatorTest extends EasyMockSupport {
+ private static final String CONFIG_TYPE = "config-type";
+ private static final String SERVICE = "service";
+ @Rule public EasyMockRule mocks = new EasyMockRule(this);
+ private Map<String, Stack.ConfigProperty> stackConfigWithMetadata = new HashMap<>();
+ private UnitValidator validator;
+ private @Mock ClusterTopology clusterTopology;
+ private @Mock Blueprint blueprint;
+ private @Mock Stack stack;
+
+ @Test(expected = IllegalArgumentException.class)
+ public void rejectsPropertyWithDifferentUnitThanStackUnit() throws Exception {
+ stackUnitIs("property1", "MB");
+ propertyToBeValidatedIs("property1", "12G");
+ validate("property1");
+ }
+
+ @Test
+ public void acceptsPropertyWithSameUnitThanStackUnit() throws Exception {
+ stackUnitIs("property1", "MB");
+ propertyToBeValidatedIs("property1", "12m");
+ validate("property1");
+ }
+
+ @Test
+ public void skipsValidatingIrrelevantProperty() throws Exception {
+ stackUnitIs("property1", "MB");
+ propertyToBeValidatedIs("property1", "12g");
+ validate("property2");
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ expect(clusterTopology.getBlueprint()).andReturn(blueprint).anyTimes();
+ expect(clusterTopology.getHostGroupInfo()).andReturn(Collections.emptyMap()).anyTimes();
+ expect(blueprint.getStack()).andReturn(stack).anyTimes();
+ expect(stack.getConfigurationPropertiesWithMetadata(SERVICE, CONFIG_TYPE)).andReturn(stackConfigWithMetadata).anyTimes();
+ }
+
+ private void propertyToBeValidatedIs(String propertyName, String propertyValue) throws InvalidTopologyException, ConfigurationTopologyException {
+ Map<String, Map<String, String>> propertiesToBeValidated = new HashMap<String, Map<String, String>>() {{
+ put(CONFIG_TYPE, new HashMap<String, String>(){{
+ put(propertyName, propertyValue);
+ }});
+ }};
+ expect(clusterTopology.getConfiguration()).andReturn(new Configuration(propertiesToBeValidated, emptyMap())).anyTimes();
+ replayAll();
+ }
+
+ private void validate(String propertyName) throws InvalidTopologyException {
+ validator = new UnitValidator(newHashSet(new UnitValidatedProperty(SERVICE, CONFIG_TYPE, propertyName)));
+ validator.validate(clusterTopology);
+ }
+
+ private void stackUnitIs(String name, String unit) {
+ ValueAttributesInfo propertyValueAttributes = new ValueAttributesInfo();
+ propertyValueAttributes.setUnit(unit);
+ stackConfigWithMetadata.put(name, new Stack.ConfigProperty(new StackConfigurationResponse(
+ name,
+ "any",
+ "any",
+ "any",
+ "any",
+ true,
+ Collections.emptySet(),
+ Collections.emptyMap(),
+ propertyValueAttributes,
+ Collections.emptySet()
+ )));
+ }
+}
\ No newline at end of file