YARN-10655. Limit queue creation depth relative to its first static parent. Contributed by Andras Gyori.
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/capacity/CapacitySchedulerAutoQueueHandler.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerAutoQueueHandler.java
index e847737..898b075 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerAutoQueueHandler.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerAutoQueueHandler.java
@@ -55,34 +55,43 @@
     List<ApplicationPlacementContext> parentsToCreate = new ArrayList<>();
 
     ApplicationPlacementContext queueCandidateContext = parentContext;
-    CSQueue existingQueueCandidate = getQueue(
+    CSQueue firstExistingQueue = getQueue(
         queueCandidateContext.getFullQueuePath());
 
-    while (existingQueueCandidate == null) {
+    while (firstExistingQueue == null) {
       parentsToCreate.add(queueCandidateContext);
       queueCandidateContext = CSQueueUtils.extractQueuePath(
           queueCandidateContext.getParentQueue());
-      existingQueueCandidate = getQueue(
+      firstExistingQueue = getQueue(
           queueCandidateContext.getFullQueuePath());
     }
 
+    CSQueue firstExistingStaticQueue = firstExistingQueue;
+    // Include the LeafQueue in the distance
+    int firstStaticParentDistance = parentsToCreate.size() + 1;
+
+    while(isNonStaticParent(firstExistingStaticQueue)) {
+      queueCandidateContext = CSQueueUtils.extractQueuePath(
+          queueCandidateContext.getParentQueue());
+      firstExistingStaticQueue = getQueue(
+          queueCandidateContext.getFullQueuePath());
+      ++firstStaticParentDistance;
+    }
+
     // Reverse the collection to to represent the hierarchy to be created
     // from highest to lowest level
     Collections.reverse(parentsToCreate);
 
-    if (!(existingQueueCandidate instanceof ParentQueue)) {
+    if (!(firstExistingQueue instanceof ParentQueue)) {
       throw new SchedulerDynamicEditException(
           "Could not auto create hierarchy of "
               + queue.getFullQueuePath() + ". Queue "
-              + existingQueueCandidate.getQueuePath() +
+              + firstExistingQueue.getQueuePath() +
               " is not a ParentQueue."
       );
     }
-    ParentQueue existingParentQueue = (ParentQueue) existingQueueCandidate;
+    ParentQueue existingParentQueue = (ParentQueue) firstExistingQueue;
     int depthLimit = extractDepthLimit(existingParentQueue);
-    // The number of levels to be created including the LeafQueue
-    // (which is last)
-    int levelsToCreate = parentsToCreate.size() + 1;
 
     if (depthLimit == 0) {
       throw new SchedulerDynamicEditException("Auto creation of queue " +
@@ -90,12 +99,12 @@
           + existingParentQueue.getQueuePath());
     }
 
-    if (levelsToCreate > depthLimit) {
+    if (firstStaticParentDistance > depthLimit) {
       throw new SchedulerDynamicEditException(
           "Could not auto create queue " + queue.getFullQueuePath()
-              + ". In order to create the desired queue hierarchy, " +
-              levelsToCreate + " levels of queues would need " +
-              "to be created, which is above the limit.");
+              + ". The distance of the LeafQueue from the first static " +
+              "ParentQueue is" + firstStaticParentDistance + ", which is " +
+              "above the limit.");
     }
 
     for (ApplicationPlacementContext current : parentsToCreate) {
@@ -123,4 +132,9 @@
   private CSQueue getQueue(String queue) {
     return queue != null ? queueManager.getQueue(queue) : null;
   }
+
+  private boolean isNonStaticParent(CSQueue queue) {
+    return (!(queue instanceof AbstractCSQueue)
+        || ((AbstractCSQueue) queue).isDynamicQueue());
+  }
 }
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerNewQueueAutoCreation.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerNewQueueAutoCreation.java
index 4facf94..2f83f1f 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerNewQueueAutoCreation.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerNewQueueAutoCreation.java
@@ -565,6 +565,26 @@
     }
   }
 
+  @Test
+  public void testAutoQueueCreationDepthLimitFromStaticParent()
+      throws Exception {
+    startScheduler();
+
+    // a is the first existing queue here and it is static, therefore
+    // the distance is 2
+    createQueue("root.a.a-auto.a1-auto");
+    Assert.assertNotNull(cs.getQueue("root.a.a-auto.a1-auto"));
+
+    try {
+      createQueue("root.a.a-auto.a2-auto.a3-auto");
+      Assert.fail("Queue creation should not succeed because the distance " +
+          "from the first static parent is above limit");
+    } catch (SchedulerDynamicEditException ignored) {
+
+    }
+
+  }
+
   private LeafQueue createQueue(String queuePath) throws YarnException {
     return autoQueueHandler.autoCreateQueue(
         CSQueueUtils.extractQueuePath(queuePath));