From 63439ee3f72010c7f6ac60934b5b823bf5863a72 Mon Sep 17 00:00:00 2001 From: Chris Bednarski Date: Thu, 19 Nov 2015 21:29:37 -0800 Subject: [PATCH] Squash []map[string]type for port_map and labels into map[string]type --- client/driver/docker.go | 38 +++++++++++----------------- client/driver/docker_test.go | 7 +++--- client/driver/driver.go | 20 +++++++++++++++ client/driver/driver_test.go | 48 ++++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 26 deletions(-) diff --git a/client/driver/docker.go b/client/driver/docker.go index 24da5dcad..f09d04021 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -37,12 +37,14 @@ type DockerDriverConfig struct { 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 + PortMapRaw []map[string]int `mapstructure:"port_map"` // + PortMap map[string]int `mapstructure:"-"` // 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 DNSServers []string `mapstructure:"dns_servers"` // DNS Server for containers DNSSearchDomains []string `mapstructure:"dns_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 + LabelsRaw []map[string]string `mapstructure:"labels"` // + Labels map[string]string `mapstructure:"-"` // Labels to set when the container starts up Auth []DockerDriverAuth `mapstructure:"auth"` // Authentication credentials for a private Docker registry } @@ -51,13 +53,9 @@ func (c *DockerDriverConfig) Validate() error { return fmt.Errorf("Docker Driver needs an image name") } - if len(c.PortMap) > 1 { - return fmt.Errorf("Only one port_map block is allowed in the docker driver config") - } + c.PortMap = mapMergeStrInt(c.PortMapRaw...) + c.Labels = mapMergeStrStr(c.LabelsRaw...) - if len(c.Labels) > 1 { - return fmt.Errorf("Only one labels block is allowed in the docker driver config") - } return nil } @@ -239,7 +237,7 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, dri // Setup port mapping and exposed ports if len(task.Resources.Networks) == 0 { d.logger.Println("[DEBUG] driver.docker: No network interfaces are available") - if len(driverConfig.PortMap) == 1 && len(driverConfig.PortMap[0]) > 0 { + if len(driverConfig.PortMap) > 0 { return c, fmt.Errorf("Trying to map ports but no network interface is available") } } else { @@ -253,11 +251,8 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, dri containerPortInt := port.Value // If the user has mapped a port using port_map we'll change it here - if len(driverConfig.PortMap) == 1 { - mapped, ok := driverConfig.PortMap[0][port.Label] - if ok { - containerPortInt = mapped - } + if mapped, ok := driverConfig.PortMap[port.Label]; ok { + containerPortInt = mapped } hostPortStr := strconv.Itoa(port.Value) @@ -277,11 +272,8 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, dri containerPortInt := port.Value // If the user has mapped a port using port_map we'll change it here - if len(driverConfig.PortMap) == 1 { - mapped, ok := driverConfig.PortMap[0][port.Label] - if ok { - containerPortInt = mapped - } + if mapped, ok := driverConfig.PortMap[port.Label]; ok { + containerPortInt = mapped } hostPortStr := strconv.Itoa(port.Value) @@ -302,8 +294,8 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, dri // TODO refactor the implementation in TaskEnvironmentVariables to match // the 0.2 ports world view. Docker seems to be the only place where // this is actually needed, but this is kinda hacky. - if len(driverConfig.PortMap) == 1 { - env.SetPorts(network.MapLabelToValues(driverConfig.PortMap[0])) + if len(driverConfig.PortMap) > 0 { + env.SetPorts(network.MapLabelToValues(driverConfig.PortMap)) } hostConfig.PortBindings = publishedPorts config.ExposedPorts = exposedPorts @@ -324,8 +316,8 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, dri d.logger.Println("[DEBUG] driver.docker: ignoring command arguments because command is not specified") } - if len(driverConfig.Labels) == 1 { - config.Labels = driverConfig.Labels[0] + if len(driverConfig.Labels) > 0 { + config.Labels = driverConfig.Labels d.logger.Printf("[DEBUG] driver.docker: applied labels on the container: %+v", config.Labels) } diff --git a/client/driver/docker_test.go b/client/driver/docker_test.go index 219f15d38..f37bc6bc8 100644 --- a/client/driver/docker_test.go +++ b/client/driver/docker_test.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "path/filepath" "reflect" + "runtime/debug" "testing" "time" @@ -92,7 +93,7 @@ func dockerSetup(t *testing.T, task *structs.Task) (*docker.Client, DriverHandle client, err := docker.NewClientFromEnv() if err != nil { - t.Fatalf("err: %v", err) + t.Fatalf("Failed to initialize client: %s\nStack\n%s", err, debug.Stack()) } driverCtx := testDockerDriverContext(task.Name) @@ -102,11 +103,11 @@ func dockerSetup(t *testing.T, task *structs.Task) (*docker.Client, DriverHandle handle, err := driver.Start(ctx, task) if err != nil { ctx.AllocDir.Destroy() - t.Fatalf("err: %v", err) + t.Fatalf("Failed to start driver: %s\nStack\n%s", err, debug.Stack()) } if handle == nil { ctx.AllocDir.Destroy() - t.Fatalf("missing handle") + t.Fatalf("handle is nil\nStack\n%s", debug.Stack()) } cleanup := func() { diff --git a/client/driver/driver.go b/client/driver/driver.go index 1eedd8392..a82847f4c 100644 --- a/client/driver/driver.go +++ b/client/driver/driver.go @@ -145,3 +145,23 @@ func TaskEnvironmentVariables(ctx *ExecContext, task *structs.Task) environment. return env } + +func mapMergeStrInt(maps ...map[string]int) map[string]int { + out := map[string]int{} + for _, in := range maps { + for key, val := range in { + out[key] = val + } + } + return out +} + +func mapMergeStrStr(maps ...map[string]string) map[string]string { + out := map[string]string{} + for _, in := range maps { + for key, val := range in { + out[key] = val + } + } + return out +} diff --git a/client/driver/driver_test.go b/client/driver/driver_test.go index fd4f30569..dccd91d7f 100644 --- a/client/driver/driver_test.go +++ b/client/driver/driver_test.go @@ -99,3 +99,51 @@ func TestDriver_TaskEnvironmentVariables(t *testing.T) { t.Fatalf("TaskEnvironmentVariables(%#v, %#v) returned %#v; want %#v", ctx, task, act, exp) } } + +func TestMapMergeStrInt(t *testing.T) { + a := map[string]int{ + "cakes": 5, + "cookies": 3, + } + + b := map[string]int{ + "cakes": 3, + "pies": 2, + } + + c := mapMergeStrInt(a, b) + + d := map[string]int{ + "cakes": 3, + "cookies": 3, + "pies": 2, + } + + if !reflect.DeepEqual(c, d) { + t.Errorf("\nExpected\n%+v\nGot\n%+v\n", d, c) + } +} + +func TestMapMergeStrStr(t *testing.T) { + a := map[string]string{ + "cake": "chocolate", + "cookie": "caramel", + } + + b := map[string]string{ + "cake": "strawberry", + "pie": "apple", + } + + c := mapMergeStrStr(a, b) + + d := map[string]string{ + "cake": "strawberry", + "cookie": "caramel", + "pie": "apple", + } + + if !reflect.DeepEqual(c, d) { + t.Errorf("\nExpected\n%+v\nGot\n%+v\n", d, c) + } +}