Repository: ambari Updated Branches: refs/heads/branch-2.5 e615beb8e -> afeb6f3a3
AMBARI-20877.Custom RM principal causes zookeeper HA state store to be inaccessible. (Attila Magyar via stoader) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/afeb6f3a Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/afeb6f3a Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/afeb6f3a Branch: refs/heads/branch-2.5 Commit: afeb6f3a3402652db5dbda2c598c77b74ef0988e Parents: e615beb Author: Attila Magyar <amag...@hortonworks.com> Authored: Thu Jun 8 15:41:37 2017 +0200 Committer: Toader, Sebastian <stoa...@hortonworks.com> Committed: Thu Jun 8 15:41:37 2017 +0200 ---------------------------------------------------------------------- .../security/kerberos/kerberos_descriptor.md | 5 +- .../server/controller/KerberosHelperImpl.java | 19 +++-- .../state/kerberos/KerberosDescriptor.java | 51 ++++++++++++++ .../kerberos/VariableReplacementHelper.java | 23 +++++- .../stacks/HDP/2.6/services/YARN/kerberos.json | 4 +- .../server/controller/KerberosHelperTest.java | 43 ++++++------ .../state/kerberos/KerberosDescriptorTest.java | 9 +++ .../kerberos/VariableReplacementHelperTest.java | 73 ++++++++++++-------- 8 files changed, 169 insertions(+), 58 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/afeb6f3a/ambari-server/docs/security/kerberos/kerberos_descriptor.md ---------------------------------------------------------------------- diff --git a/ambari-server/docs/security/kerberos/kerberos_descriptor.md b/ambari-server/docs/security/kerberos/kerberos_descriptor.md index 54af50f..a59564c 100644 --- a/ambari-server/docs/security/kerberos/kerberos_descriptor.md +++ b/ambari-server/docs/security/kerberos/kerberos_descriptor.md @@ -288,8 +288,9 @@ the configuration type and containing values for each relevant property. Each property name and value may be a concrete value or contain variables to be replaced using values from the stack-level `properties` block or any available configuration. Properties from the `properties` -block are referenced by name (`${property_name}`) and configuration properties are reference by -configuration specification (`${config-type/property_name}`). +block are referenced by name (`${property_name}`), configuration properties are reference by +configuration specification (`${config-type/property_name}`) and kerberos principals are referenced by the principal path +(`principals/SERVICE/COMPONENT/principal_name`). ``` "configurations" : [ http://git-wip-us.apache.org/repos/asf/ambari/blob/afeb6f3a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java index 846bc3d..802c93d 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java @@ -1276,10 +1276,21 @@ public class KerberosHelperImpl implements KerberosHelper { @Override public Map<String, Map<String, String>> calculateConfigurations(Cluster cluster, String hostname, Map<String, String> kerberosDescriptorProperties) - throws AmbariException { - return addAdditionalConfigurations(cluster, - calculateExistingConfigurations(cluster, hostname), - hostname, kerberosDescriptorProperties); + throws AmbariException + { + Map<String, Map<String, String>> configuration = addAdditionalConfigurations(cluster, + calculateExistingConfigurations(cluster, hostname), + hostname, kerberosDescriptorProperties); + configuration.put("principals", principalNames(cluster, configuration)); + return configuration; + } + + private Map<String, String> principalNames(Cluster cluster, Map<String, Map<String, String>> configuration) throws AmbariException { + Map<String, String> result = new HashMap<>(); + for (Map.Entry<String, String> each : getKerberosDescriptor(cluster).principals().entrySet()) { + result.put(each.getKey(), variableReplacementHelper.replaceVariables(each.getValue(), configuration)); + } + return result; } @Override http://git-wip-us.apache.org/repos/asf/ambari/blob/afeb6f3a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java index e7be589..86a5e01 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java @@ -20,12 +20,16 @@ package org.apache.ambari.server.state.kerberos; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.TreeMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.ambari.server.AmbariException; +import org.apache.commons.lang.StringUtils; + /** * KerberosDescriptor is an implementation of an AbstractKerberosDescriptorContainer that * encapsulates an entire Kerberos descriptor hierarchy. @@ -418,4 +422,51 @@ public class KerberosDescriptor extends AbstractKerberosDescriptorContainer { return authToLocalProperties; } + + /** + * Get a map of principals, where the key is the principal path (SERVICE/COMPONENT/principal_name or SERVICE/principal_name) and the value is the principal. + * + * For example if the kerberos principal of the HISTORYSERVER is defined in the kerberos.json: + * "name": "history_server_jhs", + * "principal": { + * "value": "jhs/_HOST@${realm}", + * "type" : "service", + * }, + * Then "jhs/_h...@example.com" will be put into the map under the "MAPREDUCE2/HISTORYSERVER/history_server_jhs" key. + */ + public Map<String, String> principals() throws AmbariException { + Map<String,String> result = new HashMap<>(); + for (AbstractKerberosDescriptorContainer each : nullToEmpty(getChildContainers())) { + if ((each instanceof KerberosServiceDescriptor)) { + collectFromComponents(each.getName(), nullToEmpty(((KerberosServiceDescriptor) each).getComponents()).values(), result); + collectFromIdentities(each.getName(), "", nullToEmpty(each.getIdentities()), result); + } + } + return result; + } + + private static void collectFromComponents(String service, Collection<KerberosComponentDescriptor> components, Map<String, String> result) { + for (KerberosComponentDescriptor each : components) { + collectFromIdentities(service, each.getName(), nullToEmpty(each.getIdentities()), result); + } + } + + private static void collectFromIdentities(String service, String component, Collection<KerberosIdentityDescriptor> identities, Map<String, String> result) { + for (KerberosIdentityDescriptor each : identities) { + if (each.getPrincipalDescriptor() != null && !each.getReferencedServiceName().isPresent() && !each.getName().startsWith("/")) { + String path = StringUtils.isBlank(component) + ? String.format("%s/%s", service, each.getName()) + : String.format("%s/%s/%s", service, component, each.getName()); + result.put(path, each.getPrincipalDescriptor().getName()); + } + } + } + + private static <T> Collection<T> nullToEmpty(Collection<T> collection) { + return collection == null ? Collections.<T>emptyList() : collection; + } + + private static <K,V> Map<K,V> nullToEmpty(Map<K,V> collection) { + return collection == null ? Collections.<K,V>emptyMap() : collection; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/afeb6f3a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelper.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelper.java index 77333b8..0dd551c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelper.java @@ -42,7 +42,7 @@ public class VariableReplacementHelper { /** * a regular expression Pattern used to find "variable" placeholders in strings */ - private static final Pattern PATTERN_VARIABLE = Pattern.compile("\\$\\{(?:([\\w\\-\\.]+)/)?([\\w\\-\\.]+)(?:\\s*\\|\\s*(.+?))?\\}"); + private static final Pattern PATTERN_VARIABLE = Pattern.compile("\\$\\{(?:([\\w\\-\\.]+)/)?([\\w\\-\\./]+)(?:\\s*\\|\\s*(.+?))?\\}"); /** * a regular expression Pattern used to parse "function" declarations: name(arg1, arg2, ...) @@ -57,6 +57,7 @@ public class VariableReplacementHelper { put("each", new EachFunction()); put("toLower", new ToLowerFunction()); put("append", new AppendFunction()); + put("principalPrimary", new PrincipalPrimary()); } }; @@ -377,4 +378,24 @@ public class VariableReplacementHelper { return sourceData; } } + + /** + * Get the primary part of a Kerberos principal. + * The format of a typical Kerberos principal is primary/instance@REALM. + */ + private static class PrincipalPrimary implements Function { + @Override + public String perform(String[] args, String data, Map<String, Map<String, String>> replacementsMap) { + if (data == null) { + return null; + } + if (data.contains("/")) { + return data.split("/")[0]; + } else if (data.contains("@")) { + return data.split("@")[0]; + } else { + return data; + } + } + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/afeb6f3a/ambari-server/src/main/resources/stacks/HDP/2.6/services/YARN/kerberos.json ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/HDP/2.6/services/YARN/kerberos.json b/ambari-server/src/main/resources/stacks/HDP/2.6/services/YARN/kerberos.json index ae4db4f..b1501b8 100644 --- a/ambari-server/src/main/resources/stacks/HDP/2.6/services/YARN/kerberos.json +++ b/ambari-server/src/main/resources/stacks/HDP/2.6/services/YARN/kerberos.json @@ -32,9 +32,9 @@ "yarn.resourcemanager.proxyuser.*.hosts": "", "yarn.resourcemanager.proxyuser.*.users": "", "yarn.resourcemanager.proxy-user-privileges.enabled": "true", - "yarn.resourcemanager.zk-acl" : "sasl:rm:rwcda", + "yarn.resourcemanager.zk-acl" : "sasl:${principals/YARN/RESOURCEMANAGER/resource_manager_rm|principalPrimary()}:rwcda", "hadoop.registry.secure" : "true", - "hadoop.registry.system.accounts" : "sasl:yarn,sasl:mapred,sasl:hadoop,sasl:hdfs,sasl:rm,sasl:hive", + "hadoop.registry.system.accounts" : "sasl:${principals/YARN/APP_TIMELINE_SERVER/app_timeline_server_yarn|principalPrimary()},sasl:${principals/MAPREDUCE2/HISTORYSERVER/history_server_jhs|principalPrimary()},sasl:${principals/HDFS/NAMENODE/hdfs|principalPrimary()},sasl:${principals/YARN/RESOURCEMANAGER/resource_manager_rm|principalPrimary()},sasl:${principals/HIVE/HIVE_SERVER/hive_server_hive|principalPrimary()}", "hadoop.registry.client.auth" : "kerberos", "hadoop.registry.jaas.context" : "Client" } http://git-wip-us.apache.org/repos/asf/ambari/blob/afeb6f3a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java index 2162e76..9b9f087 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java @@ -1009,27 +1009,27 @@ public class KerberosHelperTest extends EasyMockSupport { expect(serviceComponentKerberosClient.getName()).andReturn(Role.KERBEROS_CLIENT.name()).anyTimes(); expect(serviceComponentKerberosClient.getServiceComponentHosts()).andReturn(Collections.singletonMap("host1", schKerberosClient)).anyTimes(); - final Service serviceKerberos = createStrictMock(Service.class); + final Service serviceKerberos = createNiceMock(Service.class); expect(serviceKerberos.getName()).andReturn(Service.Type.KERBEROS.name()).anyTimes(); expect(serviceKerberos.getServiceComponents()) .andReturn(Collections.singletonMap(Role.KERBEROS_CLIENT.name(), serviceComponentKerberosClient)) - .times(1); + .anyTimes(); serviceKerberos.setSecurityState(SecurityState.SECURED_KERBEROS); expectLastCall().once(); - final Service service1 = createStrictMock(Service.class); + final Service service1 = createNiceMock(Service.class); expect(service1.getName()).andReturn("SERVICE1").anyTimes(); expect(service1.getServiceComponents()) .andReturn(Collections.<String, ServiceComponent>emptyMap()) - .times(1); + .anyTimes(); service1.setSecurityState(SecurityState.SECURED_KERBEROS); expectLastCall().once(); - final Service service2 = createStrictMock(Service.class); + final Service service2 = createNiceMock(Service.class); expect(service2.getName()).andReturn("SERVICE2").anyTimes(); expect(service2.getServiceComponents()) .andReturn(Collections.<String, ServiceComponent>emptyMap()) - .times(1); + .anyTimes(); service2.setSecurityState(SecurityState.SECURED_KERBEROS); expectLastCall().once(); @@ -1094,7 +1094,7 @@ public class KerberosHelperTest extends EasyMockSupport { expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).once(); expect(kerberosDescriptor.getService("SERVICE2")).andReturn(serviceDescriptor2).once(); - setupKerberosDescriptor(kerberosDescriptor, 1); + setupKerberosDescriptor(kerberosDescriptor); setupStageFactory(); // This is a STRICT mock to help ensure that the end result is what we want. @@ -1301,7 +1301,7 @@ public class KerberosHelperTest extends EasyMockSupport { expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).once(); expect(kerberosDescriptor.getService("SERVICE2")).andReturn(serviceDescriptor2).once(); - setupKerberosDescriptor(kerberosDescriptor, 1); + setupKerberosDescriptor(kerberosDescriptor); setupStageFactory(); // This is a STRICT mock to help ensure that the end result is what we want. @@ -1499,7 +1499,7 @@ public class KerberosHelperTest extends EasyMockSupport { expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).atLeastOnce(); expect(kerberosDescriptor.getService("SERVICE2")).andReturn(serviceDescriptor2).atLeastOnce(); - setupKerberosDescriptor(kerberosDescriptor, 1); + setupKerberosDescriptor(kerberosDescriptor); setupStageFactory(); // This is a STRICT mock to help ensure that the end result is what we want. @@ -1646,7 +1646,7 @@ public class KerberosHelperTest extends EasyMockSupport { expect(serviceKerberos.getName()).andReturn(Service.Type.KERBEROS.name()).anyTimes(); expect(serviceKerberos.getServiceComponents()) .andReturn(Collections.singletonMap(Role.KERBEROS_CLIENT.name(), serviceComponentKerberosClient)) - .times(1); + .anyTimes(); final Service service1 = createStrictMock(Service.class); expect(service1.getName()).andReturn("SERVICE1").anyTimes(); @@ -1722,7 +1722,7 @@ public class KerberosHelperTest extends EasyMockSupport { expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).atLeastOnce(); expect(kerberosDescriptor.getService("SERVICE2")).andReturn(serviceDescriptor2).atLeastOnce(); - setupKerberosDescriptor(kerberosDescriptor, 1); + setupKerberosDescriptor(kerberosDescriptor); setupStageFactory(); final RequestStageContainer requestStageContainer; @@ -2263,7 +2263,7 @@ public class KerberosHelperTest extends EasyMockSupport { expect(kerberosDescriptor.getIdentities(eq(true), anyObject(Map.class))).andReturn(null).atLeastOnce(); expect(kerberosDescriptor.getAuthToLocalProperties()).andReturn(Collections.singleton("core-site/auth.to.local")).atLeastOnce(); - setupKerberosDescriptor(kerberosDescriptor, 2); + setupKerberosDescriptor(kerberosDescriptor); RecommendationResponse.BlueprintConfigurations coreSiteRecommendation = createNiceMock(RecommendationResponse .BlueprintConfigurations.class); @@ -2695,7 +2695,7 @@ public class KerberosHelperTest extends EasyMockSupport { expectLastCall().once(); } - setupKerberosDescriptor(kerberosDescriptor, 1); + setupKerberosDescriptor(kerberosDescriptor); Map<String, Map<String, String>> existingConfigurations = new HashMap<>(); existingConfigurations.put("kerberos-env", propertiesKerberosEnv); @@ -2822,7 +2822,7 @@ public class KerberosHelperTest extends EasyMockSupport { expect(kerberosDescriptor.getProperties()).andReturn(kerberosDescriptorProperties); expect(kerberosDescriptor.getService("SERVICE1")).andReturn(service1KerberosDescriptor).times(1); - setupKerberosDescriptor(kerberosDescriptor, 1); + setupKerberosDescriptor(kerberosDescriptor); Map<String, Map<String, String>> existingConfigurations = new HashMap<>(); existingConfigurations.put("kerberos-env", propertiesKerberosEnv); @@ -2858,9 +2858,10 @@ public class KerberosHelperTest extends EasyMockSupport { assertEquals(0, capturedPrincipalsForKeytab.size()); } - private void setupKerberosDescriptor(KerberosDescriptor kerberosDescriptor, int expectedCalls) throws Exception { + private void setupKerberosDescriptor(KerberosDescriptor kerberosDescriptor) throws Exception { // cluster.getCurrentStackVersion expectation is already specified in main test method - expect(metaInfo.getKerberosDescriptor("HDP", "2.2")).andReturn(kerberosDescriptor).times(expectedCalls); + expect(metaInfo.getKerberosDescriptor("HDP", "2.2")).andReturn(kerberosDescriptor).anyTimes(); + expect(kerberosDescriptor.principals()).andReturn(Collections.<String, String>emptyMap()).anyTimes(); } private void setupStageFactory() { @@ -3110,7 +3111,7 @@ public class KerberosHelperTest extends EasyMockSupport { expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).times(1); } - setupKerberosDescriptor(kerberosDescriptor, 1); + setupKerberosDescriptor(kerberosDescriptor); setupStageFactory(); // This is a STRICT mock to help ensure that the end result is what we want. @@ -3312,7 +3313,7 @@ public class KerberosHelperTest extends EasyMockSupport { expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).times(1); expect(kerberosDescriptor.getService("SERVICE3")).andReturn(serviceDescriptor3).times(1); - setupKerberosDescriptor(kerberosDescriptor, 1); + setupKerberosDescriptor(kerberosDescriptor); setupStageFactory(); // This is a STRICT mock to help ensure that the end result is what we want. @@ -3489,7 +3490,7 @@ public class KerberosHelperTest extends EasyMockSupport { final KerberosDescriptor kerberosDescriptor = createStrictMock(KerberosDescriptor.class); expect(kerberosDescriptor.getProperties()).andReturn(null).once(); - setupKerberosDescriptor(kerberosDescriptor, 1); + setupKerberosDescriptor(kerberosDescriptor); setupStageFactory(); // Preparation Stage @@ -3659,7 +3660,7 @@ public class KerberosHelperTest extends EasyMockSupport { final KerberosDescriptor kerberosDescriptor = createStrictMock(KerberosDescriptor.class); expect(kerberosDescriptor.getProperties()).andReturn(null).once(); - setupKerberosDescriptor(kerberosDescriptor, 1); + setupKerberosDescriptor(kerberosDescriptor); setupStageFactory(); // This is a STRICT mock to help ensure that the end result is what we want. @@ -3969,7 +3970,7 @@ public class KerberosHelperTest extends EasyMockSupport { expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).anyTimes(); expect(kerberosDescriptor.getService("SERVICE2")).andReturn(serviceDescriptor2).anyTimes(); - setupKerberosDescriptor(kerberosDescriptor, 1); + setupKerberosDescriptor(kerberosDescriptor); replayAll(); http://git-wip-us.apache.org/repos/asf/ambari/blob/afeb6f3a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java index d484ee5..747558d 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java @@ -493,4 +493,13 @@ public class KerberosDescriptorTest { }}); Assert.assertEquals(1, identities.size()); } + + @Test + public void testCollectPrincipalNames() throws Exception { + URL systemResourceURL = ClassLoader.getSystemResource("kerberos/test_get_referenced_identity_descriptor.json"); + KerberosDescriptor descriptor = KERBEROS_DESCRIPTOR_FACTORY.createInstance(new File(systemResourceURL.getFile())); + Map<String, String> principalsPerComponent = descriptor.principals(); + Assert.assertEquals("service2_component1@${realm}", principalsPerComponent.get("SERVICE2/SERVICE2_COMPONENT1/service2_component1_identity")); + Assert.assertEquals("service1@${realm}", principalsPerComponent.get("SERVICE1/service1_identity")); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/afeb6f3a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelperTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelperTest.java index 857047b..159ad69 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelperTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelperTest.java @@ -24,6 +24,8 @@ import org.apache.ambari.server.AmbariException; import org.junit.Test; import org.junit.experimental.categories.Category; +import static junit.framework.Assert.assertEquals; + import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -72,62 +74,62 @@ public class VariableReplacementHelperTest { } }; - Assert.assertEquals("concrete", + assertEquals("concrete", helper.replaceVariables("concrete", configurations)); - Assert.assertEquals("Hello World", + assertEquals("Hello World", helper.replaceVariables("${global_variable}", configurations)); - Assert.assertEquals("Replacement1", + assertEquals("Replacement1", helper.replaceVariables("${config-type/variable.name}", configurations)); - Assert.assertEquals("Replacement1|Replacement2", + assertEquals("Replacement1|Replacement2", helper.replaceVariables("${config-type/variable.name}|${config-type2/variable.name}", configurations)); - Assert.assertEquals("Replacement1|Replacement2|${config-type3/variable.name}", + assertEquals("Replacement1|Replacement2|${config-type3/variable.name}", helper.replaceVariables("${config-type/variable.name}|${config-type2/variable.name}|${config-type3/variable.name}", configurations)); - Assert.assertEquals("Replacement2|Replacement2", + assertEquals("Replacement2|Replacement2", helper.replaceVariables("${config-type/variable.name1}|${config-type2/variable.name}", configurations)); - Assert.assertEquals("Replacement1_reference", + assertEquals("Replacement1_reference", helper.replaceVariables("${config-type/variable.name}_reference", configurations)); - Assert.assertEquals("dash", + assertEquals("dash", helper.replaceVariables("${variable-name}", configurations)); - Assert.assertEquals("underscore", + assertEquals("underscore", helper.replaceVariables("${variable_name}", configurations)); - Assert.assertEquals("config_type_dot", + assertEquals("config_type_dot", helper.replaceVariables("${config_type/variable.name}", configurations)); - Assert.assertEquals("config_type_dash", + assertEquals("config_type_dash", helper.replaceVariables("${config_type/variable-name}", configurations)); - Assert.assertEquals("config_type_underscore", + assertEquals("config_type_underscore", helper.replaceVariables("${config_type/variable_name}", configurations)); - Assert.assertEquals("config.type_dot", + assertEquals("config.type_dot", helper.replaceVariables("${config.type/variable.name}", configurations)); - Assert.assertEquals("config.type_dash", + assertEquals("config.type_dash", helper.replaceVariables("${config.type/variable-name}", configurations)); - Assert.assertEquals("config.type_underscore", + assertEquals("config.type_underscore", helper.replaceVariables("${config.type/variable_name}", configurations)); - Assert.assertEquals("dot", + assertEquals("dot", helper.replaceVariables("${variable.name}", configurations)); // Replacement yields an empty string - Assert.assertEquals("", + assertEquals("", helper.replaceVariables("${config-type/variable.name2}", configurations)); // This might cause an infinite loop... we assume protection is in place... try { - Assert.assertEquals("${config-type2/self_reference}", + assertEquals("${config-type2/self_reference}", helper.replaceVariables("${config-type2/self_reference}", configurations)); Assert.fail(String.format("%s expected to be thrown", AmbariException.class.getName())); } catch (AmbariException e) { @@ -146,13 +148,13 @@ public class VariableReplacementHelperTest { } }; - Assert.assertEquals("hive.metastore.local=false,hive.metastore.uris=thrift://c6401.ambari.apache.org:9083,hive.metastore.sasl.enabled=true,hive.metastore.execute.setugi=true,hive.metastore.warehouse.dir=/apps/hive/warehouse,hive.exec.mode.local.auto=false,hive.metastore.kerberos.principal=hive/_h...@example.com", + assertEquals("hive.metastore.local=false,hive.metastore.uris=thrift://c6401.ambari.apache.org:9083,hive.metastore.sasl.enabled=true,hive.metastore.execute.setugi=true,hive.metastore.warehouse.dir=/apps/hive/warehouse,hive.exec.mode.local.auto=false,hive.metastore.kerberos.principal=hive/_h...@example.com", helper.replaceVariables("hive.metastore.local=false,hive.metastore.uris=thrift://${host}:9083,hive.metastore.sasl.enabled=true,hive.metastore.execute.setugi=true,hive.metastore.warehouse.dir=/apps/hive/warehouse,hive.exec.mode.local.auto=false,hive.metastore.kerberos.principal=hive/_HOST@${realm}", configurations)); - Assert.assertEquals("Hello my realm is {EXAMPLE.COM}", + assertEquals("Hello my realm is {EXAMPLE.COM}", helper.replaceVariables("Hello my realm is {${realm}}", configurations)); - Assert.assertEquals("$c6401.ambari.apache.org", + assertEquals("$c6401.ambari.apache.org", helper.replaceVariables("$${host}", configurations)); } @@ -178,10 +180,10 @@ public class VariableReplacementHelperTest { } }; - Assert.assertEquals("test=thrift://one:9083\\,thrift://two:9083\\,thrift://three:9083\\,thrift://four:9083", + assertEquals("test=thrift://one:9083\\,thrift://two:9083\\,thrift://three:9083\\,thrift://four:9083", helper.replaceVariables("test=${delimited.data|each(thrift://%s:9083, \\\\,, \\s*\\,\\s*)}", configurations)); - Assert.assertEquals("hive.metastore.local=false,hive.metastore.uris=thrift://host1.unit.test:9083\\,thrift://host2.unit.test:9083\\,thrift://host3.unit.test:9083,hive.metastore.sasl.enabled=true,hive.metastore.execute.setugi=true,hive.metastore.warehouse.dir=/apps/hive/warehouse,hive.exec.mode.local.auto=false,hive.metastore.kerberos.principal=hive/_h...@unit.test", + assertEquals("hive.metastore.local=false,hive.metastore.uris=thrift://host1.unit.test:9083\\,thrift://host2.unit.test:9083\\,thrift://host3.unit.test:9083,hive.metastore.sasl.enabled=true,hive.metastore.execute.setugi=true,hive.metastore.warehouse.dir=/apps/hive/warehouse,hive.exec.mode.local.auto=false,hive.metastore.kerberos.principal=hive/_h...@unit.test", helper.replaceVariables("hive.metastore.local=false,hive.metastore.uris=${clusterHostInfo/hive_metastore_host | each(thrift://%s:9083, \\\\,, \\s*\\,\\s*)},hive.metastore.sasl.enabled=true,hive.metastore.execute.setugi=true,hive.metastore.warehouse.dir=/apps/hive/warehouse,hive.exec.mode.local.auto=false,hive.metastore.kerberos.principal=hive/_HOST@${realm}", configurations)); List<String> expected; @@ -191,25 +193,25 @@ public class VariableReplacementHelperTest { actual = new LinkedList<String>(Arrays.asList(helper.replaceVariables("${foobar-site/hello | append(foobar-site/data, \\,, true)}", configurations).split(","))); Collections.sort(expected); Collections.sort(actual); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); expected = new LinkedList<String>(Arrays.asList("four", "hello", "one", "there", "three", "two")); actual = new LinkedList<String>(Arrays.asList(helper.replaceVariables("${foobar-site/hello_there | append(foobar-site/data, \\,, true)}", configurations).split(","))); Collections.sort(expected); Collections.sort(actual); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); expected = new LinkedList<String>(Arrays.asList("four", "hello", "one", "there", "three", "two")); actual = new LinkedList<String>(Arrays.asList(helper.replaceVariables("${foobar-site/hello_there_one | append(foobar-site/data, \\,, true)}", configurations).split(","))); Collections.sort(expected); Collections.sort(actual); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); expected = new LinkedList<String>(Arrays.asList("four", "hello", "one", "one", "there", "three", "two")); actual = new LinkedList<String>(Arrays.asList(helper.replaceVariables("${foobar-site/hello_there_one | append(foobar-site/data, \\,, false)}", configurations).split(","))); Collections.sort(expected); Collections.sort(actual); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); // Test invalid number of arguments. try { @@ -220,7 +222,22 @@ public class VariableReplacementHelperTest { // Ignore this is expected. } - Assert.assertEquals("test=unit.test", helper.replaceVariables("test=${realm|toLower()}", configurations)); + assertEquals("test=unit.test", helper.replaceVariables("test=${realm|toLower()}", configurations)); } + @Test + public void testReplacePrincipalWithPrimary() throws AmbariException { + Map<String, Map<String, String>> config = new HashMap<String, Map<String, String>>() { + { + put("principals", new HashMap<String, String>() {{ + put("resource_manager_rm", "rm/h...@example.com"); + put("hive_server_hive", "h...@example.com"); + put("hdfs", "hdfs"); + }}); + } + }; + assertEquals("hdfs", helper.replaceVariables("${principals/hdfs|principalPrimary()}", config)); + assertEquals("rm", helper.replaceVariables("${principals/resource_manager_rm|principalPrimary()}", config)); + assertEquals("hive", helper.replaceVariables("${principals/hive_server_hive|principalPrimary()}", config)); + } } \ No newline at end of file