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 bee6bf8..2d6ea32 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 @@ -329,7 +329,7 @@ public GetApplicationReportResponse getApplicationReport( boolean allowAccess = checkAccess(callerUGI, application.getUser(), ApplicationAccessType.VIEW_APP, application); ApplicationReport report = - application.createAndGetApplicationReport(callerUGI.getUserName(), + application.createAndGetApplicationReport(callerUGI.getShortUserName(), allowAccess); GetApplicationReportResponse response = recordFactory @@ -795,7 +795,7 @@ public void remove() { } reports.add(application.createAndGetApplicationReport( - callerUGI.getUserName(), allowAccess)); + callerUGI.getShortUserName(), allowAccess)); } GetApplicationsResponse response = diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestAMRMTokenRetrieval.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestAMRMTokenRetrieval.java new file mode 100644 index 0000000..3bb0f08 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestAMRMTokenRetrieval.java @@ -0,0 +1,253 @@ +/** + * 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 org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.authentication.util.KerberosName; +import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationReportRequest; +import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationReportResponse; +import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationsRequest; +import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationsResponse; +import org.apache.hadoop.yarn.api.protocolrecords.GetNewApplicationRequest; +import org.apache.hadoop.yarn.api.protocolrecords.GetNewApplicationResponse; +import org.apache.hadoop.yarn.api.protocolrecords.SubmitApplicationRequest; +import org.apache.hadoop.yarn.api.records.ApplicationId; +import org.apache.hadoop.yarn.api.records.ApplicationReport; +import org.apache.hadoop.yarn.api.records.ApplicationSubmissionContext; +import org.apache.hadoop.yarn.api.records.ContainerLaunchContext; +import org.apache.hadoop.yarn.api.records.Token; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.exceptions.YarnException; +import org.apache.hadoop.yarn.factories.RecordFactory; +import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; +import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp; +import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMAppState; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler; +import org.apache.hadoop.yarn.util.Records; +import org.apache.hadoop.yarn.util.resource.Resources; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +public class TestAMRMTokenRetrieval { + + private final static String kerberosRule = "RULE:[1:$1@$0](.*@EXAMPLE.COM)s/@.*//\nDEFAULT"; + + static { + KerberosName.setRules(kerberosRule); + } + + private static final UserGroupInformation owner = + UserGroupInformation.createRemoteUser("owner"); + private static final UserGroupInformation other = + UserGroupInformation.createRemoteUser("other"); + private static final UserGroupInformation ownerKerb = + UserGroupInformation.createRemoteUser("owner@EXAMPLE.COM"); + private static final UserGroupInformation otherKerb = + UserGroupInformation.createRemoteUser("other@EXAMPLE.COM"); + private final static RecordFactory recordFactory = + RecordFactoryProvider.getRecordFactory(null); + + private ResourceManager resourceManager; + + @Before + public void setup() { + Configuration conf = new YarnConfiguration(); + conf.setClass(YarnConfiguration.RM_SCHEDULER, + TestMoveApplication.FifoSchedulerWithMove.class, FifoScheduler.class); + conf.set(YarnConfiguration.YARN_ADMIN_ACL, " "); + conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true); + resourceManager = new ResourceManager(); + resourceManager.init(conf); + resourceManager.getRMContext().getContainerTokenSecretManager().rollMasterKey(); + resourceManager.getRMContext().getNMTokenSecretManager().rollMasterKey(); + resourceManager.start(); + } + + @Test + public void testGetAMRMTokenByOwner() throws Exception { + ApplicationId unmanagedAppKerberizedOwner = + submitApplication(ownerKerb, true); + + Token amrmToken = getAMRMTokenUsingGetApplicationReport(ownerKerb, + unmanagedAppKerberizedOwner); + assertNotNull(amrmToken); + + ApplicationId unmanagedAppRegularOwner = + submitApplication(owner, true); + + Token amrmToken1 = getAMRMTokenUsingGetApplicationReport(owner, + unmanagedAppRegularOwner); + assertNotNull(amrmToken1); + + ApplicationId managedAppKerberizedOwner = + submitApplication(ownerKerb, false); + + Token amrmToken2 = getAMRMTokenUsingGetApplicationReport(ownerKerb, + managedAppKerberizedOwner); + assertNull(amrmToken2); + + ApplicationId managedAppRegularOwner = + submitApplication(owner, false); + + Token amrmToken3 = getAMRMTokenUsingGetApplicationReport(owner, + managedAppRegularOwner); + assertNull(amrmToken3); + + /* + While ownerKerb ("OWNER@EXAMPLE.COM") and owner ("owner") represent two + different principles. In the RM they map to the same short name, + "owner", in other words both ownerKerb and owner map to a single user + within the RM. For this reason we expect the getApplications request to + return 2 AMRMTokens instead of 1. So in summary, a single user named + "owner" has submitted 4 apps, 2 of which are unmanaged and therefore + contain an AMRMToken in their application reports. + */ + + List ownerAMRMTokens = getAMRMTokensUsingGetApplications(owner); + assertTrue(ownerAMRMTokens.size() == 2); + + List kerberizedOwnerAMRMTokens = + getAMRMTokensUsingGetApplications(ownerKerb); + assertTrue(kerberizedOwnerAMRMTokens.size() == 2); + } + + @Test + public void testGetAMRMTokenByOtherUser() throws Exception { + ApplicationId unmanagedAppKerberizedOwner = + submitApplication(ownerKerb, true); + ApplicationId unmanagedAppRegularOwner = submitApplication(owner, true); + + Token amrmToken = getAMRMTokenUsingGetApplicationReport(otherKerb, + unmanagedAppKerberizedOwner); + assertNull(amrmToken); + + Token amrmToken1 = getAMRMTokenUsingGetApplicationReport(other, + unmanagedAppRegularOwner); + assertNull(amrmToken1); + + List otherAMRMTokens1 = getAMRMTokensUsingGetApplications(other); + assertTrue(otherAMRMTokens1.isEmpty()); + + List otherAMRMTokens2 = + getAMRMTokensUsingGetApplications(otherKerb); + assertTrue(otherAMRMTokens2.isEmpty()); + } + + private ApplicationId submitApplication(UserGroupInformation submitter, + boolean isUnmanaged) throws YarnException, IOException, InterruptedException { + GetNewApplicationRequest request = + Records.newRecord(GetNewApplicationRequest.class); + GetNewApplicationResponse newApp = + this.resourceManager.getClientRMService().getNewApplication(request); + + ApplicationSubmissionContext context = + recordFactory.newRecordInstance(ApplicationSubmissionContext.class); + context.setApplicationId(newApp.getApplicationId()); + context.setQueue("test"); + context.setUnmanagedAM(isUnmanaged); + + ContainerLaunchContext amContainer + = Records.newRecord(ContainerLaunchContext.class); + context.setAMContainerSpec(amContainer); + context.setResource(Resources.createResource( + YarnConfiguration.DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_MB)); + + final SubmitApplicationRequest submitApplicationRequest = recordFactory + .newRecordInstance(SubmitApplicationRequest.class); + submitApplicationRequest.setApplicationSubmissionContext(context); + + submitter.doAs(new PrivilegedExceptionAction() { + @Override + public Object run() throws Exception { + resourceManager.getClientRMService() + .submitApplication(submitApplicationRequest); + return null; + } + }); + + RMApp app = resourceManager.rmContext.getRMApps() + .get(newApp.getApplicationId()); + + for(int i = 0; (app.getState() != RMAppState.ACCEPTED) && i < 20; i++) { + Thread.sleep(100); + } + assertTrue(app.getState() == RMAppState.ACCEPTED); + + return newApp.getApplicationId(); + } + + private Token getAMRMTokenUsingGetApplicationReport(UserGroupInformation requester, + ApplicationId appId) throws IOException, InterruptedException { + final GetApplicationReportRequest applicationReportRequest = recordFactory + .newRecordInstance(GetApplicationReportRequest.class); + applicationReportRequest.setApplicationId(appId); + + return requester.doAs(new PrivilegedExceptionAction() { + @Override + public Token run() throws Exception { + GetApplicationReportResponse applicationReportResponse = + resourceManager.getClientRMService() + .getApplicationReport(applicationReportRequest); + + return applicationReportResponse.getApplicationReport().getAMRMToken(); + } + }); + } + + private List getAMRMTokensUsingGetApplications(UserGroupInformation requester) + throws IOException, InterruptedException { + final GetApplicationsRequest getApplicationsRequest = recordFactory + .newRecordInstance(GetApplicationsRequest.class); + + return requester.doAs(new PrivilegedExceptionAction>() { + @Override + public List run() throws Exception { + GetApplicationsResponse applications = resourceManager + .getClientRMService().getApplications(getApplicationsRequest); + + List amRMTokens = new ArrayList(); + + for (ApplicationReport appReport : applications.getApplicationList()) { + if (appReport.getAMRMToken() != null) { + amRMTokens.add(appReport.getAMRMToken()); + } + } + + return amRMTokens; + } + }); + } + + @After + public void tearDown() { + resourceManager.stop(); + } + +}