diff --git a/local/backend.go b/local/backend.go index 05e84a88a..6fb82871d 100644 --- a/local/backend.go +++ b/local/backend.go @@ -21,10 +21,7 @@ package local import ( "bufio" "context" - "fmt" "io" - "sort" - "strconv" "strings" "time" @@ -33,7 +30,6 @@ import ( "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" "github.com/docker/docker/pkg/stringid" - "github.com/docker/go-connections/nat" "github.com/pkg/errors" "github.com/docker/compose-cli/api/compose" @@ -102,8 +98,8 @@ func (ms *local) Inspect(ctx context.Context, id string) (containers.Container, command = strings.Join(c.Config.Cmd, " ") } - rc := containerJSONToRuntimeConfig(&c) - hc := containerJSONToHostConfig(&c) + rc := toRuntimeConfig(&c) + hc := toHostConfig(&c) return containers.Container{ ID: stringid.TruncateID(c.ID), @@ -116,66 +112,6 @@ func (ms *local) Inspect(ctx context.Context, id string) (containers.Container, }, nil } -func containerJSONToRuntimeConfig(m *types.ContainerJSON) *containers.RuntimeConfig { - if m.Config == nil { - return nil - } - var env map[string]string - if m.Config.Env != nil { - env = make(map[string]string) - for _, e := range m.Config.Env { - tokens := strings.Split(e, "=") - if len(tokens) != 2 { - continue - } - env[tokens[0]] = tokens[1] - } - } - - var labels []string - if m.Config.Labels != nil { - for k, v := range m.Config.Labels { - labels = append(labels, fmt.Sprintf("%s=%s", k, v)) - } - } - sort.Strings(labels) - - if env == nil && - labels == nil { - return nil - } - - return &containers.RuntimeConfig{ - Env: env, - Labels: labels, - } -} - -func containerJSONToHostConfig(m *types.ContainerJSON) *containers.HostConfig { - if m.HostConfig == nil { - return nil - } - - var restartPolicy string - switch m.HostConfig.RestartPolicy.Name { - case "always": - restartPolicy = containers.RestartPolicyAny - case "on-failure": - restartPolicy = containers.RestartPolicyOnFailure - case "no", "": - fallthrough - default: - restartPolicy = containers.RestartPolicyNone - } - - return &containers.HostConfig{ - AutoRemove: m.HostConfig.AutoRemove, - RestartPolicy: restartPolicy, - CPULimit: float64(m.HostConfig.Resources.NanoCPUs) / 1e9, - MemoryLimit: uint64(m.HostConfig.Resources.Memory), - } -} - func (ms *local) List(ctx context.Context, all bool) ([]containers.Container, error) { css, err := ms.apiClient.ContainerList(ctx, types.ContainerListOptions{ All: all, @@ -352,47 +288,3 @@ func (ms *local) Delete(ctx context.Context, containerID string, request contain } return err } - -func toPorts(ports []types.Port) []containers.Port { - result := []containers.Port{} - for _, port := range ports { - result = append(result, containers.Port{ - ContainerPort: uint32(port.PrivatePort), - HostPort: uint32(port.PublicPort), - HostIP: port.IP, - Protocol: port.Type, - }) - } - - return result -} - -func fromPorts(ports []containers.Port) (map[nat.Port]struct{}, map[nat.Port][]nat.PortBinding, error) { - var ( - exposedPorts = make(map[nat.Port]struct{}, len(ports)) - bindings = make(map[nat.Port][]nat.PortBinding) - ) - - for _, port := range ports { - p, err := nat.NewPort(port.Protocol, strconv.Itoa(int(port.ContainerPort))) - if err != nil { - return nil, nil, err - } - - if _, exists := exposedPorts[p]; !exists { - exposedPorts[p] = struct{}{} - } - - portBinding := nat.PortBinding{ - HostIP: port.HostIP, - HostPort: strconv.Itoa(int(port.HostPort)), - } - bslice, exists := bindings[p] - if !exists { - bslice = []nat.PortBinding{} - } - bindings[p] = append(bslice, portBinding) - } - - return exposedPorts, bindings, nil -} diff --git a/local/convert.go b/local/convert.go new file mode 100644 index 000000000..05931a366 --- /dev/null +++ b/local/convert.go @@ -0,0 +1,150 @@ +// +build local + +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package local + +import ( + "fmt" + "sort" + "strconv" + "strings" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/go-connections/nat" + + "github.com/docker/compose-cli/api/containers" +) + +func toRuntimeConfig(m *types.ContainerJSON) *containers.RuntimeConfig { + if m.Config == nil { + return nil + } + var env map[string]string + if m.Config.Env != nil { + env = make(map[string]string) + for _, e := range m.Config.Env { + tokens := strings.Split(e, "=") + if len(tokens) != 2 { + continue + } + env[tokens[0]] = tokens[1] + } + } + + var labels []string + if m.Config.Labels != nil { + for k, v := range m.Config.Labels { + labels = append(labels, fmt.Sprintf("%s=%s", k, v)) + } + } + sort.Strings(labels) + + if env == nil && + labels == nil { + return nil + } + + return &containers.RuntimeConfig{ + Env: env, + Labels: labels, + } +} + +func toHostConfig(m *types.ContainerJSON) *containers.HostConfig { + if m.HostConfig == nil { + return nil + } + + return &containers.HostConfig{ + AutoRemove: m.HostConfig.AutoRemove, + RestartPolicy: fromRestartPolicyName(m.HostConfig.RestartPolicy.Name), + CPULimit: float64(m.HostConfig.Resources.NanoCPUs) / 1e9, + MemoryLimit: uint64(m.HostConfig.Resources.Memory), + } +} + +func toPorts(ports []types.Port) []containers.Port { + result := []containers.Port{} + for _, port := range ports { + result = append(result, containers.Port{ + ContainerPort: uint32(port.PrivatePort), + HostPort: uint32(port.PublicPort), + HostIP: port.IP, + Protocol: port.Type, + }) + } + + return result +} + +func fromPorts(ports []containers.Port) (map[nat.Port]struct{}, map[nat.Port][]nat.PortBinding, error) { + var ( + exposedPorts = make(map[nat.Port]struct{}, len(ports)) + bindings = make(map[nat.Port][]nat.PortBinding) + ) + + for _, port := range ports { + p, err := nat.NewPort(port.Protocol, strconv.Itoa(int(port.ContainerPort))) + if err != nil { + return nil, nil, err + } + + if _, exists := exposedPorts[p]; !exists { + exposedPorts[p] = struct{}{} + } + + portBinding := nat.PortBinding{ + HostIP: port.HostIP, + HostPort: strconv.Itoa(int(port.HostPort)), + } + bslice, exists := bindings[p] + if !exists { + bslice = []nat.PortBinding{} + } + bindings[p] = append(bslice, portBinding) + } + + return exposedPorts, bindings, nil +} + +func fromRestartPolicyName(m string) string { + switch m { + case "always": + return containers.RestartPolicyAny + case "on-failure": + return containers.RestartPolicyOnFailure + case "no", "": + fallthrough + default: + return containers.RestartPolicyNone + } +} + +func toRestartPolicy(p string) container.RestartPolicy { + switch p { + case containers.RestartPolicyAny: + return container.RestartPolicy{Name: "always"} + case containers.RestartPolicyOnFailure: + return container.RestartPolicy{Name: "on-failure"} + case containers.RestartPolicyNone: + fallthrough + default: + return container.RestartPolicy{Name: "no"} + } +} diff --git a/local/backend_test.go b/local/convert_test.go similarity index 72% rename from local/backend_test.go rename to local/convert_test.go index 428f1d2e3..987b6c98a 100644 --- a/local/backend_test.go +++ b/local/convert_test.go @@ -36,7 +36,7 @@ func TestToRuntimeConfig(t *testing.T) { Labels: map[string]string{"foo1": "bar1", "foo2": "bar2"}, }, } - rc := containerJSONToRuntimeConfig(m) + rc := toRuntimeConfig(m) res := &containers.RuntimeConfig{ Env: map[string]string{"FOO1": "BAR1", "FOO2": "BAR2"}, Labels: []string{"foo1=bar1", "foo2=bar2"}, @@ -65,7 +65,7 @@ func TestToHostConfig(t *testing.T) { }, ContainerJSONBase: base, } - hc := containerJSONToHostConfig(m) + hc := toHostConfig(m) res := &containers.HostConfig{ AutoRemove: true, RestartPolicy: containers.RestartPolicyNone, @@ -74,3 +74,30 @@ func TestToHostConfig(t *testing.T) { } assert.DeepEqual(t, hc, res) } + +func TestFromRestartPolicyName(t *testing.T) { + t.Parallel() + moby := []string{"always", "on-failure", "no", ""} + ours := []string{ + containers.RestartPolicyAny, + containers.RestartPolicyOnFailure, + containers.RestartPolicyNone, + containers.RestartPolicyNone, + } + for i, p := range moby { + assert.Equal(t, fromRestartPolicyName(p), ours[i]) + } +} + +func TestToRestartPolicy(t *testing.T) { + t.Parallel() + ours := []string{containers.RestartPolicyAny, containers.RestartPolicyOnFailure, containers.RestartPolicyNone} + moby := []container.RestartPolicy{ + {Name: "always"}, + {Name: "on-failure"}, + {Name: "no"}, + } + for i, p := range ours { + assert.Equal(t, toRestartPolicy(p), moby[i]) + } +}