AMBARI-22325 Support for attributes in configuration (benyoka)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/f53855b0 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/f53855b0 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/f53855b0 Branch: refs/heads/branch-feature-AMBARI-14714-blueprintv2 Commit: f53855b06b0a580b93b8b2dfd4357ff34ff37291 Parents: 387b948 Author: Balazs Bence Sari <beny...@apache.org> Authored: Tue Nov 21 23:05:57 2017 +0100 Committer: Doroszlai, Attila <adorosz...@hortonworks.com> Committed: Fri Dec 8 20:24:25 2017 +0100 ---------------------------------------------------------------------- .../ambari/server/topology/Configurable.java | 40 +++++-- .../server/topology/ConfigurableTest.java | 120 +++++++++++++++++++ 2 files changed, 150 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/f53855b0/ambari-server/src/main/java/org/apache/ambari/server/topology/Configurable.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/Configurable.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/Configurable.java index af91e40..dca16e0 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/topology/Configurable.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/Configurable.java @@ -18,7 +18,6 @@ package org.apache.ambari.server.topology; -import static java.util.Collections.singletonMap; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; @@ -26,34 +25,55 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; public interface Configurable { void setConfiguration(Configuration configuration); Configuration getConfiguration(); @JsonProperty("configurations") - default void setConfigs(Collection<Map<String, Map<String, Map<String, String>>>> configs) { + default void setConfigs(Collection<Map<String, Map<String, Map<String, ? extends Object>>>> configs) { if (null != configs) { Map<String, Map<String, String>> allProps = configs.stream(). filter(map -> map != null && !map.isEmpty() && map.values().iterator().next().get(Configuration.PROPERTIES_KEY) != null). collect(toMap( config -> config.keySet().iterator().next(), - config -> config.values().iterator().next().get(Configuration.PROPERTIES_KEY) + config -> (Map<String, String>)config.values().iterator().next().get(Configuration.PROPERTIES_KEY) )); - setConfiguration(new Configuration(allProps, new HashMap<>())); + Map<String, Map<String, Map<String, String>>> allAttributes = configs.stream(). + filter(map -> map != null && !map.isEmpty() && map.values().iterator().next().get(Configuration.ATTRIBUTES_KEY) != null). + collect(toMap( + config -> config.keySet().iterator().next(), + config -> (Map<String, Map<String, String>>) + config.values().iterator().next().get(Configuration.ATTRIBUTES_KEY) + )); + setConfiguration(new Configuration(allProps, allAttributes)); } } @JsonProperty("configurations") - default Collection<Map<String, Map<String, Map<String, String>>>> getConfigs() { + default Collection<Map<String, Map<String, Map<String, ? extends Object>>>> getConfigs() { Configuration config = getConfiguration(); - return config != null - ? config.getProperties().entrySet().stream() - .map(e -> singletonMap(e.getKey(), singletonMap(Configuration.PROPERTIES_KEY, e.getValue()))) - .collect(toList()) - : Collections.emptyList(); + if (config != null) { + Set<String> keys = Sets.union(config.getProperties().keySet(), config.getAttributes().keySet()); + return keys.stream().map(key -> { + Map<String, Map<String, ? extends Object>> map = new HashMap<>(2); + if (config.getProperties().containsKey(key)) { + map.put(Configuration.PROPERTIES_KEY, config.getProperties().get(key)); + } + if (config.getAttributes().containsKey(key)) { + map.put(Configuration.ATTRIBUTES_KEY, config.getAttributes().get(key)); + } + return ImmutableMap.of(key, map); + }).collect(toList()); + } + else { + return Collections.emptyList(); + } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/f53855b0/ambari-server/src/test/java/org/apache/ambari/server/topology/ConfigurableTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/ConfigurableTest.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/ConfigurableTest.java new file mode 100644 index 0000000..2c74dc5 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/ConfigurableTest.java @@ -0,0 +1,120 @@ +package org.apache.ambari.server.topology; + +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableMap; + +public class ConfigurableTest { + public static final String CONFIG_JSON; + // TODO: This crazy initialization is needed to work around a suspected Eclipse java compiler bug. + // It will be removed once unit test compilation will have been fixed and IDE will be able to use javac. + static { + String str1 = + "[" + + " {" + + " 'hdfs-site': {" + + " 'properties': {" + + " 'dfs.block.access.token.enable': 'true'," + + " 'dfs.blocksize': '134217728'" + + " }," + + " 'properties_attributes': {" + + " 'final': {" + + " 'fs.webhdfs.enabled': 'true'," + + " 'dfs.namenode.http-address': 'true'" + + " }" + + " }" + + " }" + + " }," + + " {" + + " 'core-site': {" + + " 'properties': {" + + " 'fs.defaultFS': 'hdfs://mycluster'," + + " 'fs.trash.interval': '360'" + + " }," + + " 'properties_attributes': {" + + " 'final': {" + + " 'fs.defaultFS': 'true'" + + " }" + + " }" + + " }" + + " }" + + "]"; + String str2 = str1.replace('\'', '"'); + CONFIG_JSON = str2; + } + + private List<Map<String, Map<String, Map<String, ? extends Object>>>> rawConfig; + private Map<String, Map<String, String>> expectedProperties; + private Map<String, Map<String, Map<String, String>>>expectedAttributes; + private SimpleConfigurable configurable; + + @Before + public void setUp() throws Exception { + // TODO: Remove this check of static field initialization correctness once IDE can use javac + assertEquals(CONFIG_JSON.replace('\'', '"'), CONFIG_JSON); + + configurable = new SimpleConfigurable(); + rawConfig = new ObjectMapper().readValue(CONFIG_JSON, + new TypeReference<List<Map<String, Map<String, Map<String, ? extends Object>>>>>() {}); + + expectedProperties = ImmutableMap.of( + "hdfs-site", ImmutableMap.of( + "dfs.block.access.token.enable", "true", + "dfs.blocksize", "134217728" + ), + "core-site", ImmutableMap.of( + "fs.defaultFS", "hdfs://mycluster", + "fs.trash.interval", "360" + ) + ); + + expectedAttributes = ImmutableMap.of( + "hdfs-site", ImmutableMap.of( + "final", ImmutableMap.of( + "fs.webhdfs.enabled", "true", + "dfs.namenode.http-address", "true" + ) + ), + "core-site", ImmutableMap.of( + "final", ImmutableMap.of("fs.defaultFS", "true") + ) + ); + } + + @Test + public void setConfigs() throws Exception { + configurable.setConfigs(rawConfig); + assertEquals(expectedProperties, configurable.getConfiguration().getProperties()); + assertEquals(expectedAttributes, configurable.getConfiguration().getAttributes()); + } + + @Test + public void getConfigs() throws Exception { + Configuration conf = new Configuration(expectedProperties, expectedAttributes); + configurable.setConfiguration(conf); + assertEquals(rawConfig, configurable.getConfigs()); + } + + static class SimpleConfigurable implements Configurable { + + private Configuration configuration; + + @Override + public void setConfiguration(Configuration configuration) { + this.configuration = configuration; + } + + @Override + public Configuration getConfiguration() { + return this.configuration; + } + } +} \ No newline at end of file