/** * 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.io.IOException; import java.util.HashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.fs.CommonConfigurationKeys; import org.apache.hadoop.security.GroupMappingServiceProvider; import org.apache.hadoop.yarn.api.records.ApplicationAccessType; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.server.resourcemanager.MockRM; import org.apache.hadoop.yarn.server.resourcemanager.RMContext; 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.SchedulerApplication; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.SimpleGroupsMapping; import org.junit.After; import org.junit.Assert; import org.junit.Test; public class TestQueueMappings { private static final Log LOG = LogFactory.getLog(TestQueueMappings.class); private static final String Q1 = "q1"; private static final String Q2 = "q2"; private final static String Q1_PATH = CapacitySchedulerConfiguration.ROOT + "." + Q1; private final static String Q2_PATH = CapacitySchedulerConfiguration.ROOT + "." + Q2; private MockRM resourceManager; @After public void tearDown() throws Exception { if (resourceManager != null) { LOG.info("Stopping the resource manager"); resourceManager.stop(); } } private void setupQueueConfiguration(CapacitySchedulerConfiguration conf) { // Define top-level queues conf.setQueues(CapacitySchedulerConfiguration.ROOT, new String[] { Q1, Q2 }); conf.setCapacity(Q1_PATH, 10); conf.setCapacity(Q2_PATH, 90); LOG.info("Setup top-level queues q1 and q2"); } @Test (timeout = 60000) public void testQueueMapping() throws Exception { CapacitySchedulerConfiguration csConf = new CapacitySchedulerConfiguration(); setupQueueConfiguration(csConf); YarnConfiguration conf = new YarnConfiguration(csConf); CapacityScheduler cs = new CapacityScheduler(); RMContext rmContext = TestUtils.getMockRMContext(); cs.setConf(conf); cs.setRMContext(rmContext); cs.init(conf); cs.start(); conf.setClass(CommonConfigurationKeys.HADOOP_SECURITY_GROUP_MAPPING, SimpleGroupsMapping.class, GroupMappingServiceProvider.class); conf.set(CapacitySchedulerConfiguration.ENABLE_QUEUE_MAPPING_OVERRIDE, "true"); // configuration parsing tests - negative test cases checkInvalidQMapping(conf, cs, "x:a:b", "invalid specifier"); checkInvalidQMapping(conf, cs, "u:a", "no queue specified"); checkInvalidQMapping(conf, cs, "g:a", "no queue specified"); checkInvalidQMapping(conf, cs, "u:a:b,g:a", "multiple mappings with invalid mapping"); checkInvalidQMapping(conf, cs, "u:a:b,g:a:d:e", "too many path segments"); checkInvalidQMapping(conf, cs, "u::", "empty source and queue"); checkInvalidQMapping(conf, cs, "u:", "missing source missing queue"); checkInvalidQMapping(conf, cs, "u:a:", "empty source missing q"); // simple base case for mapping user to queue conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, "u:a:" + Q1); cs.reinitialize(conf, null); checkQMapping("a", Q1, cs); // group mapping test conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, "g:agroup:" + Q1); cs.reinitialize(conf, null); checkQMapping("a", Q1, cs); // %user tests conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, "u:%user:" + Q2); cs.reinitialize(conf, null); checkQMapping("a", Q2, cs); conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, "u:%user:%user"); cs.reinitialize(conf, null); checkQMapping("a", "a", cs); // %primary_group tests conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, "u:%user:%primary_group"); cs.reinitialize(conf, null); checkQMapping("a", "agroup", cs); // non-primary group mapping conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, "g:asubgroup1:" + Q1); cs.reinitialize(conf, null); checkQMapping("a", Q1, cs); // space trimming conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, " u : a : " + Q1); cs.reinitialize(conf, null); checkQMapping("a", Q1, cs); csConf = new CapacitySchedulerConfiguration(); csConf.set(YarnConfiguration.RM_SCHEDULER, CapacityScheduler.class.getName()); setupQueueConfiguration(csConf); conf = new YarnConfiguration(csConf); resourceManager = new MockRM(csConf); resourceManager.start(); conf.setClass(CommonConfigurationKeys.HADOOP_SECURITY_GROUP_MAPPING, SimpleGroupsMapping.class, GroupMappingServiceProvider.class); conf.set(CapacitySchedulerConfiguration.ENABLE_QUEUE_MAPPING_OVERRIDE, "true"); conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, "u:user:" + Q1); resourceManager.getResourceScheduler().reinitialize(conf, null); // ensure that if the user specifies a Q that is still overriden checkAppQueue(resourceManager, "user", Q2, Q1); // toggle admin override and retry conf.setBoolean( CapacitySchedulerConfiguration.ENABLE_QUEUE_MAPPING_OVERRIDE, false); conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, "u:user:" + Q1); setupQueueConfiguration(csConf); resourceManager.getResourceScheduler().reinitialize(conf, null); checkAppQueue(resourceManager, "user", Q2, Q2); // ensure that if a user does not specify a Q, the user mapping is used checkAppQueue(resourceManager, "user", null, Q1); conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, "g:usergroup:" + Q2); setupQueueConfiguration(csConf); resourceManager.getResourceScheduler().reinitialize(conf, null); // ensure that if a user does not specify a Q, the group mapping is used checkAppQueue(resourceManager, "user", null, Q2); // if the mapping specifies a queue that does not exist, the job is rejected conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, "u:user:non_existent_queue"); setupQueueConfiguration(csConf); boolean fail = false; try { resourceManager.getResourceScheduler().reinitialize(conf, null); } catch (IOException ioex) { fail = true; } Assert.assertTrue("queue initialization failed for non-existent q", fail); resourceManager.stop(); } private void checkAppQueue(MockRM resourceManager, String user, String submissionQueue, String expected) throws Exception { RMApp app = resourceManager.submitApp(200, "name", user, new HashMap<ApplicationAccessType, String>(), false, submissionQueue, -1, null, "MAPREDUCE", false); RMAppState expectedState = expected.isEmpty() ? RMAppState.FAILED : RMAppState.ACCEPTED; resourceManager.waitForState(app.getApplicationId(), expectedState); // get scheduler app CapacityScheduler cs = (CapacityScheduler) resourceManager.getResourceScheduler(); SchedulerApplication schedulerApp = cs.getSchedulerApplications().get(app.getApplicationId()); String queue = ""; if (schedulerApp != null) { queue = schedulerApp.getQueue().getQueueName(); } Assert.assertTrue("expected " + expected + " actual " + queue, expected.equals(queue)); Assert.assertEquals(expected, app.getQueue()); } private void checkInvalidQMapping(YarnConfiguration conf, CapacityScheduler cs, String mapping, String reason) throws IOException { boolean fail = false; try { conf.set(CapacitySchedulerConfiguration.QUEUE_MAPPING, mapping); cs.reinitialize(conf, null); } catch (IOException ex) { fail = true; } Assert.assertTrue("invalid mapping did not throw exception for " + reason, fail); } private void checkQMapping(String user, String expected, CapacityScheduler cs) throws IOException { String actual = cs.getMappedQueueForTest(user); Assert.assertTrue("expected " + expected + " actual " + actual, expected.equals(actual)); } }