1
0
mirror of https://github.com/docker/cli.git synced 2026-01-06 05:41:44 +03:00

vendor: github.com/moby/moby/api, moby/moby/client master

Signed-off-by: Rob Murray <rob.murray@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Rob Murray
2025-10-26 16:45:58 +00:00
committed by Sebastiaan van Stijn
parent 965a0e3518
commit 4a608069a7
19 changed files with 166 additions and 122 deletions

View File

@@ -23,21 +23,21 @@ type AttachOptions struct {
}
func inspectContainerAndCheckState(ctx context.Context, apiClient client.APIClient, args string) (*container.InspectResponse, error) {
c, err := apiClient.ContainerInspect(ctx, args)
c, err := apiClient.ContainerInspect(ctx, args, client.ContainerInspectOptions{})
if err != nil {
return nil, err
}
if !c.State.Running {
if !c.Container.State.Running {
return nil, errors.New("cannot attach to a stopped container, start it first")
}
if c.State.Paused {
if c.Container.State.Paused {
return nil, errors.New("cannot attach to a paused container, unpause it first")
}
if c.State.Restarting {
if c.Container.State.Restarting {
return nil, errors.New("cannot attach to a restarting container, wait until it is running")
}
return &c, nil
return &c.Container, nil
}
// newAttachCommand creates a new cobra.Command for `docker attach`

View File

@@ -8,6 +8,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/internal/test"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/client"
"gotest.tools/v3/assert"
)
@@ -16,24 +17,26 @@ func TestNewAttachCommandErrors(t *testing.T) {
name string
args []string
expectedError string
containerInspectFunc func(img string) (container.InspectResponse, error)
containerInspectFunc func(img string) (client.ContainerInspectResult, error)
}{
{
name: "client-error",
args: []string{"5cb5bb5e4a3b"},
expectedError: "something went wrong",
containerInspectFunc: func(containerID string) (container.InspectResponse, error) {
return container.InspectResponse{}, errors.New("something went wrong")
containerInspectFunc: func(containerID string) (client.ContainerInspectResult, error) {
return client.ContainerInspectResult{}, errors.New("something went wrong")
},
},
{
name: "client-stopped",
args: []string{"5cb5bb5e4a3b"},
expectedError: "cannot attach to a stopped container",
containerInspectFunc: func(containerID string) (container.InspectResponse, error) {
return container.InspectResponse{
State: &container.State{
Running: false,
containerInspectFunc: func(containerID string) (client.ContainerInspectResult, error) {
return client.ContainerInspectResult{
Container: container.InspectResponse{
State: &container.State{
Running: false,
},
},
}, nil
},
@@ -42,11 +45,13 @@ func TestNewAttachCommandErrors(t *testing.T) {
name: "client-paused",
args: []string{"5cb5bb5e4a3b"},
expectedError: "cannot attach to a paused container",
containerInspectFunc: func(containerID string) (container.InspectResponse, error) {
return container.InspectResponse{
State: &container.State{
Running: true,
Paused: true,
containerInspectFunc: func(containerID string) (client.ContainerInspectResult, error) {
return client.ContainerInspectResult{
Container: container.InspectResponse{
State: &container.State{
Running: true,
Paused: true,
},
},
}, nil
},
@@ -55,12 +60,14 @@ func TestNewAttachCommandErrors(t *testing.T) {
name: "client-restarting",
args: []string{"5cb5bb5e4a3b"},
expectedError: "cannot attach to a restarting container",
containerInspectFunc: func(containerID string) (container.InspectResponse, error) {
return container.InspectResponse{
State: &container.State{
Running: true,
Paused: false,
Restarting: true,
containerInspectFunc: func(containerID string) (client.ContainerInspectResult, error) {
return client.ContainerInspectResult{
Container: container.InspectResponse{
State: &container.State{
Running: true,
Paused: false,
Restarting: true,
},
},
}, nil
},

View File

@@ -11,7 +11,7 @@ import (
type fakeClient struct {
client.Client
inspectFunc func(string) (container.InspectResponse, error)
inspectFunc func(string) (client.ContainerInspectResult, error)
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)
@@ -45,11 +45,11 @@ func (f *fakeClient) ContainerList(_ context.Context, options client.ContainerLi
return []container.Summary{}, nil
}
func (f *fakeClient) ContainerInspect(_ context.Context, containerID string) (container.InspectResponse, error) {
func (f *fakeClient) ContainerInspect(_ context.Context, containerID string, options client.ContainerInspectOptions) (client.ContainerInspectResult, error) {
if f.inspectFunc != nil {
return f.inspectFunc(containerID)
}
return container.InspectResponse{}, nil
return client.ContainerInspectResult{}, nil
}
func (f *fakeClient) ExecCreate(_ context.Context, containerID string, config client.ExecCreateOptions) (client.ExecCreateResult, error) {

View File

@@ -97,7 +97,7 @@ func RunExec(ctx context.Context, dockerCLI command.Cli, containerIDorName strin
// otherwise if we error out we will leak execIDs on the server (and
// there's no easy way to clean those up). But also in order to make "not
// exist" errors take precedence we do a dummy inspect first.
if _, err := apiClient.ContainerInspect(ctx, containerIDorName); err != nil {
if _, err := apiClient.ContainerInspect(ctx, containerIDorName, client.ContainerInspectOptions{}); err != nil {
return err
}
if !options.Detach {
@@ -119,10 +119,17 @@ func RunExec(ctx context.Context, dockerCLI command.Cli, containerIDorName strin
}
if options.Detach {
var cs client.ConsoleSize
if execOptions.ConsoleSize != nil {
cs = client.ConsoleSize{
Height: execOptions.ConsoleSize[0],
Width: execOptions.ConsoleSize[1],
}
}
_, err := apiClient.ExecStart(ctx, execID, client.ExecStartOptions{
Detach: options.Detach,
Tty: execOptions.Tty,
ConsoleSize: execOptions.ConsoleSize,
TTY: execOptions.Tty,
ConsoleSize: cs,
})
return err
}
@@ -159,9 +166,16 @@ func interactiveExec(ctx context.Context, dockerCli command.Cli, execOptions *cl
fillConsoleSize(execOptions, dockerCli)
apiClient := dockerCli.Client()
var cs client.ConsoleSize
if execOptions.ConsoleSize != nil {
cs = client.ConsoleSize{
Height: execOptions.ConsoleSize[0],
Width: execOptions.ConsoleSize[1],
}
}
resp, err := apiClient.ExecAttach(ctx, execID, client.ExecAttachOptions{
Tty: execOptions.Tty,
ConsoleSize: execOptions.ConsoleSize,
TTY: execOptions.Tty,
ConsoleSize: cs,
})
if err != nil {
return err

View File

@@ -12,7 +12,6 @@ import (
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/opts"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/client"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -177,8 +176,8 @@ func TestRunExec(t *testing.T) {
doc: "inspect error",
options: NewExecOptions(),
client: &fakeClient{
inspectFunc: func(string) (container.InspectResponse, error) {
return container.InspectResponse{}, errors.New("failed inspect")
inspectFunc: func(string) (client.ContainerInspectResult, error) {
return client.ContainerInspectResult{}, errors.New("failed inspect")
},
},
expectedError: "failed inspect",
@@ -251,14 +250,14 @@ func TestNewExecCommandErrors(t *testing.T) {
name string
args []string
expectedError string
containerInspectFunc func(img string) (container.InspectResponse, error)
containerInspectFunc func(img string) (client.ContainerInspectResult, error)
}{
{
name: "client-error",
args: []string{"5cb5bb5e4a3b", "-t", "-i", "bash"},
expectedError: "something went wrong",
containerInspectFunc: func(containerID string) (container.InspectResponse, error) {
return container.InspectResponse{}, errors.New("something went wrong")
containerInspectFunc: func(containerID string) (client.ContainerInspectResult, error) {
return client.ContainerInspectResult{}, errors.New("something went wrong")
},
},
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/inspect"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/moby/moby/client"
"github.com/spf13/cobra"
)
@@ -46,6 +47,10 @@ func newInspectCommand(dockerCLI command.Cli) *cobra.Command {
func runInspect(ctx context.Context, dockerCLI command.Cli, opts inspectOptions) error {
apiClient := dockerCLI.Client()
return inspect.Inspect(dockerCLI.Out(), opts.refs, opts.format, func(ref string) (any, []byte, error) {
return apiClient.ContainerInspectWithRaw(ctx, ref, opts.size)
res, err := apiClient.ContainerInspect(ctx, ref, client.ContainerInspectOptions{Size: opts.size})
if err != nil {
return nil, nil, err
}
return &res.Container, res.Raw, nil
})
}

View File

@@ -54,12 +54,12 @@ func newLogsCommand(dockerCLI command.Cli) *cobra.Command {
}
func runLogs(ctx context.Context, dockerCli command.Cli, opts *logsOptions) error {
c, err := dockerCli.Client().ContainerInspect(ctx, opts.container)
c, err := dockerCli.Client().ContainerInspect(ctx, opts.container, client.ContainerInspectOptions{})
if err != nil {
return err
}
responseBody, err := dockerCli.Client().ContainerLogs(ctx, c.ID, client.ContainerLogsOptions{
responseBody, err := dockerCli.Client().ContainerLogs(ctx, c.Container.ID, client.ContainerLogsOptions{
ShowStdout: true,
ShowStderr: true,
Since: opts.since,
@@ -74,7 +74,7 @@ func runLogs(ctx context.Context, dockerCli command.Cli, opts *logsOptions) erro
}
defer responseBody.Close()
if c.Config.Tty {
if c.Container.Config.Tty {
_, err = io.Copy(dockerCli.Out(), responseBody)
} else {
_, err = stdcopy.StdCopy(dockerCli.Out(), dockerCli.Err(), responseBody)

View File

@@ -20,10 +20,12 @@ var logFn = func(expectedOut string) func(string, client.ContainerLogsOptions) (
}
func TestRunLogs(t *testing.T) {
inspectFn := func(containerID string) (container.InspectResponse, error) {
return container.InspectResponse{
Config: &container.Config{Tty: true},
State: &container.State{Running: false},
inspectFn := func(containerID string) (client.ContainerInspectResult, error) {
return client.ContainerInspectResult{
Container: container.InspectResponse{
Config: &container.Config{Tty: true},
State: &container.State{Running: false},
},
}, nil
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/docker/cli/cli/command/completion"
"github.com/fvbommel/sortorder"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/client"
"github.com/spf13/cobra"
)
@@ -52,7 +53,7 @@ func newPortCommand(dockerCLI command.Cli) *cobra.Command {
// proto is specified. We should consider changing this to "any" protocol
// for the given private port.
func runPort(ctx context.Context, dockerCli command.Cli, opts *portOptions) error {
c, err := dockerCli.Client().ContainerInspect(ctx, opts.container)
c, err := dockerCli.Client().ContainerInspect(ctx, opts.container, client.ContainerInspectOptions{})
if err != nil {
return err
}
@@ -63,7 +64,7 @@ func runPort(ctx context.Context, dockerCli command.Cli, opts *portOptions) erro
if err != nil {
return err
}
frontends, exists := c.NetworkSettings.Ports[port]
frontends, exists := c.Container.NetworkSettings.Ports[port]
if !exists || len(frontends) == 0 {
return fmt.Errorf("no public port '%s' published for %s", opts.port, opts.container)
}
@@ -71,7 +72,7 @@ func runPort(ctx context.Context, dockerCli command.Cli, opts *portOptions) erro
out = append(out, net.JoinHostPort(frontend.HostIP.String(), frontend.HostPort))
}
} else {
for from, frontends := range c.NetworkSettings.Ports {
for from, frontends := range c.Container.NetworkSettings.Ports {
for _, frontend := range frontends {
out = append(out, fmt.Sprintf("%s -> %s", from, net.JoinHostPort(frontend.HostIP.String(), frontend.HostPort)))
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/docker/cli/internal/test"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/client"
"gotest.tools/v3/assert"
"gotest.tools/v3/golden"
)
@@ -46,7 +47,7 @@ func TestNewPortCommandOutput(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
inspectFunc: func(string) (container.InspectResponse, error) {
inspectFunc: func(string) (client.ContainerInspectResult, error) {
ci := container.InspectResponse{NetworkSettings: &container.NetworkSettings{}}
ci.NetworkSettings.Ports = network.PortMap{
network.MustParsePort("80/tcp"): make([]network.PortBinding, len(tc.ips)),
@@ -64,7 +65,7 @@ func TestNewPortCommandOutput(t *testing.T) {
HostIP: ip, HostPort: "5678",
}
}
return ci, nil
return client.ContainerInspectResult{Container: ci}, nil
},
})
cmd := newPortCommand(cli)

View File

@@ -80,16 +80,16 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er
// 2. Attach to the container.
ctr := opts.Containers[0]
c, err := dockerCli.Client().ContainerInspect(ctx, ctr)
c, err := dockerCli.Client().ContainerInspect(ctx, ctr, client.ContainerInspectOptions{})
if err != nil {
return err
}
// We always use c.ID instead of container to maintain consistency during `docker start`
if !c.Config.Tty {
if !c.Container.Config.Tty {
sigc := notifyAllSignals()
bgCtx := context.WithoutCancel(ctx)
go ForwardAllSignals(bgCtx, dockerCli.Client(), c.ID, sigc)
go ForwardAllSignals(bgCtx, dockerCli.Client(), c.Container.ID, sigc)
defer signal.StopCatch(sigc)
}
@@ -100,7 +100,7 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er
options := client.ContainerAttachOptions{
Stream: true,
Stdin: opts.OpenStdin && c.Config.OpenStdin,
Stdin: opts.OpenStdin && c.Container.Config.OpenStdin,
Stdout: true,
Stderr: true,
DetachKeys: detachKeys,
@@ -112,7 +112,7 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er
in = dockerCli.In()
}
resp, errAttach := dockerCli.Client().ContainerAttach(ctx, c.ID, options)
resp, errAttach := dockerCli.Client().ContainerAttach(ctx, c.Container.ID, options)
if errAttach != nil {
return errAttach
}
@@ -128,7 +128,7 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er
outputStream: dockerCli.Out(),
errorStream: dockerCli.Err(),
resp: resp.HijackedResponse,
tty: c.Config.Tty,
tty: c.Container.Config.Tty,
detachKeys: options.DetachKeys,
}
@@ -142,17 +142,17 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er
// 3. We should open a channel for receiving status code of the container
// no matter it's detached, removed on daemon side(--rm) or exit normally.
statusChan := waitExitOrRemoved(ctx, dockerCli.Client(), c.ID, c.HostConfig.AutoRemove)
statusChan := waitExitOrRemoved(ctx, dockerCli.Client(), c.Container.ID, c.Container.HostConfig.AutoRemove)
// 4. Start the container.
err = dockerCli.Client().ContainerStart(ctx, c.ID, client.ContainerStartOptions{
err = dockerCli.Client().ContainerStart(ctx, c.Container.ID, client.ContainerStartOptions{
CheckpointID: opts.Checkpoint,
CheckpointDir: opts.CheckpointDir,
})
if err != nil {
cancelFun()
<-cErr
if c.HostConfig.AutoRemove {
if c.Container.HostConfig.AutoRemove {
// wait container to be removed
<-statusChan
}
@@ -160,8 +160,8 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er
}
// 5. Wait for attachment to break.
if c.Config.Tty && dockerCli.Out().IsTerminal() {
if err := MonitorTtySize(ctx, dockerCli, c.ID, false); err != nil {
if c.Container.Config.Tty && dockerCli.Out().IsTerminal() {
if err := MonitorTtySize(ctx, dockerCli, c.Container.ID, false); err != nil {
_, _ = fmt.Fprintln(dockerCli.Err(), "Error monitoring TTY size:", err)
}
}

View File

@@ -99,7 +99,11 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions)
func inspectContainers(ctx context.Context, dockerCli command.Cli, getSize bool) inspect.GetRefFunc {
return func(ref string) (any, []byte, error) {
return dockerCli.Client().ContainerInspectWithRaw(ctx, ref, getSize)
res, err := dockerCli.Client().ContainerInspect(ctx, ref, client.ContainerInspectOptions{Size: getSize})
if err != nil {
return nil, nil, err
}
return res.Container, res.Raw, err
}
}

View File

@@ -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.20251024193508-be8d6e2f2825 // master
github.com/moby/moby/client v0.1.0-beta.2.0.20251024193508-be8d6e2f2825 // master
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/patternmatcher v0.6.0
github.com/moby/swarmkit/v2 v2.1.0
github.com/moby/sys/atomicwriter v0.1.0

View File

@@ -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.20251024193508-be8d6e2f2825 h1:hIQtHzNpFguJCWlgZ4z9L83YjLYpf9uP9+3cSYXP9hg=
github.com/moby/moby/api v1.52.0-beta.2.0.20251024193508-be8d6e2f2825/go.mod h1:/ou52HkRydg4+odrUR3vFsGgjIyHvprrpEQEkweL10s=
github.com/moby/moby/client v0.1.0-beta.2.0.20251024193508-be8d6e2f2825 h1:7kbhU8foMePfI9vB24bSld1RzJQpbquW8sZarquRHbY=
github.com/moby/moby/client v0.1.0-beta.2.0.20251024193508-be8d6e2f2825/go.mod h1:sxVfwGqVgh7n+tdxA4gFToQ/lf+bM7zATnvQjVnsKT4=
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/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=

View File

@@ -63,8 +63,7 @@ type ContainerAPIClient interface {
ContainerDiff(ctx context.Context, container string, options ContainerDiffOptions) (ContainerDiffResult, error)
ExecAPIClient
ContainerExport(ctx context.Context, container string) (io.ReadCloser, error)
ContainerInspect(ctx context.Context, container string) (container.InspectResponse, error)
ContainerInspectWithRaw(ctx context.Context, container string, getSize bool) (container.InspectResponse, []byte, error)
ContainerInspect(ctx context.Context, container string, options ContainerInspectOptions) (ContainerInspectResult, error)
ContainerKill(ctx context.Context, container, signal string) error
ContainerList(ctx context.Context, options ContainerListOptions) ([]container.Summary, error)
ContainerLogs(ctx context.Context, container string, options ContainerLogsOptions) (io.ReadCloser, error)

View File

@@ -5,6 +5,7 @@ import (
"encoding/json"
"net/http"
"github.com/containerd/errdefs"
"github.com/moby/moby/api/types/container"
)
@@ -61,17 +62,19 @@ func (cli *Client) ExecCreate(ctx context.Context, containerID string, options E
return ExecCreateResult{ID: response.ID}, err
}
type execStartAttachOptions struct {
// ExecStart will first check if it's detached
Detach bool
// Check if there's a tty
Tty bool
// Terminal size [height, width], unused if Tty == false
ConsoleSize *[2]uint `json:",omitempty"`
type ConsoleSize struct {
Height, Width uint
}
// ExecStartOptions holds options for starting a container exec.
type ExecStartOptions execStartAttachOptions
type ExecStartOptions struct {
// ExecStart will first check if it's detached
Detach bool
// Check if there's a tty
TTY bool
// Terminal size [height, width], unused if TTY == false
ConsoleSize ConsoleSize `json:",omitzero"`
}
// ExecStartResult holds the result of starting a container exec.
type ExecStartResult struct {
@@ -80,9 +83,11 @@ type ExecStartResult struct {
// ExecStart starts an exec process already created in the docker host.
func (cli *Client) ExecStart(ctx context.Context, execID string, options ExecStartOptions) (ExecStartResult, error) {
req := container.ExecStartRequest{
Detach: options.Detach,
Tty: options.Tty,
ConsoleSize: options.ConsoleSize,
Detach: options.Detach,
Tty: options.TTY,
}
if err := applyConsoleSize(&req, &options.ConsoleSize); err != nil {
return ExecStartResult{}, err
}
resp, err := cli.post(ctx, "/exec/"+execID+"/start", nil, req, nil)
defer ensureReaderClosed(resp)
@@ -90,7 +95,12 @@ func (cli *Client) ExecStart(ctx context.Context, execID string, options ExecSta
}
// ExecAttachOptions holds options for attaching to a container exec.
type ExecAttachOptions execStartAttachOptions
type ExecAttachOptions struct {
// Check if there's a tty
TTY bool
// Terminal size [height, width], unused if TTY == false
ConsoleSize ConsoleSize `json:",omitzero"`
}
// ExecAttachResult holds the result of attaching to a container exec.
type ExecAttachResult struct {
@@ -117,9 +127,11 @@ type ExecAttachResult struct {
// [stdcopy.StdCopy]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdCopy
func (cli *Client) ExecAttach(ctx context.Context, execID string, options ExecAttachOptions) (ExecAttachResult, error) {
req := container.ExecStartRequest{
Detach: options.Detach,
Tty: options.Tty,
ConsoleSize: options.ConsoleSize,
Detach: false,
Tty: options.TTY,
}
if err := applyConsoleSize(&req, &options.ConsoleSize); err != nil {
return ExecAttachResult{}, err
}
response, err := cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, req, http.Header{
"Content-Type": {"application/json"},
@@ -127,6 +139,16 @@ func (cli *Client) ExecAttach(ctx context.Context, execID string, options ExecAt
return ExecAttachResult{HijackedResponse: response}, err
}
func applyConsoleSize(req *container.ExecStartRequest, consoleSize *ConsoleSize) error {
if consoleSize.Height != 0 || consoleSize.Width != 0 {
if !req.Tty {
return errdefs.ErrInvalidArgument.WithMessage("console size is only supported when TTY is enabled")
}
req.ConsoleSize = &[2]uint{consoleSize.Height, consoleSize.Width}
}
return nil
}
// ExecInspectOptions holds options for inspecting a container exec.
type ExecInspectOptions struct {
}

View File

@@ -1,57 +1,47 @@
package client
import (
"bytes"
"context"
"encoding/json"
"io"
"net/url"
"github.com/moby/moby/api/types/container"
)
// ContainerInspect returns the container information.
func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (container.InspectResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.InspectResponse{}, err
}
resp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.InspectResponse{}, err
}
var response container.InspectResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
// ContainerInspectOptions holds options for inspecting a container using
// the [Client.ConfigInspect] method.
type ContainerInspectOptions struct {
// Size controls whether the container's filesystem size should be calculated.
// When set, the [container.InspectResponse.SizeRw] and [container.InspectResponse.SizeRootFs]
// fields in [ContainerInspectResult.Container] are populated with the result.
//
// Calculating the size can be a costly operation, and should not be used
// unless needed.
Size bool
}
// ContainerInspectWithRaw returns the container information and its raw representation.
func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID string, getSize bool) (container.InspectResponse, []byte, error) {
// ContainerInspectResult holds the result from the [Client.ConfigInspect] method.
type ContainerInspectResult struct {
Container container.InspectResponse
Raw json.RawMessage
}
// ContainerInspect returns the container information.
func (cli *Client) ContainerInspect(ctx context.Context, containerID string, options ContainerInspectOptions) (ContainerInspectResult, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.InspectResponse{}, nil, err
return ContainerInspectResult{}, err
}
query := url.Values{}
if getSize {
if options.Size {
query.Set("size", "1")
}
resp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.InspectResponse{}, nil, err
return ContainerInspectResult{}, err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return container.InspectResponse{}, nil, err
}
var response container.InspectResponse
rdr := bytes.NewReader(body)
err = json.NewDecoder(rdr).Decode(&response)
return response, body, err
var out ContainerInspectResult
out.Raw, err = decodeWithRaw(resp, &out.Container)
return out, err
}

View File

@@ -51,7 +51,7 @@ func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, loadOpts ...I
}, nil
}
// LoadResponse returns information to the client about a load process.
// ImageLoadResult returns information to the client about a load process.
//
// TODO(thaJeztah): remove this type, and just use an io.ReadCloser
//

4
vendor/modules.txt vendored
View File

@@ -168,7 +168,7 @@ 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.20251024193508-be8d6e2f2825
# github.com/moby/moby/api v1.52.0-beta.2.0.20251026152250-0a134ecc1623
## explicit; go 1.23.0
github.com/moby/moby/api/pkg/authconfig
github.com/moby/moby/api/pkg/progress
@@ -192,7 +192,7 @@ 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.20251024193508-be8d6e2f2825
# github.com/moby/moby/client v0.1.0-beta.2.0.20251026152250-0a134ecc1623
## explicit; go 1.23.0
github.com/moby/moby/client
github.com/moby/moby/client/internal