diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
index 8d34f4e..4aca943 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
@@ -1120,6 +1120,44 @@ private static void addDeprecatedKeys() {
public static final String NM_DEFAULT_DOCKER_CONTAINER_EXECUTOR_EXEC_NAME =
"/usr/bin/docker";
+ /** Prefix for runtime configuration constants. */
+ public static final String LINUX_CONTAINER_RUNTIME_PREFIX = NM_PREFIX +
+ "runtime.linux.";
+ public static final String DOCKER_CONTAINER_RUNTIME_PREFIX =
+ LINUX_CONTAINER_RUNTIME_PREFIX + "docker.";
+
+ /** Capabilities allowed (and added by default) for docker containers. **/
+ public static final String NM_DOCKER_CONTAINER_CAPABILITIES =
+ DOCKER_CONTAINER_RUNTIME_PREFIX + "capabilities";
+
+ /** These are the default capabilities added by docker. We'll use the same
+ * set here. While these may not be case-sensitive from a docker
+ * perspective, it is best to keep these uppercase.
+ */
+ public static final String[] DEFAULT_NM_DOCKER_CONTAINER_CAPABILITIES = {
+ "CHOWN",
+ "DAC_OVERRIDE",
+ "FSETID",
+ "FOWNER",
+ "MKNOD",
+ "NET_RAW",
+ "SETGID",
+ "SETUID",
+ "SETFCAP",
+ "SETPCAP",
+ "NET_BIND_SERVICE",
+ "SYS_CHROOT",
+ "KILL",
+ "AUDIT_WRITE" };
+
+ /** Allow privileged containers. Use with extreme care. */
+ public static final String NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS =
+ DOCKER_CONTAINER_RUNTIME_PREFIX + "allow-privileged-containers";
+
+ /** Privileged containers are disabled by default. */
+ public static final boolean DEFAULT_NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS =
+ false;
+
/** The path to the Linux container executor.*/
public static final String NM_LINUX_CONTAINER_EXECUTOR_PATH =
NM_PREFIX + "linux-container-executor.path";
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
index e3d2c69..2ebad31 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
@@ -1420,6 +1420,23 @@
+ This configuration setting determines the capabilities
+ assigned to docker containers when they are launched. While these may not
+ be case-sensitive from a docker perspective, it is best to keep these
+ uppercase.
+ yarn.nodemanager.runtime.linux.docker.capabilities
+ CHOWN,DAC_OVERRIDE,FSETID,FOWNER,MKNOD,NET_RAW,SETGID,SETUID,SETFCAP,SETPCAP,NET_BIND_SERVICE,SYS_CHROOT,KILL,AUDIT_WRITE
+
+
+
+ This configuration setting determines if
+ privileged docker containers are allowed on this cluster.
+ Use with extreme care.
+ yarn.nodemanager.runtime.linux.docker.allow-privileged-containers
+ false
+
+
+
This flag determines whether memory limit will be set for the Windows Job
Object of the containers launched by the default container executor.
yarn.nodemanager.windows-container.memory-limit.enabled
diff --git 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 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 2430a78..9974cc2 100644
--- 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
+++ 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
@@ -26,7 +26,10 @@
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.util.StringUtils;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.security.AdminACLsManager;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation;
@@ -43,8 +46,11 @@
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntimeConstants.*;
@@ -63,11 +69,14 @@
@InterfaceAudience.Private
public static final String ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE =
"YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE";
-
+ @InterfaceAudience.Private
+ public static final String ENV_DOCKER_CONTAINER_RUN_PRIVILEGED_CONTAINER =
+ "YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER";
private Configuration conf;
private DockerClient dockerClient;
private PrivilegedOperationExecutor privilegedOperationExecutor;
+ private AdminACLsManager adminACLsManager;
public static boolean isDockerContainerRequested(
Map env) {
@@ -90,6 +99,7 @@ public void initialize(Configuration conf)
throws ContainerExecutionException {
this.conf = conf;
dockerClient = new DockerClient(conf);
+ adminACLsManager = new AdminACLsManager(conf);
}
@Override
@@ -131,6 +141,70 @@ public void addCGroupParentIfRequired(String resourcesOptions,
}
}
+ private boolean allowPrivilegedContainerExecution(Container container)
+ throws ContainerExecutionException {
+ //For a privileged container to be run all of the following three conditions
+ // must be satisfied:
+ //1) Submitting user must request for a privileged container
+ //2) Privileged containers must be enabled on the cluster
+ //3) Submitting user must be an admin.
+
+ 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);
+ return false;
+ }
+
+ if (LOG.isInfoEnabled()) {
+ LOG.info("Privileged container requested for : " + container
+ .getContainerId().toString());
+ }
+
+ //Ok, so we have been asked to run a privileged container. Security
+ // checks need to be run. Each violation is an error.
+
+ //check if privileged containers are enabled.
+ boolean privilegedContainersEnabledOnCluster = conf.getBoolean(
+ YarnConfiguration.NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS,
+ YarnConfiguration.DEFAULT_NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS);
+
+ if (!privilegedContainersEnabledOnCluster) {
+ String errorMsg = "Privileged container being requested but privileged "
+ + "containers are not enabled on this cluster";
+ LOG.error(errorMsg);
+ throw new ContainerExecutionException(errorMsg);
+ }
+
+ //check if submitting user is an admin.
+ String submittingUser = container.getUser();
+ UserGroupInformation submitterUgi = UserGroupInformation
+ .createRemoteUser(submittingUser);
+
+ if (!adminACLsManager.isAdmin(submitterUgi)) {
+ String errorMsg = "Cannot launch privileged container. Submitting user ("
+ + submittingUser + ") fails admin ACL check.";
+ LOG.error(errorMsg);
+ throw new ContainerExecutionException(errorMsg);
+ }
+
+ if (LOG.isInfoEnabled()) {
+ LOG.info("All checks pass. Launching privileged container for : "
+ + container.getContainerId().toString());
+ }
+
+ return true;
+ }
+
@Override
public void launchContainer(ContainerRuntimeContext ctx)
@@ -154,12 +228,17 @@ public void launchContainer(ContainerRuntimeContext ctx)
List localDirs = ctx.getExecutionAttribute(LOCAL_DIRS);
@SuppressWarnings("unchecked")
List logDirs = ctx.getExecutionAttribute(LOG_DIRS);
+ Set capabilities = new HashSet<>(Arrays.asList(conf.getStrings(
+ YarnConfiguration.NM_DOCKER_CONTAINER_CAPABILITIES,
+ YarnConfiguration.DEFAULT_NM_DOCKER_CONTAINER_CAPABILITIES)));
+
@SuppressWarnings("unchecked")
DockerRunCommand runCommand = new DockerRunCommand(containerIdStr,
runAsUser, imageName)
.detachOnRun()
.setContainerWorkDir(containerWorkDir.toString())
.setNetworkType("host")
+ .setCapabilities(capabilities)
.addMountLocation("/etc/passwd", "/etc/password:ro");
List allDirs = new ArrayList<>(localDirs);
@@ -169,6 +248,10 @@ public void launchContainer(ContainerRuntimeContext ctx)
runCommand.addMountLocation(dir, dir);
}
+ if (allowPrivilegedContainerExecution(container)) {
+ runCommand.setPrivileged();
+ }
+
String resourcesOpts = ctx.getExecutionAttribute(RESOURCES_OPTIONS);
/** Disabling docker's cgroup parent support for the time being. Docker
diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRunCommand.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRunCommand.java
index f9a890e..7c49ef9 100644
--- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRunCommand.java
+++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRunCommand.java
@@ -24,6 +24,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
public class DockerRunCommand extends DockerCommand {
private static final String RUN_COMMAND = "run";
@@ -68,6 +69,23 @@ public DockerRunCommand setCGroupParent(String parentPath) {
return this;
}
+ /* Run a privileged container. Use with extreme care */
+ public DockerRunCommand setPrivileged() {
+ super.addCommandArguments("--privileged");
+ return this;
+ }
+
+ public DockerRunCommand setCapabilities(Set capabilties) {
+ //first, drop all capabilities
+ super.addCommandArguments("--cap-drop=ALL");
+
+ //now, add the capabilities supplied
+ for (String capability : capabilties) {
+ super.addCommandArguments("--cap-add=" + capability);
+ }
+
+ return this;
+ }
public DockerRunCommand addDevice(String sourceDevice, String
destinationDevice) {
super.addCommandArguments("--device=" + sourceDevice + ":" +
diff --git 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 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 31ed496..a968137 100644
--- 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
+++ 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
@@ -20,10 +20,13 @@
package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.yarn.api.records.ContainerId;
import org.apache.hadoop.yarn.api.records.ContainerLaunchContext;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.server.nodemanager.LocalDirsHandlerService;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation;
@@ -44,15 +47,20 @@
import java.nio.file.Files;
import java.nio.file.Paths;
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;
import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntimeConstants.*;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
public class TestDockerContainerRuntime {
+ private static final Log LOG = LogFactory
+ .getLog(TestDockerContainerRuntime.class);
private Configuration conf;
PrivilegedOperationExecutor mockExecutor;
String containerId;
@@ -72,6 +80,9 @@
List localDirs;
List logDirs;
String resourcesOptions;
+ ContainerRuntimeContext.Builder builder;
+ String submittingUser = "test";
+ String adminUser = "admin";
@Before
public void setup() {
@@ -96,6 +107,7 @@ public void setup() {
when(cId.toString()).thenReturn(containerId);
when(container.getLaunchContext()).thenReturn(context);
when(context.getEnvironment()).thenReturn(env);
+ when(container.getUser()).thenReturn(submittingUser);
runAsUser = "run_as_user";
user = "user";
@@ -111,6 +123,22 @@ public void setup() {
localDirs.add("/test_local_dir");
logDirs.add("/test_log_dir");
+
+ builder = new ContainerRuntimeContext
+ .Builder(container);
+
+ builder.setExecutionAttribute(RUN_AS_USER, runAsUser)
+ .setExecutionAttribute(USER, user)
+ .setExecutionAttribute(APPID, appId)
+ .setExecutionAttribute(CONTAINER_ID_STR, containerIdStr)
+ .setExecutionAttribute(CONTAINER_WORK_DIR, containerWorkDir)
+ .setExecutionAttribute(NM_PRIVATE_CONTAINER_SCRIPT_PATH,
+ nmPrivateContainerScriptPath)
+ .setExecutionAttribute(NM_PRIVATE_TOKENS_PATH, nmPrivateTokensPath)
+ .setExecutionAttribute(PID_FILE_PATH, pidFilePath)
+ .setExecutionAttribute(LOCAL_DIRS, localDirs)
+ .setExecutionAttribute(LOG_DIRS, logDirs)
+ .setExecutionAttribute(RESOURCES_OPTIONS, resourcesOptions);
}
@Test
@@ -129,33 +157,9 @@ public void testSelectDockerContainerType() {
.isDockerContainerRequested(envOtherType));
}
- @Test
@SuppressWarnings("unchecked")
- public void testDockerContainerLaunch()
- throws ContainerExecutionException, PrivilegedOperationException,
- IOException {
- DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
- mockExecutor);
- runtime.initialize(conf);
-
- ContainerRuntimeContext.Builder builder = new ContainerRuntimeContext
- .Builder(container);
-
- builder.setExecutionAttribute(RUN_AS_USER, runAsUser)
- .setExecutionAttribute(USER, user)
- .setExecutionAttribute(APPID, appId)
- .setExecutionAttribute(CONTAINER_ID_STR, containerIdStr)
- .setExecutionAttribute(CONTAINER_WORK_DIR, containerWorkDir)
- .setExecutionAttribute(NM_PRIVATE_CONTAINER_SCRIPT_PATH,
- nmPrivateContainerScriptPath)
- .setExecutionAttribute(NM_PRIVATE_TOKENS_PATH, nmPrivateTokensPath)
- .setExecutionAttribute(PID_FILE_PATH, pidFilePath)
- .setExecutionAttribute(LOCAL_DIRS, localDirs)
- .setExecutionAttribute(LOG_DIRS, logDirs)
- .setExecutionAttribute(RESOURCES_OPTIONS, resourcesOptions);
-
- runtime.launchContainer(builder.build());
-
+ private PrivilegedOperation capturePrivilegedOperationAndVerifyArgs()
+ throws PrivilegedOperationException {
ArgumentCaptor opCaptor = ArgumentCaptor.forClass(
PrivilegedOperation.class);
@@ -186,20 +190,51 @@ public void testDockerContainerLaunch()
Assert.assertEquals(containerId, args.get(4));
Assert.assertEquals(containerWorkDir.toString(), args.get(5));
Assert.assertEquals(nmPrivateContainerScriptPath.toUri()
- .toString(), args.get(6));
+ .toString(), args.get(6));
Assert.assertEquals(nmPrivateTokensPath.toUri().getPath(), args.get(7));
Assert.assertEquals(pidFilePath.toString(), args.get(8));
Assert.assertEquals(localDirs.get(0), args.get(9));
Assert.assertEquals(logDirs.get(0), args.get(10));
Assert.assertEquals(resourcesOptions, args.get(12));
+ return op;
+ }
+
+ @Test
+ public void testDockerContainerLaunch()
+ throws ContainerExecutionException, PrivilegedOperationException,
+ IOException {
+ DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
+ mockExecutor);
+ runtime.initialize(conf);
+
+ String[] testCapabilities = {"NET_BIND_SERVICE", "SYS_CHROOT"};
+
+ conf.setStrings(YarnConfiguration.NM_DOCKER_CONTAINER_CAPABILITIES,
+ testCapabilities);
+ runtime.launchContainer(builder.build());
+
+ PrivilegedOperation op = capturePrivilegedOperationAndVerifyArgs();
+ List args = op.getArguments();
String dockerCommandFile = args.get(11);
+ /* Ordering of capabilities depends on HashSet ordering. */
+ Set capabilitySet = new HashSet<>(Arrays.asList(testCapabilities));
+ StringBuilder expectedCapabilitiesString = new StringBuilder(
+ "--cap-drop=ALL ");
+
+ for(String capability : capabilitySet) {
+ expectedCapabilitiesString.append("--cap-add=").append(capability)
+ .append(" ");
+ }
+
//This is the expected docker invocation for this case
StringBuffer expectedCommandTemplate = new StringBuffer("run --name=%1$s ")
.append("--user=%2$s -d ")
.append("--workdir=%3$s ")
- .append("--net=host -v /etc/passwd:/etc/password:ro ")
+ .append("--net=host ")
+ .append(expectedCapabilitiesString)
+ .append("-v /etc/passwd:/etc/password:ro ")
.append("-v %4$s:%4$s ")
.append("-v %5$s:%5$s ")
.append("-v %6$s:%6$s ")
@@ -216,4 +251,146 @@ public void testDockerContainerLaunch()
Assert.assertEquals(1, dockerCommands.size());
Assert.assertEquals(expectedCommand, dockerCommands.get(0));
}
+
+ @Test
+ public void testLaunchPrivilegedContainersInvalidEnvVar()
+ throws ContainerExecutionException, PrivilegedOperationException,
+ IOException{
+ DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
+ mockExecutor);
+ runtime.initialize(conf);
+
+ env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
+ "invalid-value");
+ runtime.launchContainer(builder.build());
+
+ PrivilegedOperation op = capturePrivilegedOperationAndVerifyArgs();
+ List args = op.getArguments();
+ String dockerCommandFile = args.get(11);
+
+ List dockerCommands = Files.readAllLines(Paths.get
+ (dockerCommandFile), Charset.forName("UTF-8"));
+
+ Assert.assertEquals(1, dockerCommands.size());
+
+ String command = dockerCommands.get(0);
+
+ //ensure --privileged isn't in the invocation
+ Assert.assertTrue("Unexpected --privileged in docker run args : " + command,
+ !command.contains("--privileged"));
+ }
+
+ @Test
+ public void testLaunchPrivilegedContainersWithDisabledSetting()
+ throws ContainerExecutionException, PrivilegedOperationException,
+ IOException{
+ DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
+ mockExecutor);
+ runtime.initialize(conf);
+
+ env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
+ "true");
+
+ try {
+ runtime.launchContainer(builder.build());
+ Assert.fail("Expected a privileged launch container failure.");
+ } catch (ContainerExecutionException e) {
+ LOG.info("Caught expected exception : " + e);
+ }
+ }
+
+ @Test
+ public void testLaunchPrivilegedContainersWithEnabledSettingAndDefaultACL()
+ throws ContainerExecutionException, PrivilegedOperationException,
+ IOException{
+ //Enable privileged containers.
+ conf.setBoolean(YarnConfiguration.NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS,
+ true);
+
+ DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
+ mockExecutor);
+ runtime.initialize(conf);
+
+ env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
+ "true");
+
+ runtime.launchContainer(builder.build());
+ PrivilegedOperation op = capturePrivilegedOperationAndVerifyArgs();
+ List args = op.getArguments();
+ String dockerCommandFile = args.get(11);
+
+ List dockerCommands = Files.readAllLines(Paths.get
+ (dockerCommandFile), Charset.forName("UTF-8"));
+
+ Assert.assertEquals(1, dockerCommands.size());
+
+ String command = dockerCommands.get(0);
+
+ //by default yarn.admin.acl allows everyone to be an admin.
+ //ensure --privileged is in the invocation
+ Assert.assertTrue("Did not find expected '--privileged' in docker run args "
+ + ": " + command, command.contains("--privileged"));
+ }
+
+
+ @Test
+ public void testLaunchPrivilegedContainersWithEnabledSettingAndNonAdminUser()
+ throws ContainerExecutionException, PrivilegedOperationException,
+ IOException{
+ //Enable privileged containers.
+ conf.setBoolean(YarnConfiguration.NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS,
+ true);
+ //Add user to admin user list.
+ conf.set(YarnConfiguration.YARN_ADMIN_ACL, adminUser);
+
+ DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
+ mockExecutor);
+ runtime.initialize(conf);
+
+ env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
+ "true");
+
+ try {
+ runtime.launchContainer(builder.build());
+ Assert.fail("Expected a privileged launch container failure.");
+ } catch (ContainerExecutionException e) {
+ LOG.info("Caught expected exception : " + e);
+ }
+ }
+
+ @Test
+ public void testLaunchPrivilegedContainersWithEnabledSettingAndAdminUser()
+ throws ContainerExecutionException, PrivilegedOperationException,
+ IOException{
+ //Enable privileged containers.
+ conf.setBoolean(YarnConfiguration.NM_DOCKER_ALLOW_PRIVILEGED_CONTAINERS,
+ true);
+ //Add user to admin user list.
+ conf.set(YarnConfiguration.YARN_ADMIN_ACL, submittingUser);
+
+ DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
+ mockExecutor);
+ runtime.initialize(conf);
+
+ env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
+ "true");
+
+ runtime.launchContainer(builder.build());
+ PrivilegedOperation op = capturePrivilegedOperationAndVerifyArgs();
+ List args = op.getArguments();
+ String dockerCommandFile = args.get(11);
+
+ List dockerCommands = Files.readAllLines(Paths.get
+ (dockerCommandFile), Charset.forName("UTF-8"));
+
+ Assert.assertEquals(1, dockerCommands.size());
+
+ String command = dockerCommands.get(0);
+
+ //by default yarn.admin.acl allows everyone to be an admin.
+ //ensure --privileged is in the invocation
+ Assert.assertTrue("Did not find expected '--privileged' in docker run args "
+ + ": " + command, command.contains("--privileged"));
+ }
+
}