From 6ed16a2cc1f0853f07e23490314458d7f44c3531 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 27 Oct 2025 20:48:23 +0100 Subject: [PATCH 1/2] vendor: github.com/moby/moby/api, moby/moby/client master Signed-off-by: Sebastiaan van Stijn --- cli/command/container/client_test.go | 40 ++++---- cli/command/container/kill.go | 6 +- cli/command/container/kill_test.go | 19 ++-- cli/command/container/pause.go | 6 +- cli/command/container/pause_test.go | 13 +-- cli/command/container/restart.go | 2 +- cli/command/container/restart_test.go | 14 +-- cli/command/container/rm.go | 3 +- cli/command/container/rm_test.go | 6 +- cli/command/container/run.go | 2 +- cli/command/container/run_test.go | 10 +- cli/command/container/signals.go | 5 +- cli/command/container/signals_test.go | 5 +- cli/command/container/signals_unix_test.go | 5 +- cli/command/container/start.go | 7 +- cli/command/container/stats_helpers.go | 5 +- cli/command/container/stop.go | 3 +- cli/command/container/stop_test.go | 6 +- cli/command/container/tty.go | 2 +- cli/command/container/unpause.go | 6 +- cli/command/image/build.go | 4 +- cli/command/image/build/context.go | 4 +- cli/command/service/progress/progress.go | 4 +- cli/command/service/progress/progress_test.go | 2 +- cli/command/swarm/progress/root_rotation.go | 4 +- vendor.mod | 4 +- vendor.sum | 8 +- .../moby/moby/api/types/container/stats.go | 78 ++++++++++++--- .../moby/moby/api/types/jsonstream/message.go | 15 +++ .../moby/moby/client/client_interfaces.go | 19 ++-- .../moby/moby/client/container_kill.go | 26 ++++- .../moby/moby/client/container_pause.go | 19 +++- .../moby/moby/client/container_remove.go | 14 ++- .../moby/moby/client/container_resize.go | 38 +++++--- .../moby/moby/client/container_restart.go | 32 ++++++- .../moby/moby/client/container_start.go | 16 +++- .../moby/moby/client/container_stats.go | 94 ++++++++++--------- .../moby/moby/client/container_stop.go | 18 +++- .../moby/moby/client/container_unpause.go | 19 +++- .../github.com/moby/moby/client/image_load.go | 23 ----- .../{api => client}/pkg/progress/progress.go | 0 .../pkg/progress/progressreader.go | 0 .../pkg/streamformatter/streamformatter.go | 29 +----- .../pkg/streamformatter/streamwriter.go | 4 +- vendor/modules.txt | 8 +- 45 files changed, 398 insertions(+), 249 deletions(-) create mode 100644 vendor/github.com/moby/moby/api/types/jsonstream/message.go rename vendor/github.com/moby/moby/{api => client}/pkg/progress/progress.go (100%) rename vendor/github.com/moby/moby/{api => client}/pkg/progress/progressreader.go (100%) rename vendor/github.com/moby/moby/{api => client}/pkg/streamformatter/streamformatter.go (81%) rename vendor/github.com/moby/moby/{api => client}/pkg/streamformatter/streamwriter.go (91%) diff --git a/cli/command/container/client_test.go b/cli/command/container/client_test.go index a9a55a6a7a..238e3190ac 100644 --- a/cli/command/container/client_test.go +++ b/cli/command/container/client_test.go @@ -15,7 +15,7 @@ type fakeClient struct { execInspectFunc func(execID string) (client.ExecInspectResult, error) execCreateFunc func(containerID string, options client.ExecCreateOptions) (client.ExecCreateResult, error) createContainerFunc func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) - containerStartFunc func(containerID string, options client.ContainerStartOptions) error + containerStartFunc func(containerID string, options client.ContainerStartOptions) (client.ContainerStartResult, error) imageCreateFunc func(ctx context.Context, parentReference string, options client.ImageCreateOptions) (client.ImageCreateResult, error) infoFunc func() (system.Info, error) containerStatPathFunc func(containerID, path string) (container.PathStat, error) @@ -25,16 +25,16 @@ type fakeClient struct { containerListFunc func(client.ContainerListOptions) ([]container.Summary, error) containerExportFunc func(string) (io.ReadCloser, error) containerExecResizeFunc func(id string, options client.ExecResizeOptions) (client.ExecResizeResult, error) - containerRemoveFunc func(ctx context.Context, containerID string, options client.ContainerRemoveOptions) error - containerRestartFunc func(ctx context.Context, containerID string, options client.ContainerStopOptions) error - containerStopFunc func(ctx context.Context, containerID string, options client.ContainerStopOptions) error - containerKillFunc func(ctx context.Context, containerID, signal string) error + containerRemoveFunc func(ctx context.Context, containerID string, options client.ContainerRemoveOptions) (client.ContainerRemoveResult, error) + containerRestartFunc func(ctx context.Context, containerID string, options client.ContainerRestartOptions) (client.ContainerRestartResult, error) + containerStopFunc func(ctx context.Context, containerID string, options client.ContainerStopOptions) (client.ContainerStopResult, error) + containerKillFunc func(ctx context.Context, containerID string, options client.ContainerKillOptions) (client.ContainerKillResult, error) containerPruneFunc func(ctx context.Context, options client.ContainerPruneOptions) (client.ContainerPruneResult, error) containerAttachFunc func(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.ContainerAttachResult, error) containerDiffFunc func(ctx context.Context, containerID string) (client.ContainerDiffResult, error) containerRenameFunc func(ctx context.Context, oldName, newName string) error containerCommitFunc func(ctx context.Context, container string, options client.ContainerCommitOptions) (client.ContainerCommitResult, error) - containerPauseFunc func(ctx context.Context, container string) error + containerPauseFunc func(ctx context.Context, container string, options client.ContainerPauseOptions) (client.ContainerPauseResult, error) Version string } @@ -77,11 +77,11 @@ func (f *fakeClient) ContainerCreate(_ context.Context, options client.Container return client.ContainerCreateResult{}, nil } -func (f *fakeClient) ContainerRemove(ctx context.Context, containerID string, options client.ContainerRemoveOptions) error { +func (f *fakeClient) ContainerRemove(ctx context.Context, containerID string, options client.ContainerRemoveOptions) (client.ContainerRemoveResult, error) { if f.containerRemoveFunc != nil { return f.containerRemoveFunc(ctx, containerID, options) } - return nil + return client.ContainerRemoveResult{}, nil } func (f *fakeClient) ImageCreate(ctx context.Context, parentReference string, options client.ImageCreateOptions) (client.ImageCreateResult, error) { @@ -130,11 +130,11 @@ func (f *fakeClient) ContainerWait(_ context.Context, containerID string, _ cont return nil, nil } -func (f *fakeClient) ContainerStart(_ context.Context, containerID string, options client.ContainerStartOptions) error { +func (f *fakeClient) ContainerStart(_ context.Context, containerID string, options client.ContainerStartOptions) (client.ContainerStartResult, error) { if f.containerStartFunc != nil { return f.containerStartFunc(containerID, options) } - return nil + return client.ContainerStartResult{}, nil } func (f *fakeClient) ContainerExport(_ context.Context, containerID string) (io.ReadCloser, error) { @@ -151,11 +151,11 @@ func (f *fakeClient) ExecResize(_ context.Context, id string, options client.Exe return client.ExecResizeResult{}, nil } -func (f *fakeClient) ContainerKill(ctx context.Context, containerID, signal string) error { +func (f *fakeClient) ContainerKill(ctx context.Context, containerID string, options client.ContainerKillOptions) (client.ContainerKillResult, error) { if f.containerKillFunc != nil { - return f.containerKillFunc(ctx, containerID, signal) + return f.containerKillFunc(ctx, containerID, options) } - return nil + return client.ContainerKillResult{}, nil } func (f *fakeClient) ContainersPrune(ctx context.Context, options client.ContainerPruneOptions) (client.ContainerPruneResult, error) { @@ -165,18 +165,18 @@ func (f *fakeClient) ContainersPrune(ctx context.Context, options client.Contain return client.ContainerPruneResult{}, nil } -func (f *fakeClient) ContainerRestart(ctx context.Context, containerID string, options client.ContainerStopOptions) error { +func (f *fakeClient) ContainerRestart(ctx context.Context, containerID string, options client.ContainerRestartOptions) (client.ContainerRestartResult, error) { if f.containerRestartFunc != nil { return f.containerRestartFunc(ctx, containerID, options) } - return nil + return client.ContainerRestartResult{}, nil } -func (f *fakeClient) ContainerStop(ctx context.Context, containerID string, options client.ContainerStopOptions) error { +func (f *fakeClient) ContainerStop(ctx context.Context, containerID string, options client.ContainerStopOptions) (client.ContainerStopResult, error) { if f.containerStopFunc != nil { return f.containerStopFunc(ctx, containerID, options) } - return nil + return client.ContainerStopResult{}, nil } func (f *fakeClient) ContainerAttach(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.ContainerAttachResult, error) { @@ -209,10 +209,10 @@ func (f *fakeClient) ContainerCommit(ctx context.Context, containerID string, op return client.ContainerCommitResult{}, nil } -func (f *fakeClient) ContainerPause(ctx context.Context, containerID string) error { +func (f *fakeClient) ContainerPause(ctx context.Context, containerID string, options client.ContainerPauseOptions) (client.ContainerPauseResult, error) { if f.containerPauseFunc != nil { - return f.containerPauseFunc(ctx, containerID) + return f.containerPauseFunc(ctx, containerID, options) } - return nil + return client.ContainerPauseResult{}, nil } diff --git a/cli/command/container/kill.go b/cli/command/container/kill.go index 1b2f7b34c7..368c35a4de 100644 --- a/cli/command/container/kill.go +++ b/cli/command/container/kill.go @@ -8,6 +8,7 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/completion" + "github.com/moby/moby/client" "github.com/spf13/cobra" ) @@ -47,7 +48,10 @@ func newKillCommand(dockerCLI command.Cli) *cobra.Command { func runKill(ctx context.Context, dockerCLI command.Cli, opts *killOptions) error { apiClient := dockerCLI.Client() errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, container string) error { - return apiClient.ContainerKill(ctx, container, opts.signal) + _, err := apiClient.ContainerKill(ctx, container, client.ContainerKillOptions{ + Signal: opts.signal, + }) + return err }) var errs []error diff --git a/cli/command/container/kill_test.go b/cli/command/container/kill_test.go index c5268dd4bc..fdaa2eb96f 100644 --- a/cli/command/container/kill_test.go +++ b/cli/command/container/kill_test.go @@ -8,19 +8,16 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/moby/moby/client" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) func TestRunKill(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ - containerKillFunc: func( - ctx context.Context, - container string, - signal string, - ) error { - assert.Assert(t, is.Equal(signal, "STOP")) - return nil + containerKillFunc: func(ctx context.Context, container string, options client.ContainerKillOptions) (client.ContainerKillResult, error) { + assert.Assert(t, is.Equal(options.Signal, "STOP")) + return client.ContainerKillResult{}, nil }, }) @@ -47,12 +44,8 @@ func TestRunKill(t *testing.T) { func TestRunKillClientError(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ - containerKillFunc: func( - ctx context.Context, - container string, - signal string, - ) error { - return fmt.Errorf("client error for container %s", container) + containerKillFunc: func(ctx context.Context, container string, options client.ContainerKillOptions) (client.ContainerKillResult, error) { + return client.ContainerKillResult{}, fmt.Errorf("client error for container %s", container) }, }) diff --git a/cli/command/container/pause.go b/cli/command/container/pause.go index a30f2d41a0..ede873bfb1 100644 --- a/cli/command/container/pause.go +++ b/cli/command/container/pause.go @@ -9,6 +9,7 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/completion" "github.com/moby/moby/api/types/container" + "github.com/moby/moby/client" "github.com/spf13/cobra" ) @@ -40,7 +41,10 @@ func newPauseCommand(dockerCLI command.Cli) *cobra.Command { func runPause(ctx context.Context, dockerCLI command.Cli, opts *pauseOptions) error { apiClient := dockerCLI.Client() - errChan := parallelOperation(ctx, opts.containers, apiClient.ContainerPause) + errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, container string) error { + _, err := apiClient.ContainerPause(ctx, container, client.ContainerPauseOptions{}) + return err + }) var errs []error for _, ctr := range opts.containers { diff --git a/cli/command/container/pause_test.go b/cli/command/container/pause_test.go index 04e4f40672..41619c1772 100644 --- a/cli/command/container/pause_test.go +++ b/cli/command/container/pause_test.go @@ -8,18 +8,13 @@ import ( "testing" "github.com/docker/cli/internal/test" + "github.com/moby/moby/client" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) func TestRunPause(t *testing.T) { - cli := test.NewFakeCli( - &fakeClient{ - containerPauseFunc: func(ctx context.Context, container string) error { - return nil - }, - }, - ) + cli := test.NewFakeCli(&fakeClient{}) cmd := newPauseCommand(cli) cmd.SetOut(io.Discard) @@ -41,8 +36,8 @@ func TestRunPause(t *testing.T) { func TestRunPauseClientError(t *testing.T) { cli := test.NewFakeCli( &fakeClient{ - containerPauseFunc: func(ctx context.Context, container string) error { - return fmt.Errorf("client error for container %s", container) + containerPauseFunc: func(ctx context.Context, container string, options client.ContainerPauseOptions) (client.ContainerPauseResult, error) { + return client.ContainerPauseResult{}, fmt.Errorf("client error for container %s", container) }, }, ) diff --git a/cli/command/container/restart.go b/cli/command/container/restart.go index c96396bd41..4aad94351f 100644 --- a/cli/command/container/restart.go +++ b/cli/command/container/restart.go @@ -66,7 +66,7 @@ func runRestart(ctx context.Context, dockerCLI command.Cli, opts *restartOptions var errs []error // TODO(thaJeztah): consider using parallelOperation for restart, similar to "stop" and "remove" for _, name := range opts.containers { - err := apiClient.ContainerRestart(ctx, name, client.ContainerStopOptions{ + _, err := apiClient.ContainerRestart(ctx, name, client.ContainerRestartOptions{ Signal: opts.signal, Timeout: timeout, }) diff --git a/cli/command/container/restart_test.go b/cli/command/container/restart_test.go index ed67c275d3..569571b717 100644 --- a/cli/command/container/restart_test.go +++ b/cli/command/container/restart_test.go @@ -19,7 +19,7 @@ func TestRestart(t *testing.T) { name string args []string restarted []string - expectedOpts client.ContainerStopOptions + expectedOpts client.ContainerRestartOptions expectedErr string }{ { @@ -36,19 +36,19 @@ func TestRestart(t *testing.T) { { name: "with -t", args: []string{"-t", "2", "container-1"}, - expectedOpts: client.ContainerStopOptions{Timeout: func(to int) *int { return &to }(2)}, + expectedOpts: client.ContainerRestartOptions{Timeout: func(to int) *int { return &to }(2)}, restarted: []string{"container-1"}, }, { name: "with --timeout", args: []string{"--timeout", "2", "container-1"}, - expectedOpts: client.ContainerStopOptions{Timeout: func(to int) *int { return &to }(2)}, + expectedOpts: client.ContainerRestartOptions{Timeout: func(to int) *int { return &to }(2)}, restarted: []string{"container-1"}, }, { name: "with --time", args: []string{"--time", "2", "container-1"}, - expectedOpts: client.ContainerStopOptions{Timeout: func(to int) *int { return &to }(2)}, + expectedOpts: client.ContainerRestartOptions{Timeout: func(to int) *int { return &to }(2)}, restarted: []string{"container-1"}, }, { @@ -62,17 +62,17 @@ func TestRestart(t *testing.T) { mutex := new(sync.Mutex) cli := test.NewFakeCli(&fakeClient{ - containerRestartFunc: func(ctx context.Context, containerID string, options client.ContainerStopOptions) error { + containerRestartFunc: func(ctx context.Context, containerID string, options client.ContainerRestartOptions) (client.ContainerRestartResult, error) { assert.Check(t, is.DeepEqual(options, tc.expectedOpts)) if containerID == "nosuchcontainer" { - return notFound(errors.New("Error: no such container: " + containerID)) + return client.ContainerRestartResult{}, notFound(errors.New("Error: no such container: " + containerID)) } // TODO(thaJeztah): consider using parallelOperation for restart, similar to "stop" and "remove" mutex.Lock() restarted = append(restarted, containerID) mutex.Unlock() - return nil + return client.ContainerRestartResult{}, nil }, Version: "1.36", }) diff --git a/cli/command/container/rm.go b/cli/command/container/rm.go index 1fd2bc61dd..8251f2a9dd 100644 --- a/cli/command/container/rm.go +++ b/cli/command/container/rm.go @@ -67,11 +67,12 @@ func runRm(ctx context.Context, dockerCLI command.Cli, opts *rmOptions) error { if ctrID == "" { return errors.New("container name cannot be empty") } - return apiClient.ContainerRemove(ctx, ctrID, client.ContainerRemoveOptions{ + _, err := apiClient.ContainerRemove(ctx, ctrID, client.ContainerRemoveOptions{ RemoveVolumes: opts.rmVolumes, RemoveLinks: opts.rmLink, Force: opts.force, }) + return err }) var errs []error diff --git a/cli/command/container/rm_test.go b/cli/command/container/rm_test.go index 75359fab7d..86f6c4e0a2 100644 --- a/cli/command/container/rm_test.go +++ b/cli/command/container/rm_test.go @@ -27,7 +27,7 @@ func TestRemoveForce(t *testing.T) { mutex := new(sync.Mutex) cli := test.NewFakeCli(&fakeClient{ - containerRemoveFunc: func(ctx context.Context, container string, options client.ContainerRemoveOptions) error { + containerRemoveFunc: func(ctx context.Context, container string, options client.ContainerRemoveOptions) (client.ContainerRemoveResult, error) { // containerRemoveFunc is called in parallel for each container // by the remove command so append must be synchronized. mutex.Lock() @@ -35,9 +35,9 @@ func TestRemoveForce(t *testing.T) { mutex.Unlock() if container == "nosuchcontainer" { - return notFound(errors.New("Error: no such container: " + container)) + return client.ContainerRemoveResult{}, notFound(errors.New("Error: no such container: " + container)) } - return nil + return client.ContainerRemoveResult{}, nil }, Version: "1.36", }) diff --git a/cli/command/container/run.go b/cli/command/container/run.go index 64836b0a97..1d7d56c08c 100644 --- a/cli/command/container/run.go +++ b/cli/command/container/run.go @@ -193,7 +193,7 @@ func runContainer(ctx context.Context, dockerCli command.Cli, runOpts *runOption statusChan := waitExitOrRemoved(statusCtx, apiClient, containerID, copts.autoRemove) // start the container - if err := apiClient.ContainerStart(ctx, containerID, client.ContainerStartOptions{}); err != nil { + if _, err := apiClient.ContainerStart(ctx, containerID, client.ContainerStartOptions{}); err != nil { // If we have hijackedIOStreamer, we should notify // hijackedIOStreamer we are going to exit and wait // to avoid the terminal are not restored. diff --git a/cli/command/container/run_test.go b/cli/command/container/run_test.go index 94f31d2c8e..a65491bd06 100644 --- a/cli/command/container/run_test.go +++ b/cli/command/container/run_test.go @@ -14,11 +14,11 @@ import ( "github.com/docker/cli/cli/streams" "github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test/notary" - "github.com/moby/moby/api/pkg/progress" - "github.com/moby/moby/api/pkg/streamformatter" "github.com/moby/moby/api/types" "github.com/moby/moby/api/types/container" "github.com/moby/moby/client" + "github.com/moby/moby/client/pkg/progress" + "github.com/moby/moby/client/pkg/streamformatter" "github.com/spf13/pflag" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" @@ -149,11 +149,11 @@ func TestRunAttachTermination(t *testing.T) { createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { return client.ContainerCreateResult{ID: "id"}, nil }, - containerKillFunc: func(ctx context.Context, containerID, sig string) error { - if sig == "TERM" { + containerKillFunc: func(ctx context.Context, container string, options client.ContainerKillOptions) (client.ContainerKillResult, error) { + if options.Signal == "TERM" { close(killCh) } - return nil + return client.ContainerKillResult{}, nil }, containerAttachFunc: func(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.ContainerAttachResult, error) { server, clientConn := net.Pipe() diff --git a/cli/command/container/signals.go b/cli/command/container/signals.go index 17d8e70440..3a98c19623 100644 --- a/cli/command/container/signals.go +++ b/cli/command/container/signals.go @@ -48,7 +48,10 @@ func ForwardAllSignals(ctx context.Context, apiClient client.ContainerAPIClient, continue } - if err := apiClient.ContainerKill(ctx, cid, sig); err != nil { + _, err := apiClient.ContainerKill(ctx, cid, client.ContainerKillOptions{ + Signal: sig, + }) + if err != nil { logrus.Debugf("Error sending signal: %s", err) } } diff --git a/cli/command/container/signals_test.go b/cli/command/container/signals_test.go index f6bb114122..f5e24c47dd 100644 --- a/cli/command/container/signals_test.go +++ b/cli/command/container/signals_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/moby/moby/client" "github.com/moby/sys/signal" ) @@ -14,9 +15,9 @@ func TestForwardSignals(t *testing.T) { defer cancel() called := make(chan struct{}) - apiClient := &fakeClient{containerKillFunc: func(ctx context.Context, container, signal string) error { + apiClient := &fakeClient{containerKillFunc: func(ctx context.Context, container string, options client.ContainerKillOptions) (client.ContainerKillResult, error) { close(called) - return nil + return client.ContainerKillResult{}, nil }} sigc := make(chan os.Signal) diff --git a/cli/command/container/signals_unix_test.go b/cli/command/container/signals_unix_test.go index f0d1868952..5ca8cb51dc 100644 --- a/cli/command/container/signals_unix_test.go +++ b/cli/command/container/signals_unix_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/moby/moby/client" "golang.org/x/sys/unix" "gotest.tools/v3/assert" ) @@ -22,9 +23,9 @@ func TestIgnoredSignals(t *testing.T) { defer cancel() var called bool - apiClient := &fakeClient{containerKillFunc: func(ctx context.Context, container, signal string) error { + apiClient := &fakeClient{containerKillFunc: func(ctx context.Context, container string, options client.ContainerKillOptions) (client.ContainerKillResult, error) { called = true - return nil + return client.ContainerKillResult{}, nil }} sigc := make(chan os.Signal) diff --git a/cli/command/container/start.go b/cli/command/container/start.go index e0a4fa20de..0973c51f80 100644 --- a/cli/command/container/start.go +++ b/cli/command/container/start.go @@ -145,7 +145,7 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er statusChan := waitExitOrRemoved(ctx, dockerCli.Client(), c.Container.ID, c.Container.HostConfig.AutoRemove) // 4. Start the container. - err = dockerCli.Client().ContainerStart(ctx, c.Container.ID, client.ContainerStartOptions{ + _, err = dockerCli.Client().ContainerStart(ctx, c.Container.ID, client.ContainerStartOptions{ CheckpointID: opts.Checkpoint, CheckpointDir: opts.CheckpointDir, }) @@ -183,10 +183,11 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er return errors.New("you cannot restore multiple containers at once") } ctr := opts.Containers[0] - return dockerCli.Client().ContainerStart(ctx, ctr, client.ContainerStartOptions{ + _, err := dockerCli.Client().ContainerStart(ctx, ctr, client.ContainerStartOptions{ CheckpointID: opts.Checkpoint, CheckpointDir: opts.CheckpointDir, }) + return err default: // We're not going to attach to anything. // Start as many containers as we want. @@ -197,7 +198,7 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er func startContainersWithoutAttachments(ctx context.Context, dockerCli command.Cli, containers []string) error { var failedContainers []string for _, ctr := range containers { - if err := dockerCli.Client().ContainerStart(ctx, ctr, client.ContainerStartOptions{}); err != nil { + if _, err := dockerCli.Client().ContainerStart(ctx, ctr, client.ContainerStartOptions{}); err != nil { _, _ = fmt.Fprintln(dockerCli.Err(), err) failedContainers = append(failedContainers, ctr) continue diff --git a/cli/command/container/stats_helpers.go b/cli/command/container/stats_helpers.go index 37b1964fd5..72e5c064cb 100644 --- a/cli/command/container/stats_helpers.go +++ b/cli/command/container/stats_helpers.go @@ -60,7 +60,10 @@ func collect(ctx context.Context, s *Stats, cli client.ContainerAPIClient, strea } }() - response, err := cli.ContainerStats(ctx, s.Container, streamStats) + response, err := cli.ContainerStats(ctx, s.Container, client.ContainerStatsOptions{ + Stream: streamStats, + IncludePreviousSample: !streamStats, // collect previous CPU value for the first result when not streaming. + }) if err != nil { s.SetError(err) return diff --git a/cli/command/container/stop.go b/cli/command/container/stop.go index 57a9fcbb86..0834d52f7e 100644 --- a/cli/command/container/stop.go +++ b/cli/command/container/stop.go @@ -64,10 +64,11 @@ func runStop(ctx context.Context, dockerCLI command.Cli, opts *stopOptions) erro apiClient := dockerCLI.Client() errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, id string) error { - return apiClient.ContainerStop(ctx, id, client.ContainerStopOptions{ + _, err := apiClient.ContainerStop(ctx, id, client.ContainerStopOptions{ Signal: opts.signal, Timeout: timeout, }) + return err }) var errs []error for _, ctr := range opts.containers { diff --git a/cli/command/container/stop_test.go b/cli/command/container/stop_test.go index abb075b132..ed7fc335e2 100644 --- a/cli/command/container/stop_test.go +++ b/cli/command/container/stop_test.go @@ -62,10 +62,10 @@ func TestStop(t *testing.T) { mutex := new(sync.Mutex) cli := test.NewFakeCli(&fakeClient{ - containerStopFunc: func(ctx context.Context, containerID string, options client.ContainerStopOptions) error { + containerStopFunc: func(ctx context.Context, containerID string, options client.ContainerStopOptions) (client.ContainerStopResult, error) { assert.Check(t, is.DeepEqual(options, tc.expectedOpts)) if containerID == "nosuchcontainer" { - return notFound(errors.New("Error: no such container: " + containerID)) + return client.ContainerStopResult{}, notFound(errors.New("Error: no such container: " + containerID)) } // containerStopFunc is called in parallel for each container @@ -73,7 +73,7 @@ func TestStop(t *testing.T) { mutex.Lock() stopped = append(stopped, containerID) mutex.Unlock() - return nil + return client.ContainerStopResult{}, nil }, Version: "1.36", }) diff --git a/cli/command/container/tty.go b/cli/command/container/tty.go index 66e5985c05..61908e1cc5 100644 --- a/cli/command/container/tty.go +++ b/cli/command/container/tty.go @@ -27,7 +27,7 @@ func resizeTTYTo(ctx context.Context, apiClient client.ContainerAPIClient, id st Width: width, }) } else { - err = apiClient.ContainerResize(ctx, id, client.ContainerResizeOptions{ + _, err = apiClient.ContainerResize(ctx, id, client.ContainerResizeOptions{ Height: height, Width: width, }) diff --git a/cli/command/container/unpause.go b/cli/command/container/unpause.go index 58493c1705..e18024b994 100644 --- a/cli/command/container/unpause.go +++ b/cli/command/container/unpause.go @@ -9,6 +9,7 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/completion" "github.com/moby/moby/api/types/container" + "github.com/moby/moby/client" "github.com/spf13/cobra" ) @@ -41,7 +42,10 @@ func newUnpauseCommand(dockerCLI command.Cli) *cobra.Command { func runUnpause(ctx context.Context, dockerCLI command.Cli, opts *unpauseOptions) error { apiClient := dockerCLI.Client() - errChan := parallelOperation(ctx, opts.containers, apiClient.ContainerUnpause) + errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, container string) error { + _, err := apiClient.ContainerUnpause(ctx, container, client.ContainerUnPauseOptions{}) + return err + }) var errs []error for _, ctr := range opts.containers { if err := <-errChan; err != nil { diff --git a/cli/command/image/build.go b/cli/command/image/build.go index 07b5628e19..9f4b25bac7 100644 --- a/cli/command/image/build.go +++ b/cli/command/image/build.go @@ -21,12 +21,12 @@ import ( "github.com/docker/cli/internal/jsonstream" "github.com/docker/cli/opts" "github.com/moby/go-archive" - "github.com/moby/moby/api/pkg/progress" - "github.com/moby/moby/api/pkg/streamformatter" buildtypes "github.com/moby/moby/api/types/build" "github.com/moby/moby/api/types/container" registrytypes "github.com/moby/moby/api/types/registry" "github.com/moby/moby/client" + "github.com/moby/moby/client/pkg/progress" + "github.com/moby/moby/client/pkg/streamformatter" "github.com/spf13/cobra" ) diff --git a/cli/command/image/build/context.go b/cli/command/image/build/context.go index 04c35dc1d9..2de860507c 100644 --- a/cli/command/image/build/context.go +++ b/cli/command/image/build/context.go @@ -20,8 +20,8 @@ import ( "github.com/docker/cli/cli/command/image/build/internal/git" "github.com/moby/go-archive" "github.com/moby/go-archive/compression" - "github.com/moby/moby/api/pkg/progress" - "github.com/moby/moby/api/pkg/streamformatter" + "github.com/moby/moby/client/pkg/progress" + "github.com/moby/moby/client/pkg/streamformatter" "github.com/moby/patternmatcher" ) diff --git a/cli/command/service/progress/progress.go b/cli/command/service/progress/progress.go index fb0bc30e99..a4de39b8fb 100644 --- a/cli/command/service/progress/progress.go +++ b/cli/command/service/progress/progress.go @@ -12,10 +12,10 @@ import ( "time" "github.com/docker/cli/cli/command/formatter" - "github.com/moby/moby/api/pkg/progress" - "github.com/moby/moby/api/pkg/streamformatter" "github.com/moby/moby/api/types/swarm" "github.com/moby/moby/client" + "github.com/moby/moby/client/pkg/progress" + "github.com/moby/moby/client/pkg/streamformatter" ) var ( diff --git a/cli/command/service/progress/progress_test.go b/cli/command/service/progress/progress_test.go index 133596c934..7cd7664e35 100644 --- a/cli/command/service/progress/progress_test.go +++ b/cli/command/service/progress/progress_test.go @@ -5,8 +5,8 @@ import ( "strconv" "testing" - "github.com/moby/moby/api/pkg/progress" "github.com/moby/moby/api/types/swarm" + "github.com/moby/moby/client/pkg/progress" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) diff --git a/cli/command/swarm/progress/root_rotation.go b/cli/command/swarm/progress/root_rotation.go index dfd299ef09..54e53e55d9 100644 --- a/cli/command/swarm/progress/root_rotation.go +++ b/cli/command/swarm/progress/root_rotation.go @@ -8,10 +8,10 @@ import ( "os/signal" "time" - "github.com/moby/moby/api/pkg/progress" - "github.com/moby/moby/api/pkg/streamformatter" "github.com/moby/moby/api/types/swarm" "github.com/moby/moby/client" + "github.com/moby/moby/client/pkg/progress" + "github.com/moby/moby/client/pkg/streamformatter" "github.com/opencontainers/go-digest" ) diff --git a/vendor.mod b/vendor.mod index 0c0b976a65..2130c01593 100644 --- a/vendor.mod +++ b/vendor.mod @@ -28,8 +28,8 @@ require ( github.com/google/uuid v1.6.0 github.com/mattn/go-runewidth v0.0.17 github.com/moby/go-archive v0.1.0 - github.com/moby/moby/api v1.52.0-beta.2.0.20251026152250-0a134ecc1623 // master - github.com/moby/moby/client v0.1.0-beta.2.0.20251026152250-0a134ecc1623 // master + github.com/moby/moby/api v1.52.0-beta.2.0.20251028144225-90109a373da9 // master + github.com/moby/moby/client v0.1.0-beta.2.0.20251028144225-90109a373da9 // master github.com/moby/patternmatcher v0.6.0 github.com/moby/swarmkit/v2 v2.1.0 github.com/moby/sys/atomicwriter v0.1.0 diff --git a/vendor.sum b/vendor.sum index b8186ee35f..55e213030e 100644 --- a/vendor.sum +++ b/vendor.sum @@ -170,10 +170,10 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= -github.com/moby/moby/api v1.52.0-beta.2.0.20251026152250-0a134ecc1623 h1:9Ulm1meUBVvvSDB65RmF7VymYBGmZ0peXCVWh6fzdoM= -github.com/moby/moby/api v1.52.0-beta.2.0.20251026152250-0a134ecc1623/go.mod h1:/ou52HkRydg4+odrUR3vFsGgjIyHvprrpEQEkweL10s= -github.com/moby/moby/client v0.1.0-beta.2.0.20251026152250-0a134ecc1623 h1:PkaM+LLZasetNAPJX0whFXr1GXjNQWMlyMEeUAeNUnE= -github.com/moby/moby/client v0.1.0-beta.2.0.20251026152250-0a134ecc1623/go.mod h1:sxVfwGqVgh7n+tdxA4gFToQ/lf+bM7zATnvQjVnsKT4= +github.com/moby/moby/api v1.52.0-beta.2.0.20251028144225-90109a373da9 h1:DDumCtiHK751YhrY/tbUdMo5BN8dRarxbW4ScVh/KZg= +github.com/moby/moby/api v1.52.0-beta.2.0.20251028144225-90109a373da9/go.mod h1:v0K/motq8oWmx+rtApG1rBTIpQ8KUONUjpf+U73gags= +github.com/moby/moby/client v0.1.0-beta.2.0.20251028144225-90109a373da9 h1:iAQD/kAfqMAb2p48advqXGOT8eWyEv+Xge7KbcsZduk= +github.com/moby/moby/client v0.1.0-beta.2.0.20251028144225-90109a373da9/go.mod h1:1YrJTvhL771Q4xiwwe72NSS17lgsCF67xu8fEfSd77g= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/swarmkit/v2 v2.1.0 h1:u+cJ5hSyF3HnzsyI+NtegYxdIPQIuibk7IbpXNxuISM= diff --git a/vendor/github.com/moby/moby/api/types/container/stats.go b/vendor/github.com/moby/moby/api/types/container/stats.go index 133bc35ecf..6a34f6ab76 100644 --- a/vendor/github.com/moby/moby/api/types/container/stats.go +++ b/vendor/github.com/moby/moby/api/types/container/stats.go @@ -149,24 +149,76 @@ type PidsStats struct { // StatsResponse aggregates all types of stats of one container. type StatsResponse struct { + // ID is the ID of the container for which the stats were collected. + ID string `json:"id,omitempty"` + + // Name is the name of the container for which the stats were collected. Name string `json:"name,omitempty"` - ID string `json:"id,omitempty"` - // Common stats - Read time.Time `json:"read"` - PreRead time.Time `json:"preread"` + // OSType is the OS of the container ("linux" or "windows") to allow + // platform-specific handling of stats. + OSType string `json:"os_type,omitempty"` - // Linux specific stats, not populated on Windows. - PidsStats PidsStats `json:"pids_stats,omitempty"` + // Read is the date and time at which this sample was collected. + Read time.Time `json:"read"` + + // CPUStats contains CPU related info of the container. + CPUStats CPUStats `json:"cpu_stats,omitempty"` + + // MemoryStats aggregates all memory stats since container inception on Linux. + // Windows returns stats for commit and private working set only. + MemoryStats MemoryStats `json:"memory_stats,omitempty"` + + // Networks contains Nntwork statistics for the container per interface. + // + // This field is omitted if the container has no networking enabled. + Networks map[string]NetworkStats `json:"networks,omitempty"` + + // ------------------------------------------------------------------------- + // Linux-specific stats, not populated on Windows. + // ------------------------------------------------------------------------- + + // PidsStats contains Linux-specific stats of a container's process-IDs (PIDs). + // + // This field is Linux-specific and omitted for Windows containers. + PidsStats PidsStats `json:"pids_stats,omitempty"` + + // BlkioStats stores all IO service stats for data read and write. + // + // This type is Linux-specific and holds many fields that are specific + // to cgroups v1. + // + // On a cgroup v2 host, all fields other than "io_service_bytes_recursive" + // are omitted or "null". + // + // This type is only populated on Linux and omitted for Windows containers. BlkioStats BlkioStats `json:"blkio_stats,omitempty"` - // Windows specific stats, not populated on Linux. - NumProcs uint32 `json:"num_procs"` + // ------------------------------------------------------------------------- + // Windows-specific stats, not populated on Linux. + // ------------------------------------------------------------------------- + + // NumProcs is the number of processors on the system. + // + // This field is Windows-specific and always zero for Linux containers. + NumProcs uint32 `json:"num_procs"` + + // StorageStats is the disk I/O stats for read/write on Windows. + // + // This type is Windows-specific and omitted for Linux containers. StorageStats StorageStats `json:"storage_stats,omitempty"` - // Shared stats - CPUStats CPUStats `json:"cpu_stats,omitempty"` - PreCPUStats CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous" - MemoryStats MemoryStats `json:"memory_stats,omitempty"` - Networks map[string]NetworkStats `json:"networks,omitempty"` + // ------------------------------------------------------------------------- + // PreRead and PreCPUStats contain the previous sample of stats for + // the container, and can be used to perform delta-calculation. + // ------------------------------------------------------------------------- + + // PreRead is the date and time at which this first sample was collected. + // This field is not propagated if the "one-shot" option is set. If the + // "one-shot" option is set, this field may be omitted, empty, or set + // to a default date (`0001-01-01T00:00:00Z`). + PreRead time.Time `json:"preread"` + + // PreCPUStats contains the CPUStats of the previous sample. + PreCPUStats CPUStats `json:"precpu_stats,omitempty"` } diff --git a/vendor/github.com/moby/moby/api/types/jsonstream/message.go b/vendor/github.com/moby/moby/api/types/jsonstream/message.go new file mode 100644 index 0000000000..2e1346d419 --- /dev/null +++ b/vendor/github.com/moby/moby/api/types/jsonstream/message.go @@ -0,0 +1,15 @@ +package jsonstream + +import "encoding/json" + +// JSONMessage defines a message struct. It describes +// the created time, where it from, status, ID of the +// message. It's used for docker events. +type Message struct { + Stream string `json:"stream,omitempty"` + Status string `json:"status,omitempty"` + Progress *Progress `json:"progressDetail,omitempty"` + ID string `json:"id,omitempty"` + Error *Error `json:"errorDetail,omitempty"` + Aux *json.RawMessage `json:"aux,omitempty"` // Aux contains out-of-band data, such as digests for push signing and image id after building. +} diff --git a/vendor/github.com/moby/moby/client/client_interfaces.go b/vendor/github.com/moby/moby/client/client_interfaces.go index d81ad71f88..9c69782e55 100644 --- a/vendor/github.com/moby/moby/client/client_interfaces.go +++ b/vendor/github.com/moby/moby/client/client_interfaces.go @@ -64,21 +64,20 @@ type ContainerAPIClient interface { ExecAPIClient ContainerExport(ctx context.Context, container string) (io.ReadCloser, error) ContainerInspect(ctx context.Context, container string, options ContainerInspectOptions) (ContainerInspectResult, error) - ContainerKill(ctx context.Context, container, signal string) error + ContainerKill(ctx context.Context, container string, options ContainerKillOptions) (ContainerKillResult, error) ContainerList(ctx context.Context, options ContainerListOptions) ([]container.Summary, error) ContainerLogs(ctx context.Context, container string, options ContainerLogsOptions) (io.ReadCloser, error) - ContainerPause(ctx context.Context, container string) error - ContainerRemove(ctx context.Context, container string, options ContainerRemoveOptions) error + ContainerPause(ctx context.Context, container string, options ContainerPauseOptions) (ContainerPauseResult, error) + ContainerRemove(ctx context.Context, container string, options ContainerRemoveOptions) (ContainerRemoveResult, error) ContainerRename(ctx context.Context, container, newContainerName string) error - ContainerResize(ctx context.Context, container string, options ContainerResizeOptions) error - ContainerRestart(ctx context.Context, container string, options ContainerStopOptions) error + ContainerResize(ctx context.Context, container string, options ContainerResizeOptions) (ContainerResizeResult, error) + ContainerRestart(ctx context.Context, container string, options ContainerRestartOptions) (ContainerRestartResult, error) ContainerStatPath(ctx context.Context, container, path string) (container.PathStat, error) - ContainerStats(ctx context.Context, container string, stream bool) (StatsResponseReader, error) - ContainerStatsOneShot(ctx context.Context, container string) (StatsResponseReader, error) - ContainerStart(ctx context.Context, container string, options ContainerStartOptions) error - ContainerStop(ctx context.Context, container string, options ContainerStopOptions) error + ContainerStats(ctx context.Context, container string, options ContainerStatsOptions) (ContainerStatsResult, error) + ContainerStart(ctx context.Context, container string, options ContainerStartOptions) (ContainerStartResult, error) + ContainerStop(ctx context.Context, container string, options ContainerStopOptions) (ContainerStopResult, error) ContainerTop(ctx context.Context, container string, arguments []string) (container.TopResponse, error) - ContainerUnpause(ctx context.Context, container string) error + ContainerUnpause(ctx context.Context, container string, options ContainerUnPauseOptions) (ContainerUnPauseResult, error) ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.UpdateResponse, error) ContainerWait(ctx context.Context, container string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error) CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, container.PathStat, error) diff --git a/vendor/github.com/moby/moby/client/container_kill.go b/vendor/github.com/moby/moby/client/container_kill.go index d198337fd9..ae7a4ebd8b 100644 --- a/vendor/github.com/moby/moby/client/container_kill.go +++ b/vendor/github.com/moby/moby/client/container_kill.go @@ -5,19 +5,35 @@ import ( "net/url" ) +// ContainerKillOptions holds options for [Client.ContainerKill]. +type ContainerKillOptions struct { + // Signal (optional) is the signal to send to the container to (gracefully) + // stop it before forcibly terminating the container with SIGKILL after a + // timeout. If no value is set, the default (SIGKILL) is used. + Signal string `json:",omitempty"` +} + +// ContainerKillResult holds the result of [Client.ContainerKill], +type ContainerKillResult struct { + // Add future fields here. +} + // ContainerKill terminates the container process but does not remove the container from the docker host. -func (cli *Client) ContainerKill(ctx context.Context, containerID, signal string) error { +func (cli *Client) ContainerKill(ctx context.Context, containerID string, options ContainerKillOptions) (ContainerKillResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return err + return ContainerKillResult{}, err } query := url.Values{} - if signal != "" { - query.Set("signal", signal) + if options.Signal != "" { + query.Set("signal", options.Signal) } resp, err := cli.post(ctx, "/containers/"+containerID+"/kill", query, nil, nil) defer ensureReaderClosed(resp) - return err + if err != nil { + return ContainerKillResult{}, err + } + return ContainerKillResult{}, nil } diff --git a/vendor/github.com/moby/moby/client/container_pause.go b/vendor/github.com/moby/moby/client/container_pause.go index c3488b9723..07669c8970 100644 --- a/vendor/github.com/moby/moby/client/container_pause.go +++ b/vendor/github.com/moby/moby/client/container_pause.go @@ -2,14 +2,27 @@ package client import "context" +// ContainerPauseOptions holds options for [Client.ContainerPause]. +type ContainerPauseOptions struct { + // Add future optional parameters here. +} + +// ContainerPauseResult holds the result of [Client.ContainerPause], +type ContainerPauseResult struct { + // Add future fields here. +} + // ContainerPause pauses the main process of a given container without terminating it. -func (cli *Client) ContainerPause(ctx context.Context, containerID string) error { +func (cli *Client) ContainerPause(ctx context.Context, containerID string, options ContainerPauseOptions) (ContainerPauseResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return err + return ContainerPauseResult{}, err } resp, err := cli.post(ctx, "/containers/"+containerID+"/pause", nil, nil, nil) defer ensureReaderClosed(resp) - return err + if err != nil { + return ContainerPauseResult{}, err + } + return ContainerPauseResult{}, nil } diff --git a/vendor/github.com/moby/moby/client/container_remove.go b/vendor/github.com/moby/moby/client/container_remove.go index e7f1794f86..0fbfa05fa1 100644 --- a/vendor/github.com/moby/moby/client/container_remove.go +++ b/vendor/github.com/moby/moby/client/container_remove.go @@ -12,11 +12,16 @@ type ContainerRemoveOptions struct { Force bool } +// ContainerRemoveResult holds the result of [Client.ContainerRemove], +type ContainerRemoveResult struct { + // Add future fields here. +} + // ContainerRemove kills and removes a container from the docker host. -func (cli *Client) ContainerRemove(ctx context.Context, containerID string, options ContainerRemoveOptions) error { +func (cli *Client) ContainerRemove(ctx context.Context, containerID string, options ContainerRemoveOptions) (ContainerRemoveResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return err + return ContainerRemoveResult{}, err } query := url.Values{} @@ -33,5 +38,8 @@ func (cli *Client) ContainerRemove(ctx context.Context, containerID string, opti resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil) defer ensureReaderClosed(resp) - return err + if err != nil { + return ContainerRemoveResult{}, err + } + return ContainerRemoveResult{}, nil } diff --git a/vendor/github.com/moby/moby/client/container_resize.go b/vendor/github.com/moby/moby/client/container_resize.go index 3111552549..311a9dcf5a 100644 --- a/vendor/github.com/moby/moby/client/container_resize.go +++ b/vendor/github.com/moby/moby/client/container_resize.go @@ -14,13 +14,28 @@ type ContainerResizeOptions struct { Width uint } +// ContainerResizeResult holds the result of [Client.ContainerResize], +type ContainerResizeResult struct { + // Add future fields here. +} + // ContainerResize changes the size of the pseudo-TTY for a container. -func (cli *Client) ContainerResize(ctx context.Context, containerID string, options ContainerResizeOptions) error { +func (cli *Client) ContainerResize(ctx context.Context, containerID string, options ContainerResizeOptions) (ContainerResizeResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return err + return ContainerResizeResult{}, err } - return cli.resize(ctx, "/containers/"+containerID, options.Height, options.Width) + // FIXME(thaJeztah): the API / backend accepts uint32, but container.ResizeOptions uses uint. + query := url.Values{} + query.Set("h", strconv.FormatUint(uint64(options.Height), 10)) + query.Set("w", strconv.FormatUint(uint64(options.Width), 10)) + + resp, err := cli.post(ctx, "/containers/"+containerID+"/resize", query, nil, nil) + defer ensureReaderClosed(resp) + if err != nil { + return ContainerResizeResult{}, err + } + return ContainerResizeResult{}, nil } // ExecResizeOptions holds options for resizing a container exec TTY. @@ -36,17 +51,16 @@ func (cli *Client) ExecResize(ctx context.Context, execID string, options ExecRe if err != nil { return ExecResizeResult{}, err } - err = cli.resize(ctx, "/exec/"+execID, options.Height, options.Width) - return ExecResizeResult{}, err -} - -func (cli *Client) resize(ctx context.Context, basePath string, height, width uint) error { // FIXME(thaJeztah): the API / backend accepts uint32, but container.ResizeOptions uses uint. query := url.Values{} - query.Set("h", strconv.FormatUint(uint64(height), 10)) - query.Set("w", strconv.FormatUint(uint64(width), 10)) + query.Set("h", strconv.FormatUint(uint64(options.Height), 10)) + query.Set("w", strconv.FormatUint(uint64(options.Width), 10)) - resp, err := cli.post(ctx, basePath+"/resize", query, nil, nil) + resp, err := cli.post(ctx, "/exec/"+execID+"/resize", query, nil, nil) defer ensureReaderClosed(resp) - return err + if err != nil { + return ExecResizeResult{}, err + } + return ExecResizeResult{}, nil + } diff --git a/vendor/github.com/moby/moby/client/container_restart.go b/vendor/github.com/moby/moby/client/container_restart.go index 872a986482..e883f75891 100644 --- a/vendor/github.com/moby/moby/client/container_restart.go +++ b/vendor/github.com/moby/moby/client/container_restart.go @@ -6,13 +6,36 @@ import ( "strconv" ) +// ContainerRestartOptions holds options for [Client.ContainerRestart]. +type ContainerRestartOptions struct { + // Signal (optional) is the signal to send to the container to (gracefully) + // stop it before forcibly terminating the container with SIGKILL after the + // timeout expires. If no value is set, the default (SIGTERM) is used. + Signal string `json:",omitempty"` + + // Timeout (optional) is the timeout (in seconds) to wait for the container + // to stop gracefully before forcibly terminating it with SIGKILL. + // + // - Use nil to use the default timeout (10 seconds). + // - Use '-1' to wait indefinitely. + // - Use '0' to not wait for the container to exit gracefully, and + // immediately proceeds to forcibly terminating the container. + // - Other positive values are used as timeout (in seconds). + Timeout *int `json:",omitempty"` +} + +// ContainerRestartResult holds the result of [Client.ContainerRestart], +type ContainerRestartResult struct { + // Add future fields here. +} + // ContainerRestart stops, and starts a container again. // It makes the daemon wait for the container to be up again for // a specific amount of time, given the timeout. -func (cli *Client) ContainerRestart(ctx context.Context, containerID string, options ContainerStopOptions) error { +func (cli *Client) ContainerRestart(ctx context.Context, containerID string, options ContainerRestartOptions) (ContainerRestartResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return err + return ContainerRestartResult{}, err } query := url.Values{} @@ -24,5 +47,8 @@ func (cli *Client) ContainerRestart(ctx context.Context, containerID string, opt } resp, err := cli.post(ctx, "/containers/"+containerID+"/restart", query, nil, nil) defer ensureReaderClosed(resp) - return err + if err != nil { + return ContainerRestartResult{}, err + } + return ContainerRestartResult{}, nil } diff --git a/vendor/github.com/moby/moby/client/container_start.go b/vendor/github.com/moby/moby/client/container_start.go index 7715900890..dfb821d1d1 100644 --- a/vendor/github.com/moby/moby/client/container_start.go +++ b/vendor/github.com/moby/moby/client/container_start.go @@ -5,17 +5,22 @@ import ( "net/url" ) -// ContainerStartOptions holds parameters to start containers. +// ContainerStartOptions holds options for [Client.ContainerStart]. type ContainerStartOptions struct { CheckpointID string CheckpointDir string } +// ContainerStartResult holds the result of [Client.ContainerStart], +type ContainerStartResult struct { + // Add future fields here. +} + // ContainerStart sends a request to the docker daemon to start a container. -func (cli *Client) ContainerStart(ctx context.Context, containerID string, options ContainerStartOptions) error { +func (cli *Client) ContainerStart(ctx context.Context, containerID string, options ContainerStartOptions) (ContainerStartResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return err + return ContainerStartResult{}, err } query := url.Values{} @@ -28,5 +33,8 @@ func (cli *Client) ContainerStart(ctx context.Context, containerID string, optio resp, err := cli.post(ctx, "/containers/"+containerID+"/start", query, nil, nil) defer ensureReaderClosed(resp) - return err + if err != nil { + return ContainerStartResult{}, err + } + return ContainerStartResult{}, nil } diff --git a/vendor/github.com/moby/moby/client/container_stats.go b/vendor/github.com/moby/moby/client/container_stats.go index d2493ed730..6a4b1c3b6c 100644 --- a/vendor/github.com/moby/moby/client/container_stats.go +++ b/vendor/github.com/moby/moby/client/container_stats.go @@ -6,62 +6,68 @@ import ( "net/url" ) -// StatsResponseReader wraps an [io.ReadCloser] to read (a stream of) stats -// for a container, as produced by the GET "/stats" endpoint. -// -// The OSType field is set to the server's platform to allow -// platform-specific handling of the response. -// -// TODO(thaJeztah): remove this wrapper, and make OSType part of [github.com/moby/moby/api/types/container.StatsResponse]. -type StatsResponseReader struct { - Body io.ReadCloser `json:"body"` - OSType string `json:"ostype"` +// ContainerStatsOptions holds parameters to retrieve container statistics +// using the [Client.ContainerStats] method. +type ContainerStatsOptions struct { + // Stream enables streaming [container.StatsResponse] results instead + // of collecting a single sample. If enabled, the client remains attached + // until the [ContainerStatsResult.Body] is closed or the context is + // cancelled. + Stream bool + + // IncludePreviousSample asks the daemon to collect a prior sample to populate the + // [container.StatsResponse.PreRead] and [container.StatsResponse.PreCPUStats] + // fields. + // + // It set, the daemon collects two samples at a one-second interval before + // returning the result. The first sample populates the PreCPUStats (“previous + // CPU”) field, allowing delta calculations for CPU usage. If false, only + // a single sample is taken and returned immediately, leaving PreRead and + // PreCPUStats empty. + // + // This option has no effect if Stream is enabled. If Stream is enabled, + // [container.StatsResponse.PreCPUStats] is never populated for the first + // record. + IncludePreviousSample bool } -// ContainerStats returns near realtime stats for a given container. -// It's up to the caller to close the [io.ReadCloser] returned. -func (cli *Client) ContainerStats(ctx context.Context, containerID string, stream bool) (StatsResponseReader, error) { +// ContainerStatsResult holds the result from [Client.ContainerStats]. +// +// It wraps an [io.ReadCloser] that provides one or more [container.StatsResponse] +// objects for a container, as produced by the "GET /containers/{id}/stats" endpoint. +// If streaming is disabled, the stream contains a single record. +type ContainerStatsResult struct { + Body io.ReadCloser +} + +// ContainerStats retrieves live resource usage statistics for the specified +// container. The caller must close the [io.ReadCloser] in the returned result +// to release associated resources. +func (cli *Client) ContainerStats(ctx context.Context, containerID string, options ContainerStatsOptions) (ContainerStatsResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return StatsResponseReader{}, err + return ContainerStatsResult{}, err } query := url.Values{} - query.Set("stream", "0") - if stream { - query.Set("stream", "1") + if options.Stream { + query.Set("stream", "true") + } else { + // Note: daemons before v29.0 return an error if both set: "cannot have stream=true and one-shot=true" + // + // TODO(thaJeztah): consider making "stream=false" the default for the API as well, or using Accept Header to switch. + query.Set("stream", "false") + if !options.IncludePreviousSample { + query.Set("one-shot", "true") + } } resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil) if err != nil { - return StatsResponseReader{}, err + return ContainerStatsResult{}, err } - return StatsResponseReader{ - Body: resp.Body, - OSType: resp.Header.Get("Ostype"), - }, nil -} - -// ContainerStatsOneShot gets a single stat entry from a container. -// It differs from `ContainerStats` in that the API should not wait to prime the stats -func (cli *Client) ContainerStatsOneShot(ctx context.Context, containerID string) (StatsResponseReader, error) { - containerID, err := trimID("container", containerID) - if err != nil { - return StatsResponseReader{}, err - } - - query := url.Values{} - query.Set("stream", "0") - query.Set("one-shot", "1") - - resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil) - if err != nil { - return StatsResponseReader{}, err - } - - return StatsResponseReader{ - Body: resp.Body, - OSType: resp.Header.Get("Ostype"), + return ContainerStatsResult{ + Body: resp.Body, }, nil } diff --git a/vendor/github.com/moby/moby/client/container_stop.go b/vendor/github.com/moby/moby/client/container_stop.go index 0dc542b603..d4d47d8fd4 100644 --- a/vendor/github.com/moby/moby/client/container_stop.go +++ b/vendor/github.com/moby/moby/client/container_stop.go @@ -6,11 +6,11 @@ import ( "strconv" ) -// ContainerStopOptions holds the options to stop or restart a container. +// ContainerStopOptions holds the options for [Client.ContainerStop]. type ContainerStopOptions struct { // Signal (optional) is the signal to send to the container to (gracefully) // stop it before forcibly terminating the container with SIGKILL after the - // timeout expires. If not value is set, the default (SIGTERM) is used. + // timeout expires. If no value is set, the default (SIGTERM) is used. Signal string `json:",omitempty"` // Timeout (optional) is the timeout (in seconds) to wait for the container @@ -24,6 +24,11 @@ type ContainerStopOptions struct { Timeout *int `json:",omitempty"` } +// ContainerStopResult holds the result of [Client.ContainerStop], +type ContainerStopResult struct { + // Add future fields here. +} + // ContainerStop stops a container. In case the container fails to stop // gracefully within a time frame specified by the timeout argument, // it is forcefully terminated (killed). @@ -31,10 +36,10 @@ type ContainerStopOptions struct { // If the timeout is nil, the container's StopTimeout value is used, if set, // otherwise the engine default. A negative timeout value can be specified, // meaning no timeout, i.e. no forceful termination is performed. -func (cli *Client) ContainerStop(ctx context.Context, containerID string, options ContainerStopOptions) error { +func (cli *Client) ContainerStop(ctx context.Context, containerID string, options ContainerStopOptions) (ContainerStopResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return err + return ContainerStopResult{}, err } query := url.Values{} @@ -46,5 +51,8 @@ func (cli *Client) ContainerStop(ctx context.Context, containerID string, option } resp, err := cli.post(ctx, "/containers/"+containerID+"/stop", query, nil, nil) defer ensureReaderClosed(resp) - return err + if err != nil { + return ContainerStopResult{}, err + } + return ContainerStopResult{}, nil } diff --git a/vendor/github.com/moby/moby/client/container_unpause.go b/vendor/github.com/moby/moby/client/container_unpause.go index edaf236c1f..4c37c774dd 100644 --- a/vendor/github.com/moby/moby/client/container_unpause.go +++ b/vendor/github.com/moby/moby/client/container_unpause.go @@ -2,14 +2,27 @@ package client import "context" +// ContainerUnPauseOptions holds options for [Client.ContainerUnpause]. +type ContainerUnPauseOptions struct { + // Add future optional parameters here. +} + +// ContainerUnPauseResult holds the result of [Client.ContainerUnpause], +type ContainerUnPauseResult struct { + // Add future fields here. +} + // ContainerUnpause resumes the process execution within a container. -func (cli *Client) ContainerUnpause(ctx context.Context, containerID string) error { +func (cli *Client) ContainerUnpause(ctx context.Context, containerID string, options ContainerUnPauseOptions) (ContainerUnPauseResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return err + return ContainerUnPauseResult{}, err } resp, err := cli.post(ctx, "/containers/"+containerID+"/unpause", nil, nil, nil) defer ensureReaderClosed(resp) - return err + if err != nil { + return ContainerUnPauseResult{}, err + } + return ContainerUnPauseResult{}, nil } diff --git a/vendor/github.com/moby/moby/client/image_load.go b/vendor/github.com/moby/moby/client/image_load.go index c52fd3f452..fab3098460 100644 --- a/vendor/github.com/moby/moby/client/image_load.go +++ b/vendor/github.com/moby/moby/client/image_load.go @@ -47,36 +47,13 @@ func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, loadOpts ...I } return ImageLoadResult{ body: resp.Body, - JSON: resp.Header.Get("Content-Type") == "application/json", }, nil } // ImageLoadResult returns information to the client about a load process. -// -// TODO(thaJeztah): remove this type, and just use an io.ReadCloser -// -// This type was added in https://github.com/moby/moby/pull/18878, related -// to https://github.com/moby/moby/issues/19177; -// -// Make docker load to output json when the response content type is json -// Swarm hijacks the response from docker load and returns JSON rather -// than plain text like the Engine does. This makes the API library to return -// information to figure that out. -// -// However the "load" endpoint unconditionally returns JSON; -// https://github.com/moby/moby/blob/7b9d2ef6e5518a3d3f3cc418459f8df786cfbbd1/api/server/router/image/image_routes.go#L248-L255 -// -// PR https://github.com/moby/moby/pull/21959 made the response-type depend -// on whether "quiet" was set, but this logic got changed in a follow-up -// https://github.com/moby/moby/pull/25557, which made the JSON response-type -// unconditionally, but the output produced depend on whether"quiet" was set. -// -// We should deprecated the "quiet" option, as it's really a client -// responsibility. type ImageLoadResult struct { // Body must be closed to avoid a resource leak body io.ReadCloser - JSON bool } func (r ImageLoadResult) Read(p []byte) (n int, err error) { diff --git a/vendor/github.com/moby/moby/api/pkg/progress/progress.go b/vendor/github.com/moby/moby/client/pkg/progress/progress.go similarity index 100% rename from vendor/github.com/moby/moby/api/pkg/progress/progress.go rename to vendor/github.com/moby/moby/client/pkg/progress/progress.go diff --git a/vendor/github.com/moby/moby/api/pkg/progress/progressreader.go b/vendor/github.com/moby/moby/client/pkg/progress/progressreader.go similarity index 100% rename from vendor/github.com/moby/moby/api/pkg/progress/progressreader.go rename to vendor/github.com/moby/moby/client/pkg/progress/progressreader.go diff --git a/vendor/github.com/moby/moby/api/pkg/streamformatter/streamformatter.go b/vendor/github.com/moby/moby/client/pkg/streamformatter/streamformatter.go similarity index 81% rename from vendor/github.com/moby/moby/api/pkg/streamformatter/streamformatter.go rename to vendor/github.com/moby/moby/client/pkg/streamformatter/streamformatter.go index a2fdd7efe6..9ad64af3fc 100644 --- a/vendor/github.com/moby/moby/api/pkg/streamformatter/streamformatter.go +++ b/vendor/github.com/moby/moby/client/pkg/streamformatter/streamformatter.go @@ -10,29 +10,10 @@ import ( "time" "github.com/docker/go-units" - "github.com/moby/moby/api/pkg/progress" "github.com/moby/moby/api/types/jsonstream" + "github.com/moby/moby/client/pkg/progress" ) -// jsonMessage defines a message struct. It describes -// the created time, where it from, status, ID of the -// message. It's used for docker events. -// -// It is a reduced set of [jsonmessage.JSONMessage]. -type jsonMessage struct { - Stream string `json:"stream,omitempty"` - Status string `json:"status,omitempty"` - Progress *jsonstream.Progress `json:"progressDetail,omitempty"` - ID string `json:"id,omitempty"` - Error *jsonstream.Error `json:"errorDetail,omitempty"` - Aux *json.RawMessage `json:"aux,omitempty"` // Aux contains out-of-band data, such as digests for push signing and image id after building. - - // ErrorMessage contains errors encountered during the operation. - // - // Deprecated: this field is deprecated since docker v0.6.0 / API v1.4. Use [Error.Message] instead. This field will be omitted in a future release. - ErrorMessage string `json:"error,omitempty"` // deprecated -} - const streamNewline = "\r\n" type jsonProgressFormatter struct{} @@ -44,7 +25,7 @@ func appendNewline(source []byte) []byte { // FormatStatus formats the specified objects according to the specified format (and id). func FormatStatus(id, format string, a ...any) []byte { str := fmt.Sprintf(format, a...) - b, err := json.Marshal(&jsonMessage{ID: id, Status: str}) + b, err := json.Marshal(&jsonstream.Message{ID: id, Status: str}) if err != nil { return FormatError(err) } @@ -57,7 +38,7 @@ func FormatError(err error) []byte { if !ok { jsonError = &jsonstream.Error{Message: err.Error()} } - if b, err := json.Marshal(&jsonMessage{Error: jsonError, ErrorMessage: err.Error()}); err == nil { + if b, err := json.Marshal(&jsonstream.Message{Error: jsonError}); err == nil { return appendNewline(b) } return []byte(`{"error":"format error"}` + streamNewline) @@ -81,7 +62,7 @@ func (sf *jsonProgressFormatter) formatProgress(id, action string, progress *jso auxJSON = new(json.RawMessage) *auxJSON = auxJSONBytes } - b, err := json.Marshal(&jsonMessage{ + b, err := json.Marshal(&jsonstream.Message{ Status: action, Progress: progress, ID: id, @@ -234,7 +215,7 @@ func (sf *AuxFormatter) Emit(id string, aux any) error { } auxJSON := new(json.RawMessage) *auxJSON = auxJSONBytes - msgJSON, err := json.Marshal(&jsonMessage{ID: id, Aux: auxJSON}) + msgJSON, err := json.Marshal(&jsonstream.Message{ID: id, Aux: auxJSON}) if err != nil { return err } diff --git a/vendor/github.com/moby/moby/api/pkg/streamformatter/streamwriter.go b/vendor/github.com/moby/moby/client/pkg/streamformatter/streamwriter.go similarity index 91% rename from vendor/github.com/moby/moby/api/pkg/streamformatter/streamwriter.go rename to vendor/github.com/moby/moby/client/pkg/streamformatter/streamwriter.go index a5f26d565c..544070bb9a 100644 --- a/vendor/github.com/moby/moby/api/pkg/streamformatter/streamwriter.go +++ b/vendor/github.com/moby/moby/client/pkg/streamformatter/streamwriter.go @@ -3,6 +3,8 @@ package streamformatter import ( "encoding/json" "io" + + "github.com/moby/moby/api/types/jsonstream" ) type streamWriter struct { @@ -20,7 +22,7 @@ func (sw *streamWriter) Write(buf []byte) (int, error) { } func (sw *streamWriter) format(buf []byte) []byte { - msg := &jsonMessage{Stream: sw.lineFormat(buf)} + msg := &jsonstream.Message{Stream: sw.lineFormat(buf)} b, err := json.Marshal(msg) if err != nil { return FormatError(err) diff --git a/vendor/modules.txt b/vendor/modules.txt index 17d259b0ed..569dfb4496 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -168,12 +168,10 @@ github.com/moby/docker-image-spec/specs-go/v1 github.com/moby/go-archive github.com/moby/go-archive/compression github.com/moby/go-archive/tarheader -# github.com/moby/moby/api v1.52.0-beta.2.0.20251026152250-0a134ecc1623 +# github.com/moby/moby/api v1.52.0-beta.2.0.20251028144225-90109a373da9 ## explicit; go 1.23.0 github.com/moby/moby/api/pkg/authconfig -github.com/moby/moby/api/pkg/progress github.com/moby/moby/api/pkg/stdcopy -github.com/moby/moby/api/pkg/streamformatter github.com/moby/moby/api/types github.com/moby/moby/api/types/auxprogress github.com/moby/moby/api/types/blkiodev @@ -192,13 +190,15 @@ github.com/moby/moby/api/types/storage github.com/moby/moby/api/types/swarm github.com/moby/moby/api/types/system github.com/moby/moby/api/types/volume -# github.com/moby/moby/client v0.1.0-beta.2.0.20251026152250-0a134ecc1623 +# github.com/moby/moby/client v0.1.0-beta.2.0.20251028144225-90109a373da9 ## explicit; go 1.23.0 github.com/moby/moby/client github.com/moby/moby/client/internal github.com/moby/moby/client/internal/timestamp github.com/moby/moby/client/pkg/jsonmessage +github.com/moby/moby/client/pkg/progress github.com/moby/moby/client/pkg/security +github.com/moby/moby/client/pkg/streamformatter github.com/moby/moby/client/pkg/stringid github.com/moby/moby/client/pkg/versions # github.com/moby/patternmatcher v0.6.0 From 83319f09f7a0565b4c5c64f4a2cf7458ee37c96f Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 27 Oct 2025 16:29:47 +0100 Subject: [PATCH 2/2] cli/command/container: use per-stats OSType if present Signed-off-by: Sebastiaan van Stijn --- cli/command/container/stats.go | 2 ++ cli/command/container/stats_helpers.go | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/cli/command/container/stats.go b/cli/command/container/stats.go index 84ca3d72d4..e6aaa24e0b 100644 --- a/cli/command/container/stats.go +++ b/cli/command/container/stats.go @@ -109,6 +109,8 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions) apiClient := dockerCLI.Client() // Get the daemonOSType to handle platform-specific stats fields. + // This value is used as a fallback for docker < v29, which did not + // include the OSType field per stats. daemonOSType = dockerCLI.ServerInfo().OSType // waitFirst is a WaitGroup to wait first stat data's reach for each container diff --git a/cli/command/container/stats_helpers.go b/cli/command/container/stats_helpers.go index 72e5c064cb..4f7c746be2 100644 --- a/cli/command/container/stats_helpers.go +++ b/cli/command/container/stats_helpers.go @@ -88,6 +88,12 @@ func collect(ctx context.Context, s *Stats, cli client.ContainerAPIClient, strea continue } + // Daemon versions before v29 did not return per-stats OSType; + // fall back to using the daemon's OSType. + if v.OSType == "" { + v.OSType = daemonOSType + } + if daemonOSType == "windows" { netRx, netTx := calculateNetwork(v.Networks) s.SetStatistics(StatsEntry{