diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAppManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAppManager.java
index 783fab0bc05..a8763fa3bd3 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAppManager.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAppManager.java
@@ -68,6 +68,8 @@
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.YarnScheduler;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CSQueue;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FSQueue;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
import org.apache.hadoop.yarn.server.utils.BuilderUtils;
import org.apache.hadoop.yarn.util.Times;
@@ -412,7 +414,8 @@ private RMAppImpl createAndPopulateNewRMApp(
// We only replace the queue when it's a new application
if (!isRecovery) {
- replaceQueueFromPlacementContext(placementContext, submissionContext);
+ copyPlacementQueueToSubmissionContext(placementContext,
+ submissionContext);
// fail the submission if configured application timeout value is invalid
RMServerUtils.validateApplicationTimeouts(
@@ -437,38 +440,60 @@ private RMAppImpl createAndPopulateNewRMApp(
submissionContext.setPriority(appPriority);
}
- // Since FairScheduler queue mapping is done inside scheduler,
- // if FairScheduler is used and the queue doesn't exist, we should not
- // fail here because queue will be created inside FS. Ideally, FS queue
- // mapping should be done outside scheduler too like CS.
- // For now, exclude FS for the acl check.
- if (!isRecovery && YarnConfiguration.isAclEnabled(conf)
- && scheduler instanceof CapacityScheduler) {
- String queueName = submissionContext.getQueue();
- String appName = submissionContext.getApplicationName();
- CSQueue csqueue = ((CapacityScheduler) scheduler).getQueue(queueName);
-
- if (csqueue == null && placementContext != null) {
- //could be an auto created queue through queue mapping. Validate
- // parent queue exists and has valid acls
- String parentQueueName = placementContext.getParentQueue();
- csqueue = ((CapacityScheduler) scheduler).getQueue(parentQueueName);
- }
+ if (!isRecovery && YarnConfiguration.isAclEnabled(conf)) {
+ if (scheduler instanceof CapacityScheduler) {
+ String queueName = submissionContext.getQueue();
+ String appName = submissionContext.getApplicationName();
+ CSQueue csqueue = ((CapacityScheduler) scheduler).getQueue(queueName);
+
+ if (csqueue == null && placementContext != null) {
+ //could be an auto created queue through queue mapping. Validate
+ // parent queue exists and has valid acls
+ String parentQueueName = placementContext.getParentQueue();
+ csqueue = ((CapacityScheduler) scheduler).getQueue(parentQueueName);
+ }
- if (csqueue != null
- && !authorizer.checkPermission(
- new AccessRequest(csqueue.getPrivilegedEntity(), userUgi,
- SchedulerUtils.toAccessType(QueueACL.SUBMIT_APPLICATIONS),
- applicationId.toString(), appName, Server.getRemoteAddress(),
- null))
- && !authorizer.checkPermission(
- new AccessRequest(csqueue.getPrivilegedEntity(), userUgi,
- SchedulerUtils.toAccessType(QueueACL.ADMINISTER_QUEUE),
- applicationId.toString(), appName, Server.getRemoteAddress(),
- null))) {
- throw RPCUtil.getRemoteException(new AccessControlException(
- "User " + user + " does not have permission to submit "
- + applicationId + " to queue " + submissionContext.getQueue()));
+ if (csqueue != null
+ && !authorizer.checkPermission(
+ new AccessRequest(csqueue.getPrivilegedEntity(), userUgi,
+ SchedulerUtils.toAccessType(QueueACL.SUBMIT_APPLICATIONS),
+ applicationId.toString(), appName, Server.getRemoteAddress(),
+ null))
+ && !authorizer.checkPermission(
+ new AccessRequest(csqueue.getPrivilegedEntity(), userUgi,
+ SchedulerUtils.toAccessType(QueueACL.ADMINISTER_QUEUE),
+ applicationId.toString(), appName, Server.getRemoteAddress(),
+ null))) {
+ throw RPCUtil.getRemoteException(new AccessControlException(
+ "User " + user + " does not have permission to submit "
+ + applicationId + " to queue "
+ + submissionContext.getQueue()));
+ }
+ }
+ if (scheduler instanceof FairScheduler) {
+ // if we have not placed the app just skip this, the submit will be
+ // rejected in the scheduler.
+ if (placementContext != null) {
+ // The queue might not be created yet. Walk up the tree to check the
+ // parent ACL. The queueName is assured root which always exists
+ String queueName = submissionContext.getQueue();
+ FSQueue queue = ((FairScheduler) scheduler).getQueueManager().
+ getQueue(queueName);
+ while (queue == null) {
+ int sepIndex = queueName.lastIndexOf(".");
+ queueName = queueName.substring(0, sepIndex);
+ queue = ((FairScheduler) scheduler).getQueueManager().
+ getQueue(queueName);
+ }
+ if (!queue.hasAccess(QueueACL.SUBMIT_APPLICATIONS, userUgi) &&
+ !queue.hasAccess(QueueACL.ADMINISTER_QUEUE, userUgi)) {
+ throw RPCUtil.getRemoteException(new AccessControlException(
+ "User " + user + " does not have permission to submit "
+ + applicationId + " to queue " +
+ submissionContext.getQueue() +
+ " denied by ACL for queue " + queueName));
+ }
+ }
}
}
@@ -835,34 +860,39 @@ ApplicationPlacementContext placeApplication(
// Placement could also fail if the user doesn't exist in system
// skip if the user is not found during recovery.
if (isRecovery) {
- LOG.warn("PlaceApplication failed,skipping on recovery of rm");
+ LOG.warn("Application placement failed for user " + user +
+ " and application " + context.getApplicationId() +
+ ", skipping placement on recovery of rm");
+ LOG.debug("Exception that caused the placement failure", e);
return placementContext;
}
throw e;
}
}
- if (placementContext == null && (context.getQueue() == null) || context
- .getQueue().isEmpty()) {
+ // The submission context when created often has a queue set. In case of
+ // the FairScheduler a null placement context is still considered as a
+ // failure, even when a queue is provided on submit. This case handled in
+ // the scheduler.
+ if (placementContext == null && (context.getQueue() == null) ||
+ context.getQueue().isEmpty()) {
String msg = "Failed to place application " + context.getApplicationId()
- + " to queue and specified " + "queue is invalid : " + context
- .getQueue();
+ + " in a queue and submit context queue is null or empty";
LOG.error(msg);
throw new YarnException(msg);
}
return placementContext;
}
- void replaceQueueFromPlacementContext(
+ private void copyPlacementQueueToSubmissionContext(
ApplicationPlacementContext placementContext,
ApplicationSubmissionContext context) {
- // Set it to ApplicationSubmissionContext
- //apply queue mapping only to new application submissions
+ // Set the queue from the placement in the ApplicationSubmissionContext
+ // Placement rule are only considered for new applications
if (placementContext != null && !StringUtils.equalsIgnoreCase(
context.getQueue(), placementContext.getQueue())) {
- LOG.info("Placed application=" + context.getApplicationId() +
- " to queue=" + placementContext.getQueue() + ", original queue="
- + context
- .getQueue());
+ LOG.info("Placed application with ID " + context.getApplicationId() +
+ " in queue: " + placementContext.getQueue() +
+ ", original submission queue was: " + context.getQueue());
context.setQueue(placementContext.getQueue());
}
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/DefaultPlacementRule.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/DefaultPlacementRule.java
new file mode 100644
index 00000000000..d462ad8b1a3
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/DefaultPlacementRule.java
@@ -0,0 +1,134 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.yarn.server.resourcemanager.placement;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FSQueue;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.QueueManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+
+import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.assureRoot;
+import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.isValidQueueName;
+
+/**
+ * Places apps in the specified default queue. If no default queue is
+ * specified the app is placed in root.default queue.
+ */
+public class DefaultPlacementRule extends PlacementRule {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(DefaultPlacementRule.class);
+
+ private QueueManager queueManager;
+ @VisibleForTesting
+ public String defaultQueueName;
+
+ /**
+ * Create a new rule from the xml config.
+ * @param conf An xml element from the {@link FairScheduler#conf}
+ */
+ public DefaultPlacementRule(Element conf) {
+ // Default create for this rule is true
+ createQueue = true;
+ // No config can be set when no policy is defined and we use defaults
+ if (conf != null) {
+ String create = conf.getAttribute("create");
+ if (create != null && !create.isEmpty()) {
+ createQueue = Boolean.parseBoolean(create);
+ }
+ defaultQueueName = conf.getAttribute("queue");
+ }
+ // The queue name does not have to be set and we really use "default"
+ if (defaultQueueName == null || defaultQueueName.isEmpty()) {
+ defaultQueueName = assureRoot(YarnConfiguration.DEFAULT_QUEUE_NAME);
+ } else {
+ defaultQueueName = assureRoot(defaultQueueName);
+ }
+ LOG.debug("Default rule instantiated with queue name: {}, " +
+ "and create flag: {}", defaultQueueName, createQueue);
+ }
+
+ /**
+ * Create a new rule just setting the create flag.
+ * @param create String form of the boolean flag, ignored by the rule.
+ */
+ public DefaultPlacementRule(boolean create) {
+ createQueue = create;
+ // No config so fall back to the real default.
+ defaultQueueName = assureRoot(YarnConfiguration.DEFAULT_QUEUE_NAME);
+ LOG.debug("Default rule instantiated with default queue name: {}, " +
+ "and create flag: {}", defaultQueueName, createQueue);
+ }
+
+ @Override
+ public boolean initialize(ResourceScheduler scheduler) throws IOException {
+ if (!(scheduler instanceof FairScheduler)) {
+ LOG.error("Default rule configured for wrong scheduler type.");
+ throw new IOException(
+ "Default rule can only be configured for the FairScheduler");
+ }
+ // A queue read from the config could be illegal check it
+ if (!isValidQueueName(defaultQueueName)) {
+ LOG.error("Default rule configured with an illegal queue name: '{}'",
+ defaultQueueName);
+ throw new IOException(
+ "Default rule configured with an illegal queue name: '" +
+ defaultQueueName + "'.");
+ }
+ if (getParentRule() != null) {
+ LOG.error("You cannot configure a parent rule for the Default rule.");
+ throw new IOException(
+ "Parent rule should not be configured for Default rule.");
+ }
+
+ FairScheduler fs = (FairScheduler) scheduler;
+ queueManager = fs.getQueueManager();
+
+ return true;
+ }
+
+ @Override
+ public ApplicationPlacementContext getPlacementForApp(
+ ApplicationSubmissionContext asc, String user) {
+
+ // If we can create the queue in the rule or the queue exists return it
+ if (createQueue || configuredQueue(defaultQueueName)) {
+ return new ApplicationPlacementContext(defaultQueueName);
+ }
+ return null;
+ }
+
+ /**
+ * Check if the queue exists and is part of the configuration i.e. not
+ * a {@link FSQueue#isDynamic()} queue.
+ * @param queueName name of the queue to check
+ * @return true if the queue exists and is a "configured" queue
+ */
+ private boolean configuredQueue(String queueName) {
+ FSQueue queue = queueManager.getQueue(queueName);
+ return (queue != null && !queue.isDynamic());
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/FairQueuePlacementUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/FairQueuePlacementUtils.java
new file mode 100644
index 00000000000..6e59d57589a
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/FairQueuePlacementUtils.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.yarn.server.resourcemanager.placement;
+
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairSchedulerUtilities;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility methods used by Fair scheduler placement rules.
+ * {@link
+ * org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler}
+ */
+public final class FairQueuePlacementUtils {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(QueuePlacementRuleUtils.class);
+
+ private static final String ROOT_QUEUE = "root";
+ // Constants for name clean up and hierarchy checks
+ private static final String DOT_REPLACEMENT = "_dot_";
+ protected static final String DOT = ".";
+
+ private FairQueuePlacementUtils() {
+ }
+
+ /**
+ * Replace the periods in the username or group name with "_dot_" and
+ * remove trailing and leading whitespace.
+ *
+ * @param name The name to clean
+ * @return The name with {@link #DOT} replaced with {@link #DOT_REPLACEMENT}
+ */
+ protected static String cleanName(String name) {
+ name = FairSchedulerUtilities.trimQueueName(name);
+ if (name.contains(DOT)) {
+ String converted = name.replaceAll("\\.", DOT_REPLACEMENT);
+ LOG.warn("Name {} is converted to {} when it is used as a queue name.",
+ name, converted);
+ return converted;
+ } else {
+ return name;
+ }
+ }
+
+ /**
+ * Assure root prefix for a queue name.
+ *
+ * @param queueName The queue name to check for the root prefix
+ * @return The root prefixed queue name
+ */
+ protected static String assureRoot(String queueName) {
+ if (queueName != null && !queueName.isEmpty()) {
+ if (!queueName.startsWith(ROOT_QUEUE + DOT) &&
+ !queueName.equals(ROOT_QUEUE)) {
+ queueName = ROOT_QUEUE + DOT + queueName;
+ }
+ } else {
+ LOG.warn("AssureRoot: queueName is empty or null.");
+ }
+ return queueName;
+ }
+
+ /**
+ * Validate the queue name: it may not start or end with a {@link #DOT}.
+ *
+ * @param queueName The queue name to validate
+ * @return false if the queue name starts or ends with a
+ * {@link #DOT}, true
+ */
+ protected static boolean isValidQueueName(String queueName) {
+ if (queueName != null) {
+ if (queueName.equals(FairSchedulerUtilities.trimQueueName(queueName)) &&
+ !queueName.startsWith(DOT) &&
+ !queueName.endsWith(DOT)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/PlacementFactory.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/PlacementFactory.java
index a5de66463bb..76177120365 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/PlacementFactory.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/PlacementFactory.java
@@ -23,6 +23,8 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.util.ReflectionUtils;
+import java.lang.reflect.Constructor;
+
/**
* Factory class for creating instances of {@link PlacementRule}.
*/
@@ -42,4 +44,27 @@ public static PlacementRule getPlacementRule(String ruleStr,
LOG.info("Using PlacementRule implementation - " + ruleClass);
return ReflectionUtils.newInstance(ruleClass, conf);
}
-}
\ No newline at end of file
+
+ /**
+ * Create a new {@link PlacementRule} based on the rule class from the
+ * configuration. This is used to instantiate rules with different
+ * constructors by the FairScheduler.
+ * @param A class that represent a {@link PlacementRule}
+ * @param theClass The specific class reference to instantiate
+ * @param classType argument type of the constructor
+ * @param initArg argument for the constructor
+ * @return Created class instance
+ */
+ public static T getPlacementRule(Class theClass, Class classType,
+ Object initArg) {
+ T result;
+ try {
+ Constructor method = theClass.getDeclaredConstructor(classType);
+ method.setAccessible(true);
+ result = method.newInstance(initArg);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return result;
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/PlacementRule.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/PlacementRule.java
index 0f3d43c5ad7..e5583951ffc 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/PlacementRule.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/PlacementRule.java
@@ -20,11 +20,35 @@
import java.io.IOException;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
+/**
+ * Abstract base for all Placement Rules.
+ */
public abstract class PlacementRule {
+ // Flag to show if the rule can create a queue
+ @VisibleForTesting
+ public boolean createQueue = false;
+ private PlacementRule parentRule = null;
+
+ /**
+ * Set a rule to generate the parent queue dynamically.
+ * @param parent A PlacementRule
+ */
+ public void setParentRule(PlacementRule parent) {
+ this.parentRule = parent;
+ }
+
+ /**
+ * Get the rule that is set to generate the parent queue dynamically.
+ * @return The rule set or null if not set.
+ */
+ public PlacementRule getParentRule() {
+ return parentRule;
+ }
public String getName() {
return this.getClass().getName();
@@ -34,7 +58,7 @@ public abstract boolean initialize(
ResourceScheduler scheduler) throws IOException;
/**
- * Get queue for a given application
+ * Get queue for a given application.
*
* @param asc application submission context
* @param user userName
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/PrimaryGroupPlacementRule.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/PrimaryGroupPlacementRule.java
new file mode 100644
index 00000000000..b97de30317d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/PrimaryGroupPlacementRule.java
@@ -0,0 +1,158 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.yarn.server.resourcemanager.placement;
+
+import org.apache.hadoop.security.Groups;
+import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FSLeafQueue;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FSQueue;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.QueueManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+import java.util.List;
+
+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.cleanName;
+
+/**
+ * Places apps in queues by the primary group of the submitter.
+ */
+public class PrimaryGroupPlacementRule extends PlacementRule {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(PrimaryGroupPlacementRule.class);
+
+ private QueueManager queueManager;
+ private Groups groupProvider;
+
+ /**
+ * Create a new rule from the xml config.
+ * @param conf An xml element from the {@link FairScheduler#conf}
+ */
+ public PrimaryGroupPlacementRule(Element conf) {
+ // No config can be set when no policy is defined and we use defaults
+ createQueue = true;
+ if (conf != null) {
+ String create = conf.getAttribute("create");
+ if (create != null && !create.isEmpty()) {
+ createQueue = Boolean.parseBoolean(create);
+ }
+ }
+ LOG.debug("PrimaryGroupPlacementRule instantiated with create flag: {}",
+ createQueue);
+ }
+
+ /**
+ * Create a new rule just setting the create flag.
+ * @param create String form of the boolean flag. Only true
+ * will set the flag to True
+ */
+ public PrimaryGroupPlacementRule(boolean create) {
+ createQueue = create;
+ LOG.debug("PrimaryGroupPlacementRule instantiated with create flag: {}",
+ createQueue);
+ }
+
+ @Override
+ public boolean initialize(ResourceScheduler scheduler) throws IOException {
+ if (!(scheduler instanceof FairScheduler)) {
+ LOG.error("PrimaryGroup rule configured for wrong scheduler type.");
+ throw new IOException(
+ "PrimaryGroup rule can only be configured for the FairScheduler");
+ }
+ if (getParentRule() != null &&
+ getParentRule().getName().equals(getName())) {
+ LOG.error("PrimaryGroup rule has parent rule of the same type " +
+ "configured. You may not configure parent and child rule of the " +
+ "same type.");
+ throw new IOException(
+ "Parent rule should not be the same type as the child rule "
+ + "(PrimaryGroup)");
+ }
+
+ FairScheduler fs = (FairScheduler) scheduler;
+ queueManager = fs.getQueueManager();
+ groupProvider = new Groups(fs.getConfig());
+
+ return true;
+ }
+
+ @Override
+ public ApplicationPlacementContext getPlacementForApp(
+ ApplicationSubmissionContext asc, String user) throws YarnException {
+
+ // All users should have at least one group the primary group. If no groups
+ // are returned then there is a real issue.
+ final List groupList;
+ try {
+ groupList = groupProvider.getGroups(user);
+ } catch (IOException ioe) {
+ throw new YarnException("Group resolution failed", ioe);
+ }
+ if (groupList.isEmpty()) {
+ LOG.error("Group placement rule failed: No groups returned for user {}",
+ user);
+ throw new YarnException("No groups returned for user " + user);
+ }
+
+ String cleanGroup = cleanName(groupList.get(0));
+ String queueName;
+ PlacementRule parentRule = getParentRule();
+
+ if (getParentRule() != null) {
+ LOG.debug("PrimaryGroup rule: parent rule found: {}",
+ parentRule.getName());
+ ApplicationPlacementContext parent =
+ parentRule.getPlacementForApp(asc, user);
+ if (parent == null ||
+ queueManager.getQueue(parent.getQueue()) instanceof FSLeafQueue) {
+ LOG.debug("PrimaryGroup rule: parent rule failed");
+ return null;
+ }
+ LOG.debug("PrimaryGroup rule: parent rule result: {}",
+ parent.getQueue());
+ queueName = parent.getQueue() + DOT + cleanGroup;
+ } else {
+ queueName = assureRoot(cleanGroup);
+ }
+
+ // If we can create the queue in the rule or the queue exists return it
+ if (createQueue || configuredQueue(queueName)) {
+ return new ApplicationPlacementContext(queueName);
+ }
+ return null;
+ }
+
+ /**
+ * Check if the queue exists and is part of the configuration i.e. not
+ * a {@link FSQueue#isDynamic()} queue.
+ * @param queueName name of the queue to check
+ * @return true if the queue exists and is a "configured" queue
+ */
+ private boolean configuredQueue(String queueName) {
+ FSQueue queue = queueManager.getQueue(queueName);
+ return (queue != null && !queue.isDynamic());
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/RejectPlacementRule.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/RejectPlacementRule.java
new file mode 100644
index 00000000000..e5a9dc5b12f
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/RejectPlacementRule.java
@@ -0,0 +1,76 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.yarn.server.resourcemanager.placement;
+
+import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+
+/**
+ * Places apps in queues by username of the submitter.
+ */
+public class RejectPlacementRule extends PlacementRule {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(RejectPlacementRule.class);
+
+ /**
+ * Create a new rule from the xml config. All placements are
+ * rejected and the parameters are ignored.
+ * @param conf An xml element from the {@link FairScheduler#conf}
+ */
+ public RejectPlacementRule(Element conf) {
+ LOG.debug("RejectPlacementRule instantiated");
+ }
+
+ /**
+ * Create a new rule just setting the create flag. All placements are
+ * rejected and the parameters are ignored.
+ * @param create Create flag (ignored in this rule)
+ */
+ public RejectPlacementRule(boolean create) {
+ LOG.debug("RejectPlacementRule instantiated");
+ }
+
+ @Override
+ public boolean initialize(ResourceScheduler scheduler) throws IOException {
+ if (!(scheduler instanceof FairScheduler)) {
+ LOG.error("Reject rule configured for wrong scheduler type.");
+ throw new IOException(
+ "Reject rule can only be configured for the FairScheduler");
+ }
+ if (getParentRule() != null) {
+ LOG.error("You cannot configure a parent rule for the Reject rule.");
+ throw new IOException(
+ "Parent rule should not be configured for Reject rule.");
+ }
+
+ return true;
+ }
+
+ @Override
+ public ApplicationPlacementContext getPlacementForApp(
+ ApplicationSubmissionContext asc, String user) {
+ return null;
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/SecondaryGroupExistingPlacementRule.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/SecondaryGroupExistingPlacementRule.java
new file mode 100644
index 00000000000..ed73f689bea
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/SecondaryGroupExistingPlacementRule.java
@@ -0,0 +1,157 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.yarn.server.resourcemanager.placement;
+
+import org.apache.hadoop.security.Groups;
+import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FSLeafQueue;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FSQueue;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.QueueManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+import java.util.List;
+
+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.cleanName;
+
+/**
+ * Places apps in queues by the secondary group of the submitter, if the
+ * submitter is a member of more than one group.
+ * The first "matching" queue based on the group list is returned. The match
+ * takes into account the parent rule and create flag,
+ */
+public class SecondaryGroupExistingPlacementRule extends PlacementRule {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(SecondaryGroupExistingPlacementRule.class);
+
+ private QueueManager queueManager;
+ private Groups groupProvider;
+
+ /**
+ * Create a new rule from the xml config.
+ * @param conf An xml element from the {@link FairScheduler#conf}
+ */
+ public SecondaryGroupExistingPlacementRule(Element conf) {
+ // No config can be set when no policy is defined and we use defaults
+ createQueue = true;
+ if (conf != null) {
+ String create = conf.getAttribute("create");
+ if (create != null && !create.isEmpty()) {
+ createQueue = Boolean.parseBoolean(create);
+ }
+ }
+ LOG.debug("SecondaryGroupExistingPlacementRule instantiated with create "
+ + "flag: {}", createQueue);
+ }
+
+ /**
+ * Create a new rule just setting the create flag.
+ * @param create String form of the boolean flag. Only true
+ * will set the flag to True
+ */
+ public SecondaryGroupExistingPlacementRule(boolean create) {
+ createQueue = create;
+ LOG.debug("SecondaryGroupExistingPlacementRule instantiated with create "
+ + "flag: {}", createQueue);
+ }
+
+ @Override
+ public boolean initialize(ResourceScheduler scheduler) throws IOException {
+ if (!(scheduler instanceof FairScheduler)) {
+ LOG.error(
+ "SecondaryGroupExisting rule configured for wrong scheduler type.");
+ throw new IOException("SecondaryGroupExisting rule can only be " +
+ "configured for the FairScheduler");
+ }
+ if (getParentRule() != null &&
+ getParentRule().getName().equals(getName())) {
+ LOG.error("SecondaryGroupExisting rule has parent rule of the same " +
+ "type configured. You may not configure parent and child rule of " +
+ "the same type.");
+ throw new IOException("Parent rule should not be the same type as the " +
+ "child rule (SecondaryGroupExisting)");
+ }
+
+ FairScheduler fs = (FairScheduler) scheduler;
+ queueManager = fs.getQueueManager();
+ groupProvider = new Groups(fs.getConfig());
+
+ return true;
+ }
+
+ @Override
+ public ApplicationPlacementContext getPlacementForApp(
+ ApplicationSubmissionContext asc, String user) throws YarnException {
+
+ // All users should have at least one group the primary group. If no groups
+ // are returned then there is a real issue.
+ final List groupList;
+ try {
+ groupList = groupProvider.getGroups(user);
+ } catch (IOException ioe) {
+ throw new YarnException("Group resolution failed", ioe);
+ }
+
+ String parentQueue = null;
+ PlacementRule parentRule = getParentRule();
+
+ if (parentRule != null) {
+ LOG.debug("SecondaryGroupExisting rule: parent rule found: {}",
+ parentRule.getName());
+ ApplicationPlacementContext parent =
+ parentRule.getPlacementForApp(asc, user);
+ if (parent == null ||
+ queueManager.getQueue(parent.getQueue()) instanceof FSLeafQueue) {
+ LOG.debug("SecondaryGroupExisting rule: parent rule failed");
+ return null;
+ }
+ parentQueue = parent.getQueue();
+ LOG.debug("SecondaryGroupExisting rule: parent rule result: {}",
+ parentQueue);
+ }
+ // now check the groups inside the parent
+ for (int i = 1; i < groupList.size(); i++) {
+ String group = cleanName(groupList.get(i));
+ String queueName =
+ parentQueue == null ? assureRoot(group) : parentQueue + DOT + group;
+ if (configuredQueue(queueName)) {
+ return new ApplicationPlacementContext(queueName);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Check if the queue exists and is part of the configuration i.e. not
+ * a {@link FSQueue#isDynamic()} queue.
+ * @param queueName name of the queue to check
+ * @return true if the queue exists and is a "configured" queue
+ */
+ private boolean configuredQueue(String queueName) {
+ FSQueue queue = queueManager.getQueue(queueName);
+ return (queue != null && !queue.isDynamic());
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/SpecifiedPlacementRule.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/SpecifiedPlacementRule.java
new file mode 100644
index 00000000000..b86a25e248e
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/SpecifiedPlacementRule.java
@@ -0,0 +1,128 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.yarn.server.resourcemanager.placement;
+
+import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FSQueue;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.QueueManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+
+import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.assureRoot;
+import static org.apache.hadoop.yarn.server.resourcemanager.placement.FairQueuePlacementUtils.isValidQueueName;
+
+/**
+ * Places apps in queues by requested queue of the submitter.
+ */
+public class SpecifiedPlacementRule extends PlacementRule {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(SpecifiedPlacementRule.class);
+
+ private QueueManager queueManager;
+
+ /**
+ * Create a new rule from the xml config.
+ * @param conf An xml element from the {@link FairScheduler#conf}
+ */
+ public SpecifiedPlacementRule(Element conf) {
+ createQueue = true;
+ // No config can be set when no policy is defined and we use defaults
+ if (conf != null) {
+ String create = conf.getAttribute("create");
+ if (create != null && !create.isEmpty()) {
+ createQueue = Boolean.parseBoolean(create);
+ }
+ }
+ LOG.debug("Specified rule instantiated with create flag: {}",
+ createQueue);
+ }
+
+ /**
+ * Create a new rule just setting the create flag.
+ * @param create String form of the boolean flag. Only true
+ * will set the flag to True
+ */
+ public SpecifiedPlacementRule(boolean create) {
+ createQueue = create;
+ LOG.debug("Specified rule instantiated with create flag: {}",
+ createQueue);
+ }
+
+ @Override
+ public boolean initialize(ResourceScheduler scheduler) throws IOException {
+ if (!(scheduler instanceof FairScheduler)) {
+ LOG.error("Specified rule configured for wrong scheduler type.");
+ throw new IOException(
+ "Specified rule can only be configured for the FairScheduler");
+ }
+ if (getParentRule() != null) {
+ LOG.error(
+ "You cannot configure any parent rule for the Specified rule.");
+ throw new IOException(
+ "Parent rule should not be configured for Specified rule.");
+ }
+
+ FairScheduler fs = (FairScheduler) scheduler;
+ queueManager = fs.getQueueManager();
+
+ return true;
+ }
+
+ @Override
+ public ApplicationPlacementContext getPlacementForApp(
+ ApplicationSubmissionContext asc, String user) throws YarnException {
+
+ // Sanity check the provided queue
+ String queueName = asc.getQueue();
+ if (!isValidQueueName(queueName)) {
+ LOG.error("Specified queue name not valid: '{}'", queueName);
+ throw new YarnException("Application submitted by user " + user +
+ "with illegal queue name '" + queueName + "'.");
+ }
+ // On submission the requested queue will be set to "default" if no queue
+ // is specified: just check the next rule in that case
+ if (queueName.equals(YarnConfiguration.DEFAULT_QUEUE_NAME)) {
+ return null;
+ }
+ queueName = assureRoot(queueName);
+ // If we can create the queue in the rule or the queue exists return it
+ if (createQueue || configuredQueue(queueName)) {
+ return new ApplicationPlacementContext(queueName);
+ }
+ return null;
+ }
+
+ /**
+ * Check if the queue exists and is part of the configuration i.e. not
+ * a {@link FSQueue#isDynamic()} queue.
+ * @param queueName name of the queue to check
+ * @return true if the queue exists and is a "configured" queue
+ */
+ private boolean configuredQueue(String queueName) {
+ FSQueue queue = queueManager.getQueue(queueName);
+ return (queue != null && !queue.isDynamic());
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/UserPlacementRule.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/UserPlacementRule.java
new file mode 100644
index 00000000000..a18650c2450
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/placement/UserPlacementRule.java
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.yarn.server.resourcemanager.placement;
+
+import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FSLeafQueue;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FSQueue;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.QueueManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+
+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.cleanName;
+
+/**
+ * Places apps in queues by username of the submitter.
+ */
+public class UserPlacementRule extends PlacementRule {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(UserPlacementRule.class);
+
+ private QueueManager queueManager;
+
+ /**
+ * Create a new rule from the xml config.
+ * @param conf An xml element from the {@link FairScheduler#conf}
+ */
+ public UserPlacementRule(Element conf) {
+ // No config can be set when no policy is defined and we use defaults
+ createQueue = true;
+ if (conf != null) {
+ String create = conf.getAttribute("create");
+ if (create != null && !create.isEmpty()) {
+ createQueue = Boolean.parseBoolean(create);
+ }
+ }
+ LOG.debug("User rule instantiated with create flag: {}",
+ createQueue);
+ }
+
+ /**
+ * Create a new rule just setting the create flag.
+ * @param create String form of the boolean flag. Only true
+ * will set the flag to True
+ */
+ public UserPlacementRule(boolean create) {
+ createQueue = create;
+ LOG.debug("User rule instantiated with create flag: {}",
+ createQueue);
+ }
+
+ @Override
+ public boolean initialize(ResourceScheduler scheduler) throws IOException {
+ if (!(scheduler instanceof FairScheduler)) {
+ LOG.error("User rule configured for wrong scheduler type.");
+ throw new IOException(
+ "User rule can only be configured for the FairScheduler");
+ }
+ if (getParentRule() != null &&
+ getParentRule().getName().equals(getName())) {
+ LOG.error("User rule has parent rule of the same type configured. You " +
+ "may not configure parent and child rule of the same type.");
+ throw new IOException(
+ "Parent rule should not be the same type as the child rule (User)");
+ }
+
+ FairScheduler fs = (FairScheduler) scheduler;
+ queueManager = fs.getQueueManager();
+
+ return true;
+ }
+
+ @Override
+ public ApplicationPlacementContext getPlacementForApp(
+ ApplicationSubmissionContext asc, String user) throws YarnException {
+ String queueName;
+
+ String cleanUser = cleanName(user);
+ PlacementRule parentRule = getParentRule();
+ if (parentRule != null) {
+ LOG.debug("User rule: parent rule found: {}", parentRule.getName());
+ ApplicationPlacementContext parent =
+ parentRule.getPlacementForApp(asc, user);
+ if (parent == null ||
+ queueManager.getQueue(parent.getQueue()) instanceof FSLeafQueue) {
+ LOG.debug("User rule: parent rule failed");
+ return null;
+ }
+ LOG.debug("User rule: parent rule result: {}", parent.getQueue());
+ queueName = parent.getQueue() + DOT + cleanUser;
+ } else {
+ queueName = assureRoot(cleanUser);
+ }
+
+ // If we can create the queue in the rule or the queue exists return it
+ if (createQueue || configuredQueue(queueName)) {
+ return new ApplicationPlacementContext(queueName);
+ }
+ return null;
+ }
+
+ /**
+ * Check if the queue exists and is part of the configuration i.e. not
+ * a {@link FSQueue#isDynamic()} queue.
+ * @param queueName name of the queue to check
+ * @return true if the queue exists and is a "configured" queue
+ */
+ private boolean configuredQueue(String queueName) {
+ FSQueue queue = queueManager.getQueue(queueName);
+ return (queue != null && !queue.isDynamic());
+ }
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java
index 826d9f523eb..5bdf96d9e04 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java
@@ -23,7 +23,6 @@
import java.util.Map;
import java.util.Set;
-import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.authorize.AccessControlList;
import org.apache.hadoop.yarn.api.records.ReservationACL;
import org.apache.hadoop.yarn.api.records.Resource;
@@ -107,6 +106,15 @@
private final Set nonPreemptableQueues;
+ /**
+ * Create a fully initialised configuration for the scheduler.
+ * @param queueProperties The list of queues and their properties from the
+ * configuration.
+ * @param allocationFileParser The allocation file parser
+ * @param newPlacementPolicy An initialised queue placement policy.
+ * @param globalReservationQueueConfig The reservation queue config
+ * @throws AllocationConfigurationException
+ */
public AllocationConfiguration(QueueProperties queueProperties,
AllocationFileParser allocationFileParser,
QueuePlacementPolicy newPlacementPolicy,
@@ -145,7 +153,13 @@ public AllocationConfiguration(QueueProperties queueProperties,
queueProperties.getMaxContainerAllocation();
}
- public AllocationConfiguration(Configuration conf) {
+ /**
+ * Create a base scheduler configuration with just the defaults set.
+ * Should only be called to init a basic setup on scheduler init.
+ * @param scheduler The {@link FairScheduler} to create and initialise the
+ * placement policy.
+ */
+ public AllocationConfiguration(FairScheduler scheduler) {
minQueueResources = new HashMap<>();
maxChildQueueResources = new HashMap<>();
maxQueueResources = new HashMap<>();
@@ -170,7 +184,7 @@ public AllocationConfiguration(Configuration conf) {
configuredQueues.put(queueType, new HashSet<>());
}
placementPolicy =
- QueuePlacementPolicy.fromConfiguration(conf, configuredQueues);
+ QueuePlacementPolicy.fromConfiguration(scheduler);
nonPreemptableQueues = new HashSet<>();
queueMaxContainerAllocationMap = new HashMap<>();
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationFileLoaderService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationFileLoaderService.java
index 3300948ce70..a0c70503869 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationFileLoaderService.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationFileLoaderService.java
@@ -78,6 +78,7 @@
"(?i)(hdfs)|(file)|(s3a)|(viewfs)";
private final Clock clock;
+ private final FairScheduler scheduler;
// Last time we successfully reloaded queues
private volatile long lastSuccessfulReload;
@@ -95,14 +96,15 @@
private Thread reloadThread;
private volatile boolean running = true;
- public AllocationFileLoaderService() {
- this(SystemClock.getInstance());
+ public AllocationFileLoaderService(FairScheduler scheduler) {
+ this(SystemClock.getInstance(), scheduler);
}
private List defaultPermissions;
- public AllocationFileLoaderService(Clock clock) {
+ public AllocationFileLoaderService(Clock clock, FairScheduler scheduler) {
super(AllocationFileLoaderService.class.getName());
+ this.scheduler = scheduler;
this.clock = clock;
}
@@ -255,9 +257,8 @@ public synchronized void reloadAllocations()
QueueProperties queueProperties = queueParser.parse();
// Load placement policy and pass it configured queues
- Configuration conf = getConfig();
QueuePlacementPolicy newPlacementPolicy =
- getQueuePlacementPolicy(allocationFileParser, queueProperties, conf);
+ getQueuePlacementPolicy(allocationFileParser);
setupRootQueueProperties(allocationFileParser, queueProperties);
ReservationQueueConfiguration globalReservationQueueConfig =
@@ -273,16 +274,14 @@ public synchronized void reloadAllocations()
}
private QueuePlacementPolicy getQueuePlacementPolicy(
- AllocationFileParser allocationFileParser,
- QueueProperties queueProperties, Configuration conf)
+ AllocationFileParser allocationFileParser)
throws AllocationConfigurationException {
if (allocationFileParser.getQueuePlacementPolicy().isPresent()) {
return QueuePlacementPolicy.fromXml(
allocationFileParser.getQueuePlacementPolicy().get(),
- queueProperties.getConfiguredQueues(), conf);
+ scheduler);
} else {
- return QueuePlacementPolicy.fromConfiguration(conf,
- queueProperties.getConfiguredQueues());
+ return QueuePlacementPolicy.fromConfiguration(scheduler);
}
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FairScheduler.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FairScheduler.java
index 282367edbaa..90a8ac9106a 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FairScheduler.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FairScheduler.java
@@ -57,6 +57,7 @@
import org.apache.hadoop.yarn.server.api.protocolrecords.NMContainerStatus;
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
import org.apache.hadoop.yarn.server.resourcemanager.RMCriticalThreadUncaughtExceptionHandler;
+import org.apache.hadoop.yarn.server.resourcemanager.placement.ApplicationPlacementContext;
import org.apache.hadoop.yarn.server.resourcemanager.recovery.RMStateStore.RMState;
import org.apache.hadoop.yarn.server.resourcemanager.reservation.ReservationConstants;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp;
@@ -211,7 +212,7 @@
public FairScheduler() {
super(FairScheduler.class.getName());
context = new FSContext(this);
- allocsLoader = new AllocationFileLoaderService();
+ allocsLoader = new AllocationFileLoaderService(this);
queueMgr = new QueueManager(this);
maxRunningEnforcer = new MaxRunningAppsEnforcer(this);
}
@@ -220,6 +221,10 @@ public FSContext getContext() {
return context;
}
+ public RMContext getRMContext() {
+ return rmContext;
+ }
+
public boolean isAtLeastReservationThreshold(
ResourceCalculator resourceCalculator, Resource resource) {
return Resources.greaterThanOrEqual(resourceCalculator,
@@ -452,7 +457,21 @@ public int getContinuousSchedulingSleepMs() {
* configured limits, but the app will not be marked as runnable.
*/
protected void addApplication(ApplicationId applicationId,
- String queueName, String user, boolean isAppRecovering) {
+ String queueName, String user, boolean isAppRecovering,
+ ApplicationPlacementContext placementContext) {
+ // If the placement was rejected the placementContext will be null.
+ // We ignore placement rules on recovery.
+ if (!isAppRecovering && placementContext == null) {
+ String message =
+ "Reject application " + applicationId + " submitted by user " + user
+ + " application rejected by placement rules.";
+ rejectApplicationWithMessage(applicationId, message);
+ return;
+ }
+ // If we get here the queue placement has been run and the queueName
+ // reflects that already. If we are recovering the application the queue
+ // was not replaced by the placement rules and the queueName needs to be
+ // sanity checked
if (queueName == null || queueName.isEmpty()) {
String message =
"Reject application " + applicationId + " submitted by user " + user
@@ -472,12 +491,38 @@ protected void addApplication(ApplicationId applicationId,
writeLock.lock();
try {
- RMApp rmApp = rmContext.getRMApps().get(applicationId);
- FSLeafQueue queue = assignToQueue(rmApp, queueName, user, applicationId);
+ // Assign the app to the queue creating and prevent queue delete.
+ FSLeafQueue queue = queueMgr.getLeafQueue(queueName, true,
+ applicationId);
if (queue == null) {
+ rejectApplicationWithMessage(applicationId,
+ queueName + " is not a leaf queue");
return;
}
+ // Enforce ACLs: 2nd check, there could be a time laps between the app
+ // creation in the RMAppManager and getting here. That means we could
+ // have a configuration change (prevent race condition)
+ UserGroupInformation userUgi = UserGroupInformation.createRemoteUser(
+ user);
+
+ if (!queue.hasAccess(QueueACL.SUBMIT_APPLICATIONS, userUgi) &&
+ !queue.hasAccess(QueueACL.ADMINISTER_QUEUE, userUgi)) {
+ String msg = "User " + user + " does not have permission to submit " +
+ applicationId + " to queue " + queueName;
+ rejectApplicationWithMessage(applicationId, msg);
+ queue.removeAssignedApp(applicationId);
+ return;
+ }
+
+ RMApp rmApp = rmContext.getRMApps().get(applicationId);
+ if (rmApp != null) {
+ rmApp.setQueue(queueName);
+ } else {
+ LOG.error("Couldn't find RM app for " + applicationId +
+ " to set queue name on");
+ }
+
if (rmApp != null && rmApp.getAMResourceRequests() != null) {
// Resources.fitsIn would always return false when queueMaxShare is 0
// for any resource, but only using Resources.fitsIn is not enough
@@ -496,7 +541,7 @@ protected void addApplication(ApplicationId applicationId,
+ "it has zero amount of resource for a requested "
+ "resource! Invalid requested AM resources: %s, "
+ "maximum queue resources: %s",
- applicationId, queue.getName(),
+ applicationId, queueName,
invalidAMResourceRequests, queue.getMaxShare());
rejectApplicationWithMessage(applicationId, msg);
queue.removeAssignedApp(applicationId);
@@ -504,27 +549,13 @@ protected void addApplication(ApplicationId applicationId,
}
}
- // Enforce ACLs
- UserGroupInformation userUgi = UserGroupInformation.createRemoteUser(
- user);
-
- if (!queue.hasAccess(QueueACL.SUBMIT_APPLICATIONS, userUgi) && !queue
- .hasAccess(QueueACL.ADMINISTER_QUEUE, userUgi)) {
- String msg = "User " + userUgi.getUserName()
- + " cannot submit applications to queue " + queue.getName()
- + "(requested queuename is " + queueName + ")";
- rejectApplicationWithMessage(applicationId, msg);
- queue.removeAssignedApp(applicationId);
- return;
- }
-
SchedulerApplication application =
- new SchedulerApplication(queue, user);
+ new SchedulerApplication<>(queue, user);
applications.put(applicationId, application);
queue.getMetrics().submitApp(user);
LOG.info("Accepted application " + applicationId + " from user: " + user
- + ", in queue: " + queue.getName()
+ + ", in queue: " + queueName
+ ", currently num of applications: " + applications.size());
if (isAppRecovering) {
if (LOG.isDebugEnabled()) {
@@ -597,60 +628,6 @@ protected void addApplicationAttempt(
}
}
- /**
- * Helper method for the tests to assign the app to a queue.
- */
- @VisibleForTesting
- FSLeafQueue assignToQueue(RMApp rmApp, String queueName, String user) {
- return assignToQueue(rmApp, queueName, user, null);
- }
-
- /**
- * Helper method that attempts to assign the app to a queue. The method is
- * responsible to call the appropriate event-handler if the app is rejected.
- */
- private FSLeafQueue assignToQueue(RMApp rmApp, String queueName, String user,
- ApplicationId applicationId) {
- FSLeafQueue queue = null;
- String appRejectMsg = null;
-
- try {
- QueuePlacementPolicy placementPolicy = allocConf.getPlacementPolicy();
- queueName = placementPolicy.assignAppToQueue(queueName, user);
- if (queueName == null) {
- appRejectMsg = "Application rejected by queue placement policy";
- } else {
- queue = queueMgr.getLeafQueue(queueName, true, applicationId);
- if (queue == null) {
- appRejectMsg = queueName + " is not a leaf queue";
- }
- }
- } catch (IllegalStateException se) {
- appRejectMsg = "Unable to match app " + rmApp.getApplicationId() +
- " to a queue placement policy, and no valid terminal queue " +
- " placement rule is configured. Please contact an administrator " +
- " to confirm that the fair scheduler configuration contains a " +
- " valid terminal queue placement rule.";
- } catch (InvalidQueueNameException qne) {
- appRejectMsg = qne.getMessage();
- } catch (IOException ioe) {
- // IOException should only happen for a user without groups
- appRejectMsg = "Error assigning app to a queue: " + ioe.getMessage();
- }
-
- if (appRejectMsg != null && rmApp != null) {
- rejectApplicationWithMessage(rmApp.getApplicationId(), appRejectMsg);
- return null;
- }
-
- if (rmApp != null) {
- rmApp.setQueue(queue.getName());
- } else {
- LOG.error("Couldn't find RM app to set queue name on");
- }
- return queue;
- }
-
private void removeApplication(ApplicationId applicationId,
RMAppState finalState) {
SchedulerApplication application = applications.remove(
@@ -1268,7 +1245,8 @@ public void handle(SchedulerEvent event) {
if (queueName != null) {
addApplication(appAddedEvent.getApplicationId(),
queueName, appAddedEvent.getUser(),
- appAddedEvent.getIsAppRecovering());
+ appAddedEvent.getIsAppRecovering(),
+ appAddedEvent.getPlacementContext());
}
break;
case APP_REMOVED:
@@ -1445,12 +1423,8 @@ private void initScheduler(Configuration conf) throws IOException {
// This stores per-application scheduling information
this.applications = new ConcurrentHashMap<>();
- allocConf = new AllocationConfiguration(conf);
- try {
- queueMgr.initialize(conf);
- } catch (Exception e) {
- throw new IOException("Failed to start FairScheduler", e);
- }
+ allocConf = new AllocationConfiguration(this);
+ queueMgr.initialize();
if (continuousSchedulingEnabled) {
// Continuous scheduling is deprecated log it on startup
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/QueueManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/QueueManager.java
index a9c06780069..6b7d971b867 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/QueueManager.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/QueueManager.java
@@ -18,34 +18,28 @@
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
-import javax.xml.parsers.ParserConfigurationException;
-
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience.Private;
import org.apache.hadoop.classification.InterfaceStability.Unstable;
-import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.policies.FifoPolicy;
-import org.xml.sax.SAXException;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.util.Iterator;
-import java.util.Set;
/**
* Maintains a list of queues as well as scheduling parameters for each queue,
@@ -106,8 +100,7 @@ public FSParentQueue getRootQueue() {
return rootQueue;
}
- public void initialize(Configuration conf) throws IOException,
- SAXException, AllocationConfigurationException, ParserConfigurationException {
+ public void initialize() {
// Policies of root and default queue are set to
// SchedulingPolicy.DEFAULT_POLICY since the allocation file hasn't been
// loaded yet.
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/QueuePlacementPolicy.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/QueuePlacementPolicy.java
index 30ea213529d..1e144910be3 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/QueuePlacementPolicy.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/QueuePlacementPolicy.java
@@ -23,85 +23,223 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.classification.InterfaceAudience.Private;
import org.apache.hadoop.classification.InterfaceStability.Unstable;
import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.security.Groups;
-import org.apache.hadoop.util.ReflectionUtils;
+import org.apache.hadoop.yarn.server.resourcemanager.placement.DefaultPlacementRule;
+import org.apache.hadoop.yarn.server.resourcemanager.placement.PlacementRule;
+import org.apache.hadoop.yarn.server.resourcemanager.placement.PrimaryGroupPlacementRule;
+import org.apache.hadoop.yarn.server.resourcemanager.placement.RejectPlacementRule;
+import org.apache.hadoop.yarn.server.resourcemanager.placement.SecondaryGroupExistingPlacementRule;
+import org.apache.hadoop.yarn.server.resourcemanager.placement.SpecifiedPlacementRule;
+import org.apache.hadoop.yarn.server.resourcemanager.placement.UserPlacementRule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import static org.apache.hadoop.yarn.server.resourcemanager.placement.PlacementFactory.getPlacementRule;
+
+/**
+ * The FairScheduler rules based policy for placing an application in a queue.
+ * It parses the configuration and updates the {@link PlacementManager} with a
+ * list of {@link PlacementRule}s to execute in order.
+ */
@Private
@Unstable
public class QueuePlacementPolicy {
- private static final Map> ruleClasses;
+ private static final Logger LOG =
+ LoggerFactory.getLogger(QueuePlacementPolicy.class);
+
+ // The list of known rules:
+ // key to the map is the name in the configuration.
+ // for each name the mapping contains the class name of the implementation
+ // and a flag (true, false or create) which describes the terminal state
+ // see {@link #getTerminal} comments.
+ private static final Map> RULES;
static {
- Map> map =
- new HashMap>();
- map.put("user", QueuePlacementRule.User.class);
- map.put("primaryGroup", QueuePlacementRule.PrimaryGroup.class);
- map.put("secondaryGroupExistingQueue",
- QueuePlacementRule.SecondaryGroupExistingQueue.class);
- map.put("specified", QueuePlacementRule.Specified.class);
- map.put("nestedUserQueue",
- QueuePlacementRule.NestedUserQueue.class);
- map.put("default", QueuePlacementRule.Default.class);
- map.put("reject", QueuePlacementRule.Reject.class);
- ruleClasses = Collections.unmodifiableMap(map);
+ Map> map = new HashMap<>();
+ map.put("user", new ArrayList