Skip to content

Commit b2b6a54

Browse files
yinonvcursoragent
andcommitted
refactor: migrate Docker integration to moby/moby/client
Replace the legacy github.com/docker/docker client packages with the new github.com/moby/moby/client (v2) API across the docker component, config, logs, network, runtime, and waiter, updating call sites to the new options-struct based signatures. Bump related dependencies in go.mod/go.sum. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 9e31812 commit b2b6a54

9 files changed

Lines changed: 166 additions & 181 deletions

File tree

cmd/envite/docker.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package main
77
import (
88
"encoding/json"
99
"fmt"
10-
"github.com/docker/docker/client"
10+
"github.com/moby/moby/client"
1111
"github.com/perimeterx/envite"
1212
"github.com/perimeterx/envite/docker"
1313
)

docker/component.go

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,11 @@ import (
1515
"sync/atomic"
1616
"time"
1717

18-
"github.com/docker/docker/api/types"
19-
"github.com/docker/docker/api/types/container"
20-
"github.com/docker/docker/api/types/filters"
21-
"github.com/docker/docker/api/types/image"
22-
"github.com/docker/docker/client"
23-
"github.com/docker/docker/errdefs"
24-
"github.com/docker/docker/pkg/jsonmessage"
25-
"github.com/docker/docker/pkg/stdcopy"
18+
cerrdefs "github.com/containerd/errdefs"
19+
"github.com/moby/moby/api/pkg/stdcopy"
20+
"github.com/moby/moby/api/types/container"
21+
"github.com/moby/moby/client"
22+
"github.com/moby/moby/api/types/jsonstream"
2623
"github.com/perimeterx/envite"
2724
)
2825

@@ -121,7 +118,11 @@ func (c *Component) Prepare(ctx context.Context) error {
121118

122119
// create a dedicated copy of the docker image to prevent
123120
// other environments running concurrently from removing our image.
124-
return c.cli.ImageTag(ctx, c.config.Image, c.imageCloneTag)
121+
_, err = c.cli.ImageTag(ctx, client.ImageTagOptions{
122+
Source: c.config.Image,
123+
Target: c.imageCloneTag,
124+
})
125+
return err
125126
}
126127

127128
// pullImage pulls the Docker image specified in the configuration.
@@ -144,7 +145,7 @@ func (c *Component) pullImage(ctx context.Context) error {
144145
scanner := bufio.NewScanner(reader)
145146
for scanner.Scan() {
146147
bytes := scanner.Bytes()
147-
msg := jsonmessage.JSONMessage{}
148+
msg := jsonstream.Message{}
148149
err = json.Unmarshal(bytes, &msg)
149150
if err != nil {
150151
return fmt.Errorf("failed to parse image pull output: %w", err)
@@ -191,17 +192,16 @@ func (c *Component) startContainer(ctx context.Context) (string, error) {
191192
defer c.lock.Unlock()
192193

193194
var id string
194-
res, err := c.cli.ContainerCreate(
195-
ctx,
196-
c.runConfig.containerConfig,
197-
c.runConfig.hostConfig,
198-
c.runConfig.networkingConfig,
199-
c.runConfig.platformConfig,
200-
c.containerName,
201-
)
195+
res, err := c.cli.ContainerCreate(ctx, client.ContainerCreateOptions{
196+
Config: c.runConfig.containerConfig,
197+
HostConfig: c.runConfig.hostConfig,
198+
NetworkingConfig: c.runConfig.networkingConfig,
199+
Platform: c.runConfig.platformConfig,
200+
Name: c.containerName,
201+
})
202202
if err == nil {
203203
id = res.ID
204-
} else if !errdefs.IsConflict(err) {
204+
} else if !cerrdefs.IsConflict(err) {
205205
return "", fmt.Errorf("failed to create container: %w", err)
206206
} else {
207207
cont, err := c.findContainer(ctx)
@@ -212,7 +212,7 @@ func (c *Component) startContainer(ctx context.Context) (string, error) {
212212
id = cont.ID
213213
}
214214

215-
err = c.cli.ContainerStart(context.Background(), id, container.StartOptions{})
215+
_, err = c.cli.ContainerStart(context.Background(), id, client.ContainerStartOptions{})
216216
if err != nil {
217217
return "", fmt.Errorf("failed to start container: %w", err)
218218
}
@@ -234,13 +234,13 @@ func (c *Component) Stop(ctx context.Context) error {
234234
return nil
235235
}
236236

237-
err = c.cli.ContainerStop(ctx, cont.ID, container.StopOptions{})
237+
_, err = c.cli.ContainerStop(ctx, cont.ID, client.ContainerStopOptions{})
238238
if err != nil {
239239
return err
240240
}
241241

242-
err = c.cli.ContainerRemove(ctx, cont.ID, container.RemoveOptions{Force: true})
243-
if err != nil && !errdefs.IsNotFound(err) && !errdefs.IsConflict(err) {
242+
_, err = c.cli.ContainerRemove(ctx, cont.ID, client.ContainerRemoveOptions{Force: true})
243+
if err != nil && !cerrdefs.IsNotFound(err) && !cerrdefs.IsConflict(err) {
244244
return err
245245
}
246246

@@ -261,7 +261,7 @@ func (c *Component) Cleanup(ctx context.Context) error {
261261
}
262262

263263
func (c *Component) removeImage(ctx context.Context) error {
264-
_, err := c.cli.ImageRemove(ctx, c.imageCloneTag, image.RemoveOptions{})
264+
_, err := c.cli.ImageRemove(ctx, c.imageCloneTag, client.ImageRemoveOptions{})
265265
if err != nil && !strings.Contains(err.Error(), "reference does not exist") && !strings.Contains(err.Error(), "No such image") {
266266
return err
267267
}
@@ -271,8 +271,8 @@ func (c *Component) removeImage(ctx context.Context) error {
271271
return nil
272272
}
273273

274-
_, err = c.cli.ImageRemove(ctx, c.config.Image, image.RemoveOptions{})
275-
if err != nil && !errdefs.IsNotFound(err) {
274+
_, err = c.cli.ImageRemove(ctx, c.config.Image, client.ImageRemoveOptions{})
275+
if err != nil && !cerrdefs.IsNotFound(err) {
276276
return err
277277
}
278278

@@ -289,7 +289,7 @@ func (c *Component) Status(context.Context) (envite.ComponentStatus, error) {
289289
return "", fmt.Errorf("failed to find container: %w", err)
290290
}
291291

292-
if cont == nil || cont.State != "running" {
292+
if cont == nil || cont.State != container.StateRunning {
293293
status = envite.ComponentStatusStopped
294294
c.status.Store(envite.ComponentStatusStopped)
295295
}
@@ -327,17 +327,16 @@ func (c *Component) Exec(ctx context.Context, cmd []string) (int, error) {
327327
}
328328

329329
c.Writer().WriteString(c.Writer().Color.Cyan(fmt.Sprintf("executing: %s", strings.Join(cmd, " "))))
330-
response, err := c.cli.ContainerExecCreate(ctx, cont.ID, container.ExecOptions{
330+
response, err := c.cli.ExecCreate(ctx, cont.ID, client.ExecCreateOptions{
331331
Cmd: cmd,
332-
Detach: false,
333332
AttachStdout: true,
334333
AttachStderr: true,
335334
})
336335
if err != nil {
337336
return 0, fmt.Errorf("failed to create exec: %w", err)
338337
}
339338

340-
hijack, err := c.cli.ContainerExecAttach(ctx, response.ID, container.ExecStartOptions{})
339+
hijack, err := c.cli.ExecAttach(ctx, response.ID, client.ExecAttachOptions{})
341340
if err != nil {
342341
return 0, fmt.Errorf("failed to attach exec: %w", err)
343342
}
@@ -349,7 +348,7 @@ func (c *Component) Exec(ctx context.Context, cmd []string) (int, error) {
349348

350349
hijack.Close()
351350

352-
execResp, err := c.cli.ContainerExecInspect(ctx, response.ID)
351+
execResp, err := c.cli.ExecInspect(ctx, response.ID, client.ExecInspectOptions{})
353352
if err != nil {
354353
return 0, fmt.Errorf("failed to inspect exec: %w", err)
355354
}
@@ -358,16 +357,16 @@ func (c *Component) Exec(ctx context.Context, cmd []string) (int, error) {
358357
return execResp.ExitCode, nil
359358
}
360359

361-
func (c *Component) findContainer(ctx context.Context) (*types.Container, error) {
362-
containers, err := c.cli.ContainerList(ctx, container.ListOptions{
360+
func (c *Component) findContainer(ctx context.Context) (*container.Summary, error) {
361+
listResult, err := c.cli.ContainerList(ctx, client.ContainerListOptions{
363362
All: true,
364-
Filters: filters.NewArgs(filters.Arg("name", c.containerName)),
363+
Filters: make(client.Filters).Add("name", c.containerName),
365364
})
366365
if err != nil {
367366
return nil, fmt.Errorf("failed to list containers: %w", err)
368367
}
369368

370-
for _, co := range containers {
369+
for _, co := range listResult.Items {
371370
if len(co.Names) > 0 && co.Names[0][1:] == c.containerName {
372371
return &co, nil
373372
}

docker/config.go

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,21 @@ package docker
66

77
import (
88
"fmt"
9-
"github.com/docker/docker/api/types"
10-
"github.com/docker/docker/api/types/blkiodev"
11-
"github.com/docker/docker/api/types/container"
12-
"github.com/docker/docker/api/types/image"
13-
"github.com/docker/docker/api/types/mount"
14-
"github.com/docker/docker/api/types/network"
15-
"github.com/docker/docker/api/types/strslice"
9+
"net/netip"
10+
"os"
11+
"strings"
12+
"time"
13+
1614
"github.com/docker/go-units"
15+
"github.com/moby/moby/api/types/blkiodev"
16+
"github.com/moby/moby/api/types/container"
17+
"github.com/moby/moby/api/types/mount"
18+
"github.com/moby/moby/api/types/network"
19+
"github.com/moby/moby/api/types/registry"
20+
"github.com/moby/moby/api/types/strslice"
21+
mobyclient "github.com/moby/moby/client"
1722
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
1823
"gopkg.in/yaml.v3"
19-
"os"
20-
"time"
2124
)
2225

2326
// Config represents Docker Component configuration
@@ -287,7 +290,7 @@ type ImagePullOptions struct {
287290

288291
// PrivilegeFunc - used for https://github.com/moby/moby/blob/v24.0.6/api/types/client.go#L281
289292
// available only via code, not available in config files
290-
PrivilegeFunc types.RequestPrivilegeFunc `json:"-"`
293+
PrivilegeFunc registry.RequestAuthConfig `json:"-"`
291294

292295
// Platform - used for https://github.com/moby/moby/blob/v24.0.6/api/types/client.go#L282
293296
Platform string `json:"platform,omitempty"`
@@ -643,30 +646,65 @@ func (c Config) initialize(network *Network, imageCloneTag string) (*runConfig,
643646
return result, nil
644647
}
645648

646-
func (c Config) imagePullOptions() (image.PullOptions, error) {
647-
result := image.PullOptions{}
649+
func (c Config) imagePullOptions() (mobyclient.ImagePullOptions, error) {
650+
result := mobyclient.ImagePullOptions{}
648651

649652
if c.ImagePullOptions != nil {
650653
var auth string
651654
if c.ImagePullOptions.RegistryAuthFunc != nil {
652655
var err error
653656
auth, err = c.ImagePullOptions.RegistryAuthFunc()
654657
if err != nil {
655-
return image.PullOptions{}, fmt.Errorf("failed to get registry auth: %w", err)
658+
return mobyclient.ImagePullOptions{}, fmt.Errorf("failed to get registry auth: %w", err)
656659
}
657660
} else {
658661
auth = c.ImagePullOptions.RegistryAuth
659662
}
660663

664+
platforms, err := parsePlatforms(c.ImagePullOptions.Platform)
665+
if err != nil {
666+
return mobyclient.ImagePullOptions{}, err
667+
}
668+
661669
result.All = c.ImagePullOptions.All
662670
result.RegistryAuth = auth
663671
result.PrivilegeFunc = c.ImagePullOptions.PrivilegeFunc
664-
result.Platform = c.ImagePullOptions.Platform
672+
result.Platforms = platforms
665673
}
666674

667675
return result, nil
668676
}
669677

678+
func parseDNSAddrs(addrs []string) []netip.Addr {
679+
result := make([]netip.Addr, 0, len(addrs))
680+
for _, addr := range addrs {
681+
parsed, err := netip.ParseAddr(addr)
682+
if err != nil {
683+
continue
684+
}
685+
result = append(result, parsed)
686+
}
687+
return result
688+
}
689+
690+
func parsePlatforms(platform string) ([]ocispec.Platform, error) {
691+
if platform == "" {
692+
return nil, nil
693+
}
694+
695+
parts := strings.Split(platform, "/")
696+
switch len(parts) {
697+
case 1:
698+
return []ocispec.Platform{{Architecture: parts[0]}}, nil
699+
case 2:
700+
return []ocispec.Platform{{OS: parts[0], Architecture: parts[1]}}, nil
701+
case 3:
702+
return []ocispec.Platform{{OS: parts[0], Architecture: parts[1], Variant: parts[2]}}, nil
703+
default:
704+
return nil, fmt.Errorf("invalid platform %q", platform)
705+
}
706+
}
707+
670708
func (c Config) containerConfig(imageCloneTag string) *container.Config {
671709
env := make([]string, 0, len(c.Env))
672710
for key, value := range c.Env {
@@ -693,7 +731,6 @@ func (c Config) containerConfig(imageCloneTag string) *container.Config {
693731
WorkingDir: c.WorkingDir,
694732
Entrypoint: strslice.StrSlice(c.Entrypoint),
695733
NetworkDisabled: c.NetworkDisabled,
696-
MacAddress: c.MacAddress,
697734
OnBuild: c.OnBuild,
698735
Labels: c.Labels,
699736
StopSignal: c.StopSignal,
@@ -734,7 +771,7 @@ func (c Config) hostConfig(network *Network) *container.HostConfig {
734771
CapAdd: strslice.StrSlice(c.CapAdd),
735772
CapDrop: strslice.StrSlice(c.CapDrop),
736773
CgroupnsMode: c.CgroupnsMode,
737-
DNS: c.DNS,
774+
DNS: parseDNSAddrs(c.DNS),
738775
DNSOptions: c.DNSOptions,
739776
DNSSearch: c.DNSSearch,
740777
ExtraHosts: c.ExtraHosts,
@@ -811,7 +848,6 @@ func (c *Resources) build() container.Resources {
811848
Devices: mapSlice(c.Devices, DeviceMapping.build),
812849
DeviceCgroupRules: c.DeviceCgroupRules,
813850
DeviceRequests: mapSlice(c.DeviceRequests, DeviceRequest.build),
814-
KernelMemoryTCP: c.KernelMemoryTCP,
815851
MemoryReservation: c.MemoryReservation,
816852
MemorySwap: c.MemorySwap,
817853
MemorySwappiness: c.MemorySwappiness,

docker/logs.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ package docker
77
import (
88
"bufio"
99
"context"
10-
"github.com/docker/docker/api/types/container"
11-
"github.com/docker/docker/client"
12-
"github.com/docker/docker/pkg/stdcopy"
10+
"github.com/moby/moby/api/pkg/stdcopy"
11+
"github.com/moby/moby/client"
1312
"strings"
1413
"time"
1514
)
@@ -18,7 +17,7 @@ type logHandler func(timestamp time.Time, text string, stream stdcopy.StdType) (
1817

1918
// followLogs attaches to container's output
2019
func followLogs(ctx context.Context, cli *client.Client, id string, handler logHandler) error {
21-
containerReader, err := cli.ContainerLogs(ctx, id, container.LogsOptions{
20+
containerReader, err := cli.ContainerLogs(ctx, id, client.ContainerLogsOptions{
2221
ShowStdout: true,
2322
ShowStderr: true,
2423
Timestamps: true,

0 commit comments

Comments
 (0)