From 5f11288e41fca2e414dcbea130c7702e29d4d610 Mon Sep 17 00:00:00 2001 From: Jason Lowe Date: Tue, 22 May 2018 09:27:08 -0500 Subject: [PATCH] YARN-8206. Sending a kill does not immediately kill docker containers. Contributed by Eric Badger --- .../runtime/DockerLinuxContainerRuntime.java | 93 ++++-- .../runtime/TestDockerContainerRuntime.java | 305 ++++++++---------- 2 files changed, 200 insertions(+), 198 deletions(-) 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/runtime/DockerLinuxContainerRuntime.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/runtime/DockerLinuxContainerRuntime.java index 40cb0314300..787e8928aa6 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/runtime/DockerLinuxContainerRuntime.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/runtime/DockerLinuxContainerRuntime.java @@ -617,19 +617,8 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime { */ private boolean allowPrivilegedContainerExecution(Container container) throws ContainerExecutionException { - Map environment = container.getLaunchContext() - .getEnvironment(); - String runPrivilegedContainerEnvVar = environment - .get(ENV_DOCKER_CONTAINER_RUN_PRIVILEGED_CONTAINER); - if (runPrivilegedContainerEnvVar == null) { - return false; - } - - if (!runPrivilegedContainerEnvVar.equalsIgnoreCase("true")) { - LOG.warn("NOT running a privileged container. Value of " + - ENV_DOCKER_CONTAINER_RUN_PRIVILEGED_CONTAINER - + "is invalid: " + runPrivilegedContainerEnvVar); + if(!isContainerRequestedAsPrivileged(container)) { return false; } @@ -669,6 +658,20 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime { return true; } + /** + * This function only returns whether a privileged container was requested, + * not whether the container was or will be launched as privileged. + * @param container + * @return + */ + private boolean isContainerRequestedAsPrivileged( + Container container) { + String runPrivilegedContainerEnvVar = container.getLaunchContext() + .getEnvironment().get(ENV_DOCKER_CONTAINER_RUN_PRIVILEGED_CONTAINER); + return Boolean.parseBoolean(runPrivilegedContainerEnvVar); + } + + @VisibleForTesting private String mountReadOnlyPath(String mount, Map> localizedResources) throws ContainerExecutionException { @@ -963,19 +966,16 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime { public void signalContainer(ContainerRuntimeContext ctx) throws ContainerExecutionException { ContainerExecutor.Signal signal = ctx.getExecutionAttribute(SIGNAL); - String containerId = ctx.getContainer().getContainerId().toString(); Map env = ctx.getContainer().getLaunchContext().getEnvironment(); try { if (ContainerExecutor.Signal.NULL.equals(signal)) { executeLivelinessCheck(ctx); + } else if (ContainerExecutor.Signal.TERM.equals(signal)) { + String containerId = ctx.getContainer().getContainerId().toString(); + handleContainerStop(containerId, env); } else { - if (ContainerExecutor.Signal.KILL.equals(signal) - || ContainerExecutor.Signal.TERM.equals(signal)) { - handleContainerStop(containerId, env); - } else { - handleContainerKill(containerId, env, signal); - } + handleContainerKill(ctx, env, signal); } } catch (ContainerExecutionException e) { LOG.warn("Signal docker container failed. Exception: ", e); @@ -1184,21 +1184,50 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime { } } - private void handleContainerKill(String containerId, Map env, + private void handleContainerKill(ContainerRuntimeContext ctx, + Map env, ContainerExecutor.Signal signal) throws ContainerExecutionException { - DockerCommandExecutor.DockerContainerStatus containerStatus = - DockerCommandExecutor.getContainerStatus(containerId, conf, - privilegedOperationExecutor, nmContext); - if (DockerCommandExecutor.isKillable(containerStatus)) { - DockerKillCommand dockerKillCommand = - new DockerKillCommand(containerId).setSignal(signal.name()); - DockerCommandExecutor.executeDockerCommand(dockerKillCommand, containerId, - env, conf, privilegedOperationExecutor, false, nmContext); - } else { - if (LOG.isDebugEnabled()) { + Container container = ctx.getContainer(); + + // Only need to check whether the container was asked to be privileged. + // If the container had failed the permissions checks upon launch, it + // would have never been launched and thus we wouldn't be here + // attempting to signal it. + if (isContainerRequestedAsPrivileged(container)) { + String containerId = container.getContainerId().toString(); + DockerCommandExecutor.DockerContainerStatus containerStatus = + DockerCommandExecutor.getContainerStatus(containerId, conf, + privilegedOperationExecutor, nmContext); + if (DockerCommandExecutor.isKillable(containerStatus)) { + DockerKillCommand dockerKillCommand = + new DockerKillCommand(containerId).setSignal(signal.name()); + DockerCommandExecutor.executeDockerCommand(dockerKillCommand, + containerId, env, conf, privilegedOperationExecutor, false, + nmContext); + } else { LOG.debug( - "Container status is " + containerStatus.getName() - + ", skipping kill - " + containerId); + "Container status is {}, skipping kill - {}", + containerStatus.getName(), containerId); + } + } else { + PrivilegedOperation privOp = new PrivilegedOperation( + PrivilegedOperation.OperationType.SIGNAL_CONTAINER); + privOp.appendArgs(ctx.getExecutionAttribute(RUN_AS_USER), + ctx.getExecutionAttribute(USER), + Integer.toString(PrivilegedOperation.RunAsUserCommand + .SIGNAL_CONTAINER.getValue()), + ctx.getExecutionAttribute(PID), + Integer.toString(ctx.getExecutionAttribute(SIGNAL).getValue())); + privOp.disableFailureLogging(); + try { + privilegedOperationExecutor.executePrivilegedOperation(null, + privOp, null, null, false, false); + } catch (PrivilegedOperationException e) { + //Don't log the failure here. Some kinds of signaling failures are + // acceptable. Let the calling executor decide what to do. + throw new ContainerExecutionException("Signal container failed using " + + "signal: " + signal.name(), e + .getExitCode(), e.getOutput(), e.getErrorOutput()); } } } 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/runtime/TestDockerContainerRuntime.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/runtime/TestDockerContainerRuntime.java index af69e2226a2..ef21ef093bc 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/runtime/TestDockerContainerRuntime.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/runtime/TestDockerContainerRuntime.java @@ -43,13 +43,8 @@ import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileg import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationException; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationExecutor; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsHandler; -import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerClient; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerCommandExecutor; -import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerKillCommand; -import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerRmCommand; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerRunCommand; -import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerStartCommand; -import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerStopCommand; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerVolumeCommand; import org.apache.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.DockerCommandPlugin; import org.apache.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.ResourcePlugin; @@ -87,6 +82,7 @@ import java.util.Random; import java.util.Set; import java.util.concurrent.ConcurrentMap; +import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_RUN_PRIVILEGED_CONTAINER; import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntimeConstants.APPID; import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntimeConstants.APPLICATION_LOCAL_DIRS; import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntimeConstants.CONTAINER_ID_STR; @@ -103,7 +99,6 @@ import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.r import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntimeConstants.RESOURCES_OPTIONS; import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntimeConstants.RUN_AS_USER; import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntimeConstants.SIGNAL; -import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntimeConstants.TC_COMMAND_FILE; import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntimeConstants.USER; import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntimeConstants.USER_FILECACHE_DIRS; import static org.mockito.Matchers.anyString; @@ -317,20 +312,24 @@ public class TestDockerContainerRuntime { .isDockerContainerRequested(envOtherType)); } - @SuppressWarnings("unchecked") private PrivilegedOperation capturePrivilegedOperation() throws PrivilegedOperationException { + return capturePrivilegedOperation(1); + } + + @SuppressWarnings("unchecked") + private PrivilegedOperation capturePrivilegedOperation(int invocations) + throws PrivilegedOperationException { ArgumentCaptor opCaptor = ArgumentCaptor.forClass( PrivilegedOperation.class); - //single invocation expected //due to type erasure + mocking, this verification requires a suppress // warning annotation on the entire method - verify(mockExecutor, times(1)) + verify(mockExecutor, times(invocations)) .executePrivilegedOperation(anyList(), opCaptor.capture(), any( File.class), anyMap(), anyBoolean(), anyBoolean()); - //verification completed. we need to isolate specific invications. + //verification completed. we need to isolate specific invocations. // hence, reset mock here Mockito.reset(mockExecutor); @@ -918,6 +917,8 @@ public class TestDockerContainerRuntime { @Test public void testLaunchPrivilegedContainersWithDisabledSetting() throws ContainerExecutionException { + conf.setBoolean(YarnConfiguration.NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS, + false); DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime( mockExecutor, mockCGroupsHandler); runtime.initialize(conf, nmContext); @@ -939,6 +940,7 @@ public class TestDockerContainerRuntime { //Enable privileged containers. conf.setBoolean(YarnConfiguration.NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS, true); + conf.set(YarnConfiguration.NM_DOCKER_PRIVILEGED_CONTAINERS_ACL, ""); DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime( mockExecutor, mockCGroupsHandler); @@ -1356,9 +1358,12 @@ public class TestDockerContainerRuntime { public void testDockerStopOnTermSignalWhenRunning() throws ContainerExecutionException, PrivilegedOperationException, IOException { - List dockerCommands = getDockerCommandsForSignal( - ContainerExecutor.Signal.TERM, - DockerCommandExecutor.DockerContainerStatus.RUNNING); + when(mockExecutor + .executePrivilegedOperation(anyList(), any(PrivilegedOperation.class), + any(File.class), anyMap(), anyBoolean(), anyBoolean())).thenReturn( + DockerCommandExecutor.DockerContainerStatus.RUNNING.getName()); + List dockerCommands = getDockerCommandsForDockerStop( + ContainerExecutor.Signal.TERM); Assert.assertEquals(4, dockerCommands.size()); Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0)); Assert.assertEquals(" docker-command=stop", dockerCommands.get(1)); @@ -1370,11 +1375,54 @@ public class TestDockerContainerRuntime { @Test public void testDockerStopOnKillSignalWhenRunning() + throws ContainerExecutionException, PrivilegedOperationException { + List dockerCommands = getDockerCommandsForSignal( + ContainerExecutor.Signal.KILL); + Assert.assertEquals(5, dockerCommands.size()); + Assert.assertEquals(runAsUser, dockerCommands.get(0)); + Assert.assertEquals(user, dockerCommands.get(1)); + Assert.assertEquals( + Integer.toString(PrivilegedOperation.RunAsUserCommand + .SIGNAL_CONTAINER.getValue()), + dockerCommands.get(2)); + Assert.assertEquals(signalPid, dockerCommands.get(3)); + Assert.assertEquals( + Integer.toString(ContainerExecutor.Signal.KILL.getValue()), + dockerCommands.get(4)); + } + + @Test + public void testDockerKillOnQuitSignalWhenRunning() throws Exception { + List dockerCommands = getDockerCommandsForSignal( + ContainerExecutor.Signal.QUIT); + + Assert.assertEquals(5, dockerCommands.size()); + Assert.assertEquals(runAsUser, dockerCommands.get(0)); + Assert.assertEquals(user, dockerCommands.get(1)); + Assert.assertEquals( + Integer.toString(PrivilegedOperation.RunAsUserCommand + .SIGNAL_CONTAINER.getValue()), + dockerCommands.get(2)); + Assert.assertEquals(signalPid, dockerCommands.get(3)); + Assert.assertEquals( + Integer.toString(ContainerExecutor.Signal.QUIT.getValue()), + dockerCommands.get(4)); + } + + @Test + public void testDockerStopOnTermSignalWhenRunningPrivileged() throws ContainerExecutionException, PrivilegedOperationException, IOException { - List dockerCommands = getDockerCommandsForSignal( - ContainerExecutor.Signal.KILL, - DockerCommandExecutor.DockerContainerStatus.RUNNING); + conf.set(YarnConfiguration.NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS, "true"); + conf.set(YarnConfiguration.NM_DOCKER_PRIVILEGED_CONTAINERS_ACL, + submittingUser); + env.put(ENV_DOCKER_CONTAINER_RUN_PRIVILEGED_CONTAINER, "true"); + when(mockExecutor + .executePrivilegedOperation(anyList(), any(PrivilegedOperation.class), + any(File.class), anyMap(), anyBoolean(), anyBoolean())).thenReturn( + DockerCommandExecutor.DockerContainerStatus.RUNNING.getName()); + List dockerCommands = getDockerCommandsForDockerStop( + ContainerExecutor.Signal.TERM); Assert.assertEquals(4, dockerCommands.size()); Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0)); Assert.assertEquals(" docker-command=stop", dockerCommands.get(1)); @@ -1385,10 +1433,42 @@ public class TestDockerContainerRuntime { } @Test - public void testDockerKillOnQuitSignalWhenRunning() throws Exception { - List dockerCommands = getDockerCommandsForSignal( - ContainerExecutor.Signal.QUIT, - DockerCommandExecutor.DockerContainerStatus.RUNNING); + public void testDockerStopOnKillSignalWhenRunningPrivileged() + throws ContainerExecutionException, PrivilegedOperationException, + IOException { + conf.set(YarnConfiguration.NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS, "true"); + conf.set(YarnConfiguration.NM_DOCKER_PRIVILEGED_CONTAINERS_ACL, + submittingUser); + env.put(ENV_DOCKER_CONTAINER_RUN_PRIVILEGED_CONTAINER, "true"); + when(mockExecutor + .executePrivilegedOperation(anyList(), any(PrivilegedOperation.class), + any(File.class), anyMap(), anyBoolean(), anyBoolean())).thenReturn( + DockerCommandExecutor.DockerContainerStatus.RUNNING.getName()); + List dockerCommands = getDockerCommandsForDockerStop( + ContainerExecutor.Signal.KILL); + Assert.assertEquals(4, dockerCommands.size()); + Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0)); + Assert.assertEquals(" docker-command=kill", dockerCommands.get(1)); + Assert.assertEquals( + " name=container_e11_1518975676334_14532816_01_000001", + dockerCommands.get(2)); + Assert.assertEquals(" signal=KILL", dockerCommands.get(3)); + } + + @Test + public void testDockerKillOnQuitSignalWhenRunningPrivileged() + throws Exception { + conf.set(YarnConfiguration.NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS, "true"); + conf.set(YarnConfiguration.NM_DOCKER_PRIVILEGED_CONTAINERS_ACL, + submittingUser); + env.put(ENV_DOCKER_CONTAINER_RUN_PRIVILEGED_CONTAINER, "true"); + when(mockExecutor + .executePrivilegedOperation(anyList(), any(PrivilegedOperation.class), + any(File.class), anyMap(), anyBoolean(), anyBoolean())).thenReturn( + DockerCommandExecutor.DockerContainerStatus.RUNNING.getName()); + List dockerCommands = getDockerCommandsForDockerStop( + ContainerExecutor.Signal.QUIT); + Assert.assertEquals(4, dockerCommands.size()); Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0)); Assert.assertEquals(" docker-command=kill", dockerCommands.get(1)); @@ -1403,8 +1483,8 @@ public class TestDockerContainerRuntime { env.put(DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_DELAYED_REMOVAL, "false"); conf.set(YarnConfiguration.NM_DOCKER_ALLOW_DELAYED_REMOVAL, "true"); - MockRuntime runtime = new MockRuntime(mockExecutor, - DockerCommandExecutor.DockerContainerStatus.EXITED, true); + DockerLinuxContainerRuntime runtime = + new DockerLinuxContainerRuntime(mockExecutor, mockCGroupsHandler); builder.setExecutionAttribute(RUN_AS_USER, runAsUser) .setExecutionAttribute(USER, user); runtime.initialize(enableMockContainerExecutor(conf), null); @@ -1420,8 +1500,8 @@ public class TestDockerContainerRuntime { env.put(DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_DELAYED_REMOVAL, "true"); conf.set(YarnConfiguration.NM_DOCKER_ALLOW_DELAYED_REMOVAL, "true"); - MockRuntime runtime = new MockRuntime(mockExecutor, - DockerCommandExecutor.DockerContainerStatus.EXITED, true); + DockerLinuxContainerRuntime runtime = + new DockerLinuxContainerRuntime(mockExecutor, mockCGroupsHandler); builder.setExecutionAttribute(RUN_AS_USER, runAsUser) .setExecutionAttribute(USER, user); runtime.initialize(enableMockContainerExecutor(conf), null); @@ -1431,13 +1511,34 @@ public class TestDockerContainerRuntime { File.class), anyMap(), anyBoolean(), anyBoolean()); } - private List getDockerCommandsForSignal( - ContainerExecutor.Signal signal, - DockerCommandExecutor.DockerContainerStatus status) + private List getDockerCommandsForDockerStop( + ContainerExecutor.Signal signal) throws ContainerExecutionException, PrivilegedOperationException, IOException { - MockRuntime runtime = new MockRuntime(mockExecutor, status, false); + DockerLinuxContainerRuntime runtime = + new DockerLinuxContainerRuntime(mockExecutor, mockCGroupsHandler); + builder.setExecutionAttribute(RUN_AS_USER, runAsUser) + .setExecutionAttribute(USER, user) + .setExecutionAttribute(PID, signalPid) + .setExecutionAttribute(SIGNAL, signal); + runtime.initialize(enableMockContainerExecutor(conf), nmContext); + runtime.signalContainer(builder.build()); + + PrivilegedOperation op = capturePrivilegedOperation(2); + Assert.assertEquals(op.getOperationType(), + PrivilegedOperation.OperationType.RUN_DOCKER_CMD); + String dockerCommandFile = op.getArguments().get(0); + return Files.readAllLines(Paths.get(dockerCommandFile), + Charset.forName("UTF-8")); + } + + private List getDockerCommandsForSignal( + ContainerExecutor.Signal signal) + throws ContainerExecutionException, PrivilegedOperationException { + + DockerLinuxContainerRuntime runtime = + new DockerLinuxContainerRuntime(mockExecutor, mockCGroupsHandler); builder.setExecutionAttribute(RUN_AS_USER, runAsUser) .setExecutionAttribute(USER, user) .setExecutionAttribute(PID, signalPid) @@ -1447,10 +1548,8 @@ public class TestDockerContainerRuntime { PrivilegedOperation op = capturePrivilegedOperation(); Assert.assertEquals(op.getOperationType(), - PrivilegedOperation.OperationType.RUN_DOCKER_CMD); - String dockerCommandFile = op.getArguments().get(0); - return Files.readAllLines(Paths.get(dockerCommandFile), - Charset.forName("UTF-8")); + PrivilegedOperation.OperationType.SIGNAL_CONTAINER); + return op.getArguments(); } /** @@ -1937,12 +2036,16 @@ public class TestDockerContainerRuntime { public void testDockerContainerRelaunch() throws ContainerExecutionException, PrivilegedOperationException, IOException { - DockerLinuxContainerRuntime runtime = new MockRuntime(mockExecutor, - DockerCommandExecutor.DockerContainerStatus.EXITED, false); - runtime.initialize(conf, null); + DockerLinuxContainerRuntime runtime = + new DockerLinuxContainerRuntime(mockExecutor, mockCGroupsHandler); + when(mockExecutor + .executePrivilegedOperation(anyList(), any(PrivilegedOperation.class), + any(File.class), anyMap(), anyBoolean(), anyBoolean())).thenReturn( + DockerCommandExecutor.DockerContainerStatus.STOPPED.getName()); + runtime.initialize(conf, nmContext); runtime.relaunchContainer(builder.build()); - PrivilegedOperation op = capturePrivilegedOperation(); + PrivilegedOperation op = capturePrivilegedOperation(2); List args = op.getArguments(); String dockerCommandFile = args.get(11); @@ -1960,134 +2063,4 @@ public class TestDockerContainerRuntime { " name=container_e11_1518975676334_14532816_01_000001", dockerCommands.get(counter)); } - - class MockRuntime extends DockerLinuxContainerRuntime { - - private PrivilegedOperationExecutor privilegedOperationExecutor; - private DockerCommandExecutor.DockerContainerStatus containerStatus; - private boolean delayedRemovalAllowed; - - MockRuntime(PrivilegedOperationExecutor privilegedOperationExecutor, - DockerCommandExecutor.DockerContainerStatus containerStatus, - boolean delayedRemovalAllowed) { - super(privilegedOperationExecutor); - this.privilegedOperationExecutor = privilegedOperationExecutor; - this.containerStatus = containerStatus; - this.delayedRemovalAllowed = delayedRemovalAllowed; - } - - @Override - public void signalContainer(ContainerRuntimeContext ctx) - throws ContainerExecutionException { - ContainerExecutor.Signal signal = ctx.getExecutionAttribute(SIGNAL); - String containerName = ctx.getContainer().getContainerId().toString(); - Map environment = - ctx.getContainer().getLaunchContext().getEnvironment(); - try { - if (ContainerExecutor.Signal.KILL.equals(signal) - || ContainerExecutor.Signal.TERM.equals(signal)) { - if (DockerCommandExecutor.isStoppable(containerStatus)) { - DockerStopCommand dockerStopCommand = - new DockerStopCommand(containerName) - .setGracePeriod(dockerStopGracePeriod); - DockerCommandExecutor.executeDockerCommand(dockerStopCommand, - containerName, environment, conf, mockExecutor, false, - nmContext); - } - } else { - if (DockerCommandExecutor.isKillable(containerStatus)) { - DockerKillCommand dockerKillCommand = - new DockerKillCommand(containerName); - dockerKillCommand.setSignal(signal.name()); - DockerCommandExecutor.executeDockerCommand(dockerKillCommand, - containerName, environment, conf, mockExecutor, false, - nmContext); - } - } - } catch (ContainerExecutionException e) { - LOG.warn("Signal docker container failed. Exception: ", e); - throw new ContainerExecutionException("Signal docker container failed", - e.getExitCode(), e.getOutput(), e.getErrorOutput()); - } - } - - @Override - public void reapContainer(ContainerRuntimeContext ctx) - throws ContainerExecutionException { - String delayedRemoval = env.get(ENV_DOCKER_CONTAINER_DELAYED_REMOVAL); - if (delayedRemovalAllowed && delayedRemoval != null - && delayedRemoval.equalsIgnoreCase("true")) { - LOG.info("Delayed removal requested and allowed, skipping removal - " - + containerId); - } else { - if (DockerCommandExecutor.isRemovable(containerStatus)) { - DockerRmCommand dockerRmCommand = new DockerRmCommand(containerId); - DockerCommandExecutor - .executeDockerCommand(dockerRmCommand, containerId, env, conf, - privilegedOperationExecutor, false, nmContext); - } - } - } - - @Override - public void relaunchContainer(ContainerRuntimeContext ctx) - throws ContainerExecutionException { - if (DockerCommandExecutor.isRemovable(containerStatus)) { - String relaunchContainerIdStr = - ctx.getContainer().getContainerId().toString(); - DockerStartCommand startCommand = - new DockerStartCommand(containerIdStr); - DockerClient dockerClient = new DockerClient(conf); - String commandFile = dockerClient.writeCommandToTempFile(startCommand, - relaunchContainerIdStr); - String relaunchRunAsUser = ctx.getExecutionAttribute(RUN_AS_USER); - Path relaunchNmPrivateContainerScriptPath = ctx.getExecutionAttribute( - NM_PRIVATE_CONTAINER_SCRIPT_PATH); - Path relaunchContainerWorkDir = - ctx.getExecutionAttribute(CONTAINER_WORK_DIR); - //we can't do better here thanks to type-erasure - @SuppressWarnings("unchecked") - List relaunchLocalDirs = ctx.getExecutionAttribute(LOCAL_DIRS); - @SuppressWarnings("unchecked") - List relaunchLogDirs = ctx.getExecutionAttribute(LOG_DIRS); - String resourcesOpts = ctx.getExecutionAttribute(RESOURCES_OPTIONS); - - PrivilegedOperation launchOp = new PrivilegedOperation( - PrivilegedOperation.OperationType.LAUNCH_DOCKER_CONTAINER); - - launchOp.appendArgs(relaunchRunAsUser, ctx.getExecutionAttribute(USER), - Integer.toString(PrivilegedOperation - .RunAsUserCommand.LAUNCH_DOCKER_CONTAINER.getValue()), - ctx.getExecutionAttribute(APPID), - relaunchContainerIdStr, - relaunchContainerWorkDir.toString(), - relaunchNmPrivateContainerScriptPath.toUri().getPath(), - ctx.getExecutionAttribute(NM_PRIVATE_TOKENS_PATH).toUri().getPath(), - ctx.getExecutionAttribute(PID_FILE_PATH).toString(), - StringUtils.join(PrivilegedOperation.LINUX_FILE_PATH_SEPARATOR, - relaunchLocalDirs), - StringUtils.join(PrivilegedOperation.LINUX_FILE_PATH_SEPARATOR, - relaunchLogDirs), - commandFile, - resourcesOpts); - - String tcCommandFile = ctx.getExecutionAttribute(TC_COMMAND_FILE); - - if (tcCommandFile != null) { - launchOp.appendArgs(tcCommandFile); - } - - try { - privilegedOperationExecutor.executePrivilegedOperation(null, - launchOp, null, null, false, false); - } catch (PrivilegedOperationException e) { - LOG.warn("Relaunch container failed. Exception: ", e); - LOG.info("Docker command used: " + startCommand); - - throw new ContainerExecutionException("Launch container failed", e - .getExitCode(), e.getOutput(), e.getErrorOutput()); - } - } - } - } }