YARN-4253. Standardize on using PrivilegedOperationExecutor for all invocations of container-executor in LinuxContainerExecutor. Contributed by Sidharta Seethana.

This commit is contained in:
Varun Vasudev 2015-10-14 14:56:48 +05:30
parent 2a98724342
commit 8d59293089
2 changed files with 144 additions and 134 deletions

View File

@ -931,6 +931,9 @@ Release 2.8.0 - UNRELEASED
YARN-4017. container-executor overuses PATH_MAX. (Sidharta Seethana via vvasudev) YARN-4017. container-executor overuses PATH_MAX. (Sidharta Seethana via vvasudev)
YARN-4253. Standardize on using PrivilegedOperationExecutor for all
invocations of container-executor in LinuxContainerExecutor. (Sidharta Seethana via vvasudev)
Release 2.7.2 - UNRELEASED Release 2.7.2 - UNRELEASED
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -26,8 +26,6 @@
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.util.ReflectionUtils; import org.apache.hadoop.util.ReflectionUtils;
import org.apache.hadoop.util.Shell.ExitCodeException;
import org.apache.hadoop.util.Shell.ShellCommandExecutor;
import org.apache.hadoop.util.StringUtils; import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.yarn.api.ApplicationConstants; import org.apache.hadoop.yarn.api.ApplicationConstants;
import org.apache.hadoop.yarn.api.records.ContainerId; import org.apache.hadoop.yarn.api.records.ContainerId;
@ -78,7 +76,6 @@ public class LinuxContainerExecutor extends ContainerExecutor {
private String nonsecureLocalUser; private String nonsecureLocalUser;
private Pattern nonsecureLocalUserPattern; private Pattern nonsecureLocalUserPattern;
private String containerExecutorExe;
private LCEResourcesHandler resourcesHandler; private LCEResourcesHandler resourcesHandler;
private boolean containerSchedPriorityIsSet = false; private boolean containerSchedPriorityIsSet = false;
private int containerSchedPriorityAdjustment = 0; private int containerSchedPriorityAdjustment = 0;
@ -97,28 +94,28 @@ public LinuxContainerExecutor(LinuxContainerRuntime linuxContainerRuntime) {
@Override @Override
public void setConf(Configuration conf) { public void setConf(Configuration conf) {
super.setConf(conf); super.setConf(conf);
containerExecutorExe = getContainerExecutorExecutablePath(conf);
resourcesHandler = ReflectionUtils.newInstance( resourcesHandler = ReflectionUtils.newInstance(
conf.getClass(YarnConfiguration.NM_LINUX_CONTAINER_RESOURCES_HANDLER, conf.getClass(YarnConfiguration.NM_LINUX_CONTAINER_RESOURCES_HANDLER,
DefaultLCEResourcesHandler.class, LCEResourcesHandler.class), conf); DefaultLCEResourcesHandler.class, LCEResourcesHandler.class), conf);
resourcesHandler.setConf(conf); resourcesHandler.setConf(conf);
if (conf.get(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY) != null) { if (conf.get(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY)
containerSchedPriorityIsSet = true; != null) {
containerSchedPriorityAdjustment = conf containerSchedPriorityIsSet = true;
.getInt(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY, containerSchedPriorityAdjustment = conf
YarnConfiguration.DEFAULT_NM_CONTAINER_EXECUTOR_SCHED_PRIORITY); .getInt(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY,
YarnConfiguration.DEFAULT_NM_CONTAINER_EXECUTOR_SCHED_PRIORITY);
} }
nonsecureLocalUser = conf.get( nonsecureLocalUser = conf.get(
YarnConfiguration.NM_NONSECURE_MODE_LOCAL_USER_KEY, YarnConfiguration.NM_NONSECURE_MODE_LOCAL_USER_KEY,
YarnConfiguration.DEFAULT_NM_NONSECURE_MODE_LOCAL_USER); YarnConfiguration.DEFAULT_NM_NONSECURE_MODE_LOCAL_USER);
nonsecureLocalUserPattern = Pattern.compile( nonsecureLocalUserPattern = Pattern.compile(
conf.get(YarnConfiguration.NM_NONSECURE_MODE_USER_PATTERN_KEY, conf.get(YarnConfiguration.NM_NONSECURE_MODE_USER_PATTERN_KEY,
YarnConfiguration.DEFAULT_NM_NONSECURE_MODE_USER_PATTERN)); YarnConfiguration.DEFAULT_NM_NONSECURE_MODE_USER_PATTERN));
containerLimitUsers = conf.getBoolean( containerLimitUsers = conf.getBoolean(
YarnConfiguration.NM_NONSECURE_MODE_LIMIT_USERS, YarnConfiguration.NM_NONSECURE_MODE_LIMIT_USERS,
YarnConfiguration.DEFAULT_NM_NONSECURE_MODE_LIMIT_USERS); YarnConfiguration.DEFAULT_NM_NONSECURE_MODE_LIMIT_USERS);
if (!containerLimitUsers) { if (!containerLimitUsers) {
LOG.warn(YarnConfiguration.NM_NONSECURE_MODE_LIMIT_USERS + LOG.warn(YarnConfiguration.NM_NONSECURE_MODE_LIMIT_USERS +
": impersonation without authentication enabled"); ": impersonation without authentication enabled");
@ -128,14 +125,14 @@ public void setConf(Configuration conf) {
void verifyUsernamePattern(String user) { void verifyUsernamePattern(String user) {
if (!UserGroupInformation.isSecurityEnabled() && if (!UserGroupInformation.isSecurityEnabled() &&
!nonsecureLocalUserPattern.matcher(user).matches()) { !nonsecureLocalUserPattern.matcher(user).matches()) {
throw new IllegalArgumentException("Invalid user name '" + user + "'," + throw new IllegalArgumentException("Invalid user name '" + user + "'," +
" it must match '" + nonsecureLocalUserPattern.pattern() + "'"); " it must match '" + nonsecureLocalUserPattern.pattern() + "'");
} }
} }
String getRunAsUser(String user) { String getRunAsUser(String user) {
if (UserGroupInformation.isSecurityEnabled() || if (UserGroupInformation.isSecurityEnabled() ||
!containerLimitUsers) { !containerLimitUsers) {
return user; return user;
} else { } else {
return nonsecureLocalUser; return nonsecureLocalUser;
@ -147,10 +144,11 @@ protected String getContainerExecutorExecutablePath(Configuration conf) {
System.getenv(ApplicationConstants.Environment.HADOOP_YARN_HOME.key()); System.getenv(ApplicationConstants.Environment.HADOOP_YARN_HOME.key());
File hadoopBin = new File(yarnHomeEnvVar, "bin"); File hadoopBin = new File(yarnHomeEnvVar, "bin");
String defaultPath = String defaultPath =
new File(hadoopBin, "container-executor").getAbsolutePath(); new File(hadoopBin, "container-executor").getAbsolutePath();
return null == conf return null == conf
? defaultPath ? defaultPath
: conf.get(YarnConfiguration.NM_LINUX_CONTAINER_EXECUTOR_PATH, defaultPath); : conf.get(YarnConfiguration.NM_LINUX_CONTAINER_EXECUTOR_PATH,
defaultPath);
} }
protected void addSchedPriorityCommand(List<String> command) { protected void addSchedPriorityCommand(List<String> command) {
@ -160,31 +158,29 @@ protected void addSchedPriorityCommand(List<String> command) {
} }
} }
@Override @Override
public void init() throws IOException { public void init() throws IOException {
// Send command to executor which will just start up, Configuration conf = super.getConf();
// Send command to executor which will just start up,
// verify configuration/permissions and exit // verify configuration/permissions and exit
List<String> command = new ArrayList<String>(
Arrays.asList(containerExecutorExe,
"--checksetup"));
String[] commandArray = command.toArray(new String[command.size()]);
ShellCommandExecutor shExec = new ShellCommandExecutor(commandArray);
if (LOG.isDebugEnabled()) {
LOG.debug("checkLinuxExecutorSetup: " + Arrays.toString(commandArray));
}
try { try {
shExec.execute(); PrivilegedOperation checkSetupOp = new PrivilegedOperation(
} catch (ExitCodeException e) { PrivilegedOperation.OperationType.CHECK_SETUP, (String) null);
int exitCode = shExec.getExitCode(); PrivilegedOperationExecutor privilegedOperationExecutor =
PrivilegedOperationExecutor.getInstance(conf);
privilegedOperationExecutor.executePrivilegedOperation(checkSetupOp,
false);
} catch (PrivilegedOperationException e) {
int exitCode = e.getExitCode();
LOG.warn("Exit code from container executor initialization is : " LOG.warn("Exit code from container executor initialization is : "
+ exitCode, e); + exitCode, e);
logOutput(shExec.getOutput());
throw new IOException("Linux container executor not configured properly" throw new IOException("Linux container executor not configured properly"
+ " (error=" + exitCode + ")", e); + " (error=" + exitCode + ")", e);
} }
Configuration conf = super.getConf();
try { try {
resourceHandlerChain = ResourceHandlerModule resourceHandlerChain = ResourceHandlerModule
.getConfiguredResourceHandlerChain(conf); .getConfiguredResourceHandlerChain(conf);
@ -193,7 +189,8 @@ public void init() throws IOException {
} }
} catch (ResourceHandlerException e) { } catch (ResourceHandlerException e) {
LOG.error("Failed to bootstrap configured resource subsystems! ", e); LOG.error("Failed to bootstrap configured resource subsystems! ", e);
throw new IOException("Failed to bootstrap configured resource subsystems!"); throw new IOException(
"Failed to bootstrap configured resource subsystems!");
} }
try { try {
@ -204,7 +201,7 @@ public void init() throws IOException {
this.linuxContainerRuntime = runtime; this.linuxContainerRuntime = runtime;
} }
} catch (ContainerExecutionException e) { } catch (ContainerExecutionException e) {
throw new IOException("Failed to initialize linux container runtime(s)!"); throw new IOException("Failed to initialize linux container runtime(s)!");
} }
resourcesHandler.init(this); resourcesHandler.init(this);
@ -221,50 +218,59 @@ public void startLocalizer(LocalizerStartContext ctx)
LocalDirsHandlerService dirsHandler = ctx.getDirsHandler(); LocalDirsHandlerService dirsHandler = ctx.getDirsHandler();
List<String> localDirs = dirsHandler.getLocalDirs(); List<String> localDirs = dirsHandler.getLocalDirs();
List<String> logDirs = dirsHandler.getLogDirs(); List<String> logDirs = dirsHandler.getLogDirs();
verifyUsernamePattern(user); verifyUsernamePattern(user);
String runAsUser = getRunAsUser(user); String runAsUser = getRunAsUser(user);
List<String> command = new ArrayList<String>(); PrivilegedOperation initializeContainerOp = new PrivilegedOperation(
addSchedPriorityCommand(command); PrivilegedOperation.OperationType.INITIALIZE_CONTAINER, (String) null);
command.addAll(Arrays.asList(containerExecutorExe, List<String> prefixCommands = new ArrayList<>();
runAsUser,
user, addSchedPriorityCommand(prefixCommands);
Integer.toString(PrivilegedOperation.RunAsUserCommand.INITIALIZE_CONTAINER.getValue()), initializeContainerOp.appendArgs(
appId, runAsUser,
nmPrivateContainerTokensPath.toUri().getPath().toString(), user,
StringUtils.join(PrivilegedOperation.LINUX_FILE_PATH_SEPARATOR, Integer.toString(
localDirs), PrivilegedOperation.RunAsUserCommand.INITIALIZE_CONTAINER
StringUtils.join(PrivilegedOperation.LINUX_FILE_PATH_SEPARATOR, .getValue()),
logDirs))); appId,
nmPrivateContainerTokensPath.toUri().getPath().toString(),
StringUtils.join(PrivilegedOperation.LINUX_FILE_PATH_SEPARATOR,
localDirs),
StringUtils.join(PrivilegedOperation.LINUX_FILE_PATH_SEPARATOR,
logDirs));
File jvm = // use same jvm as parent File jvm = // use same jvm as parent
new File(new File(System.getProperty("java.home"), "bin"), "java"); new File(new File(System.getProperty("java.home"), "bin"), "java");
command.add(jvm.toString()); initializeContainerOp.appendArgs(jvm.toString());
command.add("-classpath"); initializeContainerOp.appendArgs("-classpath");
command.add(System.getProperty("java.class.path")); initializeContainerOp.appendArgs(System.getProperty("java.class.path"));
String javaLibPath = System.getProperty("java.library.path"); String javaLibPath = System.getProperty("java.library.path");
if (javaLibPath != null) { if (javaLibPath != null) {
command.add("-Djava.library.path=" + javaLibPath); initializeContainerOp.appendArgs("-Djava.library.path=" + javaLibPath);
}
command.addAll(ContainerLocalizer.getJavaOpts(getConf()));
buildMainArgs(command, user, appId, locId, nmAddr, localDirs);
String[] commandArray = command.toArray(new String[command.size()]);
ShellCommandExecutor shExec = new ShellCommandExecutor(commandArray);
if (LOG.isDebugEnabled()) {
LOG.debug("initApplication: " + Arrays.toString(commandArray));
} }
initializeContainerOp.appendArgs(ContainerLocalizer.getJavaOpts(getConf()));
List<String> localizerArgs = new ArrayList<>();
buildMainArgs(localizerArgs, user, appId, locId, nmAddr, localDirs);
initializeContainerOp.appendArgs(localizerArgs);
try { try {
shExec.execute(); Configuration conf = super.getConf();
if (LOG.isDebugEnabled()) { PrivilegedOperationExecutor privilegedOperationExecutor =
logOutput(shExec.getOutput()); PrivilegedOperationExecutor.getInstance(conf);
}
} catch (ExitCodeException e) { privilegedOperationExecutor.executePrivilegedOperation(prefixCommands,
int exitCode = shExec.getExitCode(); initializeContainerOp, null, null, false);
} catch (PrivilegedOperationException e) {
int exitCode = e.getExitCode();
LOG.warn("Exit code from container " + locId + " startLocalizer is : " LOG.warn("Exit code from container " + locId + " startLocalizer is : "
+ exitCode, e); + exitCode, e);
logOutput(shExec.getOutput());
throw new IOException("Application " + appId + " initialization failed" + throw new IOException("Application " + appId + " initialization failed" +
" (exitCode=" + exitCode + ") with output: " + shExec.getOutput(), e); " (exitCode=" + exitCode + ") with output: " + e.getOutput(), e);
} }
} }
@ -292,7 +298,7 @@ public int launchContainer(ContainerStartContext ctx) throws IOException {
ContainerId containerId = container.getContainerId(); ContainerId containerId = container.getContainerId();
String containerIdStr = ConverterUtils.toString(containerId); String containerIdStr = ConverterUtils.toString(containerId);
resourcesHandler.preExecute(containerId, resourcesHandler.preExecute(containerId,
container.getResource()); container.getResource());
String resourcesOptions = resourcesHandler.getResourcesOption( String resourcesOptions = resourcesHandler.getResourcesOption(
@ -307,21 +313,21 @@ public int launchContainer(ContainerStartContext ctx) throws IOException {
if (ops != null) { if (ops != null) {
List<PrivilegedOperation> resourceOps = new ArrayList<>(); List<PrivilegedOperation> resourceOps = new ArrayList<>();
resourceOps.add(new PrivilegedOperation resourceOps.add(new PrivilegedOperation(
(PrivilegedOperation.OperationType.ADD_PID_TO_CGROUP, PrivilegedOperation.OperationType.ADD_PID_TO_CGROUP,
resourcesOptions)); resourcesOptions));
for (PrivilegedOperation op : ops) { for (PrivilegedOperation op : ops) {
switch (op.getOperationType()) { switch (op.getOperationType()) {
case ADD_PID_TO_CGROUP: case ADD_PID_TO_CGROUP:
resourceOps.add(op); resourceOps.add(op);
break; break;
case TC_MODIFY_STATE: case TC_MODIFY_STATE:
tcCommandFile = op.getArguments().get(0); tcCommandFile = op.getArguments().get(0);
break; break;
default: default:
LOG.warn("PrivilegedOperation type unsupported in launch: " LOG.warn("PrivilegedOperation type unsupported in launch: "
+ op.getOperationType()); + op.getOperationType());
} }
} }
@ -333,7 +339,8 @@ public int launchContainer(ContainerStartContext ctx) throws IOException {
resourcesOptions = operation.getArguments().get(0); resourcesOptions = operation.getArguments().get(0);
} catch (PrivilegedOperationException e) { } catch (PrivilegedOperationException e) {
LOG.error("Failed to squash cgroup operations!", e); LOG.error("Failed to squash cgroup operations!", e);
throw new ResourceHandlerException("Failed to squash cgroup operations!"); throw new ResourceHandlerException(
"Failed to squash cgroup operations!");
} }
} }
} }
@ -346,7 +353,7 @@ public int launchContainer(ContainerStartContext ctx) throws IOException {
try { try {
Path pidFilePath = getPidFilePath(containerId); Path pidFilePath = getPidFilePath(containerId);
if (pidFilePath != null) { if (pidFilePath != null) {
List<String> prefixCommands= new ArrayList<>(); List<String> prefixCommands = new ArrayList<>();
ContainerRuntimeContext.Builder builder = new ContainerRuntimeContext ContainerRuntimeContext.Builder builder = new ContainerRuntimeContext
.Builder(container); .Builder(container);
@ -376,7 +383,8 @@ public int launchContainer(ContainerStartContext ctx) throws IOException {
linuxContainerRuntime.launchContainer(builder.build()); linuxContainerRuntime.launchContainer(builder.build());
} else { } else {
LOG.info("Container was marked as inactive. Returning terminated error"); LOG.info(
"Container was marked as inactive. Returning terminated error");
return ExitCode.TERMINATED.getExitCode(); return ExitCode.TERMINATED.getExitCode();
} }
} catch (ContainerExecutionException e) { } catch (ContainerExecutionException e) {
@ -388,7 +396,7 @@ public int launchContainer(ContainerStartContext ctx) throws IOException {
if (exitCode != ExitCode.FORCE_KILLED.getExitCode() if (exitCode != ExitCode.FORCE_KILLED.getExitCode()
&& exitCode != ExitCode.TERMINATED.getExitCode()) { && exitCode != ExitCode.TERMINATED.getExitCode()) {
LOG.warn("Exception from container-launch with container ID: " LOG.warn("Exception from container-launch with container ID: "
+ containerId + " and exit code: " + exitCode , e); + containerId + " and exit code: " + exitCode, e);
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("Exception from container-launch.\n"); builder.append("Exception from container-launch.\n");
@ -481,7 +489,8 @@ public boolean signalContainer(ContainerSignalContext ctx)
linuxContainerRuntime.signalContainer(runtimeContext); linuxContainerRuntime.signalContainer(runtimeContext);
} catch (ContainerExecutionException e) { } catch (ContainerExecutionException e) {
int retCode = e.getExitCode(); int retCode = e.getExitCode();
if (retCode == PrivilegedOperation.ResultCode.INVALID_CONTAINER_PID.getValue()) { if (retCode == PrivilegedOperation.ResultCode.INVALID_CONTAINER_PID
.getValue()) {
return false; return false;
} }
LOG.warn("Error in signalling container " + pid + " with " + signal LOG.warn("Error in signalling container " + pid + " with " + signal
@ -501,17 +510,20 @@ public void deleteAsUser(DeletionAsUserContext ctx) {
List<Path> baseDirs = ctx.getBasedirs(); List<Path> baseDirs = ctx.getBasedirs();
verifyUsernamePattern(user); verifyUsernamePattern(user);
String runAsUser = getRunAsUser(user);
String runAsUser = getRunAsUser(user);
String dirString = dir == null ? "" : dir.toUri().getPath(); String dirString = dir == null ? "" : dir.toUri().getPath();
List<String> command = new ArrayList<String>( PrivilegedOperation deleteAsUserOp = new PrivilegedOperation(
Arrays.asList(containerExecutorExe, PrivilegedOperation.OperationType.DELETE_AS_USER, (String) null);
runAsUser,
user, deleteAsUserOp.appendArgs(
Integer.toString(PrivilegedOperation. runAsUser,
RunAsUserCommand.DELETE_AS_USER.getValue()), user,
dirString)); Integer.toString(PrivilegedOperation.
RunAsUserCommand.DELETE_AS_USER.getValue()),
dirString);
List<String> pathsToDelete = new ArrayList<String>(); List<String> pathsToDelete = new ArrayList<String>();
if (baseDirs == null || baseDirs.size() == 0) { if (baseDirs == null || baseDirs.size() == 0) {
LOG.info("Deleting absolute path : " + dir); LOG.info("Deleting absolute path : " + dir);
@ -521,28 +533,24 @@ public void deleteAsUser(DeletionAsUserContext ctx) {
Path del = dir == null ? baseDir : new Path(baseDir, dir); Path del = dir == null ? baseDir : new Path(baseDir, dir);
LOG.info("Deleting path : " + del); LOG.info("Deleting path : " + del);
pathsToDelete.add(del.toString()); pathsToDelete.add(del.toString());
command.add(baseDir.toUri().getPath()); deleteAsUserOp.appendArgs(baseDir.toUri().getPath());
} }
} }
String[] commandArray = command.toArray(new String[command.size()]);
ShellCommandExecutor shExec = new ShellCommandExecutor(commandArray);
if (LOG.isDebugEnabled()) {
LOG.debug("deleteAsUser: " + Arrays.toString(commandArray));
}
try { try {
shExec.execute(); Configuration conf = super.getConf();
if (LOG.isDebugEnabled()) { PrivilegedOperationExecutor privilegedOperationExecutor =
logOutput(shExec.getOutput()); PrivilegedOperationExecutor.getInstance(conf);
}
} catch (IOException e) { privilegedOperationExecutor.executePrivilegedOperation(deleteAsUserOp,
int exitCode = shExec.getExitCode(); false);
} catch (PrivilegedOperationException e) {
int exitCode = e.getExitCode();
LOG.error("DeleteAsUser for " + StringUtils.join(" ", pathsToDelete) LOG.error("DeleteAsUser for " + StringUtils.join(" ", pathsToDelete)
+ " returned with exit code: " + exitCode, e); + " returned with exit code: " + exitCode, e);
LOG.error("Output from LinuxContainerExecutor's deleteAsUser follows:");
logOutput(shExec.getOutput());
} }
} }
@Override @Override
public boolean isContainerAlive(ContainerLivenessContext ctx) public boolean isContainerAlive(ContainerLivenessContext ctx)
throws IOException { throws IOException {
@ -560,26 +568,25 @@ public boolean isContainerAlive(ContainerLivenessContext ctx)
} }
public void mountCgroups(List<String> cgroupKVs, String hierarchy) public void mountCgroups(List<String> cgroupKVs, String hierarchy)
throws IOException { throws IOException {
List<String> command = new ArrayList<String>(
Arrays.asList(containerExecutorExe, "--mount-cgroups", hierarchy));
command.addAll(cgroupKVs);
String[] commandArray = command.toArray(new String[command.size()]);
ShellCommandExecutor shExec = new ShellCommandExecutor(commandArray);
if (LOG.isDebugEnabled()) {
LOG.debug("mountCgroups: " + Arrays.toString(commandArray));
}
try { try {
shExec.execute(); PrivilegedOperation mountCGroupsOp = new PrivilegedOperation(
} catch (IOException e) { PrivilegedOperation.OperationType.MOUNT_CGROUPS, hierarchy);
int ret_code = shExec.getExitCode(); Configuration conf = super.getConf();
LOG.warn("Exception in LinuxContainerExecutor mountCgroups ", e);
logOutput(shExec.getOutput()); mountCGroupsOp.appendArgs(cgroupKVs);
throw new IOException("Problem mounting cgroups " + cgroupKVs + PrivilegedOperationExecutor privilegedOperationExecutor =
"; exit code = " + ret_code + " and output: " + shExec.getOutput(), e); PrivilegedOperationExecutor.getInstance(conf);
privilegedOperationExecutor.executePrivilegedOperation(mountCGroupsOp,
false);
} catch (PrivilegedOperationException e) {
int exitCode = e.getExitCode();
LOG.warn("Exception in LinuxContainerExecutor mountCgroups ", e);
throw new IOException("Problem mounting cgroups " + cgroupKVs +
"; exit code = " + exitCode + " and output: " + e.getOutput(),
e);
} }
} }
} }