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,