diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java index c4e8ff2b963..c6ec6fddfbf 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java @@ -3158,6 +3158,14 @@ public static boolean areNodeLabelsEnabled( public static final String NM_SCRIPT_BASED_NODE_LABELS_PROVIDER_SCRIPT_OPTS = NM_SCRIPT_BASED_NODE_LABELS_PROVIDER_PREFIX + "opts"; + /* + * Support to view apps for given user in secure cluster. + */ + public static final String DISPLAY_APPS_FOR_LOGGED_IN_USER = + RM_PREFIX + "display.per-user-apps"; + public static final boolean DEFAULT_DISPLAY_APPS_FOR_LOGGED_IN_USER = + false; + // RM and NM CSRF props public static final String REST_CSRF = "webapp.rest-csrf."; public static final String RM_CSRF_PREFIX = RM_PREFIX + REST_CSRF; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java index d98e558f145..a0c3db622b4 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java @@ -215,6 +215,8 @@ private ReservationSystem reservationSystem; private ReservationInputValidator rValidator; + private boolean displayPerUserApps = false; + private static final EnumSet ACTIVE_APP_STATES = EnumSet.of( RMAppState.ACCEPTED, RMAppState.RUNNING); @@ -275,7 +277,11 @@ protected void serviceStart() throws Exception { } refreshServiceAcls(conf, RMPolicyProvider.getInstance()); } - + + this.displayPerUserApps = conf.getBoolean( + YarnConfiguration.DISPLAY_APPS_FOR_LOGGED_IN_USER, + YarnConfiguration.DEFAULT_DISPLAY_APPS_FOR_LOGGED_IN_USER); + this.server.start(); clientBindAddress = conf.updateConnectAddr(YarnConfiguration.RM_BIND_HOST, YarnConfiguration.RM_ADDRESS, @@ -909,6 +915,12 @@ public void remove() { continue; } + // Given RM is configured to display apps per user, skip apps to which + // this caller doesn't have access to view. + if (displayPerUserApps && !allowAccess) { + continue; + } + reports.add(application.createAndGetApplicationReport( callerUGI.getUserName(), allowAccess)); } @@ -1804,4 +1816,9 @@ public GetAllResourceTypeInfoResponse getResourceTypeInfo( response.setResourceTypeInfo(ResourceUtils.getResourcesTypeInfo()); return response; } + + @VisibleForTesting + public void setDisplayPerUserApps(boolean displayPerUserApps) { + this.displayPerUserApps = displayPerUserApps; + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMService.java index 49718a2af72..35b3f86d015 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMService.java @@ -1121,6 +1121,12 @@ public void handle(Event event) {} assertEquals("Incorrect number of applications for user", 3, rmService.getApplications(request).getApplicationList().size()); + rmService.setDisplayPerUserApps(true); + userSet.clear(); + assertEquals("Incorrect number of applications for user", 6, + rmService.getApplications(request).getApplicationList().size()); + rmService.setDisplayPerUserApps(false); + // Check tags request = GetApplicationsRequest.newInstance( ApplicationsRequestScope.ALL, null, null, null, null, null, null, @@ -2107,4 +2113,72 @@ protected ClientRMService createClientRMService() { rm.stop(); rpc.stopProxy(client, conf); } + + @Test + public void testGetApplicationsWithPerUserApps() + throws IOException, YarnException { + /* + * Submit 3 applications alternately in two queues + */ + // Basic setup + YarnScheduler yarnScheduler = mockYarnScheduler(); + RMContext rmContext = mock(RMContext.class); + mockRMContext(yarnScheduler, rmContext); + RMStateStore stateStore = mock(RMStateStore.class); + when(rmContext.getStateStore()).thenReturn(stateStore); + doReturn(mock(RMTimelineCollectorManager.class)).when(rmContext) + .getRMTimelineCollectorManager(); + + RMAppManager appManager = new RMAppManager(rmContext, yarnScheduler, null, + mock(ApplicationACLsManager.class), new Configuration()); + when(rmContext.getDispatcher().getEventHandler()) + .thenReturn(new EventHandler() { + public void handle(Event event) { + } + }); + + // Simulate Queue ACL manager which returns false always + QueueACLsManager queueAclsManager = mock(QueueACLsManager.class); + when(queueAclsManager.checkAccess(any(UserGroupInformation.class), + any(QueueACL.class), any(RMApp.class), any(String.class), + anyListOf(String.class))).thenReturn(false); + + // Simulate app ACL manager which returns false always + ApplicationACLsManager appAclsManager = mock(ApplicationACLsManager.class); + when(appAclsManager.checkAccess(eq(UserGroupInformation.getCurrentUser()), + any(ApplicationAccessType.class), any(String.class), + any(ApplicationId.class))).thenReturn(false); + ClientRMService rmService = new ClientRMService(rmContext, yarnScheduler, + appManager, appAclsManager, queueAclsManager, null); + rmService.init(new Configuration()); + + // Initialize appnames and queues + String[] queues = {QUEUE_1, QUEUE_2}; + String[] appNames = {MockApps.newAppName(), MockApps.newAppName(), + MockApps.newAppName()}; + ApplicationId[] appIds = {getApplicationId(101), getApplicationId(102), + getApplicationId(103)}; + List tags = Arrays.asList("Tag1", "Tag2", "Tag3"); + + long[] submitTimeMillis = new long[3]; + // Submit applications + for (int i = 0; i < appIds.length; i++) { + ApplicationId appId = appIds[i]; + SubmitApplicationRequest submitRequest = mockSubmitAppRequest(appId, + appNames[i], queues[i % queues.length], + new HashSet(tags.subList(0, i + 1))); + rmService.submitApplication(submitRequest); + submitTimeMillis[i] = System.currentTimeMillis(); + } + + // Test different cases of ClientRMService#getApplications() + GetApplicationsRequest request = GetApplicationsRequest.newInstance(); + assertEquals("Incorrect total number of apps", 6, + rmService.getApplications(request).getApplicationList().size()); + + rmService.setDisplayPerUserApps(true); + assertEquals("Incorrect number of applications for user", 0, + rmService.getApplications(request).getApplicationList().size()); + rmService.setDisplayPerUserApps(false); + } }