mirror of https://github.com/docker/cli.git
vendor: github.com/docker/docker a65c948e7edf (v25.0.0-dev)
full diff: 4b19b2f4ba...a65c948e7e
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
79f24c7afb
commit
d40fc1a0fa
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,12 @@ 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"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewFormat returns a format for use with a checkpoint Context
|
// NewFormat returns a format for use with a checkpoint Context
|
||||||
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
},
|
},
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"})
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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=
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
type errInvalidParameter struct{ error }
|
||||||
|
|
||||||
|
func (e *errInvalidParameter) InvalidParameter() {}
|
||||||
|
|
||||||
|
func (e *errInvalidParameter) Unwrap() error {
|
||||||
|
return e.error
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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"`
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 != "" {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue