diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ReservationACL.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ReservationACL.java
new file mode 100644
index 0000000..99a16f8
--- /dev/null
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/records/ReservationACL.java
@@ -0,0 +1,53 @@
+/**
+ * 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.api.records;
+
+import org.apache.hadoop.classification.InterfaceAudience.Public;
+import org.apache.hadoop.classification.InterfaceStability.Stable;
+
+/**
+ * {@code ReservationACL} enumerates the various ACLs for reservations.
+ *
+ * The ACL is one of:
+ *
+ * - {@link #CREATE_RESERVATIONS} - ACL to create reservations.
+ * -
+ * {@link #ADMINISTER_RESERVATIONS} - ACL to update and delete reservations.
+ *
+ * - {@link #LIST_RESERVATIONS} - ACL to list reservations.
+ *
+ */
+@Public
+@Stable
+public enum ReservationACL {
+ /**
+ * ACL to create reservations.
+ */
+ CREATE_RESERVATIONS,
+
+ /**
+ * ACL to update and delete reservations.
+ */
+ ADMINISTER_RESERVATIONS,
+
+ /**
+ * ACL to list reservations.
+ */
+ LIST_RESERVATIONS
+}
\ No newline at end of file
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
index d84c155..3845987 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
@@ -279,6 +279,11 @@ private static void addDeprecatedKeys() {
YARN_PREFIX + "acl.enable";
public static final boolean DEFAULT_YARN_ACL_ENABLE = false;
+ /** Are reservation acls enabled.*/
+ public static final String YARN_RESERVATION_ACL_ENABLE =
+ YARN_PREFIX + "acl.reservation-enable";
+ public static final boolean DEFAULT_YARN_RESERVATION_ACL_ENABLE = false;
+
public static boolean isAclEnabled(Configuration conf) {
return conf.getBoolean(YARN_ACL_ENABLE, DEFAULT_YARN_ACL_ENABLE);
}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/AccessType.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/AccessType.java
index 32459b9..1f3d55b 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/AccessType.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/AccessType.java
@@ -30,4 +30,9 @@
// queue
SUBMIT_APP,
ADMINISTER_QUEUE,
+
+ // reservations
+ CREATE_RESERVATIONS,
+ ADMINISTER_RESERVATIONS,
+ LIST_RESERVATIONS
}
\ No newline at end of file
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
index d8ea3ad..1d410f1 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
@@ -191,6 +191,12 @@
+ Are reservation acls enabled.
+ yarn.acl.reservation-enable
+ false
+
+
+
ACL of who can be admin of the YARN cluster.
yarn.admin.acl
*
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java
index 55def86..a30b4bb 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java
@@ -33,6 +33,7 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.commons.cli.UnrecognizedOptionException;
import org.apache.commons.lang.math.LongRange;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -117,6 +118,7 @@
import org.apache.hadoop.yarn.api.records.Priority;
import org.apache.hadoop.yarn.api.records.QueueACL;
import org.apache.hadoop.yarn.api.records.QueueInfo;
+import org.apache.hadoop.yarn.api.records.ReservationACL;
import org.apache.hadoop.yarn.api.records.ReservationAllocationState;
import org.apache.hadoop.yarn.api.records.ReservationDefinition;
import org.apache.hadoop.yarn.api.records.ReservationId;
@@ -158,6 +160,7 @@
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.YarnScheduler;
import org.apache.hadoop.yarn.server.resourcemanager.security.QueueACLsManager;
import org.apache.hadoop.yarn.server.resourcemanager.security.RMDelegationTokenSecretManager;
+import org.apache.hadoop.yarn.server.resourcemanager.security.ReservationsACLsManager;
import org.apache.hadoop.yarn.server.resourcemanager.security.authorize.RMPolicyProvider;
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
import org.apache.hadoop.yarn.server.utils.BuilderUtils;
@@ -604,6 +607,17 @@ public SubmitApplicationResponse submitApplication(
}
}
+ ReservationId reservationId = request.getApplicationSubmissionContext()
+ .getReservationID();
+
+ // Need to check reservation acls if the reservationId is present.
+ if (reservationSystem != null && reservationId != null) {
+ ReservationAllocation reservation = reservationSystem.getPlan(
+ submissionContext.getQueue()).getReservationById(reservationId);
+ checkReservationACLs(submissionContext.getQueue(), AuditConstants
+ .SUBMIT_RESERVATION_REQUEST, reservation.getUser(), null);
+ }
+
try {
// call RMAppManager to submit application directly
rmAppManager.submitApplication(submissionContext,
@@ -1222,7 +1236,7 @@ public ReservationSubmissionResponse submitReservation(
String queueName = request.getQueue();
String user =
checkReservationACLs(queueName,
- AuditConstants.SUBMIT_RESERVATION_REQUEST);
+ AuditConstants.SUBMIT_RESERVATION_REQUEST, null, null);
try {
// Try to place the reservation using the agent
boolean result =
@@ -1261,10 +1275,12 @@ public ReservationUpdateResponse updateReservation(
rValidator.validateReservationUpdateRequest(reservationSystem, request);
ReservationId reservationId = request.getReservationId();
String queueName = reservationSystem.getQueueForReservation(reservationId);
+ String submitter = reservationSystem.getPlan(queueName)
+ .getReservationById(reservationId).getUser();
// Check ACLs
String user =
checkReservationACLs(queueName,
- AuditConstants.UPDATE_RESERVATION_REQUEST);
+ AuditConstants.UPDATE_RESERVATION_REQUEST, submitter, null);
// Try to update the reservation using default agent
try {
boolean result =
@@ -1300,10 +1316,12 @@ public ReservationDeleteResponse deleteReservation(
rValidator.validateReservationDeleteRequest(reservationSystem, request);
ReservationId reservationId = request.getReservationId();
String queueName = reservationSystem.getQueueForReservation(reservationId);
+ String submitter = reservationSystem.getPlan(queueName).getReservationById(
+ reservationId).getUser();
// Check ACLs
String user =
checkReservationACLs(queueName,
- AuditConstants.DELETE_RESERVATION_REQUEST);
+ AuditConstants.DELETE_RESERVATION_REQUEST, submitter, null);
// Try to update the reservation using default agent
try {
boolean result =
@@ -1340,8 +1358,10 @@ public ReservationListResponse listReservations(
boolean includeResourceAllocations = requestInfo
.getIncludeResourceAllocations();
+ boolean[] canListAllReservations = new boolean[1];
String user = checkReservationACLs(requestInfo.getQueue(),
- AuditConstants.LIST_RESERVATION_REQUEST);
+ AuditConstants.LIST_RESERVATION_REQUEST, null,
+ canListAllReservations);
ReservationId requestedId = null;
if (requestInfo.getReservationId() != null
@@ -1354,8 +1374,16 @@ public ReservationListResponse listReservations(
long endTime = requestInfo.getEndTime() <= -1? Long.MAX_VALUE : requestInfo
.getEndTime();
- Set reservations = plan.getReservations(
- requestedId, new ReservationInterval(startTime, endTime), user);
+ Set reservations;
+
+ if (canListAllReservations != null && canListAllReservations.length == 1
+ && canListAllReservations[0]) {
+ reservations = plan.getReservations(
+ requestedId, new ReservationInterval(startTime, endTime));
+ } else {
+ reservations = plan.getReservations(
+ requestedId, new ReservationInterval(startTime, endTime), user);
+ }
List info =
ReservationSystemUtil.convertAllocationsToReservationInfo(
@@ -1419,7 +1447,9 @@ private void refreshScheduler(String planName,
}
}
- private String checkReservationACLs(String queueName, String auditConstant)
+ private String checkReservationACLs(String queueName, String auditConstant,
+ String reservationCreatorName,
+ boolean[] canListAllReservations)
throws YarnException {
UserGroupInformation callerUGI;
try {
@@ -1429,22 +1459,70 @@ private String checkReservationACLs(String queueName, String auditConstant)
"ClientRMService", "Error getting UGI");
throw RPCUtil.getRemoteException(ie);
}
- // Check if user has access on the managed queue
- if (!queueACLsManager.checkAccess(callerUGI, QueueACL.SUBMIT_APPLICATIONS,
- queueName, null, null)) {
- RMAuditLogger.logFailure(
- callerUGI.getShortUserName(),
- auditConstant,
- "User doesn't have permissions to "
- + QueueACL.SUBMIT_APPLICATIONS.toString(), "ClientRMService",
- AuditConstants.UNAUTHORIZED_USER);
- throw RPCUtil.getRemoteException(new AccessControlException("User "
- + callerUGI.getShortUserName() + " cannot perform operation "
- + QueueACL.SUBMIT_APPLICATIONS.name() + " on queue" + queueName));
+
+ // This can only be true if the reservation is going to be deleted or
+ // updated
+ boolean resBelongsToCurrentUser = reservationCreatorName != null
+ && !reservationCreatorName.equals("")
+ && reservationCreatorName.equals(callerUGI.getUserName());
+
+ ReservationsACLsManager manager = reservationSystem
+ .getReservationsACLsManager();
+
+ boolean isAdministrator = manager.checkAccess(callerUGI,
+ ReservationACL.ADMINISTER_RESERVATIONS, queueName);
+
+ if (auditConstant.equals(AuditConstants.LIST_RESERVATION_REQUEST)) {
+ if (canListAllReservations != null
+ && canListAllReservations.length == 1) {
+ canListAllReservations[0] = isAdministrator || manager.checkAccess(
+ callerUGI, ReservationACL.LIST_RESERVATIONS, queueName);
+ }
+ return callerUGI.getShortUserName();
+ }
+
+ ReservationACL reservationACL = getReservationACLFromAuditConstant(
+ auditConstant);
+
+ // A user can delete, update their own reservation, therefore, If
+ // resBelongsToCurrentUser is true, allow access. If not, make sure, that
+ // administrator is not required and check for the right ACL.
+ if (!(isAdministrator || resBelongsToCurrentUser ||
+ manager.checkAccess(callerUGI, reservationACL, queueName))) {
+ handleNoAccess(callerUGI.getShortUserName(), queueName, auditConstant,
+ reservationACL.toString(), reservationACL.name());
}
+
return callerUGI.getShortUserName();
}
+ private ReservationACL getReservationACLFromAuditConstant(
+ String auditConstant) throws YarnException{
+ if (auditConstant.equals(AuditConstants.SUBMIT_RESERVATION_REQUEST)) {
+ return ReservationACL.CREATE_RESERVATIONS;
+ } else if (auditConstant.equals(AuditConstants.LIST_RESERVATION_REQUEST)) {
+ return ReservationACL.LIST_RESERVATIONS;
+ } else if (auditConstant.equals(AuditConstants.DELETE_RESERVATION_REQUEST)
+ || auditConstant.equals(AuditConstants.UPDATE_RESERVATION_REQUEST)) {
+ return ReservationACL.ADMINISTER_RESERVATIONS;
+ } else {
+ String error = "Audit Constant " + auditConstant + " is not recognized.";
+ LOG.error(error);
+ throw RPCUtil.getRemoteException(new UnrecognizedOptionException(error));
+ }
+ }
+
+ private void handleNoAccess(String name, String queue, String auditConstant,
+ String acl, String op) throws YarnException {
+ RMAuditLogger.logFailure(
+ name,
+ auditConstant,
+ "User doesn't have permissions to " + acl, "ClientRMService",
+ auditConstant);
+ throw RPCUtil.getRemoteException(new AccessControlException("User "
+ + name + " cannot perform operation " + op + " on queue " + queue));
+ }
+
@Override
public UpdateApplicationPriorityResponse updateApplicationPriority(
UpdateApplicationPriorityRequest request) throws YarnException,
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/AbstractReservationSystem.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/AbstractReservationSystem.java
index 551be1c..13430fd 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/AbstractReservationSystem.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/AbstractReservationSystem.java
@@ -39,6 +39,7 @@
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.security.ReservationsACLsManager;
import org.apache.hadoop.yarn.util.Clock;
import org.apache.hadoop.yarn.util.UTCClock;
import org.apache.hadoop.yarn.util.resource.ResourceCalculator;
@@ -98,6 +99,8 @@
private PlanFollower planFollower;
+ private ReservationsACLsManager reservationsACLsManager;
+
private boolean isRecoveryEnabled = false;
/**
@@ -158,6 +161,8 @@ private void initialize(Configuration conf) throws YarnException {
isRecoveryEnabled = conf.getBoolean(
YarnConfiguration.RECOVERY_ENABLED,
YarnConfiguration.DEFAULT_RM_RECOVERY_ENABLED);
+
+ reservationsACLsManager = new ReservationsACLsManager(scheduler, conf);
}
private void loadPlan(String planName,
@@ -475,6 +480,10 @@ protected SharingPolicy getAdmissionPolicy(String queueName) {
}
}
+ public ReservationsACLsManager getReservationsACLsManager() {
+ return this.reservationsACLsManager;
+ }
+
protected abstract ReservationSchedulerConfiguration
getReservationSchedulerConfiguration();
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/CapacityOverTimePolicy.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/CapacityOverTimePolicy.java
index 424b543..8fd08db 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/CapacityOverTimePolicy.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/CapacityOverTimePolicy.java
@@ -26,7 +26,6 @@
import org.apache.hadoop.yarn.api.records.ReservationId;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.server.resourcemanager.reservation.RLESparseResourceAllocation.RLEOperator;
-import org.apache.hadoop.yarn.server.resourcemanager.reservation.exceptions.MismatchedUserException;
import org.apache.hadoop.yarn.server.resourcemanager.reservation.exceptions.PlanningException;
import org.apache.hadoop.yarn.server.resourcemanager.reservation.exceptions.PlanningQuotaException;
import org.apache.hadoop.yarn.server.resourcemanager.reservation.exceptions.ResourceOverCommitException;
@@ -85,14 +84,6 @@ public void validate(Plan plan, ReservationAllocation reservation)
ReservationAllocation oldReservation =
plan.getReservationById(reservation.getReservationId());
- // sanity check that the update of a reservation is not changing username
- if (oldReservation != null
- && !oldReservation.getUser().equals(reservation.getUser())) {
- throw new MismatchedUserException(
- "Updating an existing reservation with mismatched user:"
- + oldReservation.getUser() + " != " + reservation.getUser());
- }
-
long startTime = reservation.getStartTime();
long endTime = reservation.getEndTime();
long step = plan.getStep();
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/InMemoryPlan.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/InMemoryPlan.java
index 586f1c0..12a584a 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/InMemoryPlan.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/InMemoryPlan.java
@@ -476,7 +476,13 @@ public Resource getTotalCommittedResources(long t) {
}
@Override
- public Set getReservations(ReservationId
+ public Set getReservations(ReservationId
+ reservationID, ReservationInterval interval) {
+ return getReservations(reservationID, interval, null);
+ }
+
+ @Override
+ public Set getReservations(ReservationId
reservationID, ReservationInterval interval, String user) {
if (reservationID != null) {
ReservationAllocation allocation = getReservationById(reservationID);
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/PlanView.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/PlanView.java
index 0ad6485..ca60f99 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/PlanView.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/PlanView.java
@@ -49,6 +49,21 @@
reservationID, ReservationInterval interval, String user);
/**
+ * Return a set of {@link ReservationAllocation} identified by any user.
+ *
+ * @param reservationID the unqiue id to identify the
+ * {@link ReservationAllocation}
+ * @param interval the time interval used to retrieve the reservation
+ * allocations from. Only reservations with start time no
+ * greater than the interval end time, and end time no less
+ * than the interval start time will be selected.
+ * @return {@link ReservationAllocation} identified by the user who
+ * made the reservation
+ */
+ Set getReservations(ReservationId reservationID,
+ ReservationInterval interval);
+
+ /**
* Return a {@link ReservationAllocation} identified by its
* {@link ReservationId}
*
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/ReservationSchedulerConfiguration.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/ReservationSchedulerConfiguration.java
index afca8f9..740b88c 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/ReservationSchedulerConfiguration.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/ReservationSchedulerConfiguration.java
@@ -20,8 +20,12 @@
import org.apache.hadoop.classification.InterfaceAudience;
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.ReservationDefinition;
+import java.util.Map;
+
public abstract class ReservationSchedulerConfiguration extends Configuration {
@InterfaceAudience.Private
@@ -68,6 +72,17 @@ public ReservationSchedulerConfiguration(
public abstract boolean isReservable(String queue);
/**
+ * Gets a map containing the {@link AccessControlList} of users for each
+ * {@link ReservationACL} acl on thee specified queue.
+ *
+ * @param queue the queue with which to check a user's permissions.
+ * @return The a Map of {@link ReservationACL} to {@link AccessControlList}
+ * which contains a list of users that have the specified permission level.
+ */
+ public abstract Map getReservationAcls(
+ String queue);
+
+ /**
* Gets the length of time in milliseconds for which the {@link SharingPolicy}
* checks for validity
* @param queue name of the queue
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/ReservationSystem.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/ReservationSystem.java
index 56a08ef..8b62972 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/ReservationSystem.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/reservation/ReservationSystem.java
@@ -27,6 +27,7 @@
import org.apache.hadoop.yarn.server.resourcemanager.recovery.Recoverable;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.Queue;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.security.ReservationsACLsManager;
import java.util.Map;
@@ -123,4 +124,12 @@ void reinitialize(Configuration conf, RMContext rmContext)
*/
void setQueueForReservation(ReservationId reservationId, String queueName);
+ /**
+ * Get the {@link ReservationsACLsManager} to use to check for the reservation
+ * access on a user.
+ *
+ * @return the reservation ACL manager to use to check reservation ACLs.
+ *
+ */
+ ReservationsACLsManager getReservationsACLsManager();
}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/SchedulerUtils.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/SchedulerUtils.java
index a80e921..0c93a35 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/SchedulerUtils.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/SchedulerUtils.java
@@ -30,6 +30,7 @@
import org.apache.hadoop.yarn.api.records.ContainerStatus;
import org.apache.hadoop.yarn.api.records.QueueACL;
import org.apache.hadoop.yarn.api.records.QueueInfo;
+import org.apache.hadoop.yarn.api.records.ReservationACL;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.api.records.ResourceRequest;
import org.apache.hadoop.yarn.exceptions.InvalidLabelResourceRequestException;
@@ -361,7 +362,20 @@ public static AccessType toAccessType(QueueACL acl) {
}
return null;
}
-
+
+ public static AccessType toAccessType(ReservationACL acl) {
+ switch (acl) {
+ case ADMINISTER_RESERVATIONS:
+ return AccessType.ADMINISTER_RESERVATIONS;
+ case CREATE_RESERVATIONS:
+ return AccessType.CREATE_RESERVATIONS;
+ case LIST_RESERVATIONS:
+ return AccessType.LIST_RESERVATIONS;
+ default:
+ return null;
+ }
+ }
+
public static boolean checkResourceRequestMatchingNodePartition(
String requestedPartition, String nodePartition,
SchedulingMode schedulingMode) {
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerConfiguration.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerConfiguration.java
index 2e8fd24..b9a6853 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerConfiguration.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerConfiguration.java
@@ -40,6 +40,7 @@
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.yarn.api.records.QueueACL;
import org.apache.hadoop.yarn.api.records.QueueState;
+import org.apache.hadoop.yarn.api.records.ReservationACL;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.nodelabels.CommonNodeLabelsManager;
@@ -566,6 +567,34 @@ public void setAcl(String queue, QueueACL acl, String aclString) {
set(queuePrefix + getAclKey(acl), aclString);
}
+ private static String getAclKey(ReservationACL acl) {
+ return "acl_" + StringUtils.toLowerCase(acl.toString());
+ }
+
+ @Override
+ public Map getReservationAcls(String
+ queue) {
+ Map resAcls = new HashMap<>();
+ for (ReservationACL acl : ReservationACL.values()) {
+ resAcls.put(acl, getReservationAcl(queue, acl));
+ }
+ return resAcls;
+ }
+
+ public AccessControlList getReservationAcl(String queue, ReservationACL acl) {
+ String queuePrefix = getQueuePrefix(queue);
+ // The root queue defaults to all access if not defined
+ // Sub queues inherit access if not defined
+ String defaultAcl = ALL_ACL;
+ String aclString = get(queuePrefix + getAclKey(acl), defaultAcl);
+ return new AccessControlList(aclString);
+ }
+
+ public void setAcl(String queue, ReservationACL acl, String aclString) {
+ String queuePrefix = getQueuePrefix(queue);
+ set(queuePrefix + getAclKey(acl), aclString);
+ }
+
public Map getAcls(String queue) {
Map acls =
new HashMap();
@@ -581,6 +610,13 @@ public void setAcls(String queue, Map acls) {
}
}
+ public void setReservationAcls(String queue,
+ Map acls) {
+ for (Map.Entry e : acls.entrySet()) {
+ setAcl(queue, e.getKey(), e.getValue().getAclString());
+ }
+ }
+
public String[] getQueues(String queue) {
LOG.debug("CSConf - getQueues called for: queuePrefix=" + getQueuePrefix(queue));
String[] queues = getStrings(getQueuePrefix(queue) + QUEUES);
diff --git 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 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 180ae49..f984fef 100644
--- 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
+++ 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
@@ -26,6 +26,7 @@
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authorize.AccessControlList;
import org.apache.hadoop.yarn.api.records.QueueACL;
+import org.apache.hadoop.yarn.api.records.ReservationACL;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.server.resourcemanager.reservation.ReservationSchedulerConfiguration;
import org.apache.hadoop.yarn.server.resourcemanager.resource.ResourceWeights;
@@ -65,6 +66,10 @@
// ACL's for each queue. Only specifies non-default ACL's from configuration.
private final Map> queueAcls;
+ // Reservation ACL's for each queue. Only specifies non-default ACL's from
+ // configuration.
+ private final Map> resAcls;
+
// Min share preemption timeout for each queue in seconds. If a job in the queue
// waits this long without receiving its guaranteed share, it is allowed to
// preempt other jobs' tasks.
@@ -113,6 +118,7 @@ public AllocationConfiguration(Map minQueueResources,
Map fairSharePreemptionTimeouts,
Map fairSharePreemptionThresholds,
Map> queueAcls,
+ Map> resAcls,
QueuePlacementPolicy placementPolicy,
Map> configuredQueues,
ReservationQueueConfiguration globalReservationQueueConfig,
@@ -134,6 +140,7 @@ public AllocationConfiguration(Map minQueueResources,
this.fairSharePreemptionTimeouts = fairSharePreemptionTimeouts;
this.fairSharePreemptionThresholds = fairSharePreemptionThresholds;
this.queueAcls = queueAcls;
+ this.resAcls = resAcls;
this.reservableQueues = reservableQueues;
this.globalReservationQueueConfig = globalReservationQueueConfig;
this.placementPolicy = placementPolicy;
@@ -153,6 +160,7 @@ public AllocationConfiguration(Configuration conf) {
queueMaxResourcesDefault = Resources.unbounded();
queueMaxAMShareDefault = 0.5f;
queueAcls = new HashMap>();
+ resAcls = new HashMap>();
minSharePreemptionTimeouts = new HashMap();
fairSharePreemptionTimeouts = new HashMap();
fairSharePreemptionThresholds = new HashMap();
@@ -184,7 +192,17 @@ public AccessControlList getQueueAcl(String queue, QueueACL operation) {
}
return (queue.equals("root")) ? EVERYBODY_ACL : NOBODY_ACL;
}
-
+
+ @Override
+ /**
+ * Get the map of reservation ACLs to {@link AccessControlList} for the
+ * specified queue.
+ */
+ public Map getReservationAcls(String
+ queue) {
+ return this.resAcls.get(queue);
+ }
+
/**
* Get a queue's min share preemption timeout configured in the allocation
* file, in milliseconds. Return -1 if not set.
diff --git 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 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 d6012af..c80133d 100644
--- 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
+++ 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
@@ -39,6 +39,7 @@
import org.apache.hadoop.security.authorize.AccessControlList;
import org.apache.hadoop.service.AbstractService;
import org.apache.hadoop.yarn.api.records.QueueACL;
+import org.apache.hadoop.yarn.api.records.ReservationACL;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.server.resourcemanager.resource.ResourceWeights;
import org.apache.hadoop.yarn.util.Clock;
@@ -223,6 +224,8 @@ public synchronized void reloadAllocations() throws IOException,
new HashMap();
Map> queueAcls =
new HashMap>();
+ Map> reservationAcls =
+ new HashMap>();
Set reservableQueues = new HashSet();
Set nonPreemptableQueues = new HashSet();
int userMaxAppsDefault = Integer.MAX_VALUE;
@@ -360,8 +363,8 @@ public synchronized void reloadAllocations() throws IOException,
loadQueue(parent, element, minQueueResources, maxQueueResources,
queueMaxApps, userMaxApps, queueMaxAMShares, queueWeights,
queuePolicies, minSharePreemptionTimeouts, fairSharePreemptionTimeouts,
- fairSharePreemptionThresholds, queueAcls, configuredQueues,
- reservableQueues, nonPreemptableQueues);
+ fairSharePreemptionThresholds, queueAcls, reservationAcls,
+ configuredQueues, reservableQueues, nonPreemptableQueues);
}
// Load placement policy and pass it configured queues
@@ -409,8 +412,8 @@ public synchronized void reloadAllocations() throws IOException,
queueMaxResourcesDefault, queueMaxAMShareDefault, queuePolicies,
defaultSchedPolicy, minSharePreemptionTimeouts,
fairSharePreemptionTimeouts, fairSharePreemptionThresholds, queueAcls,
- newPlacementPolicy, configuredQueues, globalReservationQueueConfig,
- reservableQueues, nonPreemptableQueues);
+ reservationAcls, newPlacementPolicy, configuredQueues,
+ globalReservationQueueConfig, reservableQueues, nonPreemptableQueues);
lastSuccessfulReload = clock.getTime();
lastReloadAttemptFailed = false;
@@ -431,6 +434,7 @@ private void loadQueue(String parentName, Element element,
Map fairSharePreemptionTimeouts,
Map fairSharePreemptionThresholds,
Map> queueAcls,
+ Map> resAcls,
Map> configuredQueues,
Set reservableQueues,
Set nonPreemptableQueues)
@@ -453,6 +457,7 @@ private void loadQueue(String parentName, Element element,
}
Map acls =
new HashMap();
+ Map racls = new HashMap<>();
NodeList fields = element.getChildNodes();
boolean isLeaf = true;
@@ -506,6 +511,18 @@ private void loadQueue(String parentName, Element element,
} else if ("aclAdministerApps".equals(field.getTagName())) {
String text = ((Text)field.getFirstChild()).getData();
acls.put(QueueACL.ADMINISTER_QUEUE, new AccessControlList(text));
+ } else if ("aclCreateReservations".equals(field.getTagName())) {
+ String text = ((Text)field.getFirstChild()).getData();
+ racls.put(ReservationACL.CREATE_RESERVATIONS,
+ new AccessControlList(text));
+ } else if ("aclAdministerReservations".equals(field.getTagName())) {
+ String text = ((Text)field.getFirstChild()).getData();
+ racls.put(ReservationACL.ADMINISTER_RESERVATIONS,
+ new AccessControlList(text));
+ } else if ("aclListReservations".equals(field.getTagName())) {
+ String text = ((Text)field.getFirstChild()).getData();
+ racls.put(ReservationACL.LIST_RESERVATIONS, new AccessControlList(
+ text));
} else if ("reservation".equals(field.getTagName())) {
isLeaf = false;
reservableQueues.add(queueName);
@@ -521,7 +538,7 @@ private void loadQueue(String parentName, Element element,
queueMaxApps, userMaxApps, queueMaxAMShares, queueWeights,
queuePolicies, minSharePreemptionTimeouts,
fairSharePreemptionTimeouts, fairSharePreemptionThresholds,
- queueAcls, configuredQueues, reservableQueues,
+ queueAcls, resAcls, configuredQueues, reservableQueues,
nonPreemptableQueues);
isLeaf = false;
}
@@ -543,6 +560,7 @@ private void loadQueue(String parentName, Element element,
configuredQueues.get(FSQueueType.PARENT).add(queueName);
}
queueAcls.put(queueName, acls);
+ resAcls.put(queueName, racls);
if (maxQueueResources.containsKey(queueName) &&
minQueueResources.containsKey(queueName)
&& !Resources.fitsIn(minQueueResources.get(queueName),
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/ReservationsACLsManager.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/ReservationsACLsManager.java
new file mode 100644
index 0000000..fae04d7
--- /dev/null
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/ReservationsACLsManager.java
@@ -0,0 +1,98 @@
+/**
+* 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.security;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authorize.AccessControlList;
+import org.apache.hadoop.yarn.api.records.ReservationACL;
+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.capacity.CSQueue;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacitySchedulerConfiguration;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.AllocationConfiguration;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The {@link ReservationsACLsManager} is used to check a specified user's
+ * permissons to perform a reservation operation on the
+ * {@link CapacityScheduler} and the {@link FairScheduler}.
+ * {@link ReservationACL}s are used to specify reservation operations.
+ */
+public class ReservationsACLsManager {
+ private boolean isReservationACLsEnable;
+ private Map> reservationAcls
+ = new HashMap<>();
+
+ @VisibleForTesting
+ public ReservationsACLsManager() throws YarnException {
+ this(new CapacityScheduler(), new CapacitySchedulerConfiguration());
+ }
+
+ public ReservationsACLsManager(ResourceScheduler scheduler,
+ Configuration conf) throws YarnException {
+ this.isReservationACLsEnable =
+ conf.getBoolean(YarnConfiguration.YARN_RESERVATION_ACL_ENABLE,
+ YarnConfiguration.DEFAULT_YARN_RESERVATION_ACL_ENABLE) &&
+ conf.getBoolean(YarnConfiguration.YARN_ACL_ENABLE,
+ YarnConfiguration.DEFAULT_YARN_ACL_ENABLE);
+ if (scheduler instanceof CapacityScheduler) {
+ CapacitySchedulerConfiguration csConf = new
+ CapacitySchedulerConfiguration(conf);
+
+ for (String planQueue : scheduler.getPlanQueues()) {
+ CSQueue queue = ((CapacityScheduler) scheduler).getQueue(planQueue);
+ reservationAcls.put(planQueue, csConf.getReservationAcls(queue
+ .getQueuePath()));
+ }
+ } else if (scheduler instanceof FairScheduler) {
+ AllocationConfiguration aConf = ((FairScheduler) scheduler)
+ .getAllocationConfiguration();
+ for (String planQueue : scheduler.getPlanQueues()) {
+ reservationAcls.put(planQueue, aConf.getReservationAcls(planQueue));
+ }
+ }
+ }
+
+ public boolean checkAccess(UserGroupInformation callerUGI,
+ ReservationACL acl, String queueName) {
+ if (!isReservationACLsEnable) {
+ return true;
+ }
+
+ if (this.reservationAcls.containsKey(queueName)) {
+ Map acls = this.reservationAcls.get(
+ queueName);
+ if (acls.containsKey(acl)) {
+ return acls.get(acl).isUserAllowed(callerUGI);
+ } else {
+ // Give access if acl is undefined for queue.
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/ACLsTestBase.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/ACLsTestBase.java
new file mode 100644
index 0000000..e661703
--- /dev/null
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/ACLsTestBase.java
@@ -0,0 +1,123 @@
+/**
+* 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;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.security.PrivilegedExceptionAction;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authorize.AccessControlList;
+import org.apache.hadoop.service.Service.STATE;
+import org.apache.hadoop.yarn.api.ApplicationClientProtocol;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.event.Dispatcher;
+import org.apache.hadoop.yarn.event.DrainDispatcher;
+import org.apache.hadoop.yarn.ipc.YarnRPC;
+import org.junit.Before;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public abstract class ACLsTestBase {
+
+ protected static final String COMMON_USER = "common_user";
+ protected static final String QUEUE_A_USER = "queueA_user";
+ protected static final String QUEUE_B_USER = "queueB_user";
+ protected static final String ROOT_ADMIN = "root_admin";
+ protected static final String QUEUE_A_ADMIN = "queueA_admin";
+ protected static final String QUEUE_B_ADMIN = "queueB_admin";
+
+ protected static final String QUEUEA = "queueA";
+ protected static final String QUEUEB = "queueB";
+ protected static final String QUEUEC = "queueC";
+
+ protected static final Log LOG = LogFactory.getLog(TestApplicationACLs.class);
+
+ MockRM resourceManager;
+ Configuration conf;
+ YarnRPC rpc;
+ InetSocketAddress rmAddress;
+
+ @Before
+ public void setup() throws InterruptedException, IOException {
+ conf = createConfiguration();
+ rpc = YarnRPC.create(conf);
+ rmAddress = conf.getSocketAddr(
+ YarnConfiguration.RM_ADDRESS, YarnConfiguration.DEFAULT_RM_ADDRESS,
+ YarnConfiguration.DEFAULT_RM_PORT);
+
+ AccessControlList adminACL = new AccessControlList("");
+ conf.set(YarnConfiguration.YARN_ADMIN_ACL, adminACL.getAclString());
+
+ resourceManager = new MockRM(conf) {
+ protected ClientRMService createClientRMService() {
+ return new ClientRMService(getRMContext(), this.scheduler,
+ this.rmAppManager, this.applicationACLsManager,
+ this.queueACLsManager, getRMContext()
+ .getRMDelegationTokenSecretManager());
+ }
+
+ @Override
+ protected Dispatcher createDispatcher() {
+ return new DrainDispatcher();
+ }
+
+ @Override
+ protected void doSecureLogin() throws IOException {
+ }
+ };
+ new Thread() {
+ public void run() {
+ resourceManager.start();
+ };
+ }.start();
+ int waitCount = 0;
+ while (resourceManager.getServiceState() == STATE.INITED
+ && waitCount++ < 60) {
+ LOG.info("Waiting for RM to start...");
+ Thread.sleep(1500);
+ }
+ if (resourceManager.getServiceState() != STATE.STARTED) {
+ // RM could have failed.
+ throw new IOException("ResourceManager failed to start. Final state is "
+ + resourceManager.getServiceState());
+ }
+ }
+
+ protected ApplicationClientProtocol getRMClientForUser(String user)
+ throws IOException, InterruptedException {
+ UserGroupInformation userUGI = UserGroupInformation.createRemoteUser(user);
+ ApplicationClientProtocol userClient =
+ userUGI
+ .doAs(new PrivilegedExceptionAction() {
+ @Override
+ public ApplicationClientProtocol run() throws Exception {
+ return (ApplicationClientProtocol) rpc.getProxy(
+ ApplicationClientProtocol.class, rmAddress, conf);
+ }
+ });
+ return userClient;
+ }
+
+ protected abstract Configuration createConfiguration() throws IOException;
+}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/QueueACLsTestBase.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/QueueACLsTestBase.java
index e8f1425..82b3e24 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/QueueACLsTestBase.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/QueueACLsTestBase.java
@@ -18,20 +18,12 @@
package org.apache.hadoop.yarn.server.resourcemanager;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.security.PrivilegedExceptionAction;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authorize.AccessControlList;
-import org.apache.hadoop.service.Service.STATE;
import org.apache.hadoop.yarn.api.ApplicationClientProtocol;
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationReportRequest;
import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationReportResponse;
@@ -43,73 +35,13 @@
import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext;
import org.apache.hadoop.yarn.api.records.ContainerLaunchContext;
import org.apache.hadoop.yarn.api.records.Resource;
-import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.exceptions.YarnException;
-import org.apache.hadoop.yarn.ipc.YarnRPC;
import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppState;
import org.apache.hadoop.yarn.server.utils.BuilderUtils;
import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
-public abstract class QueueACLsTestBase {
-
- protected static final String COMMON_USER = "common_user";
- protected static final String QUEUE_A_USER = "queueA_user";
- protected static final String QUEUE_B_USER = "queueB_user";
- protected static final String ROOT_ADMIN = "root_admin";
- protected static final String QUEUE_A_ADMIN = "queueA_admin";
- protected static final String QUEUE_B_ADMIN = "queueB_admin";
-
- protected static final String QUEUEA = "queueA";
- protected static final String QUEUEB = "queueB";
-
- private static final Log LOG = LogFactory.getLog(TestApplicationACLs.class);
-
- MockRM resourceManager;
- Configuration conf;
- YarnRPC rpc;
- InetSocketAddress rmAddress;
-
- @Before
- public void setup() throws InterruptedException, IOException {
- conf = createConfiguration();
- rpc = YarnRPC.create(conf);
- rmAddress = conf.getSocketAddr(
- YarnConfiguration.RM_ADDRESS, YarnConfiguration.DEFAULT_RM_ADDRESS,
- YarnConfiguration.DEFAULT_RM_PORT);
-
- AccessControlList adminACL = new AccessControlList("");
- conf.set(YarnConfiguration.YARN_ADMIN_ACL, adminACL.getAclString());
-
- resourceManager = new MockRM(conf) {
- protected ClientRMService createClientRMService() {
- return new ClientRMService(getRMContext(), this.scheduler,
- this.rmAppManager, this.applicationACLsManager,
- this.queueACLsManager, getRMContext().getRMDelegationTokenSecretManager());
- };
-
- @Override
- protected void doSecureLogin() throws IOException {
- }
- };
- new Thread() {
- public void run() {
- resourceManager.start();
- };
- }.start();
- int waitCount = 0;
- while (resourceManager.getServiceState() == STATE.INITED
- && waitCount++ < 60) {
- LOG.info("Waiting for RM to start...");
- Thread.sleep(1500);
- }
- if (resourceManager.getServiceState() != STATE.STARTED) {
- // RM could have failed.
- throw new IOException("ResourceManager failed to start. Final state is "
- + resourceManager.getServiceState());
- }
- }
+public abstract class QueueACLsTestBase extends ACLsTestBase {
@After
public void tearDown() {
@@ -248,21 +180,4 @@ private ApplicationId submitAppAndGetAppId(String submitter,
acls.put(ApplicationAccessType.MODIFY_APP, modifyACL.getAclString());
return acls;
}
-
- private ApplicationClientProtocol getRMClientForUser(String user)
- throws IOException, InterruptedException {
- UserGroupInformation userUGI = UserGroupInformation.createRemoteUser(user);
- ApplicationClientProtocol userClient =
- userUGI
- .doAs(new PrivilegedExceptionAction() {
- @Override
- public ApplicationClientProtocol run() throws Exception {
- return (ApplicationClientProtocol) rpc.getProxy(
- ApplicationClientProtocol.class, rmAddress, conf);
- }
- });
- return userClient;
- }
-
- protected abstract Configuration createConfiguration() throws IOException;
}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/ReservationACLsTestBase.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/ReservationACLsTestBase.java
new file mode 100644
index 0000000..13910b5
--- /dev/null
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/ReservationACLsTestBase.java
@@ -0,0 +1,388 @@
+/**
+* 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;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.UUID;
+
+import org.apache.hadoop.yarn.api.ApplicationClientProtocol;
+import org.apache.hadoop.yarn.api.protocolrecords.ReservationDeleteRequest;
+import org.apache.hadoop.yarn.api.protocolrecords.ReservationListRequest;
+import org.apache.hadoop.yarn.api.protocolrecords.ReservationListResponse;
+import org.apache.hadoop.yarn.api.protocolrecords.ReservationSubmissionRequest;
+import org.apache.hadoop.yarn.api.protocolrecords.ReservationSubmissionResponse;
+import org.apache.hadoop.yarn.api.protocolrecords.ReservationUpdateRequest;
+import org.apache.hadoop.yarn.api.records.ReservationACL;
+import org.apache.hadoop.yarn.api.records.ReservationId;
+import org.apache.hadoop.yarn.api.records.ReservationDefinition;
+import org.apache.hadoop.yarn.api.records.ReservationRequest;
+import org.apache.hadoop.yarn.api.records.ReservationRequestInterpreter;
+import org.apache.hadoop.yarn.api.records.ReservationRequests;
+import org.apache.hadoop.yarn.event.DrainDispatcher;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.resourcemanager.reservation.Plan;
+import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacitySchedulerConfiguration;
+import org.apache.hadoop.yarn.server.utils.BuilderUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+
+public abstract class ReservationACLsTestBase extends ACLsTestBase {
+
+ private final int defaultDuration = 600000;
+ private final ReservationRequest defaultRequest = ReservationRequest
+ .newInstance(BuilderUtils.newResource(1024, 1), 1, 1,
+ defaultDuration);
+ private final ReservationRequests defaultRequests = ReservationRequests
+ .newInstance(Collections.singletonList(defaultRequest),
+ ReservationRequestInterpreter.R_ALL);
+
+ @After
+ public void tearDown() {
+ if (resourceManager != null) {
+ resourceManager.stop();
+ }
+ }
+
+ @Test
+ public void testApplicationACLs() throws Exception {
+ registerNode("test:1234", 8192, 8);
+ String queueA = !useFullQueuePath()? QUEUEA : CapacitySchedulerConfiguration
+ .ROOT + "." + QUEUEA;
+ String queueB = !useFullQueuePath()? QUEUEB : CapacitySchedulerConfiguration
+ .ROOT + "." + QUEUEB;
+ String queueC = !useFullQueuePath()? QUEUEC : CapacitySchedulerConfiguration
+ .ROOT + "." + QUEUEC;
+
+ // Submit Reservations
+
+ // Users of queue A can submit reservations on QueueA.
+ verifySubmitReservationSuccess(QUEUE_A_USER, queueA);
+ verifySubmitReservationSuccess(QUEUE_A_ADMIN, queueA);
+
+ // Users of queue B cannot submit reservations on QueueA.
+ verifySubmitReservationFailure(QUEUE_B_USER, queueA);
+ verifySubmitReservationFailure(QUEUE_B_ADMIN, queueA);
+
+ // Users of queue B can submit reservations on QueueB.
+ verifySubmitReservationSuccess(QUEUE_B_USER, queueB);
+ verifySubmitReservationSuccess(QUEUE_B_ADMIN, queueB);
+
+ // Users of queue A cannot submit reservations on QueueB.
+ verifySubmitReservationFailure(QUEUE_A_USER, queueB);
+ verifySubmitReservationFailure(QUEUE_A_ADMIN, queueB);
+
+ // Everyone can submit reservations on QueueC.
+ verifySubmitReservationSuccess(QUEUE_B_USER, queueC);
+ verifySubmitReservationSuccess(QUEUE_B_ADMIN, queueC);
+ verifySubmitReservationSuccess(QUEUE_A_USER, queueC);
+ verifySubmitReservationSuccess(QUEUE_A_ADMIN, queueC);
+ verifySubmitReservationSuccess(COMMON_USER, queueC);
+
+ // List Reservations
+
+ // User with List Reservations, or Admin ACL can list everyone's
+ // reservations.
+ verifyListReservationSuccess(QUEUE_A_ADMIN, QUEUE_A_USER, queueA);
+ verifyListReservationSuccess(COMMON_USER, QUEUE_A_ADMIN, queueA);
+ verifyListReservationSuccess(COMMON_USER, QUEUE_A_USER, queueA);
+
+ // User without Admin or Reservation ACL can only list their own
+ // reservations
+ verifyListReservationSuccess(QUEUE_A_USER, QUEUE_A_USER, queueA);
+ verifyListReservationSuccess(QUEUE_A_ADMIN, QUEUE_A_ADMIN, queueA);
+ verifyListReservationFailure(QUEUE_A_USER, QUEUE_A_ADMIN, queueA);
+
+ // User with List Reservations, or Admin ACL can list everyone's
+ // reservations.
+ verifyListReservationSuccess(QUEUE_B_ADMIN, QUEUE_B_USER, queueB);
+ verifyListReservationSuccess(COMMON_USER, QUEUE_B_ADMIN, queueB);
+ verifyListReservationSuccess(COMMON_USER, QUEUE_B_USER, queueB);
+
+ // User without Admin or Reservation ACL can only list their own
+ // reservations
+ verifyListReservationSuccess(QUEUE_B_USER, QUEUE_B_USER, queueB);
+ verifyListReservationSuccess(QUEUE_B_ADMIN, QUEUE_B_ADMIN, queueB);
+ verifyListReservationFailure(QUEUE_B_USER, QUEUE_B_ADMIN, queueB);
+
+ // All users can list reservations on QueueC because acls are enabled
+ // but not defined.
+ verifyListReservationSuccess(QUEUE_A_USER, QUEUE_A_ADMIN, queueC);
+ verifyListReservationSuccess(QUEUE_B_USER, QUEUE_A_ADMIN, queueC);
+ verifyListReservationSuccess(QUEUE_B_ADMIN, QUEUE_A_ADMIN, queueC);
+ verifyListReservationSuccess(COMMON_USER, QUEUE_A_ADMIN, queueC);
+ verifyListReservationSuccess(QUEUE_A_ADMIN, QUEUE_A_USER, queueC);
+ verifyListReservationSuccess(QUEUE_B_USER, QUEUE_A_USER, queueC);
+ verifyListReservationSuccess(QUEUE_B_ADMIN, QUEUE_A_USER, queueC);
+ verifyListReservationSuccess(COMMON_USER, QUEUE_A_USER, queueC);
+
+ // Delete Reservations
+
+ // Only the user who made the reservation or an admin can delete it.
+ verifyDeleteReservationSuccess(QUEUE_A_USER, QUEUE_A_USER, queueA);
+ verifyDeleteReservationSuccess(QUEUE_A_USER, QUEUE_A_ADMIN, queueA);
+
+ // A non-admin cannot delete another user's reservation.
+ verifyDeleteReservationFailure(QUEUE_A_USER, COMMON_USER, queueA);
+ verifyDeleteReservationFailure(QUEUE_A_USER, QUEUE_B_USER, queueA);
+ verifyDeleteReservationFailure(QUEUE_A_USER, QUEUE_B_ADMIN, queueA);
+
+ // Only the user who made the reservation or an admin can delete it.
+ verifyDeleteReservationSuccess(QUEUE_B_USER, QUEUE_B_USER, queueB);
+ verifyDeleteReservationSuccess(QUEUE_B_USER, QUEUE_B_ADMIN, queueB);
+
+ // A non-admin cannot delete another user's reservation.
+ verifyDeleteReservationFailure(QUEUE_B_USER, COMMON_USER, queueB);
+ verifyDeleteReservationFailure(QUEUE_B_USER, QUEUE_A_USER, queueB);
+ verifyDeleteReservationFailure(QUEUE_B_USER, QUEUE_A_ADMIN, queueB);
+
+ // All users can delete any reservation on QueueC because acls are enabled
+ // but not defined.
+ verifyDeleteReservationSuccess(QUEUE_B_ADMIN, COMMON_USER, queueC);
+ verifyDeleteReservationSuccess(QUEUE_B_ADMIN, QUEUE_B_USER, queueC);
+ verifyDeleteReservationSuccess(QUEUE_B_ADMIN, QUEUE_B_ADMIN, queueC);
+ verifyDeleteReservationSuccess(QUEUE_B_ADMIN, QUEUE_A_USER, queueC);
+ verifyDeleteReservationSuccess(QUEUE_B_ADMIN, QUEUE_A_ADMIN, queueC);
+
+ // Update Reservation
+
+ // Only the user who made the reservation or an admin can update it.
+ verifyUpdateReservationSuccess(QUEUE_A_USER, QUEUE_A_USER, queueA);
+ verifyUpdateReservationSuccess(QUEUE_A_USER, QUEUE_A_ADMIN, queueA);
+
+ // A non-admin cannot delete another user's reservation.
+ verifyUpdateReservationFailure(QUEUE_A_USER, COMMON_USER, queueA);
+ verifyUpdateReservationFailure(QUEUE_A_USER, QUEUE_B_USER, queueA);
+ verifyUpdateReservationFailure(QUEUE_A_USER, QUEUE_B_ADMIN, queueA);
+
+ // Only the user who made the reservation or an admin can update it.
+ verifyUpdateReservationSuccess(QUEUE_B_USER, QUEUE_B_USER, queueB);
+ verifyUpdateReservationSuccess(QUEUE_B_USER, QUEUE_B_ADMIN, queueB);
+
+ // A non-admin cannot delete another user's reservation.
+ verifyUpdateReservationFailure(QUEUE_B_USER, COMMON_USER, queueB);
+ verifyUpdateReservationFailure(QUEUE_B_USER, QUEUE_A_USER, queueB);
+ verifyUpdateReservationFailure(QUEUE_B_USER, QUEUE_A_ADMIN, queueB);
+
+ // All users can delete any reservation on QueueC because acls are enabled
+ // but not defined.
+ verifyDeleteReservationSuccess(QUEUE_B_ADMIN, COMMON_USER, queueC);
+ verifyDeleteReservationSuccess(QUEUE_B_ADMIN, QUEUE_B_USER, queueC);
+ verifyDeleteReservationSuccess(QUEUE_B_ADMIN, QUEUE_B_ADMIN, queueC);
+ verifyDeleteReservationSuccess(QUEUE_B_ADMIN, QUEUE_A_USER, queueC);
+ verifyDeleteReservationSuccess(QUEUE_B_ADMIN, QUEUE_A_ADMIN, queueC);
+ }
+
+ private void verifySubmitReservationSuccess(String submitter, String
+ queueName) throws Exception {
+ ReservationId reservationId =
+ submitReservation(submitter, queueName);
+
+ deleteReservation(submitter, reservationId);
+ }
+
+ private void verifySubmitReservationFailure(String submitter, String
+ queueName) throws Exception {
+ try {
+ submitReservation(submitter, queueName);
+ Assert.fail("Submit reservation by the enemy should fail!");
+ } catch (YarnException e) {
+ handleAdministerException(e, submitter, queueName, ReservationACL
+ .CREATE_RESERVATIONS.name());
+ }
+ }
+
+ private void verifyListReservationSuccess(String lister, String
+ submitter, String queueName) throws Exception {
+ ReservationId reservationId =
+ submitReservation(submitter, queueName);
+
+ ReservationListResponse adminResponse = listReservation(lister, queueName);
+
+ assert(adminResponse.getReservationAllocationState().size() == 1);
+ assert(adminResponse.getReservationAllocationState().get(0).getUser()
+ .equals(submitter));
+
+ deleteReservation(submitter, reservationId);
+ }
+
+ private void verifyListReservationFailure(String lister, String submitter,
+ String queueName) throws Exception {
+ ReservationId reservationId =
+ submitReservation(submitter, queueName);
+ ReservationListResponse response = listReservation(lister, queueName);
+ assert(response.getReservationAllocationState().size() == 0);
+ deleteReservation(submitter, reservationId);
+ }
+
+ private void verifyDeleteReservationSuccess(String submitter, String killer,
+ String queueName) throws Exception {
+ ReservationId reservationId =
+ submitReservation(submitter, queueName);
+
+ deleteReservation(killer, reservationId);
+ }
+
+ private void verifyDeleteReservationFailure(String submitter, String killer,
+ String queueName) throws Exception {
+
+ ReservationId reservationId =
+ submitReservation(submitter, queueName);
+
+ try {
+ deleteReservation(killer, reservationId);
+ Assert.fail("Reservation deletion by the enemy should fail!");
+ } catch (YarnException e) {
+ handleAdministerException(e, killer, queueName, ReservationACL
+ .ADMINISTER_RESERVATIONS.name());
+ }
+
+ deleteReservation(submitter, reservationId);
+ }
+
+ private void verifyUpdateReservationSuccess(String submitter, String updater,
+ String queueName) throws Exception {
+ ReservationId reservationId =
+ submitReservation(submitter, queueName);
+
+ final ReservationUpdateRequest updateRequest =
+ ReservationUpdateRequest.newInstance(
+ makeSimpleReservationDefinition(), reservationId);
+
+ ApplicationClientProtocol ownerClient = getRMClientForUser(updater);
+
+ ownerClient.updateReservation(updateRequest);
+
+ deleteReservation(updater, reservationId);
+ }
+
+ private void verifyUpdateReservationFailure(String submitter, String updater,
+ String queueName) throws Exception {
+ ReservationId reservationId =
+ submitReservation(submitter, queueName);
+
+ final ReservationUpdateRequest updateRequest =
+ ReservationUpdateRequest.newInstance(
+ makeSimpleReservationDefinition(), reservationId);
+
+ ApplicationClientProtocol unauthorizedClient = getRMClientForUser(updater);
+ try {
+ unauthorizedClient.updateReservation(updateRequest);
+ Assert.fail("Reservation updating by the enemy should fail.");
+ } catch (YarnException e) {
+ handleAdministerException(e, updater, queueName, ReservationACL
+ .ADMINISTER_RESERVATIONS.name());
+ }
+
+ deleteReservation(submitter, reservationId);
+ }
+
+ private ReservationDefinition makeSimpleReservationDefinition() {
+ long arrival = System.currentTimeMillis();
+
+ String reservationName = UUID.randomUUID().toString();
+ return ReservationDefinition.newInstance
+ (arrival, arrival + (int)(defaultDuration * 1.1), defaultRequests,
+ reservationName);
+ }
+
+ private ReservationListResponse listReservation(String lister,
+ String queueName) throws Exception {
+ final ReservationListRequest listRequest =
+ ReservationListRequest.newInstance(queueName, null, -1, -1, false);
+
+ ApplicationClientProtocol ownerClient = getRMClientForUser(lister);
+
+ return ownerClient.listReservations(listRequest);
+ }
+
+ private void deleteReservation(String deleter, ReservationId id) throws
+ Exception {
+
+ ApplicationClientProtocol deleteClient = getRMClientForUser(deleter);
+
+ final ReservationDeleteRequest deleteRequest = ReservationDeleteRequest
+ .newInstance(id);
+
+ deleteClient.deleteReservation(deleteRequest);
+ }
+
+ private ReservationId submitReservation(String submitter,
+ String queueName) throws Exception {
+
+ ApplicationClientProtocol submitterClient = getRMClientForUser(submitter);
+ ReservationSubmissionRequest reservationSubmissionRequest =
+ ReservationSubmissionRequest.newInstance(
+ makeSimpleReservationDefinition(), queueName);
+
+ ReservationSubmissionResponse response = submitterClient.submitReservation
+ (reservationSubmissionRequest);
+ return response.getReservationId();
+ }
+
+ private void handleAdministerException(Exception e, String killer, String
+ queue, String operation) {
+ LOG.info("Got exception while killing app as the enemy", e);
+ Assert.assertTrue(e.getMessage().contains("User " + killer
+ + " cannot perform operation " + operation + " on queue "
+ + queue));
+ }
+
+ private void registerNode(String host, int memory, int vCores) throws
+ Exception {
+ try {
+ resourceManager.registerNode(host, memory, vCores);
+ int attempts = 10;
+ Collection plans;
+ do {
+ DrainDispatcher dispatcher =
+ (DrainDispatcher) resourceManager.getRMContext().getDispatcher();
+ dispatcher.await();
+ LOG.info("Waiting for node capacity to be added to plan");
+ plans = resourceManager.getRMContext().getReservationSystem()
+ .getAllPlans().values();
+
+ if (checkCapacity(plans)) {
+ break;
+ }
+ Thread.sleep(100);
+ } while (attempts-- > 0);
+ if (attempts <= 0) {
+ Assert.fail("Exhausted attempts in checking if node capacity was "
+ + "added to the plan");
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ private boolean checkCapacity(Collection plans) {
+ for (Plan plan : plans) {
+ if (plan.getTotalCapacity().getMemory() > 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected abstract boolean useFullQueuePath();
+}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerReservationACLs.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerReservationACLs.java
new file mode 100644
index 0000000..d42d4d6
--- /dev/null
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerReservationACLs.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.scheduler.capacity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.server.resourcemanager.ReservationACLsTestBase;
+
+public class TestCapacitySchedulerReservationACLs extends
+ ReservationACLsTestBase {
+ @Override
+ protected Configuration createConfiguration() {
+ CapacitySchedulerConfiguration csConf =
+ new CapacitySchedulerConfiguration();
+ csConf.setQueues(CapacitySchedulerConfiguration.ROOT, new String[] {
+ QUEUEA, QUEUEB, QUEUEC });
+
+ String absoluteQueueA = CapacitySchedulerConfiguration.ROOT + "." + QUEUEA;
+ String absoluteQueueB = CapacitySchedulerConfiguration.ROOT + "." + QUEUEB;
+ String absoluteQueueC = CapacitySchedulerConfiguration.ROOT + "." + QUEUEC;
+
+ csConf.setCapacity(absoluteQueueA, 50f);
+ csConf.setCapacity(absoluteQueueB, 20f);
+ csConf.setCapacity(absoluteQueueC, 30f);
+ csConf.setReservable(absoluteQueueA, true);
+ csConf.setReservable(absoluteQueueB, true);
+ csConf.setReservable(absoluteQueueC, true);
+
+ // Set up ACLs on Queue A
+ Map reservationAclsOnQueueA =
+ new HashMap<>();
+
+ AccessControlList submitACLonQueueA = new AccessControlList(QUEUE_A_USER);
+ AccessControlList adminACLonQueueA = new AccessControlList(QUEUE_A_ADMIN);
+ AccessControlList listACLonQueueA = new AccessControlList(COMMON_USER);
+
+ reservationAclsOnQueueA.put(ReservationACL.CREATE_RESERVATIONS,
+ submitACLonQueueA);
+ reservationAclsOnQueueA.put(ReservationACL.ADMINISTER_RESERVATIONS,
+ adminACLonQueueA);
+ reservationAclsOnQueueA.put(ReservationACL.LIST_RESERVATIONS,
+ listACLonQueueA);
+
+ csConf.setReservationAcls(absoluteQueueA, reservationAclsOnQueueA);
+
+ // Set up ACLs on Queue B
+ Map reservationAclsOnQueueB =
+ new HashMap<>();
+
+ AccessControlList submitACLonQueueB = new AccessControlList(QUEUE_B_USER);
+ AccessControlList adminACLonQueueB = new AccessControlList(QUEUE_B_ADMIN);
+ AccessControlList listACLonQueueB = new AccessControlList(COMMON_USER);
+
+ reservationAclsOnQueueB.put(ReservationACL.CREATE_RESERVATIONS,
+ submitACLonQueueB);
+ reservationAclsOnQueueB.put(ReservationACL.ADMINISTER_RESERVATIONS,
+ adminACLonQueueB);
+ reservationAclsOnQueueB.put(ReservationACL.LIST_RESERVATIONS,
+ listACLonQueueB);
+
+ csConf.setReservationAcls(absoluteQueueB, reservationAclsOnQueueB);
+
+ csConf.setBoolean(YarnConfiguration.RM_RESERVATION_SYSTEM_ENABLE, true);
+ csConf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
+ csConf.setBoolean(YarnConfiguration.YARN_RESERVATION_ACL_ENABLE, true);
+ csConf.set("yarn.resourcemanager.scheduler.class", CapacityScheduler
+ .class.getName());
+
+ return csConf;
+ }
+
+ @Override
+ protected boolean useFullQueuePath() {
+ return false;
+ }
+}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestFairSchedulerReservationACLs.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestFairSchedulerReservationACLs.java
new file mode 100644
index 0000000..aa38dc2
--- /dev/null
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestFairSchedulerReservationACLs.java
@@ -0,0 +1,85 @@
+/**
+ * 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.scheduler.fair;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.server.resourcemanager.ReservationACLsTestBase;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class TestFairSchedulerReservationACLs extends ReservationACLsTestBase {
+ @Override
+ protected Configuration createConfiguration() throws IOException {
+ FairSchedulerConfiguration fsConf = new FairSchedulerConfiguration();
+
+ final String TEST_DIR = new File(System.getProperty("test.build.data",
+ "/tmp")).getAbsolutePath();
+ final String ALLOC_FILE = new File(TEST_DIR, "test-queues.xml")
+ .getAbsolutePath();
+ PrintWriter out = new PrintWriter(new FileWriter(ALLOC_FILE));
+ out.println("");
+ out.println("");
+ out.println(" ");
+ out.println(" " +
+ "queueA_user,common_user " +
+ "");
+ out.println(" " +
+ "queueA_admin " +
+ "");
+ out.println(" common_user ");
+ out.println(" queueA_user,common_user ");
+ out.println(" queueA_admin ");
+ out.println(" ");
+ out.println(" ");
+ out.println(" ");
+ out.println(" queueB_user,common_user ");
+ out.println(" queueB_admin ");
+ out.println(" " +
+ "queueB_user,common_user " +
+ "");
+ out.println(" " +
+ "queueB_admin " +
+ "");
+ out.println(" common_user ");
+ out.println(" ");
+ out.println(" ");
+ out.println(" ");
+ out.println(" ");
+ out.println(" ");
+ out.println("");
+ out.close();
+ fsConf.set(FairSchedulerConfiguration.ALLOCATION_FILE, ALLOC_FILE);
+
+ fsConf.setBoolean(YarnConfiguration.RM_RESERVATION_SYSTEM_ENABLE, true);
+ fsConf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
+ fsConf.setBoolean(YarnConfiguration.YARN_RESERVATION_ACL_ENABLE, true);
+ fsConf.set("yarn.resourcemanager.scheduler.class", FairScheduler.class
+ .getName());
+
+ return fsConf;
+ }
+
+ @Override
+ protected boolean useFullQueuePath() {
+ return true;
+ }
+}
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesAppsModification.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesAppsModification.java
index 9abcf9c..57518dd 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesAppsModification.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesAppsModification.java
@@ -210,6 +210,8 @@ public void configureScheduler() {
} catch(IOException e) {
}
conf.set(FairSchedulerConfiguration.ALLOCATION_FILE, FS_ALLOC_FILE);
+ conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
+ conf.setBoolean(YarnConfiguration.YARN_RESERVATION_ACL_ENABLE, true);
conf.set("yarn.resourcemanager.scheduler.class",
FairScheduler.class.getName());
}