Repository: aurora
Updated Branches:
  refs/heads/master 8bdfb8500 -> b002e4223


Add support for arbitrary Docker parameters.

Reviewed at https://reviews.apache.org/r/34337/


Project: http://git-wip-us.apache.org/repos/asf/aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/b002e422
Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/b002e422
Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/b002e422

Branch: refs/heads/master
Commit: b002e42233b2ebc2618063b05a97b4f89da6baf2
Parents: 8bdfb85
Author: Mauricio Garavaglia <mauriciogaravag...@gmail.com>
Authored: Wed Jul 22 15:40:13 2015 -0700
Committer: Bill Farner <wfar...@apache.org>
Committed: Wed Jul 22 15:40:13 2015 -0700

----------------------------------------------------------------------
 .../thrift/org/apache/aurora/gen/api.thrift     | 10 +++++++
 docs/configuration-reference.md                 | 17 +++++++++--
 .../configuration/ConfigurationManager.java     | 15 ++++++++--
 .../scheduler/mesos/MesosTaskFactory.java       | 14 +++++++--
 .../python/apache/aurora/config/schema/base.py  |  4 +++
 src/main/python/apache/aurora/config/thrift.py  |  7 ++++-
 .../mesos/MesosTaskFactoryImplTest.java         | 31 +++++++++++++++++---
 .../python/apache/aurora/config/test_thrift.py  | 19 +++++++++++-
 8 files changed, 104 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/aurora/blob/b002e422/api/src/main/thrift/org/apache/aurora/gen/api.thrift
----------------------------------------------------------------------
diff --git a/api/src/main/thrift/org/apache/aurora/gen/api.thrift 
b/api/src/main/thrift/org/apache/aurora/gen/api.thrift
index d740a90..f792be0 100644
--- a/api/src/main/thrift/org/apache/aurora/gen/api.thrift
+++ b/api/src/main/thrift/org/apache/aurora/gen/api.thrift
@@ -208,10 +208,20 @@ struct Volume {
 struct MesosContainer {
 }
 
+/** Describes a parameter passed to docker cli */
+struct DockerParameter {
+  /** a parameter to pass to docker. (e.g. volume) */
+  1: string name
+  /** the value to pass to a parameter (e.g. /src/webapp:/opt/webapp) */
+  2: string value
+}
+
 /** Describes a docker container */
 struct DockerContainer {
   /** The container image to be run */
   1: string image
+  /** The arbitrary parameters to pass to container */
+  2: optional list<DockerParameter> parameters
 }
 
 /** Describes a container to be used in a task */

http://git-wip-us.apache.org/repos/asf/aurora/blob/b002e422/docs/configuration-reference.md
----------------------------------------------------------------------
diff --git a/docs/configuration-reference.md b/docs/configuration-reference.md
index dafd306..ad2701c 100644
--- a/docs/configuration-reference.md
+++ b/docs/configuration-reference.md
@@ -417,9 +417,20 @@ Describes the container the job's processes will run 
inside.
 
 ### Docker Object
 
-  param          | type           | description
-  -----          | :----:         | -----------
-  ```image```    | String         | The name of the docker image to execute.  
If the image does not exist locally it will be pulled with ```docker pull```.
+  param            | type            | description
+  -----            | :----:          | -----------
+  ```image```      | String          | The name of the docker image to 
execute.  If the image does not exist locally it will be pulled with ```docker 
pull```.
+  ```parameters``` | List(Parameter) | Additional parameters to pass to the 
docker containerizer.
+
+### Docker Parameter Object
+
+Docker CLI parameters. This needs to be enabled by the scheduler 
`enable_docker_parameters` option.
+See [Docker Command Line 
Reference](https://docs.docker.com/reference/commandline/run/) for valid 
parameters. 
+
+  param            | type            | description
+  -----            | :----:          | -----------
+  ```name```       | String          | The name of the docker parameter. E.g. 
volume
+  ```value```      | String          | The value of the parameter. E.g. 
/usr/local/bin:/usr/bin:rw
 
 ### LifecycleConfig Objects
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/b002e422/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
 
b/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
index be79e70..d103d19 100644
--- 
a/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
+++ 
b/src/main/java/org/apache/aurora/scheduler/configuration/ConfigurationManager.java
@@ -63,6 +63,10 @@ public final class ConfigurationManager {
   private static final Arg<List<Container._Fields>> ALLOWED_CONTAINER_TYPES =
       Arg.create(ImmutableList.of(Container._Fields.MESOS));
 
+  @CmdLine(name = "allow_docker_parameters",
+      help = "Allow to pass docker container parameters in the job.")
+  private static final Arg<Boolean> ENABLE_DOCKER_PARAMETERS = 
Arg.create(false);
+
   public static final String DEDICATED_ATTRIBUTE = "dedicated";
 
   private static final Pattern GOOD_IDENTIFIER = 
Pattern.compile(GOOD_IDENTIFIER_PATTERN_JVM);
@@ -336,8 +340,15 @@ public final class ConfigurationManager {
     if (config.isSetContainer()) {
       IContainer containerConfig = config.getContainer();
       containerType = Optional.of(containerConfig.getSetField());
-      if (containerConfig.isSetDocker() && 
!containerConfig.getDocker().isSetImage()) {
-        throw new TaskDescriptionException("A container must specify an 
image");
+      if (containerConfig.isSetDocker()) {
+        if (!containerConfig.getDocker().isSetImage()) {
+          throw new TaskDescriptionException("A container must specify an 
image");
+        }
+        if (containerConfig.getDocker().isSetParameters()
+            && !containerConfig.getDocker().getParameters().isEmpty()
+            && !ENABLE_DOCKER_PARAMETERS.get()) {
+          throw new TaskDescriptionException("Docker parameters not allowed.");
+        }
       }
     } else {
       // Default to mesos container type if unset.

http://git-wip-us.apache.org/repos/asf/aurora/blob/b002e422/src/main/java/org/apache/aurora/scheduler/mesos/MesosTaskFactory.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/aurora/scheduler/mesos/MesosTaskFactory.java 
b/src/main/java/org/apache/aurora/scheduler/mesos/MesosTaskFactory.java
index c0d165a..c91c0ea 100644
--- a/src/main/java/org/apache/aurora/scheduler/mesos/MesosTaskFactory.java
+++ b/src/main/java/org/apache/aurora/scheduler/mesos/MesosTaskFactory.java
@@ -23,6 +23,7 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.protobuf.ByteString;
+import com.twitter.common.base.Function;
 import com.twitter.common.quantity.Amount;
 import com.twitter.common.quantity.Data;
 
@@ -36,8 +37,10 @@ import org.apache.aurora.scheduler.base.Tasks;
 import org.apache.aurora.scheduler.configuration.Resources;
 import org.apache.aurora.scheduler.storage.entities.IAssignedTask;
 import org.apache.aurora.scheduler.storage.entities.IDockerContainer;
+import org.apache.aurora.scheduler.storage.entities.IDockerParameter;
 import org.apache.aurora.scheduler.storage.entities.IJobKey;
 import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
+import org.apache.mesos.Protos;
 import org.apache.mesos.Protos.CommandInfo;
 import org.apache.mesos.Protos.ContainerInfo;
 import org.apache.mesos.Protos.ExecutorID;
@@ -180,9 +183,16 @@ public interface MesosTaskFactory {
         TaskInfo.Builder taskBuilder) {
 
       IDockerContainer config = taskConfig.getContainer().getDocker();
-      ContainerInfo.DockerInfo.Builder dockerBuilder = 
ContainerInfo.DockerInfo.newBuilder()
-          .setImage(config.getImage());
+      Iterable<Protos.Parameter> parameters = 
Iterables.transform(config.getParameters(),
+          new Function<IDockerParameter, Protos.Parameter>() {
+            @Override public Protos.Parameter apply(IDockerParameter item) {
+              return Protos.Parameter.newBuilder().setKey(item.getName())
+                .setValue(item.getValue()).build();
+            }
+          });
 
+      ContainerInfo.DockerInfo.Builder dockerBuilder = 
ContainerInfo.DockerInfo.newBuilder()
+          .setImage(config.getImage()).addAllParameters(parameters);
       ContainerInfo.Builder containerBuilder = ContainerInfo.newBuilder()
           .setType(ContainerInfo.Type.DOCKER)
           .setDocker(dockerBuilder.build());

http://git-wip-us.apache.org/repos/asf/aurora/blob/b002e422/src/main/python/apache/aurora/config/schema/base.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/config/schema/base.py 
b/src/main/python/apache/aurora/config/schema/base.py
index d1f1e4f..214d559 100644
--- a/src/main/python/apache/aurora/config/schema/base.py
+++ b/src/main/python/apache/aurora/config/schema/base.py
@@ -88,9 +88,13 @@ class MesosTaskInstance(Struct):
   health_check_config = Default(HealthCheckConfig, HealthCheckConfig())
   lifecycle           = LifecycleConfig
 
+class Parameter(Struct):
+  name = Required(String)
+  value = Required(String)
 
 class Docker(Struct):
   image = Required(String)
+  parameters = Default(List(Parameter), [])
 
 
 class Container(Struct):

http://git-wip-us.apache.org/repos/asf/aurora/blob/b002e422/src/main/python/apache/aurora/config/thrift.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/config/thrift.py 
b/src/main/python/apache/aurora/config/thrift.py
index 88dd1c7..adf53bb 100644
--- a/src/main/python/apache/aurora/config/thrift.py
+++ b/src/main/python/apache/aurora/config/thrift.py
@@ -27,6 +27,7 @@ from gen.apache.aurora.api.ttypes import (
     Container,
     CronCollisionPolicy,
     DockerContainer,
+    DockerParameter,
     ExecutorConfig,
     Identity,
     JobConfiguration,
@@ -129,7 +130,11 @@ def create_container_config(container):
   if container is Empty:
     return Container(MesosContainer(), None)
   elif container.docker() is not Empty:
-    return Container(None, 
DockerContainer(fully_interpolated(container.docker().image())))
+    params = list()
+    if container.docker().parameters() is not Empty:
+      for p in fully_interpolated(container.docker().parameters()):
+        params.append(DockerParameter(p['name'], p['value']))
+    return Container(None, 
DockerContainer(fully_interpolated(container.docker().image()), params))
   else:
     raise InvalidConfig('If a container is specified it must set one type.')
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/b002e422/src/test/java/org/apache/aurora/scheduler/mesos/MesosTaskFactoryImplTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/aurora/scheduler/mesos/MesosTaskFactoryImplTest.java 
b/src/test/java/org/apache/aurora/scheduler/mesos/MesosTaskFactoryImplTest.java
index c0cadfb..7f18bbc 100644
--- 
a/src/test/java/org/apache/aurora/scheduler/mesos/MesosTaskFactoryImplTest.java
+++ 
b/src/test/java/org/apache/aurora/scheduler/mesos/MesosTaskFactoryImplTest.java
@@ -21,6 +21,7 @@ import com.twitter.common.quantity.Data;
 import org.apache.aurora.gen.AssignedTask;
 import org.apache.aurora.gen.Container;
 import org.apache.aurora.gen.DockerContainer;
+import org.apache.aurora.gen.DockerParameter;
 import org.apache.aurora.gen.Identity;
 import org.apache.aurora.gen.JobKey;
 import org.apache.aurora.gen.MesosContainer;
@@ -35,7 +36,9 @@ import 
org.apache.aurora.scheduler.storage.entities.ITaskConfig;
 import org.apache.mesos.Protos;
 import org.apache.mesos.Protos.CommandInfo;
 import org.apache.mesos.Protos.CommandInfo.URI;
+import org.apache.mesos.Protos.ContainerInfo.DockerInfo;
 import org.apache.mesos.Protos.ExecutorInfo;
+import org.apache.mesos.Protos.Parameter;
 import org.apache.mesos.Protos.SlaveID;
 import org.apache.mesos.Protos.TaskInfo;
 import org.junit.Before;
@@ -67,7 +70,14 @@ public class MesosTaskFactoryImplTest {
   private static final IAssignedTask TASK_WITH_DOCKER = 
IAssignedTask.build(TASK.newBuilder()
       .setTask(
           new TaskConfig(TASK.getTask().newBuilder())
-              .setContainer(Container.docker(new 
DockerContainer("testimage")))));
+              .setContainer(Container.docker(
+                      new DockerContainer("testimage")))));
+  private static final IAssignedTask TASK_WITH_DOCKER_PARAMS = 
IAssignedTask.build(TASK.newBuilder()
+      .setTask(
+          new TaskConfig(TASK.getTask().newBuilder())
+              .setContainer(Container.docker(
+                  new DockerContainer("testimage").setParameters(
+                      ImmutableList.of(new DockerParameter("label", 
"testparameter")))))));
 
   private static final SlaveID SLAVE = 
SlaveID.newBuilder().setValue("slave-id").build();
 
@@ -161,15 +171,28 @@ public class MesosTaskFactoryImplTest {
   }
 
   private TaskInfo getDockerTaskInfo() {
+    return getDockerTaskInfo(TASK_WITH_DOCKER);
+  }
+
+  private TaskInfo getDockerTaskInfo(IAssignedTask task) {
     config = TaskExecutors.SOME_OVERHEAD_EXECUTOR;
     taskFactory = new MesosTaskFactoryImpl(config);
-    return taskFactory.createFrom(TASK_WITH_DOCKER, SLAVE);
+    return taskFactory.createFrom(task, SLAVE);
   }
 
   @Test
   public void testDockerContainer() {
-    TaskInfo task = getDockerTaskInfo();
-    assertEquals("testimage", 
task.getExecutor().getContainer().getDocker().getImage());
+    DockerInfo docker = 
getDockerTaskInfo().getExecutor().getContainer().getDocker();
+    assertEquals("testimage", docker.getImage());
+    assertTrue(docker.getParametersList().isEmpty());
+  }
+
+  @Test
+  public void testDockerContainerWithParameters() {
+    DockerInfo docker = 
getDockerTaskInfo(TASK_WITH_DOCKER_PARAMS).getExecutor().getContainer()
+            .getDocker();
+    Parameter parameters = 
Parameter.newBuilder().setKey("label").setValue("testparameter").build();
+    assertEquals(ImmutableList.of(parameters), docker.getParametersList());
   }
 
   @Test(expected = NullPointerException.class)

http://git-wip-us.apache.org/repos/asf/aurora/blob/b002e422/src/test/python/apache/aurora/config/test_thrift.py
----------------------------------------------------------------------
diff --git a/src/test/python/apache/aurora/config/test_thrift.py 
b/src/test/python/apache/aurora/config/test_thrift.py
index f48ac88..061864e 100644
--- a/src/test/python/apache/aurora/config/test_thrift.py
+++ b/src/test/python/apache/aurora/config/test_thrift.py
@@ -18,7 +18,14 @@ import re
 import pytest
 
 from apache.aurora.config import AuroraConfig
-from apache.aurora.config.schema.base import HealthCheckConfig, Job, SimpleTask
+from apache.aurora.config.schema.base import (
+    Container,
+    Docker,
+    HealthCheckConfig,
+    Job,
+    Parameter,
+    SimpleTask
+)
 from apache.aurora.config.thrift import convert as convert_pystachio_to_thrift
 from apache.aurora.config.thrift import InvalidConfig, task_instance_from_job
 from apache.thermos.config.schema import Process, Resources, Task
@@ -66,6 +73,16 @@ def test_simple_config():
   assert tti.environment == HELLO_WORLD.environment().get()
 
 
+def test_docker_with_parameters():
+  helloworld = HELLO_WORLD(
+    container=Container(
+      docker=Docker(image='test_image', parameters=[Parameter(name='foo', 
value='bar')])
+    )
+  )
+  job = convert_pystachio_to_thrift(helloworld)
+  assert job.taskConfig.container.docker.image == 'test_image'
+
+
 def test_config_with_options():
   hwc = HELLO_WORLD(
     production=True,

Reply via email to