HADOOP-17079. Optimize UGI#getGroups by adding UGI#getGroupsSet. (#2085)
This commit is contained in:
parent
5dd270e208
commit
f91a8ad88b
|
@ -2695,7 +2695,7 @@ public abstract class FileSystem extends Configured
|
||||||
if (perm.getUserAction().implies(mode)) {
|
if (perm.getUserAction().implies(mode)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (ugi.getGroups().contains(stat.getGroup())) {
|
} else if (ugi.getGroupsSet().contains(stat.getGroup())) {
|
||||||
if (perm.getGroupAction().implies(mode)) {
|
if (perm.getGroupAction().implies(mode)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,7 +272,7 @@ public class SecureIOUtils {
|
||||||
UserGroupInformation.createRemoteUser(expectedOwner);
|
UserGroupInformation.createRemoteUser(expectedOwner);
|
||||||
final String adminsGroupString = "Administrators";
|
final String adminsGroupString = "Administrators";
|
||||||
success = owner.equals(adminsGroupString)
|
success = owner.equals(adminsGroupString)
|
||||||
&& ugi.getGroups().contains(adminsGroupString);
|
&& ugi.getGroupsSet().contains(adminsGroupString);
|
||||||
} else {
|
} else {
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.hadoop.security;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -106,6 +107,29 @@ public class CompositeGroupsMapping
|
||||||
// does nothing in this provider of user to groups mapping
|
// does nothing in this provider of user to groups mapping
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
Set<String> groupSet = new HashSet<String>();
|
||||||
|
|
||||||
|
Set<String> groups = null;
|
||||||
|
for (GroupMappingServiceProvider provider : providersList) {
|
||||||
|
try {
|
||||||
|
groups = provider.getGroupsSet(user);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warn("Unable to get groups for user {} via {} because: {}",
|
||||||
|
user, provider.getClass().getSimpleName(), e.toString());
|
||||||
|
LOG.debug("Stacktrace: ", e);
|
||||||
|
}
|
||||||
|
if (groups != null && !groups.isEmpty()) {
|
||||||
|
groupSet.addAll(groups);
|
||||||
|
if (!combined) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return groupSet;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Configuration getConf() {
|
public synchronized Configuration getConf() {
|
||||||
return conf;
|
return conf;
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.hadoop.security;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
@ -52,4 +53,13 @@ public interface GroupMappingServiceProvider {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void cacheGroupsAdd(List<String> groups) throws IOException;
|
public void cacheGroupsAdd(List<String> groups) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all various group memberships of a given user.
|
||||||
|
* Returns EMPTY set in case of non-existing user
|
||||||
|
* @param user User's name
|
||||||
|
* @return set of group memberships of user
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
Set<String> getGroupsSet(String user) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
@ -78,8 +77,8 @@ public class Groups {
|
||||||
|
|
||||||
private final GroupMappingServiceProvider impl;
|
private final GroupMappingServiceProvider impl;
|
||||||
|
|
||||||
private final LoadingCache<String, List<String>> cache;
|
private final LoadingCache<String, Set<String>> cache;
|
||||||
private final AtomicReference<Map<String, List<String>>> staticMapRef =
|
private final AtomicReference<Map<String, Set<String>>> staticMapRef =
|
||||||
new AtomicReference<>();
|
new AtomicReference<>();
|
||||||
private final long cacheTimeout;
|
private final long cacheTimeout;
|
||||||
private final long negativeCacheTimeout;
|
private final long negativeCacheTimeout;
|
||||||
|
@ -168,8 +167,7 @@ public class Groups {
|
||||||
CommonConfigurationKeys.HADOOP_USER_GROUP_STATIC_OVERRIDES_DEFAULT);
|
CommonConfigurationKeys.HADOOP_USER_GROUP_STATIC_OVERRIDES_DEFAULT);
|
||||||
Collection<String> mappings = StringUtils.getStringCollection(
|
Collection<String> mappings = StringUtils.getStringCollection(
|
||||||
staticMapping, ";");
|
staticMapping, ";");
|
||||||
Map<String, List<String>> staticUserToGroupsMap =
|
Map<String, Set<String>> staticUserToGroupsMap = new HashMap<>();
|
||||||
new HashMap<String, List<String>>();
|
|
||||||
for (String users : mappings) {
|
for (String users : mappings) {
|
||||||
Collection<String> userToGroups = StringUtils.getStringCollection(users,
|
Collection<String> userToGroups = StringUtils.getStringCollection(users,
|
||||||
"=");
|
"=");
|
||||||
|
@ -181,10 +179,10 @@ public class Groups {
|
||||||
String[] userToGroupsArray = userToGroups.toArray(new String[userToGroups
|
String[] userToGroupsArray = userToGroups.toArray(new String[userToGroups
|
||||||
.size()]);
|
.size()]);
|
||||||
String user = userToGroupsArray[0];
|
String user = userToGroupsArray[0];
|
||||||
List<String> groups = Collections.emptyList();
|
Set<String> groups = Collections.emptySet();
|
||||||
if (userToGroupsArray.length == 2) {
|
if (userToGroupsArray.length == 2) {
|
||||||
groups = (List<String>) StringUtils
|
groups = new LinkedHashSet(StringUtils
|
||||||
.getStringCollection(userToGroupsArray[1]);
|
.getStringCollection(userToGroupsArray[1]));
|
||||||
}
|
}
|
||||||
staticUserToGroupsMap.put(user, groups);
|
staticUserToGroupsMap.put(user, groups);
|
||||||
}
|
}
|
||||||
|
@ -203,15 +201,47 @@ public class Groups {
|
||||||
/**
|
/**
|
||||||
* Get the group memberships of a given user.
|
* Get the group memberships of a given user.
|
||||||
* If the user's group is not cached, this method may block.
|
* If the user's group is not cached, this method may block.
|
||||||
|
* Note this method can be expensive as it involves Set->List conversion.
|
||||||
|
* For user with large group membership (i.e., > 1000 groups), we recommend
|
||||||
|
* using getGroupSet to avoid the conversion and fast membership look up via
|
||||||
|
* contains().
|
||||||
* @param user User's name
|
* @param user User's name
|
||||||
* @return the group memberships of the user
|
* @return the group memberships of the user as list
|
||||||
|
* @throws IOException if user does not exist
|
||||||
|
* @deprecated Use {@link #getGroupsSet(String user)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public List<String> getGroups(final String user) throws IOException {
|
||||||
|
return Collections.unmodifiableList(new ArrayList<>(
|
||||||
|
getGroupInternal(user)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the group memberships of a given user.
|
||||||
|
* If the user's group is not cached, this method may block.
|
||||||
|
* This provide better performance when user has large group membership via
|
||||||
|
* 1) avoid set->list->set conversion for the caller UGI/PermissionCheck
|
||||||
|
* 2) fast lookup using contains() via Set instead of List
|
||||||
|
* @param user User's name
|
||||||
|
* @return the group memberships of the user as set
|
||||||
* @throws IOException if user does not exist
|
* @throws IOException if user does not exist
|
||||||
*/
|
*/
|
||||||
public List<String> getGroups(final String user) throws IOException {
|
public Set<String> getGroupsSet(final String user) throws IOException {
|
||||||
|
return Collections.unmodifiableSet(getGroupInternal(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the group memberships of a given user.
|
||||||
|
* If the user's group is not cached, this method may block.
|
||||||
|
* @param user User's name
|
||||||
|
* @return the group memberships of the user as Set
|
||||||
|
* @throws IOException if user does not exist
|
||||||
|
*/
|
||||||
|
private Set<String> getGroupInternal(final String user) throws IOException {
|
||||||
// No need to lookup for groups of static users
|
// No need to lookup for groups of static users
|
||||||
Map<String, List<String>> staticUserToGroupsMap = staticMapRef.get();
|
Map<String, Set<String>> staticUserToGroupsMap = staticMapRef.get();
|
||||||
if (staticUserToGroupsMap != null) {
|
if (staticUserToGroupsMap != null) {
|
||||||
List<String> staticMapping = staticUserToGroupsMap.get(user);
|
Set<String> staticMapping = staticUserToGroupsMap.get(user);
|
||||||
if (staticMapping != null) {
|
if (staticMapping != null) {
|
||||||
return staticMapping;
|
return staticMapping;
|
||||||
}
|
}
|
||||||
|
@ -267,7 +297,7 @@ public class Groups {
|
||||||
/**
|
/**
|
||||||
* Deals with loading data into the cache.
|
* Deals with loading data into the cache.
|
||||||
*/
|
*/
|
||||||
private class GroupCacheLoader extends CacheLoader<String, List<String>> {
|
private class GroupCacheLoader extends CacheLoader<String, Set<String>> {
|
||||||
|
|
||||||
private ListeningExecutorService executorService;
|
private ListeningExecutorService executorService;
|
||||||
|
|
||||||
|
@ -308,7 +338,7 @@ public class Groups {
|
||||||
* @throws IOException to prevent caching negative entries
|
* @throws IOException to prevent caching negative entries
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<String> load(String user) throws Exception {
|
public Set<String> load(String user) throws Exception {
|
||||||
LOG.debug("GroupCacheLoader - load.");
|
LOG.debug("GroupCacheLoader - load.");
|
||||||
TraceScope scope = null;
|
TraceScope scope = null;
|
||||||
Tracer tracer = Tracer.curThreadTracer();
|
Tracer tracer = Tracer.curThreadTracer();
|
||||||
|
@ -316,9 +346,9 @@ public class Groups {
|
||||||
scope = tracer.newScope("Groups#fetchGroupList");
|
scope = tracer.newScope("Groups#fetchGroupList");
|
||||||
scope.addKVAnnotation("user", user);
|
scope.addKVAnnotation("user", user);
|
||||||
}
|
}
|
||||||
List<String> groups = null;
|
Set<String> groups = null;
|
||||||
try {
|
try {
|
||||||
groups = fetchGroupList(user);
|
groups = fetchGroupSet(user);
|
||||||
} finally {
|
} finally {
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
scope.close();
|
scope.close();
|
||||||
|
@ -334,9 +364,7 @@ public class Groups {
|
||||||
throw noGroupsForUser(user);
|
throw noGroupsForUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return immutable de-duped list
|
return groups;
|
||||||
return Collections.unmodifiableList(
|
|
||||||
new ArrayList<>(new LinkedHashSet<>(groups)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -345,8 +373,8 @@ public class Groups {
|
||||||
* implementation, otherwise is arranges for the cache to be updated later
|
* implementation, otherwise is arranges for the cache to be updated later
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<List<String>> reload(final String key,
|
public ListenableFuture<Set<String>> reload(final String key,
|
||||||
List<String> oldValue)
|
Set<String> oldValue)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
LOG.debug("GroupCacheLoader - reload (async).");
|
LOG.debug("GroupCacheLoader - reload (async).");
|
||||||
if (!reloadGroupsInBackground) {
|
if (!reloadGroupsInBackground) {
|
||||||
|
@ -354,19 +382,16 @@ public class Groups {
|
||||||
}
|
}
|
||||||
|
|
||||||
backgroundRefreshQueued.incrementAndGet();
|
backgroundRefreshQueued.incrementAndGet();
|
||||||
ListenableFuture<List<String>> listenableFuture =
|
ListenableFuture<Set<String>> listenableFuture =
|
||||||
executorService.submit(new Callable<List<String>>() {
|
executorService.submit(() -> {
|
||||||
@Override
|
backgroundRefreshQueued.decrementAndGet();
|
||||||
public List<String> call() throws Exception {
|
backgroundRefreshRunning.incrementAndGet();
|
||||||
backgroundRefreshQueued.decrementAndGet();
|
Set<String> results = load(key);
|
||||||
backgroundRefreshRunning.incrementAndGet();
|
return results;
|
||||||
List<String> results = load(key);
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
Futures.addCallback(listenableFuture, new FutureCallback<List<String>>() {
|
Futures.addCallback(listenableFuture, new FutureCallback<Set<String>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<String> result) {
|
public void onSuccess(Set<String> result) {
|
||||||
backgroundRefreshSuccess.incrementAndGet();
|
backgroundRefreshSuccess.incrementAndGet();
|
||||||
backgroundRefreshRunning.decrementAndGet();
|
backgroundRefreshRunning.decrementAndGet();
|
||||||
}
|
}
|
||||||
|
@ -380,11 +405,12 @@ public class Groups {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queries impl for groups belonging to the user. This could involve I/O and take awhile.
|
* Queries impl for groups belonging to the user.
|
||||||
|
* This could involve I/O and take awhile.
|
||||||
*/
|
*/
|
||||||
private List<String> fetchGroupList(String user) throws IOException {
|
private Set<String> fetchGroupSet(String user) throws IOException {
|
||||||
long startMs = timer.monotonicNow();
|
long startMs = timer.monotonicNow();
|
||||||
List<String> groupList = impl.getGroups(user);
|
Set<String> groups = impl.getGroupsSet(user);
|
||||||
long endMs = timer.monotonicNow();
|
long endMs = timer.monotonicNow();
|
||||||
long deltaMs = endMs - startMs ;
|
long deltaMs = endMs - startMs ;
|
||||||
UserGroupInformation.metrics.addGetGroups(deltaMs);
|
UserGroupInformation.metrics.addGetGroups(deltaMs);
|
||||||
|
@ -392,8 +418,7 @@ public class Groups {
|
||||||
LOG.warn("Potential performance problem: getGroups(user=" + user +") " +
|
LOG.warn("Potential performance problem: getGroups(user=" + user +") " +
|
||||||
"took " + deltaMs + " milliseconds.");
|
"took " + deltaMs + " milliseconds.");
|
||||||
}
|
}
|
||||||
|
return groups;
|
||||||
return groupList;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,11 @@ package org.apache.hadoop.security;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
|
||||||
|
@ -75,6 +78,18 @@ public class JniBasedUnixGroupsMapping implements GroupMappingServiceProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroups(String user) throws IOException {
|
public List<String> getGroups(String user) throws IOException {
|
||||||
|
return Arrays.asList(getGroupsInternal(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
String[] groups = getGroupsInternal(user);
|
||||||
|
Set<String> result = new LinkedHashSet(groups.length);
|
||||||
|
CollectionUtils.addAll(result, groups);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] getGroupsInternal(String user) throws IOException {
|
||||||
String[] groups = new String[0];
|
String[] groups = new String[0];
|
||||||
try {
|
try {
|
||||||
groups = getGroupsForUser(user);
|
groups = getGroupsForUser(user);
|
||||||
|
@ -85,7 +100,7 @@ public class JniBasedUnixGroupsMapping implements GroupMappingServiceProvider {
|
||||||
LOG.info("Error getting groups for " + user + ": " + e.getMessage());
|
LOG.info("Error getting groups for " + user + ": " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Arrays.asList(groups);
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.hadoop.security;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.hadoop.util.NativeCodeLoader;
|
import org.apache.hadoop.util.NativeCodeLoader;
|
||||||
import org.apache.hadoop.util.PerformanceAdvisory;
|
import org.apache.hadoop.util.PerformanceAdvisory;
|
||||||
|
@ -61,4 +62,9 @@ public class JniBasedUnixGroupsMappingWithFallback implements
|
||||||
impl.cacheGroupsAdd(groups);
|
impl.cacheGroupsAdd(groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return impl.getGroupsSet(user);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.hadoop.security;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.hadoop.util.NativeCodeLoader;
|
import org.apache.hadoop.util.NativeCodeLoader;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -60,4 +61,9 @@ public class JniBasedUnixGroupsNetgroupMappingWithFallback implements
|
||||||
impl.cacheGroupsAdd(groups);
|
impl.cacheGroupsAdd(groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return impl.getGroupsSet(user);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -302,12 +303,12 @@ public class LdapGroupsMapping
|
||||||
}
|
}
|
||||||
|
|
||||||
private DirContext ctx;
|
private DirContext ctx;
|
||||||
private Configuration conf;
|
private volatile Configuration conf;
|
||||||
|
|
||||||
private Iterator<String> ldapUrls;
|
private volatile Iterator<String> ldapUrls;
|
||||||
private String currentLdapUrl;
|
private String currentLdapUrl;
|
||||||
|
|
||||||
private boolean useSsl;
|
private volatile boolean useSsl;
|
||||||
private String keystore;
|
private String keystore;
|
||||||
private String keystorePass;
|
private String keystorePass;
|
||||||
private String truststore;
|
private String truststore;
|
||||||
|
@ -320,21 +321,21 @@ public class LdapGroupsMapping
|
||||||
private Iterator<BindUserInfo> bindUsers;
|
private Iterator<BindUserInfo> bindUsers;
|
||||||
private BindUserInfo currentBindUser;
|
private BindUserInfo currentBindUser;
|
||||||
|
|
||||||
private String userbaseDN;
|
private volatile String userbaseDN;
|
||||||
private String groupbaseDN;
|
private String groupbaseDN;
|
||||||
private String groupSearchFilter;
|
private String groupSearchFilter;
|
||||||
private String userSearchFilter;
|
private volatile String userSearchFilter;
|
||||||
private String memberOfAttr;
|
private volatile String memberOfAttr;
|
||||||
private String groupMemberAttr;
|
private String groupMemberAttr;
|
||||||
private String groupNameAttr;
|
private volatile String groupNameAttr;
|
||||||
private int groupHierarchyLevels;
|
private volatile int groupHierarchyLevels;
|
||||||
private String posixUidAttr;
|
private volatile String posixUidAttr;
|
||||||
private String posixGidAttr;
|
private volatile String posixGidAttr;
|
||||||
private boolean isPosix;
|
private boolean isPosix;
|
||||||
private boolean useOneQuery;
|
private volatile boolean useOneQuery;
|
||||||
private int numAttempts;
|
private int numAttempts;
|
||||||
private int numAttemptsBeforeFailover;
|
private volatile int numAttemptsBeforeFailover;
|
||||||
private String ldapCtxFactoryClassName;
|
private volatile String ldapCtxFactoryClassName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns list of groups for a user.
|
* Returns list of groups for a user.
|
||||||
|
@ -348,38 +349,7 @@ public class LdapGroupsMapping
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized List<String> getGroups(String user) {
|
public synchronized List<String> getGroups(String user) {
|
||||||
/*
|
return new ArrayList<>(getGroupsSet(user));
|
||||||
* Normal garbage collection takes care of removing Context instances when
|
|
||||||
* they are no longer in use. Connections used by Context instances being
|
|
||||||
* garbage collected will be closed automatically. So in case connection is
|
|
||||||
* closed and gets CommunicationException, retry some times with new new
|
|
||||||
* DirContext/connection.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Tracks the number of attempts made using the same LDAP server
|
|
||||||
int atemptsBeforeFailover = 1;
|
|
||||||
|
|
||||||
for (int attempt = 1; attempt <= numAttempts; attempt++,
|
|
||||||
atemptsBeforeFailover++) {
|
|
||||||
try {
|
|
||||||
return doGetGroups(user, groupHierarchyLevels);
|
|
||||||
} catch (AuthenticationException e) {
|
|
||||||
switchBindUser(e);
|
|
||||||
} catch (NamingException e) {
|
|
||||||
LOG.warn("Failed to get groups for user {} (attempt={}/{}) using {}. " +
|
|
||||||
"Exception: ", user, attempt, numAttempts, currentLdapUrl, e);
|
|
||||||
LOG.trace("TRACE", e);
|
|
||||||
|
|
||||||
if (failover(atemptsBeforeFailover, numAttemptsBeforeFailover)) {
|
|
||||||
atemptsBeforeFailover = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset ctx so that new DirContext can be created with new connection
|
|
||||||
this.ctx = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -458,10 +428,10 @@ public class LdapGroupsMapping
|
||||||
* @return a list of strings representing group names of the user.
|
* @return a list of strings representing group names of the user.
|
||||||
* @throws NamingException if unable to find group names
|
* @throws NamingException if unable to find group names
|
||||||
*/
|
*/
|
||||||
private List<String> lookupGroup(SearchResult result, DirContext c,
|
private Set<String> lookupGroup(SearchResult result, DirContext c,
|
||||||
int goUpHierarchy)
|
int goUpHierarchy)
|
||||||
throws NamingException {
|
throws NamingException {
|
||||||
List<String> groups = new ArrayList<>();
|
Set<String> groups = new LinkedHashSet<>();
|
||||||
Set<String> groupDNs = new HashSet<>();
|
Set<String> groupDNs = new HashSet<>();
|
||||||
|
|
||||||
NamingEnumeration<SearchResult> groupResults;
|
NamingEnumeration<SearchResult> groupResults;
|
||||||
|
@ -484,11 +454,7 @@ public class LdapGroupsMapping
|
||||||
getGroupNames(groupResult, groups, groupDNs, goUpHierarchy > 0);
|
getGroupNames(groupResult, groups, groupDNs, goUpHierarchy > 0);
|
||||||
}
|
}
|
||||||
if (goUpHierarchy > 0 && !isPosix) {
|
if (goUpHierarchy > 0 && !isPosix) {
|
||||||
// convert groups to a set to ensure uniqueness
|
goUpGroupHierarchy(groupDNs, goUpHierarchy, groups);
|
||||||
Set<String> groupset = new HashSet<>(groups);
|
|
||||||
goUpGroupHierarchy(groupDNs, goUpHierarchy, groupset);
|
|
||||||
// convert set back to list for compatibility
|
|
||||||
groups = new ArrayList<>(groupset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return groups;
|
return groups;
|
||||||
|
@ -507,7 +473,7 @@ public class LdapGroupsMapping
|
||||||
* return an empty string array.
|
* return an empty string array.
|
||||||
* @throws NamingException if unable to get group names
|
* @throws NamingException if unable to get group names
|
||||||
*/
|
*/
|
||||||
List<String> doGetGroups(String user, int goUpHierarchy)
|
Set<String> doGetGroups(String user, int goUpHierarchy)
|
||||||
throws NamingException {
|
throws NamingException {
|
||||||
DirContext c = getDirContext();
|
DirContext c = getDirContext();
|
||||||
|
|
||||||
|
@ -518,11 +484,11 @@ public class LdapGroupsMapping
|
||||||
if (!results.hasMoreElements()) {
|
if (!results.hasMoreElements()) {
|
||||||
LOG.debug("doGetGroups({}) returned no groups because the " +
|
LOG.debug("doGetGroups({}) returned no groups because the " +
|
||||||
"user is not found.", user);
|
"user is not found.", user);
|
||||||
return Collections.emptyList();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
SearchResult result = results.nextElement();
|
SearchResult result = results.nextElement();
|
||||||
|
|
||||||
List<String> groups = Collections.emptyList();
|
Set<String> groups = Collections.emptySet();
|
||||||
if (useOneQuery) {
|
if (useOneQuery) {
|
||||||
try {
|
try {
|
||||||
/**
|
/**
|
||||||
|
@ -536,7 +502,7 @@ public class LdapGroupsMapping
|
||||||
memberOfAttr + "' attribute." +
|
memberOfAttr + "' attribute." +
|
||||||
"Returned user object: " + result.toString());
|
"Returned user object: " + result.toString());
|
||||||
}
|
}
|
||||||
groups = new ArrayList<>();
|
groups = new LinkedHashSet<>();
|
||||||
NamingEnumeration groupEnumeration = groupDNAttr.getAll();
|
NamingEnumeration groupEnumeration = groupDNAttr.getAll();
|
||||||
while (groupEnumeration.hasMore()) {
|
while (groupEnumeration.hasMore()) {
|
||||||
String groupDN = groupEnumeration.next().toString();
|
String groupDN = groupEnumeration.next().toString();
|
||||||
|
@ -700,6 +666,42 @@ public class LdapGroupsMapping
|
||||||
// does nothing in this provider of user to groups mapping
|
// does nothing in this provider of user to groups mapping
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) {
|
||||||
|
/*
|
||||||
|
* Normal garbage collection takes care of removing Context instances when
|
||||||
|
* they are no longer in use. Connections used by Context instances being
|
||||||
|
* garbage collected will be closed automatically. So in case connection is
|
||||||
|
* closed and gets CommunicationException, retry some times with new new
|
||||||
|
* DirContext/connection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Tracks the number of attempts made using the same LDAP server
|
||||||
|
int atemptsBeforeFailover = 1;
|
||||||
|
|
||||||
|
for (int attempt = 1; attempt <= numAttempts; attempt++,
|
||||||
|
atemptsBeforeFailover++) {
|
||||||
|
try {
|
||||||
|
return doGetGroups(user, groupHierarchyLevels);
|
||||||
|
} catch (AuthenticationException e) {
|
||||||
|
switchBindUser(e);
|
||||||
|
} catch (NamingException e) {
|
||||||
|
LOG.warn("Failed to get groups for user {} (attempt={}/{}) using {}. " +
|
||||||
|
"Exception: ", user, attempt, numAttempts, currentLdapUrl, e);
|
||||||
|
LOG.trace("TRACE", e);
|
||||||
|
|
||||||
|
if (failover(atemptsBeforeFailover, numAttemptsBeforeFailover)) {
|
||||||
|
atemptsBeforeFailover = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset ctx so that new DirContext can be created with new connection
|
||||||
|
this.ctx = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Configuration getConf() {
|
public synchronized Configuration getConf() {
|
||||||
return conf;
|
return conf;
|
||||||
|
|
|
@ -15,8 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.security;
|
package org.apache.hadoop.security;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides groups mapping for {@link UserGroupInformation} when the
|
* This class provides groups mapping for {@link UserGroupInformation} when the
|
||||||
|
@ -31,6 +33,19 @@ public class NullGroupsMapping implements GroupMappingServiceProvider {
|
||||||
public void cacheGroupsAdd(List<String> groups) {
|
public void cacheGroupsAdd(List<String> groups) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all various group memberships of a given user.
|
||||||
|
* Returns EMPTY set in case of non-existing user
|
||||||
|
*
|
||||||
|
* @param user User's name
|
||||||
|
* @return set of group memberships of user
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an empty list.
|
* Returns an empty list.
|
||||||
* @param user ignored
|
* @param user ignored
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.security;
|
package org.apache.hadoop.security;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
@ -25,7 +24,9 @@ import org.apache.hadoop.util.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,4 +89,18 @@ public class RuleBasedLdapGroupsMapping extends LdapGroupsMapping {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized Set<String> getGroupsSet(String user) {
|
||||||
|
Set<String> groups = super.getGroupsSet(user);
|
||||||
|
switch (rule) {
|
||||||
|
case TO_UPPER:
|
||||||
|
return groups.stream().map(StringUtils::toUpperCase).collect(
|
||||||
|
Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
case TO_LOWER:
|
||||||
|
return groups.stream().map(StringUtils::toLowerCase).collect(
|
||||||
|
Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
case NONE:
|
||||||
|
default:
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,11 @@
|
||||||
package org.apache.hadoop.security;
|
package org.apache.hadoop.security;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.LinkedList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -53,7 +56,7 @@ public class ShellBasedUnixGroupsMapping extends Configured
|
||||||
|
|
||||||
private long timeout = CommonConfigurationKeys.
|
private long timeout = CommonConfigurationKeys.
|
||||||
HADOOP_SECURITY_GROUP_SHELL_COMMAND_TIMEOUT_DEFAULT;
|
HADOOP_SECURITY_GROUP_SHELL_COMMAND_TIMEOUT_DEFAULT;
|
||||||
private static final List<String> EMPTY_GROUPS = new LinkedList<>();
|
private static final Set<String> EMPTY_GROUPS_SET = Collections.emptySet();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setConf(Configuration conf) {
|
public void setConf(Configuration conf) {
|
||||||
|
@ -94,7 +97,7 @@ public class ShellBasedUnixGroupsMapping extends Configured
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroups(String userName) throws IOException {
|
public List<String> getGroups(String userName) throws IOException {
|
||||||
return getUnixGroups(userName);
|
return new ArrayList(getUnixGroups(userName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,6 +118,11 @@ public class ShellBasedUnixGroupsMapping extends Configured
|
||||||
// does nothing in this provider of user to groups mapping
|
// does nothing in this provider of user to groups mapping
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String userName) throws IOException {
|
||||||
|
return getUnixGroups(userName);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a ShellCommandExecutor object using the user's name.
|
* Create a ShellCommandExecutor object using the user's name.
|
||||||
*
|
*
|
||||||
|
@ -192,44 +200,33 @@ public class ShellBasedUnixGroupsMapping extends Configured
|
||||||
* group is returned first.
|
* group is returned first.
|
||||||
* @throws IOException if encounter any error when running the command
|
* @throws IOException if encounter any error when running the command
|
||||||
*/
|
*/
|
||||||
private List<String> getUnixGroups(String user) throws IOException {
|
private Set<String> getUnixGroups(String user) throws IOException {
|
||||||
ShellCommandExecutor executor = createGroupExecutor(user);
|
ShellCommandExecutor executor = createGroupExecutor(user);
|
||||||
|
|
||||||
List<String> groups;
|
Set<String> groups;
|
||||||
try {
|
try {
|
||||||
executor.execute();
|
executor.execute();
|
||||||
groups = resolveFullGroupNames(executor.getOutput());
|
groups = resolveFullGroupNames(executor.getOutput());
|
||||||
} catch (ExitCodeException e) {
|
} catch (ExitCodeException e) {
|
||||||
if (handleExecutorTimeout(executor, user)) {
|
if (handleExecutorTimeout(executor, user)) {
|
||||||
return EMPTY_GROUPS;
|
return EMPTY_GROUPS_SET;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
groups = resolvePartialGroupNames(user, e.getMessage(),
|
groups = resolvePartialGroupNames(user, e.getMessage(),
|
||||||
executor.getOutput());
|
executor.getOutput());
|
||||||
} catch (PartialGroupNameException pge) {
|
} catch (PartialGroupNameException pge) {
|
||||||
LOG.warn("unable to return groups for user {}", user, pge);
|
LOG.warn("unable to return groups for user {}", user, pge);
|
||||||
return EMPTY_GROUPS;
|
return EMPTY_GROUPS_SET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
if (handleExecutorTimeout(executor, user)) {
|
if (handleExecutorTimeout(executor, user)) {
|
||||||
return EMPTY_GROUPS;
|
return EMPTY_GROUPS_SET;
|
||||||
} else {
|
} else {
|
||||||
// If its not an executor timeout, we should let the caller handle it
|
// If its not an executor timeout, we should let the caller handle it
|
||||||
throw ioe;
|
throw ioe;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove duplicated primary group
|
|
||||||
if (!Shell.WINDOWS) {
|
|
||||||
for (int i = 1; i < groups.size(); i++) {
|
|
||||||
if (groups.get(i).equals(groups.get(0))) {
|
|
||||||
groups.remove(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,13 +239,13 @@ public class ShellBasedUnixGroupsMapping extends Configured
|
||||||
* @return a linked list of group names
|
* @return a linked list of group names
|
||||||
* @throws PartialGroupNameException
|
* @throws PartialGroupNameException
|
||||||
*/
|
*/
|
||||||
private List<String> parsePartialGroupNames(String groupNames,
|
private Set<String> parsePartialGroupNames(String groupNames,
|
||||||
String groupIDs) throws PartialGroupNameException {
|
String groupIDs) throws PartialGroupNameException {
|
||||||
StringTokenizer nameTokenizer =
|
StringTokenizer nameTokenizer =
|
||||||
new StringTokenizer(groupNames, Shell.TOKEN_SEPARATOR_REGEX);
|
new StringTokenizer(groupNames, Shell.TOKEN_SEPARATOR_REGEX);
|
||||||
StringTokenizer idTokenizer =
|
StringTokenizer idTokenizer =
|
||||||
new StringTokenizer(groupIDs, Shell.TOKEN_SEPARATOR_REGEX);
|
new StringTokenizer(groupIDs, Shell.TOKEN_SEPARATOR_REGEX);
|
||||||
List<String> groups = new LinkedList<String>();
|
Set<String> groups = new LinkedHashSet<>();
|
||||||
while (nameTokenizer.hasMoreTokens()) {
|
while (nameTokenizer.hasMoreTokens()) {
|
||||||
// check for unresolvable group names.
|
// check for unresolvable group names.
|
||||||
if (!idTokenizer.hasMoreTokens()) {
|
if (!idTokenizer.hasMoreTokens()) {
|
||||||
|
@ -277,10 +274,10 @@ public class ShellBasedUnixGroupsMapping extends Configured
|
||||||
* @param userName the user's name
|
* @param userName the user's name
|
||||||
* @param errMessage error message from the shell command
|
* @param errMessage error message from the shell command
|
||||||
* @param groupNames the incomplete list of group names
|
* @param groupNames the incomplete list of group names
|
||||||
* @return a list of resolved group names
|
* @return a set of resolved group names
|
||||||
* @throws PartialGroupNameException if the resolution fails or times out
|
* @throws PartialGroupNameException if the resolution fails or times out
|
||||||
*/
|
*/
|
||||||
private List<String> resolvePartialGroupNames(String userName,
|
private Set<String> resolvePartialGroupNames(String userName,
|
||||||
String errMessage, String groupNames) throws PartialGroupNameException {
|
String errMessage, String groupNames) throws PartialGroupNameException {
|
||||||
// Exception may indicate that some group names are not resolvable.
|
// Exception may indicate that some group names are not resolvable.
|
||||||
// Shell-based implementation should tolerate unresolvable groups names,
|
// Shell-based implementation should tolerate unresolvable groups names,
|
||||||
|
@ -322,16 +319,16 @@ public class ShellBasedUnixGroupsMapping extends Configured
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Split group names into a linked list.
|
* Split group names into a set.
|
||||||
*
|
*
|
||||||
* @param groupNames a string representing the user's group names
|
* @param groupNames a string representing the user's group names
|
||||||
* @return a linked list of group names
|
* @return a set of group names
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected List<String> resolveFullGroupNames(String groupNames) {
|
protected Set<String> resolveFullGroupNames(String groupNames) {
|
||||||
StringTokenizer tokenizer =
|
StringTokenizer tokenizer =
|
||||||
new StringTokenizer(groupNames, Shell.TOKEN_SEPARATOR_REGEX);
|
new StringTokenizer(groupNames, Shell.TOKEN_SEPARATOR_REGEX);
|
||||||
List<String> groups = new LinkedList<String>();
|
Set<String> groups = new LinkedHashSet<>();
|
||||||
while (tokenizer.hasMoreTokens()) {
|
while (tokenizer.hasMoreTokens()) {
|
||||||
groups.add(tokenizer.nextToken());
|
groups.add(tokenizer.nextToken());
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ import java.security.PrivilegedAction;
|
||||||
import java.security.PrivilegedActionException;
|
import java.security.PrivilegedActionException;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
@ -1483,8 +1482,8 @@ public class UserGroupInformation {
|
||||||
* map that has the translation of usernames to groups.
|
* map that has the translation of usernames to groups.
|
||||||
*/
|
*/
|
||||||
private static class TestingGroups extends Groups {
|
private static class TestingGroups extends Groups {
|
||||||
private final Map<String, List<String>> userToGroupsMapping =
|
private final Map<String, Set<String>> userToGroupsMapping =
|
||||||
new HashMap<String,List<String>>();
|
new HashMap<>();
|
||||||
private Groups underlyingImplementation;
|
private Groups underlyingImplementation;
|
||||||
|
|
||||||
private TestingGroups(Groups underlyingImplementation) {
|
private TestingGroups(Groups underlyingImplementation) {
|
||||||
|
@ -1494,17 +1493,22 @@ public class UserGroupInformation {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroups(String user) throws IOException {
|
public List<String> getGroups(String user) throws IOException {
|
||||||
List<String> result = userToGroupsMapping.get(user);
|
return new ArrayList<>(getGroupsSet(user));
|
||||||
|
}
|
||||||
if (result == null) {
|
|
||||||
result = underlyingImplementation.getGroups(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
Set<String> result = userToGroupsMapping.get(user);
|
||||||
|
if (result == null) {
|
||||||
|
result = underlyingImplementation.getGroupsSet(user);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUserGroups(String user, String[] groups) {
|
private void setUserGroups(String user, String[] groups) {
|
||||||
userToGroupsMapping.put(user, Arrays.asList(groups));
|
Set<String> groupsSet = new LinkedHashSet<>();
|
||||||
|
Collections.addAll(groupsSet, groups);
|
||||||
|
userToGroupsMapping.put(user, groupsSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1563,11 +1567,11 @@ public class UserGroupInformation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPrimaryGroupName() throws IOException {
|
public String getPrimaryGroupName() throws IOException {
|
||||||
List<String> groups = getGroups();
|
Set<String> groupsSet = getGroupsSet();
|
||||||
if (groups.isEmpty()) {
|
if (groupsSet.isEmpty()) {
|
||||||
throw new IOException("There is no primary group for UGI " + this);
|
throw new IOException("There is no primary group for UGI " + this);
|
||||||
}
|
}
|
||||||
return groups.get(0);
|
return groupsSet.iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1680,21 +1684,24 @@ public class UserGroupInformation {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the group names for this user. {@link #getGroups()} is less
|
* Get the group names for this user. {@link #getGroupsSet()} is less
|
||||||
* expensive alternative when checking for a contained element.
|
* expensive alternative when checking for a contained element.
|
||||||
* @return the list of users with the primary group first. If the command
|
* @return the list of users with the primary group first. If the command
|
||||||
* fails, it returns an empty list.
|
* fails, it returns an empty list.
|
||||||
*/
|
*/
|
||||||
public String[] getGroupNames() {
|
public String[] getGroupNames() {
|
||||||
List<String> groups = getGroups();
|
Collection<String> groupsSet = getGroupsSet();
|
||||||
return groups.toArray(new String[groups.size()]);
|
return groupsSet.toArray(new String[groupsSet.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the group names for this user.
|
* Get the group names for this user. {@link #getGroupsSet()} is less
|
||||||
|
* expensive alternative when checking for a contained element.
|
||||||
* @return the list of users with the primary group first. If the command
|
* @return the list of users with the primary group first. If the command
|
||||||
* fails, it returns an empty list.
|
* fails, it returns an empty list.
|
||||||
|
* @deprecated Use {@link #getGroupsSet()} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public List<String> getGroups() {
|
public List<String> getGroups() {
|
||||||
ensureInitialized();
|
ensureInitialized();
|
||||||
try {
|
try {
|
||||||
|
@ -1705,6 +1712,21 @@ public class UserGroupInformation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the groups names for the user as a Set.
|
||||||
|
* @return the set of users with the primary group first. If the command
|
||||||
|
* fails, it returns an empty set.
|
||||||
|
*/
|
||||||
|
public Set<String> getGroupsSet() {
|
||||||
|
ensureInitialized();
|
||||||
|
try {
|
||||||
|
return groups.getGroupsSet(getShortUserName());
|
||||||
|
} catch (IOException ie) {
|
||||||
|
LOG.debug("Failed to get groups for user {}", getShortUserName(), ie);
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the username.
|
* Return the username.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
@ -231,8 +232,9 @@ public class AccessControlList implements Writable {
|
||||||
if (allAllowed || users.contains(ugi.getShortUserName())) {
|
if (allAllowed || users.contains(ugi.getShortUserName())) {
|
||||||
return true;
|
return true;
|
||||||
} else if (!groups.isEmpty()) {
|
} else if (!groups.isEmpty()) {
|
||||||
for (String group : ugi.getGroups()) {
|
Set<String> ugiGroups = ugi.getGroupsSet();
|
||||||
if (groups.contains(group)) {
|
for (String group : groups) {
|
||||||
|
if (ugiGroups.contains(group)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,8 +62,10 @@ import java.net.URL;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
@ -410,6 +412,13 @@ public class TestHttpServer extends HttpServerFunctionalTest {
|
||||||
public List<String> getGroups(String user) throws IOException {
|
public List<String> getGroups(String user) throws IOException {
|
||||||
return mapping.get(user);
|
return mapping.get(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
Set<String> result = new HashSet();
|
||||||
|
result.addAll(mapping.get(user));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,7 +22,9 @@ import static org.junit.Assert.assertTrue;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configurable;
|
import org.apache.hadoop.conf.Configurable;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
@ -87,13 +89,22 @@ public class TestCompositeGroupMapping {
|
||||||
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<String> toList(String group) {
|
protected List<String> toList(String group) {
|
||||||
if (group != null) {
|
if (group != null) {
|
||||||
return Arrays.asList(new String[] {group});
|
return Arrays.asList(new String[] {group});
|
||||||
}
|
}
|
||||||
return new ArrayList<String>();
|
return new ArrayList<String>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Set<String> toSet(String group) {
|
||||||
|
if (group != null) {
|
||||||
|
Set<String> result = new HashSet<>();
|
||||||
|
result.add(group);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return new HashSet<String>();
|
||||||
|
}
|
||||||
|
|
||||||
protected void checkTestConf(String expectedValue) {
|
protected void checkTestConf(String expectedValue) {
|
||||||
String configValue = getConf().get(PROVIDER_SPECIFIC_CONF_KEY);
|
String configValue = getConf().get(PROVIDER_SPECIFIC_CONF_KEY);
|
||||||
|
@ -106,32 +117,49 @@ public class TestCompositeGroupMapping {
|
||||||
private static class UserProvider extends GroupMappingProviderBase {
|
private static class UserProvider extends GroupMappingProviderBase {
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroups(String user) throws IOException {
|
public List<String> getGroups(String user) throws IOException {
|
||||||
|
return toList(getGroupInternal(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return toSet(getGroupInternal(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getGroupInternal(String user) throws IOException {
|
||||||
checkTestConf(PROVIDER_SPECIFIC_CONF_VALUE_FOR_USER);
|
checkTestConf(PROVIDER_SPECIFIC_CONF_VALUE_FOR_USER);
|
||||||
|
|
||||||
String group = null;
|
String group = null;
|
||||||
if (user.equals(john.name)) {
|
if (user.equals(john.name)) {
|
||||||
group = john.group;
|
group = john.group;
|
||||||
} else if (user.equals(jack.name)) {
|
} else if (user.equals(jack.name)) {
|
||||||
group = jack.group;
|
group = jack.group;
|
||||||
}
|
}
|
||||||
|
return group;
|
||||||
return toList(group);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ClusterProvider extends GroupMappingProviderBase {
|
private static class ClusterProvider extends GroupMappingProviderBase {
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroups(String user) throws IOException {
|
public List<String> getGroups(String user) throws IOException {
|
||||||
|
return toList(getGroupsInternal(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return toSet(getGroupsInternal(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getGroupsInternal(String user) throws IOException {
|
||||||
checkTestConf(PROVIDER_SPECIFIC_CONF_VALUE_FOR_CLUSTER);
|
checkTestConf(PROVIDER_SPECIFIC_CONF_VALUE_FOR_CLUSTER);
|
||||||
|
|
||||||
String group = null;
|
String group = null;
|
||||||
if (user.equals(hdfs.name)) {
|
if (user.equals(hdfs.name)) {
|
||||||
group = hdfs.group;
|
group = hdfs.group;
|
||||||
} else if (user.equals(jack.name)) { // jack has another group from clusterProvider
|
} else if (user.equals(jack.name)) { // jack has another group from clusterProvider
|
||||||
group = jack.group2;
|
group = jack.group2;
|
||||||
}
|
}
|
||||||
|
return group;
|
||||||
return toList(group);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,9 @@ import java.io.IOException;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
@ -75,7 +75,7 @@ public class TestGroupsCaching {
|
||||||
private static volatile CountDownLatch latch = null;
|
private static volatile CountDownLatch latch = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroups(String user) throws IOException {
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
TESTLOG.info("Getting groups for " + user);
|
TESTLOG.info("Getting groups for " + user);
|
||||||
delayIfNecessary();
|
delayIfNecessary();
|
||||||
|
|
||||||
|
@ -86,9 +86,14 @@ public class TestGroupsCaching {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blackList.contains(user)) {
|
if (blackList.contains(user)) {
|
||||||
return new LinkedList<String>();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
return new LinkedList<String>(allGroups);
|
return new LinkedHashSet<>(allGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getGroups(String user) throws IOException {
|
||||||
|
return new ArrayList<>(getGroupsSet(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -129,7 +134,7 @@ public class TestGroupsCaching {
|
||||||
TESTLOG.info("Resetting FakeGroupMapping");
|
TESTLOG.info("Resetting FakeGroupMapping");
|
||||||
blackList.clear();
|
blackList.clear();
|
||||||
allGroups.clear();
|
allGroups.clear();
|
||||||
requestCount = 0;
|
resetRequestCount();
|
||||||
getGroupsDelayMs = 0;
|
getGroupsDelayMs = 0;
|
||||||
throwException = false;
|
throwException = false;
|
||||||
latch = null;
|
latch = null;
|
||||||
|
@ -197,6 +202,12 @@ public class TestGroupsCaching {
|
||||||
throw new IOException("For test");
|
throw new IOException("For test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
requestCount++;
|
||||||
|
throw new IOException("For test");
|
||||||
|
}
|
||||||
|
|
||||||
public static int getRequestCount() {
|
public static int getRequestCount() {
|
||||||
return requestCount;
|
return requestCount;
|
||||||
}
|
}
|
||||||
|
@ -550,7 +561,7 @@ public class TestGroupsCaching {
|
||||||
FakeGroupMapping.clearBlackList();
|
FakeGroupMapping.clearBlackList();
|
||||||
|
|
||||||
// We make an initial request to populate the cache
|
// We make an initial request to populate the cache
|
||||||
groups.getGroups("me");
|
List<String> g1 = groups.getGroups("me");
|
||||||
|
|
||||||
// add another group
|
// add another group
|
||||||
groups.cacheGroupsAdd(Arrays.asList("grp3"));
|
groups.cacheGroupsAdd(Arrays.asList("grp3"));
|
||||||
|
|
|
@ -24,7 +24,9 @@ import org.mockito.Mockito;
|
||||||
|
|
||||||
import javax.naming.NamingException;
|
import javax.naming.NamingException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.apache.hadoop.security.RuleBasedLdapGroupsMapping
|
import static org.apache.hadoop.security.RuleBasedLdapGroupsMapping
|
||||||
.CONVERSION_RULE_KEY;
|
.CONVERSION_RULE_KEY;
|
||||||
|
@ -40,7 +42,7 @@ public class TestRuleBasedLdapGroupsMapping {
|
||||||
public void testGetGroupsToUpper() throws NamingException {
|
public void testGetGroupsToUpper() throws NamingException {
|
||||||
RuleBasedLdapGroupsMapping groupsMapping = Mockito.spy(
|
RuleBasedLdapGroupsMapping groupsMapping = Mockito.spy(
|
||||||
new RuleBasedLdapGroupsMapping());
|
new RuleBasedLdapGroupsMapping());
|
||||||
List<String> groups = new ArrayList<>();
|
Set<String> groups = new LinkedHashSet<>();
|
||||||
groups.add("group1");
|
groups.add("group1");
|
||||||
groups.add("group2");
|
groups.add("group2");
|
||||||
Mockito.doReturn(groups).when((LdapGroupsMapping) groupsMapping)
|
Mockito.doReturn(groups).when((LdapGroupsMapping) groupsMapping)
|
||||||
|
@ -61,7 +63,7 @@ public class TestRuleBasedLdapGroupsMapping {
|
||||||
public void testGetGroupsToLower() throws NamingException {
|
public void testGetGroupsToLower() throws NamingException {
|
||||||
RuleBasedLdapGroupsMapping groupsMapping = Mockito.spy(
|
RuleBasedLdapGroupsMapping groupsMapping = Mockito.spy(
|
||||||
new RuleBasedLdapGroupsMapping());
|
new RuleBasedLdapGroupsMapping());
|
||||||
List<String> groups = new ArrayList<>();
|
Set<String> groups = new LinkedHashSet<>();
|
||||||
groups.add("GROUP1");
|
groups.add("GROUP1");
|
||||||
groups.add("GROUP2");
|
groups.add("GROUP2");
|
||||||
Mockito.doReturn(groups).when((LdapGroupsMapping) groupsMapping)
|
Mockito.doReturn(groups).when((LdapGroupsMapping) groupsMapping)
|
||||||
|
@ -82,7 +84,7 @@ public class TestRuleBasedLdapGroupsMapping {
|
||||||
public void testGetGroupsInvalidRule() throws NamingException {
|
public void testGetGroupsInvalidRule() throws NamingException {
|
||||||
RuleBasedLdapGroupsMapping groupsMapping = Mockito.spy(
|
RuleBasedLdapGroupsMapping groupsMapping = Mockito.spy(
|
||||||
new RuleBasedLdapGroupsMapping());
|
new RuleBasedLdapGroupsMapping());
|
||||||
List<String> groups = new ArrayList<>();
|
Set<String> groups = new LinkedHashSet<>();
|
||||||
groups.add("group1");
|
groups.add("group1");
|
||||||
groups.add("GROUP2");
|
groups.add("GROUP2");
|
||||||
Mockito.doReturn(groups).when((LdapGroupsMapping) groupsMapping)
|
Mockito.doReturn(groups).when((LdapGroupsMapping) groupsMapping)
|
||||||
|
@ -93,7 +95,7 @@ public class TestRuleBasedLdapGroupsMapping {
|
||||||
conf.set(CONVERSION_RULE_KEY, "none");
|
conf.set(CONVERSION_RULE_KEY, "none");
|
||||||
groupsMapping.setConf(conf);
|
groupsMapping.setConf(conf);
|
||||||
|
|
||||||
Assert.assertEquals(groups, groupsMapping.getGroups("admin"));
|
Assert.assertEquals(groups, groupsMapping.getGroupsSet("admin"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,7 @@ import java.text.MessageFormat;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main class of HttpFSServer server.
|
* Main class of HttpFSServer server.
|
||||||
|
@ -288,7 +289,7 @@ public class HttpFSServer {
|
||||||
case INSTRUMENTATION: {
|
case INSTRUMENTATION: {
|
||||||
enforceRootPath(op.value(), path);
|
enforceRootPath(op.value(), path);
|
||||||
Groups groups = HttpFSServerWebApp.get().get(Groups.class);
|
Groups groups = HttpFSServerWebApp.get().get(Groups.class);
|
||||||
List<String> userGroups = groups.getGroups(user.getShortUserName());
|
Set<String> userGroups = groups.getGroupsSet(user.getShortUserName());
|
||||||
if (!userGroups.contains(HttpFSServerWebApp.get().getAdminGroup())) {
|
if (!userGroups.contains(HttpFSServerWebApp.get().getAdminGroup())) {
|
||||||
throw new AccessControlException(
|
throw new AccessControlException(
|
||||||
"User not in HttpFSServer admin group");
|
"User not in HttpFSServer admin group");
|
||||||
|
|
|
@ -22,10 +22,13 @@ import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
public interface Groups {
|
public interface Groups {
|
||||||
|
|
||||||
public List<String> getGroups(String user) throws IOException;
|
public List<String> getGroups(String user) throws IOException;
|
||||||
|
|
||||||
|
Set<String> getGroupsSet(String user) throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.hadoop.lib.util.ConfigurationUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
public class GroupsService extends BaseService implements Groups {
|
public class GroupsService extends BaseService implements Groups {
|
||||||
|
@ -50,9 +51,18 @@ public class GroupsService extends BaseService implements Groups {
|
||||||
return Groups.class;
|
return Groups.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #getGroupsSet(String user)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroups(String user) throws IOException {
|
public List<String> getGroups(String user) throws IOException {
|
||||||
return hGroups.getGroups(user);
|
return hGroups.getGroups(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return hGroups.getGroupsSet(user);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,9 +60,11 @@ import java.nio.charset.Charset;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
@ -170,6 +172,11 @@ public class TestHttpFSServer extends HFSTestCase {
|
||||||
return Arrays.asList(HadoopUsersConfTestHelper.getHadoopUserGroups(user));
|
return Arrays.asList(HadoopUsersConfTestHelper.getHadoopUserGroups(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return new HashSet<>(getGroups(user));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Configuration createHttpFSConf(boolean addDelegationTokenAuthHandler,
|
private Configuration createHttpFSConf(boolean addDelegationTokenAuthHandler,
|
||||||
|
|
|
@ -21,7 +21,9 @@ import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import org.apache.hadoop.security.GroupMappingServiceProvider;
|
import org.apache.hadoop.security.GroupMappingServiceProvider;
|
||||||
import org.apache.hadoop.test.HadoopUsersConfTestHelper;
|
import org.apache.hadoop.test.HadoopUsersConfTestHelper;
|
||||||
|
|
||||||
|
@ -47,4 +49,17 @@ public class DummyGroupMapping implements GroupMappingServiceProvider {
|
||||||
@Override
|
@Override
|
||||||
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
if (user.equals("root")) {
|
||||||
|
return Sets.newHashSet("admin");
|
||||||
|
} else if (user.equals("nobody")) {
|
||||||
|
return Sets.newHashSet("nobody");
|
||||||
|
} else {
|
||||||
|
String[] groups = HadoopUsersConfTestHelper.getHadoopUserGroups(user);
|
||||||
|
return (groups != null) ? Sets.newHashSet(groups) :
|
||||||
|
Collections.emptySet();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
package org.apache.hadoop.hdfs.server.federation.router;
|
package org.apache.hadoop.hdfs.server.federation.router;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -126,8 +124,7 @@ public class RouterPermissionChecker extends FSPermissionChecker {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is the user a member of the super group?
|
// Is the user a member of the super group?
|
||||||
List<String> groups = ugi.getGroups();
|
if (ugi.getGroupsSet().contains(superGroup)) {
|
||||||
if (groups.contains(superGroup)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ public abstract class MountTable extends BaseRecord {
|
||||||
// Set permission fields
|
// Set permission fields
|
||||||
UserGroupInformation ugi = NameNode.getRemoteUser();
|
UserGroupInformation ugi = NameNode.getRemoteUser();
|
||||||
record.setOwnerName(ugi.getShortUserName());
|
record.setOwnerName(ugi.getShortUserName());
|
||||||
String group = ugi.getGroups().isEmpty() ? ugi.getShortUserName()
|
String group = ugi.getGroupsSet().isEmpty() ? ugi.getShortUserName()
|
||||||
: ugi.getPrimaryGroupName();
|
: ugi.getPrimaryGroupName();
|
||||||
record.setGroupName(group);
|
record.setGroupName(group);
|
||||||
record.setMode(new FsPermission(
|
record.setMode(new FsPermission(
|
||||||
|
|
|
@ -45,6 +45,7 @@ import java.net.URL;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
@ -135,6 +136,8 @@ public class TestRouterRefreshSuperUserGroupsConfiguration {
|
||||||
when(ugi.getRealUser()).thenReturn(impersonator);
|
when(ugi.getRealUser()).thenReturn(impersonator);
|
||||||
when(ugi.getUserName()).thenReturn("victim");
|
when(ugi.getUserName()).thenReturn("victim");
|
||||||
when(ugi.getGroups()).thenReturn(Arrays.asList("groupVictim"));
|
when(ugi.getGroups()).thenReturn(Arrays.asList("groupVictim"));
|
||||||
|
when(ugi.getGroupsSet()).thenReturn(new LinkedHashSet<>(Arrays.asList(
|
||||||
|
"groupVictim")));
|
||||||
|
|
||||||
// Exception should be thrown before applying config
|
// Exception should be thrown before applying config
|
||||||
LambdaTestUtils.intercept(
|
LambdaTestUtils.intercept(
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package org.apache.hadoop.hdfs.server.federation.router;
|
package org.apache.hadoop.hdfs.server.federation.router;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.CommonConfigurationKeys;
|
import org.apache.hadoop.fs.CommonConfigurationKeys;
|
||||||
import org.apache.hadoop.fs.FileSystem;
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
|
@ -56,7 +57,9 @@ import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
@ -111,6 +114,16 @@ public class TestRouterUserMappings {
|
||||||
@Override
|
@Override
|
||||||
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
LOG.info("Getting groups in MockUnixGroupsMapping");
|
||||||
|
String g1 = user + (10 * i + 1);
|
||||||
|
String g2 = user + (10 * i + 2);
|
||||||
|
Set<String> s = Sets.newHashSet(g1, g2);
|
||||||
|
i++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -191,6 +204,10 @@ public class TestRouterUserMappings {
|
||||||
final List<String> groupNames2 = new ArrayList<>();
|
final List<String> groupNames2 = new ArrayList<>();
|
||||||
groupNames2.add("gr3");
|
groupNames2.add("gr3");
|
||||||
groupNames2.add("gr4");
|
groupNames2.add("gr4");
|
||||||
|
final Set<String> groupNamesSet1 = new LinkedHashSet<>();
|
||||||
|
groupNamesSet1.addAll(groupNames1);
|
||||||
|
final Set<String> groupNamesSet2 = new LinkedHashSet<>();
|
||||||
|
groupNamesSet2.addAll(groupNames2);
|
||||||
|
|
||||||
//keys in conf
|
//keys in conf
|
||||||
String userKeyGroups = DefaultImpersonationProvider.getTestProvider().
|
String userKeyGroups = DefaultImpersonationProvider.getTestProvider().
|
||||||
|
@ -222,6 +239,8 @@ public class TestRouterUserMappings {
|
||||||
// set groups for users
|
// set groups for users
|
||||||
when(ugi1.getGroups()).thenReturn(groupNames1);
|
when(ugi1.getGroups()).thenReturn(groupNames1);
|
||||||
when(ugi2.getGroups()).thenReturn(groupNames2);
|
when(ugi2.getGroups()).thenReturn(groupNames2);
|
||||||
|
when(ugi1.getGroupsSet()).thenReturn(groupNamesSet1);
|
||||||
|
when(ugi2.getGroupsSet()).thenReturn(groupNamesSet2);
|
||||||
|
|
||||||
// check before refresh
|
// check before refresh
|
||||||
LambdaTestUtils.intercept(AuthorizationException.class,
|
LambdaTestUtils.intercept(AuthorizationException.class,
|
||||||
|
|
|
@ -1082,8 +1082,7 @@ public class DataNode extends ReconfigurableBase
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is the user a member of the super group?
|
// Is the user a member of the super group?
|
||||||
List<String> groups = callerUgi.getGroups();
|
if (callerUgi.getGroupsSet().contains(supergroup)) {
|
||||||
if (groups.contains(supergroup)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Not a superuser.
|
// Not a superuser.
|
||||||
|
|
|
@ -103,7 +103,7 @@ public class FSPermissionChecker implements AccessControlEnforcer {
|
||||||
this.fsOwner = fsOwner;
|
this.fsOwner = fsOwner;
|
||||||
this.supergroup = supergroup;
|
this.supergroup = supergroup;
|
||||||
this.callerUgi = callerUgi;
|
this.callerUgi = callerUgi;
|
||||||
this.groups = callerUgi.getGroups();
|
this.groups = callerUgi.getGroupsSet();
|
||||||
user = callerUgi.getShortUserName();
|
user = callerUgi.getShortUserName();
|
||||||
isSuper = user.equals(fsOwner) || groups.contains(supergroup);
|
isSuper = user.equals(fsOwner) || groups.contains(supergroup);
|
||||||
this.attributeProvider = attributeProvider;
|
this.attributeProvider = attributeProvider;
|
||||||
|
|
|
@ -34,8 +34,11 @@ import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.FileSystem;
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
|
@ -84,6 +87,16 @@ public class TestRefreshUserMappings {
|
||||||
@Override
|
@Override
|
||||||
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) {
|
||||||
|
LOG.info("Getting groups in MockUnixGroupsMapping");
|
||||||
|
String g1 = user + (10 * i + 1);
|
||||||
|
String g2 = user + (10 * i + 2);
|
||||||
|
Set<String> s = Sets.newHashSet(g1, g2);
|
||||||
|
i++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -196,6 +209,8 @@ public class TestRefreshUserMappings {
|
||||||
// set groups for users
|
// set groups for users
|
||||||
when(ugi1.getGroups()).thenReturn(groupNames1);
|
when(ugi1.getGroups()).thenReturn(groupNames1);
|
||||||
when(ugi2.getGroups()).thenReturn(groupNames2);
|
when(ugi2.getGroups()).thenReturn(groupNames2);
|
||||||
|
when(ugi1.getGroupsSet()).thenReturn(new LinkedHashSet<>(groupNames1));
|
||||||
|
when(ugi2.getGroupsSet()).thenReturn(new LinkedHashSet<>(groupNames2));
|
||||||
|
|
||||||
|
|
||||||
// check before
|
// check before
|
||||||
|
|
|
@ -26,7 +26,9 @@ import java.security.PrivilegedExceptionAction;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.hadoop.HadoopIllegalArgumentException;
|
import org.apache.hadoop.HadoopIllegalArgumentException;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
@ -56,6 +58,7 @@ import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import org.apache.hadoop.security.authorize.AuthorizationException;
|
import org.apache.hadoop.security.authorize.AuthorizationException;
|
||||||
import org.apache.hadoop.yarn.logaggregation.AggregatedLogDeletionService;
|
import org.apache.hadoop.yarn.logaggregation.AggregatedLogDeletionService;
|
||||||
|
import org.mockito.internal.util.collections.Sets;
|
||||||
|
|
||||||
@RunWith(Parameterized.class)
|
@RunWith(Parameterized.class)
|
||||||
public class TestHSAdminServer {
|
public class TestHSAdminServer {
|
||||||
|
@ -91,6 +94,15 @@ public class TestHSAdminServer {
|
||||||
@Override
|
@Override
|
||||||
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
Set<String> result = new LinkedHashSet<>();
|
||||||
|
result.add(user + (10 * i + 1));
|
||||||
|
result.add(user + (10 * i +2));
|
||||||
|
i++;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Parameters
|
@Parameters
|
||||||
|
@ -189,6 +201,9 @@ public class TestHSAdminServer {
|
||||||
when(superUser.getUserName()).thenReturn("superuser");
|
when(superUser.getUserName()).thenReturn("superuser");
|
||||||
when(ugi.getGroups())
|
when(ugi.getGroups())
|
||||||
.thenReturn(Arrays.asList(new String[] { "group3" }));
|
.thenReturn(Arrays.asList(new String[] { "group3" }));
|
||||||
|
when(ugi.getGroupsSet())
|
||||||
|
.thenReturn(Sets.newSet("group3"));
|
||||||
|
|
||||||
when(ugi.getUserName()).thenReturn("regularUser");
|
when(ugi.getUserName()).thenReturn("regularUser");
|
||||||
|
|
||||||
// Set super user groups not to include groups of regularUser
|
// Set super user groups not to include groups of regularUser
|
||||||
|
|
|
@ -28,6 +28,7 @@ import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
@ -276,6 +277,11 @@ public class TestHsWebServicesAcls {
|
||||||
@Override
|
@Override
|
||||||
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MockJobForAcls implements Job {
|
private static class MockJobForAcls implements Job {
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class NetworkTagMappingJsonManager implements NetworkTagMappingManager {
|
||||||
container.getUser());
|
container.getUser());
|
||||||
List<Group> groups = this.networkTagMapping.getGroups();
|
List<Group> groups = this.networkTagMapping.getGroups();
|
||||||
for(Group group : groups) {
|
for(Group group : groups) {
|
||||||
if (userUGI.getGroups().contains(group.getGroupName())) {
|
if (userUGI.getGroupsSet().contains(group.getGroupName())) {
|
||||||
return group.getNetworkTagID();
|
return group.getNetworkTagID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,9 +303,9 @@ public class JavaSandboxLinuxContainerRuntime
|
||||||
private static List<String> getGroupPolicyFiles(Configuration conf,
|
private static List<String> getGroupPolicyFiles(Configuration conf,
|
||||||
String user) throws ContainerExecutionException {
|
String user) throws ContainerExecutionException {
|
||||||
Groups groups = Groups.getUserToGroupsMappingService(conf);
|
Groups groups = Groups.getUserToGroupsMappingService(conf);
|
||||||
List<String> userGroups;
|
Set<String> userGroups;
|
||||||
try {
|
try {
|
||||||
userGroups = groups.getGroups(user);
|
userGroups = groups.getGroupsSet(user);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ContainerExecutionException("Container user does not exist");
|
throw new ContainerExecutionException("Container user does not exist");
|
||||||
}
|
}
|
||||||
|
@ -330,11 +330,11 @@ public class JavaSandboxLinuxContainerRuntime
|
||||||
String whitelistGroup = configuration.get(
|
String whitelistGroup = configuration.get(
|
||||||
YarnConfiguration.YARN_CONTAINER_SANDBOX_WHITELIST_GROUP);
|
YarnConfiguration.YARN_CONTAINER_SANDBOX_WHITELIST_GROUP);
|
||||||
Groups groups = Groups.getUserToGroupsMappingService(configuration);
|
Groups groups = Groups.getUserToGroupsMappingService(configuration);
|
||||||
List<String> userGroups;
|
Set<String> userGroups;
|
||||||
boolean isWhitelisted = false;
|
boolean isWhitelisted = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
userGroups = groups.getGroups(username);
|
userGroups = groups.getGroupsSet(username);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ContainerExecutionException("Container user does not exist");
|
throw new ContainerExecutionException("Container user does not exist");
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.DOT;
|
import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.DOT;
|
||||||
import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.assureRoot;
|
import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.assureRoot;
|
||||||
|
@ -62,19 +62,19 @@ public class PrimaryGroupPlacementRule extends FSPlacementRule {
|
||||||
|
|
||||||
// All users should have at least one group the primary group. If no groups
|
// All users should have at least one group the primary group. If no groups
|
||||||
// are returned then there is a real issue.
|
// are returned then there is a real issue.
|
||||||
final List<String> groupList;
|
final Set<String> groupSet;
|
||||||
try {
|
try {
|
||||||
groupList = groupProvider.getGroups(user);
|
groupSet = groupProvider.getGroupsSet(user);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new YarnException("Group resolution failed", ioe);
|
throw new YarnException("Group resolution failed", ioe);
|
||||||
}
|
}
|
||||||
if (groupList.isEmpty()) {
|
if (groupSet.isEmpty()) {
|
||||||
LOG.error("Group placement rule failed: No groups returned for user {}",
|
LOG.error("Group placement rule failed: No groups returned for user {}",
|
||||||
user);
|
user);
|
||||||
throw new YarnException("No groups returned for user " + user);
|
throw new YarnException("No groups returned for user " + user);
|
||||||
}
|
}
|
||||||
|
|
||||||
String cleanGroup = cleanName(groupList.get(0));
|
String cleanGroup = cleanName(groupSet.iterator().next());
|
||||||
String queueName;
|
String queueName;
|
||||||
PlacementRule parentRule = getParentRule();
|
PlacementRule parentRule = getParentRule();
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,8 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.DOT;
|
import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.DOT;
|
||||||
import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.assureRoot;
|
import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.assureRoot;
|
||||||
|
@ -65,9 +66,9 @@ public class SecondaryGroupExistingPlacementRule extends FSPlacementRule {
|
||||||
|
|
||||||
// All users should have at least one group the primary group. If no groups
|
// All users should have at least one group the primary group. If no groups
|
||||||
// are returned then there is a real issue.
|
// are returned then there is a real issue.
|
||||||
final List<String> groupList;
|
final Set<String> groupSet;
|
||||||
try {
|
try {
|
||||||
groupList = groupProvider.getGroups(user);
|
groupSet = groupProvider.getGroupsSet(user);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new YarnException("Group resolution failed", ioe);
|
throw new YarnException("Group resolution failed", ioe);
|
||||||
}
|
}
|
||||||
|
@ -90,8 +91,9 @@ public class SecondaryGroupExistingPlacementRule extends FSPlacementRule {
|
||||||
parentQueue);
|
parentQueue);
|
||||||
}
|
}
|
||||||
// now check the groups inside the parent
|
// now check the groups inside the parent
|
||||||
for (int i = 1; i < groupList.size(); i++) {
|
Iterator<String> it = groupSet.iterator();
|
||||||
String group = cleanName(groupList.get(i));
|
while (it.hasNext()) {
|
||||||
|
String group = cleanName(it.next());
|
||||||
String queueName =
|
String queueName =
|
||||||
parentQueue == null ? assureRoot(group) : parentQueue + DOT + group;
|
parentQueue == null ? assureRoot(group) : parentQueue + DOT + group;
|
||||||
if (configuredQueue(queueName)) {
|
if (configuredQueue(queueName)) {
|
||||||
|
|
|
@ -20,7 +20,9 @@ package org.apache.hadoop.yarn.server.resourcemanager.placement;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience.Private;
|
import org.apache.hadoop.classification.InterfaceAudience.Private;
|
||||||
|
@ -74,18 +76,21 @@ public class UserGroupMappingPlacementRule extends PlacementRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPrimaryGroup(String user) throws IOException {
|
private String getPrimaryGroup(String user) throws IOException {
|
||||||
return groups.getGroups(user).get(0);
|
return groups.getGroupsSet(user).iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getSecondaryGroup(String user) throws IOException {
|
private String getSecondaryGroup(String user) throws IOException {
|
||||||
List<String> groupsList = groups.getGroups(user);
|
Set<String> groupsSet = groups.getGroupsSet(user);
|
||||||
String secondaryGroup = null;
|
String secondaryGroup = null;
|
||||||
// Traverse all secondary groups (as there could be more than one
|
// Traverse all secondary groups (as there could be more than one
|
||||||
// and position is not guaranteed) and ensure there is queue with
|
// and position is not guaranteed) and ensure there is queue with
|
||||||
// the same name
|
// the same name
|
||||||
for (int i = 1; i < groupsList.size(); i++) {
|
Iterator<String> it = groupsSet.iterator();
|
||||||
if (this.queueManager.getQueue(groupsList.get(i)) != null) {
|
it.next();
|
||||||
secondaryGroup = groupsList.get(i);
|
while (it.hasNext()) {
|
||||||
|
String group = it.next();
|
||||||
|
if (this.queueManager.getQueue(group) != null) {
|
||||||
|
secondaryGroup = group;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +185,7 @@ public class UserGroupMappingPlacementRule extends PlacementRule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mapping.getType().equals(MappingType.GROUP)) {
|
if (mapping.getType().equals(MappingType.GROUP)) {
|
||||||
for (String userGroups : groups.getGroups(user)) {
|
for (String userGroups : groups.getGroupsSet(user)) {
|
||||||
if (userGroups.equals(mapping.getSource())) {
|
if (userGroups.equals(mapping.getSource())) {
|
||||||
if (mapping.getQueue().equals(CURRENT_USER_MAPPING)) {
|
if (mapping.getQueue().equals(CURRENT_USER_MAPPING)) {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
|
|
|
@ -1459,6 +1459,11 @@ public class TestRMAdminService {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return ImmutableSet.copyOf(group);
|
||||||
|
}
|
||||||
|
|
||||||
public static void updateGroups() {
|
public static void updateGroups() {
|
||||||
group.clear();
|
group.clear();
|
||||||
group.add("test_group_D");
|
group.add("test_group_D");
|
||||||
|
|
|
@ -18,17 +18,20 @@
|
||||||
|
|
||||||
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair;
|
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.apache.hadoop.security.GroupMappingServiceProvider;
|
import org.apache.hadoop.security.GroupMappingServiceProvider;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class PeriodGroupsMapping implements GroupMappingServiceProvider {
|
public class PeriodGroupsMapping implements GroupMappingServiceProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroups(String user) {
|
public List<String> getGroups(String user) {
|
||||||
return Arrays.asList(user + ".group", user + "subgroup1", user + "subgroup2");
|
return Arrays.asList(user + ".group", user + "subgroup1",
|
||||||
|
user + "subgroup2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -41,4 +44,9 @@ public class PeriodGroupsMapping implements GroupMappingServiceProvider {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return ImmutableSet.of(user + ".group", user + "subgroup1",
|
||||||
|
user + "subgroup2");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,9 @@ import org.apache.hadoop.security.GroupMappingServiceProvider;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group Mapping class used for test cases. Returns only primary group of the
|
* Group Mapping class used for test cases. Returns only primary group of the
|
||||||
|
@ -44,4 +46,9 @@ public class PrimaryGroupMapping implements GroupMappingServiceProvider {
|
||||||
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return Collections.singleton(user + "group");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,9 @@ package org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import org.apache.hadoop.security.GroupMappingServiceProvider;
|
import org.apache.hadoop.security.GroupMappingServiceProvider;
|
||||||
|
|
||||||
public class SimpleGroupsMapping implements GroupMappingServiceProvider {
|
public class SimpleGroupsMapping implements GroupMappingServiceProvider {
|
||||||
|
@ -45,4 +47,10 @@ public class SimpleGroupsMapping implements GroupMappingServiceProvider {
|
||||||
@Override
|
@Override
|
||||||
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
public void cacheGroupsAdd(List<String> groups) throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getGroupsSet(String user) throws IOException {
|
||||||
|
return ImmutableSet.of(user + "group", user + "subgroup1",
|
||||||
|
user + "subgroup2");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue