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());
+ }
+}