YARN-10958. Use correct configuration for Group service init in CSMappingPlacementRule (#3560)
* YARN-10958. Initial commit * Fix javadoc + behaviour * Fix review comments * fix checkstyle + blanks * fix checkstyle + blanks * Fix checkstyle + blanks
This commit is contained in:
parent
3e1135469e
commit
414d40155c
@ -493,4 +493,9 @@ public static synchronized Groups getUserToGroupsMappingService(
|
|||||||
GROUPS = new Groups(conf);
|
GROUPS = new Groups(conf);
|
||||||
return GROUPS;
|
return GROUPS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public static void reset() {
|
||||||
|
GROUPS = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ public boolean initialize(ResourceScheduler scheduler) throws IOException {
|
|||||||
overrideWithQueueMappings = conf.getOverrideWithQueueMappings();
|
overrideWithQueueMappings = conf.getOverrideWithQueueMappings();
|
||||||
|
|
||||||
if (groups == null) {
|
if (groups == null) {
|
||||||
groups = Groups.getUserToGroupsMappingService(conf);
|
groups = Groups.getUserToGroupsMappingService(csContext.getConf());
|
||||||
}
|
}
|
||||||
|
|
||||||
MappingRuleValidationContext validationContext = buildValidationContext();
|
MappingRuleValidationContext validationContext = buildValidationContext();
|
||||||
@ -535,4 +535,9 @@ private String cleanName(String name) {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public Groups getGroups() {
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
package org.apache.hadoop.yarn.server.resourcemanager.placement.csmappingrule;
|
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.ImmutableMap;
|
||||||
import org.apache.hadoop.thirdparty.com.google.common.collect.ImmutableSet;
|
import org.apache.hadoop.thirdparty.com.google.common.collect.ImmutableSet;
|
||||||
import org.apache.hadoop.security.Groups;
|
import org.apache.hadoop.security.Groups;
|
||||||
@ -51,6 +53,7 @@
|
|||||||
import static junit.framework.TestCase.assertNull;
|
import static junit.framework.TestCase.assertNull;
|
||||||
import static junit.framework.TestCase.assertTrue;
|
import static junit.framework.TestCase.assertTrue;
|
||||||
import static junit.framework.TestCase.fail;
|
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.ArgumentMatchers.isNull;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
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",
|
"Application should have been placed to root.groups.sec_dot_test_dot_grp",
|
||||||
engine, app, "test.user", "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.<br>
|
||||||
|
* 2. Create a Configuration object in which the property "hadoop.security.group.mapping"
|
||||||
|
* refers to an existing a test implementation.<br>
|
||||||
|
* 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.<br>
|
||||||
|
* 4. Create an instance of CSMappingPlacementRule with a single primary group rule.<br>
|
||||||
|
* 5. Run the placement evaluation.<br>
|
||||||
|
* 6. Expected: The returned queue matches what is supposed to be coming from the test group
|
||||||
|
* mapping service ("testuser" --> "testGroup1").<br>
|
||||||
|
* 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.<br>
|
||||||
|
* 8. Call Groups.refresh() which changes the group mapping ("testuser" --> "testGroup0"). This
|
||||||
|
* requires that the test group mapping service implement GroupMappingServiceProvider
|
||||||
|
* .cacheGroupsRefresh().<br>
|
||||||
|
* 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.<br>
|
||||||
|
* 10. Run the placement evaluation again<br>
|
||||||
|
* 11. Expected: with the same user, the target queue has changed to 'testGroup0'.<br>
|
||||||
|
* <p>
|
||||||
|
* These all looks convoluted, but the steps above make sure all the following conditions are met:
|
||||||
|
* <p>
|
||||||
|
* 1. CSMappingPlacementRule will force the initialization of groups.<br>
|
||||||
|
* 2. We select the correct configuration for group service init.<br>
|
||||||
|
* 3. We don't create a new Groups instance if the singleton is initialized, so we cover the
|
||||||
|
* original problem described in YARN-10597.<br>
|
||||||
|
*/
|
||||||
|
@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<MappingRule> mappingRules = new ArrayList<>();
|
||||||
|
mappingRules.add(
|
||||||
|
new MappingRule(
|
||||||
|
MappingRuleMatchers.createUserMatcher(user),
|
||||||
|
(new MappingRuleActions.PlaceToQueueAction(
|
||||||
|
"root.man.%primary_group", true))
|
||||||
|
.setFallbackReject()));
|
||||||
|
CapacitySchedulerConfiguration csConf = new CapacitySchedulerConfiguration() {
|
||||||
|
@Override
|
||||||
|
public List<MappingRule> getMappingRules() {
|
||||||
|
return mappingRules;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
csConf.setOverrideWithQueueMappings(true);
|
||||||
|
//Intentionally add a dummy implementation class -
|
||||||
|
// The "HADOOP_SECURITY_GROUP_MAPPING" should not be read from the
|
||||||
|
// CapacitySchedulerConfiguration instance!
|
||||||
|
csConf.setClass(HADOOP_SECURITY_GROUP_MAPPING, String.class, Object.class);
|
||||||
|
|
||||||
|
CapacityScheduler cs = createMockCS(yarnConf, csConf);
|
||||||
|
|
||||||
|
//Create app, submit to placement engine, expecting queue=testGroup1
|
||||||
|
CSMappingPlacementRule engine = initPlacementEngine(cs);
|
||||||
|
ApplicationSubmissionContext app = createApp("app");
|
||||||
|
assertPlace(engine, app, user, "root.man.testGroup1");
|
||||||
|
|
||||||
|
//Intentionally add a dummy implementation class!
|
||||||
|
// The "HADOOP_SECURITY_GROUP_MAPPING" should not be read from the
|
||||||
|
// CapacitySchedulerConfiguration instance!
|
||||||
|
//This makes sure that the Groups instance is not recreated by CSMappingPlacementRule
|
||||||
|
yarnConf.setClass(HADOOP_SECURITY_GROUP_MAPPING, String.class, Object.class);
|
||||||
|
|
||||||
|
//Refresh the groups, this makes testGroup0 as primary group for "testUser"
|
||||||
|
engine.getGroups().refresh();
|
||||||
|
|
||||||
|
//Create app, submit to placement engine, expecting queue=testGroup0 (the new primary group)
|
||||||
|
engine = initPlacementEngine(cs);
|
||||||
|
assertPlace(engine, app, user, "root.man.testGroup0");
|
||||||
|
}
|
||||||
|
|
||||||
|
private CSMappingPlacementRule initPlacementEngine(CapacityScheduler cs) throws IOException {
|
||||||
|
CSMappingPlacementRule engine = new CSMappingPlacementRule();
|
||||||
|
engine.setFailOnConfigError(true);
|
||||||
|
engine.initialize(cs);
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CapacityScheduler createMockCS(Configuration conf,
|
||||||
|
CapacitySchedulerConfiguration csConf) {
|
||||||
|
CapacitySchedulerQueueManager qm =
|
||||||
|
mock(CapacitySchedulerQueueManager.class);
|
||||||
|
createQueueHierarchy(qm);
|
||||||
|
|
||||||
|
CapacityScheduler cs = mock(CapacityScheduler.class);
|
||||||
|
when(cs.getConfiguration()).thenReturn(csConf);
|
||||||
|
when(cs.getConf()).thenReturn(conf);
|
||||||
|
when(cs.getCapacitySchedulerQueueManager()).thenReturn(qm);
|
||||||
|
return cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MockUnixGroupsMapping implements GroupMappingServiceProvider {
|
||||||
|
|
||||||
|
public MockUnixGroupsMapping() {
|
||||||
|
GROUP.clear();
|
||||||
|
GROUP.add("testGroup1");
|
||||||
|
GROUP.add("testGroup2");
|
||||||
|
GROUP.add("testGroup3");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final List<String> GROUP = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getGroups(String user) throws IOException {
|
||||||
|
return GROUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cacheGroupsRefresh() {
|
||||||
|
GROUP.add(0, "testGroup0");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cacheGroupsAdd(List<String> groups) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) {
|
||||||
|
return ImmutableSet.copyOf(GROUP);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user