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: + *

+ */ +@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 d3c1f1a..5b8909b 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-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/amrmproxy/MockResourceManagerFacade.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/amrmproxy/MockResourceManagerFacade.java index c512f8d..d21e4c8 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/amrmproxy/MockResourceManagerFacade.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/amrmproxy/MockResourceManagerFacade.java @@ -488,4 +488,4 @@ public FailApplicationAttemptResponse failApplicationAttempt( FailApplicationAttemptRequest request) throws YarnException, IOException { throw new NotImplementedException(); } -} \ No newline at end of file +} 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 8ca7e5b..cbc3af0 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 (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,69 @@ 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 != "" + && reservationCreatorName.equals(callerUGI.getUserName()); + + ReservationsACLsManager manager = reservationSystem + .getReservationsACLsManager(); + + boolean isAdministrator = manager.checkAccess(callerUGI, + ReservationACL.ADMINISTER_RESERVATIONS, queueName); + + if (auditConstant == 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 == AuditConstants.SUBMIT_RESERVATION_REQUEST) { + return ReservationACL.CREATE_RESERVATIONS; + } else if (auditConstant == AuditConstants.LIST_RESERVATION_REQUEST) { + return ReservationACL.LIST_RESERVATIONS; + } else if (auditConstant == AuditConstants.DELETE_RESERVATION_REQUEST + || auditConstant == 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..409f40b 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..9531b4c 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. + * + * @returns 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..9203631 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 1e62b44..860443b 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 @@ -39,6 +39,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; @@ -565,6 +566,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(); @@ -580,6 +609,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 bf4eae8..4c8ebfa 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. @@ -111,6 +116,7 @@ public AllocationConfiguration(Map minQueueResources, Map fairSharePreemptionTimeouts, Map fairSharePreemptionThresholds, Map> queueAcls, + Map> resAcls, QueuePlacementPolicy placementPolicy, Map> configuredQueues, ReservationQueueConfiguration globalReservationQueueConfig, @@ -131,6 +137,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; @@ -149,6 +156,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(); @@ -179,7 +187,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 9049525..7ac0434 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(); int userMaxAppsDefault = Integer.MAX_VALUE; int queueMaxAppsDefault = Integer.MAX_VALUE; @@ -359,8 +362,8 @@ public synchronized void reloadAllocations() throws IOException, loadQueue(parent, element, minQueueResources, maxQueueResources, queueMaxApps, userMaxApps, queueMaxAMShares, queueWeights, queuePolicies, minSharePreemptionTimeouts, fairSharePreemptionTimeouts, - fairSharePreemptionThresholds, queueAcls, configuredQueues, - reservableQueues); + fairSharePreemptionThresholds, queueAcls, reservationAcls, + configuredQueues, reservableQueues); } // Load placement policy and pass it configured queues @@ -408,9 +411,9 @@ public synchronized void reloadAllocations() throws IOException, queueMaxResourcesDefault, queueMaxAMShareDefault, queuePolicies, defaultSchedPolicy, minSharePreemptionTimeouts, fairSharePreemptionTimeouts, fairSharePreemptionThresholds, queueAcls, - newPlacementPolicy, configuredQueues, globalReservationQueueConfig, - reservableQueues); - + reservationAcls, newPlacementPolicy, configuredQueues, + globalReservationQueueConfig, reservableQueues); + lastSuccessfulReload = clock.getTime(); lastReloadAttemptFailed = false; @@ -430,6 +433,7 @@ private void loadQueue(String parentName, Element element, Map fairSharePreemptionTimeouts, Map fairSharePreemptionThresholds, Map> queueAcls, + Map> resAcls, Map> configuredQueues, Set reservableQueues) throws AllocationConfigurationException { @@ -451,6 +455,7 @@ private void loadQueue(String parentName, Element element, } Map acls = new HashMap(); + Map racls = new HashMap<>(); NodeList fields = element.getChildNodes(); boolean isLeaf = true; @@ -504,17 +509,29 @@ 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); configuredQueues.get(FSQueueType.PARENT).add(queueName); - } else if ("queue".endsWith(field.getTagName()) || + } else if ("queue".endsWith(field.getTagName()) || "pool".equals(field.getTagName())) { loadQueue(queueName, field, minQueueResources, maxQueueResources, queueMaxApps, userMaxApps, queueMaxAMShares, queueWeights, queuePolicies, minSharePreemptionTimeouts, fairSharePreemptionTimeouts, fairSharePreemptionThresholds, - queueAcls, configuredQueues, reservableQueues); + queueAcls, resAcls, configuredQueues, reservableQueues); isLeaf = false; } } @@ -535,6 +552,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..19a65c5 --- /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,99 @@ +/** +* 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 org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairSchedulerConfiguration; + +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..dd59729 --- /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..15ae8ed --- /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; + } +}