Skip to content

Commit dfdc6d6

Browse files
YARN-9886. Queue mapping based on userid passed through application tag. Contributed by Julia Kinga Marton
1 parent ea8ffac commit dfdc6d6

File tree

6 files changed

+306
-4
lines changed

6 files changed

+306
-4
lines changed

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,6 +1859,14 @@ public static boolean isAclEnabled(Configuration conf) {
18591859
"container-monitor.procfs-tree.smaps-based-rss.enabled";
18601860
public static final boolean DEFAULT_PROCFS_USE_SMAPS_BASED_RSS_ENABLED =
18611861
false;
1862+
private static final String APPLICATION_TAG_BASED_PLACEMENT_PREFIX =
1863+
"application-tag-based-placement";
1864+
public static final String APPLICATION_TAG_BASED_PLACEMENT_ENABLED =
1865+
APPLICATION_TAG_BASED_PLACEMENT_PREFIX + ".enable";
1866+
public static final boolean DEFAULT_APPLICATION_TAG_BASED_PLACEMENT_ENABLED =
1867+
false;
1868+
public static final String APPLICATION_TAG_BASED_PLACEMENT_USER_WHITELIST =
1869+
APPLICATION_TAG_BASED_PLACEMENT_PREFIX + ".username.whitelist";
18621870

18631871
/** Enable/disable container metrics. */
18641872
@Private

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/ApplicationSubmissionContextPBImpl.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@
2121
import java.util.ArrayList;
2222
import java.util.Collections;
2323
import java.util.HashMap;
24-
import java.util.HashSet;
2524
import java.util.Iterator;
2625
import java.util.List;
2726
import java.util.Map;
2827
import java.util.Set;
28+
import java.util.TreeSet;
2929

3030
import org.apache.hadoop.classification.InterfaceAudience.Private;
3131
import org.apache.hadoop.classification.InterfaceStability.Unstable;
@@ -247,7 +247,7 @@ private void initApplicationTags() {
247247
return;
248248
}
249249
ApplicationSubmissionContextProtoOrBuilder p = viaProto ? proto : builder;
250-
this.applicationTags = new HashSet<String>();
250+
this.applicationTags = new TreeSet<>();
251251
this.applicationTags.addAll(p.getApplicationTagsList());
252252
}
253253

@@ -305,7 +305,7 @@ public synchronized void setApplicationTags(Set<String> tags) {
305305
}
306306
checkTags(tags);
307307
// Convert applicationTags to lower case and add
308-
this.applicationTags = new HashSet<String>();
308+
this.applicationTags = new TreeSet<>();
309309
for (String tag : tags) {
310310
this.applicationTags.add(StringUtils.toLowerCase(tag));
311311
}

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,26 @@
12881288
<value>false</value>
12891289
</property>
12901290

1291+
<property>
1292+
<description>
1293+
Whether to enable application placement based on user ID passed via
1294+
application tags. When it is enabled, u=&lt;userId&gt; pattern will be checked
1295+
and if found, the application will be placed onto the found user's queue,
1296+
if the original user has enough rights on the passed user's queue.
1297+
</description>
1298+
<name>application-tag-based-placement.enable</name>
1299+
<value>false</value>
1300+
</property>
1301+
1302+
<property>
1303+
<description>
1304+
Comma separated list of users who can use the application tag based
1305+
placement, if it is enabled.
1306+
</description>
1307+
<name>application-tag-based-placement.username.whitelist</name>
1308+
<value></value>
1309+
</property>
1310+
12911311
<property>
12921312
<description>How long to keep aggregation logs before deleting them. -1 disables.
12931313
Be careful set this too small and you will spam the name node.</description>

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAppManager.java

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,10 @@ ApplicationPlacementContext placeApplication(
889889
ApplicationPlacementContext placementContext = null;
890890
if (placementManager != null) {
891891
try {
892-
placementContext = placementManager.placeApplication(context, user);
892+
String usernameUsedForPlacement =
893+
getUserNameForPlacement(user, context, placementManager);
894+
placementContext = placementManager
895+
.placeApplication(context, usernameUsedForPlacement);
893896
} catch (YarnException e) {
894897
// Placement could also fail if the user doesn't exist in system
895898
// skip if the user is not found during recovery.
@@ -916,6 +919,80 @@ ApplicationPlacementContext placeApplication(
916919
return placementContext;
917920
}
918921

922+
@VisibleForTesting
923+
protected String getUserNameForPlacement(final String user,
924+
final ApplicationSubmissionContext context,
925+
final PlacementManager placementManager) throws YarnException {
926+
927+
boolean applicationTagBasedPlacementEnabled = conf
928+
.getBoolean(YarnConfiguration.APPLICATION_TAG_BASED_PLACEMENT_ENABLED,
929+
YarnConfiguration.DEFAULT_APPLICATION_TAG_BASED_PLACEMENT_ENABLED);
930+
931+
String usernameUsedForPlacement = user;
932+
if (!applicationTagBasedPlacementEnabled) {
933+
return usernameUsedForPlacement;
934+
}
935+
if (!isWhitelistedUser(user, conf)) {
936+
LOG.warn("User '{}' is not allowed to do placement based " +
937+
"on application tag", user);
938+
return usernameUsedForPlacement;
939+
}
940+
LOG.debug("Application tag based placement is enabled, checking for " +
941+
"userId in the application tag");
942+
Set<String> applicationTags = context.getApplicationTags();
943+
String userNameFromAppTag = getUserNameFromApplicationTag(applicationTags);
944+
if (userNameFromAppTag != null) {
945+
LOG.debug("Found userId '{}' in application tag", userNameFromAppTag);
946+
UserGroupInformation callerUGI = UserGroupInformation
947+
.createRemoteUser(userNameFromAppTag);
948+
// check if the actual user has rights to submit application to the
949+
// user's queue from the application tag
950+
String queue = placementManager
951+
.placeApplication(context, usernameUsedForPlacement).getQueue();
952+
if (callerUGI != null && scheduler
953+
.checkAccess(callerUGI, QueueACL.SUBMIT_APPLICATIONS, queue)) {
954+
usernameUsedForPlacement = userNameFromAppTag;
955+
} else {
956+
LOG.warn("User '{}' from application tag does not have access to " +
957+
" queue '{}'. " + "The placement is done for user '{}'",
958+
userNameFromAppTag, queue, user);
959+
}
960+
} else {
961+
LOG.warn("userId was not found in application tags");
962+
}
963+
return usernameUsedForPlacement;
964+
}
965+
966+
private boolean isWhitelistedUser(final String user,
967+
final Configuration config) {
968+
String[] userWhitelist = config.getStrings(YarnConfiguration
969+
.APPLICATION_TAG_BASED_PLACEMENT_USER_WHITELIST);
970+
if (userWhitelist == null || userWhitelist.length == 0) {
971+
return false;
972+
}
973+
for (String s: userWhitelist) {
974+
if (s.equals(user)) {
975+
return true;
976+
}
977+
}
978+
return false;
979+
}
980+
981+
private String getUserNameFromApplicationTag(Set<String> applicationTags) {
982+
String userIdPrefix = "u=";
983+
for (String tag: applicationTags) {
984+
if (tag.startsWith(userIdPrefix)) {
985+
String[] userIdTag = tag.split("=");
986+
if (userIdTag.length == 2) {
987+
return userIdTag[1];
988+
} else {
989+
LOG.warn("Found wrongly qualified username in tag");
990+
}
991+
}
992+
}
993+
return null;
994+
}
995+
919996
private void copyPlacementQueueToSubmissionContext(
920997
ApplicationPlacementContext placementContext,
921998
ApplicationSubmissionContext context) {

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/AppManagerTestBase.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.apache.hadoop.yarn.api.records.ApplicationId;
3030
import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
3131
import org.apache.hadoop.yarn.exceptions.YarnException;
32+
import org.apache.hadoop.yarn.server.resourcemanager.placement.PlacementManager;
3233
import org.apache.hadoop.yarn.server.resourcemanager.recovery.RMStateStore;
3334
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp;
3435
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.YarnScheduler;
@@ -103,5 +104,11 @@ public void submitApplication(
103104
super.submitApplication(submissionContext, System.currentTimeMillis(),
104105
user);
105106
}
107+
108+
public String getUserNameForPlacement(final String user,
109+
final ApplicationSubmissionContext context,
110+
final PlacementManager placementManager) throws YarnException {
111+
return super.getUserNameForPlacement(user, context, placementManager);
112+
}
106113
}
107114
}

0 commit comments

Comments
 (0)