Merge pull request #4534 from thaJeztah/update_engine

vendor: github.com/docker/docker 5b53ddfcdd1c (v25.0.0-dev)
This commit is contained in:
Sebastiaan van Stijn 2023-08-28 23:03:41 +02:00 committed by GitHub
commit 962056e434
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 403 additions and 159 deletions

View File

@ -3,34 +3,34 @@ package checkpoint
import ( import (
"context" "context"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
"github.com/docker/docker/client" "github.com/docker/docker/client"
) )
type fakeClient struct { type fakeClient struct {
client.Client client.Client
checkpointCreateFunc func(container string, options types.CheckpointCreateOptions) error checkpointCreateFunc func(container string, options checkpoint.CreateOptions) error
checkpointDeleteFunc func(container string, options types.CheckpointDeleteOptions) error checkpointDeleteFunc func(container string, options checkpoint.DeleteOptions) error
checkpointListFunc func(container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) checkpointListFunc func(container string, options checkpoint.ListOptions) ([]checkpoint.Summary, error)
} }
func (cli *fakeClient) CheckpointCreate(_ context.Context, container string, options types.CheckpointCreateOptions) error { func (cli *fakeClient) CheckpointCreate(_ context.Context, container string, options checkpoint.CreateOptions) error {
if cli.checkpointCreateFunc != nil { if cli.checkpointCreateFunc != nil {
return cli.checkpointCreateFunc(container, options) return cli.checkpointCreateFunc(container, options)
} }
return nil return nil
} }
func (cli *fakeClient) CheckpointDelete(_ context.Context, container string, options types.CheckpointDeleteOptions) error { func (cli *fakeClient) CheckpointDelete(_ context.Context, container string, options checkpoint.DeleteOptions) error {
if cli.checkpointDeleteFunc != nil { if cli.checkpointDeleteFunc != nil {
return cli.checkpointDeleteFunc(container, options) return cli.checkpointDeleteFunc(container, options)
} }
return nil return nil
} }
func (cli *fakeClient) CheckpointList(_ context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) { func (cli *fakeClient) CheckpointList(_ context.Context, container string, options checkpoint.ListOptions) ([]checkpoint.Summary, error) {
if cli.checkpointListFunc != nil { if cli.checkpointListFunc != nil {
return cli.checkpointListFunc(container, options) return cli.checkpointListFunc(container, options)
} }
return []types.Checkpoint{}, nil return []checkpoint.Summary{}, nil
} }

View File

@ -7,7 +7,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion" "github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -41,15 +41,11 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command {
} }
func runCreate(dockerCli command.Cli, opts createOptions) error { func runCreate(dockerCli command.Cli, opts createOptions) error {
client := dockerCli.Client() err := dockerCli.Client().CheckpointCreate(context.Background(), opts.container, checkpoint.CreateOptions{
checkpointOpts := types.CheckpointCreateOptions{
CheckpointID: opts.checkpoint, CheckpointID: opts.checkpoint,
CheckpointDir: opts.checkpointDir, CheckpointDir: opts.checkpointDir,
Exit: !opts.leaveRunning, Exit: !opts.leaveRunning,
} })
err := client.CheckpointCreate(context.Background(), opts.container, checkpointOpts)
if err != nil { if err != nil {
return err return err
} }

View File

@ -6,7 +6,7 @@ import (
"testing" "testing"
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
"github.com/pkg/errors" "github.com/pkg/errors"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp" is "gotest.tools/v3/assert/cmp"
@ -15,7 +15,7 @@ import (
func TestCheckpointCreateErrors(t *testing.T) { func TestCheckpointCreateErrors(t *testing.T) {
testCases := []struct { testCases := []struct {
args []string args []string
checkpointCreateFunc func(container string, options types.CheckpointCreateOptions) error checkpointCreateFunc func(container string, options checkpoint.CreateOptions) error
expectedError string expectedError string
}{ }{
{ {
@ -28,7 +28,7 @@ func TestCheckpointCreateErrors(t *testing.T) {
}, },
{ {
args: []string{"foo", "bar"}, args: []string{"foo", "bar"},
checkpointCreateFunc: func(container string, options types.CheckpointCreateOptions) error { checkpointCreateFunc: func(container string, options checkpoint.CreateOptions) error {
return errors.Errorf("error creating checkpoint for container foo") return errors.Errorf("error creating checkpoint for container foo")
}, },
expectedError: "error creating checkpoint for container foo", expectedError: "error creating checkpoint for container foo",
@ -50,7 +50,7 @@ func TestCheckpointCreateWithOptions(t *testing.T) {
var containerID, checkpointID, checkpointDir string var containerID, checkpointID, checkpointDir string
var exit bool var exit bool
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
checkpointCreateFunc: func(container string, options types.CheckpointCreateOptions) error { checkpointCreateFunc: func(container string, options checkpoint.CreateOptions) error {
containerID = container containerID = container
checkpointID = options.CheckpointID checkpointID = options.CheckpointID
checkpointDir = options.CheckpointDir checkpointDir = options.CheckpointDir
@ -59,14 +59,14 @@ func TestCheckpointCreateWithOptions(t *testing.T) {
}, },
}) })
cmd := newCreateCommand(cli) cmd := newCreateCommand(cli)
checkpoint := "checkpoint-bar" cp := "checkpoint-bar"
cmd.SetArgs([]string{"container-foo", checkpoint}) cmd.SetArgs([]string{"container-foo", cp})
cmd.Flags().Set("leave-running", "true") cmd.Flags().Set("leave-running", "true")
cmd.Flags().Set("checkpoint-dir", "/dir/foo") cmd.Flags().Set("checkpoint-dir", "/dir/foo")
assert.NilError(t, cmd.Execute()) assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("container-foo", containerID)) assert.Check(t, is.Equal("container-foo", containerID))
assert.Check(t, is.Equal(checkpoint, checkpointID)) assert.Check(t, is.Equal(cp, checkpointID))
assert.Check(t, is.Equal("/dir/foo", checkpointDir)) assert.Check(t, is.Equal("/dir/foo", checkpointDir))
assert.Check(t, is.Equal(false, exit)) assert.Check(t, is.Equal(false, exit))
assert.Check(t, is.Equal(checkpoint, strings.TrimSpace(cli.OutBuffer().String()))) assert.Check(t, is.Equal(cp, strings.TrimSpace(cli.OutBuffer().String())))
} }

View File

@ -2,12 +2,11 @@ package checkpoint
import ( import (
"github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
) )
const ( const (
defaultCheckpointFormat = "table {{.Name}}" defaultCheckpointFormat = "table {{.Name}}"
checkpointNameHeader = "CHECKPOINT NAME" checkpointNameHeader = "CHECKPOINT NAME"
) )
@ -21,10 +20,10 @@ func NewFormat(source string) formatter.Format {
} }
// FormatWrite writes formatted checkpoints using the Context // FormatWrite writes formatted checkpoints using the Context
func FormatWrite(ctx formatter.Context, checkpoints []types.Checkpoint) error { func FormatWrite(ctx formatter.Context, checkpoints []checkpoint.Summary) error {
render := func(format func(subContext formatter.SubContext) error) error { render := func(format func(subContext formatter.SubContext) error) error {
for _, checkpoint := range checkpoints { for _, cp := range checkpoints {
if err := format(&checkpointContext{c: checkpoint}); err != nil { if err := format(&checkpointContext{c: cp}); err != nil {
return err return err
} }
} }
@ -35,7 +34,7 @@ func FormatWrite(ctx formatter.Context, checkpoints []types.Checkpoint) error {
type checkpointContext struct { type checkpointContext struct {
formatter.HeaderContext formatter.HeaderContext
c types.Checkpoint c checkpoint.Summary
} }
func newCheckpointContext() *checkpointContext { func newCheckpointContext() *checkpointContext {

View File

@ -5,7 +5,7 @@ import (
"testing" "testing"
"github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
) )
@ -38,15 +38,14 @@ checkpoint-3:
}, },
} }
checkpoints := []types.Checkpoint{
{Name: "checkpoint-1"},
{Name: "checkpoint-2"},
{Name: "checkpoint-3"},
}
for _, testcase := range cases { for _, testcase := range cases {
out := bytes.NewBufferString("") out := bytes.NewBufferString("")
testcase.context.Output = out testcase.context.Output = out
err := FormatWrite(testcase.context, checkpoints) err := FormatWrite(testcase.context, []checkpoint.Summary{
{Name: "checkpoint-1"},
{Name: "checkpoint-2"},
{Name: "checkpoint-3"},
})
assert.NilError(t, err) assert.NilError(t, err)
assert.Equal(t, out.String(), testcase.expected) assert.Equal(t, out.String(), testcase.expected)
} }

View File

@ -7,7 +7,7 @@ import (
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion" "github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -36,13 +36,9 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
} }
func runList(dockerCli command.Cli, container string, opts listOptions) error { func runList(dockerCli command.Cli, container string, opts listOptions) error {
client := dockerCli.Client() checkpoints, err := dockerCli.Client().CheckpointList(context.Background(), container, checkpoint.ListOptions{
listOpts := types.CheckpointListOptions{
CheckpointDir: opts.checkpointDir, CheckpointDir: opts.checkpointDir,
} })
checkpoints, err := client.CheckpointList(context.Background(), container, listOpts)
if err != nil { if err != nil {
return err return err
} }

View File

@ -5,7 +5,7 @@ import (
"testing" "testing"
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
"github.com/pkg/errors" "github.com/pkg/errors"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp" is "gotest.tools/v3/assert/cmp"
@ -15,7 +15,7 @@ import (
func TestCheckpointListErrors(t *testing.T) { func TestCheckpointListErrors(t *testing.T) {
testCases := []struct { testCases := []struct {
args []string args []string
checkpointListFunc func(container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) checkpointListFunc func(container string, options checkpoint.ListOptions) ([]checkpoint.Summary, error)
expectedError string expectedError string
}{ }{
{ {
@ -28,8 +28,8 @@ func TestCheckpointListErrors(t *testing.T) {
}, },
{ {
args: []string{"foo"}, args: []string{"foo"},
checkpointListFunc: func(container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) { checkpointListFunc: func(container string, options checkpoint.ListOptions) ([]checkpoint.Summary, error) {
return []types.Checkpoint{}, errors.Errorf("error getting checkpoints for container foo") return []checkpoint.Summary{}, errors.Errorf("error getting checkpoints for container foo")
}, },
expectedError: "error getting checkpoints for container foo", expectedError: "error getting checkpoints for container foo",
}, },
@ -49,10 +49,10 @@ func TestCheckpointListErrors(t *testing.T) {
func TestCheckpointListWithOptions(t *testing.T) { func TestCheckpointListWithOptions(t *testing.T) {
var containerID, checkpointDir string var containerID, checkpointDir string
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
checkpointListFunc: func(container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) { checkpointListFunc: func(container string, options checkpoint.ListOptions) ([]checkpoint.Summary, error) {
containerID = container containerID = container
checkpointDir = options.CheckpointDir checkpointDir = options.CheckpointDir
return []types.Checkpoint{ return []checkpoint.Summary{
{Name: "checkpoint-foo"}, {Name: "checkpoint-foo"},
}, nil }, nil
}, },

View File

@ -5,7 +5,7 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -32,13 +32,9 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
return cmd return cmd
} }
func runRemove(dockerCli command.Cli, container string, checkpoint string, opts removeOptions) error { func runRemove(dockerCli command.Cli, container string, checkpointID string, opts removeOptions) error {
client := dockerCli.Client() return dockerCli.Client().CheckpointDelete(context.Background(), container, checkpoint.DeleteOptions{
CheckpointID: checkpointID,
removeOpts := types.CheckpointDeleteOptions{
CheckpointID: checkpoint,
CheckpointDir: opts.checkpointDir, CheckpointDir: opts.checkpointDir,
} })
return client.CheckpointDelete(context.Background(), container, removeOpts)
} }

View File

@ -5,7 +5,7 @@ import (
"testing" "testing"
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
"github.com/pkg/errors" "github.com/pkg/errors"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp" is "gotest.tools/v3/assert/cmp"
@ -14,7 +14,7 @@ import (
func TestCheckpointRemoveErrors(t *testing.T) { func TestCheckpointRemoveErrors(t *testing.T) {
testCases := []struct { testCases := []struct {
args []string args []string
checkpointDeleteFunc func(container string, options types.CheckpointDeleteOptions) error checkpointDeleteFunc func(container string, options checkpoint.DeleteOptions) error
expectedError string expectedError string
}{ }{
{ {
@ -27,7 +27,7 @@ func TestCheckpointRemoveErrors(t *testing.T) {
}, },
{ {
args: []string{"foo", "bar"}, args: []string{"foo", "bar"},
checkpointDeleteFunc: func(container string, options types.CheckpointDeleteOptions) error { checkpointDeleteFunc: func(container string, options checkpoint.DeleteOptions) error {
return errors.Errorf("error deleting checkpoint") return errors.Errorf("error deleting checkpoint")
}, },
expectedError: "error deleting checkpoint", expectedError: "error deleting checkpoint",
@ -48,7 +48,7 @@ func TestCheckpointRemoveErrors(t *testing.T) {
func TestCheckpointRemoveWithOptions(t *testing.T) { func TestCheckpointRemoveWithOptions(t *testing.T) {
var containerID, checkpointID, checkpointDir string var containerID, checkpointID, checkpointDir string
cli := test.NewFakeCli(&fakeClient{ cli := test.NewFakeCli(&fakeClient{
checkpointDeleteFunc: func(container string, options types.CheckpointDeleteOptions) error { checkpointDeleteFunc: func(container string, options checkpoint.DeleteOptions) error {
containerID = container containerID = container
checkpointID = options.CheckpointID checkpointID = options.CheckpointID
checkpointDir = options.CheckpointDir checkpointDir = options.CheckpointDir

View File

@ -185,7 +185,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
flags.VarP(&copts.labels, "label", "l", "Set meta data on a container") flags.VarP(&copts.labels, "label", "l", "Set meta data on a container")
flags.Var(&copts.labelsFile, "label-file", "Read in a line delimited file of labels") flags.Var(&copts.labelsFile, "label-file", "Read in a line delimited file of labels")
flags.BoolVar(&copts.readonlyRootfs, "read-only", false, "Mount the container's root filesystem as read only") flags.BoolVar(&copts.readonlyRootfs, "read-only", false, "Mount the container's root filesystem as read only")
flags.StringVar(&copts.restartPolicy, "restart", "no", "Restart policy to apply when a container exits") flags.StringVar(&copts.restartPolicy, "restart", string(container.RestartPolicyDisabled), "Restart policy to apply when a container exits")
flags.StringVar(&copts.stopSignal, "stop-signal", "", "Signal to stop the container") flags.StringVar(&copts.stopSignal, "stop-signal", "", "Signal to stop the container")
flags.IntVar(&copts.stopTimeout, "stop-timeout", 0, "Timeout (in seconds) to stop a container") flags.IntVar(&copts.stopTimeout, "stop-timeout", 0, "Timeout (in seconds) to stop a container")
flags.SetAnnotation("stop-timeout", "version", []string{"1.25"}) flags.SetAnnotation("stop-timeout", "version", []string{"1.25"})

View File

@ -711,7 +711,7 @@ func TestParseRestartPolicy(t *testing.T) {
{ {
input: "no", input: "no",
expected: container.RestartPolicy{ expected: container.RestartPolicy{
Name: "no", Name: container.RestartPolicyDisabled,
}, },
}, },
{ {
@ -721,13 +721,13 @@ func TestParseRestartPolicy(t *testing.T) {
{ {
input: "always", input: "always",
expected: container.RestartPolicy{ expected: container.RestartPolicy{
Name: "always", Name: container.RestartPolicyAlways,
}, },
}, },
{ {
input: "always:1", input: "always:1",
expected: container.RestartPolicy{ expected: container.RestartPolicy{
Name: "always", Name: container.RestartPolicyAlways,
MaximumRetryCount: 1, MaximumRetryCount: 1,
}, },
}, },
@ -738,7 +738,7 @@ func TestParseRestartPolicy(t *testing.T) {
{ {
input: "on-failure:1", input: "on-failure:1",
expected: container.RestartPolicy{ expected: container.RestartPolicy{
Name: "on-failure", Name: container.RestartPolicyOnFailure,
MaximumRetryCount: 1, MaximumRetryCount: 1,
}, },
}, },
@ -749,7 +749,7 @@ func TestParseRestartPolicy(t *testing.T) {
{ {
input: "unless-stopped", input: "unless-stopped",
expected: container.RestartPolicy{ expected: container.RestartPolicy{
Name: "unless-stopped", Name: container.RestartPolicyUnlessStopped,
}, },
}, },
{ {

View File

@ -91,6 +91,6 @@ func ParseRestartPolicy(policy string) (container.RestartPolicy, error) {
p.MaximumRetryCount = count p.MaximumRetryCount = count
} }
p.Name = k p.Name = container.RestartPolicyMode(k)
return p, nil return p, nil
} }

View File

@ -12,7 +12,7 @@ require (
github.com/containerd/containerd v1.6.22 github.com/containerd/containerd v1.6.22
github.com/creack/pty v1.1.18 github.com/creack/pty v1.1.18
github.com/docker/distribution v2.8.2+incompatible github.com/docker/distribution v2.8.2+incompatible
github.com/docker/docker v24.0.0-rc.2.0.20230807181406-4b19b2f4babd+incompatible // master (v25.0.0-dev) github.com/docker/docker v24.0.0-rc.2.0.20230828170219-a65c948e7edf+incompatible // master (v25.0.0-dev)
github.com/docker/docker-credential-helpers v0.8.0 github.com/docker/docker-credential-helpers v0.8.0
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/docker/go-units v0.5.0 github.com/docker/go-units v0.5.0

View File

@ -50,8 +50,8 @@ github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xb
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v24.0.0-rc.2.0.20230807181406-4b19b2f4babd+incompatible h1:jpw4copYljr4wqeQ6nSzvBNe83BqmStvHsvZdnlnEo0= github.com/docker/docker v24.0.0-rc.2.0.20230828170219-a65c948e7edf+incompatible h1:kW2gtg0d8U36kbMoM7eqXIA7PuXGw3l/A3cxwdnbZPU=
github.com/docker/docker v24.0.0-rc.2.0.20230807181406-4b19b2f4babd+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v24.0.0-rc.2.0.20230828170219-a65c948e7edf+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40= github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=

View File

@ -5073,7 +5073,7 @@ definitions:
Go runtime (`GOOS`). Go runtime (`GOOS`).
Currently returned values are "linux" and "windows". A full list of Currently returned values are "linux" and "windows". A full list of
possible values can be found in the [Go documentation](https://golang.org/doc/install/source#environment). possible values can be found in the [Go documentation](https://go.dev/doc/install/source#environment).
type: "string" type: "string"
example: "linux" example: "linux"
Architecture: Architecture:
@ -5081,7 +5081,7 @@ definitions:
Hardware architecture of the host, as returned by the Go runtime Hardware architecture of the host, as returned by the Go runtime
(`GOARCH`). (`GOARCH`).
A full list of possible values can be found in the [Go documentation](https://golang.org/doc/install/source#environment). A full list of possible values can be found in the [Go documentation](https://go.dev/doc/install/source#environment).
type: "string" type: "string"
example: "x86_64" example: "x86_64"
NCPU: NCPU:
@ -9929,6 +9929,10 @@ paths:
example: example:
Id: "22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30" Id: "22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30"
Warning: "" Warning: ""
400:
description: "bad parameter"
schema:
$ref: "#/definitions/ErrorResponse"
403: 403:
description: | description: |
Forbidden operation. This happens when trying to create a network named after a pre-defined network, Forbidden operation. This happens when trying to create a network named after a pre-defined network,

View File

@ -0,0 +1,7 @@
package checkpoint
// Summary represents the details of a checkpoint when listing endpoints.
type Summary struct {
// Name is the name of the checkpoint.
Name string
}

View File

@ -0,0 +1,19 @@
package checkpoint
// CreateOptions holds parameters to create a checkpoint from a container.
type CreateOptions struct {
CheckpointID string
CheckpointDir string
Exit bool
}
// ListOptions holds parameters to list checkpoints for a container.
type ListOptions struct {
CheckpointDir string
}
// DeleteOptions holds parameters to delete a checkpoint from a container.
type DeleteOptions struct {
CheckpointID string
CheckpointDir string
}

View File

@ -11,24 +11,6 @@ import (
units "github.com/docker/go-units" units "github.com/docker/go-units"
) )
// CheckpointCreateOptions holds parameters to create a checkpoint from a container
type CheckpointCreateOptions struct {
CheckpointID string
CheckpointDir string
Exit bool
}
// CheckpointListOptions holds parameters to list checkpoints for a container
type CheckpointListOptions struct {
CheckpointDir string
}
// CheckpointDeleteOptions holds parameters to delete a checkpoint from a container
type CheckpointDeleteOptions struct {
CheckpointID string
CheckpointDir string
}
// ContainerAttachOptions holds parameters to attach to a container. // ContainerAttachOptions holds parameters to attach to a container.
type ContainerAttachOptions struct { type ContainerAttachOptions struct {
Stream bool Stream bool

View File

@ -0,0 +1,9 @@
package container
type errInvalidParameter struct{ error }
func (e *errInvalidParameter) InvalidParameter() {}
func (e *errInvalidParameter) Unwrap() error {
return e.error
}

View File

@ -1,6 +1,7 @@
package container // import "github.com/docker/docker/api/types/container" package container // import "github.com/docker/docker/api/types/container"
import ( import (
"fmt"
"strings" "strings"
"github.com/docker/docker/api/types/blkiodev" "github.com/docker/docker/api/types/blkiodev"
@ -271,33 +272,42 @@ type DeviceMapping struct {
// RestartPolicy represents the restart policies of the container. // RestartPolicy represents the restart policies of the container.
type RestartPolicy struct { type RestartPolicy struct {
Name string Name RestartPolicyMode
MaximumRetryCount int MaximumRetryCount int
} }
type RestartPolicyMode string
const (
RestartPolicyDisabled RestartPolicyMode = "no"
RestartPolicyAlways RestartPolicyMode = "always"
RestartPolicyOnFailure RestartPolicyMode = "on-failure"
RestartPolicyUnlessStopped RestartPolicyMode = "unless-stopped"
)
// IsNone indicates whether the container has the "no" restart policy. // IsNone indicates whether the container has the "no" restart policy.
// This means the container will not automatically restart when exiting. // This means the container will not automatically restart when exiting.
func (rp *RestartPolicy) IsNone() bool { func (rp *RestartPolicy) IsNone() bool {
return rp.Name == "no" || rp.Name == "" return rp.Name == RestartPolicyDisabled || rp.Name == ""
} }
// IsAlways indicates whether the container has the "always" restart policy. // IsAlways indicates whether the container has the "always" restart policy.
// This means the container will automatically restart regardless of the exit status. // This means the container will automatically restart regardless of the exit status.
func (rp *RestartPolicy) IsAlways() bool { func (rp *RestartPolicy) IsAlways() bool {
return rp.Name == "always" return rp.Name == RestartPolicyAlways
} }
// IsOnFailure indicates whether the container has the "on-failure" restart policy. // IsOnFailure indicates whether the container has the "on-failure" restart policy.
// This means the container will automatically restart of exiting with a non-zero exit status. // This means the container will automatically restart of exiting with a non-zero exit status.
func (rp *RestartPolicy) IsOnFailure() bool { func (rp *RestartPolicy) IsOnFailure() bool {
return rp.Name == "on-failure" return rp.Name == RestartPolicyOnFailure
} }
// IsUnlessStopped indicates whether the container has the // IsUnlessStopped indicates whether the container has the
// "unless-stopped" restart policy. This means the container will // "unless-stopped" restart policy. This means the container will
// automatically restart unless user has put it to stopped state. // automatically restart unless user has put it to stopped state.
func (rp *RestartPolicy) IsUnlessStopped() bool { func (rp *RestartPolicy) IsUnlessStopped() bool {
return rp.Name == "unless-stopped" return rp.Name == RestartPolicyUnlessStopped
} }
// IsSame compares two RestartPolicy to see if they are the same // IsSame compares two RestartPolicy to see if they are the same
@ -305,6 +315,33 @@ func (rp *RestartPolicy) IsSame(tp *RestartPolicy) bool {
return rp.Name == tp.Name && rp.MaximumRetryCount == tp.MaximumRetryCount return rp.Name == tp.Name && rp.MaximumRetryCount == tp.MaximumRetryCount
} }
// ValidateRestartPolicy validates the given RestartPolicy.
func ValidateRestartPolicy(policy RestartPolicy) error {
switch policy.Name {
case RestartPolicyAlways, RestartPolicyUnlessStopped, RestartPolicyDisabled:
if policy.MaximumRetryCount != 0 {
msg := "invalid restart policy: maximum retry count can only be used with 'on-failure'"
if policy.MaximumRetryCount < 0 {
msg += " and cannot be negative"
}
return &errInvalidParameter{fmt.Errorf(msg)}
}
return nil
case RestartPolicyOnFailure:
if policy.MaximumRetryCount < 0 {
return &errInvalidParameter{fmt.Errorf("invalid restart policy: maximum retry count cannot be negative")}
}
return nil
case "":
// Versions before v25.0.0 created an empty restart-policy "name" as
// default. Allow an empty name with "any" MaximumRetryCount for
// backward-compatibility.
return nil
default:
return &errInvalidParameter{fmt.Errorf("invalid restart policy: unknown policy '%s'; use one of '%s', '%s', '%s', or '%s'", policy.Name, RestartPolicyDisabled, RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyUnlessStopped)}
}
}
// LogMode is a type to define the available modes for logging // LogMode is a type to define the available modes for logging
// These modes affect how logs are handled when log messages start piling up. // These modes affect how logs are handled when log messages start piling up.
type LogMode string type LogMode string

View File

@ -1,7 +1,7 @@
package events // import "github.com/docker/docker/api/types/events" package events // import "github.com/docker/docker/api/types/events"
// Type is used for event-types. // Type is used for event-types.
type Type = string type Type string
// List of known event types. // List of known event types.
const ( const (

View File

@ -0,0 +1,132 @@
package network
import (
"errors"
"fmt"
"net/netip"
"github.com/docker/docker/internal/multierror"
)
// IPAM represents IP Address Management
type IPAM struct {
Driver string
Options map[string]string // Per network IPAM driver options
Config []IPAMConfig
}
// IPAMConfig represents IPAM configurations
type IPAMConfig struct {
Subnet string `json:",omitempty"`
IPRange string `json:",omitempty"`
Gateway string `json:",omitempty"`
AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
}
type ipFamily string
const (
ip4 ipFamily = "IPv4"
ip6 ipFamily = "IPv6"
)
func ValidateIPAM(ipam *IPAM, enableIPv6 bool) error {
if ipam == nil {
return nil
}
var errs []error
for _, cfg := range ipam.Config {
subnet, err := netip.ParsePrefix(cfg.Subnet)
if err != nil {
errs = append(errs, fmt.Errorf("invalid subnet %s: invalid CIDR block notation", cfg.Subnet))
continue
}
subnetFamily := ip4
if subnet.Addr().Is6() {
subnetFamily = ip6
}
if subnet != subnet.Masked() {
errs = append(errs, fmt.Errorf("invalid subnet %s: it should be %s", subnet, subnet.Masked()))
}
if !enableIPv6 && subnetFamily == ip6 {
errs = append(errs, fmt.Errorf("invalid subnet %s: IPv6 has not been enabled for this network", subnet))
}
if ipRangeErrs := validateIPRange(cfg.IPRange, subnet, subnetFamily); len(ipRangeErrs) > 0 {
errs = append(errs, ipRangeErrs...)
}
if err := validateAddress(cfg.Gateway, subnet, subnetFamily); err != nil {
errs = append(errs, fmt.Errorf("invalid gateway %s: %w", cfg.Gateway, err))
}
for auxName, aux := range cfg.AuxAddress {
if err := validateAddress(aux, subnet, subnetFamily); err != nil {
errs = append(errs, fmt.Errorf("invalid auxiliary address %s: %w", auxName, err))
}
}
}
if err := multierror.Join(errs...); err != nil {
return fmt.Errorf("invalid network config:\n%w", err)
}
return nil
}
func validateIPRange(ipRange string, subnet netip.Prefix, subnetFamily ipFamily) []error {
if ipRange == "" {
return nil
}
prefix, err := netip.ParsePrefix(ipRange)
if err != nil {
return []error{fmt.Errorf("invalid ip-range %s: invalid CIDR block notation", ipRange)}
}
family := ip4
if prefix.Addr().Is6() {
family = ip6
}
if family != subnetFamily {
return []error{fmt.Errorf("invalid ip-range %s: parent subnet is an %s block", ipRange, subnetFamily)}
}
var errs []error
if prefix.Bits() < subnet.Bits() {
errs = append(errs, fmt.Errorf("invalid ip-range %s: CIDR block is bigger than its parent subnet %s", ipRange, subnet))
}
if prefix != prefix.Masked() {
errs = append(errs, fmt.Errorf("invalid ip-range %s: it should be %s", prefix, prefix.Masked()))
}
if !subnet.Overlaps(prefix) {
errs = append(errs, fmt.Errorf("invalid ip-range %s: parent subnet %s doesn't contain ip-range", ipRange, subnet))
}
return errs
}
func validateAddress(address string, subnet netip.Prefix, subnetFamily ipFamily) error {
if address == "" {
return nil
}
addr, err := netip.ParseAddr(address)
if err != nil {
return errors.New("invalid address")
}
family := ip4
if addr.Is6() {
family = ip6
}
if family != subnetFamily {
return fmt.Errorf("parent subnet is an %s block", subnetFamily)
}
if !subnet.Contains(addr) {
return fmt.Errorf("parent subnet %s doesn't contain this address", subnet)
}
return nil
}

View File

@ -9,21 +9,6 @@ type Address struct {
PrefixLen int PrefixLen int
} }
// IPAM represents IP Address Management
type IPAM struct {
Driver string
Options map[string]string // Per network IPAM driver options
Config []IPAMConfig
}
// IPAMConfig represents IPAM configurations
type IPAMConfig struct {
Subnet string `json:",omitempty"`
IPRange string `json:",omitempty"`
Gateway string `json:",omitempty"`
AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
}
// EndpointIPAMConfig represents IPAM configurations for the endpoint // EndpointIPAMConfig represents IPAM configurations for the endpoint
type EndpointIPAMConfig struct { type EndpointIPAMConfig struct {
IPv4Address string `json:",omitempty"` IPv4Address string `json:",omitempty"`

View File

@ -494,11 +494,6 @@ type NetworkInspectOptions struct {
Verbose bool Verbose bool
} }
// Checkpoint represents the details of a checkpoint
type Checkpoint struct {
Name string // Name is the name of the checkpoint
}
// DiskUsageObject represents an object type used for disk usage query filtering. // DiskUsageObject represents an object type used for disk usage query filtering.
type DiskUsageObject string type DiskUsageObject string

View File

@ -1,6 +1,29 @@
package types package types
import "github.com/docker/docker/api/types/system" import (
"github.com/docker/docker/api/types/checkpoint"
"github.com/docker/docker/api/types/system"
)
// CheckpointCreateOptions holds parameters to create a checkpoint from a container.
//
// Deprecated: use [checkpoint.CreateOptions].
type CheckpointCreateOptions = checkpoint.CreateOptions
// CheckpointListOptions holds parameters to list checkpoints for a container
//
// Deprecated: use [checkpoint.ListOptions].
type CheckpointListOptions = checkpoint.ListOptions
// CheckpointDeleteOptions holds parameters to delete a checkpoint from a container
//
// Deprecated: use [checkpoint.DeleteOptions].
type CheckpointDeleteOptions = checkpoint.DeleteOptions
// Checkpoint represents the details of a checkpoint when listing endpoints.
//
// Deprecated: use [checkpoint.Summary].
type Checkpoint = checkpoint.Summary
// Info contains response of Engine API: // Info contains response of Engine API:
// GET "/info" // GET "/info"

View File

@ -16,11 +16,11 @@ func compare(v1, v2 string) int {
otherTab = strings.Split(v2, ".") otherTab = strings.Split(v2, ".")
) )
max := len(currTab) maxVer := len(currTab)
if len(otherTab) > max { if len(otherTab) > maxVer {
max = len(otherTab) maxVer = len(otherTab)
} }
for i := 0; i < max; i++ { for i := 0; i < maxVer; i++ {
var currInt, otherInt int var currInt, otherInt int
if len(currTab) > i { if len(currTab) > i {

View File

@ -20,6 +20,7 @@ func main() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer cli.Close()
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil { if err != nil {

View File

@ -3,11 +3,11 @@ package client // import "github.com/docker/docker/client"
import ( import (
"context" "context"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
) )
// CheckpointCreate creates a checkpoint from the given container with the given name // CheckpointCreate creates a checkpoint from the given container with the given name
func (cli *Client) CheckpointCreate(ctx context.Context, container string, options types.CheckpointCreateOptions) error { func (cli *Client) CheckpointCreate(ctx context.Context, container string, options checkpoint.CreateOptions) error {
resp, err := cli.post(ctx, "/containers/"+container+"/checkpoints", nil, options, nil) resp, err := cli.post(ctx, "/containers/"+container+"/checkpoints", nil, options, nil)
ensureReaderClosed(resp) ensureReaderClosed(resp)
return err return err

View File

@ -4,11 +4,11 @@ import (
"context" "context"
"net/url" "net/url"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
) )
// CheckpointDelete deletes the checkpoint with the given name from the given container // CheckpointDelete deletes the checkpoint with the given name from the given container
func (cli *Client) CheckpointDelete(ctx context.Context, containerID string, options types.CheckpointDeleteOptions) error { func (cli *Client) CheckpointDelete(ctx context.Context, containerID string, options checkpoint.DeleteOptions) error {
query := url.Values{} query := url.Values{}
if options.CheckpointDir != "" { if options.CheckpointDir != "" {
query.Set("dir", options.CheckpointDir) query.Set("dir", options.CheckpointDir)

View File

@ -5,12 +5,12 @@ import (
"encoding/json" "encoding/json"
"net/url" "net/url"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
) )
// CheckpointList returns the checkpoints of the given container in the docker host // CheckpointList returns the checkpoints of the given container in the docker host
func (cli *Client) CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) { func (cli *Client) CheckpointList(ctx context.Context, container string, options checkpoint.ListOptions) ([]checkpoint.Summary, error) {
var checkpoints []types.Checkpoint var checkpoints []checkpoint.Summary
query := url.Values{} query := url.Values{}
if options.CheckpointDir != "" { if options.CheckpointDir != "" {

View File

@ -21,11 +21,11 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
if err != nil { if err != nil {
return types.HijackedResponse{}, err return types.HijackedResponse{}, err
} }
req, err := cli.buildRequest(http.MethodPost, cli.getAPIPath(ctx, path, query), bodyEncoded, headers) req, err := cli.buildRequest(ctx, http.MethodPost, cli.getAPIPath(ctx, path, query), bodyEncoded, headers)
if err != nil { if err != nil {
return types.HijackedResponse{}, err return types.HijackedResponse{}, err
} }
conn, mediaType, err := cli.setupHijackConn(ctx, req, "tcp") conn, mediaType, err := cli.setupHijackConn(req, "tcp")
if err != nil { if err != nil {
return types.HijackedResponse{}, err return types.HijackedResponse{}, err
} }
@ -35,17 +35,18 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
// DialHijack returns a hijacked connection with negotiated protocol proto. // DialHijack returns a hijacked connection with negotiated protocol proto.
func (cli *Client) DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error) { func (cli *Client) DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error) {
req, err := http.NewRequest(http.MethodPost, url, nil) req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
req = cli.addHeaders(req, meta) req = cli.addHeaders(req, meta)
conn, _, err := cli.setupHijackConn(ctx, req, proto) conn, _, err := cli.setupHijackConn(req, proto)
return conn, err return conn, err
} }
func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto string) (net.Conn, string, error) { func (cli *Client) setupHijackConn(req *http.Request, proto string) (net.Conn, string, error) {
ctx := req.Context()
req.Header.Set("Connection", "Upgrade") req.Header.Set("Connection", "Upgrade")
req.Header.Set("Upgrade", proto) req.Header.Set("Upgrade", proto)

View File

@ -3,7 +3,7 @@ package client // import "github.com/docker/docker/client"
import ( import (
"context" "context"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types/checkpoint"
) )
type apiClientExperimental interface { type apiClientExperimental interface {
@ -12,7 +12,7 @@ type apiClientExperimental interface {
// CheckpointAPIClient defines API client methods for the checkpoints // CheckpointAPIClient defines API client methods for the checkpoints
type CheckpointAPIClient interface { type CheckpointAPIClient interface {
CheckpointCreate(ctx context.Context, container string, options types.CheckpointCreateOptions) error CheckpointCreate(ctx context.Context, container string, options checkpoint.CreateOptions) error
CheckpointDelete(ctx context.Context, container string, options types.CheckpointDeleteOptions) error CheckpointDelete(ctx context.Context, container string, options checkpoint.DeleteOptions) error
CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) CheckpointList(ctx context.Context, container string, options checkpoint.ListOptions) ([]checkpoint.Summary, error)
} }

View File

@ -21,11 +21,11 @@ func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
// Using cli.buildRequest() + cli.doRequest() instead of cli.sendRequest() // Using cli.buildRequest() + cli.doRequest() instead of cli.sendRequest()
// because ping requests are used during API version negotiation, so we want // because ping requests are used during API version negotiation, so we want
// to hit the non-versioned /_ping endpoint, not /v1.xx/_ping // to hit the non-versioned /_ping endpoint, not /v1.xx/_ping
req, err := cli.buildRequest(http.MethodHead, path.Join(cli.basePath, "/_ping"), nil, nil) req, err := cli.buildRequest(ctx, http.MethodHead, path.Join(cli.basePath, "/_ping"), nil, nil)
if err != nil { if err != nil {
return ping, err return ping, err
} }
serverResp, err := cli.doRequest(ctx, req) serverResp, err := cli.doRequest(req)
if err == nil { if err == nil {
defer ensureReaderClosed(serverResp) defer ensureReaderClosed(serverResp)
switch serverResp.statusCode { switch serverResp.statusCode {
@ -37,11 +37,9 @@ func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
return ping, err return ping, err
} }
req, err = cli.buildRequest(http.MethodGet, path.Join(cli.basePath, "/_ping"), nil, nil) // HEAD failed; fallback to GET.
if err != nil { req.Method = http.MethodGet
return ping, err serverResp, err = cli.doRequest(req)
}
serverResp, err = cli.doRequest(ctx, req)
defer ensureReaderClosed(serverResp) defer ensureReaderClosed(serverResp)
if err != nil { if err != nil {
return ping, err return ping, err

View File

@ -96,8 +96,8 @@ func encodeBody(obj interface{}, headers http.Header) (io.Reader, http.Header, e
return body, headers, nil return body, headers, nil
} }
func (cli *Client) buildRequest(method, path string, body io.Reader, headers http.Header) (*http.Request, error) { func (cli *Client) buildRequest(ctx context.Context, method, path string, body io.Reader, headers http.Header) (*http.Request, error) {
req, err := http.NewRequest(method, path, body) req, err := http.NewRequestWithContext(ctx, method, path, body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -117,12 +117,12 @@ func (cli *Client) buildRequest(method, path string, body io.Reader, headers htt
} }
func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers http.Header) (serverResponse, error) { func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers http.Header) (serverResponse, error) {
req, err := cli.buildRequest(method, cli.getAPIPath(ctx, path, query), body, headers) req, err := cli.buildRequest(ctx, method, cli.getAPIPath(ctx, path, query), body, headers)
if err != nil { if err != nil {
return serverResponse{}, err return serverResponse{}, err
} }
resp, err := cli.doRequest(ctx, req) resp, err := cli.doRequest(req)
switch { switch {
case errors.Is(err, context.Canceled): case errors.Is(err, context.Canceled):
return serverResponse{}, errdefs.Cancelled(err) return serverResponse{}, errdefs.Cancelled(err)
@ -134,10 +134,9 @@ func (cli *Client) sendRequest(ctx context.Context, method, path string, query u
return resp, errdefs.FromStatusCode(err, resp.statusCode) return resp, errdefs.FromStatusCode(err, resp.statusCode)
} }
func (cli *Client) doRequest(ctx context.Context, req *http.Request) (serverResponse, error) { func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
serverResp := serverResponse{statusCode: -1, reqURL: req.URL} serverResp := serverResponse{statusCode: -1, reqURL: req.URL}
req = req.WithContext(ctx)
resp, err := cli.client.Do(req) resp, err := cli.client.Do(req)
if err != nil { if err != nil {
if cli.scheme != "https" && strings.Contains(err.Error(), "malformed HTTP response") { if cli.scheme != "https" && strings.Contains(err.Error(), "malformed HTTP response") {
@ -227,18 +226,17 @@ func (cli *Client) checkResponseErr(serverResp serverResponse) error {
return fmt.Errorf("request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), serverResp.reqURL) return fmt.Errorf("request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), serverResp.reqURL)
} }
var errorMessage string var daemonErr error
if serverResp.header.Get("Content-Type") == "application/json" && (cli.version == "" || versions.GreaterThan(cli.version, "1.23")) { if serverResp.header.Get("Content-Type") == "application/json" && (cli.version == "" || versions.GreaterThan(cli.version, "1.23")) {
var errorResponse types.ErrorResponse var errorResponse types.ErrorResponse
if err := json.Unmarshal(body, &errorResponse); err != nil { if err := json.Unmarshal(body, &errorResponse); err != nil {
return errors.Wrap(err, "Error reading JSON") return errors.Wrap(err, "Error reading JSON")
} }
errorMessage = strings.TrimSpace(errorResponse.Message) daemonErr = errors.New(strings.TrimSpace(errorResponse.Message))
} else { } else {
errorMessage = strings.TrimSpace(string(body)) daemonErr = errors.New(strings.TrimSpace(string(body)))
} }
return errors.Wrap(daemonErr, "Error response from daemon")
return errors.Wrap(errors.New(errorMessage), "Error response from daemon")
} }
func (cli *Client) addHeaders(req *http.Request, headers http.Header) *http.Request { func (cli *Client) addHeaders(req *http.Request, headers http.Header) *http.Request {

View File

@ -0,0 +1,46 @@
package multierror
import (
"strings"
)
// Join is a drop-in replacement for errors.Join with better formatting.
func Join(errs ...error) error {
n := 0
for _, err := range errs {
if err != nil {
n++
}
}
if n == 0 {
return nil
}
e := &joinError{
errs: make([]error, 0, n),
}
for _, err := range errs {
if err != nil {
e.errs = append(e.errs, err)
}
}
return e
}
type joinError struct {
errs []error
}
func (e *joinError) Error() string {
if len(e.errs) == 1 {
return strings.TrimSpace(e.errs[0].Error())
}
stringErrs := make([]string, 0, len(e.errs))
for _, subErr := range e.errs {
stringErrs = append(stringErrs, strings.Replace(subErr.Error(), "\n", "\n\t", -1))
}
return "* " + strings.Join(stringErrs, "\n* ")
}
func (e *joinError) Unwrap() []error {
return e.errs
}

View File

@ -224,6 +224,25 @@ func ApplyUncompressedLayer(dest string, layer io.Reader, options *TarOptions) (
return applyLayerHandler(dest, layer, options, false) return applyLayerHandler(dest, layer, options, false)
} }
// IsEmpty checks if the tar archive is empty (doesn't contain any entries).
func IsEmpty(rd io.Reader) (bool, error) {
decompRd, err := DecompressStream(rd)
if err != nil {
return true, fmt.Errorf("failed to decompress archive: %v", err)
}
defer decompRd.Close()
tarReader := tar.NewReader(decompRd)
if _, err := tarReader.Next(); err != nil {
if err == io.EOF {
return true, nil
}
return false, fmt.Errorf("failed to read next archive header: %v", err)
}
return false, nil
}
// do the bulk load of ApplyLayer, but allow for not calling DecompressStream // do the bulk load of ApplyLayer, but allow for not calling DecompressStream
func applyLayerHandler(dest string, layer io.Reader, options *TarOptions, decompress bool) (int64, error) { func applyLayerHandler(dest string, layer io.Reader, options *TarOptions, decompress bool) (int64, error) {
dest = filepath.Clean(dest) dest = filepath.Clean(dest)

4
vendor/modules.txt vendored
View File

@ -49,11 +49,12 @@ github.com/docker/distribution/registry/client/transport
github.com/docker/distribution/registry/storage/cache github.com/docker/distribution/registry/storage/cache
github.com/docker/distribution/registry/storage/cache/memory github.com/docker/distribution/registry/storage/cache/memory
github.com/docker/distribution/uuid github.com/docker/distribution/uuid
# github.com/docker/docker v24.0.0-rc.2.0.20230807181406-4b19b2f4babd+incompatible # github.com/docker/docker v24.0.0-rc.2.0.20230828170219-a65c948e7edf+incompatible
## explicit ## explicit
github.com/docker/docker/api github.com/docker/docker/api
github.com/docker/docker/api/types github.com/docker/docker/api/types
github.com/docker/docker/api/types/blkiodev github.com/docker/docker/api/types/blkiodev
github.com/docker/docker/api/types/checkpoint
github.com/docker/docker/api/types/container github.com/docker/docker/api/types/container
github.com/docker/docker/api/types/events github.com/docker/docker/api/types/events
github.com/docker/docker/api/types/filters github.com/docker/docker/api/types/filters
@ -72,6 +73,7 @@ github.com/docker/docker/builder/remotecontext/git
github.com/docker/docker/builder/remotecontext/urlutil github.com/docker/docker/builder/remotecontext/urlutil
github.com/docker/docker/client github.com/docker/docker/client
github.com/docker/docker/errdefs github.com/docker/docker/errdefs
github.com/docker/docker/internal/multierror
github.com/docker/docker/pkg/archive github.com/docker/docker/pkg/archive
github.com/docker/docker/pkg/homedir github.com/docker/docker/pkg/homedir
github.com/docker/docker/pkg/idtools github.com/docker/docker/pkg/idtools