You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by vv...@apache.org on 2015/07/27 22:32:01 UTC

[3/4] hadoop git commit: YARN-3853. Add docker container runtime support to LinuxContainterExecutor. Contributed by Sidharta Seethana.

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/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
----------------------------------------------------------------------
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/docker/DockerRunCommand.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/docker/DockerRunCommand.java
new file mode 100644
index 0000000..f9a890e
--- /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/runtime/docker/DockerRunCommand.java
@@ -0,0 +1,107 @@
+/*
+ * *
+ *  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.runtime.docker;
+
+import org.apache.hadoop.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DockerRunCommand extends DockerCommand {
+  private static final String RUN_COMMAND = "run";
+  private final String image;
+  private List<String> overrrideCommandWithArgs;
+
+  /** The following are mandatory: */
+  public DockerRunCommand(String containerId, String user, String image) {
+    super(RUN_COMMAND);
+    super.addCommandArguments("--name=" + containerId, "--user=" + user);
+    this.image = image;
+  }
+
+  public DockerRunCommand removeContainerOnExit() {
+    super.addCommandArguments("--rm");
+    return this;
+  }
+
+  public DockerRunCommand detachOnRun() {
+    super.addCommandArguments("-d");
+    return this;
+  }
+
+  public DockerRunCommand setContainerWorkDir(String workdir) {
+    super.addCommandArguments("--workdir=" + workdir);
+    return this;
+  }
+
+  public DockerRunCommand setNetworkType(String type) {
+    super.addCommandArguments("--net=" + type);
+    return this;
+  }
+
+  public DockerRunCommand addMountLocation(String sourcePath, String
+      destinationPath) {
+    super.addCommandArguments("-v", sourcePath + ":" + destinationPath);
+    return this;
+  }
+
+  public DockerRunCommand setCGroupParent(String parentPath) {
+    super.addCommandArguments("--cgroup-parent=" + parentPath);
+    return this;
+  }
+
+  public DockerRunCommand addDevice(String sourceDevice, String
+      destinationDevice) {
+    super.addCommandArguments("--device=" + sourceDevice + ":" +
+        destinationDevice);
+    return this;
+  }
+
+  public DockerRunCommand enableDetach() {
+    super.addCommandArguments("--detach=true");
+    return this;
+  }
+
+  public DockerRunCommand disableDetach() {
+    super.addCommandArguments("--detach=false");
+    return this;
+  }
+
+  public DockerRunCommand setOverrideCommandWithArgs(
+      List<String> overrideCommandWithArgs) {
+    this.overrrideCommandWithArgs = overrideCommandWithArgs;
+    return this;
+  }
+
+  @Override
+  public String getCommandWithArguments() {
+    List<String> argList = new ArrayList<>();
+
+    argList.add(super.getCommandWithArguments());
+    argList.add(image);
+
+    if (overrrideCommandWithArgs != null) {
+      argList.addAll(overrrideCommandWithArgs);
+    }
+
+    return StringUtils.join(" ", argList);
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/runtime/ContainerExecutionException.java
----------------------------------------------------------------------
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/runtime/ContainerExecutionException.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/runtime/ContainerExecutionException.java
new file mode 100644
index 0000000..1fbece2
--- /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/runtime/ContainerExecutionException.java
@@ -0,0 +1,85 @@
+/*
+ * *
+ *  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.runtime;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+
+/** Exception caused in a container runtime impl. 'Runtime' is not used in
+ * the class name to avoid confusion with a java RuntimeException
+ */
+
+@InterfaceAudience.Private
+@InterfaceStability.Unstable
+public class ContainerExecutionException extends YarnException {
+  private static final long serialVersionUID = 1L;
+  private static final Integer EXIT_CODE_UNSET = -1;
+  private static final String OUTPUT_UNSET = "<unknown>";
+
+  private Integer exitCode;
+  private String output;
+  private String errorOutput;
+
+  public ContainerExecutionException(String message) {
+    super(message);
+    exitCode = EXIT_CODE_UNSET;
+    output = OUTPUT_UNSET;
+    errorOutput = OUTPUT_UNSET;
+  }
+
+  public ContainerExecutionException(Throwable throwable) {
+    super(throwable);
+    exitCode = EXIT_CODE_UNSET;
+    output = OUTPUT_UNSET;
+    errorOutput = OUTPUT_UNSET;
+  }
+
+
+  public ContainerExecutionException(String message, Integer exitCode, String
+      output, String errorOutput) {
+    super(message);
+    this.exitCode = exitCode;
+    this.output = output;
+    this.errorOutput = errorOutput;
+  }
+
+  public ContainerExecutionException(Throwable cause, Integer exitCode, String
+      output, String errorOutput) {
+    super(cause);
+    this.exitCode = exitCode;
+    this.output = output;
+    this.errorOutput = errorOutput;
+  }
+
+  public Integer getExitCode() {
+    return exitCode;
+  }
+
+  public String getOutput() {
+    return output;
+  }
+
+  public String getErrorOutput() {
+    return errorOutput;
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/runtime/ContainerRuntime.java
----------------------------------------------------------------------
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/runtime/ContainerRuntime.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/runtime/ContainerRuntime.java
new file mode 100644
index 0000000..e05f3fc
--- /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/runtime/ContainerRuntime.java
@@ -0,0 +1,50 @@
+/*
+ * *
+ *  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.runtime;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/** An abstraction for various container runtime implementations. Examples
+ * include Process Tree, Docker, Appc runtimes etc., These implementations
+ * are meant for low-level OS container support - dependencies on
+ * higher-level nodemananger constructs should be avoided.
+ */
+
+@InterfaceAudience.Private
+@InterfaceStability.Unstable
+public interface ContainerRuntime {
+  /** Prepare a container to be ready for launch */
+  void prepareContainer(ContainerRuntimeContext ctx)
+      throws ContainerExecutionException;
+
+  /** Launch a container. */
+  void launchContainer(ContainerRuntimeContext ctx)
+      throws ContainerExecutionException;
+
+  /** Signal a container - request to terminate, status check etc., */
+  void signalContainer(ContainerRuntimeContext ctx)
+      throws ContainerExecutionException;
+
+  /** Any container cleanup that may be required. */
+  void reapContainer(ContainerRuntimeContext ctx)
+      throws ContainerExecutionException;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/runtime/ContainerRuntimeConstants.java
----------------------------------------------------------------------
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/runtime/ContainerRuntimeConstants.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/runtime/ContainerRuntimeConstants.java
new file mode 100644
index 0000000..4473856
--- /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/runtime/ContainerRuntimeConstants.java
@@ -0,0 +1,33 @@
+/*
+ * *
+ *  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.runtime;
+
+import org.apache.hadoop.classification.InterfaceAudience.Private;
+
+public class ContainerRuntimeConstants {
+
+  /* Switch container runtimes. Work in progress: These
+   * parameters may be changed/removed in the future. */
+
+  @Private
+  public static final String ENV_CONTAINER_TYPE =
+      "YARN_CONTAINER_RUNTIME_TYPE";
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/runtime/ContainerRuntimeContext.java
----------------------------------------------------------------------
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/runtime/ContainerRuntimeContext.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/runtime/ContainerRuntimeContext.java
new file mode 100644
index 0000000..4194b99
--- /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/runtime/ContainerRuntimeContext.java
@@ -0,0 +1,105 @@
+/*
+ * *
+ *  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.runtime;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+@InterfaceAudience.Private
+@InterfaceStability.Unstable
+public final class ContainerRuntimeContext {
+  private final Container container;
+  private final Map<Attribute<?>, Object> executionAttributes;
+
+  /** An attribute class that attempts to provide better type safety as compared
+   * with using a map of string to object.
+   * @param <T>
+   */
+  public static final class Attribute<T> {
+    private final Class<T> valueClass;
+    private final String id;
+
+    private Attribute(Class<T> valueClass, String id) {
+        this.valueClass = valueClass;
+        this.id = id;
+    }
+
+    @Override
+    public int hashCode() {
+      return valueClass.hashCode() + 31 * id.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (obj == null || !(obj instanceof Attribute)){
+        return false;
+      }
+
+      Attribute<?> attribute = (Attribute<?>) obj;
+
+      return valueClass.equals(attribute.valueClass) && id.equals(attribute.id);
+    }
+    public static <T> Attribute<T> attribute(Class<T> valueClass, String id) {
+      return new Attribute<T>(valueClass, id);
+    }
+  }
+
+  public static final class Builder {
+    private final Container container;
+    private Map<Attribute<?>, Object> executionAttributes;
+
+    public Builder(Container container) {
+      executionAttributes = new HashMap<>();
+      this.container = container;
+    }
+
+    public <E> Builder setExecutionAttribute(Attribute<E> attribute, E value) {
+      this.executionAttributes.put(attribute, attribute.valueClass.cast(value));
+      return this;
+    }
+
+    public ContainerRuntimeContext build() {
+      return new ContainerRuntimeContext(this);
+    }
+  }
+
+  private ContainerRuntimeContext(Builder builder) {
+    this.container = builder.container;
+    this.executionAttributes = builder.executionAttributes;
+  }
+
+  public Container getContainer() {
+    return this.container;
+  }
+
+  public Map<Attribute<?>, Object> getExecutionAttributes() {
+    return Collections.unmodifiableMap(this.executionAttributes);
+  }
+
+  public <E> E getExecutionAttribute(Attribute<E> attribute) {
+    return attribute.valueClass.cast(executionAttributes.get(attribute));
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerLivenessContext.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerLivenessContext.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerLivenessContext.java
index acadae9..43113ef 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerLivenessContext.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerLivenessContext.java
@@ -22,6 +22,7 @@ package org.apache.hadoop.yarn.server.nodemanager.executor;
 
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
 
 /**
  * Encapsulates information required for container liveness checks.
@@ -30,16 +31,23 @@ import org.apache.hadoop.classification.InterfaceStability;
 @InterfaceAudience.Private
 @InterfaceStability.Unstable
 public final class ContainerLivenessContext {
+  private final Container container;
   private final String user;
   private final String pid;
 
   public static final class Builder {
+    private Container container;
     private String user;
     private String pid;
 
     public Builder() {
     }
 
+    public Builder setContainer(Container container) {
+      this.container = container;
+      return this;
+    }
+
     public Builder setUser(String user) {
       this.user = user;
       return this;
@@ -56,10 +64,15 @@ public final class ContainerLivenessContext {
   }
 
   private ContainerLivenessContext(Builder builder) {
+    this.container = builder.container;
     this.user = builder.user;
     this.pid = builder.pid;
   }
 
+  public Container getContainer() {
+    return this.container;
+  }
+
   public String getUser() {
     return this.user;
   }

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerReacquisitionContext.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerReacquisitionContext.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerReacquisitionContext.java
index 8adcab7..d93cdaf 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerReacquisitionContext.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerReacquisitionContext.java
@@ -23,6 +23,7 @@ package org.apache.hadoop.yarn.server.nodemanager.executor;
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
 import org.apache.hadoop.yarn.api.records.ContainerId;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
 
 /**
  * Encapsulates information required for container reacquisition.
@@ -31,16 +32,23 @@ import org.apache.hadoop.yarn.api.records.ContainerId;
 @InterfaceAudience.Private
 @InterfaceStability.Unstable
 public final class ContainerReacquisitionContext {
+  private final Container container;
   private final String user;
   private final ContainerId containerId;
 
   public static final class Builder {
+    private Container container;
     private String user;
     private ContainerId containerId;
 
     public Builder() {
     }
 
+    public Builder setContainer(Container container) {
+      this.container = container;
+      return this;
+    }
+
     public Builder setUser(String user) {
       this.user = user;
       return this;
@@ -57,10 +65,15 @@ public final class ContainerReacquisitionContext {
   }
 
   private ContainerReacquisitionContext(Builder builder) {
+    this.container = builder.container;
     this.user = builder.user;
     this.containerId = builder.containerId;
   }
 
+  public Container getContainer() {
+    return this.container;
+  }
+
   public String getUser() {
     return this.user;
   }

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerSignalContext.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerSignalContext.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerSignalContext.java
index cc40af5..56b571b 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerSignalContext.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerSignalContext.java
@@ -23,6 +23,7 @@ package org.apache.hadoop.yarn.server.nodemanager.executor;
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
 import org.apache.hadoop.yarn.server.nodemanager.ContainerExecutor.Signal;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
 
 /**
  * Encapsulates information required for container signaling.
@@ -31,11 +32,13 @@ import org.apache.hadoop.yarn.server.nodemanager.ContainerExecutor.Signal;
 @InterfaceAudience.Private
 @InterfaceStability.Unstable
 public final class ContainerSignalContext {
+  private final Container container;
   private final String user;
   private final String pid;
   private final Signal signal;
 
   public static final class Builder {
+    private Container container;
     private String user;
     private String pid;
     private Signal signal;
@@ -43,6 +46,11 @@ public final class ContainerSignalContext {
     public Builder() {
     }
 
+    public Builder setContainer(Container container) {
+      this.container = container;
+      return this;
+    }
+
     public Builder setUser(String user) {
       this.user = user;
       return this;
@@ -64,11 +72,16 @@ public final class ContainerSignalContext {
   }
 
   private ContainerSignalContext(Builder builder) {
+    this.container = builder.container;
     this.user = builder.user;
     this.pid = builder.pid;
     this.signal = builder.signal;
   }
 
+  public Container getContainer() {
+    return this.container;
+  }
+
   public String getUser() {
     return this.user;
   }

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerStartContext.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerStartContext.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerStartContext.java
index 7dfff02..ffcc519 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerStartContext.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerStartContext.java
@@ -25,7 +25,9 @@ import org.apache.hadoop.classification.InterfaceStability;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
 
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Encapsulates information required for starting/launching containers.
@@ -35,6 +37,7 @@ import java.util.List;
 @InterfaceStability.Unstable
 public final class ContainerStartContext {
   private final Container container;
+  private final Map<Path, List<String>> localizedResources;
   private final Path nmPrivateContainerScriptPath;
   private final Path nmPrivateTokensPath;
   private final String user;
@@ -45,6 +48,7 @@ public final class ContainerStartContext {
 
   public static final class Builder {
     private Container container;
+    private Map<Path, List<String>> localizedResources;
     private Path nmPrivateContainerScriptPath;
     private Path nmPrivateTokensPath;
     private String user;
@@ -61,6 +65,12 @@ public final class ContainerStartContext {
       return this;
     }
 
+    public Builder setLocalizedResources(Map<Path,
+        List<String>> localizedResources) {
+      this.localizedResources = localizedResources;
+      return this;
+    }
+
     public Builder setNmPrivateContainerScriptPath(
         Path nmPrivateContainerScriptPath) {
       this.nmPrivateContainerScriptPath = nmPrivateContainerScriptPath;
@@ -104,6 +114,7 @@ public final class ContainerStartContext {
 
   private ContainerStartContext(Builder builder) {
     this.container = builder.container;
+    this.localizedResources = builder.localizedResources;
     this.nmPrivateContainerScriptPath = builder.nmPrivateContainerScriptPath;
     this.nmPrivateTokensPath = builder.nmPrivateTokensPath;
     this.user = builder.user;
@@ -117,6 +128,14 @@ public final class ContainerStartContext {
     return this.container;
   }
 
+  public Map<Path, List<String>> getLocalizedResources() {
+    if (this.localizedResources != null) {
+      return Collections.unmodifiableMap(this.localizedResources);
+    } else {
+      return null;
+    }
+  }
+
   public Path getNmPrivateContainerScriptPath() {
     return this.nmPrivateContainerScriptPath;
   }
@@ -138,10 +157,10 @@ public final class ContainerStartContext {
   }
 
   public List<String> getLocalDirs() {
-    return this.localDirs;
+    return Collections.unmodifiableList(this.localDirs);
   }
 
   public List<String> getLogDirs() {
-    return this.logDirs;
+    return Collections.unmodifiableList(this.logDirs);
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestLinuxContainerExecutorWithMocks.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestLinuxContainerExecutorWithMocks.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestLinuxContainerExecutorWithMocks.java
index 30c0392..0ef788b 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestLinuxContainerExecutorWithMocks.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestLinuxContainerExecutorWithMocks.java
@@ -32,6 +32,8 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.io.LineNumberReader;
 import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -50,6 +52,10 @@ import org.apache.hadoop.yarn.conf.YarnConfiguration;
 import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
 import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerDiagnosticsUpdateEvent;
 import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationExecutor;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.DefaultLinuxContainerRuntime;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntime;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException;
 import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerSignalContext;
 import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerStartContext;
 import org.apache.hadoop.yarn.server.nodemanager.executor.DeletionAsUserContext;
@@ -61,11 +67,19 @@ import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+
 public class TestLinuxContainerExecutorWithMocks {
 
   private static final Log LOG = LogFactory
       .getLog(TestLinuxContainerExecutorWithMocks.class);
 
+  private static final String MOCK_EXECUTOR =
+      "./src/test/resources/mock-container-executor";
+  private static final String MOCK_EXECUTOR_WITH_ERROR =
+      "./src/test/resources/mock-container-executer-with-error";
+
+  private String tmpMockExecutor;
   private LinuxContainerExecutor mockExec = null;
   private final File mockParamFile = new File("./params.txt");
   private LocalDirsHandlerService dirsHandler;
@@ -88,20 +102,42 @@ public class TestLinuxContainerExecutorWithMocks {
     reader.close();
     return ret;
   }
-  
+
+  private void setupMockExecutor(String executorPath, Configuration conf)
+      throws IOException {
+    //we'll always use the tmpMockExecutor - since
+    // PrivilegedOperationExecutor can only be initialized once.
+
+    Files.copy(Paths.get(executorPath), Paths.get(tmpMockExecutor),
+        REPLACE_EXISTING);
+
+    File executor = new File(tmpMockExecutor);
+
+    if (!FileUtil.canExecute(executor)) {
+      FileUtil.setExecutable(executor, true);
+    }
+    String executorAbsolutePath = executor.getAbsolutePath();
+    conf.set(YarnConfiguration.NM_LINUX_CONTAINER_EXECUTOR_PATH,
+        executorAbsolutePath);
+  }
+
   @Before
-  public void setup() {
+  public void setup() throws IOException, ContainerExecutionException {
     assumeTrue(!Path.WINDOWS);
-    File f = new File("./src/test/resources/mock-container-executor");
-    if(!FileUtil.canExecute(f)) {
-      FileUtil.setExecutable(f, true);
-    }
-    String executorPath = f.getAbsolutePath();
+
+    tmpMockExecutor = System.getProperty("test.build.data") +
+        "/tmp-mock-container-executor";
+
     Configuration conf = new Configuration();
-    conf.set(YarnConfiguration.NM_LINUX_CONTAINER_EXECUTOR_PATH, executorPath);
-    mockExec = new LinuxContainerExecutor();
+    LinuxContainerRuntime linuxContainerRuntime;
+
+    setupMockExecutor(MOCK_EXECUTOR, conf);
+    linuxContainerRuntime = new DefaultLinuxContainerRuntime(
+        PrivilegedOperationExecutor.getInstance(conf));
     dirsHandler = new LocalDirsHandlerService();
     dirsHandler.init(conf);
+    linuxContainerRuntime.initialize(conf);
+    mockExec = new LinuxContainerExecutor(linuxContainerRuntime);
     mockExec.setConf(conf);
   }
 
@@ -114,7 +150,7 @@ public class TestLinuxContainerExecutorWithMocks {
   public void testContainerLaunch() throws IOException {
     String appSubmitter = "nobody";
     String cmd = String.valueOf(
-        LinuxContainerExecutor.Commands.LAUNCH_CONTAINER.getValue());
+        PrivilegedOperation.RunAsUserCommand.LAUNCH_CONTAINER.getValue());
     String appId = "APP_ID";
     String containerId = "CONTAINER_ID";
     Container container = mock(Container.class);
@@ -161,13 +197,8 @@ public class TestLinuxContainerExecutorWithMocks {
   public void testContainerLaunchWithPriority() throws IOException {
 
     // set the scheduler priority to make sure still works with nice -n prio
-    File f = new File("./src/test/resources/mock-container-executor");
-    if (!FileUtil.canExecute(f)) {
-      FileUtil.setExecutable(f, true);
-    }
-    String executorPath = f.getAbsolutePath();
     Configuration conf = new Configuration();
-    conf.set(YarnConfiguration.NM_LINUX_CONTAINER_EXECUTOR_PATH, executorPath);
+    setupMockExecutor(MOCK_EXECUTOR, conf);
     conf.setInt(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY, 2);
 
     mockExec.setConf(conf);
@@ -231,20 +262,25 @@ public class TestLinuxContainerExecutorWithMocks {
   
   
   @Test
-  public void testContainerLaunchError() throws IOException {
+  public void testContainerLaunchError()
+      throws IOException, ContainerExecutionException {
 
     // reinitialize executer
-    File f = new File("./src/test/resources/mock-container-executer-with-error");
-    if (!FileUtil.canExecute(f)) {
-      FileUtil.setExecutable(f, true);
-    }
-    String executorPath = f.getAbsolutePath();
     Configuration conf = new Configuration();
-    conf.set(YarnConfiguration.NM_LINUX_CONTAINER_EXECUTOR_PATH, executorPath);
+    setupMockExecutor(MOCK_EXECUTOR_WITH_ERROR, conf);
     conf.set(YarnConfiguration.NM_LOCAL_DIRS, "file:///bin/echo");
     conf.set(YarnConfiguration.NM_LOG_DIRS, "file:///dev/null");
 
-    mockExec = spy(new LinuxContainerExecutor());
+
+    LinuxContainerExecutor exec;
+    LinuxContainerRuntime linuxContainerRuntime = new
+        DefaultLinuxContainerRuntime(PrivilegedOperationExecutor.getInstance
+        (conf));
+
+    linuxContainerRuntime.initialize(conf);
+    exec = new LinuxContainerExecutor(linuxContainerRuntime);
+
+    mockExec = spy(exec);
     doAnswer(
         new Answer() {
           @Override
@@ -263,7 +299,7 @@ public class TestLinuxContainerExecutorWithMocks {
 
     String appSubmitter = "nobody";
     String cmd = String
-        .valueOf(LinuxContainerExecutor.Commands.LAUNCH_CONTAINER.getValue());
+        .valueOf(PrivilegedOperation.RunAsUserCommand.LAUNCH_CONTAINER.getValue());
     String appId = "APP_ID";
     String containerId = "CONTAINER_ID";
     Container container = mock(Container.class);
@@ -299,6 +335,7 @@ public class TestLinuxContainerExecutorWithMocks {
     Path pidFile = new Path(workDir, "pid.txt");
 
     mockExec.activateContainer(cId, pidFile);
+
     int ret = mockExec.launchContainer(new ContainerStartContext.Builder()
         .setContainer(container)
         .setNmPrivateContainerScriptPath(scriptPath)
@@ -330,16 +367,23 @@ public class TestLinuxContainerExecutorWithMocks {
     
   }
 
-  
   @Test
   public void testContainerKill() throws IOException {
     String appSubmitter = "nobody";
     String cmd = String.valueOf(
-        LinuxContainerExecutor.Commands.SIGNAL_CONTAINER.getValue());
+        PrivilegedOperation.RunAsUserCommand.SIGNAL_CONTAINER.getValue());
     ContainerExecutor.Signal signal = ContainerExecutor.Signal.QUIT;
     String sigVal = String.valueOf(signal.getValue());
-    
+
+    Container container = mock(Container.class);
+    ContainerId cId = mock(ContainerId.class);
+    ContainerLaunchContext context = mock(ContainerLaunchContext.class);
+
+    when(container.getContainerId()).thenReturn(cId);
+    when(container.getLaunchContext()).thenReturn(context);
+
     mockExec.signalContainer(new ContainerSignalContext.Builder()
+        .setContainer(container)
         .setUser(appSubmitter)
         .setPid("1000")
         .setSignal(signal)
@@ -353,7 +397,7 @@ public class TestLinuxContainerExecutorWithMocks {
   public void testDeleteAsUser() throws IOException {
     String appSubmitter = "nobody";
     String cmd = String.valueOf(
-        LinuxContainerExecutor.Commands.DELETE_AS_USER.getValue());
+        PrivilegedOperation.RunAsUserCommand.DELETE_AS_USER.getValue());
     Path dir = new Path("/tmp/testdir");
     Path testFile = new Path("testfile");
     Path baseDir0 = new Path("/grid/0/BaseDir");
@@ -395,14 +439,9 @@ public class TestLinuxContainerExecutorWithMocks {
         Arrays.asList(YarnConfiguration.DEFAULT_NM_NONSECURE_MODE_LOCAL_USER,
             appSubmitter, cmd, "", baseDir0.toString(), baseDir1.toString()),
         readMockParams());
-
-    File f = new File("./src/test/resources/mock-container-executer-with-error");
-    if (!FileUtil.canExecute(f)) {
-      FileUtil.setExecutable(f, true);
-    }
-    String executorPath = f.getAbsolutePath();
+    ;
     Configuration conf = new Configuration();
-    conf.set(YarnConfiguration.NM_LINUX_CONTAINER_EXECUTOR_PATH, executorPath);
+    setupMockExecutor(MOCK_EXECUTOR, conf);
     mockExec.setConf(conf);
 
     mockExec.deleteAsUser(new DeletionAsUserContext.Builder()

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/privileged/TestPrivilegedOperationExecutor.java
----------------------------------------------------------------------
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/privileged/TestPrivilegedOperationExecutor.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/privileged/TestPrivilegedOperationExecutor.java
index 8f297ed..849dbab 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/privileged/TestPrivilegedOperationExecutor.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/privileged/TestPrivilegedOperationExecutor.java
@@ -118,7 +118,7 @@ public class TestPrivilegedOperationExecutor {
     PrivilegedOperationExecutor exec = PrivilegedOperationExecutor
         .getInstance(confWithExecutorPath);
     PrivilegedOperation op = new PrivilegedOperation(PrivilegedOperation
-        .OperationType.LAUNCH_CONTAINER, (String) null);
+        .OperationType.TC_MODIFY_STATE, (String) null);
     String[] cmdArray = exec.getPrivilegedOperationExecutionCommand(null, op);
 
     //No arguments added - so the resulting array should consist of
@@ -127,10 +127,8 @@ public class TestPrivilegedOperationExecutor {
     Assert.assertEquals(customExecutorPath, cmdArray[0]);
     Assert.assertEquals(op.getOperationType().getOption(), cmdArray[1]);
 
-    //other (dummy) arguments to launch container
-    String[] additionalArgs = { "test_user", "yarn", "1", "app_01",
-        "container_01", "workdir", "launch_script.sh", "tokens", "pidfile",
-        "nm-local-dirs", "nm-log-dirs", "resource-spec" };
+    //other (dummy) arguments to tc modify state
+    String[] additionalArgs = { "cmd_file_1", "cmd_file_2", "cmd_file_3"};
 
     op.appendArgs(additionalArgs);
     cmdArray = exec.getPrivilegedOperationExecutionCommand(null, op);

http://git-wip-us.apache.org/repos/asf/hadoop/blob/9da487e0/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
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..31ed496
--- /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/runtime/TestDockerContainerRuntime.java
@@ -0,0 +1,219 @@
+/*
+ * *
+ *  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.runtime;
+
+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.server.nodemanager.LocalDirsHandlerService;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation;
+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.runtime.ContainerExecutionException;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeConstants;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeContext;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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 Configuration conf;
+  PrivilegedOperationExecutor mockExecutor;
+  String containerId;
+  Container container;
+  ContainerId cId;
+  ContainerLaunchContext context;
+  HashMap<String, String> env;
+  String image;
+  String runAsUser;
+  String user;
+  String appId;
+  String containerIdStr = containerId;
+  Path containerWorkDir;
+  Path nmPrivateContainerScriptPath;
+  Path nmPrivateTokensPath;
+  Path pidFilePath;
+  List<String> localDirs;
+  List<String> logDirs;
+  String resourcesOptions;
+
+  @Before
+  public void setup() {
+    String tmpPath = new StringBuffer(System.getProperty("test.build.data"))
+        .append
+        ('/').append("hadoop.tmp.dir").toString();
+
+    conf = new Configuration();
+    conf.set("hadoop.tmp.dir", tmpPath);
+
+    mockExecutor = Mockito
+        .mock(PrivilegedOperationExecutor.class);
+    containerId = "container_id";
+    container = mock(Container.class);
+    cId = mock(ContainerId.class);
+    context = mock(ContainerLaunchContext.class);
+    env = new HashMap<String, String>();
+    image = "busybox:latest";
+
+    env.put(DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_IMAGE, image);
+    when(container.getContainerId()).thenReturn(cId);
+    when(cId.toString()).thenReturn(containerId);
+    when(container.getLaunchContext()).thenReturn(context);
+    when(context.getEnvironment()).thenReturn(env);
+
+    runAsUser = "run_as_user";
+    user = "user";
+    appId = "app_id";
+    containerIdStr = containerId;
+    containerWorkDir = new Path("/test_container_work_dir");
+    nmPrivateContainerScriptPath = new Path("/test_script_path");
+    nmPrivateTokensPath = new Path("/test_private_tokens_path");
+    pidFilePath = new Path("/test_pid_file_path");
+    localDirs = new ArrayList<>();
+    logDirs = new ArrayList<>();
+    resourcesOptions = "cgroups:none";
+
+    localDirs.add("/test_local_dir");
+    logDirs.add("/test_log_dir");
+  }
+
+  @Test
+  public void testSelectDockerContainerType() {
+    Map<String, String> envDockerType = new HashMap<>();
+    Map<String, String> envOtherType = new HashMap<>();
+
+    envDockerType.put(ContainerRuntimeConstants.ENV_CONTAINER_TYPE, "docker");
+    envOtherType.put(ContainerRuntimeConstants.ENV_CONTAINER_TYPE, "other");
+
+    Assert.assertEquals(false, DockerLinuxContainerRuntime
+        .isDockerContainerRequested(null));
+    Assert.assertEquals(true, DockerLinuxContainerRuntime
+        .isDockerContainerRequested(envDockerType));
+    Assert.assertEquals(false, DockerLinuxContainerRuntime
+        .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());
+
+    ArgumentCaptor<PrivilegedOperation> 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))
+        .executePrivilegedOperation(anyList(), opCaptor.capture(), any(
+            File.class), any(Map.class), eq(false));
+
+    PrivilegedOperation op = opCaptor.getValue();
+
+    Assert.assertEquals(PrivilegedOperation.OperationType
+        .LAUNCH_DOCKER_CONTAINER, op.getOperationType());
+
+    List<String> args = op.getArguments();
+
+    //This invocation of container-executor should use 13 arguments in a
+    // specific order (sigh.)
+    Assert.assertEquals(13, args.size());
+
+    //verify arguments
+    Assert.assertEquals(runAsUser, args.get(0));
+    Assert.assertEquals(user, args.get(1));
+    Assert.assertEquals(Integer.toString(PrivilegedOperation.RunAsUserCommand
+        .LAUNCH_DOCKER_CONTAINER.getValue()), args.get(2));
+    Assert.assertEquals(appId, args.get(3));
+    Assert.assertEquals(containerId, args.get(4));
+    Assert.assertEquals(containerWorkDir.toString(), args.get(5));
+    Assert.assertEquals(nmPrivateContainerScriptPath.toUri()
+            .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));
+
+    String dockerCommandFile = args.get(11);
+
+    //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("-v %4$s:%4$s ")
+        .append("-v %5$s:%5$s ")
+        .append("-v %6$s:%6$s ")
+        .append("%7$s ")
+        .append("bash %8$s/launch_container.sh");
+
+    String expectedCommand = String.format(expectedCommandTemplate.toString(),
+        containerId, runAsUser, containerWorkDir, localDirs.get(0),
+        containerWorkDir, logDirs.get(0), image, containerWorkDir);
+
+    List<String> dockerCommands = Files.readAllLines(Paths.get
+            (dockerCommandFile), Charset.forName("UTF-8"));
+
+    Assert.assertEquals(1, dockerCommands.size());
+    Assert.assertEquals(expectedCommand, dockerCommands.get(0));
+  }
+}