From 85ec3124610ebb0e3b314fb73ac7625f749be141 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Fri, 13 Nov 2020 09:38:21 +0100 Subject: [PATCH 01/16] convert compose model into moby API types to prepare "up" local implementation Signed-off-by: Nicolas De Loof --- local/backend.go | 24 +-- local/compose.go | 352 ++++++++++++++++++++++++++++++++++++++++++++ local/containers.go | 28 ++-- 3 files changed, 382 insertions(+), 22 deletions(-) create mode 100644 local/compose.go diff --git a/local/backend.go b/local/backend.go index 134fddb0..b72658de 100644 --- a/local/backend.go +++ b/local/backend.go @@ -20,7 +20,6 @@ package local import ( "context" - "github.com/docker/docker/client" "github.com/docker/compose-cli/api/compose" @@ -53,22 +52,23 @@ func service(ctx context.Context) (backend.Service, error) { }, nil } -func (cs *containerService) ContainerService() containers.Service { - return cs +func (s *local) ContainerService() containers.Service { + return s.containerService } -func (ms *local) ComposeService() compose.Service { +func (s *local) ComposeService() compose.Service { + return s +} + +func (s *local) SecretsService() secrets.Service { return nil } -func (ms *local) SecretsService() secrets.Service { +func (s *local) VolumeService() volumes.Service { + return s.volumeService +} + +func (s *local) ResourceService() resources.Service { return nil } -func (vs *volumeService) VolumeService() volumes.Service { - return vs -} - -func (ms *local) ResourceService() resources.Service { - return nil -} diff --git a/local/compose.go b/local/compose.go new file mode 100644 index 00000000..8cb57de2 --- /dev/null +++ b/local/compose.go @@ -0,0 +1,352 @@ +// +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 ( + "context" + "fmt" + "github.com/compose-spec/compose-go/types" + "github.com/docker/compose-cli/api/compose" + moby "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/strslice" + "github.com/docker/docker/errdefs" + "github.com/docker/go-connections/nat" + "github.com/pkg/errors" + "io" + "path/filepath" + "strings" +) + +func (s *local) Up(ctx context.Context, project *types.Project, detach bool) error { + for k, network := range project.Networks { + if !network.External.External { + network.Name = fmt.Sprintf("%s_%s", project.Name, k) + project.Networks[k] = network + } + err := s.ensureNetwork(ctx, network) + if err != nil { + return err + } + } + + for _, service := range project.Services { + containerConfig, hostConfig, networkingConfig, err := getContainerCreateOptions(project, service) + if err != nil { + return err + } + name := fmt.Sprintf("%s_%s", project.Name, service.Name) + id, err := s.create(ctx, containerConfig, hostConfig, networkingConfig, name) + if err != nil { + return err + } + for net, _ := range service.Networks { + name := fmt.Sprintf("%s_%s", project.Name, net) + err = s.connectContainerToNetwork(ctx, id, service.Name, name) + if err != nil { + return err + } + } + err = s.containerService.apiClient.ContainerStart(ctx, id, moby.ContainerStartOptions{}) + if err != nil { + return err + } + } + return nil +} + + +func (s *local) Down(ctx context.Context, projectName string) error { + panic("implement me") +} + +func (s *local) Logs(ctx context.Context, projectName string, w io.Writer) error { + panic("implement me") +} + +func (s *local) Ps(ctx context.Context, projectName string) ([]compose.ServiceStatus, error) { + panic("implement me") +} + +func (s *local) List(ctx context.Context, projectName string) ([]compose.Stack, error) { + panic("implement me") +} + +func (s *local) Convert(ctx context.Context, project *types.Project, format string) ([]byte, error) { + panic("implement me") +} + + +func getContainerCreateOptions(p *types.Project, s types.ServiceConfig) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) { + labels := map[string]string{ + "com.docker.compose.project": p.Name, + "com.docker.compose.service": s.Name, + } + + var ( + runCmd strslice.StrSlice + entrypoint strslice.StrSlice + ) + if len(s.Command) > 0 { + runCmd = strslice.StrSlice(s.Command) + } + if len(s.Entrypoint) > 0 { + entrypoint = strslice.StrSlice(s.Entrypoint) + } + image := s.Image + if s.Image == "" { + image = fmt.Sprintf("%s_%s", p.Name, s.Name) + } + + var ( + tty = s.Tty + stdinOpen = s.StdinOpen + attachStdin = false + ) + + containerConfig := container.Config{ + Hostname: s.Hostname, + Domainname: s.DomainName, + User: s.User, + ExposedPorts: buildContainerPorts(s), + Tty: tty, + OpenStdin: stdinOpen, + StdinOnce: true, + AttachStdin: attachStdin, + AttachStderr: true, + AttachStdout: true, + Cmd: runCmd, + Image: image, + WorkingDir: s.WorkingDir, + Entrypoint: entrypoint, + NetworkDisabled: s.NetworkMode == "disabled", + MacAddress: s.MacAddress, + Labels: labels, + StopSignal: s.StopSignal, + // Env: s.Environment, FIXME conversion + // Healthcheck: s.HealthCheck, FIXME conversion + // Volumes: // FIXME unclear to me the overlap with HostConfig.Mounts + // StopTimeout: s.StopGracePeriod FIXME conversion + } + + mountOptions, err := buildContainerMountOptions(p, s) + if err != nil { + return nil, nil, nil, err + } + + bindings, err := buildContainerBindingOptions(s) + if err != nil { + return nil, nil, nil, err + } + + networkMode := getNetworkMode(p, s) + hostConfig := container.HostConfig{ + Mounts: mountOptions, + CapAdd: strslice.StrSlice(s.CapAdd), + CapDrop: strslice.StrSlice(s.CapDrop), + NetworkMode: networkMode, + Init: s.Init, + ReadonlyRootfs: s.ReadOnly, + // ShmSize: , TODO + Sysctls: s.Sysctls, + PortBindings: bindings, + } + + networkConfig := buildDefaultNetworkConfig(s, networkMode) + return &containerConfig, &hostConfig, networkConfig, nil +} + +func buildContainerPorts(s types.ServiceConfig) nat.PortSet { + ports := nat.PortSet{} + for _, p := range s.Ports { + p := nat.Port(fmt.Sprintf("%d/%s", p.Target, p.Protocol)) + ports[p] = struct{}{} + } + return ports +} + +func buildContainerBindingOptions(s types.ServiceConfig) (nat.PortMap, error) { + bindings := nat.PortMap{} + for _, port := range s.Ports { + p := nat.Port(fmt.Sprintf("%d/%s", port.Target, port.Protocol)) + bind := []nat.PortBinding{} + binding := nat.PortBinding{} + if port.Published > 0 { + binding.HostPort = fmt.Sprint(port.Published) + } + bind = append(bind, binding) + bindings[p] = bind + } + return bindings, nil +} + +func buildContainerMountOptions(p *types.Project, s types.ServiceConfig) ([]mount.Mount, error) { + mounts := []mount.Mount{} + + for _, v := range s.Volumes { + source := v.Source + if v.Type == "bind" && !filepath.IsAbs(source) { + // FIXME handle ~/ + source = filepath.Join(p.WorkingDir, source) + } + + mounts = append(mounts, mount.Mount{ + Type: mount.Type(v.Type), + Source: source, + Target: v.Target, + ReadOnly: v.ReadOnly, + Consistency: mount.Consistency(v.Consistency), + BindOptions: buildBindOption(v.Bind), + VolumeOptions: buildVolumeOptions(v.Volume), + TmpfsOptions: buildTmpfsOptions(v.Tmpfs), + }) + } + return mounts, nil +} + +func buildBindOption(bind *types.ServiceVolumeBind) *mount.BindOptions { + if bind == nil { + return nil + } + return &mount.BindOptions{ + Propagation: mount.Propagation(bind.Propagation), + // NonRecursive: false, FIXME missing from model ? + } +} + +func buildVolumeOptions(vol *types.ServiceVolumeVolume) *mount.VolumeOptions { + if vol == nil { + return nil + } + return &mount.VolumeOptions{ + NoCopy: vol.NoCopy, + // Labels: , // FIXME missing from model ? + // DriverConfig: , // FIXME missing from model ? + } +} + +func buildTmpfsOptions(tmpfs *types.ServiceVolumeTmpfs) *mount.TmpfsOptions { + if tmpfs == nil { + return nil + } + return &mount.TmpfsOptions{ + SizeBytes: tmpfs.Size, + // Mode: , // FIXME missing from model ? + } +} + +func buildDefaultNetworkConfig(s types.ServiceConfig, networkMode container.NetworkMode) *network.NetworkingConfig { + config := map[string]*network.EndpointSettings{} + net := string(networkMode) + config[net] = &network.EndpointSettings{ + Aliases: getAliases(s, s.Networks[net]), + } + + return &network.NetworkingConfig{ + EndpointsConfig: config, + } +} + +func getAliases(s types.ServiceConfig, c *types.ServiceNetworkConfig) []string { + aliases := []string{s.Name} + if c != nil { + aliases = append(aliases, c.Aliases...) + } + return aliases +} + +func getNetworkMode(p *types.Project, service types.ServiceConfig) container.NetworkMode { + mode := service.NetworkMode + if mode == "" { + if len(p.Networks) > 0 { + for name := range getNetworksForService(service) { + return container.NetworkMode(p.Networks[name].Name) + } + } + return container.NetworkMode("none") + } + + /// FIXME incomplete implementation + if strings.HasPrefix(mode, "service:") { + panic("Not yet implemented") + } + if strings.HasPrefix(mode, "container:") { + panic("Not yet implemented") + } + + return container.NetworkMode(mode) +} + +func getNetworksForService(s types.ServiceConfig) map[string]*types.ServiceNetworkConfig { + if len(s.Networks) > 0 { + return s.Networks + } + return map[string]*types.ServiceNetworkConfig{"default": nil} +} + + +func (s *local) ensureNetwork(ctx context.Context, n types.NetworkConfig) error { + _, err := s.containerService.apiClient.NetworkInspect(ctx, n.Name, moby.NetworkInspectOptions{}) + if err != nil { + if errdefs.IsNotFound(err) { + createOpts := moby.NetworkCreate{ + // TODO NameSpace Labels + Labels: n.Labels, + Driver: n.Driver, + Options: n.DriverOpts, + Internal: n.Internal, + Attachable: n.Attachable, + } + + if n.Ipam.Driver != "" || len(n.Ipam.Config) > 0 { + createOpts.IPAM = &network.IPAM{} + } + + if n.Ipam.Driver != "" { + createOpts.IPAM.Driver = n.Ipam.Driver + } + + for _, ipamConfig := range n.Ipam.Config { + config := network.IPAMConfig{ + Subnet: ipamConfig.Subnet, + } + createOpts.IPAM.Config = append(createOpts.IPAM.Config, config) + } + if _, err := s.containerService.apiClient.NetworkCreate(context.Background(), n.Name, createOpts); err != nil { + return errors.Wrapf(err, "failed to create network %s", n.Name) + } + return nil + } else { + return err + } + } + return nil +} + +func (s *local) connectContainerToNetwork(ctx context.Context, id string, service string, n string) error { + err := s.containerService.apiClient.NetworkConnect(ctx, n, id, &network.EndpointSettings{ + Aliases: []string{service}, + }) + if err != nil { + return err + } + return nil +} diff --git a/local/containers.go b/local/containers.go index 327a991e..99cda41e 100644 --- a/local/containers.go +++ b/local/containers.go @@ -21,6 +21,7 @@ package local import ( "bufio" "context" + "github.com/docker/docker/api/types/network" "io" "strings" "time" @@ -134,13 +135,21 @@ func (cs *containerService) Run(ctx context.Context, r containers.ContainerConfi }, } - created, err := cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, nil, r.ID) + id, err := cs.create(ctx, containerConfig, hostConfig, nil, r.ID) + if err != nil { + return err + } + return cs.apiClient.ContainerStart(ctx, id, types.ContainerStartOptions{}) +} + +func (cs *containerService) create(ctx context.Context, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, name string) (string, error) { + created, err := cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, name) if err != nil { if client.IsErrNotFound(err) { - io, err := cs.apiClient.ImagePull(ctx, r.Image, types.ImagePullOptions{}) + io, err := cs.apiClient.ImagePull(ctx, containerConfig.Image, types.ImagePullOptions{}) if err != nil { - return err + return "", err } scanner := bufio.NewScanner(io) @@ -149,21 +158,20 @@ func (cs *containerService) Run(ctx context.Context, r containers.ContainerConfi } if err = scanner.Err(); err != nil { - return err + return "", err } if err = io.Close(); err != nil { - return err + return "", err } - created, err = cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, nil, r.ID) + created, err = cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, name) if err != nil { - return err + return "", err } } else { - return err + return "", err } } - - return cs.apiClient.ContainerStart(ctx, created.ID, types.ContainerStartOptions{}) + return created.ID, nil } func (cs *containerService) Start(ctx context.Context, containerID string) error { From 3f52508efe5bb02e57f2e6c64cddbb66c156d88a Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Fri, 13 Nov 2020 16:20:34 +0100 Subject: [PATCH 02/16] Skeletton implementation for compose commands Signed-off-by: Nicolas De Loof --- local/compose.go | 80 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 6 deletions(-) diff --git a/local/compose.go b/local/compose.go index 8cb57de2..41bd3875 100644 --- a/local/compose.go +++ b/local/compose.go @@ -20,20 +20,25 @@ package local import ( "context" + "encoding/json" "fmt" "github.com/compose-spec/compose-go/types" "github.com/docker/compose-cli/api/compose" + "github.com/docker/compose-cli/api/containers" moby "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/strslice" "github.com/docker/docker/errdefs" "github.com/docker/go-connections/nat" "github.com/pkg/errors" + "github.com/sanathkr/go-yaml" "io" "path/filepath" "strings" + "sync" ) func (s *local) Up(ctx context.Context, project *types.Project, detach bool) error { @@ -75,26 +80,89 @@ func (s *local) Up(ctx context.Context, project *types.Project, detach bool) err func (s *local) Down(ctx context.Context, projectName string) error { - panic("implement me") + list, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + Filters: filters.NewArgs( + filters.Arg("label", "com.docker.compose.project="+projectName), + ), + }) + if err != nil { + return err + } + for _, c := range list { + s.containerService.Stop(ctx, c.ID, nil) + } + return nil } func (s *local) Logs(ctx context.Context, projectName string, w io.Writer) error { - panic("implement me") + list, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + Filters: filters.NewArgs( + filters.Arg("label", "com.docker.compose.project="+projectName), + ), + }) + if err != nil { + return err + } + var wg sync.WaitGroup + for _, c := range list { + go func() { + s.containerService.Logs(ctx, c.ID, containers.LogsRequest{ + Follow: true, + Writer: w, + }) + wg.Done() + }() + wg.Add(1) + } + wg.Wait() + return nil } func (s *local) Ps(ctx context.Context, projectName string) ([]compose.ServiceStatus, error) { - panic("implement me") + list, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + Filters: filters.NewArgs( + filters.Arg("label", "com.docker.compose.project="+projectName), + ), + }) + if err != nil { + return nil, err + } + var status []compose.ServiceStatus + for _,c := range list { + // TODO group by service + status = append(status, compose.ServiceStatus{ + ID: c.ID, + Name: c.Labels["com.docker.compose.service"], + Replicas: 0, + Desired: 0, + Ports: nil, + Publishers: nil, + }) + } + return status, nil } func (s *local) List(ctx context.Context, projectName string) ([]compose.Stack, error) { - panic("implement me") + _, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{All: true}) + if err != nil { + return nil, err + } + var stacks []compose.Stack + // TODO rebuild stacks based on containers + return stacks, nil } func (s *local) Convert(ctx context.Context, project *types.Project, format string) ([]byte, error) { - panic("implement me") + switch format { + case "json": + return json.MarshalIndent(project, "", " ") + case "yaml": + return yaml.Marshal(project) + default: + return nil, fmt.Errorf("unsupported format %q", format) + } } - func getContainerCreateOptions(p *types.Project, s types.ServiceConfig) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) { labels := map[string]string{ "com.docker.compose.project": p.Name, From 74de423cc33db21f21668e58e87a9b3f674a91bf Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Fri, 13 Nov 2020 17:39:56 +0100 Subject: [PATCH 03/16] reuse ECS logConsumer to implement formatted compose log output Signed-off-by: Nicolas De Loof --- ecs/logs.go | 41 +--------------- {ecs => formatter}/colors.go | 2 +- formatter/logs.go | 91 ++++++++++++++++++++++++++++++++++++ local/backend.go | 1 + local/compose.go | 34 +++++++++++++- 5 files changed, 127 insertions(+), 42 deletions(-) rename {ecs => formatter}/colors.go (98%) create mode 100644 formatter/logs.go diff --git a/ecs/logs.go b/ecs/logs.go index 3f24ca29..53658b78 100644 --- a/ecs/logs.go +++ b/ecs/logs.go @@ -17,51 +17,14 @@ package ecs import ( - "bytes" "context" - "fmt" + "github.com/docker/compose-cli/formatter" "io" - "strconv" - "strings" ) func (b *ecsAPIService) Logs(ctx context.Context, project string, w io.Writer) error { - consumer := logConsumer{ - colors: map[string]colorFunc{}, - width: 0, - writer: w, - } + consumer := formatter.NewLogConsumer(w) err := b.aws.GetLogs(ctx, project, consumer.Log) return err } -func (l *logConsumer) Log(service, container, message string) { - cf, ok := l.colors[service] - if !ok { - cf = <-loop - l.colors[service] = cf - l.computeWidth() - } - prefix := fmt.Sprintf("%-"+strconv.Itoa(l.width)+"s |", service) - - for _, line := range strings.Split(message, "\n") { - buf := bytes.NewBufferString(fmt.Sprintf("%s %s\n", cf(prefix), line)) - l.writer.Write(buf.Bytes()) // nolint:errcheck - } -} - -func (l *logConsumer) computeWidth() { - width := 0 - for n := range l.colors { - if len(n) > width { - width = len(n) - } - } - l.width = width + 3 -} - -type logConsumer struct { - colors map[string]colorFunc - width int - writer io.Writer -} diff --git a/ecs/colors.go b/formatter/colors.go similarity index 98% rename from ecs/colors.go rename to formatter/colors.go index a08bc917..090a396b 100644 --- a/ecs/colors.go +++ b/formatter/colors.go @@ -14,7 +14,7 @@ limitations under the License. */ -package ecs +package formatter import ( "fmt" diff --git a/formatter/logs.go b/formatter/logs.go new file mode 100644 index 00000000..a9e28774 --- /dev/null +++ b/formatter/logs.go @@ -0,0 +1,91 @@ +/* + 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 formatter + +import ( + "bytes" + "fmt" + "io" + "strconv" + "strings" +) + + +func NewLogConsumer(w io.Writer) LogConsumer { + return LogConsumer{ + colors: map[string]colorFunc{}, + width: 0, + writer: w, + } +} + +func (l *LogConsumer) Log(service, container, message string) { + cf, ok := l.colors[service] + if !ok { + cf = <-loop + l.colors[service] = cf + l.computeWidth() + } + prefix := fmt.Sprintf("%-"+strconv.Itoa(l.width)+"s |", service) + + for _, line := range strings.Split(message, "\n") { + buf := bytes.NewBufferString(fmt.Sprintf("%s %s\n", cf(prefix), line)) + l.writer.Write(buf.Bytes()) // nolint:errcheck + } +} + +func (l *LogConsumer) GetWriter(service, container string) io.Writer { + return splitBuffer{ + service: service, + container: container, + consumer: l, + } +} + +func (l *LogConsumer) computeWidth() { + width := 0 + for n := range l.colors { + if len(n) > width { + width = len(n) + } + } + l.width = width + 3 +} + +type LogConsumer struct { + colors map[string]colorFunc + width int + writer io.Writer +} + + +type splitBuffer struct { + service string + container string + consumer *LogConsumer +} + +func (s splitBuffer) Write(b []byte) (n int, err error) { + split := bytes.Split(b, []byte{'\n'}) + for _, line := range split { + if len(line) != 0 { + s.consumer.Log(s.service, s.container, string(line)) + } + } + return len(b), nil +} + diff --git a/local/backend.go b/local/backend.go index b72658de..6fc5d08a 100644 --- a/local/backend.go +++ b/local/backend.go @@ -72,3 +72,4 @@ func (s *local) ResourceService() resources.Service { return nil } + diff --git a/local/compose.go b/local/compose.go index 41bd3875..1291ad4a 100644 --- a/local/compose.go +++ b/local/compose.go @@ -25,6 +25,7 @@ import ( "github.com/compose-spec/compose-go/types" "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/containers" + "github.com/docker/compose-cli/formatter" moby "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" @@ -43,7 +44,7 @@ import ( func (s *local) Up(ctx context.Context, project *types.Project, detach bool) error { for k, network := range project.Networks { - if !network.External.External { + if !network.External.External && network.Name != "" { network.Name = fmt.Sprintf("%s_%s", project.Name, k) project.Networks[k] = network } @@ -53,6 +54,17 @@ func (s *local) Up(ctx context.Context, project *types.Project, detach bool) err } } + for k, volume := range project.Volumes { + if !volume.External.External && volume.Name != "" { + volume.Name = fmt.Sprintf("%s_%s", project.Name, k) + project.Volumes[k] = volume + } + err := s.ensureVolume(ctx, volume) + if err != nil { + return err + } + } + for _, service := range project.Services { containerConfig, hostConfig, networkingConfig, err := getContainerCreateOptions(project, service) if err != nil { @@ -104,11 +116,13 @@ func (s *local) Logs(ctx context.Context, projectName string, w io.Writer) error return err } var wg sync.WaitGroup + consumer := formatter.NewLogConsumer(w) for _, c := range list { + service := c.Labels["com.docker.compose.service"] go func() { s.containerService.Logs(ctx, c.ID, containers.LogsRequest{ Follow: true, - Writer: w, + Writer: consumer.GetWriter(service, c.ID), }) wg.Done() }() @@ -418,3 +432,19 @@ func (s *local) connectContainerToNetwork(ctx context.Context, id string, servic } return nil } + +func (s *local) ensureVolume(ctx context.Context, volume types.VolumeConfig) error { + // TODO could identify volume by label vs name + _, err := s.volumeService.Inspect(ctx, volume.Name) + if err != nil { + if errdefs.IsNotFound(err) { + // TODO we miss support for driver_opts and labels + _, err := s.volumeService.Create(ctx, volume.Name, nil) + if err != nil { + return err + } + } + return err + } + return nil +} From 7944a1b94fbbe725340e54a86699a2306e47926f Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 16 Nov 2020 09:43:00 +0100 Subject: [PATCH 04/16] implement image pull on `compose up` with progress Signed-off-by: Nicolas De Loof --- go.mod | 5 ++- go.sum | 29 ++--------------- local/compose.go | 78 ++++++++++++++++++++++++++++++++++++++++++++- local/containers.go | 4 +-- 4 files changed, 83 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index 38a2efbe..10532233 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,6 @@ require ( github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/Azure/go-autorest/autorest/validation v0.2.0 // indirect github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 - github.com/Microsoft/hcsshim v0.8.9 // indirect github.com/aws/aws-sdk-go v1.35.15 github.com/awslabs/goformation/v4 v4.15.3 github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 @@ -27,13 +26,14 @@ require ( github.com/containerd/containerd v1.3.5 // indirect github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8 github.com/docker/distribution v0.0.0-00010101000000-000000000000 // indirect - github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible + github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible github.com/docker/docker-credential-helpers v0.6.3 // indirect github.com/docker/go-connections v0.4.0 github.com/docker/go-units v0.4.0 github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect github.com/gobwas/pool v0.2.0 // indirect github.com/gobwas/ws v1.0.4 + github.com/gogo/protobuf v1.3.1 // indirect github.com/golang/mock v1.4.4 github.com/golang/protobuf v1.4.3 github.com/google/go-cmp v0.5.3 @@ -48,7 +48,6 @@ require ( github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 github.com/morikuni/aec v1.0.0 github.com/opencontainers/go-digest v1.0.0 - github.com/opencontainers/runc v0.1.1 // indirect github.com/pkg/errors v0.9.1 github.com/prometheus/tsdb v0.10.0 github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b diff --git a/go.sum b/go.sum index 6f081194..c89cd409 100644 --- a/go.sum +++ b/go.sum @@ -81,8 +81,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/hcsshim v0.8.9 h1:VrfodqvztU8YSOvygU+DN1BGaSGxmrNfqOv5oOuX2Bk= -github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -129,18 +127,8 @@ github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqh github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v1.0.1 h1:u7SFAJyRqWcG6ogaMAx3KjSTy1e3hT9QxqX7Jco7dRc= github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= -github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.5 h1:l0iDHQtFwcOUmOvdepI6BB67q7beT6sRp2JYsfHS08c= github.com/containerd/containerd v1.3.5/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8= -github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448 h1:PUD50EuOMkXVcpBIA/R95d56duJR9VxhwncsFbNnxW4= -github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= -github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de h1:dlfGmNcE3jDAecLqwKPMNX6nk2qh1c1Vg1/YTzpOOF4= -github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= -github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd h1:JNn81o/xG+8NEo3bC/vx9pbi/g2WI8mtP2/nXzu297Y= -github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -165,8 +153,8 @@ github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8 h1:JRquW4uqIU+eSilDhuo9 github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20200708230824-53e18a9d9bfe h1:pni13lAFm1g4cjHU6c3n4qGvvJGZQK4VvKRKMseQ42E= github.com/docker/distribution v0.0.0-20200708230824-53e18a9d9bfe/go.mod h1:Oqz4IonmMNc2N7GqfTL2xkhCQx0yS6nR+HrOZJnmKIk= -github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible h1:G2hY8RD7jB9QaSmcb8mYEIg8QbEvVAB7se8+lXHZHfg= -github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible h1:lwpV3629md5omgAKjxPWX17shI7vMRpE3nyb9WHn8pA= +github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -208,8 +196,6 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs= github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8= -github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= @@ -413,17 +399,11 @@ github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700 h1:eNUVfm/RFLIi1G7flU5/ZRTHvd4kcVuzfRnL6OFlzCI= -github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -448,7 +428,6 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -505,7 +484,6 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -602,7 +580,6 @@ golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -658,7 +635,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -820,7 +796,6 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= diff --git a/local/compose.go b/local/compose.go index 1291ad4a..1bb5afcd 100644 --- a/local/compose.go +++ b/local/compose.go @@ -26,6 +26,7 @@ import ( "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/containers" "github.com/docker/compose-cli/formatter" + "github.com/docker/compose-cli/progress" moby "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" @@ -33,6 +34,7 @@ import ( "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/strslice" "github.com/docker/docker/errdefs" + "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/go-connections/nat" "github.com/pkg/errors" "github.com/sanathkr/go-yaml" @@ -66,12 +68,17 @@ func (s *local) Up(ctx context.Context, project *types.Project, detach bool) err } for _, service := range project.Services { + err := s.applyPullPolicy(ctx, service) + if err != nil { + return err + } + containerConfig, hostConfig, networkingConfig, err := getContainerCreateOptions(project, service) if err != nil { return err } name := fmt.Sprintf("%s_%s", project.Name, service.Name) - id, err := s.create(ctx, containerConfig, hostConfig, networkingConfig, name) + id, err := s.containerService.create(ctx, containerConfig, hostConfig, networkingConfig, name) if err != nil { return err } @@ -90,6 +97,75 @@ func (s *local) Up(ctx context.Context, project *types.Project, detach bool) err return nil } +func (s *local) applyPullPolicy(ctx context.Context, service types.ServiceConfig) error { + w := progress.ContextWriter(ctx) + // TODO build vs pull should be controlled by pull policy + // if service.Build {} + if service.Image != "" { + _, _, err := s.containerService.apiClient.ImageInspectWithRaw(ctx, service.Image) + if err != nil { + if errdefs.IsNotFound(err) { + stream, err := s.containerService.apiClient.ImagePull(ctx, service.Image, moby.ImagePullOptions{}) + if err != nil { + return err + } + dec := json.NewDecoder(stream) + for { + var jm jsonmessage.JSONMessage + if err := dec.Decode(&jm); err != nil { + if err == io.EOF { + break + } + return err + } + toProgressEvent(jm, w) + } + } + } + } + return nil +} + +func toProgressEvent(jm jsonmessage.JSONMessage, w progress.Writer) { + if jm.Progress != nil { + if jm.Progress.Total != 0 { + percentage := int(float64(jm.Progress.Current)/float64(jm.Progress.Total)*100) / 2 + numSpaces := 50 - percentage + w.Event(progress.Event{ + ID: jm.ID, + Text: jm.Status, + Status: 0, + StatusText: fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces)), + Done: jm.Status == "Pull complete", + }) + } else { + if jm.Error != nil { + w.Event(progress.Event{ + ID: jm.ID, + Text: jm.Status, + Status: progress.Error, + StatusText: jm.Error.Message, + Done: true, + }) + } else if jm.Status == "Pull complete" { + w.Event(progress.Event{ + ID: jm.ID, + Text: jm.Status, + Status: progress.Done, + Done: true, + }) + } else { + w.Event(progress.Event{ + ID: jm.ID, + Text: jm.Status, + Status: progress.Working, + Done: false, + }) + } + } + } +} + func (s *local) Down(ctx context.Context, projectName string) error { list, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ diff --git a/local/containers.go b/local/containers.go index 99cda41e..52d9c1c5 100644 --- a/local/containers.go +++ b/local/containers.go @@ -143,7 +143,7 @@ func (cs *containerService) Run(ctx context.Context, r containers.ContainerConfi } func (cs *containerService) create(ctx context.Context, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, name string) (string, error) { - created, err := cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, name) + created, err := cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, nil, name) if err != nil { if client.IsErrNotFound(err) { @@ -163,7 +163,7 @@ func (cs *containerService) create(ctx context.Context, containerConfig *contain if err = io.Close(); err != nil { return "", err } - created, err = cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, name) + created, err = cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, nil, name) if err != nil { return "", err } From 0d33e5cdcc6d621f06c2425ae5ce9cb4411e542d Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 16 Nov 2020 09:51:45 +0100 Subject: [PATCH 05/16] report docker resources creation in progress Signed-off-by: Nicolas De Loof --- local/compose.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/local/compose.go b/local/compose.go index 1bb5afcd..31338e26 100644 --- a/local/compose.go +++ b/local/compose.go @@ -77,6 +77,13 @@ func (s *local) Up(ctx context.Context, project *types.Project, detach bool) err if err != nil { return err } + w := progress.ContextWriter(ctx) + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Create", + Done: false, + }) name := fmt.Sprintf("%s_%s", project.Name, service.Name) id, err := s.containerService.create(ctx, containerConfig, hostConfig, networkingConfig, name) if err != nil { @@ -89,10 +96,22 @@ func (s *local) Up(ctx context.Context, project *types.Project, detach bool) err return err } } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Start", + Done: false, + }) err = s.containerService.apiClient.ContainerStart(ctx, id, moby.ContainerStartOptions{}) if err != nil { return err } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Done, + StatusText: "Started", + Done: true, + }) } return nil } @@ -488,9 +507,22 @@ func (s *local) ensureNetwork(ctx context.Context, n types.NetworkConfig) error } createOpts.IPAM.Config = append(createOpts.IPAM.Config, config) } + w := progress.ContextWriter(ctx) + w.Event(progress.Event{ + ID: fmt.Sprintf("Network %q", n.Name), + Status: progress.Working, + StatusText: "Create", + Done: false, + }) if _, err := s.containerService.apiClient.NetworkCreate(context.Background(), n.Name, createOpts); err != nil { return errors.Wrapf(err, "failed to create network %s", n.Name) } + w.Event(progress.Event{ + ID: fmt.Sprintf("Network %q", n.Name), + Status: progress.Working, + StatusText: "Created", + Done: true, + }) return nil } else { return err @@ -514,8 +546,21 @@ func (s *local) ensureVolume(ctx context.Context, volume types.VolumeConfig) err _, err := s.volumeService.Inspect(ctx, volume.Name) if err != nil { if errdefs.IsNotFound(err) { + w := progress.ContextWriter(ctx) + w.Event(progress.Event{ + ID: fmt.Sprintf("Volume %q", volume.Name), + Status: progress.Working, + StatusText: "Create", + Done: false, + }) // TODO we miss support for driver_opts and labels _, err := s.volumeService.Create(ctx, volume.Name, nil) + w.Event(progress.Event{ + ID: fmt.Sprintf("Volume %q", volume.Name), + Status: progress.Done, + StatusText: "Created", + Done: true, + }) if err != nil { return err } From 9fdf69ea9c538e85d3a57bb48b8bc64c316d6c5e Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 16 Nov 2020 17:48:09 +0100 Subject: [PATCH 06/16] Handle container (re)create/(re)start on compose up Signed-off-by: Nicolas De Loof --- go.mod | 8 +- go.sum | 40 ++++++++- local/compose.go | 204 ++++++++++++++++++++++++++++++++++++-------- local/containers.go | 7 +- 4 files changed, 215 insertions(+), 44 deletions(-) diff --git a/go.mod b/go.mod index 10532233..e79958e4 100644 --- a/go.mod +++ b/go.mod @@ -17,23 +17,24 @@ require ( github.com/Azure/go-autorest/autorest/date v0.3.0 github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/Azure/go-autorest/autorest/validation v0.2.0 // indirect - github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 + github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab + github.com/Microsoft/hcsshim v0.8.10 // indirect github.com/aws/aws-sdk-go v1.35.15 github.com/awslabs/goformation/v4 v4.15.3 github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/compose-spec/compose-go v0.0.0-20201116112017-777513ca88e2 github.com/containerd/console v1.0.1 github.com/containerd/containerd v1.3.5 // indirect + github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a // indirect github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8 github.com/docker/distribution v0.0.0-00010101000000-000000000000 // indirect - github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible + github.com/docker/docker v17.12.0-ce-rc1.0.20201109195000-837baebb7430+incompatible github.com/docker/docker-credential-helpers v0.6.3 // indirect github.com/docker/go-connections v0.4.0 github.com/docker/go-units v0.4.0 github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect github.com/gobwas/pool v0.2.0 // indirect github.com/gobwas/ws v1.0.4 - github.com/gogo/protobuf v1.3.1 // indirect github.com/golang/mock v1.4.4 github.com/golang/protobuf v1.4.3 github.com/google/go-cmp v0.5.3 @@ -48,6 +49,7 @@ require ( github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 github.com/morikuni/aec v1.0.0 github.com/opencontainers/go-digest v1.0.0 + github.com/opencontainers/runc v0.1.1 // indirect github.com/pkg/errors v0.9.1 github.com/prometheus/tsdb v0.10.0 github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b diff --git a/go.sum b/go.sum index c89cd409..f3b01112 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -79,8 +80,10 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA= -github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab h1:9pygWVFqbY9lPxM0peffumuVDyMuIMzNLyO9uFjJuQo= +github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/hcsshim v0.8.10 h1:k5wTrpnVU2/xv8ZuzGkbXVd3js5zJ8RnumPo5RxiIxU= +github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3HV0OhsddkmM= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -118,6 +121,7 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/compose-spec/compose-go v0.0.0-20201116112017-777513ca88e2 h1:m6m0rnxmq3mPapGNAWqO6FLYg6GST7tJAAZqJ0pjadk= @@ -127,14 +131,24 @@ github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqh github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v1.0.1 h1:u7SFAJyRqWcG6ogaMAx3KjSTy1e3hT9QxqX7Jco7dRc= github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.5 h1:l0iDHQtFwcOUmOvdepI6BB67q7beT6sRp2JYsfHS08c= github.com/containerd/containerd v1.3.5/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a h1:jEIoR0aA5GogXZ8pP3DUzE+zrhaF6/1rYZy+7KkYEWM= +github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a/go.mod h1:W0qIOTD7mp2He++YVq+kgfXezRYqzP1uDuMVH1bITDY= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -153,8 +167,8 @@ github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8 h1:JRquW4uqIU+eSilDhuo9 github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20200708230824-53e18a9d9bfe h1:pni13lAFm1g4cjHU6c3n4qGvvJGZQK4VvKRKMseQ42E= github.com/docker/distribution v0.0.0-20200708230824-53e18a9d9bfe/go.mod h1:Oqz4IonmMNc2N7GqfTL2xkhCQx0yS6nR+HrOZJnmKIk= -github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible h1:lwpV3629md5omgAKjxPWX17shI7vMRpE3nyb9WHn8pA= -github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v17.12.0-ce-rc1.0.20201109195000-837baebb7430+incompatible h1:K1FeZ5nRwbPY49ukxi401rZ+0ELN21YMWDZ6QwhKcAs= +github.com/docker/docker v17.12.0-ce-rc1.0.20201109195000-837baebb7430+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -166,6 +180,7 @@ github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHz github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -196,6 +211,7 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs= github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= @@ -329,6 +345,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -399,11 +417,16 @@ github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -428,6 +451,7 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -451,6 +475,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -464,11 +489,13 @@ github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -484,6 +511,7 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -580,6 +608,7 @@ golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -646,11 +675,13 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -796,6 +827,7 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= diff --git a/local/compose.go b/local/compose.go index 31338e26..94d88546 100644 --- a/local/compose.go +++ b/local/compose.go @@ -22,6 +22,13 @@ import ( "context" "encoding/json" "fmt" + "io" + "path/filepath" + "strings" + "sync" + + "github.com/opencontainers/go-digest" + "github.com/compose-spec/compose-go/types" "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/containers" @@ -38,10 +45,6 @@ import ( "github.com/docker/go-connections/nat" "github.com/pkg/errors" "github.com/sanathkr/go-yaml" - "io" - "path/filepath" - "strings" - "sync" ) func (s *local) Up(ctx context.Context, project *types.Project, detach bool) error { @@ -67,55 +70,143 @@ func (s *local) Up(ctx context.Context, project *types.Project, detach bool) err } } + w := progress.ContextWriter(ctx) for _, service := range project.Services { err := s.applyPullPolicy(ctx, service) if err != nil { return err } - containerConfig, hostConfig, networkingConfig, err := getContainerCreateOptions(project, service) - if err != nil { - return err - } - w := progress.ContextWriter(ctx) - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Working, - StatusText: "Create", - Done: false, + actual, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + Filters: filters.NewArgs( + filters.Arg("label", "com.docker.compose.project="+project.Name), + filters.Arg("label", "com.docker.compose.service="+service.Name), + ), }) - name := fmt.Sprintf("%s_%s", project.Name, service.Name) - id, err := s.containerService.create(ctx, containerConfig, hostConfig, networkingConfig, name) if err != nil { return err } - for net, _ := range service.Networks { - name := fmt.Sprintf("%s_%s", project.Name, net) - err = s.connectContainerToNetwork(ctx, id, service.Name, name) + + expected, err := jsonHash(s) + if err != nil { + return err + } + + if len(actual) == 0 { + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Create", + Done: false, + }) + name := fmt.Sprintf("%s_%s", project.Name, service.Name) + err = s.runContainer(ctx, project, service, name, nil) if err != nil { return err } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Done, + StatusText: "Created", + Done: true, + }) + continue } + + container := actual[0] + diverged := container.Labels["com.docker.compose.config-hash"] != expected + if diverged { + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Recreate", + Done: false, + }) + err := s.containerService.Stop(ctx, container.ID, nil) + if err != nil { + return err + } + name := getContainerName(container) + tmpName := fmt.Sprintf("%s_%s", container.ID[:12], name) + err = s.containerService.apiClient.ContainerRename(ctx, container.ID, tmpName) + if err != nil { + return err + } + err = s.runContainer(ctx, project, service, name, &container) + if err != nil { + return err + } + err = s.containerService.Delete(ctx, container.ID, containers.DeleteRequest{}) + if err != nil { + return err + } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Done, + StatusText: "Recreated", + Done: true, + }) + continue + } + + if container.State == "running" { + // already running, skip + continue + } + w.Event(progress.Event{ ID: fmt.Sprintf("Service %q", service.Name), Status: progress.Working, - StatusText: "Start", + StatusText: "Restart", Done: false, }) - err = s.containerService.apiClient.ContainerStart(ctx, id, moby.ContainerStartOptions{}) + err = s.containerService.Start(ctx, container.ID) if err != nil { return err } w.Event(progress.Event{ ID: fmt.Sprintf("Service %q", service.Name), Status: progress.Done, - StatusText: "Started", + StatusText: "Restarted", Done: true, }) } return nil } +func getContainerName(c moby.Container) string { + // Names return container canonical name /foo + link aliases /linked_by/foo + for _, name := range c.Names { + if strings.LastIndex(name, "/") == 0 { + return name[1:] + } + } + return c.Names[0][1:] +} + +func (s *local) runContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, container *moby.Container) error { + containerConfig, hostConfig, networkingConfig, err := getContainerCreateOptions(project, service, container) + if err != nil { + return err + } + id, err := s.containerService.create(ctx, containerConfig, hostConfig, networkingConfig, name) + if err != nil { + return err + } + for net, _ := range service.Networks { + name := fmt.Sprintf("%s_%s", project.Name, net) + err = s.connectContainerToNetwork(ctx, id, service.Name, name) + if err != nil { + return err + } + } + err = s.containerService.apiClient.ContainerStart(ctx, id, moby.ContainerStartOptions{}) + if err != nil { + return err + } + return nil +} + func (s *local) applyPullPolicy(ctx context.Context, service types.ServiceConfig) error { w := progress.ContextWriter(ctx) // TODO build vs pull should be controlled by pull policy @@ -185,7 +276,6 @@ func toProgressEvent(jm jsonmessage.JSONMessage, w progress.Writer) { } } - func (s *local) Down(ctx context.Context, projectName string) error { list, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs( @@ -196,7 +286,10 @@ func (s *local) Down(ctx context.Context, projectName string) error { return err } for _, c := range list { - s.containerService.Stop(ctx, c.ID, nil) + err := s.containerService.Stop(ctx, c.ID, nil) + if err != nil { + return err + } } return nil } @@ -237,7 +330,7 @@ func (s *local) Ps(ctx context.Context, projectName string) ([]compose.ServiceSt return nil, err } var status []compose.ServiceStatus - for _,c := range list { + for _, c := range list { // TODO group by service status = append(status, compose.ServiceStatus{ ID: c.ID, @@ -272,10 +365,15 @@ func (s *local) Convert(ctx context.Context, project *types.Project, format stri } } -func getContainerCreateOptions(p *types.Project, s types.ServiceConfig) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) { +func getContainerCreateOptions(p *types.Project, s types.ServiceConfig, inherit *moby.Container) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) { + hash, err := jsonHash(s) + if err != nil { + return nil, nil, nil, err + } labels := map[string]string{ - "com.docker.compose.project": p.Name, - "com.docker.compose.service": s.Name, + "com.docker.compose.project": p.Name, + "com.docker.compose.service": s.Name, + "com.docker.compose.config-hash": hash, } var ( @@ -324,7 +422,7 @@ func getContainerCreateOptions(p *types.Project, s types.ServiceConfig) (*conta // StopTimeout: s.StopGracePeriod FIXME conversion } - mountOptions, err := buildContainerMountOptions(p, s) + mountOptions, err := buildContainerMountOptions(p, s, inherit) if err != nil { return nil, nil, nil, err } @@ -351,7 +449,7 @@ func getContainerCreateOptions(p *types.Project, s types.ServiceConfig) (*conta return &containerConfig, &hostConfig, networkConfig, nil } -func buildContainerPorts(s types.ServiceConfig) nat.PortSet { +func buildContainerPorts(s types.ServiceConfig) nat.PortSet { ports := nat.PortSet{} for _, p := range s.Ports { p := nat.Port(fmt.Sprintf("%d/%s", p.Target, p.Protocol)) @@ -360,7 +458,7 @@ func buildContainerPorts(s types.ServiceConfig) nat.PortSet { return ports } -func buildContainerBindingOptions(s types.ServiceConfig) (nat.PortMap, error) { +func buildContainerBindingOptions(s types.ServiceConfig) (nat.PortMap, error) { bindings := nat.PortMap{} for _, port := range s.Ports { p := nat.Port(fmt.Sprintf("%d/%s", port.Target, port.Protocol)) @@ -375,10 +473,32 @@ func buildContainerBindingOptions(s types.ServiceConfig) (nat.PortMap, error) { return bindings, nil } -func buildContainerMountOptions(p *types.Project, s types.ServiceConfig) ([]mount.Mount, error) { +func buildContainerMountOptions(p *types.Project, s types.ServiceConfig, inherit *moby.Container) ([]mount.Mount, error) { mounts := []mount.Mount{} + var inherited []string + if inherit != nil { + for _, m := range inherit.Mounts { + if m.Type == "tmpfs" { + continue + } + src := m.Source + if m.Type == "volume" { + src = m.Name + } + mounts = append(mounts, mount.Mount{ + Type: m.Type, + Source: src, + Target: m.Destination, + ReadOnly: !m.RW, + }) + inherited = append(inherited, m.Destination) + } + } for _, v := range s.Volumes { + if contains(inherited, v.Target) { + continue + } source := v.Source if v.Type == "bind" && !filepath.IsAbs(source) { // FIXME handle ~/ @@ -442,7 +562,7 @@ func buildDefaultNetworkConfig(s types.ServiceConfig, networkMode container.Netw } } -func getAliases(s types.ServiceConfig, c *types.ServiceNetworkConfig) []string { +func getAliases(s types.ServiceConfig, c *types.ServiceNetworkConfig) []string { aliases := []string{s.Name} if c != nil { aliases = append(aliases, c.Aliases...) @@ -479,7 +599,6 @@ func getNetworksForService(s types.ServiceConfig) map[string]*types.ServiceNetwo return map[string]*types.ServiceNetworkConfig{"default": nil} } - func (s *local) ensureNetwork(ctx context.Context, n types.NetworkConfig) error { _, err := s.containerService.apiClient.NetworkInspect(ctx, n.Name, moby.NetworkInspectOptions{}) if err != nil { @@ -569,3 +688,20 @@ func (s *local) ensureVolume(ctx context.Context, volume types.VolumeConfig) err } return nil } + +func jsonHash(o interface{}) (string, error) { + bytes, err := json.Marshal(o) + if err != nil { + return "", nil + } + return digest.SHA256.FromBytes(bytes).String(), nil +} + +func contains(slice []string, item string) bool { + for _, v := range slice { + if v == item { + return true + } + } + return false +} diff --git a/local/containers.go b/local/containers.go index 52d9c1c5..debfd22e 100644 --- a/local/containers.go +++ b/local/containers.go @@ -21,11 +21,12 @@ package local import ( "bufio" "context" - "github.com/docker/docker/api/types/network" "io" "strings" "time" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" @@ -143,7 +144,7 @@ func (cs *containerService) Run(ctx context.Context, r containers.ContainerConfi } func (cs *containerService) create(ctx context.Context, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, name string) (string, error) { - created, err := cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, nil, name) + created, err := cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, name) if err != nil { if client.IsErrNotFound(err) { @@ -163,7 +164,7 @@ func (cs *containerService) create(ctx context.Context, containerConfig *contain if err = io.Close(); err != nil { return "", err } - created, err = cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, nil, name) + created, err = cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, name) if err != nil { return "", err } From b0ee6d285a22f70567f74afa34998fbe3358eb87 Mon Sep 17 00:00:00 2001 From: Djordje Lukic Date: Mon, 16 Nov 2020 18:22:09 +0100 Subject: [PATCH 07/16] Update docker/docker to be able to run this on a Mac, use goroutines when starting a stack Signed-off-by: Djordje Lukic --- go.mod | 7 +- go.sum | 39 +--------- local/compose.go | 172 +++++++++++++++++++++++--------------------- local/containers.go | 11 ++- 4 files changed, 103 insertions(+), 126 deletions(-) diff --git a/go.mod b/go.mod index e79958e4..74cbce54 100644 --- a/go.mod +++ b/go.mod @@ -18,23 +18,22 @@ require ( github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/Azure/go-autorest/autorest/validation v0.2.0 // indirect github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab - github.com/Microsoft/hcsshim v0.8.10 // indirect github.com/aws/aws-sdk-go v1.35.15 github.com/awslabs/goformation/v4 v4.15.3 github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/compose-spec/compose-go v0.0.0-20201116112017-777513ca88e2 github.com/containerd/console v1.0.1 github.com/containerd/containerd v1.3.5 // indirect - github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a // indirect github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8 github.com/docker/distribution v0.0.0-00010101000000-000000000000 // indirect - github.com/docker/docker v17.12.0-ce-rc1.0.20201109195000-837baebb7430+incompatible + github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible github.com/docker/docker-credential-helpers v0.6.3 // indirect github.com/docker/go-connections v0.4.0 github.com/docker/go-units v0.4.0 github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect github.com/gobwas/pool v0.2.0 // indirect github.com/gobwas/ws v1.0.4 + github.com/gogo/protobuf v1.3.1 // indirect github.com/golang/mock v1.4.4 github.com/golang/protobuf v1.4.3 github.com/google/go-cmp v0.5.3 @@ -49,7 +48,7 @@ require ( github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 github.com/morikuni/aec v1.0.0 github.com/opencontainers/go-digest v1.0.0 - github.com/opencontainers/runc v0.1.1 // indirect + github.com/opencontainers/image-spec v1.0.1 github.com/pkg/errors v0.9.1 github.com/prometheus/tsdb v0.10.0 github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b diff --git a/go.sum b/go.sum index f3b01112..2cbc010e 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -82,8 +81,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab h1:9pygWVFqbY9lPxM0peffumuVDyMuIMzNLyO9uFjJuQo= github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/hcsshim v0.8.10 h1:k5wTrpnVU2/xv8ZuzGkbXVd3js5zJ8RnumPo5RxiIxU= -github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3HV0OhsddkmM= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -121,34 +118,20 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/compose-spec/compose-go v0.0.0-20201116112017-777513ca88e2 h1:m6m0rnxmq3mPapGNAWqO6FLYg6GST7tJAAZqJ0pjadk= github.com/compose-spec/compose-go v0.0.0-20201116112017-777513ca88e2/go.mod h1:cZJ8y+zQzrYfN5XnEu/kMeDEP0V2D9ojF7Rb4nrneUc= -github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s= -github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= -github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v1.0.1 h1:u7SFAJyRqWcG6ogaMAx3KjSTy1e3hT9QxqX7Jco7dRc= github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= -github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.5 h1:l0iDHQtFwcOUmOvdepI6BB67q7beT6sRp2JYsfHS08c= github.com/containerd/containerd v1.3.5/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a h1:jEIoR0aA5GogXZ8pP3DUzE+zrhaF6/1rYZy+7KkYEWM= -github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a/go.mod h1:W0qIOTD7mp2He++YVq+kgfXezRYqzP1uDuMVH1bITDY= -github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= -github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= -github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -167,8 +150,8 @@ github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8 h1:JRquW4uqIU+eSilDhuo9 github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20200708230824-53e18a9d9bfe h1:pni13lAFm1g4cjHU6c3n4qGvvJGZQK4VvKRKMseQ42E= github.com/docker/distribution v0.0.0-20200708230824-53e18a9d9bfe/go.mod h1:Oqz4IonmMNc2N7GqfTL2xkhCQx0yS6nR+HrOZJnmKIk= -github.com/docker/docker v17.12.0-ce-rc1.0.20201109195000-837baebb7430+incompatible h1:K1FeZ5nRwbPY49ukxi401rZ+0ELN21YMWDZ6QwhKcAs= -github.com/docker/docker v17.12.0-ce-rc1.0.20201109195000-837baebb7430+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible h1:lwpV3629md5omgAKjxPWX17shI7vMRpE3nyb9WHn8pA= +github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -180,7 +163,6 @@ github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHz github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -211,7 +193,6 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs= github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= @@ -345,8 +326,6 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -417,16 +396,11 @@ github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -451,7 +425,6 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -475,7 +448,6 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -489,13 +461,11 @@ github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -511,7 +481,6 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -608,7 +577,6 @@ golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -675,13 +643,11 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -827,7 +793,6 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= diff --git a/local/compose.go b/local/compose.go index 94d88546..c45203a3 100644 --- a/local/compose.go +++ b/local/compose.go @@ -28,6 +28,7 @@ import ( "sync" "github.com/opencontainers/go-digest" + "golang.org/x/sync/errgroup" "github.com/compose-spec/compose-go/types" "github.com/docker/compose-cli/api/compose" @@ -71,107 +72,112 @@ func (s *local) Up(ctx context.Context, project *types.Project, detach bool) err } w := progress.ContextWriter(ctx) + eg, ctx := errgroup.WithContext(ctx) for _, service := range project.Services { - err := s.applyPullPolicy(ctx, service) - if err != nil { - return err - } + service := service + eg.Go(func() error { + err := s.applyPullPolicy(ctx, service) + if err != nil { + return err + } - actual, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ - Filters: filters.NewArgs( - filters.Arg("label", "com.docker.compose.project="+project.Name), - filters.Arg("label", "com.docker.compose.service="+service.Name), - ), - }) - if err != nil { - return err - } + actual, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + Filters: filters.NewArgs( + filters.Arg("label", "com.docker.compose.project="+project.Name), + filters.Arg("label", "com.docker.compose.service="+service.Name), + ), + }) + if err != nil { + return err + } - expected, err := jsonHash(s) - if err != nil { - return err - } + expected, err := jsonHash(s) + if err != nil { + return err + } + + if len(actual) == 0 { + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Create", + Done: false, + }) + name := fmt.Sprintf("%s_%s", project.Name, service.Name) + err = s.runContainer(ctx, project, service, name, nil) + if err != nil { + return err + } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Done, + StatusText: "Created", + Done: true, + }) + return nil + } + + container := actual[0] + diverged := container.Labels["com.docker.compose.config-hash"] != expected + if diverged { + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Recreate", + Done: false, + }) + err := s.containerService.Stop(ctx, container.ID, nil) + if err != nil { + return err + } + name := getContainerName(container) + tmpName := fmt.Sprintf("%s_%s", container.ID[:12], name) + err = s.containerService.apiClient.ContainerRename(ctx, container.ID, tmpName) + if err != nil { + return err + } + err = s.runContainer(ctx, project, service, name, &container) + if err != nil { + return err + } + err = s.containerService.Delete(ctx, container.ID, containers.DeleteRequest{}) + if err != nil { + return err + } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Done, + StatusText: "Recreated", + Done: true, + }) + return nil + } + + if container.State == "running" { + // already running, skip + return nil + } - if len(actual) == 0 { w.Event(progress.Event{ ID: fmt.Sprintf("Service %q", service.Name), Status: progress.Working, - StatusText: "Create", + StatusText: "Restart", Done: false, }) - name := fmt.Sprintf("%s_%s", project.Name, service.Name) - err = s.runContainer(ctx, project, service, name, nil) + err = s.containerService.Start(ctx, container.ID) if err != nil { return err } w.Event(progress.Event{ ID: fmt.Sprintf("Service %q", service.Name), Status: progress.Done, - StatusText: "Created", + StatusText: "Restarted", Done: true, }) - continue - } - - container := actual[0] - diverged := container.Labels["com.docker.compose.config-hash"] != expected - if diverged { - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Working, - StatusText: "Recreate", - Done: false, - }) - err := s.containerService.Stop(ctx, container.ID, nil) - if err != nil { - return err - } - name := getContainerName(container) - tmpName := fmt.Sprintf("%s_%s", container.ID[:12], name) - err = s.containerService.apiClient.ContainerRename(ctx, container.ID, tmpName) - if err != nil { - return err - } - err = s.runContainer(ctx, project, service, name, &container) - if err != nil { - return err - } - err = s.containerService.Delete(ctx, container.ID, containers.DeleteRequest{}) - if err != nil { - return err - } - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Done, - StatusText: "Recreated", - Done: true, - }) - continue - } - - if container.State == "running" { - // already running, skip - continue - } - - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Working, - StatusText: "Restart", - Done: false, - }) - err = s.containerService.Start(ctx, container.ID) - if err != nil { - return err - } - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Done, - StatusText: "Restarted", - Done: true, + return nil }) } - return nil + return eg.Wait() } func getContainerName(c moby.Container) string { @@ -193,7 +199,7 @@ func (s *local) runContainer(ctx context.Context, project *types.Project, servic if err != nil { return err } - for net, _ := range service.Networks { + for net := range service.Networks { name := fmt.Sprintf("%s_%s", project.Name, net) err = s.connectContainerToNetwork(ctx, id, service.Name, name) if err != nil { diff --git a/local/containers.go b/local/containers.go index debfd22e..67629405 100644 --- a/local/containers.go +++ b/local/containers.go @@ -26,6 +26,7 @@ import ( "time" "github.com/docker/docker/api/types/network" + v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" @@ -144,7 +145,10 @@ func (cs *containerService) Run(ctx context.Context, r containers.ContainerConfi } func (cs *containerService) create(ctx context.Context, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, name string) (string, error) { - created, err := cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, name) + created, err := cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, &v1.Platform{ + OS: "linux", + Architecture: "amd64", + }, name) if err != nil { if client.IsErrNotFound(err) { @@ -164,7 +168,10 @@ func (cs *containerService) create(ctx context.Context, containerConfig *contain if err = io.Close(); err != nil { return "", err } - created, err = cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, name) + created, err = cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, &v1.Platform{ + OS: "linux", + Architecture: "amd64", + }, name) if err != nil { return "", err } From 744aebc3fd4b2bd4f9d80b0a9675885ec5111fb9 Mon Sep 17 00:00:00 2001 From: Djordje Lukic Date: Mon, 16 Nov 2020 19:18:34 +0100 Subject: [PATCH 08/16] "Already exists" also means the pull finished Signed-off-by: Djordje Lukic --- local/compose.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local/compose.go b/local/compose.go index c45203a3..7bf41d31 100644 --- a/local/compose.go +++ b/local/compose.go @@ -263,7 +263,7 @@ func toProgressEvent(jm jsonmessage.JSONMessage, w progress.Writer) { StatusText: jm.Error.Message, Done: true, }) - } else if jm.Status == "Pull complete" { + } else if jm.Status == "Pull complete" || jm.Status == "Already exists" { w.Event(progress.Event{ ID: jm.ID, Text: jm.Status, From 8310bb2a91a3c0ea3f7082f9f5293f36c325acb3 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 17 Nov 2020 10:01:12 +0100 Subject: [PATCH 09/16] Create services in dependency order Signed-off-by: Nicolas De Loof --- local/compose.go | 222 +++++++++++++++++++------------------ local/dependencies.go | 60 ++++++++++ local/dependencies_test.go | 57 ++++++++++ 3 files changed, 233 insertions(+), 106 deletions(-) create mode 100644 local/dependencies.go create mode 100644 local/dependencies_test.go diff --git a/local/compose.go b/local/compose.go index 7bf41d31..260d2d14 100644 --- a/local/compose.go +++ b/local/compose.go @@ -28,7 +28,6 @@ import ( "sync" "github.com/opencontainers/go-digest" - "golang.org/x/sync/errgroup" "github.com/compose-spec/compose-go/types" "github.com/docker/compose-cli/api/compose" @@ -71,113 +70,115 @@ func (s *local) Up(ctx context.Context, project *types.Project, detach bool) err } } - w := progress.ContextWriter(ctx) - eg, ctx := errgroup.WithContext(ctx) for _, service := range project.Services { - service := service - eg.Go(func() error { - err := s.applyPullPolicy(ctx, service) - if err != nil { - return err - } - - actual, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ - Filters: filters.NewArgs( - filters.Arg("label", "com.docker.compose.project="+project.Name), - filters.Arg("label", "com.docker.compose.service="+service.Name), - ), - }) - if err != nil { - return err - } - - expected, err := jsonHash(s) - if err != nil { - return err - } - - if len(actual) == 0 { - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Working, - StatusText: "Create", - Done: false, - }) - name := fmt.Sprintf("%s_%s", project.Name, service.Name) - err = s.runContainer(ctx, project, service, name, nil) - if err != nil { - return err - } - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Done, - StatusText: "Created", - Done: true, - }) - return nil - } - - container := actual[0] - diverged := container.Labels["com.docker.compose.config-hash"] != expected - if diverged { - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Working, - StatusText: "Recreate", - Done: false, - }) - err := s.containerService.Stop(ctx, container.ID, nil) - if err != nil { - return err - } - name := getContainerName(container) - tmpName := fmt.Sprintf("%s_%s", container.ID[:12], name) - err = s.containerService.apiClient.ContainerRename(ctx, container.ID, tmpName) - if err != nil { - return err - } - err = s.runContainer(ctx, project, service, name, &container) - if err != nil { - return err - } - err = s.containerService.Delete(ctx, container.ID, containers.DeleteRequest{}) - if err != nil { - return err - } - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Done, - StatusText: "Recreated", - Done: true, - }) - return nil - } - - if container.State == "running" { - // already running, skip - return nil - } - - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Working, - StatusText: "Restart", - Done: false, - }) - err = s.containerService.Start(ctx, container.ID) - if err != nil { - return err - } - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Done, - StatusText: "Restarted", - Done: true, - }) - return nil - }) + err := s.applyPullPolicy(ctx, service) + if err != nil { + return err + } } - return eg.Wait() + + err := inDependencyOrder(ctx, project, func(service types.ServiceConfig) error { + return s.ensureService(ctx, project, service) + }) + return err +} + +func (s *local) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig) error { + actual, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + Filters: filters.NewArgs( + filters.Arg("label", "com.docker.compose.project="+project.Name), + filters.Arg("label", "com.docker.compose.service="+service.Name), + ), + }) + if err != nil { + return err + } + + expected, err := jsonHash(s) + if err != nil { + return err + } + + w := progress.ContextWriter(ctx) + if len(actual) == 0 { + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Create", + Done: false, + }) + name := fmt.Sprintf("%s_%s", project.Name, service.Name) + err = s.runContainer(ctx, project, service, name, nil) + if err != nil { + return err + } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Done, + StatusText: "Created", + Done: true, + }) + return nil + } + + container := actual[0] + diverged := container.Labels["com.docker.compose.config-hash"] != expected + if diverged { + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Recreate", + Done: false, + }) + err := s.containerService.Stop(ctx, container.ID, nil) + if err != nil { + return err + } + name := getContainerName(container) + tmpName := fmt.Sprintf("%s_%s", container.ID[:12], name) + err = s.containerService.apiClient.ContainerRename(ctx, container.ID, tmpName) + if err != nil { + return err + } + err = s.runContainer(ctx, project, service, name, &container) + if err != nil { + return err + } + err = s.containerService.Delete(ctx, container.ID, containers.DeleteRequest{}) + if err != nil { + return err + } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Done, + StatusText: "Recreated", + Done: true, + }) + return nil + } + + if container.State == "running" { + // already running, skip + return nil + } + + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Restart", + Done: false, + }) + err = s.containerService.Start(ctx, container.ID) + if err != nil { + return err + } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Done, + StatusText: "Restarted", + Done: true, + }) + return nil } func getContainerName(c moby.Container) string { @@ -711,3 +712,12 @@ func contains(slice []string, item string) bool { } return false } + +func containsAll(slice []string, items []string) bool { + for _, i := range items { + if !contains(slice, i) { + return false + } + } + return true +} \ No newline at end of file diff --git a/local/dependencies.go b/local/dependencies.go new file mode 100644 index 00000000..d26d1c3c --- /dev/null +++ b/local/dependencies.go @@ -0,0 +1,60 @@ +// +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 ( + "context" + "github.com/compose-spec/compose-go/types" + "golang.org/x/sync/errgroup" +) + +func inDependencyOrder(ctx context.Context, project *types.Project, fn func(types.ServiceConfig) error) error { + eg, ctx := errgroup.WithContext(ctx) + var ( + scheduled []string + ready []string + ) + results := make(chan string) + for len(ready) < len(project.Services) { + for _, service := range project.Services { + if contains(scheduled, service.Name) { + continue + } + if containsAll(ready, service.GetDependencies()) { + service := service + scheduled = append(scheduled, service.Name) + eg.Go(func() error { + err := fn(service) + if err != nil { + close(results) + return err + } + results <- service.Name + return nil + }) + } + } + result, ok := <-results + if !ok { + break + } + ready = append(ready, result) + } + return eg.Wait() +} diff --git a/local/dependencies_test.go b/local/dependencies_test.go new file mode 100644 index 00000000..035eda4e --- /dev/null +++ b/local/dependencies_test.go @@ -0,0 +1,57 @@ +// +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 ( + "context" + "gotest.tools/v3/assert" + "testing" + + "github.com/compose-spec/compose-go/types" +) + +func TestInDependencyOrder(t *testing.T) { + order := make(chan string) + project := types.Project{ + Services: []types.ServiceConfig{ + { + Name: "test1", + DependsOn: map[string]types.ServiceDependency{ + "test2": {}, + }, + }, + { + Name: "test2", + DependsOn: map[string]types.ServiceDependency{ + "test3": {}, + }, + }, + { + Name: "test3", + }, + }, + } + go inDependencyOrder(context.TODO(), &project, func(config types.ServiceConfig) error { + order <- config.Name + return nil + }) + assert.Equal(t, <- order, "test3") + assert.Equal(t, <- order, "test2") + assert.Equal(t, <- order, "test1") +} \ No newline at end of file From 6346db1d6f5b65f9fd6744e5de2c763068c4a425 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 17 Nov 2020 10:15:07 +0100 Subject: [PATCH 10/16] Move reconciliation logic into convergence.go Signed-off-by: Nicolas De Loof --- local/compose.go | 158 -------------------------------------- local/convergence.go | 178 +++++++++++++++++++++++++++++++++++++++++++ local/util.go | 50 ++++++++++++ 3 files changed, 228 insertions(+), 158 deletions(-) create mode 100644 local/convergence.go create mode 100644 local/util.go diff --git a/local/compose.go b/local/compose.go index 260d2d14..d63b262d 100644 --- a/local/compose.go +++ b/local/compose.go @@ -27,8 +27,6 @@ import ( "strings" "sync" - "github.com/opencontainers/go-digest" - "github.com/compose-spec/compose-go/types" "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/containers" @@ -83,104 +81,6 @@ func (s *local) Up(ctx context.Context, project *types.Project, detach bool) err return err } -func (s *local) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig) error { - actual, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ - Filters: filters.NewArgs( - filters.Arg("label", "com.docker.compose.project="+project.Name), - filters.Arg("label", "com.docker.compose.service="+service.Name), - ), - }) - if err != nil { - return err - } - - expected, err := jsonHash(s) - if err != nil { - return err - } - - w := progress.ContextWriter(ctx) - if len(actual) == 0 { - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Working, - StatusText: "Create", - Done: false, - }) - name := fmt.Sprintf("%s_%s", project.Name, service.Name) - err = s.runContainer(ctx, project, service, name, nil) - if err != nil { - return err - } - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Done, - StatusText: "Created", - Done: true, - }) - return nil - } - - container := actual[0] - diverged := container.Labels["com.docker.compose.config-hash"] != expected - if diverged { - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Working, - StatusText: "Recreate", - Done: false, - }) - err := s.containerService.Stop(ctx, container.ID, nil) - if err != nil { - return err - } - name := getContainerName(container) - tmpName := fmt.Sprintf("%s_%s", container.ID[:12], name) - err = s.containerService.apiClient.ContainerRename(ctx, container.ID, tmpName) - if err != nil { - return err - } - err = s.runContainer(ctx, project, service, name, &container) - if err != nil { - return err - } - err = s.containerService.Delete(ctx, container.ID, containers.DeleteRequest{}) - if err != nil { - return err - } - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Done, - StatusText: "Recreated", - Done: true, - }) - return nil - } - - if container.State == "running" { - // already running, skip - return nil - } - - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Working, - StatusText: "Restart", - Done: false, - }) - err = s.containerService.Start(ctx, container.ID) - if err != nil { - return err - } - w.Event(progress.Event{ - ID: fmt.Sprintf("Service %q", service.Name), - Status: progress.Done, - StatusText: "Restarted", - Done: true, - }) - return nil -} - func getContainerName(c moby.Container) string { // Names return container canonical name /foo + link aliases /linked_by/foo for _, name := range c.Names { @@ -191,29 +91,6 @@ func getContainerName(c moby.Container) string { return c.Names[0][1:] } -func (s *local) runContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, container *moby.Container) error { - containerConfig, hostConfig, networkingConfig, err := getContainerCreateOptions(project, service, container) - if err != nil { - return err - } - id, err := s.containerService.create(ctx, containerConfig, hostConfig, networkingConfig, name) - if err != nil { - return err - } - for net := range service.Networks { - name := fmt.Sprintf("%s_%s", project.Name, net) - err = s.connectContainerToNetwork(ctx, id, service.Name, name) - if err != nil { - return err - } - } - err = s.containerService.apiClient.ContainerStart(ctx, id, moby.ContainerStartOptions{}) - if err != nil { - return err - } - return nil -} - func (s *local) applyPullPolicy(ctx context.Context, service types.ServiceConfig) error { w := progress.ContextWriter(ctx) // TODO build vs pull should be controlled by pull policy @@ -657,15 +534,6 @@ func (s *local) ensureNetwork(ctx context.Context, n types.NetworkConfig) error return nil } -func (s *local) connectContainerToNetwork(ctx context.Context, id string, service string, n string) error { - err := s.containerService.apiClient.NetworkConnect(ctx, n, id, &network.EndpointSettings{ - Aliases: []string{service}, - }) - if err != nil { - return err - } - return nil -} func (s *local) ensureVolume(ctx context.Context, volume types.VolumeConfig) error { // TODO could identify volume by label vs name @@ -695,29 +563,3 @@ func (s *local) ensureVolume(ctx context.Context, volume types.VolumeConfig) err } return nil } - -func jsonHash(o interface{}) (string, error) { - bytes, err := json.Marshal(o) - if err != nil { - return "", nil - } - return digest.SHA256.FromBytes(bytes).String(), nil -} - -func contains(slice []string, item string) bool { - for _, v := range slice { - if v == item { - return true - } - } - return false -} - -func containsAll(slice []string, items []string) bool { - for _, i := range items { - if !contains(slice, i) { - return false - } - } - return true -} \ No newline at end of file diff --git a/local/convergence.go b/local/convergence.go new file mode 100644 index 00000000..b7c3494a --- /dev/null +++ b/local/convergence.go @@ -0,0 +1,178 @@ +// +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 ( + "context" + "fmt" + "github.com/docker/docker/api/types/network" + + "github.com/docker/compose-cli/api/containers" + "github.com/docker/compose-cli/progress" + + "github.com/compose-spec/compose-go/types" + moby "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" +) + +func (s *local) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig) error { + actual, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + Filters: filters.NewArgs( + filters.Arg("label", "com.docker.compose.project="+project.Name), + filters.Arg("label", "com.docker.compose.service="+service.Name), + ), + }) + if err != nil { + return err + } + + expected, err := jsonHash(service) + if err != nil { + return err + } + + if len(actual) == 0 { + return s.createContainer(ctx, project, service) + } + + container := actual[0] // TODO handle services with replicas + diverged := container.Labels["com.docker.compose.config-hash"] != expected + if diverged { + return s.recreateContainer(ctx, project, service, container) + } + + if container.State == "running" { + // already running, skip + return nil + } + + return s.restartContainer(ctx, service, container) +} + +func (s *local) createContainer(ctx context.Context, project *types.Project, service types.ServiceConfig) error { + w := progress.ContextWriter(ctx) + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Create", + Done: false, + }) + name := fmt.Sprintf("%s_%s", project.Name, service.Name) + err := s.runContainer(ctx, project, service, name, nil) + if err != nil { + return err + } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Done, + StatusText: "Created", + Done: true, + }) + return nil +} + +func (s *local) recreateContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, container moby.Container) error { + w := progress.ContextWriter(ctx) + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Recreate", + Done: false, + }) + err := s.containerService.Stop(ctx, container.ID, nil) + if err != nil { + return err + } + name := getContainerName(container) + tmpName := fmt.Sprintf("%s_%s", container.ID[:12], name) + err = s.containerService.apiClient.ContainerRename(ctx, container.ID, tmpName) + if err != nil { + return err + } + err = s.runContainer(ctx, project, service, name, &container) + if err != nil { + return err + } + err = s.containerService.Delete(ctx, container.ID, containers.DeleteRequest{}) + if err != nil { + return err + } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Done, + StatusText: "Recreated", + Done: true, + }) + return nil +} + +func (s *local) restartContainer(ctx context.Context, service types.ServiceConfig, container moby.Container) error { + w := progress.ContextWriter(ctx) + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Working, + StatusText: "Restart", + Done: false, + }) + err := s.containerService.Start(ctx, container.ID) + if err != nil { + return err + } + w.Event(progress.Event{ + ID: fmt.Sprintf("Service %q", service.Name), + Status: progress.Done, + StatusText: "Restarted", + Done: true, + }) + return nil +} + +func (s *local) runContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, container *moby.Container) error { + containerConfig, hostConfig, networkingConfig, err := getContainerCreateOptions(project, service, container) + if err != nil { + return err + } + id, err := s.containerService.create(ctx, containerConfig, hostConfig, networkingConfig, name) + if err != nil { + return err + } + for net := range service.Networks { + name := fmt.Sprintf("%s_%s", project.Name, net) + err = s.connectContainerToNetwork(ctx, id, service.Name, name) + if err != nil { + return err + } + } + err = s.containerService.apiClient.ContainerStart(ctx, id, moby.ContainerStartOptions{}) + if err != nil { + return err + } + return nil +} + + +func (s *local) connectContainerToNetwork(ctx context.Context, id string, service string, n string) error { + err := s.containerService.apiClient.NetworkConnect(ctx, n, id, &network.EndpointSettings{ + Aliases: []string{service}, + }) + if err != nil { + return err + } + return nil +} diff --git a/local/util.go b/local/util.go new file mode 100644 index 00000000..cabd257c --- /dev/null +++ b/local/util.go @@ -0,0 +1,50 @@ +// +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 ( + "encoding/json" + "github.com/opencontainers/go-digest" +) + +func jsonHash(o interface{}) (string, error) { + bytes, err := json.Marshal(o) + if err != nil { + return "", nil + } + return digest.SHA256.FromBytes(bytes).String(), nil +} + +func contains(slice []string, item string) bool { + for _, v := range slice { + if v == item { + return true + } + } + return false +} + +func containsAll(slice []string, items []string) bool { + for _, i := range items { + if !contains(slice, i) { + return false + } + } + return true +} From 9ec075baff459980bc486676151e9de0949364fa Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 17 Nov 2020 11:57:38 +0100 Subject: [PATCH 11/16] document public types Signed-off-by: Nicolas De Loof --- ecs/logs.go | 4 ++-- formatter/logs.go | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ecs/logs.go b/ecs/logs.go index 53658b78..5d9e9847 100644 --- a/ecs/logs.go +++ b/ecs/logs.go @@ -18,8 +18,9 @@ package ecs import ( "context" - "github.com/docker/compose-cli/formatter" "io" + + "github.com/docker/compose-cli/formatter" ) func (b *ecsAPIService) Logs(ctx context.Context, project string, w io.Writer) error { @@ -27,4 +28,3 @@ func (b *ecsAPIService) Logs(ctx context.Context, project string, w io.Writer) e err := b.aws.GetLogs(ctx, project, consumer.Log) return err } - diff --git a/formatter/logs.go b/formatter/logs.go index a9e28774..3f68b7a2 100644 --- a/formatter/logs.go +++ b/formatter/logs.go @@ -24,7 +24,7 @@ import ( "strings" ) - +// NewLogConsumer creates a new LogConsumer func NewLogConsumer(w io.Writer) LogConsumer { return LogConsumer{ colors: map[string]colorFunc{}, @@ -33,6 +33,7 @@ func NewLogConsumer(w io.Writer) LogConsumer { } } +// Log formats a log message as received from service/container func (l *LogConsumer) Log(service, container, message string) { cf, ok := l.colors[service] if !ok { @@ -48,11 +49,12 @@ func (l *LogConsumer) Log(service, container, message string) { } } +// GetWriter creates a io.Writer that will actually split by line and format by LogConsumer func (l *LogConsumer) GetWriter(service, container string) io.Writer { return splitBuffer{ - service: service, + service: service, container: container, - consumer: l, + consumer: l, } } @@ -66,13 +68,13 @@ func (l *LogConsumer) computeWidth() { l.width = width + 3 } +// LogConsumer consume logs from services and format them type LogConsumer struct { colors map[string]colorFunc width int writer io.Writer } - type splitBuffer struct { service string container string @@ -88,4 +90,3 @@ func (s splitBuffer) Write(b []byte) (n int, err error) { } return len(b), nil } - From 46cbb908fe3c76926ecd64feb68ee30dd571313f Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 17 Nov 2020 12:50:33 +0100 Subject: [PATCH 12/16] Target docker/docker 19.03 branch (api 1.40) Signed-off-by: Nicolas De Loof --- go.mod | 20 +++++--- go.sum | 113 +++++++++++++++++++------------------------- local/containers.go | 14 ++---- 3 files changed, 65 insertions(+), 82 deletions(-) diff --git a/go.mod b/go.mod index 74cbce54..21119c45 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,9 @@ go 1.15 // we need to create a new release tag for docker/distribution replace github.com/docker/distribution => github.com/docker/distribution v0.0.0-20200708230824-53e18a9d9bfe +// unix.SYS_IOCTL has been removed from golang/sys but still in use by docker/docker until 20.x +replace golang.org/x/sys => golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 + require ( github.com/AlecAivazis/survey/v2 v2.1.1 github.com/Azure/azure-sdk-for-go v43.3.0+incompatible @@ -18,22 +21,23 @@ require ( github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/Azure/go-autorest/autorest/validation v0.2.0 // indirect github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab + github.com/Microsoft/hcsshim v0.8.10 // indirect github.com/aws/aws-sdk-go v1.35.15 - github.com/awslabs/goformation/v4 v4.15.3 + github.com/awslabs/goformation/v4 v4.15.2 github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/compose-spec/compose-go v0.0.0-20201116112017-777513ca88e2 - github.com/containerd/console v1.0.1 + github.com/containerd/console v1.0.0 github.com/containerd/containerd v1.3.5 // indirect + github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a // indirect github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8 github.com/docker/distribution v0.0.0-00010101000000-000000000000 // indirect - github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible + github.com/docker/docker v17.12.0-ce-rc1.0.20200916142827-bd33bbf0497b+incompatible github.com/docker/docker-credential-helpers v0.6.3 // indirect github.com/docker/go-connections v0.4.0 github.com/docker/go-units v0.4.0 github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect github.com/gobwas/pool v0.2.0 // indirect github.com/gobwas/ws v1.0.4 - github.com/gogo/protobuf v1.3.1 // indirect github.com/golang/mock v1.4.4 github.com/golang/protobuf v1.4.3 github.com/google/go-cmp v0.5.3 @@ -45,10 +49,12 @@ require ( github.com/joho/godotenv v1.3.0 github.com/labstack/echo v3.3.10+incompatible github.com/labstack/gommon v0.3.0 // indirect - github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 + github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf github.com/morikuni/aec v1.0.0 + github.com/onsi/ginkgo v1.14.2 // indirect + github.com/onsi/gomega v1.10.2 // indirect github.com/opencontainers/go-digest v1.0.0 - github.com/opencontainers/image-spec v1.0.1 + github.com/opencontainers/runc v0.1.1 // indirect github.com/pkg/errors v0.9.1 github.com/prometheus/tsdb v0.10.0 github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b @@ -58,7 +64,7 @@ require ( github.com/stretchr/testify v1.6.1 github.com/valyala/fasttemplate v1.2.1 // indirect golang.org/x/mod v0.3.0 - golang.org/x/net v0.0.0-20201026091529-146b70c837a4 + golang.org/x/net v0.0.0-20200822124328-c89045814202 golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 google.golang.org/grpc v1.33.1 diff --git a/go.sum b/go.sum index 2cbc010e..abe7818e 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -81,6 +82,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab h1:9pygWVFqbY9lPxM0peffumuVDyMuIMzNLyO9uFjJuQo= github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/hcsshim v0.8.10 h1:k5wTrpnVU2/xv8ZuzGkbXVd3js5zJ8RnumPo5RxiIxU= +github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3HV0OhsddkmM= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -94,8 +97,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.35.15 h1:JdQNM8hJe+9N9xP53S54NDmX8GCaZn8CCJ4LBHfom4U= github.com/aws/aws-sdk-go v1.35.15/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= -github.com/awslabs/goformation/v4 v4.15.3 h1:zVRL+gAW5Xvyhd85KNsJpKaOuArxEyUYKK5+v13Bwrc= -github.com/awslabs/goformation/v4 v4.15.3/go.mod h1:wB5lKZf1J0MYH1Lt4B9w3opqz0uIjP7MMCAcib3QkwA= +github.com/awslabs/goformation/v4 v4.15.2 h1:sRfSdC1FnSBhsrz5G0XZZxapEtmJSlkNpnFQJf8ylfs= +github.com/awslabs/goformation/v4 v4.15.2/go.mod h1:GcJULxCJfloT+3pbqCluXftdEK2AD/UqpS3hkaaBntg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -118,23 +121,36 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/compose-spec/compose-go v0.0.0-20201116112017-777513ca88e2 h1:m6m0rnxmq3mPapGNAWqO6FLYg6GST7tJAAZqJ0pjadk= github.com/compose-spec/compose-go v0.0.0-20201116112017-777513ca88e2/go.mod h1:cZJ8y+zQzrYfN5XnEu/kMeDEP0V2D9ojF7Rb4nrneUc= -github.com/containerd/console v1.0.1 h1:u7SFAJyRqWcG6ogaMAx3KjSTy1e3hT9QxqX7Jco7dRc= -github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v1.0.0 h1:fU3UuQapBs+zLJu82NhR11Rif1ny2zfMMAyPJzSN5tQ= +github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.5 h1:l0iDHQtFwcOUmOvdepI6BB67q7beT6sRp2JYsfHS08c= github.com/containerd/containerd v1.3.5/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a h1:jEIoR0aA5GogXZ8pP3DUzE+zrhaF6/1rYZy+7KkYEWM= +github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a/go.mod h1:W0qIOTD7mp2He++YVq+kgfXezRYqzP1uDuMVH1bITDY= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -150,8 +166,8 @@ github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8 h1:JRquW4uqIU+eSilDhuo9 github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20200708230824-53e18a9d9bfe h1:pni13lAFm1g4cjHU6c3n4qGvvJGZQK4VvKRKMseQ42E= github.com/docker/distribution v0.0.0-20200708230824-53e18a9d9bfe/go.mod h1:Oqz4IonmMNc2N7GqfTL2xkhCQx0yS6nR+HrOZJnmKIk= -github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible h1:lwpV3629md5omgAKjxPWX17shI7vMRpE3nyb9WHn8pA= -github.com/docker/docker v20.10.0-beta1.0.20201113105859-b6bfff2a628f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v17.12.0-ce-rc1.0.20200916142827-bd33bbf0497b+incompatible h1:SiUATuP//KecDjpOK2tvZJgeScYAklvyjfK8JZlU6fo= +github.com/docker/docker v17.12.0-ce-rc1.0.20200916142827-bd33bbf0497b+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -163,6 +179,7 @@ github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHz github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -193,6 +210,7 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs= github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= @@ -300,6 +318,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U= github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= @@ -326,6 +345,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -372,8 +393,8 @@ github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8 github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mjibson/esc v0.2.0/go.mod h1:9Hw9gxxfHulMF5OJKCyhYD7PzlSdhzXyaGEBRPH1OPs= -github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 h1:SPoLlS9qUUnXcIY4pvA4CTwYjk0Is5f4UPEkeESr53k= -github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2/go.mod h1:TjQg8pa4iejrUrjiz0MCtMV38jdMNW4doKSiBrEvCQQ= +github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf h1:Un6PNx5oMK6CCwO3QTUyPiK2mtZnPrpDl5UnZ64eCkw= +github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -386,21 +407,28 @@ github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.5.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.2.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= -github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= +github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -425,6 +453,7 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -448,6 +477,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -461,11 +491,13 @@ github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -481,6 +513,7 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -577,6 +610,7 @@ golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -594,10 +628,6 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201026091529-146b70c837a4 h1:awiuzyrRjJDb+OXi9ceHO3SDxVoN3JER57mhtqkdQBs= -golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -618,54 +648,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2By golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -793,6 +777,7 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= diff --git a/local/containers.go b/local/containers.go index 67629405..84afccb3 100644 --- a/local/containers.go +++ b/local/containers.go @@ -25,12 +25,10 @@ import ( "strings" "time" - "github.com/docker/docker/api/types/network" - v1 "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" "github.com/docker/docker/pkg/stringid" @@ -145,10 +143,7 @@ func (cs *containerService) Run(ctx context.Context, r containers.ContainerConfi } func (cs *containerService) create(ctx context.Context, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, name string) (string, error) { - created, err := cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, &v1.Platform{ - OS: "linux", - Architecture: "amd64", - }, name) + created, err := cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, name) if err != nil { if client.IsErrNotFound(err) { @@ -168,10 +163,7 @@ func (cs *containerService) create(ctx context.Context, containerConfig *contain if err = io.Close(); err != nil { return "", err } - created, err = cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, &v1.Platform{ - OS: "linux", - Architecture: "amd64", - }, name) + created, err = cs.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, name) if err != nil { return "", err } From a701fd7601c260bc5212058ae7565d22b56c0057 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 17 Nov 2020 13:44:51 +0100 Subject: [PATCH 13/16] Negociate API version with docker engine Signed-off-by: Nicolas De Loof --- local/backend.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local/backend.go b/local/backend.go index 6fc5d08a..11f9ff49 100644 --- a/local/backend.go +++ b/local/backend.go @@ -41,7 +41,7 @@ func init() { } func service(ctx context.Context) (backend.Service, error) { - apiClient, err := client.NewClientWithOpts(client.FromEnv) + apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { return nil, err } From da99ad40d5530f93653a70fd9abaabff0676ca17 Mon Sep 17 00:00:00 2001 From: Guillaume Tardif Date: Tue, 17 Nov 2020 15:13:36 +0100 Subject: [PATCH 14/16] Fix logs (concurrent access to container.ID, logs was displaying the first container logs for every container) Signed-off-by: Guillaume Tardif --- local/compose.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/local/compose.go b/local/compose.go index d63b262d..3091d5f2 100644 --- a/local/compose.go +++ b/local/compose.go @@ -191,10 +191,11 @@ func (s *local) Logs(ctx context.Context, projectName string, w io.Writer) error consumer := formatter.NewLogConsumer(w) for _, c := range list { service := c.Labels["com.docker.compose.service"] + containerId := c.ID go func() { - s.containerService.Logs(ctx, c.ID, containers.LogsRequest{ + s.containerService.Logs(ctx,containerId, containers.LogsRequest{ Follow: true, - Writer: consumer.GetWriter(service, c.ID), + Writer: consumer.GetWriter(service, containerId), }) wg.Done() }() @@ -534,7 +535,6 @@ func (s *local) ensureNetwork(ctx context.Context, n types.NetworkConfig) error return nil } - func (s *local) ensureVolume(ctx context.Context, volume types.VolumeConfig) error { // TODO could identify volume by label vs name _, err := s.volumeService.Inspect(ctx, volume.Name) From 2278370ffa3fb1020e43206a56ea7e2faa61c974 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 17 Nov 2020 15:15:27 +0100 Subject: [PATCH 15/16] Handle service scale with container numbering Signed-off-by: Nicolas De Loof --- local/backend.go | 1 + local/compose.go | 46 +++++++++++++++--- local/convergence.go | 113 +++++++++++++++++++++++++++++++++---------- 3 files changed, 128 insertions(+), 32 deletions(-) diff --git a/local/backend.go b/local/backend.go index 11f9ff49..78d1195c 100644 --- a/local/backend.go +++ b/local/backend.go @@ -73,3 +73,4 @@ func (s *local) ResourceService() resources.Service { } + diff --git a/local/compose.go b/local/compose.go index 3091d5f2..5997134c 100644 --- a/local/compose.go +++ b/local/compose.go @@ -22,8 +22,10 @@ import ( "context" "encoding/json" "fmt" + "golang.org/x/sync/errgroup" "io" "path/filepath" + "strconv" "strings" "sync" @@ -169,13 +171,42 @@ func (s *local) Down(ctx context.Context, projectName string) error { if err != nil { return err } + + eg, ctx := errgroup.WithContext(ctx) + w := progress.ContextWriter(ctx) for _, c := range list { - err := s.containerService.Stop(ctx, c.ID, nil) - if err != nil { - return err - } + container := c + eg.Go(func() error { + w.Event(progress.Event{ + ID: getContainerName(container), + Text: "Stopping", + Status: progress.Working, + Done: false, + }) + err := s.containerService.Stop(ctx, container.ID, nil) + if err != nil { + return err + } + w.Event(progress.Event{ + ID: getContainerName(container), + Text: "Removing", + Status: progress.Working, + Done: false, + }) + err = s.containerService.Delete(ctx, container.ID, containers.DeleteRequest{}) + if err != nil { + return err + } + w.Event(progress.Event{ + ID: getContainerName(container), + Text: "Removed", + Status: progress.Done, + Done: true, + }) + return nil + }) } - return nil + return eg.Wait() } func (s *local) Logs(ctx context.Context, projectName string, w io.Writer) error { @@ -250,7 +281,7 @@ func (s *local) Convert(ctx context.Context, project *types.Project, format stri } } -func getContainerCreateOptions(p *types.Project, s types.ServiceConfig, inherit *moby.Container) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) { +func getContainerCreateOptions(p *types.Project, s types.ServiceConfig, number int, inherit *moby.Container) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) { hash, err := jsonHash(s) if err != nil { return nil, nil, nil, err @@ -259,6 +290,7 @@ func getContainerCreateOptions(p *types.Project, s types.ServiceConfig, inherit "com.docker.compose.project": p.Name, "com.docker.compose.service": s.Name, "com.docker.compose.config-hash": hash, + "com.docker.compose.container-number": strconv.Itoa(number), } var ( @@ -523,7 +555,7 @@ func (s *local) ensureNetwork(ctx context.Context, n types.NetworkConfig) error } w.Event(progress.Event{ ID: fmt.Sprintf("Network %q", n.Name), - Status: progress.Working, + Status: progress.Done, StatusText: "Created", Done: true, }) diff --git a/local/convergence.go b/local/convergence.go index b7c3494a..55ca3049 100644 --- a/local/convergence.go +++ b/local/convergence.go @@ -21,14 +21,14 @@ package local import ( "context" "fmt" - "github.com/docker/docker/api/types/network" - + "github.com/compose-spec/compose-go/types" "github.com/docker/compose-cli/api/containers" "github.com/docker/compose-cli/progress" - - "github.com/compose-spec/compose-go/types" moby "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/network" + "golang.org/x/sync/errgroup" + "strconv" ) func (s *local) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig) error { @@ -42,30 +42,90 @@ func (s *local) ensureService(ctx context.Context, project *types.Project, servi return err } + scale := getScale(service) + + eg, ctx := errgroup.WithContext(ctx) + if len(actual) < scale { + next, err := nextContainerNumber(actual) + if err != nil { + return err + } + missing := scale - len(actual) + for i := 0; i < missing; i++ { + number := next + i + name := fmt.Sprintf("%s_%s_%d", project.Name, service.Name, number) + eg.Go(func() error { + return s.createContainer(ctx, project, service, name, number) + }) + } + } + + if len(actual) > scale { + for i := scale; i < len(actual); i++ { + container := actual[i] + eg.Go(func() error { + err := s.containerService.Stop(ctx, container.ID, nil) + if err != nil { + return err + } + return s.containerService.Delete(ctx, container.ID, containers.DeleteRequest{}) + }) + } + actual = actual[:scale] + } + expected, err := jsonHash(service) if err != nil { return err } + for _, container := range actual { + container := container + diverged := container.Labels["com.docker.compose.config-hash"] != expected + if diverged { + eg.Go(func() error { + return s.recreateContainer(ctx, project, service, container) + }) + continue + } - if len(actual) == 0 { - return s.createContainer(ctx, project, service) + if container.State == "running" { + // already running, skip + continue + } + + eg.Go(func() error { + return s.restartContainer(ctx, service, container) + }) } - - container := actual[0] // TODO handle services with replicas - diverged := container.Labels["com.docker.compose.config-hash"] != expected - if diverged { - return s.recreateContainer(ctx, project, service, container) - } - - if container.State == "running" { - // already running, skip - return nil - } - - return s.restartContainer(ctx, service, container) + return eg.Wait() } -func (s *local) createContainer(ctx context.Context, project *types.Project, service types.ServiceConfig) error { +func nextContainerNumber(containers []moby.Container) (int, error) { + max := 0 + for _, c := range containers { + n, err := strconv.Atoi(c.Labels["com.docker.compose.container-number"]) + if err != nil { + return 0, err + } + if n > max { + max = n + } + } + return max + 1, nil + +} + +func getScale(config types.ServiceConfig) int { + if config.Deploy != nil && config.Deploy.Replicas != nil { + return int(*config.Deploy.Replicas) + } + if config.Scale != 0 { + return config.Scale + } + return 1 +} + +func (s *local) createContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, number int) error { w := progress.ContextWriter(ctx) w.Event(progress.Event{ ID: fmt.Sprintf("Service %q", service.Name), @@ -73,8 +133,7 @@ func (s *local) createContainer(ctx context.Context, project *types.Project, ser StatusText: "Create", Done: false, }) - name := fmt.Sprintf("%s_%s", project.Name, service.Name) - err := s.runContainer(ctx, project, service, name, nil) + err := s.runContainer(ctx, project, service, name, number, nil) if err != nil { return err } @@ -105,7 +164,11 @@ func (s *local) recreateContainer(ctx context.Context, project *types.Project, s if err != nil { return err } - err = s.runContainer(ctx, project, service, name, &container) + number, err := strconv.Atoi(container.Labels["com.docker.compose.container-number"]) + if err != nil { + return err + } + err = s.runContainer(ctx, project, service, name, number, &container) if err != nil { return err } @@ -143,8 +206,8 @@ func (s *local) restartContainer(ctx context.Context, service types.ServiceConfi return nil } -func (s *local) runContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, container *moby.Container) error { - containerConfig, hostConfig, networkingConfig, err := getContainerCreateOptions(project, service, container) +func (s *local) runContainer(ctx context.Context, project *types.Project, service types.ServiceConfig, name string, number int, container *moby.Container) error { + containerConfig, hostConfig, networkingConfig, err := getContainerCreateOptions(project, service, number, container) if err != nil { return err } From eb60bbb74f910a90c64c49ac1ccbf8fd2e5c4386 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 17 Nov 2020 15:56:39 +0100 Subject: [PATCH 16/16] define const for labels Signed-off-by: Nicolas De Loof --- local/compose.go | 19 ++++++++++--------- local/convergence.go | 10 +++++----- local/labels.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 local/labels.go diff --git a/local/compose.go b/local/compose.go index 5997134c..14dc3685 100644 --- a/local/compose.go +++ b/local/compose.go @@ -165,7 +165,7 @@ func toProgressEvent(jm jsonmessage.JSONMessage, w progress.Writer) { func (s *local) Down(ctx context.Context, projectName string) error { list, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs( - filters.Arg("label", "com.docker.compose.project="+projectName), + projectFilter(projectName), ), }) if err != nil { @@ -212,7 +212,7 @@ func (s *local) Down(ctx context.Context, projectName string) error { func (s *local) Logs(ctx context.Context, projectName string, w io.Writer) error { list, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs( - filters.Arg("label", "com.docker.compose.project="+projectName), + projectFilter(projectName), ), }) if err != nil { @@ -221,7 +221,7 @@ func (s *local) Logs(ctx context.Context, projectName string, w io.Writer) error var wg sync.WaitGroup consumer := formatter.NewLogConsumer(w) for _, c := range list { - service := c.Labels["com.docker.compose.service"] + service := c.Labels[serviceLabel] containerId := c.ID go func() { s.containerService.Logs(ctx,containerId, containers.LogsRequest{ @@ -239,7 +239,7 @@ func (s *local) Logs(ctx context.Context, projectName string, w io.Writer) error func (s *local) Ps(ctx context.Context, projectName string) ([]compose.ServiceStatus, error) { list, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs( - filters.Arg("label", "com.docker.compose.project="+projectName), + projectFilter(projectName), ), }) if err != nil { @@ -250,7 +250,7 @@ func (s *local) Ps(ctx context.Context, projectName string) ([]compose.ServiceSt // TODO group by service status = append(status, compose.ServiceStatus{ ID: c.ID, - Name: c.Labels["com.docker.compose.service"], + Name: c.Labels[serviceLabel], Replicas: 0, Desired: 0, Ports: nil, @@ -260,6 +260,7 @@ func (s *local) Ps(ctx context.Context, projectName string) ([]compose.ServiceSt return status, nil } + func (s *local) List(ctx context.Context, projectName string) ([]compose.Stack, error) { _, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{All: true}) if err != nil { @@ -287,10 +288,10 @@ func getContainerCreateOptions(p *types.Project, s types.ServiceConfig, number i return nil, nil, nil, err } labels := map[string]string{ - "com.docker.compose.project": p.Name, - "com.docker.compose.service": s.Name, - "com.docker.compose.config-hash": hash, - "com.docker.compose.container-number": strconv.Itoa(number), + projectLabel: p.Name, + serviceLabel: s.Name, + configHashLabel: hash, + containerNumberLabel: strconv.Itoa(number), } var ( diff --git a/local/convergence.go b/local/convergence.go index 55ca3049..cca0f966 100644 --- a/local/convergence.go +++ b/local/convergence.go @@ -34,8 +34,8 @@ import ( func (s *local) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig) error { actual, err := s.containerService.apiClient.ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs( - filters.Arg("label", "com.docker.compose.project="+project.Name), - filters.Arg("label", "com.docker.compose.service="+service.Name), + filters.Arg("label", fmt.Sprintf("%s=%s", projectLabel, project.Name)), + filters.Arg("label", fmt.Sprintf("%s=%s", serviceLabel, service.Name)), ), }) if err != nil { @@ -80,7 +80,7 @@ func (s *local) ensureService(ctx context.Context, project *types.Project, servi } for _, container := range actual { container := container - diverged := container.Labels["com.docker.compose.config-hash"] != expected + diverged := container.Labels[configHashLabel] != expected if diverged { eg.Go(func() error { return s.recreateContainer(ctx, project, service, container) @@ -103,7 +103,7 @@ func (s *local) ensureService(ctx context.Context, project *types.Project, servi func nextContainerNumber(containers []moby.Container) (int, error) { max := 0 for _, c := range containers { - n, err := strconv.Atoi(c.Labels["com.docker.compose.container-number"]) + n, err := strconv.Atoi(c.Labels[containerNumberLabel]) if err != nil { return 0, err } @@ -164,7 +164,7 @@ func (s *local) recreateContainer(ctx context.Context, project *types.Project, s if err != nil { return err } - number, err := strconv.Atoi(container.Labels["com.docker.compose.container-number"]) + number, err := strconv.Atoi(container.Labels[containerNumberLabel]) if err != nil { return err } diff --git a/local/labels.go b/local/labels.go new file mode 100644 index 00000000..29966b4d --- /dev/null +++ b/local/labels.go @@ -0,0 +1,35 @@ +// +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" + "github.com/docker/docker/api/types/filters" +) + +const ( + projectLabel = "com.docker.compose.project" + serviceLabel = "com.docker.compose.service" + configHashLabel = "com.docker.compose.config-hash" + containerNumberLabel = "com.docker.compose.container-number" +) + +func projectFilter(projectName string) filters.KeyValuePair { + return filters.Arg("label", fmt.Sprintf("%s=%s", projectLabel, projectName)) +} \ No newline at end of file