YARN-8091. Revisit checkUserAccessToQueue RM REST API. (wangda)
authorWangda Tan <wangda@apache.org>
Mon, 2 Apr 2018 22:22:05 +0000 (15:22 -0700)
committerArpit Agarwal <arp@apache.org>
Fri, 13 Apr 2018 17:19:10 +0000 (10:19 -0700)
Change-Id: I5fab3fe229c34e967487b7327c7b3c8ddf7cb795

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServiceProtocol.java
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/RMQueueAclInfo.java [new file with mode: 0644]
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServices.java
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/DefaultRequestInterceptorREST.java
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/FederationInterceptorREST.java
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/main/java/org/apache/hadoop/yarn/server/router/webapp/RouterWebServices.java
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/MockRESTRequestInterceptor.java
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-router/src/test/java/org/apache/hadoop/yarn/server/router/webapp/PassThroughRESTRequestInterceptor.java

index 423c4e1..85ea07d 100644 (file)
@@ -53,6 +53,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
@@ -673,7 +674,7 @@ public interface RMWebServiceProtocol {
    * @throws AuthorizationException if the user is not authorized to invoke this
    *                                method.
    */
-  Response checkUserAccessToQueue(String queue, String username,
+  RMQueueAclInfo checkUserAccessToQueue(String queue, String username,
       String queueAclType, HttpServletRequest hsr)
       throws AuthorizationException;
 }
index c40e8be..d30764d 100644 (file)
@@ -173,6 +173,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntr
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDefinitionInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteResponseInfo;
@@ -2523,7 +2524,7 @@ public class RMWebServices extends WebServices implements RMWebServiceProtocol {
   @Path(RMWSConsts.CHECK_USER_ACCESS_TO_QUEUE)
   @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
                 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
-  public Response checkUserAccessToQueue(
+  public RMQueueAclInfo checkUserAccessToQueue(
       @PathParam(RMWSConsts.QUEUE) String queue,
       @QueryParam(RMWSConsts.USER) String username,
       @QueryParam(RMWSConsts.QUEUE_ACL_TYPE)
@@ -2531,42 +2532,39 @@ public class RMWebServices extends WebServices implements RMWebServiceProtocol {
       @Context HttpServletRequest hsr) throws AuthorizationException {
     init();
 
-    // Check if the specified queue acl is valid.
-    QueueACL queueACL;
-    try {
-      queueACL = QueueACL.valueOf(queueAclType);
-    } catch (IllegalArgumentException e) {
-      return Response.status(Status.BAD_REQUEST).entity(
-          "Specified queueAclType=" + queueAclType
-              + " is not a valid type, valid queue acl types={"
-              + "SUBMIT_APPLICATIONS/ADMINISTER_QUEUE}").build();
-    }
-
     // For the user who invokes this REST call, he/she should have admin access
     // to the queue. Otherwise we will reject the call.
     UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
     if (callerUGI != null && !this.rm.getResourceScheduler().checkAccess(
         callerUGI, QueueACL.ADMINISTER_QUEUE, queue)) {
-      return Response.status(Status.FORBIDDEN).entity(
+      throw new ForbiddenException(
           "User=" + callerUGI.getUserName() + " doesn't haven access to queue="
-              + queue + " so it cannot check ACLs for other users.")
-          .build();
+              + queue + " so it cannot check ACLs for other users.");
     }
 
     // Create UGI for the to-be-checked user.
     UserGroupInformation user = UserGroupInformation.createRemoteUser(username);
     if (user == null) {
-      return Response.status(Status.FORBIDDEN).entity(
-          "Failed to retrieve UserGroupInformation for user=" + username)
-          .build();
+      throw new ForbiddenException(
+          "Failed to retrieve UserGroupInformation for user=" + username);
+    }
+
+    // Check if the specified queue acl is valid.
+    QueueACL queueACL;
+    try {
+      queueACL = QueueACL.valueOf(queueAclType);
+    } catch (IllegalArgumentException e) {
+      throw new BadRequestException("Specified queueAclType=" + queueAclType
+          + " is not a valid type, valid queue acl types={"
+          + "SUBMIT_APPLICATIONS/ADMINISTER_QUEUE}");
     }
 
     if (!this.rm.getResourceScheduler().checkAccess(user, queueACL, queue)) {
-      return Response.status(Status.FORBIDDEN).entity(
+      return new RMQueueAclInfo(false, user.getUserName(),
           "User=" + username + " doesn't have access to queue=" + queue
-              + " with acl-type=" + queueAclType).build();
+              + " with acl-type=" + queueAclType);
     }
 
-    return Response.status(Status.OK).build();
+    return new RMQueueAclInfo(true, user.getUserName(), "");
   }
 }
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/RMQueueAclInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/RMQueueAclInfo.java
new file mode 100644 (file)
index 0000000..8799cab
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+ * 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.webapp.dao;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RMQueueAclInfo {
+  protected boolean allowed;
+  protected String user;
+  protected String diagnostics;
+
+  public RMQueueAclInfo() {
+    
+  }
+
+  public RMQueueAclInfo(boolean allowed, String user, String diagnostics) {
+    this.allowed = allowed;
+    this.user = user;
+    this.diagnostics = diagnostics;
+  }
+
+  public boolean isAllowed() {
+    return allowed;
+  }
+
+  public void setAllowed(boolean allowed) {
+    this.allowed = allowed;
+  }
+
+  public String getUser() {
+    return user;
+  }
+
+  public void setUser(String user) {
+    this.user = user;
+  }
+
+  public String getDiagnostics() {
+    return diagnostics;
+  }
+
+  public void setDiagnostics(String diagnostics) {
+    this.diagnostics = diagnostics;
+  }
+}
index c8bbb5c..9c4acc2 100644 (file)
@@ -68,6 +68,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo;
 import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
 import org.apache.hadoop.yarn.util.AdHocLogDumper;
 import org.apache.hadoop.yarn.util.YarnVersionInfo;
+import org.apache.hadoop.yarn.webapp.BadRequestException;
 import org.apache.hadoop.yarn.webapp.ForbiddenException;
 import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
 import org.apache.hadoop.yarn.webapp.GuiceServletConfig;
@@ -798,42 +799,47 @@ public class TestRMWebServices extends JerseyTestBase {
     RMWebServices webSvc =
         new RMWebServices(mockRM, conf, mock(HttpServletResponse.class));
 
+    boolean caughtException = false;
+
     // Case 1: Only queue admin user can access other user's information
     HttpServletRequest mockHsr = mockHttpServletRequestByUserName("non-admin");
-    Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "jack",
-        QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).getStatus(),
-        Response.SC_FORBIDDEN);
+    try {
+      webSvc.checkUserAccessToQueue("queue", "jack",
+          QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr);
+    } catch (ForbiddenException e) {
+      caughtException = true;
+    }
+    Assert.assertTrue(caughtException);
 
     // Case 2: request an unknown ACL causes BAD_REQUEST
     mockHsr = mockHttpServletRequestByUserName("admin");
-    Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "jack",
-        "XYZ_ACL", mockHsr).getStatus(), Response.SC_BAD_REQUEST);
+    caughtException = false;
+    try {
+      webSvc.checkUserAccessToQueue("queue", "jack", "XYZ_ACL", mockHsr);
+    } catch (BadRequestException e) {
+      caughtException = true;
+    }
+    Assert.assertTrue(caughtException);
 
     // Case 3: get FORBIDDEN for rejected ACL
     mockHsr = mockHttpServletRequestByUserName("admin");
-    Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "jack",
-        QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).getStatus(),
-        Response.SC_FORBIDDEN);
-    Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "jack",
-        QueueACL.ADMINISTER_QUEUE.name(), mockHsr).getStatus(),
-        Response.SC_FORBIDDEN);
+    Assert.assertFalse(webSvc.checkUserAccessToQueue("queue", "jack",
+        QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).isAllowed());
+    Assert.assertFalse(webSvc.checkUserAccessToQueue("queue", "jack",
+        QueueACL.ADMINISTER_QUEUE.name(), mockHsr).isAllowed());
 
     // Case 4: get OK for listed ACLs
     mockHsr = mockHttpServletRequestByUserName("admin");
-    Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "admin",
-        QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).getStatus(),
-        Response.SC_OK);
-    Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "admin",
-        QueueACL.ADMINISTER_QUEUE.name(), mockHsr).getStatus(),
-        Response.SC_OK);
+    Assert.assertTrue(webSvc.checkUserAccessToQueue("queue", "admin",
+        QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).isAllowed());
+    Assert.assertTrue(webSvc.checkUserAccessToQueue("queue", "admin",
+        QueueACL.ADMINISTER_QUEUE.name(), mockHsr).isAllowed());
 
     // Case 5: get OK only for SUBMIT_APP acl for "yarn" user
     mockHsr = mockHttpServletRequestByUserName("admin");
-    Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "yarn",
-        QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).getStatus(),
-        Response.SC_OK);
-    Assert.assertEquals(webSvc.checkUserAccessToQueue("queue", "yarn",
-        QueueACL.ADMINISTER_QUEUE.name(), mockHsr).getStatus(),
-        Response.SC_FORBIDDEN);
+    Assert.assertTrue(webSvc.checkUserAccessToQueue("queue", "yarn",
+        QueueACL.SUBMIT_APPLICATIONS.name(), mockHsr).isAllowed());
+    Assert.assertFalse(webSvc.checkUserAccessToQueue("queue", "yarn",
+        QueueACL.ADMINISTER_QUEUE.name(), mockHsr).isAllowed());
   }
 }
index f2edd66..53e5def 100644 (file)
@@ -53,6 +53,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
@@ -471,10 +472,10 @@ public class DefaultRequestInterceptorREST
   }
 
   @Override
-  public Response checkUserAccessToQueue(String queue, String username,
+  public RMQueueAclInfo checkUserAccessToQueue(String queue, String username,
       String queueAclType, HttpServletRequest hsr) {
     return RouterWebServiceUtil.genericForward(webAppAddress, hsr,
-        Response.class, HTTPMethods.GET,
+        RMQueueAclInfo.class, HTTPMethods.GET,
         RMWSConsts.RM_WEB_SERVICE_PATH + RMWSConsts.QUEUES + "/" + queue
             + "/access", null, null);
   }
index 7c703c4..fad5d96 100644 (file)
@@ -79,6 +79,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
@@ -1184,7 +1185,7 @@ public class FederationInterceptorREST extends AbstractRESTRequestInterceptor {
   }
 
   @Override
-  public Response checkUserAccessToQueue(String queue, String username,
+  public RMQueueAclInfo checkUserAccessToQueue(String queue, String username,
       String queueAclType, HttpServletRequest hsr) {
     throw new NotImplementedException();
   }
index 1eba586..ae57f1c 100644 (file)
@@ -75,6 +75,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
@@ -837,7 +838,7 @@ public class RouterWebServices implements RMWebServiceProtocol {
   @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8,
                 MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 })
   @Override
-  public Response checkUserAccessToQueue(
+  public RMQueueAclInfo checkUserAccessToQueue(
       @PathParam(RMWSConsts.QUEUE) String queue,
       @QueryParam(RMWSConsts.USER) String username,
       @QueryParam(RMWSConsts.QUEUE_ACL_TYPE)
index f9abb5d..0007843 100644 (file)
@@ -50,6 +50,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
@@ -319,9 +320,9 @@ public class MockRESTRequestInterceptor extends AbstractRESTRequestInterceptor {
   }
 
   @Override
-  public Response checkUserAccessToQueue(String queue, String username,
+  public RMQueueAclInfo checkUserAccessToQueue(String queue, String username,
       String queueAclType, HttpServletRequest hsr) {
-    return Response.status(Status.OK).build();
+    return new RMQueueAclInfo(true, username, "");
   }
 
   @Override
index e02203e..72fd442 100644 (file)
@@ -48,6 +48,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
+import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.RMQueueAclInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo;
 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo;
@@ -69,7 +70,7 @@ public class PassThroughRESTRequestInterceptor
   }
 
   @Override
-  public Response checkUserAccessToQueue(String queue, String username,
+  public RMQueueAclInfo checkUserAccessToQueue(String queue, String username,
       String queueAclType, HttpServletRequest hsr)
       throws AuthorizationException {
     return getNextInterceptor().checkUserAccessToQueue(queue, username,