diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/Groups.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/Groups.java
index bc2ea458b33f3..70c633cdf8a23 100644
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/Groups.java
+++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/Groups.java
@@ -493,4 +493,9 @@ public static synchronized Groups getUserToGroupsMappingService(
GROUPS = new Groups(conf);
return GROUPS;
}
+
+ @VisibleForTesting
+ public static void reset() {
+ GROUPS = null;
+ }
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/CSMappingPlacementRule.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/CSMappingPlacementRule.java
index ef98c1a79f178..91e0138c4a094 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/CSMappingPlacementRule.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/CSMappingPlacementRule.java
@@ -133,7 +133,7 @@ public boolean initialize(ResourceScheduler scheduler) throws IOException {
overrideWithQueueMappings = conf.getOverrideWithQueueMappings();
if (groups == null) {
- groups = Groups.getUserToGroupsMappingService(conf);
+ groups = Groups.getUserToGroupsMappingService(csContext.getConf());
}
MappingRuleValidationContext validationContext = buildValidationContext();
@@ -535,4 +535,9 @@ private String cleanName(String name) {
return name;
}
}
+
+ @VisibleForTesting
+ public Groups getGroups() {
+ return groups;
+ }
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/placement/csmappingrule/TestCSMappingPlacementRule.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/placement/csmappingrule/TestCSMappingPlacementRule.java
index 0cf10595ee9dd..3e614bcbc967a 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/placement/csmappingrule/TestCSMappingPlacementRule.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/placement/csmappingrule/TestCSMappingPlacementRule.java
@@ -18,6 +18,8 @@
package org.apache.hadoop.yarn.server.resourcemanager.placement.csmappingrule;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.GroupMappingServiceProvider;
import org.apache.hadoop.thirdparty.com.google.common.collect.ImmutableMap;
import org.apache.hadoop.thirdparty.com.google.common.collect.ImmutableSet;
import org.apache.hadoop.security.Groups;
@@ -51,6 +53,7 @@
import static junit.framework.TestCase.assertNull;
import static junit.framework.TestCase.assertTrue;
import static junit.framework.TestCase.fail;
+import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_GROUP_MAPPING;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -771,4 +774,138 @@ public void testSecondaryGroupNameCleanup() throws IOException {
"Application should have been placed to root.groups.sec_dot_test_dot_grp",
engine, app, "test.user", "root.groups.sec_dot_test_dot_grp");
}
+
+ /**
+ * 1. Invoke Groups.reset(). This make sure that the underlying singleton {@link Groups#GROUPS}
+ * is set to null.
+ * 2. Create a Configuration object in which the property "hadoop.security.group.mapping"
+ * refers to an existing a test implementation.
+ * 3. Create a mock CapacityScheduler where getConf() and getConfiguration() contain different
+ * settings for "hadoop.security.group.mapping". Since getConf() is the service config, this
+ * should return the config object created in step #2.
+ * 4. Create an instance of CSMappingPlacementRule with a single primary group rule.
+ * 5. Run the placement evaluation.
+ * 6. Expected: The returned queue matches what is supposed to be coming from the test group
+ * mapping service ("testuser" --> "testGroup1").
+ * 7. Modify "hadoop.security.group.mapping" in the config object created in step #2.
+ * This step is required to guarantee that the CSMappingPlacementRule doesn't try to recreate
+ * the group mapping implementation and uses the one that was previously created.
+ * 8. Call Groups.refresh() which changes the group mapping ("testuser" --> "testGroup0"). This
+ * requires that the test group mapping service implement GroupMappingServiceProvider
+ * .cacheGroupsRefresh().
+ * 9. Create a new instance of CSMappingPlacementRule. This is important as we want to test
+ * that even this new {@link CSMappingPlacementRule} instance uses the same group mapping
+ * instance.
+ * 10. Run the placement evaluation again
+ * 11. Expected: with the same user, the target queue has changed to 'testGroup0'.
+ *
+ * These all looks convoluted, but the steps above make sure all the following conditions are met: + *
+ * 1. CSMappingPlacementRule will force the initialization of groups.
+ * 2. We select the correct configuration for group service init.
+ * 3. We don't create a new Groups instance if the singleton is initialized, so we cover the
+ * original problem described in YARN-10597.
+ */
+ @Test
+ public void testPlacementEngineSelectsCorrectConfigurationForGroupMapping() throws IOException {
+ Groups.reset();
+ final String user = "testuser";
+
+ //Create service-wide configuration object
+ Configuration yarnConf = new Configuration();
+ yarnConf.setClass(HADOOP_SECURITY_GROUP_MAPPING, MockUnixGroupsMapping.class,
+ GroupMappingServiceProvider.class);
+
+ //Create CS configuration object with a single, primary group mapping rule
+ List