[ https://issues.apache.org/jira/browse/YARN-11672?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17839644#comment-17839644 ]
ASF GitHub Bot commented on YARN-11672: --------------------------------------- tomicooler commented on code in PR #6734: URL: https://github.com/apache/hadoop/pull/6734#discussion_r1574695897 ########## hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsV2HandlerImpl.java: ########## @@ -0,0 +1,270 @@ +/* + * * + * 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.nodemanager.containermanager.linux.resources; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.junit.Assert; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.verifyZeroInteractions; + +/** + * Tests for the CGroups handler implementation. + */ +public class TestCGroupsV2HandlerImpl extends TestCGroupsHandlerBase { + // Create a controller file in the unified hierarchy of cgroup v2 + @Override + protected String getControllerFilePath(String controllerName) { + return new File(tmpPath, hierarchy).getAbsolutePath(); + } + + /* + * Create a mock mtab file with the following content: + * cgroup2 /path/to/parentDir cgroup2 rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot 0 0 + * + * Create the following cgroup v2 file hierarchy: + * parentDir + * ___________________________________________________ + * / \ \ + * cgroup.controllers cgroup.subtree_control test-hadoop-yarn (hierarchyDir) + * _________________ + * / \ + * cgroup.controllers cgroup.subtree_control + */ + public File createPremountedCgroups(File parentDir) + throws IOException { + String baseCgroup2Line = + "cgroup2 " + parentDir.getAbsolutePath() + + " cgroup2 rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot 0 0\n"; + File mockMtab = createFileWithContent(parentDir, UUID.randomUUID().toString(), baseCgroup2Line); + + String enabledControllers = "cpuset cpu io memory hugetlb pids rdma misc\n"; + File controllersFile = createFileWithContent(parentDir, CGroupsHandler.CGROUP_CONTROLLERS_FILE, + enabledControllers); + + File subtreeControlFile = new File(parentDir, CGroupsHandler.CGROUP_SUBTREE_CONTROL_FILE); + Assert.assertTrue("empty subtree_control file should be created", + subtreeControlFile.createNewFile()); + + File hierarchyDir = new File(parentDir, hierarchy); + if (!hierarchyDir.mkdirs()) { + String message = "Could not create directory " + hierarchyDir.getAbsolutePath(); + throw new IOException(message); + } + hierarchyDir.deleteOnExit(); + + FileUtils.copyFile(controllersFile, new File(hierarchyDir, + CGroupsHandler.CGROUP_CONTROLLERS_FILE)); + FileUtils.copyFile(subtreeControlFile, new File(hierarchyDir, + CGroupsHandler.CGROUP_SUBTREE_CONTROL_FILE)); + + return mockMtab; + } + + @Test + public void testCGroupPaths() throws IOException, ResourceHandlerException { + verifyZeroInteractions(privilegedOperationExecutorMock); + File parentDir = new File(tmpPath); + File mtab = createPremountedCgroups(parentDir); + assertTrue("Sample subsystem should be created", + new File(controllerPath).exists()); + + CGroupsHandler cGroupsHandler = new CGroupsV2HandlerImpl(createNoMountConfiguration(hierarchy), + privilegedOperationExecutorMock, mtab.getAbsolutePath()); + cGroupsHandler.initializeCGroupController(controller); + + String testCGroup = "container_01"; + String expectedPath = + controllerPath + Path.SEPARATOR + testCGroup; + String path = cGroupsHandler.getPathForCGroup(controller, testCGroup); + Assert.assertEquals(expectedPath, path); + + String expectedPathTasks = expectedPath + Path.SEPARATOR + + CGroupsHandler.CGROUP_PROCS_FILE; + path = cGroupsHandler.getPathForCGroupTasks(controller, testCGroup); + Assert.assertEquals(expectedPathTasks, path); + + String param = CGroupsHandler.CGROUP_PARAM_CLASSID; + String expectedPathParam = expectedPath + Path.SEPARATOR + + controller.getName() + "." + param; + path = cGroupsHandler.getPathForCGroupParam(controller, testCGroup, param); + Assert.assertEquals(expectedPathParam, path); + } + + @Test(expected = UnsupportedOperationException.class) + public void testUnsupportedMountConfiguration() throws Exception { + //As per junit behavior, we expect a new mock object to be available + //in this test. + verifyZeroInteractions(privilegedOperationExecutorMock); + CGroupsHandler cGroupsHandler; + File mtab = createEmptyMtabFile(); + + assertTrue("Sample subsystem should be created", + new File(controllerPath).mkdirs()); + + cGroupsHandler = new CGroupsV2HandlerImpl(createMountConfiguration(), + privilegedOperationExecutorMock, mtab.getAbsolutePath()); + cGroupsHandler.initializeCGroupController(controller); + } + + @Test + public void testCGroupOperations() throws IOException, ResourceHandlerException { + verifyZeroInteractions(privilegedOperationExecutorMock); + File parentDir = new File(tmpPath); + File mtab = createPremountedCgroups(parentDir); + assertTrue("Sample subsystem should be created", + new File(controllerPath).exists()); + + CGroupsHandler cGroupsHandler = new CGroupsV2HandlerImpl(createNoMountConfiguration(hierarchy), + privilegedOperationExecutorMock, mtab.getAbsolutePath()); + cGroupsHandler.initializeCGroupController(controller); + + String testCGroup = "container_01"; + String expectedPath = controllerPath + + Path.SEPARATOR + testCGroup; + String path = cGroupsHandler.createCGroup(controller, testCGroup); + + assertTrue(new File(expectedPath).exists()); + Assert.assertEquals(expectedPath, path); + + String param = "test_param"; + String paramValue = "test_param_value"; + + cGroupsHandler + .updateCGroupParam(controller, testCGroup, param, paramValue); + String paramPath = expectedPath + Path.SEPARATOR + controller.getName() + + "." + param; + File paramFile = new File(paramPath); + + assertTrue(paramFile.exists()); + Assert.assertEquals(paramValue, new String(Files.readAllBytes( + paramFile.toPath()))); + Assert.assertEquals(paramValue, + cGroupsHandler.getCGroupParam(controller, testCGroup, param)); + } + + /** + * Tests whether mtab parsing works as expected with a valid hierarchy set. + * @throws Exception the test will fail + */ + @Test + public void testMtabParsing() throws Exception { + // Initialize mtab and cgroup dir + File parentDir = new File(tmpPath); + // create mock cgroup + File mockMtabFile = createPremountedCgroups(parentDir); + + CGroupsV2HandlerImpl cGroupsHandler = new CGroupsV2HandlerImpl( + createMountConfiguration(), + privilegedOperationExecutorMock, mockMtabFile.getAbsolutePath()); + + // Run mtabs parsing + Map<String, Set<String>> newMtab = + cGroupsHandler.parseMtab(mockMtabFile.getAbsolutePath()); + Map<CGroupsHandler.CGroupController, String> controllerPaths = + cGroupsHandler.initializeControllerPathsFromMtab( + newMtab); + + // Verify + Assert.assertEquals(4, controllerPaths.size()); + assertTrue(controllerPaths + .containsKey(CGroupsHandler.CGroupController.CPU)); + assertTrue(controllerPaths + .containsKey(CGroupsHandler.CGroupController.MEMORY)); + String cpuDir = controllerPaths.get(CGroupsHandler.CGroupController.CPU); + String memoryDir = + controllerPaths.get(CGroupsHandler.CGroupController.MEMORY); + Assert.assertEquals(parentDir.getAbsolutePath(), cpuDir); + Assert.assertEquals(parentDir.getAbsolutePath(), memoryDir); + } + + @Test + public void testManualCgroupSetting() throws Exception { + YarnConfiguration conf = new YarnConfiguration(); + conf.set(YarnConfiguration.NM_LINUX_CONTAINER_CGROUPS_MOUNT_PATH, tmpPath); + conf.set(YarnConfiguration.NM_LINUX_CONTAINER_CGROUPS_HIERARCHY, + "/hadoop-yarn"); + + File subCgroup = new File(tmpPath, "/hadoop-yarn"); + Assert.assertTrue("temp dir should be created", subCgroup.mkdirs()); + subCgroup.deleteOnExit(); + + String enabledControllers = "cpuset cpu io memory hugetlb pids rdma misc\n"; + createFileWithContent(subCgroup, CGroupsHandler.CGROUP_CONTROLLERS_FILE, enabledControllers); + + File subtreeControlFile = new File(subCgroup.getAbsolutePath(), + CGroupsHandler.CGROUP_SUBTREE_CONTROL_FILE); + Assert.assertTrue("empty subtree_control file should be created", + subtreeControlFile.createNewFile()); + + CGroupsV2HandlerImpl cGroupsHandler = new CGroupsV2HandlerImpl(conf, null); + cGroupsHandler.initializeCGroupController(CGroupsHandler.CGroupController.CPU); + + Assert.assertEquals("CPU cgroup path was not set", subCgroup.getAbsolutePath(), + new File(cGroupsHandler.getPathForCGroup( + CGroupsHandler.CGroupController.CPU, "")).getAbsolutePath()); + + // Verify that the subtree control file was updated + String subtreeControllersEnabledString = FileUtils.readFileToString(subtreeControlFile, + StandardCharsets.UTF_8); + Set<String> subtreeControllersEnabled = new HashSet<>(Arrays.asList( + subtreeControllersEnabledString.replace("+", "").split(" "))); + + Assert.assertEquals("The newly added controllers doesn't contain + signs", + cGroupsHandler.getValidCGroups().size(), + StringUtils.countMatches(subtreeControllersEnabledString, "+")); + Assert.assertEquals(cGroupsHandler.getValidCGroups().size(), subtreeControllersEnabled.size()); + Assert.assertTrue("Controllers not enabled in subtree control file", + cGroupsHandler.getValidCGroups().containsAll(subtreeControllersEnabled)); + + // Test that the subtree control file is updated correctly even + // if it doesn't contain all the controllers + subtreeControlFile.delete(); + createFileWithContent(subCgroup, CGroupsHandler.CGROUP_SUBTREE_CONTROL_FILE, "cpu io"); + cGroupsHandler.initializeCGroupController(CGroupsHandler.CGroupController.CPU); + + subtreeControllersEnabledString = FileUtils.readFileToString(subtreeControlFile, + StandardCharsets.UTF_8); + subtreeControllersEnabled = new HashSet<>(Arrays.asList( + subtreeControllersEnabledString.replace("+", "").split(" "))); + + Assert.assertEquals("The newly added controllers doesn't contain + signs", Review Comment: Same as above. > Create a CgroupHandler implementation for cgroup v2 > --------------------------------------------------- > > Key: YARN-11672 > URL: https://issues.apache.org/jira/browse/YARN-11672 > Project: Hadoop YARN > Issue Type: Sub-task > Reporter: Benjamin Teke > Assignee: Benjamin Teke > Priority: Major > Labels: pull-request-available > > [CGroupsHandler's|https://github.com/apache/hadoop/blob/69b328943edf2f61c8fc139934420e3f10bf3813/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsHandler.java#L36] > current implementation holds the functionality to mount and setup the YARN > specific cgroup v1 functionality. A similar v2 implementation should be > created that allows initialising the v2 structure. -- This message was sent by Atlassian Jira (v8.20.10#820010) --------------------------------------------------------------------- To unsubscribe, e-mail: yarn-issues-unsubscr...@hadoop.apache.org For additional commands, e-mail: yarn-issues-h...@hadoop.apache.org