diff --git a/client/driver/docker.go b/client/driver/docker.go index 9ce049e09..50cae7059 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -35,15 +35,16 @@ type DockerAuthConfig struct { type DockerDriverConfig struct { DockerAuthConfig - ImageName string `mapstructure:"image"` // Container's Image Name - Command string `mapstructure:"command"` // The Command/Entrypoint to run when the container starts up - Args string `mapstructure:"args"` // The arguments to the Command/Entrypoint - NetworkMode string `mapstructure:"network_mode"` // The network mode of the container - host, net and none - PortMap []map[string]int `mapstructure:"port_map"` // A map of host port labels and the ports exposed on the container - Privileged bool `mapstructure:"privileged"` // Flag to run the container in priviledged mode - DNS string `mapstructure:"dns_server"` // DNS Server for containers - SearchDomains string `mapstructure:"search_domains"` // DNS Search domains for containers - Hostname string `mapstructure:"hostname"` // Hostname for containers + ImageName string `mapstructure:"image"` // Container's Image Name + Command string `mapstructure:"command"` // The Command/Entrypoint to run when the container starts up + Args string `mapstructure:"args"` // The arguments to the Command/Entrypoint + NetworkMode string `mapstructure:"network_mode"` // The network mode of the container - host, net and none + PortMap []map[string]int `mapstructure:"port_map"` // A map of host port labels and the ports exposed on the container + Privileged bool `mapstructure:"privileged"` // Flag to run the container in priviledged mode + DNS string `mapstructure:"dns_server"` // DNS Server for containers + SearchDomains string `mapstructure:"search_domains"` // DNS Search domains for containers + Hostname string `mapstructure:"hostname"` // Hostname for containers + Labels []map[string]string `mapstructure:"labels"` // Labels to set when the container starts up } func (c *DockerDriverConfig) Validate() error { @@ -54,6 +55,10 @@ func (c *DockerDriverConfig) Validate() error { if len(c.PortMap) > 1 { return fmt.Errorf("Only one port_map block is allowed in the docker driver config") } + + if len(c.Labels) > 1 { + return fmt.Errorf("Only one labels block is allowed in the docker driver config") + } return nil } @@ -323,6 +328,11 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, dri d.logger.Println("[DEBUG] driver.docker: ignoring args because command not specified") } + if len(driverConfig.Labels) == 1 { + config.Labels = driverConfig.Labels[0] + d.logger.Println("[DEBUG] driver.docker: applied labels on the container") + } + config.Env = env.List() return docker.CreateContainerOptions{ Name: fmt.Sprintf("%s-%s", task.Name, ctx.AllocID), diff --git a/client/driver/docker_test.go b/client/driver/docker_test.go index 87bb58e6f..05df5a647 100644 --- a/client/driver/docker_test.go +++ b/client/driver/docker_test.go @@ -1,10 +1,12 @@ package driver import ( + "encoding/json" "fmt" "io/ioutil" "path/filepath" "reflect" + "strings" "testing" "time" @@ -433,3 +435,58 @@ func TestDockerHostNet(t *testing.T) { } defer handle.Kill() } + +func TestDockerLabels(t *testing.T) { + if !dockerIsConnected(t) { + t.SkipNow() + } + + task := taskTemplate() + task.Config["labels"] = []map[string]string{ + map[string]string{ + "label1": "value1", + "label2": "value2", + }, + } + + driverCtx := testDockerDriverContext(task.Name) + ctx := testDriverExecContext(task, driverCtx) + defer ctx.AllocDir.Destroy() + d := NewDockerDriver(driverCtx) + + handle, err := d.Start(ctx, task) + if err != nil { + t.Fatalf("err: %v", err) + } + if handle == nil { + t.Fatalf("missing handle") + } + + client, err := docker.NewClientFromEnv() + if err != nil { + t.Fatalf("err: %v", err) + } + + // don't know if is queriable in a clean way + parts := strings.SplitN(handle.ID(), ":", 2) + var pid dockerPID + err = json.Unmarshal([]byte(parts[1]), &pid) + if err != nil { + t.Fatalf("err: %v", err) + } + + container, err := client.InspectContainer(pid.ContainerID) + if err != nil { + t.Fatalf("err: %v", err) + } + + if want, got := 2, len(container.Config.Labels); want != got { + t.Errorf("Wrong labels count for docker job. Expect: %d, got: %d", want, got) + } + + if want, got := "value1", container.Config.Labels["label1"]; want != got { + t.Errorf("Wrong label value docker job. Expect: %s, got: %s", want, got) + } + + defer handle.Kill() +} diff --git a/website/source/docs/drivers/docker.html.md b/website/source/docs/drivers/docker.html.md index 623cdd6b4..8d4abd035 100644 --- a/website/source/docs/drivers/docker.html.md +++ b/website/source/docs/drivers/docker.html.md @@ -32,29 +32,32 @@ The `docker` driver supports the following configuration in the job specificatio network mode is not supported right now and is reported as an invalid option. -* `privileged` - (optional) Privileged mode gives the container full access to +* `privileged` - (Optional) Privileged mode gives the container full access to the host. Valid options are `"true"` and `"false"` (defaults to `"false"`). Tasks with `privileged` set can only run on Nomad Agents with `docker.privileged.enabled = "true"`. -* `dns-servers` - (optional) A comma separated list of DNS servers for the container +* `dns-servers` - (Optional) A comma separated list of DNS servers for the container to use (e.g. "8.8.8.8,8.8.4.4"). *Docker API v1.10 and above only* -* `search-domains` - (optional) A comma separated list of DNS search domains for the +* `search-domains` - (Optional) A comma separated list of DNS search domains for the container to use. * `hostname` - (optional) The hostname to assign to the container. When launching more than one of a task (using `count`) with this option set, every container the task starts will have the same hostname. - + +* `labels` - (Optional) A key/value map of labels to set to the containers on start. + + **Authentication** -Registry authentication can be set per task with the following authentication -parameters. These options can provide access to private repositories that +Registry authentication can be set per task with the following authentication +parameters. These options can provide access to private repositories that utilize the docker remote api (e.g. dockerhub, quay.io) - - `auth.username` - (optional) The account username - - `auth.password` - (optional) The account password - - `auth.email` - (optional) The account email - - `auth.server-address` - (optional) The server domain/ip without the protocol + - `auth.username` - (Optional) The account username + - `auth.password` - (Optional) The account password + - `auth.email` - (Optional) The account email + - `auth.server-address` - (Optional) The server domain/ip without the protocol ### Port Mapping