diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsControllerPaths.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsControllerPaths.java new file mode 100644 index 00000000000..2461eae8fca --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsControllerPaths.java @@ -0,0 +1,111 @@ +/* + * 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 com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Maps; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsHandler.CGroupController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.List; +import java.util.Map; + +/** + * Stores cgroups paths for all {@link CGroupController}. + */ +public class CGroupsControllerPaths { + private static final Logger LOG = + LoggerFactory.getLogger(CGroupsControllerPaths.class); + + private final Map controllerPaths = + Maps.newHashMap(); + + public void storePath(CGroupController controller, String path) { + controllerPaths.put(controller, path); + } + + public String getPath(CGroupController controller) { + return controllerPaths.get(controller); + } + + public boolean hasPath(CGroupController controller) { + return controllerPaths.containsKey(controller); + } + + public boolean isEmpty() { + return controllerPaths.isEmpty(); + } + + public int getNumberOfPaths() { + return controllerPaths.size(); + } + + @VisibleForTesting + static CGroupsControllerPaths initializeFromMountConfig( + CGroupsMountConfig mountConfig) { + CGroupsControllerPaths controllerPaths = new CGroupsControllerPaths(); + + for (CGroupController controller : + CGroupController.values()) { + String controllerName = controller.getName(); + String controllerPath = findControllerPathInMountConfig(controllerName, + mountConfig); + + if (controllerPath != null) { + controllerPaths.storePath(controller, controllerPath); + } + } + return controllerPaths; + } + + /** + * Find the hierarchy of the controller. + * The kernel ensures that a controller can only be part of a single hierarchy. + * The controller can be part of multiple mount points, if they belong to the + * same hierarchy. + * @param controller subsystem like cpu, cpuset, etc... + * @param mountConfig stores map of paths to controllers + * @return The first mount path that has the requested controller and + * is also readable. If no path found for a controller, + * the return value is null. + */ + @VisibleForTesting + public static String findControllerPathInMountConfig(String controller, + CGroupsMountConfig mountConfig) { + List paths = mountConfig.getPathsForController(controller); + if (paths != null) { + for (String path : paths) { + if (new File(path).canRead()) { + return path; + } else { + LOG.warn(String.format( + "Skipping inaccessible cgroup mount point %s", path)); + } + } + } + return null; + } + + @Override + public String toString() { + return "CGroupsControllerPaths{" + + "controllerPaths=" + controllerPaths + + '}'; + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsHandlerImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsHandlerImpl.java index d2ec207f157..5226b2cd56c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsHandlerImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsHandlerImpl.java @@ -29,8 +29,6 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileUtil; import org.apache.hadoop.fs.Path; -import org.apache.hadoop.io.IOUtils; -import org.apache.hadoop.util.Shell; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationException; @@ -41,15 +39,8 @@ import java.io.*; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Support for interacting with various CGroup subsystems. Thread-safe. @@ -62,7 +53,7 @@ private static final Logger LOG = LoggerFactory.getLogger(CGroupsHandlerImpl.class); private static final String MTAB_FILE = "/proc/mounts"; - private static final String CGROUPS_FSTYPE = "cgroup"; + private final String mtabFile; private final String cGroupPrefix; @@ -70,8 +61,8 @@ private final String cGroupMountPath; private final long deleteCGroupTimeout; private final long deleteCGroupDelay; - private Map controllerPaths; - private Map> parsedMtab; + private CGroupsControllerPaths controllerPaths; + private CGroupsMountConfig cGroupsMountConfig; private final ReadWriteLock rwLock; private final PrivilegedOperationExecutor privilegedOperationExecutor; private final Clock clock; @@ -84,6 +75,7 @@ * @param mtab mount file location * @throws ResourceHandlerException if initialization failed */ + @VisibleForTesting CGroupsHandlerImpl(Configuration conf, PrivilegedOperationExecutor privilegedOperationExecutor, String mtab) throws ResourceHandlerException { @@ -103,12 +95,12 @@ this.deleteCGroupDelay = conf.getLong(YarnConfiguration.NM_LINUX_CONTAINER_CGROUPS_DELETE_DELAY, YarnConfiguration.DEFAULT_NM_LINUX_CONTAINER_CGROUPS_DELETE_DELAY); - this.controllerPaths = new HashMap<>(); - this.parsedMtab = new HashMap<>(); + this.controllerPaths = new CGroupsControllerPaths(); + this.cGroupsMountConfig = new CGroupsMountConfig(); this.rwLock = new ReentrantReadWriteLock(); this.privilegedOperationExecutor = privilegedOperationExecutor; this.clock = SystemClock.getInstance(); - mtabFile = mtab; + this.mtabFile = mtab; init(); } @@ -132,154 +124,49 @@ private void init() throws ResourceHandlerException { public String getControllerPath(CGroupController controller) { try { rwLock.readLock().lock(); - return controllerPaths.get(controller); + return controllerPaths.getPath(controller); } finally { rwLock.readLock().unlock(); } } + /** + * Cluster admins may have some subsystems mounted in specific locations + * We'll attempt to figure out mount points. We do this even if we plan + * to mount cgroups into our own tree to control the path permissions or + * to mount subsystems that are not mounted previously. + * The subsystems for new and existing mount points have to match, and + * the same hierarchy will be mounted at each mount point with the same + * subsystem set. + * @throws ResourceHandlerException + */ private void initializeControllerPaths() throws ResourceHandlerException { - // Cluster admins may have some subsystems mounted in specific locations - // We'll attempt to figure out mount points. We do this even if we plan - // to mount cgroups into our own tree to control the path permissions or - // to mount subsystems that are not mounted previously. - // The subsystems for new and existing mount points have to match, and - // the same hierarchy will be mounted at each mount point with the same - // subsystem set. - - Map> newMtab = null; - Map cPaths; + final CGroupsMountConfig mountConfig; + final CGroupsControllerPaths ctrlPaths; try { if (this.cGroupMountPath != null && !this.enableCGroupMount) { - newMtab = ResourceHandlerModule. + mountConfig = CgroupsFileSystemMountParser. parseConfiguredCGroupPath(this.cGroupMountPath); + } else { + mountConfig = MtabFileParser.parse(mtabFile); } - - if (newMtab == null) { - // parse mtab - newMtab = parseMtab(mtabFile); - } - - // find cgroup controller paths - cPaths = initializeControllerPathsFromMtab(newMtab); + ctrlPaths = CGroupsControllerPaths.initializeFromMountConfig(mountConfig); } catch (IOException e) { LOG.warn("Failed to initialize controller paths! Exception: " + e); throw new ResourceHandlerException( - "Failed to initialize controller paths!"); + "Failed to initialize controller paths!", e); } // we want to do a bulk update without the paths changing concurrently try { rwLock.writeLock().lock(); - controllerPaths = cPaths; - parsedMtab = newMtab; + this.controllerPaths = ctrlPaths; + this.cGroupsMountConfig = mountConfig; } finally { rwLock.writeLock().unlock(); } } - @VisibleForTesting - static Map initializeControllerPathsFromMtab( - Map> parsedMtab) - throws ResourceHandlerException { - Map ret = new HashMap<>(); - - for (CGroupController controller : CGroupController.values()) { - String subsystemName = controller.getName(); - String controllerPath = findControllerInMtab(subsystemName, parsedMtab); - - if (controllerPath != null) { - ret.put(controller, controllerPath); - } - } - return ret; - } - - /* We are looking for entries of the form: - * none /cgroup/path/mem cgroup rw,memory 0 0 - * - * Use a simple pattern that splits on the five spaces, and - * grabs the 2, 3, and 4th fields. - */ - - private static final Pattern MTAB_FILE_FORMAT = Pattern.compile( - "^[^\\s]+\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s[^\\s]+\\s[^\\s]+$"); - - /* - * Returns a map: path -> mount options - * for mounts with type "cgroup". Cgroup controllers will - * appear in the list of options for a path. - */ - @VisibleForTesting - static Map> parseMtab(String mtab) - throws IOException { - Map> ret = new HashMap<>(); - BufferedReader in = null; - Set validCgroups = - CGroupsHandler.CGroupController.getValidCGroups(); - - try { - FileInputStream fis = new FileInputStream(new File(mtab)); - in = new BufferedReader(new InputStreamReader(fis, "UTF-8")); - - for (String str = in.readLine(); str != null; - str = in.readLine()) { - Matcher m = MTAB_FILE_FORMAT.matcher(str); - boolean mat = m.find(); - if (mat) { - String path = m.group(1); - String type = m.group(2); - String options = m.group(3); - - if (type.equals(CGROUPS_FSTYPE)) { - Set cgroupList = - new HashSet<>(Arrays.asList(options.split(","))); - // Collect the valid subsystem names - cgroupList.retainAll(validCgroups); - ret.put(path, cgroupList); - } - } - } - } catch (IOException e) { - if (Shell.LINUX) { - throw new IOException("Error while reading " + mtab, e); - } else { - // Ignore the error, if we are running on an os other than Linux - LOG.warn("Error while reading " + mtab, e); - } - } finally { - IOUtils.cleanupWithLogger(LOG, in); - } - - return ret; - } - - /** - * Find the hierarchy of the subsystem. - * The kernel ensures that a subsystem can only be part of a single hierarchy. - * The subsystem can be part of multiple mount points, if they belong to the - * same hierarchy. - * @param controller subsystem like cpu, cpuset, etc... - * @param entries map of paths to mount options - * @return the first mount path that has the requested subsystem - */ - @VisibleForTesting - static String findControllerInMtab(String controller, - Map> entries) { - for (Map.Entry> e : entries.entrySet()) { - if (e.getValue().contains(controller)) { - if (new File(e.getKey()).canRead()) { - return e.getKey(); - } else { - LOG.warn(String.format( - "Skipping inaccessible cgroup mount point %s", e.getKey())); - } - } - } - - return null; - } - private void mountCGroupController(CGroupController controller) throws ResourceHandlerException { if (cGroupMountPath == null) { @@ -302,8 +189,8 @@ private void mountCGroupController(CGroupController controller) // the operation will fail String mountOptions; if (existingMountPath != null) { - mountOptions = Joiner.on(',') - .join(parsedMtab.get(existingMountPath)); + mountOptions = Joiner.on(',').join( + cGroupsMountConfig.getControllersForPath(existingMountPath)); } else { mountOptions = controller.getName(); } @@ -320,7 +207,7 @@ private void mountCGroupController(CGroupController controller) privilegedOperationExecutor.executePrivilegedOperation(op, false); //if privileged operation succeeds, update controller paths - controllerPaths.put(controller, requestedMountPath); + controllerPaths.storePath(controller, requestedMountPath); } catch (PrivilegedOperationException e) { LOG.error("Failed to mount controller: " + controller.getName()); throw new ResourceHandlerException("Failed to mount controller: " @@ -373,7 +260,7 @@ public void initializeCGroupController(CGroupController controller) throws mountCGroupController(controller); } - // We are working with a pre-mounted contoller + // We are working with a pre-mounted controller // Make sure that YARN cgroup hierarchy path exists initializePreMountedCGroupController(controller); } @@ -623,6 +510,11 @@ public String getCGroupMountPath() { return cGroupMountPath; } + @VisibleForTesting + public CGroupsControllerPaths getControllerPaths() { + return controllerPaths; + } + @Override public String toString() { return CGroupsHandlerImpl.class.getName() + "{" + diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsMountConfig.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsMountConfig.java new file mode 100644 index 00000000000..d32cd526036 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsMountConfig.java @@ -0,0 +1,46 @@ +/* + * 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 java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Stores a mapping between cgroup paths and controller names. + * Keys will be paths and values will be controller (subsystem) names. + */ +public class CGroupsMountConfig { + private Map> mappings = new HashMap<>(); + + public void mapPathToControllers(String path, Set controllers) { + mappings.put(path, controllers); + } + + public Set getControllersForPath(String path) { + return mappings.get(path); + } + + public List getPathsForController(String controller) { + return mappings.entrySet().stream() + .filter(e -> e.getValue().contains(controller)) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CgroupsFileSystemMountParser.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CgroupsFileSystemMountParser.java new file mode 100644 index 00000000000..c3244bbdaea --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CgroupsFileSystemMountParser.java @@ -0,0 +1,80 @@ +/* + * 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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Responsible to parse cgroups controller info from a given path and + * to procude a {@link CGroupsMountConfig} as a result. + */ +public class CgroupsFileSystemMountParser { + private static final Logger LOG = + LoggerFactory.getLogger(CgroupsFileSystemMountParser.class); + + private static final Set VALID_CGROUPS = + CGroupsHandler.CGroupController.getValidCGroups(); + + private CgroupsFileSystemMountParser() {} + + /** + * If a cgroup mount directory is specified, it returns cgroup directories + * with valid names. + * The requirement is that each hierarchy has to be named with the comma + * separated names of subsystems supported. + * For example: /sys/fs/cgroup/cpu,cpuacct + * @param cgroupMountPath Root cgroup mount path (/sys/fs/cgroup in the + * example above) + * @return A path to cgroup subsystem set mapping as an object of type + * {@link CGroupsMountConfig} + * @throws IOException if the specified directory cannot be listed + */ + public static CGroupsMountConfig parseConfiguredCGroupPath( + String cgroupMountPath) throws IOException { + File cgroupDir = new File(cgroupMountPath); + File[] cgroupFiles = cgroupDir.listFiles(); + if (cgroupFiles == null) { + throw new IOException("Empty cgroup mount directory specified: " + + cgroupMountPath); + } + + final CGroupsMountConfig mountConfig = new CGroupsMountConfig(); + for (File candidate: cgroupFiles) { + Set cgroupList = + new HashSet<>(Arrays.asList(candidate.getName().split(","))); + // Collect the valid subsystem names + cgroupList.retainAll(VALID_CGROUPS); + if (!cgroupList.isEmpty()) { + if (candidate.isDirectory()) { + mountConfig.mapPathToControllers(candidate.getAbsolutePath(), + cgroupList); + } else { + LOG.warn("The following cgroup is not a directory " + + candidate.getAbsolutePath()); + } + } + } + return mountConfig; + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/MtabFileParser.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/MtabFileParser.java new file mode 100644 index 00000000000..f8ae5f00eea --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/MtabFileParser.java @@ -0,0 +1,124 @@ +/* + * 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 com.google.common.annotations.VisibleForTesting; +import org.apache.hadoop.io.IOUtils; +import org.apache.hadoop.util.Shell; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsHandler.CGroupController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Responsible to parse cgroups controller info from a given mtab file + * (usually stores under /etc/mtab) and to procude a + * {@link CGroupsMountConfig} as a result. + */ +public class MtabFileParser { + private static final Logger LOG = + LoggerFactory.getLogger(MtabFileParser.class); + + private static final String CGROUPS_FSTYPE = "cgroup"; + public static final String FIELD = "[^\\s]+"; + public static final String CAPTURED_FIELD = "([^\\s]+)"; + public static final String WHITESPACE = "\\s"; + + /** We are looking for entries of the form: + * none /cgroup/path/mem cgroup rw,memory 0 0 + * + * Use a simple pattern that splits on the five spaces, and + * grabs the 2, 3, and 4th fields. + */ + private static final String MTAB_LINE_PATTERN = new StringBuilder("^") + .append(FIELD).append(WHITESPACE) + .append(CAPTURED_FIELD).append(WHITESPACE) + .append(CAPTURED_FIELD).append(WHITESPACE) + .append(CAPTURED_FIELD).append(WHITESPACE) + .append(FIELD).append(WHITESPACE) + .append(FIELD).append("$").toString(); + private static final Pattern MTAB_FILE_FORMAT = + Pattern.compile(MTAB_LINE_PATTERN); + + private static final Set VALID_CGROUPS = + CGroupController.getValidCGroups(); + + private MtabFileParser() {} + + /** + * Parses an mtab file, usually stored under /etc/mtab + * Cgroup controllers will appear in the list of options for a path. + * + * Example lines of valid cgroup configs coming from an mtab file:
+ * cgroup /sys/fs/cgroup/memory cgroup rw,relatime,memory 0 0 + * cgroup /sys/fs/cgroup/cpuset cgroup rw,relatime,cpuset 0 0 + * cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0 + */ + @VisibleForTesting + public static CGroupsMountConfig parse(String mtabFile) + throws IOException { + final CGroupsMountConfig mountConfig = new CGroupsMountConfig(); + + BufferedReader in = null; + try { + FileInputStream fis = new FileInputStream(new File(mtabFile)); + in = new BufferedReader(new InputStreamReader(fis, + StandardCharsets.UTF_8)); + + for (String str = in.readLine(); str != null; str = in.readLine()) { + Matcher m = MTAB_FILE_FORMAT.matcher(str); + boolean matched = m.find(); + if (matched) { + String path = m.group(1); + String type = m.group(2); + String optionsStr = m.group(3); + + if (type.equals(CGROUPS_FSTYPE)) { + Set options = + new HashSet<>(Arrays.asList(optionsStr.split(","))); + // Collect the valid controller names + options.retainAll(VALID_CGROUPS); + mountConfig.mapPathToControllers(path, options); + } + } + } + } catch (IOException e) { + if (Shell.LINUX) { + throw new IOException("Error while reading " + mtabFile, e); + } else { + // Ignore the error, if we are running on an OS other than Linux + LOG.warn("Error while reading " + mtabFile, e); + } + } finally { + IOUtils.cleanupWithLogger(LOG, in); + } + + return mountConfig; + } + +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/ResourceHandlerModule.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/ResourceHandlerModule.java index c2f0402b84e..f72412f07a6 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/ResourceHandlerModule.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/ResourceHandlerModule.java @@ -35,15 +35,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; /** * Provides mechanisms to get various resource handlers - cpu, memory, network, @@ -359,45 +353,4 @@ public static ResourceHandlerChain getConfiguredResourceHandlerChain( static void nullifyResourceHandlerChain() throws ResourceHandlerException { resourceHandlerChain = null; } - - /** - * If a cgroup mount directory is specified, it returns cgroup directories - * with valid names. - * The requirement is that each hierarchy has to be named with the comma - * separated names of subsystems supported. - * For example: /sys/fs/cgroup/cpu,cpuacct - * @param cgroupMountPath Root cgroup mount path (/sys/fs/cgroup in the - * example above) - * @return A path to cgroup subsystem set mapping in the same format as - * {@link CGroupsHandlerImpl#parseMtab(String)} - * @throws IOException if the specified directory cannot be listed - */ - public static Map> parseConfiguredCGroupPath( - String cgroupMountPath) throws IOException { - File cgroupDir = new File(cgroupMountPath); - File[] list = cgroupDir.listFiles(); - if (list == null) { - throw new IOException("Empty cgroup mount directory specified: " + - cgroupMountPath); - } - - Map> pathSubsystemMappings = new HashMap<>(); - Set validCGroups = - CGroupsHandler.CGroupController.getValidCGroups(); - for (File candidate: list) { - Set cgroupList = - new HashSet<>(Arrays.asList(candidate.getName().split(","))); - // Collect the valid subsystem names - cgroupList.retainAll(validCGroups); - if (!cgroupList.isEmpty()) { - if (candidate.isDirectory()) { - pathSubsystemMappings.put(candidate.getAbsolutePath(), cgroupList); - } else { - LOG.warn("The following cgroup is not a directory " + - candidate.getAbsolutePath()); - } - } - } - return pathSubsystemMappings; - } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/util/CgroupsLCEResourcesHandler.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/util/CgroupsLCEResourcesHandler.java index 54b6e1c170b..0c8dac582a0 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/util/CgroupsLCEResourcesHandler.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/util/CgroupsLCEResourcesHandler.java @@ -27,16 +27,13 @@ import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Writer; -import java.util.Arrays; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; + +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsControllerPaths; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsHandler.CGroupController; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsMountConfig; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CgroupsFileSystemMountParser; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.MtabFileParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,19 +41,17 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileUtil; -import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.yarn.api.records.ContainerId; import org.apache.hadoop.yarn.api.records.Resource; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsCpuResourceHandlerImpl; -import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsHandler; -import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandlerModule; import org.apache.hadoop.yarn.util.Clock; import org.apache.hadoop.yarn.util.ResourceCalculatorPlugin; import org.apache.hadoop.yarn.util.SystemClock; + /** * Resource handler that lets you setup cgroups * to to handle cpu isolation. Please look at the ResourceHandlerModule @@ -85,7 +80,7 @@ private final String CPU_PERIOD_US = "cfs_period_us"; private final String CPU_QUOTA_US = "cfs_quota_us"; private final int CPU_DEFAULT_WEIGHT = 1024; // set by kernel - private final Map controllerPaths; // Controller -> path + private final CGroupsControllerPaths controllerPaths; private long deleteCgroupTimeout; private long deleteCgroupDelay; @@ -96,7 +91,7 @@ private int nodeVCores; public CgroupsLCEResourcesHandler() { - this.controllerPaths = new HashMap(); + this.controllerPaths = new CGroupsControllerPaths(); clock = SystemClock.getInstance(); } @@ -198,7 +193,8 @@ boolean isCpuWeightEnabled() { */ private String pathForCgroup(String controller, String groupName) { - String controllerPath = controllerPaths.get(controller); + String controllerPath = controllerPaths.getPath( + CGroupController.valueOf(controller.toUpperCase())); return controllerPath + "/" + cgroupPrefix + "/" + groupName; } @@ -389,97 +385,24 @@ public String getResourcesOption(ContainerId containerId) { return sb.toString(); } - /* We are looking for entries of the form: - * none /cgroup/path/mem cgroup rw,memory 0 0 - * - * Use a simple pattern that splits on the five spaces, and - * grabs the 2, 3, and 4th fields. - */ - - private static final Pattern MTAB_FILE_FORMAT = Pattern.compile( - "^[^\\s]+\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s[^\\s]+\\s[^\\s]+$"); - - /* - * Returns a map: path -> mount options - * for mounts with type "cgroup". Cgroup controllers will - * appear in the list of options for a path. - */ - private Map> parseMtab() throws IOException { - Map> ret = new HashMap>(); - BufferedReader in = null; - Set validCgroups = - CGroupsHandler.CGroupController.getValidCGroups(); - - try { - FileInputStream fis = new FileInputStream(new File(getMtabFileName())); - in = new BufferedReader(new InputStreamReader(fis, "UTF-8")); - - for (String str = in.readLine(); str != null; - str = in.readLine()) { - Matcher m = MTAB_FILE_FORMAT.matcher(str); - boolean mat = m.find(); - if (mat) { - String path = m.group(1); - String type = m.group(2); - String options = m.group(3); - - if (type.equals(CGROUPS_FSTYPE)) { - Set cgroupList = - new HashSet<>(Arrays.asList(options.split(","))); - // Collect the valid subsystem names - cgroupList.retainAll(validCgroups); - ret.put(path, cgroupList); - } - } - } - } catch (IOException e) { - throw new IOException("Error while reading " + getMtabFileName(), e); - } finally { - IOUtils.cleanupWithLogger(LOG, in); - } - - return ret; - } - - @VisibleForTesting - String findControllerInMtab(String controller, - Map> entries) { - for (Entry> e : entries.entrySet()) { - if (e.getValue().contains(controller)) { - if (new File(e.getKey()).canRead()) { - return e.getKey(); - } else { - LOG.warn(String.format( - "Skipping inaccessible cgroup mount point %s", e.getKey())); - } - } - } - - return null; - } - private void initializeControllerPaths() throws IOException { - String controllerPath; - Map> parsedMtab = null; - + final CGroupsMountConfig mountConfig; if (this.cgroupMountPath != null && !this.cgroupMount) { - parsedMtab = ResourceHandlerModule. + mountConfig = CgroupsFileSystemMountParser. parseConfiguredCGroupPath(this.cgroupMountPath); + } else { + mountConfig = MtabFileParser.parse(getMtabFileName()); } - if (parsedMtab == null) { - parsedMtab = parseMtab(); - } - - // CPU - - controllerPath = findControllerInMtab(CONTROLLER_CPU, parsedMtab); + final String controllerPath = + CGroupsControllerPaths.findControllerPathInMountConfig( + CONTROLLER_CPU, mountConfig); if (controllerPath != null) { File f = new File(controllerPath + "/" + this.cgroupPrefix); if (FileUtil.canWrite(f)) { - controllerPaths.put(CONTROLLER_CPU, controllerPath); + controllerPaths.storePath(CGroupController.CPU, controllerPath); } else { throw new IOException("Not able to enforce cpu weights; cannot write " + "to cgroup at: " + controllerPath); @@ -496,7 +419,7 @@ String getMtabFileName() { } @VisibleForTesting - Map getControllerPaths() { - return Collections.unmodifiableMap(controllerPaths); + CGroupsControllerPaths getControllerPaths() { + return controllerPaths; } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsControllerPaths.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsControllerPaths.java new file mode 100644 index 00000000000..1110260d6fa --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsControllerPaths.java @@ -0,0 +1,74 @@ +/* + * 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.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsHandler.CGroupController; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.util.Collections; + +import static org.junit.Assert.assertTrue; + +public class TestCGroupsControllerPaths { + private String tmpPath; + + @Before + public void setup() { + // Prepare test directory + tmpPath = System.getProperty("test.build.data") + "/cgroups"; + File tmpDir = new File(tmpPath); + FileUtils.deleteQuietly(tmpDir); + assertTrue(tmpDir.mkdirs()); + } + + @Test + public void testSelectCgroup() { + File cpu = new File(tmpPath, "cpu"); + File cpuNotExist = new File(tmpPath, "cpuNotExist"); + File memory = new File(tmpPath, "memory"); + try { + Assert.assertTrue("temp dir for cpu should be created", cpu.mkdirs()); + Assert.assertTrue("temp dir for memory should be created", + memory.mkdirs()); + Assert.assertFalse("temp dir for cpu should not be created", + cpuNotExist.exists()); + + CGroupsMountConfig config = new CGroupsMountConfig(); + config.mapPathToControllers(memory.getAbsolutePath(), + Collections.singleton("memory")); + config.mapPathToControllers(cpuNotExist.getAbsolutePath(), + Collections.singleton("cpu")); + config.mapPathToControllers(cpu.getAbsolutePath(), + Collections.singleton("cpu")); + + CGroupsControllerPaths testSubject = CGroupsControllerPaths. + initializeFromMountConfig(config); + String selectedCPU = testSubject.getPath(CGroupController.CPU); + Assert.assertEquals("Wrong CPU mount point selected", + cpu.getAbsolutePath(), selectedCPU); + } finally { + FileUtils.deleteQuietly(cpu); + FileUtils.deleteQuietly(memory); + } + } + +} \ No newline at end of file diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsHandlerImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsHandlerImpl.java index b1e8989213b..578fddb9bbe 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsHandlerImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsHandlerImpl.java @@ -41,10 +41,7 @@ import java.io.IOException; import java.nio.file.Files; import java.security.Permission; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; +import java.util.Arrays; import java.util.UUID; import static org.junit.Assert.assertTrue; @@ -169,7 +166,8 @@ public static File createPremountedCgroups(File parentDir, boolean cpuAcct) + " cgroup rw,relatime,blkio 0 0\n"; assertTrue("Directory should be created", blkioCgroup.mkdirs()); - File mockMtab = new File(parentDir, UUID.randomUUID().toString()); + File mockMtab = new File(parentDir, "mockmtab_" + + UUID.randomUUID().toString()); if (!mockMtab.exists()) { if (!mockMtab.createNewFile()) { String message = "Could not create file " + mockMtab.getAbsolutePath(); @@ -353,37 +351,6 @@ public void testCGroupOperations() throws IOException { } } - /** - * 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, false); - - // Run mtabs parsing - Map> newMtab = - CGroupsHandlerImpl.parseMtab(mockMtabFile.getAbsolutePath()); - Map controllerPaths = - CGroupsHandlerImpl.initializeControllerPathsFromMtab( - newMtab); - - // Verify - Assert.assertEquals(2, controllerPaths.size()); - assertTrue(controllerPaths - .containsKey(CGroupsHandler.CGroupController.CPU)); - assertTrue(controllerPaths - .containsKey(CGroupsHandler.CGroupController.BLKIO)); - String cpuDir = controllerPaths.get(CGroupsHandler.CGroupController.CPU); - String blkioDir = - controllerPaths.get(CGroupsHandler.CGroupController.BLKIO); - Assert.assertEquals(parentDir.getAbsolutePath() + "/cpu", cpuDir); - Assert.assertEquals(parentDir.getAbsolutePath() + "/blkio", blkioDir); - } - /** * Tests whether mtab parsing works as expected with the specified hierarchy. * @param myHierarchy path to local cgroup hierarchy @@ -396,11 +363,17 @@ private void testPreMountedControllerInitialization(String myHierarchy) File mtab = createPremountedCgroups(parentDir, false); File mountPoint = new File(parentDir, "cpu"); + LOG.info("Listing of cgroups dir: " + Arrays.toString( + parentDir.listFiles())); + // Initialize YARN classes Configuration confNoMount = createNoMountConfiguration(myHierarchy); CGroupsHandlerImpl cGroupsHandler = new CGroupsHandlerImpl(confNoMount, privilegedOperationExecutorMock, mtab.getAbsolutePath()); + LOG.info("Recognized cgroups controller paths: " + + cGroupsHandler.getControllerPaths()); + File cpuCgroupMountDir = new File( cGroupsHandler.getPathForCGroup(CGroupsHandler.CGroupController.CPU, "")); @@ -487,35 +460,6 @@ private void testPreMountedControllerInitialization(String myHierarchy) } } - @Test - public void testSelectCgroup() throws Exception { - File cpu = new File(tmpPath, "cpu"); - File cpuNoExist = new File(tmpPath, "cpuNoExist"); - File memory = new File(tmpPath, "memory"); - try { - CGroupsHandlerImpl handler = new CGroupsHandlerImpl( - createNoMountConfiguration(tmpPath), - privilegedOperationExecutorMock); - Map> cgroups = new LinkedHashMap<>(); - - Assert.assertTrue("temp dir should be created", cpu.mkdirs()); - Assert.assertTrue("temp dir should be created", memory.mkdirs()); - Assert.assertFalse("temp dir should not be created", cpuNoExist.exists()); - - cgroups.put( - memory.getAbsolutePath(), Collections.singleton("memory")); - cgroups.put( - cpuNoExist.getAbsolutePath(), Collections.singleton("cpu")); - cgroups.put(cpu.getAbsolutePath(), Collections.singleton("cpu")); - String selectedCPU = handler.findControllerInMtab("cpu", cgroups); - Assert.assertEquals("Wrong CPU mount point selected", - cpu.getAbsolutePath(), selectedCPU); - } finally { - FileUtils.deleteQuietly(cpu); - FileUtils.deleteQuietly(memory); - } - } - /** * Tests whether mtab parsing works as expected with an empty hierarchy set. * @throws Exception the test will fail diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestMtabFileParser.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestMtabFileParser.java new file mode 100644 index 00000000000..328745496e2 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestMtabFileParser.java @@ -0,0 +1,81 @@ +/* + * 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.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Arrays; + +import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.TestCGroupsHandlerImpl.createPremountedCgroups; +import static org.junit.Assert.assertTrue; + +public class TestMtabFileParser { + private static final Logger LOG = + LoggerFactory.getLogger(TestMtabFileParser.class); + + private String tmpPath; + + @Before + public void setup() { + // Prepare test directory + tmpPath = System.getProperty("test.build.data") + "/cgroups"; + File tmpDir = new File(tmpPath); + FileUtils.deleteQuietly(tmpDir); + assertTrue(tmpDir.mkdirs()); + } + + /** + * 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, false); + + // Run mtabs parsing + CGroupsMountConfig mountConfig = + MtabFileParser.parse(mockMtabFile.getAbsolutePath()); + CGroupsControllerPaths controllerPaths = + CGroupsControllerPaths.initializeFromMountConfig(mountConfig); + + LOG.info("Listing of cgroups dir: " + + Arrays.toString(parentDir.listFiles())); + LOG.info("Recognized cgroups controller paths: " + controllerPaths); + // Verify + Assert.assertEquals("Number of cgroups controller paths is not expected", + 2, controllerPaths.getNumberOfPaths()); + assertTrue("There is no path for CPU in controllerPaths", controllerPaths + .hasPath(CGroupsHandler.CGroupController.CPU)); + assertTrue("There is no path for BLKIO in controllerPaths", controllerPaths + .hasPath(CGroupsHandler.CGroupController.BLKIO)); + String cpuDir = controllerPaths.getPath( + CGroupsHandler.CGroupController.CPU); + String blkioDir = + controllerPaths.getPath(CGroupsHandler.CGroupController.BLKIO); + Assert.assertEquals(parentDir.getAbsolutePath() + "/cpu", cpuDir); + Assert.assertEquals(parentDir.getAbsolutePath() + "/blkio", blkioDir); + } +} \ No newline at end of file diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/util/TestCgroupsLCEResourcesHandler.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/util/TestCgroupsLCEResourcesHandler.java index 7d8704f8b42..240900d635b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/util/TestCgroupsLCEResourcesHandler.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/util/TestCgroupsLCEResourcesHandler.java @@ -20,25 +20,23 @@ import org.apache.commons.io.FileUtils; import org.apache.hadoop.yarn.api.records.ContainerId; import org.apache.hadoop.yarn.api.records.Resource; +import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsHandler.CGroupController; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.TestCGroupsHandlerImpl; - import org.apache.hadoop.yarn.util.ControlledClock; import org.apache.hadoop.yarn.util.ResourceCalculatorPlugin; -import org.junit.Assert; -import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.junit.Test; import org.junit.After; +import org.junit.Assert; import org.junit.Before; +import org.junit.Test; import org.mockito.Mockito; -import java.io.*; -import java.util.Collections; -import java.util.LinkedHashMap; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.List; -import java.util.Map; import java.util.Scanner; -import java.util.Set; import java.util.concurrent.CountDownLatch; import static org.mockito.Mockito.when; @@ -299,6 +297,7 @@ public void testContainerLimits() throws IOException { ContainerId id = ContainerId.fromString("container_1_1_1_1"); handler.preExecute(id, Resource.newInstance(1024, 1)); Assert.assertNotNull(handler.getControllerPaths()); + Assert.assertNotNull(handler.getControllerPaths().isEmpty()); // check values // default case - files shouldn't exist, strict mode off by default File containerCpuDir = new File(cpuCgroupMountDir, id.toString()); @@ -364,33 +363,6 @@ public void testContainerLimits() throws IOException { FileUtils.deleteQuietly(cgroupDir); } - @Test - public void testSelectCgroup() { - File cpu = new File(cgroupDir, "cpu"); - File cpuNoExist = new File(cgroupDir, "cpuNoExist"); - File memory = new File(cgroupDir, "memory"); - try { - CgroupsLCEResourcesHandler handler = new CgroupsLCEResourcesHandler(); - Map> cgroups = new LinkedHashMap<>(); - - Assert.assertTrue("temp dir should be created", cpu.mkdirs()); - Assert.assertTrue("temp dir should be created", memory.mkdirs()); - Assert.assertFalse("temp dir should not be created", cpuNoExist.exists()); - - cgroups.put( - memory.getAbsolutePath(), Collections.singleton("memory")); - cgroups.put( - cpuNoExist.getAbsolutePath(), Collections.singleton("cpu")); - cgroups.put(cpu.getAbsolutePath(), Collections.singleton("cpu")); - String selectedCPU = handler.findControllerInMtab("cpu", cgroups); - Assert.assertEquals("Wrong CPU mount point selected", - cpu.getAbsolutePath(), selectedCPU); - } finally { - FileUtils.deleteQuietly(cpu); - FileUtils.deleteQuietly(memory); - } - } - @Test public void testManualCgroupSetting() throws IOException { CgroupsLCEResourcesHandler handler = new CgroupsLCEResourcesHandler(); @@ -412,7 +384,7 @@ public void testManualCgroupSetting() throws IOException { handler.init(null, plugin); Assert.assertEquals("CPU CGRoup path was not set", cpu.getParent(), - handler.getControllerPaths().get("cpu")); + handler.getControllerPaths().getPath(CGroupController.CPU)); } finally { FileUtils.deleteQuietly(cpu);