Job Specification Fields

This chapter specifies all of the possible fields for a job specification. Most, but not all, of these fields have an obvious mapping to job-spec fields.

image

This field must be an object as described below. It specifies the image field of the job spec.

The field can either be a string or an object. If it's a string, then it specifies the URI of the image to use, as documented here.

If it's an object, then it must have a string name field and it may have an optional use field. The name field specifies the URI of the image to use, as documented here.

The use fields must be a list of strings specifying what parts of the container image to use for the job spec. It must contain a non-empty subset of:

If no use field is provided, or if the first form is used where only a URI is specified, then the image will use the layers and environment from the image.

For example, the following three are identical job specifications:

{
        "image": {
                "name": "docker://ubuntu",
                "use": [ "layers", "environment" ]
        },
        "program": "echo",
        "arguments": [ "hello", "world" ]
}
{
        "image": { "name": "docker://ubuntu" },
        "program": "echo",
        "arguments": [ "hello", "world" ]
}
{
        "image": "docker://ubuntu",
        "program": "echo",
        "arguments": [ "hello", "world" ]
}

program

This field must be a string, and it specifies the program to be run. It sets the program field of the job spec. It must be provided.

arguments

This field must be a list of strings, and it specifies the program's arguments. It sets the arguments field of the job spec. If not provided, the job spec will have an empty arguments vector.

environment

This field sets the environment field of the job spec. If not provided, the job spec will have an empty environment vectors.

This field can be specified in one of two ways: implicit mode and explicit mode.

Implicit Mode

In this mode, a JSON map from string to string is expected. The job spec will have a single element in it, with the provided map. This is usually what you want.

% BAR=bar maelstrom-run --one
{
        "image": {
                "name": "docker://ubuntu",
                "use": [ "layers" ]
        },
        "program": "/usr/bin/env",
        "environment": {
                "FOO": "foo",
                "BAR": "$env{BAR}"
        }
}
BAR=bar
FOO=foo
%

This mode is incompatible with a use of environment in the image. It's ambiguous whether the desired environment is the one provided with environment or the one from the image:

% maelstrom-run --one
{
        "image": {
                "name": "docker://ubuntu",
                "use": [ "layers", "environment" ]
        },
        "program": "/usr/bin/env",
        "environment": {
                "FOO": "foo",
                "BAR": "bar"
        }
}
Error: field `environment` must provide `extend` flags if [`image` with a `use`
of `environment`](#image-use-environment) is also set at line 11 column 1
%

Explicit Mode

In this mode, a list of EnvironmentSpec is provided, and they are used verbatim in the job spec.

For example:

% BAR=bar maelstrom-run --one
{
        "image": {
                "name": "docker://ubuntu",
                "use": [ "layers", "environment" ]
        },
        "program": "/usr/bin/env",
        "environment": [
                { "vars": { "PATH": "$prev{PATH}", "FOO": "foo" }, "extend": false },
                { "vars": { "BAR": "$env{BAR}" }, "extend": true }
        ]
}
BAR=bar
FOO=foo
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
%

layers

This field sets the layers field of the job spec. Either this field, or an image with a use of layers must be provided, but not both.

To add additional layers beyond those provided by an image, use added_layers.

Here is an example of specifying layers:

% wget -O busybox https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox
...
% chmod +x ./busybox
% maelstrom-run --one
{
        "layers": [
                { "paths": [ "busybox" ] },
                { "symlinks": [{ "link": "/ls", "target": "/busybox" }] }
        ],
        "program": "/ls"
}
busybox
ls
%

added_layers

This is just like layers, except is can only be used with an image that has a use of layers. The provided layers will be append to the layers provided by the image when creating the job spec.

Here's an example:

% maelstrom-run --one
{
        "image": "docker://ubuntu",
        "added_layers": [
                { "stubs": [ "/foo/{bar,baz}" ] }
        ],
        "program": "/bin/ls",
        "arguments": [ "/foo" ]
}
bar
baz
%

mounts

This field sets the mounts field of the job spec. If this field isn't specified, an empty mounts will be set in the job spec.

The field must be a list of objects, where the format is the direct JSON translation of the corresponding job-spec type.

For example:

% maelstrom-run
{
        "image": "docker://ubuntu",
        "added_layers": [
                { "stubs": [ "/dev/{null,zero}" ] }
        ],
        "mounts": [
                { "type": "proc", "mount_point": "/proc" },
                { "type": "tmp", "mount_point": "/tmp" },
                { "type": "devices", "devices": [ "null", "zero" ] }
        ],
        "program": "mount"
}
Maelstrom LayerFS on / type fuse (ro,nosuid,nodev,relatime,user_id=0,group_id=0)
none on /proc type proc (rw,relatime)
none on /tmp type tmpfs (rw,relatime,uid=1000,gid=1000,inode64)
udev on /dev/null type devtmpfs (rw,nosuid,relatime,size=8087700k,nr_inodes=2021925,mode=755,inode64)
udev on /dev/zero type devtmpfs (rw,nosuid,relatime,size=8087700k,nr_inodes=2021925,mode=755,inode64)
%

Bind mounts can be used to transfer data out of the job:

% touch output
% cat output
% maelstrom-run --one
{
        "image": "docker://ubuntu",
        "added_layers": [
                { "stubs": [ "/output" ] }
        ],
        "mounts": [
                {
                        "type": "bind",
                        "mount_point": "/output",
                        "local_path": "output",
                        "read_only": false
                }
        ],
        "program": "bash",
        "arguments": [ "-c", "echo foo >output" ]
}
% cat output
foo
%

network

This field must be a string with a value of one: "disabled", "loopback", "local". It sets the network field of the job spec to the provided value. If this field isn't provided, the default of "disabled" is used.

enable_writable_file_system

This field must be a boolean value. If it's true, it sets the root_overlay field of the job spec to Tmp. If it's not specified, or is set to false, the [root_overlay] field will be None.

working_directory

This field must be a string, and it specifies the working directory of the program be run. It sets the working_directory field of the job spec. If not provided, / will be used.

This field is incompatible with an image that has a use of working_directory.

For example:

% maelstrom-run --one
{
        "image": "docker://ubuntu",
        "program": "pwd"
}
/
% maelstrom-run --one
{
        "image": "docker://ubuntu",
        "program": "pwd",
        "working_directory": "/root"
}
/root
%

user

This field must be an integer, and it specifies the UID of the program to be run. It sets the user field of the job spec. If not provided, 0 will be used.

For example:

% maelstrom-run --one
{
        "image": "docker://ubuntu",
        "program": "id"
}
uid=0(root) gid=0(root) groups=0(root),65534(nogroup)
% maelstrom-run --one
{
        "image": "docker://ubuntu",
        "program": "id",
        "user": 1234
}
uid=1234 gid=0(root) groups=0(root),65534(nogroup)
%

group

This field must be an integer, and it specifies the UID of the program to be run. It sets the group field of the job spec. If not provided, 0 will be used.

For example:

% maelstrom-run --one
{
        "image": "docker://ubuntu",
        "program": "id"
}
uid=0(root) gid=0(root) groups=0(root),65534(nogroup)
% maelstrom-run --one
{
        "image": "docker://ubuntu",
        "program": "id",
        "group": 4321
}
uid=0(root) gid=4321 groups=4321,65534(nogroup)
%

timeout

This field must be an integers, and it specifies a timeout for the job in seconds. It sets the timeout field of the job spec. If not provided, the job will have no timeout.

For example:

% maelstrom-run --one
{
        "image": "docker://ubuntu",
        "program": "sleep",
        "arguments": [ "1d" ],
        "timeout": 1
}
timed out
%