mirror of https://github.com/docker/cli.git
Merge pull request #5134 from thaJeztah/bump_engine
vendor: github.com/docker/docker a736d0701c41 (master, v27.0.0-dev)
This commit is contained in:
commit
cba002eb5e
|
@ -17,8 +17,8 @@ import (
|
||||||
type fakeClient struct {
|
type fakeClient struct {
|
||||||
client.Client
|
client.Client
|
||||||
inspectFunc func(string) (types.ContainerJSON, error)
|
inspectFunc func(string) (types.ContainerJSON, error)
|
||||||
execInspectFunc func(execID string) (types.ContainerExecInspect, error)
|
execInspectFunc func(execID string) (container.ExecInspect, error)
|
||||||
execCreateFunc func(containerID string, config types.ExecConfig) (types.IDResponse, error)
|
execCreateFunc func(containerID string, options container.ExecOptions) (types.IDResponse, error)
|
||||||
createContainerFunc func(config *container.Config,
|
createContainerFunc func(config *container.Config,
|
||||||
hostConfig *container.HostConfig,
|
hostConfig *container.HostConfig,
|
||||||
networkingConfig *network.NetworkingConfig,
|
networkingConfig *network.NetworkingConfig,
|
||||||
|
@ -27,8 +27,8 @@ type fakeClient struct {
|
||||||
containerStartFunc func(containerID string, options container.StartOptions) error
|
containerStartFunc func(containerID string, options container.StartOptions) error
|
||||||
imageCreateFunc func(parentReference string, options image.CreateOptions) (io.ReadCloser, error)
|
imageCreateFunc func(parentReference string, options image.CreateOptions) (io.ReadCloser, error)
|
||||||
infoFunc func() (system.Info, error)
|
infoFunc func() (system.Info, error)
|
||||||
containerStatPathFunc func(containerID, path string) (types.ContainerPathStat, error)
|
containerStatPathFunc func(containerID, path string) (container.PathStat, error)
|
||||||
containerCopyFromFunc func(containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
|
containerCopyFromFunc func(containerID, srcPath string) (io.ReadCloser, container.PathStat, error)
|
||||||
logFunc func(string, container.LogsOptions) (io.ReadCloser, error)
|
logFunc func(string, container.LogsOptions) (io.ReadCloser, error)
|
||||||
waitFunc func(string) (<-chan container.WaitResponse, <-chan error)
|
waitFunc func(string) (<-chan container.WaitResponse, <-chan error)
|
||||||
containerListFunc func(container.ListOptions) ([]types.Container, error)
|
containerListFunc func(container.ListOptions) ([]types.Container, error)
|
||||||
|
@ -36,7 +36,7 @@ type fakeClient struct {
|
||||||
containerExecResizeFunc func(id string, options container.ResizeOptions) error
|
containerExecResizeFunc func(id string, options container.ResizeOptions) error
|
||||||
containerRemoveFunc func(ctx context.Context, containerID string, options container.RemoveOptions) error
|
containerRemoveFunc func(ctx context.Context, containerID string, options container.RemoveOptions) error
|
||||||
containerKillFunc func(ctx context.Context, containerID, signal string) error
|
containerKillFunc func(ctx context.Context, containerID, signal string) error
|
||||||
containerPruneFunc func(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error)
|
containerPruneFunc func(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error)
|
||||||
containerAttachFunc func(ctx context.Context, containerID string, options container.AttachOptions) (types.HijackedResponse, error)
|
containerAttachFunc func(ctx context.Context, containerID string, options container.AttachOptions) (types.HijackedResponse, error)
|
||||||
Version string
|
Version string
|
||||||
}
|
}
|
||||||
|
@ -55,21 +55,21 @@ func (f *fakeClient) ContainerInspect(_ context.Context, containerID string) (ty
|
||||||
return types.ContainerJSON{}, nil
|
return types.ContainerJSON{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeClient) ContainerExecCreate(_ context.Context, containerID string, config types.ExecConfig) (types.IDResponse, error) {
|
func (f *fakeClient) ContainerExecCreate(_ context.Context, containerID string, config container.ExecOptions) (types.IDResponse, error) {
|
||||||
if f.execCreateFunc != nil {
|
if f.execCreateFunc != nil {
|
||||||
return f.execCreateFunc(containerID, config)
|
return f.execCreateFunc(containerID, config)
|
||||||
}
|
}
|
||||||
return types.IDResponse{}, nil
|
return types.IDResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeClient) ContainerExecInspect(_ context.Context, execID string) (types.ContainerExecInspect, error) {
|
func (f *fakeClient) ContainerExecInspect(_ context.Context, execID string) (container.ExecInspect, error) {
|
||||||
if f.execInspectFunc != nil {
|
if f.execInspectFunc != nil {
|
||||||
return f.execInspectFunc(execID)
|
return f.execInspectFunc(execID)
|
||||||
}
|
}
|
||||||
return types.ContainerExecInspect{}, nil
|
return container.ExecInspect{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeClient) ContainerExecStart(context.Context, string, types.ExecStartCheck) error {
|
func (f *fakeClient) ContainerExecStart(context.Context, string, container.ExecStartOptions) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,18 +108,18 @@ func (f *fakeClient) Info(_ context.Context) (system.Info, error) {
|
||||||
return system.Info{}, nil
|
return system.Info{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeClient) ContainerStatPath(_ context.Context, containerID, path string) (types.ContainerPathStat, error) {
|
func (f *fakeClient) ContainerStatPath(_ context.Context, containerID, path string) (container.PathStat, error) {
|
||||||
if f.containerStatPathFunc != nil {
|
if f.containerStatPathFunc != nil {
|
||||||
return f.containerStatPathFunc(containerID, path)
|
return f.containerStatPathFunc(containerID, path)
|
||||||
}
|
}
|
||||||
return types.ContainerPathStat{}, nil
|
return container.PathStat{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeClient) CopyFromContainer(_ context.Context, containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
|
func (f *fakeClient) CopyFromContainer(_ context.Context, containerID, srcPath string) (io.ReadCloser, container.PathStat, error) {
|
||||||
if f.containerCopyFromFunc != nil {
|
if f.containerCopyFromFunc != nil {
|
||||||
return f.containerCopyFromFunc(containerID, srcPath)
|
return f.containerCopyFromFunc(containerID, srcPath)
|
||||||
}
|
}
|
||||||
return nil, types.ContainerPathStat{}, nil
|
return nil, container.PathStat{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeClient) ContainerLogs(_ context.Context, containerID string, options container.LogsOptions) (io.ReadCloser, error) {
|
func (f *fakeClient) ContainerLogs(_ context.Context, containerID string, options container.LogsOptions) (io.ReadCloser, error) {
|
||||||
|
@ -168,11 +168,11 @@ func (f *fakeClient) ContainerKill(ctx context.Context, containerID, signal stri
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeClient) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) {
|
func (f *fakeClient) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
|
||||||
if f.containerPruneFunc != nil {
|
if f.containerPruneFunc != nil {
|
||||||
return f.containerPruneFunc(ctx, pruneFilters)
|
return f.containerPruneFunc(ctx, pruneFilters)
|
||||||
}
|
}
|
||||||
return types.ContainersPruneReport{}, nil
|
return container.PruneReport{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeClient) ContainerAttach(ctx context.Context, containerID string, options container.AttachOptions) (types.HijackedResponse, error) {
|
func (f *fakeClient) ContainerAttach(ctx context.Context, containerID string, options container.AttachOptions) (types.HijackedResponse, error) {
|
||||||
|
|
|
@ -15,7 +15,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/streams"
|
"github.com/docker/cli/cli/streams"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
units "github.com/docker/go-units"
|
units "github.com/docker/go-units"
|
||||||
|
@ -397,7 +397,7 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
options := types.CopyToContainerOptions{
|
options := container.CopyToContainerOptions{
|
||||||
AllowOverwriteDirWithFile: false,
|
AllowOverwriteDirWithFile: false,
|
||||||
CopyUIDGID: copyConfig.copyUIDGID,
|
CopyUIDGID: copyConfig.copyUIDGID,
|
||||||
}
|
}
|
||||||
|
@ -433,18 +433,18 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
|
||||||
// so we have to check for a `/` or `.` prefix. Also, in the case of a Windows
|
// so we have to check for a `/` or `.` prefix. Also, in the case of a Windows
|
||||||
// client, a `:` could be part of an absolute Windows path, in which case it
|
// client, a `:` could be part of an absolute Windows path, in which case it
|
||||||
// is immediately proceeded by a backslash.
|
// is immediately proceeded by a backslash.
|
||||||
func splitCpArg(arg string) (container, path string) {
|
func splitCpArg(arg string) (ctr, path string) {
|
||||||
if system.IsAbs(arg) {
|
if system.IsAbs(arg) {
|
||||||
// Explicit local absolute path, e.g., `C:\foo` or `/foo`.
|
// Explicit local absolute path, e.g., `C:\foo` or `/foo`.
|
||||||
return "", arg
|
return "", arg
|
||||||
}
|
}
|
||||||
|
|
||||||
container, path, ok := strings.Cut(arg, ":")
|
ctr, path, ok := strings.Cut(arg, ":")
|
||||||
if !ok || strings.HasPrefix(container, ".") {
|
if !ok || strings.HasPrefix(ctr, ".") {
|
||||||
// Either there's no `:` in the arg
|
// Either there's no `:` in the arg
|
||||||
// OR it's an explicit local relative path like `./file:name.txt`.
|
// OR it's an explicit local relative path like `./file:name.txt`.
|
||||||
return "", arg
|
return "", arg
|
||||||
}
|
}
|
||||||
|
|
||||||
return container, path
|
return ctr, path
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,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/container"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
is "gotest.tools/v3/assert/cmp"
|
||||||
|
@ -51,15 +51,16 @@ func TestRunCopyWithInvalidArguments(t *testing.T) {
|
||||||
func TestRunCopyFromContainerToStdout(t *testing.T) {
|
func TestRunCopyFromContainerToStdout(t *testing.T) {
|
||||||
tarContent := "the tar content"
|
tarContent := "the tar content"
|
||||||
|
|
||||||
fakeClient := &fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
|
containerCopyFromFunc: func(ctr, srcPath string) (io.ReadCloser, container.PathStat, error) {
|
||||||
assert.Check(t, is.Equal("container", container))
|
assert.Check(t, is.Equal("container", ctr))
|
||||||
return io.NopCloser(strings.NewReader(tarContent)), types.ContainerPathStat{}, nil
|
return io.NopCloser(strings.NewReader(tarContent)), container.PathStat{}, nil
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
options := copyOptions{source: "container:/path", destination: "-"}
|
err := runCopy(context.TODO(), cli, copyOptions{
|
||||||
cli := test.NewFakeCli(fakeClient)
|
source: "container:/path",
|
||||||
err := runCopy(context.TODO(), cli, options)
|
destination: "-",
|
||||||
|
})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Check(t, is.Equal(tarContent, cli.OutBuffer().String()))
|
assert.Check(t, is.Equal(tarContent, cli.OutBuffer().String()))
|
||||||
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
||||||
|
@ -70,16 +71,18 @@ func TestRunCopyFromContainerToFilesystem(t *testing.T) {
|
||||||
fs.WithFile("file1", "content\n"))
|
fs.WithFile("file1", "content\n"))
|
||||||
defer destDir.Remove()
|
defer destDir.Remove()
|
||||||
|
|
||||||
fakeClient := &fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
|
containerCopyFromFunc: func(ctr, srcPath string) (io.ReadCloser, container.PathStat, error) {
|
||||||
assert.Check(t, is.Equal("container", container))
|
assert.Check(t, is.Equal("container", ctr))
|
||||||
readCloser, err := archive.TarWithOptions(destDir.Path(), &archive.TarOptions{})
|
readCloser, err := archive.TarWithOptions(destDir.Path(), &archive.TarOptions{})
|
||||||
return readCloser, types.ContainerPathStat{}, err
|
return readCloser, container.PathStat{}, err
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
options := copyOptions{source: "container:/path", destination: destDir.Path(), quiet: true}
|
err := runCopy(context.TODO(), cli, copyOptions{
|
||||||
cli := test.NewFakeCli(fakeClient)
|
source: "container:/path",
|
||||||
err := runCopy(context.TODO(), cli, options)
|
destination: destDir.Path(),
|
||||||
|
quiet: true,
|
||||||
|
})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Check(t, is.Equal("", cli.OutBuffer().String()))
|
assert.Check(t, is.Equal("", cli.OutBuffer().String()))
|
||||||
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
|
||||||
|
@ -94,20 +97,17 @@ func TestRunCopyFromContainerToFilesystemMissingDestinationDirectory(t *testing.
|
||||||
fs.WithFile("file1", "content\n"))
|
fs.WithFile("file1", "content\n"))
|
||||||
defer destDir.Remove()
|
defer destDir.Remove()
|
||||||
|
|
||||||
fakeClient := &fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
|
containerCopyFromFunc: func(ctr, srcPath string) (io.ReadCloser, container.PathStat, error) {
|
||||||
assert.Check(t, is.Equal("container", container))
|
assert.Check(t, is.Equal("container", ctr))
|
||||||
readCloser, err := archive.TarWithOptions(destDir.Path(), &archive.TarOptions{})
|
readCloser, err := archive.TarWithOptions(destDir.Path(), &archive.TarOptions{})
|
||||||
return readCloser, types.ContainerPathStat{}, err
|
return readCloser, container.PathStat{}, err
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
|
err := runCopy(context.TODO(), cli, copyOptions{
|
||||||
options := copyOptions{
|
|
||||||
source: "container:/path",
|
source: "container:/path",
|
||||||
destination: destDir.Join("missing", "foo"),
|
destination: destDir.Join("missing", "foo"),
|
||||||
}
|
})
|
||||||
cli := test.NewFakeCli(fakeClient)
|
|
||||||
err := runCopy(context.TODO(), cli, options)
|
|
||||||
assert.ErrorContains(t, err, destDir.Join("missing"))
|
assert.ErrorContains(t, err, destDir.Join("missing"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,12 +115,11 @@ func TestRunCopyToContainerFromFileWithTrailingSlash(t *testing.T) {
|
||||||
srcFile := fs.NewFile(t, t.Name())
|
srcFile := fs.NewFile(t, t.Name())
|
||||||
defer srcFile.Remove()
|
defer srcFile.Remove()
|
||||||
|
|
||||||
options := copyOptions{
|
cli := test.NewFakeCli(&fakeClient{})
|
||||||
|
err := runCopy(context.TODO(), cli, copyOptions{
|
||||||
source: srcFile.Path() + string(os.PathSeparator),
|
source: srcFile.Path() + string(os.PathSeparator),
|
||||||
destination: "container:/path",
|
destination: "container:/path",
|
||||||
}
|
})
|
||||||
cli := test.NewFakeCli(&fakeClient{})
|
|
||||||
err := runCopy(context.TODO(), cli, options)
|
|
||||||
|
|
||||||
expectedError := "not a directory"
|
expectedError := "not a directory"
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
|
@ -130,12 +129,11 @@ func TestRunCopyToContainerFromFileWithTrailingSlash(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunCopyToContainerSourceDoesNotExist(t *testing.T) {
|
func TestRunCopyToContainerSourceDoesNotExist(t *testing.T) {
|
||||||
options := copyOptions{
|
cli := test.NewFakeCli(&fakeClient{})
|
||||||
|
err := runCopy(context.TODO(), cli, copyOptions{
|
||||||
source: "/does/not/exist",
|
source: "/does/not/exist",
|
||||||
destination: "container:/path",
|
destination: "container:/path",
|
||||||
}
|
})
|
||||||
cli := test.NewFakeCli(&fakeClient{})
|
|
||||||
err := runCopy(context.TODO(), cli, options)
|
|
||||||
expected := "no such file or directory"
|
expected := "no such file or directory"
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
expected = "cannot find the file specified"
|
expected = "cannot find the file specified"
|
||||||
|
@ -184,17 +182,19 @@ func TestSplitCpArg(t *testing.T) {
|
||||||
t.Run(testcase.doc, func(t *testing.T) {
|
t.Run(testcase.doc, func(t *testing.T) {
|
||||||
skip.If(t, testcase.os != "" && testcase.os != runtime.GOOS)
|
skip.If(t, testcase.os != "" && testcase.os != runtime.GOOS)
|
||||||
|
|
||||||
container, path := splitCpArg(testcase.path)
|
ctr, path := splitCpArg(testcase.path)
|
||||||
assert.Check(t, is.Equal(testcase.expectedContainer, container))
|
assert.Check(t, is.Equal(testcase.expectedContainer, ctr))
|
||||||
assert.Check(t, is.Equal(testcase.expectedPath, path))
|
assert.Check(t, is.Equal(testcase.expectedPath, path))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunCopyFromContainerToFilesystemIrregularDestination(t *testing.T) {
|
func TestRunCopyFromContainerToFilesystemIrregularDestination(t *testing.T) {
|
||||||
options := copyOptions{source: "container:/dev/null", destination: "/dev/random"}
|
|
||||||
cli := test.NewFakeCli(nil)
|
cli := test.NewFakeCli(nil)
|
||||||
err := runCopy(context.TODO(), cli, options)
|
err := runCopy(context.TODO(), cli, copyOptions{
|
||||||
|
source: "container:/dev/null",
|
||||||
|
destination: "/dev/random",
|
||||||
|
})
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
expected := `"/dev/random" must be a directory or a regular file`
|
expected := `"/dev/random" must be a directory or a regular file`
|
||||||
assert.ErrorContains(t, err, expected)
|
assert.ErrorContains(t, err, expected)
|
||||||
|
|
|
@ -12,7 +12,8 @@ import (
|
||||||
"github.com/docker/cli/cli/config/configfile"
|
"github.com/docker/cli/cli/config/configfile"
|
||||||
"github.com/docker/cli/opts"
|
"github.com/docker/cli/opts"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
apiclient "github.com/docker/docker/client"
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/docker/client"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -43,19 +44,18 @@ func NewExecOptions() ExecOptions {
|
||||||
// NewExecCommand creates a new cobra.Command for `docker exec`
|
// NewExecCommand creates a new cobra.Command for `docker exec`
|
||||||
func NewExecCommand(dockerCli command.Cli) *cobra.Command {
|
func NewExecCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
options := NewExecOptions()
|
options := NewExecOptions()
|
||||||
var container string
|
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "exec [OPTIONS] CONTAINER COMMAND [ARG...]",
|
Use: "exec [OPTIONS] CONTAINER COMMAND [ARG...]",
|
||||||
Short: "Execute a command in a running container",
|
Short: "Execute a command in a running container",
|
||||||
Args: cli.RequiresMinArgs(2),
|
Args: cli.RequiresMinArgs(2),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
container = args[0]
|
containerIDorName := args[0]
|
||||||
options.Command = args[1:]
|
options.Command = args[1:]
|
||||||
return RunExec(cmd.Context(), dockerCli, container, options)
|
return RunExec(cmd.Context(), dockerCli, containerIDorName, options)
|
||||||
},
|
},
|
||||||
ValidArgsFunction: completion.ContainerNames(dockerCli, false, func(container types.Container) bool {
|
ValidArgsFunction: completion.ContainerNames(dockerCli, false, func(ctr types.Container) bool {
|
||||||
return container.State != "paused"
|
return ctr.State != "paused"
|
||||||
}),
|
}),
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
"category-top": "2",
|
"category-top": "2",
|
||||||
|
@ -79,47 +79,41 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
flags.StringVarP(&options.Workdir, "workdir", "w", "", "Working directory inside the container")
|
flags.StringVarP(&options.Workdir, "workdir", "w", "", "Working directory inside the container")
|
||||||
flags.SetAnnotation("workdir", "version", []string{"1.35"})
|
flags.SetAnnotation("workdir", "version", []string{"1.35"})
|
||||||
|
|
||||||
cmd.RegisterFlagCompletionFunc(
|
_ = cmd.RegisterFlagCompletionFunc("env", func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||||
"env",
|
return os.Environ(), cobra.ShellCompDirectiveNoFileComp
|
||||||
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
})
|
||||||
return os.Environ(), cobra.ShellCompDirectiveNoFileComp
|
_ = cmd.RegisterFlagCompletionFunc("env-file", func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||||
},
|
return nil, cobra.ShellCompDirectiveDefault // _filedir
|
||||||
)
|
})
|
||||||
cmd.RegisterFlagCompletionFunc(
|
|
||||||
"env-file",
|
|
||||||
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
|
||||||
return nil, cobra.ShellCompDirectiveDefault // _filedir
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunExec executes an `exec` command
|
// RunExec executes an `exec` command
|
||||||
func RunExec(ctx context.Context, dockerCli command.Cli, container string, options ExecOptions) error {
|
func RunExec(ctx context.Context, dockerCli command.Cli, containerIDorName string, options ExecOptions) error {
|
||||||
execConfig, err := parseExec(options, dockerCli.ConfigFile())
|
execOptions, err := parseExec(options, dockerCli.ConfigFile())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
client := dockerCli.Client()
|
apiClient := dockerCli.Client()
|
||||||
|
|
||||||
// We need to check the tty _before_ we do the ContainerExecCreate, because
|
// We need to check the tty _before_ we do the ContainerExecCreate, because
|
||||||
// otherwise if we error out we will leak execIDs on the server (and
|
// otherwise if we error out we will leak execIDs on the server (and
|
||||||
// there's no easy way to clean those up). But also in order to make "not
|
// there's no easy way to clean those up). But also in order to make "not
|
||||||
// exist" errors take precedence we do a dummy inspect first.
|
// exist" errors take precedence we do a dummy inspect first.
|
||||||
if _, err := client.ContainerInspect(ctx, container); err != nil {
|
if _, err := apiClient.ContainerInspect(ctx, containerIDorName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !execConfig.Detach {
|
if !execOptions.Detach {
|
||||||
if err := dockerCli.In().CheckTty(execConfig.AttachStdin, execConfig.Tty); err != nil {
|
if err := dockerCli.In().CheckTty(execOptions.AttachStdin, execOptions.Tty); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fillConsoleSize(execConfig, dockerCli)
|
fillConsoleSize(execOptions, dockerCli)
|
||||||
|
|
||||||
response, err := client.ContainerExecCreate(ctx, container, *execConfig)
|
response, err := apiClient.ContainerExecCreate(ctx, containerIDorName, *execOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -129,52 +123,50 @@ func RunExec(ctx context.Context, dockerCli command.Cli, container string, optio
|
||||||
return errors.New("exec ID empty")
|
return errors.New("exec ID empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
if execConfig.Detach {
|
if execOptions.Detach {
|
||||||
execStartCheck := types.ExecStartCheck{
|
return apiClient.ContainerExecStart(ctx, execID, container.ExecStartOptions{
|
||||||
Detach: execConfig.Detach,
|
Detach: execOptions.Detach,
|
||||||
Tty: execConfig.Tty,
|
Tty: execOptions.Tty,
|
||||||
ConsoleSize: execConfig.ConsoleSize,
|
ConsoleSize: execOptions.ConsoleSize,
|
||||||
}
|
})
|
||||||
return client.ContainerExecStart(ctx, execID, execStartCheck)
|
|
||||||
}
|
}
|
||||||
return interactiveExec(ctx, dockerCli, execConfig, execID)
|
return interactiveExec(ctx, dockerCli, execOptions, execID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fillConsoleSize(execConfig *types.ExecConfig, dockerCli command.Cli) {
|
func fillConsoleSize(execOptions *container.ExecOptions, dockerCli command.Cli) {
|
||||||
if execConfig.Tty {
|
if execOptions.Tty {
|
||||||
height, width := dockerCli.Out().GetTtySize()
|
height, width := dockerCli.Out().GetTtySize()
|
||||||
execConfig.ConsoleSize = &[2]uint{height, width}
|
execOptions.ConsoleSize = &[2]uint{height, width}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func interactiveExec(ctx context.Context, dockerCli command.Cli, execConfig *types.ExecConfig, execID string) error {
|
func interactiveExec(ctx context.Context, dockerCli command.Cli, execOptions *container.ExecOptions, execID string) error {
|
||||||
// Interactive exec requested.
|
// Interactive exec requested.
|
||||||
var (
|
var (
|
||||||
out, stderr io.Writer
|
out, stderr io.Writer
|
||||||
in io.ReadCloser
|
in io.ReadCloser
|
||||||
)
|
)
|
||||||
|
|
||||||
if execConfig.AttachStdin {
|
if execOptions.AttachStdin {
|
||||||
in = dockerCli.In()
|
in = dockerCli.In()
|
||||||
}
|
}
|
||||||
if execConfig.AttachStdout {
|
if execOptions.AttachStdout {
|
||||||
out = dockerCli.Out()
|
out = dockerCli.Out()
|
||||||
}
|
}
|
||||||
if execConfig.AttachStderr {
|
if execOptions.AttachStderr {
|
||||||
if execConfig.Tty {
|
if execOptions.Tty {
|
||||||
stderr = dockerCli.Out()
|
stderr = dockerCli.Out()
|
||||||
} else {
|
} else {
|
||||||
stderr = dockerCli.Err()
|
stderr = dockerCli.Err()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fillConsoleSize(execConfig, dockerCli)
|
fillConsoleSize(execOptions, dockerCli)
|
||||||
|
|
||||||
client := dockerCli.Client()
|
apiClient := dockerCli.Client()
|
||||||
execStartCheck := types.ExecStartCheck{
|
resp, err := apiClient.ContainerExecAttach(ctx, execID, container.ExecAttachOptions{
|
||||||
Tty: execConfig.Tty,
|
Tty: execOptions.Tty,
|
||||||
ConsoleSize: execConfig.ConsoleSize,
|
ConsoleSize: execOptions.ConsoleSize,
|
||||||
}
|
})
|
||||||
resp, err := client.ContainerExecAttach(ctx, execID, execStartCheck)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -191,17 +183,17 @@ func interactiveExec(ctx context.Context, dockerCli command.Cli, execConfig *typ
|
||||||
outputStream: out,
|
outputStream: out,
|
||||||
errorStream: stderr,
|
errorStream: stderr,
|
||||||
resp: resp,
|
resp: resp,
|
||||||
tty: execConfig.Tty,
|
tty: execOptions.Tty,
|
||||||
detachKeys: execConfig.DetachKeys,
|
detachKeys: execOptions.DetachKeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
return streamer.stream(ctx)
|
return streamer.stream(ctx)
|
||||||
}()
|
}()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if execConfig.Tty && dockerCli.In().IsTerminal() {
|
if execOptions.Tty && dockerCli.In().IsTerminal() {
|
||||||
if err := MonitorTtySize(ctx, dockerCli, execID, true); err != nil {
|
if err := MonitorTtySize(ctx, dockerCli, execID, true); err != nil {
|
||||||
fmt.Fprintln(dockerCli.Err(), "Error monitoring TTY size:", err)
|
_, _ = fmt.Fprintln(dockerCli.Err(), "Error monitoring TTY size:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,14 +202,14 @@ func interactiveExec(ctx context.Context, dockerCli command.Cli, execConfig *typ
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return getExecExitStatus(ctx, client, execID)
|
return getExecExitStatus(ctx, apiClient, execID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExecExitStatus(ctx context.Context, client apiclient.ContainerAPIClient, execID string) error {
|
func getExecExitStatus(ctx context.Context, apiClient client.ContainerAPIClient, execID string) error {
|
||||||
resp, err := client.ContainerExecInspect(ctx, execID)
|
resp, err := apiClient.ContainerExecInspect(ctx, execID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If we can't connect, then the daemon probably died.
|
// If we can't connect, then the daemon probably died.
|
||||||
if !apiclient.IsErrConnectionFailed(err) {
|
if !client.IsErrConnectionFailed(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return cli.StatusError{StatusCode: -1}
|
return cli.StatusError{StatusCode: -1}
|
||||||
|
@ -231,8 +223,8 @@ func getExecExitStatus(ctx context.Context, client apiclient.ContainerAPIClient,
|
||||||
|
|
||||||
// parseExec parses the specified args for the specified command and generates
|
// parseExec parses the specified args for the specified command and generates
|
||||||
// an ExecConfig from it.
|
// an ExecConfig from it.
|
||||||
func parseExec(execOpts ExecOptions, configFile *configfile.ConfigFile) (*types.ExecConfig, error) {
|
func parseExec(execOpts ExecOptions, configFile *configfile.ConfigFile) (*container.ExecOptions, error) {
|
||||||
execConfig := &types.ExecConfig{
|
execOptions := &container.ExecOptions{
|
||||||
User: execOpts.User,
|
User: execOpts.User,
|
||||||
Privileged: execOpts.Privileged,
|
Privileged: execOpts.Privileged,
|
||||||
Tty: execOpts.TTY,
|
Tty: execOpts.TTY,
|
||||||
|
@ -243,23 +235,23 @@ func parseExec(execOpts ExecOptions, configFile *configfile.ConfigFile) (*types.
|
||||||
|
|
||||||
// collect all the environment variables for the container
|
// collect all the environment variables for the container
|
||||||
var err error
|
var err error
|
||||||
if execConfig.Env, err = opts.ReadKVEnvStrings(execOpts.EnvFile.GetAll(), execOpts.Env.GetAll()); err != nil {
|
if execOptions.Env, err = opts.ReadKVEnvStrings(execOpts.EnvFile.GetAll(), execOpts.Env.GetAll()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If -d is not set, attach to everything by default
|
// If -d is not set, attach to everything by default
|
||||||
if !execOpts.Detach {
|
if !execOpts.Detach {
|
||||||
execConfig.AttachStdout = true
|
execOptions.AttachStdout = true
|
||||||
execConfig.AttachStderr = true
|
execOptions.AttachStderr = true
|
||||||
if execOpts.Interactive {
|
if execOpts.Interactive {
|
||||||
execConfig.AttachStdin = true
|
execOptions.AttachStdin = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if execOpts.DetachKeys != "" {
|
if execOpts.DetachKeys != "" {
|
||||||
execConfig.DetachKeys = execOpts.DetachKeys
|
execOptions.DetachKeys = execOpts.DetachKeys
|
||||||
} else {
|
} else {
|
||||||
execConfig.DetachKeys = configFile.DetachKeys
|
execOptions.DetachKeys = configFile.DetachKeys
|
||||||
}
|
}
|
||||||
return execConfig, nil
|
return execOptions, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/docker/cli/internal/test"
|
"github.com/docker/cli/internal/test"
|
||||||
"github.com/docker/cli/opts"
|
"github.com/docker/cli/opts"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
"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"
|
||||||
|
@ -37,10 +38,10 @@ TWO=2
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
options ExecOptions
|
options ExecOptions
|
||||||
configFile configfile.ConfigFile
|
configFile configfile.ConfigFile
|
||||||
expected types.ExecConfig
|
expected container.ExecOptions
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
expected: types.ExecConfig{
|
expected: container.ExecOptions{
|
||||||
Cmd: []string{"command"},
|
Cmd: []string{"command"},
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
AttachStderr: true,
|
AttachStderr: true,
|
||||||
|
@ -48,7 +49,7 @@ TWO=2
|
||||||
options: withDefaultOpts(ExecOptions{}),
|
options: withDefaultOpts(ExecOptions{}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expected: types.ExecConfig{
|
expected: container.ExecOptions{
|
||||||
Cmd: []string{"command1", "command2"},
|
Cmd: []string{"command1", "command2"},
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
AttachStderr: true,
|
AttachStderr: true,
|
||||||
|
@ -63,7 +64,7 @@ TWO=2
|
||||||
TTY: true,
|
TTY: true,
|
||||||
User: "uid",
|
User: "uid",
|
||||||
}),
|
}),
|
||||||
expected: types.ExecConfig{
|
expected: container.ExecOptions{
|
||||||
User: "uid",
|
User: "uid",
|
||||||
AttachStdin: true,
|
AttachStdin: true,
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
|
@ -74,7 +75,7 @@ TWO=2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
options: withDefaultOpts(ExecOptions{Detach: true}),
|
options: withDefaultOpts(ExecOptions{Detach: true}),
|
||||||
expected: types.ExecConfig{
|
expected: container.ExecOptions{
|
||||||
Detach: true,
|
Detach: true,
|
||||||
Cmd: []string{"command"},
|
Cmd: []string{"command"},
|
||||||
},
|
},
|
||||||
|
@ -85,7 +86,7 @@ TWO=2
|
||||||
Interactive: true,
|
Interactive: true,
|
||||||
Detach: true,
|
Detach: true,
|
||||||
}),
|
}),
|
||||||
expected: types.ExecConfig{
|
expected: container.ExecOptions{
|
||||||
Detach: true,
|
Detach: true,
|
||||||
Tty: true,
|
Tty: true,
|
||||||
Cmd: []string{"command"},
|
Cmd: []string{"command"},
|
||||||
|
@ -94,7 +95,7 @@ TWO=2
|
||||||
{
|
{
|
||||||
options: withDefaultOpts(ExecOptions{Detach: true}),
|
options: withDefaultOpts(ExecOptions{Detach: true}),
|
||||||
configFile: configfile.ConfigFile{DetachKeys: "de"},
|
configFile: configfile.ConfigFile{DetachKeys: "de"},
|
||||||
expected: types.ExecConfig{
|
expected: container.ExecOptions{
|
||||||
Cmd: []string{"command"},
|
Cmd: []string{"command"},
|
||||||
DetachKeys: "de",
|
DetachKeys: "de",
|
||||||
Detach: true,
|
Detach: true,
|
||||||
|
@ -106,14 +107,14 @@ TWO=2
|
||||||
DetachKeys: "ab",
|
DetachKeys: "ab",
|
||||||
}),
|
}),
|
||||||
configFile: configfile.ConfigFile{DetachKeys: "de"},
|
configFile: configfile.ConfigFile{DetachKeys: "de"},
|
||||||
expected: types.ExecConfig{
|
expected: container.ExecOptions{
|
||||||
Cmd: []string{"command"},
|
Cmd: []string{"command"},
|
||||||
DetachKeys: "ab",
|
DetachKeys: "ab",
|
||||||
Detach: true,
|
Detach: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expected: types.ExecConfig{
|
expected: container.ExecOptions{
|
||||||
Cmd: []string{"command"},
|
Cmd: []string{"command"},
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
AttachStderr: true,
|
AttachStderr: true,
|
||||||
|
@ -126,7 +127,7 @@ TWO=2
|
||||||
}(),
|
}(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expected: types.ExecConfig{
|
expected: container.ExecOptions{
|
||||||
Cmd: []string{"command"},
|
Cmd: []string{"command"},
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
AttachStderr: true,
|
AttachStderr: true,
|
||||||
|
@ -206,7 +207,7 @@ func TestRunExec(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func execCreateWithID(_ string, _ types.ExecConfig) (types.IDResponse, error) {
|
func execCreateWithID(_ string, _ container.ExecOptions) (types.IDResponse, error) {
|
||||||
return types.IDResponse{ID: "execid"}, nil
|
return types.IDResponse{ID: "execid"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,9 +236,9 @@ func TestGetExecExitStatus(t *testing.T) {
|
||||||
|
|
||||||
for _, testcase := range testcases {
|
for _, testcase := range testcases {
|
||||||
client := &fakeClient{
|
client := &fakeClient{
|
||||||
execInspectFunc: func(id string) (types.ContainerExecInspect, error) {
|
execInspectFunc: func(id string) (container.ExecInspect, error) {
|
||||||
assert.Check(t, is.Equal(execID, id))
|
assert.Check(t, is.Equal(execID, id))
|
||||||
return types.ContainerExecInspect{ExitCode: testcase.exitCode}, testcase.inspectError
|
return container.ExecInspect{ExitCode: testcase.exitCode}, testcase.inspectError
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := getExecExitStatus(context.Background(), client, execID)
|
err := getExecExitStatus(context.Background(), client, execID)
|
||||||
|
|
|
@ -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/container"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
@ -15,8 +15,8 @@ func TestContainerPrunePromptTermination(t *testing.T) {
|
||||||
t.Cleanup(cancel)
|
t.Cleanup(cancel)
|
||||||
|
|
||||||
cli := test.NewFakeCli(&fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
containerPruneFunc: func(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) {
|
containerPruneFunc: func(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
|
||||||
return types.ContainersPruneReport{}, errors.New("fakeClient containerPruneFunc should not be called")
|
return container.PruneReport{}, errors.New("fakeClient containerPruneFunc should not be called")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
cmd := NewPruneCommand(cli)
|
cmd := NewPruneCommand(cli)
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"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"
|
||||||
flagsHelper "github.com/docker/cli/cli/flags"
|
flagsHelper "github.com/docker/cli/cli/flags"
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"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"
|
||||||
|
@ -164,7 +163,7 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
|
||||||
// is not valid for filtering containers.
|
// is not valid for filtering containers.
|
||||||
f := options.Filters.Clone()
|
f := options.Filters.Clone()
|
||||||
f.Add("type", string(events.ContainerEventType))
|
f.Add("type", string(events.ContainerEventType))
|
||||||
eventChan, errChan := apiClient.Events(ctx, types.EventsOptions{
|
eventChan, errChan := apiClient.Events(ctx, events.ListOptions{
|
||||||
Filters: f,
|
Filters: f,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"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"
|
||||||
|
@ -68,11 +67,11 @@ func legacyWaitExitOrRemoved(ctx context.Context, apiClient client.APIClient, co
|
||||||
f := filters.NewArgs()
|
f := filters.NewArgs()
|
||||||
f.Add("type", "container")
|
f.Add("type", "container")
|
||||||
f.Add("container", containerID)
|
f.Add("container", containerID)
|
||||||
options := types.EventsOptions{
|
|
||||||
Filters: f,
|
|
||||||
}
|
|
||||||
eventCtx, cancel := context.WithCancel(ctx)
|
eventCtx, cancel := context.WithCancel(ctx)
|
||||||
eventq, errq := apiClient.Events(eventCtx, options)
|
eventq, errq := apiClient.Events(eventCtx, events.ListOptions{
|
||||||
|
Filters: f,
|
||||||
|
})
|
||||||
|
|
||||||
eventProcessor := func(e events.Message) bool {
|
eventProcessor := func(e events.Message) bool {
|
||||||
stopProcessing := false
|
stopProcessing := false
|
||||||
|
|
|
@ -21,11 +21,11 @@ type fakeClient struct {
|
||||||
imagePushFunc func(ref string, options image.PushOptions) (io.ReadCloser, error)
|
imagePushFunc func(ref string, options image.PushOptions) (io.ReadCloser, error)
|
||||||
infoFunc func() (system.Info, error)
|
infoFunc func() (system.Info, error)
|
||||||
imagePullFunc func(ref string, options image.PullOptions) (io.ReadCloser, error)
|
imagePullFunc func(ref string, options image.PullOptions) (io.ReadCloser, error)
|
||||||
imagesPruneFunc func(pruneFilter filters.Args) (types.ImagesPruneReport, error)
|
imagesPruneFunc func(pruneFilter filters.Args) (image.PruneReport, error)
|
||||||
imageLoadFunc func(input io.Reader, quiet bool) (types.ImageLoadResponse, error)
|
imageLoadFunc func(input io.Reader, quiet bool) (image.LoadResponse, error)
|
||||||
imageListFunc func(options image.ListOptions) ([]image.Summary, error)
|
imageListFunc func(options image.ListOptions) ([]image.Summary, error)
|
||||||
imageInspectFunc func(image string) (types.ImageInspect, []byte, error)
|
imageInspectFunc func(image string) (types.ImageInspect, []byte, error)
|
||||||
imageImportFunc func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
|
imageImportFunc func(source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
|
||||||
imageHistoryFunc func(image string) ([]image.HistoryResponseItem, error)
|
imageHistoryFunc func(image string) ([]image.HistoryResponseItem, error)
|
||||||
imageBuildFunc func(context.Context, io.Reader, types.ImageBuildOptions) (types.ImageBuildResponse, error)
|
imageBuildFunc func(context.Context, io.Reader, types.ImageBuildOptions) (types.ImageBuildResponse, error)
|
||||||
}
|
}
|
||||||
|
@ -74,18 +74,18 @@ func (cli *fakeClient) ImagePull(_ context.Context, ref string, options image.Pu
|
||||||
return io.NopCloser(strings.NewReader("")), nil
|
return io.NopCloser(strings.NewReader("")), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *fakeClient) ImagesPrune(_ context.Context, pruneFilter filters.Args) (types.ImagesPruneReport, error) {
|
func (cli *fakeClient) ImagesPrune(_ context.Context, pruneFilter filters.Args) (image.PruneReport, error) {
|
||||||
if cli.imagesPruneFunc != nil {
|
if cli.imagesPruneFunc != nil {
|
||||||
return cli.imagesPruneFunc(pruneFilter)
|
return cli.imagesPruneFunc(pruneFilter)
|
||||||
}
|
}
|
||||||
return types.ImagesPruneReport{}, nil
|
return image.PruneReport{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *fakeClient) ImageLoad(_ context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) {
|
func (cli *fakeClient) ImageLoad(_ context.Context, input io.Reader, quiet bool) (image.LoadResponse, error) {
|
||||||
if cli.imageLoadFunc != nil {
|
if cli.imageLoadFunc != nil {
|
||||||
return cli.imageLoadFunc(input, quiet)
|
return cli.imageLoadFunc(input, quiet)
|
||||||
}
|
}
|
||||||
return types.ImageLoadResponse{}, nil
|
return image.LoadResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *fakeClient) ImageList(_ context.Context, options image.ListOptions) ([]image.Summary, error) {
|
func (cli *fakeClient) ImageList(_ context.Context, options image.ListOptions) ([]image.Summary, error) {
|
||||||
|
@ -102,7 +102,7 @@ func (cli *fakeClient) ImageInspectWithRaw(_ context.Context, img string) (types
|
||||||
return types.ImageInspect{}, nil, nil
|
return types.ImageInspect{}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *fakeClient) ImageImport(_ context.Context, source types.ImageImportSource, ref string,
|
func (cli *fakeClient) ImageImport(_ context.Context, source image.ImportSource, ref string,
|
||||||
options image.ImportOptions,
|
options image.ImportOptions,
|
||||||
) (io.ReadCloser, error) {
|
) (io.ReadCloser, error) {
|
||||||
if cli.imageImportFunc != nil {
|
if cli.imageImportFunc != nil {
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
dockeropts "github.com/docker/cli/opts"
|
dockeropts "github.com/docker/cli/opts"
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -53,17 +52,17 @@ func NewImportCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runImport(ctx context.Context, dockerCli command.Cli, options importOptions) error {
|
func runImport(ctx context.Context, dockerCli command.Cli, options importOptions) error {
|
||||||
var source types.ImageImportSource
|
var source image.ImportSource
|
||||||
switch {
|
switch {
|
||||||
case options.source == "-":
|
case options.source == "-":
|
||||||
// import from STDIN
|
// import from STDIN
|
||||||
source = types.ImageImportSource{
|
source = image.ImportSource{
|
||||||
Source: dockerCli.In(),
|
Source: dockerCli.In(),
|
||||||
SourceName: options.source,
|
SourceName: options.source,
|
||||||
}
|
}
|
||||||
case strings.HasPrefix(options.source, "https://"), strings.HasPrefix(options.source, "http://"):
|
case strings.HasPrefix(options.source, "https://"), strings.HasPrefix(options.source, "http://"):
|
||||||
// import from a remote source (handled by the daemon)
|
// import from a remote source (handled by the daemon)
|
||||||
source = types.ImageImportSource{
|
source = image.ImportSource{
|
||||||
SourceName: options.source,
|
SourceName: options.source,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -73,7 +72,7 @@ func runImport(ctx context.Context, dockerCli command.Cli, options importOptions
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
source = types.ImageImportSource{
|
source = image.ImportSource{
|
||||||
Source: file,
|
Source: file,
|
||||||
SourceName: "-",
|
SourceName: "-",
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ 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/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
|
@ -18,7 +17,7 @@ func TestNewImportCommandErrors(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
expectedError string
|
expectedError string
|
||||||
imageImportFunc func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
|
imageImportFunc func(source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "wrong-args",
|
name: "wrong-args",
|
||||||
|
@ -29,7 +28,7 @@ func TestNewImportCommandErrors(t *testing.T) {
|
||||||
name: "import-failed",
|
name: "import-failed",
|
||||||
args: []string{"testdata/import-command-success.input.txt"},
|
args: []string{"testdata/import-command-success.input.txt"},
|
||||||
expectedError: "something went wrong",
|
expectedError: "something went wrong",
|
||||||
imageImportFunc: func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
imageImportFunc: func(source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
||||||
return nil, errors.Errorf("something went wrong")
|
return nil, errors.Errorf("something went wrong")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -53,7 +52,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
imageImportFunc func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
|
imageImportFunc func(source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "simple",
|
name: "simple",
|
||||||
|
@ -66,7 +65,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "double",
|
name: "double",
|
||||||
args: []string{"-", "image:local"},
|
args: []string{"-", "image:local"},
|
||||||
imageImportFunc: func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
imageImportFunc: func(source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
||||||
assert.Check(t, is.Equal("image:local", ref))
|
assert.Check(t, is.Equal("image:local", ref))
|
||||||
return io.NopCloser(strings.NewReader("")), nil
|
return io.NopCloser(strings.NewReader("")), nil
|
||||||
},
|
},
|
||||||
|
@ -74,7 +73,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "message",
|
name: "message",
|
||||||
args: []string{"--message", "test message", "-"},
|
args: []string{"--message", "test message", "-"},
|
||||||
imageImportFunc: func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
imageImportFunc: func(source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
||||||
assert.Check(t, is.Equal("test message", options.Message))
|
assert.Check(t, is.Equal("test message", options.Message))
|
||||||
return io.NopCloser(strings.NewReader("")), nil
|
return io.NopCloser(strings.NewReader("")), nil
|
||||||
},
|
},
|
||||||
|
@ -82,7 +81,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "change",
|
name: "change",
|
||||||
args: []string{"--change", "ENV DEBUG=true", "-"},
|
args: []string{"--change", "ENV DEBUG=true", "-"},
|
||||||
imageImportFunc: func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
imageImportFunc: func(source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
||||||
assert.Check(t, is.Equal("ENV DEBUG=true", options.Changes[0]))
|
assert.Check(t, is.Equal("ENV DEBUG=true", options.Changes[0]))
|
||||||
return io.NopCloser(strings.NewReader("")), nil
|
return io.NopCloser(strings.NewReader("")), nil
|
||||||
},
|
},
|
||||||
|
@ -90,7 +89,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "change legacy syntax",
|
name: "change legacy syntax",
|
||||||
args: []string{"--change", "ENV DEBUG true", "-"},
|
args: []string{"--change", "ENV DEBUG true", "-"},
|
||||||
imageImportFunc: func(source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
imageImportFunc: func(source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
||||||
assert.Check(t, is.Equal("ENV DEBUG true", options.Changes[0]))
|
assert.Check(t, is.Equal("ENV DEBUG true", options.Changes[0]))
|
||||||
return io.NopCloser(strings.NewReader("")), nil
|
return io.NopCloser(strings.NewReader("")), nil
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,7 +7,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/image"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
"gotest.tools/v3/golden"
|
"gotest.tools/v3/golden"
|
||||||
|
@ -19,7 +19,7 @@ func TestNewLoadCommandErrors(t *testing.T) {
|
||||||
args []string
|
args []string
|
||||||
isTerminalIn bool
|
isTerminalIn bool
|
||||||
expectedError string
|
expectedError string
|
||||||
imageLoadFunc func(input io.Reader, quiet bool) (types.ImageLoadResponse, error)
|
imageLoadFunc func(input io.Reader, quiet bool) (image.LoadResponse, error)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "wrong-args",
|
name: "wrong-args",
|
||||||
|
@ -34,8 +34,8 @@ func TestNewLoadCommandErrors(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "pull-error",
|
name: "pull-error",
|
||||||
expectedError: "something went wrong",
|
expectedError: "something went wrong",
|
||||||
imageLoadFunc: func(input io.Reader, quiet bool) (types.ImageLoadResponse, error) {
|
imageLoadFunc: func(input io.Reader, quiet bool) (image.LoadResponse, error) {
|
||||||
return types.ImageLoadResponse{}, errors.Errorf("something went wrong")
|
return image.LoadResponse{}, errors.Errorf("something went wrong")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -62,19 +62,19 @@ func TestNewLoadCommandSuccess(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
imageLoadFunc func(input io.Reader, quiet bool) (types.ImageLoadResponse, error)
|
imageLoadFunc func(input io.Reader, quiet bool) (image.LoadResponse, error)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "simple",
|
name: "simple",
|
||||||
imageLoadFunc: func(input io.Reader, quiet bool) (types.ImageLoadResponse, error) {
|
imageLoadFunc: func(input io.Reader, quiet bool) (image.LoadResponse, error) {
|
||||||
return types.ImageLoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
return image.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "json",
|
name: "json",
|
||||||
imageLoadFunc: func(input io.Reader, quiet bool) (types.ImageLoadResponse, error) {
|
imageLoadFunc: func(input io.Reader, quiet bool) (image.LoadResponse, error) {
|
||||||
json := "{\"ID\": \"1\"}"
|
json := "{\"ID\": \"1\"}"
|
||||||
return types.ImageLoadResponse{
|
return image.LoadResponse{
|
||||||
Body: io.NopCloser(strings.NewReader(json)),
|
Body: io.NopCloser(strings.NewReader(json)),
|
||||||
JSON: true,
|
JSON: true,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -83,8 +83,8 @@ func TestNewLoadCommandSuccess(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "input-file",
|
name: "input-file",
|
||||||
args: []string{"--input", "testdata/load-command-success.input.txt"},
|
args: []string{"--input", "testdata/load-command-success.input.txt"},
|
||||||
imageLoadFunc: func(input io.Reader, quiet bool) (types.ImageLoadResponse, error) {
|
imageLoadFunc: func(input io.Reader, quiet bool) (image.LoadResponse, error) {
|
||||||
return types.ImageLoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
return image.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
|
|
||||||
"github.com/docker/cli/cli/streams"
|
"github.com/docker/cli/cli/streams"
|
||||||
"github.com/docker/cli/internal/test"
|
"github.com/docker/cli/internal/test"
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -23,7 +22,7 @@ func TestNewPruneCommandErrors(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
expectedError string
|
expectedError string
|
||||||
imagesPruneFunc func(pruneFilter filters.Args) (types.ImagesPruneReport, error)
|
imagesPruneFunc func(pruneFilter filters.Args) (image.PruneReport, error)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "wrong-args",
|
name: "wrong-args",
|
||||||
|
@ -34,8 +33,8 @@ func TestNewPruneCommandErrors(t *testing.T) {
|
||||||
name: "prune-error",
|
name: "prune-error",
|
||||||
args: []string{"--force"},
|
args: []string{"--force"},
|
||||||
expectedError: "something went wrong",
|
expectedError: "something went wrong",
|
||||||
imagesPruneFunc: func(pruneFilter filters.Args) (types.ImagesPruneReport, error) {
|
imagesPruneFunc: func(pruneFilter filters.Args) (image.PruneReport, error) {
|
||||||
return types.ImagesPruneReport{}, errors.Errorf("something went wrong")
|
return image.PruneReport{}, errors.Errorf("something went wrong")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -53,22 +52,22 @@ func TestNewPruneCommandSuccess(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
imagesPruneFunc func(pruneFilter filters.Args) (types.ImagesPruneReport, error)
|
imagesPruneFunc func(pruneFilter filters.Args) (image.PruneReport, error)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "all",
|
name: "all",
|
||||||
args: []string{"--all"},
|
args: []string{"--all"},
|
||||||
imagesPruneFunc: func(pruneFilter filters.Args) (types.ImagesPruneReport, error) {
|
imagesPruneFunc: func(pruneFilter filters.Args) (image.PruneReport, error) {
|
||||||
assert.Check(t, is.Equal("false", pruneFilter.Get("dangling")[0]))
|
assert.Check(t, is.Equal("false", pruneFilter.Get("dangling")[0]))
|
||||||
return types.ImagesPruneReport{}, nil
|
return image.PruneReport{}, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "force-deleted",
|
name: "force-deleted",
|
||||||
args: []string{"--force"},
|
args: []string{"--force"},
|
||||||
imagesPruneFunc: func(pruneFilter filters.Args) (types.ImagesPruneReport, error) {
|
imagesPruneFunc: func(pruneFilter filters.Args) (image.PruneReport, error) {
|
||||||
assert.Check(t, is.Equal("true", pruneFilter.Get("dangling")[0]))
|
assert.Check(t, is.Equal("true", pruneFilter.Get("dangling")[0]))
|
||||||
return types.ImagesPruneReport{
|
return image.PruneReport{
|
||||||
ImagesDeleted: []image.DeleteResponse{{Deleted: "image1"}},
|
ImagesDeleted: []image.DeleteResponse{{Deleted: "image1"}},
|
||||||
SpaceReclaimed: 1,
|
SpaceReclaimed: 1,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -77,17 +76,17 @@ func TestNewPruneCommandSuccess(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "label-filter",
|
name: "label-filter",
|
||||||
args: []string{"--force", "--filter", "label=foobar"},
|
args: []string{"--force", "--filter", "label=foobar"},
|
||||||
imagesPruneFunc: func(pruneFilter filters.Args) (types.ImagesPruneReport, error) {
|
imagesPruneFunc: func(pruneFilter filters.Args) (image.PruneReport, error) {
|
||||||
assert.Check(t, is.Equal("foobar", pruneFilter.Get("label")[0]))
|
assert.Check(t, is.Equal("foobar", pruneFilter.Get("label")[0]))
|
||||||
return types.ImagesPruneReport{}, nil
|
return image.PruneReport{}, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "force-untagged",
|
name: "force-untagged",
|
||||||
args: []string{"--force"},
|
args: []string{"--force"},
|
||||||
imagesPruneFunc: func(pruneFilter filters.Args) (types.ImagesPruneReport, error) {
|
imagesPruneFunc: func(pruneFilter filters.Args) (image.PruneReport, error) {
|
||||||
assert.Check(t, is.Equal("true", pruneFilter.Get("dangling")[0]))
|
assert.Check(t, is.Equal("true", pruneFilter.Get("dangling")[0]))
|
||||||
return types.ImagesPruneReport{
|
return image.PruneReport{
|
||||||
ImagesDeleted: []image.DeleteResponse{{Untagged: "image1"}},
|
ImagesDeleted: []image.DeleteResponse{{Untagged: "image1"}},
|
||||||
SpaceReclaimed: 2,
|
SpaceReclaimed: 2,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -115,8 +114,8 @@ func TestPrunePromptTermination(t *testing.T) {
|
||||||
t.Cleanup(cancel)
|
t.Cleanup(cancel)
|
||||||
|
|
||||||
cli := test.NewFakeCli(&fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
imagesPruneFunc: func(pruneFilter filters.Args) (types.ImagesPruneReport, error) {
|
imagesPruneFunc: func(pruneFilter filters.Args) (image.PruneReport, error) {
|
||||||
return types.ImagesPruneReport{}, errors.New("fakeClient imagesPruneFunc should not be called")
|
return image.PruneReport{}, errors.New("fakeClient imagesPruneFunc should not be called")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
cmd := NewPruneCommand(cli)
|
cmd := NewPruneCommand(cli)
|
||||||
|
|
|
@ -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/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
apiclient "github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,9 +38,9 @@ func NewNodeCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
// Reference returns the reference of a node. The special value "self" for a node
|
// Reference returns the reference of a node. The special value "self" for a node
|
||||||
// reference is mapped to the current node, hence the node ID is retrieved using
|
// reference is mapped to the current node, hence the node ID is retrieved using
|
||||||
// the `/info` endpoint.
|
// the `/info` endpoint.
|
||||||
func Reference(ctx context.Context, client apiclient.APIClient, ref string) (string, error) {
|
func Reference(ctx context.Context, apiClient client.APIClient, ref string) (string, error) {
|
||||||
if ref == "self" {
|
if ref == "self" {
|
||||||
info, err := client.Info(ctx)
|
info, err := apiClient.Info(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ func Reference(ctx context.Context, client apiclient.APIClient, ref string) (str
|
||||||
// If there's no node ID in /info, the node probably
|
// If there's no node ID in /info, the node probably
|
||||||
// isn't a manager. Call a swarm-specific endpoint to
|
// isn't a manager. Call a swarm-specific endpoint to
|
||||||
// get a more specific error message.
|
// get a more specific error message.
|
||||||
_, err = client.NodeList(ctx, types.NodeListOptions{})
|
_, err = apiClient.NodeList(ctx, types.NodeListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/formatter"
|
"github.com/docker/cli/cli/command/formatter"
|
||||||
"github.com/docker/cli/opts"
|
"github.com/docker/cli/opts"
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
registrytypes "github.com/docker/docker/api/types/registry"
|
registrytypes "github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -65,7 +64,7 @@ func runSearch(ctx context.Context, dockerCli command.Cli, options searchOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, indexInfo, "search")
|
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, indexInfo, "search")
|
||||||
results, err := dockerCli.Client().ImageSearch(ctx, options.term, types.ImageSearchOptions{
|
results, err := dockerCli.Client().ImageSearch(ctx, options.term, registrytypes.SearchOptions{
|
||||||
RegistryAuth: encodedAuth,
|
RegistryAuth: encodedAuth,
|
||||||
PrivilegeFunc: requestPrivilege,
|
PrivilegeFunc: requestPrivilege,
|
||||||
Filters: options.filter.Value(),
|
Filters: options.filter.Value(),
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
apiclient "github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/docker/docker/errdefs"
|
"github.com/docker/docker/errdefs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -89,14 +89,14 @@ func getServicesDeclaredNetworks(serviceConfigs []composetypes.ServiceConfig) ma
|
||||||
return serviceNetworks
|
return serviceNetworks
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateExternalNetworks(ctx context.Context, client apiclient.NetworkAPIClient, externalNetworks []string) error {
|
func validateExternalNetworks(ctx context.Context, apiClient client.NetworkAPIClient, externalNetworks []string) error {
|
||||||
for _, networkName := range externalNetworks {
|
for _, networkName := range externalNetworks {
|
||||||
if !container.NetworkMode(networkName).IsUserDefined() {
|
if !container.NetworkMode(networkName).IsUserDefined() {
|
||||||
// Networks that are not user defined always exist on all nodes as
|
// Networks that are not user defined always exist on all nodes as
|
||||||
// local-scoped networks, so there's no need to inspect them.
|
// local-scoped networks, so there's no need to inspect them.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
nw, err := client.NetworkInspect(ctx, networkName, network.InspectOptions{})
|
nw, err := apiClient.NetworkInspect(ctx, networkName, network.InspectOptions{})
|
||||||
switch {
|
switch {
|
||||||
case errdefs.IsNotFound(err):
|
case errdefs.IsNotFound(err):
|
||||||
return fmt.Errorf("network %q is declared as external, but could not be found. You need to create a swarm-scoped network before the stack is deployed", networkName)
|
return fmt.Errorf("network %q is declared as external, but could not be found. You need to create a swarm-scoped network before the stack is deployed", networkName)
|
||||||
|
@ -110,20 +110,20 @@ func validateExternalNetworks(ctx context.Context, client apiclient.NetworkAPICl
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSecrets(ctx context.Context, dockerCli command.Cli, secrets []swarm.SecretSpec) error {
|
func createSecrets(ctx context.Context, dockerCli command.Cli, secrets []swarm.SecretSpec) error {
|
||||||
client := dockerCli.Client()
|
apiClient := dockerCli.Client()
|
||||||
|
|
||||||
for _, secretSpec := range secrets {
|
for _, secretSpec := range secrets {
|
||||||
secret, _, err := client.SecretInspectWithRaw(ctx, secretSpec.Name)
|
secret, _, err := apiClient.SecretInspectWithRaw(ctx, secretSpec.Name)
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
// secret already exists, then we update that
|
// secret already exists, then we update that
|
||||||
if err := client.SecretUpdate(ctx, secret.ID, secret.Meta.Version, secretSpec); err != nil {
|
if err := apiClient.SecretUpdate(ctx, secret.ID, secret.Meta.Version, secretSpec); err != nil {
|
||||||
return fmt.Errorf("failed to update secret %s: %w", secretSpec.Name, err)
|
return fmt.Errorf("failed to update secret %s: %w", secretSpec.Name, err)
|
||||||
}
|
}
|
||||||
case errdefs.IsNotFound(err):
|
case errdefs.IsNotFound(err):
|
||||||
// secret does not exist, then we create a new one.
|
// secret does not exist, then we create a new one.
|
||||||
fmt.Fprintf(dockerCli.Out(), "Creating secret %s\n", secretSpec.Name)
|
fmt.Fprintf(dockerCli.Out(), "Creating secret %s\n", secretSpec.Name)
|
||||||
if _, err := client.SecretCreate(ctx, secretSpec); err != nil {
|
if _, err := apiClient.SecretCreate(ctx, secretSpec); err != nil {
|
||||||
return fmt.Errorf("failed to create secret %s: %w", secretSpec.Name, err)
|
return fmt.Errorf("failed to create secret %s: %w", secretSpec.Name, err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -134,20 +134,20 @@ func createSecrets(ctx context.Context, dockerCli command.Cli, secrets []swarm.S
|
||||||
}
|
}
|
||||||
|
|
||||||
func createConfigs(ctx context.Context, dockerCli command.Cli, configs []swarm.ConfigSpec) error {
|
func createConfigs(ctx context.Context, dockerCli command.Cli, configs []swarm.ConfigSpec) error {
|
||||||
client := dockerCli.Client()
|
apiClient := dockerCli.Client()
|
||||||
|
|
||||||
for _, configSpec := range configs {
|
for _, configSpec := range configs {
|
||||||
config, _, err := client.ConfigInspectWithRaw(ctx, configSpec.Name)
|
config, _, err := apiClient.ConfigInspectWithRaw(ctx, configSpec.Name)
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
// config already exists, then we update that
|
// config already exists, then we update that
|
||||||
if err := client.ConfigUpdate(ctx, config.ID, config.Meta.Version, configSpec); err != nil {
|
if err := apiClient.ConfigUpdate(ctx, config.ID, config.Meta.Version, configSpec); err != nil {
|
||||||
return fmt.Errorf("failed to update config %s: %w", configSpec.Name, err)
|
return fmt.Errorf("failed to update config %s: %w", configSpec.Name, err)
|
||||||
}
|
}
|
||||||
case errdefs.IsNotFound(err):
|
case errdefs.IsNotFound(err):
|
||||||
// config does not exist, then we create a new one.
|
// config does not exist, then we create a new one.
|
||||||
fmt.Fprintf(dockerCli.Out(), "Creating config %s\n", configSpec.Name)
|
fmt.Fprintf(dockerCli.Out(), "Creating config %s\n", configSpec.Name)
|
||||||
if _, err := client.ConfigCreate(ctx, configSpec); err != nil {
|
if _, err := apiClient.ConfigCreate(ctx, configSpec); err != nil {
|
||||||
return fmt.Errorf("failed to create config %s: %w", configSpec.Name, err)
|
return fmt.Errorf("failed to create config %s: %w", configSpec.Name, err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -158,9 +158,9 @@ func createConfigs(ctx context.Context, dockerCli command.Cli, configs []swarm.C
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNetworks(ctx context.Context, dockerCli command.Cli, namespace convert.Namespace, networks map[string]network.CreateOptions) error {
|
func createNetworks(ctx context.Context, dockerCli command.Cli, namespace convert.Namespace, networks map[string]network.CreateOptions) error {
|
||||||
client := dockerCli.Client()
|
apiClient := dockerCli.Client()
|
||||||
|
|
||||||
existingNetworks, err := getStackNetworks(ctx, client, namespace.Name())
|
existingNetworks, err := getStackNetworks(ctx, apiClient, namespace.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ func createNetworks(ctx context.Context, dockerCli command.Cli, namespace conver
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(dockerCli.Out(), "Creating network %s\n", name)
|
fmt.Fprintf(dockerCli.Out(), "Creating network %s\n", name)
|
||||||
if _, err := client.NetworkCreate(ctx, name, createOpts); err != nil {
|
if _, err := apiClient.NetworkCreate(ctx, name, createOpts); err != nil {
|
||||||
return fmt.Errorf("failed to create network %s: %w", name, err)
|
return fmt.Errorf("failed to create network %s: %w", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,37 +11,37 @@ import (
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
apiclient "github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunRemove is the swarm implementation of docker stack remove
|
// RunRemove is the swarm implementation of docker stack remove
|
||||||
func RunRemove(ctx context.Context, dockerCli command.Cli, opts options.Remove) error {
|
func RunRemove(ctx context.Context, dockerCli command.Cli, opts options.Remove) error {
|
||||||
client := dockerCli.Client()
|
apiClient := dockerCli.Client()
|
||||||
|
|
||||||
var errs []string
|
var errs []string
|
||||||
for _, namespace := range opts.Namespaces {
|
for _, namespace := range opts.Namespaces {
|
||||||
services, err := getStackServices(ctx, client, namespace)
|
services, err := getStackServices(ctx, apiClient, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
networks, err := getStackNetworks(ctx, client, namespace)
|
networks, err := getStackNetworks(ctx, apiClient, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var secrets []swarm.Secret
|
var secrets []swarm.Secret
|
||||||
if versions.GreaterThanOrEqualTo(client.ClientVersion(), "1.25") {
|
if versions.GreaterThanOrEqualTo(apiClient.ClientVersion(), "1.25") {
|
||||||
secrets, err = getStackSecrets(ctx, client, namespace)
|
secrets, err = getStackSecrets(ctx, apiClient, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var configs []swarm.Config
|
var configs []swarm.Config
|
||||||
if versions.GreaterThanOrEqualTo(client.ClientVersion(), "1.30") {
|
if versions.GreaterThanOrEqualTo(apiClient.ClientVersion(), "1.30") {
|
||||||
configs, err = getStackConfigs(ctx, client, namespace)
|
configs, err = getStackConfigs(ctx, apiClient, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ func RunRemove(ctx context.Context, dockerCli command.Cli, opts options.Remove)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opts.Detach {
|
if !opts.Detach {
|
||||||
err = waitOnTasks(ctx, client, namespace)
|
err = waitOnTasks(ctx, apiClient, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("Failed to wait on tasks of stack: %s: %s", namespace, err))
|
errs = append(errs, fmt.Sprintf("Failed to wait on tasks of stack: %s: %s", namespace, err))
|
||||||
}
|
}
|
||||||
|
@ -82,11 +82,7 @@ func sortServiceByName(services []swarm.Service) func(i, j int) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeServices(
|
func removeServices(ctx context.Context, dockerCli command.Cli, services []swarm.Service) bool {
|
||||||
ctx context.Context,
|
|
||||||
dockerCli command.Cli,
|
|
||||||
services []swarm.Service,
|
|
||||||
) bool {
|
|
||||||
var hasError bool
|
var hasError bool
|
||||||
sort.Slice(services, sortServiceByName(services))
|
sort.Slice(services, sortServiceByName(services))
|
||||||
for _, service := range services {
|
for _, service := range services {
|
||||||
|
@ -99,11 +95,7 @@ func removeServices(
|
||||||
return hasError
|
return hasError
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeNetworks(
|
func removeNetworks(ctx context.Context, dockerCli command.Cli, networks []network.Summary) bool {
|
||||||
ctx context.Context,
|
|
||||||
dockerCli command.Cli,
|
|
||||||
networks []network.Summary,
|
|
||||||
) bool {
|
|
||||||
var hasError bool
|
var hasError bool
|
||||||
for _, nw := range networks {
|
for _, nw := range networks {
|
||||||
fmt.Fprintf(dockerCli.Out(), "Removing network %s\n", nw.Name)
|
fmt.Fprintf(dockerCli.Out(), "Removing network %s\n", nw.Name)
|
||||||
|
@ -115,11 +107,7 @@ func removeNetworks(
|
||||||
return hasError
|
return hasError
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeSecrets(
|
func removeSecrets(ctx context.Context, dockerCli command.Cli, secrets []swarm.Secret) bool {
|
||||||
ctx context.Context,
|
|
||||||
dockerCli command.Cli,
|
|
||||||
secrets []swarm.Secret,
|
|
||||||
) bool {
|
|
||||||
var hasError bool
|
var hasError bool
|
||||||
for _, secret := range secrets {
|
for _, secret := range secrets {
|
||||||
fmt.Fprintf(dockerCli.Out(), "Removing secret %s\n", secret.Spec.Name)
|
fmt.Fprintf(dockerCli.Out(), "Removing secret %s\n", secret.Spec.Name)
|
||||||
|
@ -131,11 +119,7 @@ func removeSecrets(
|
||||||
return hasError
|
return hasError
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeConfigs(
|
func removeConfigs(ctx context.Context, dockerCli command.Cli, configs []swarm.Config) bool {
|
||||||
ctx context.Context,
|
|
||||||
dockerCli command.Cli,
|
|
||||||
configs []swarm.Config,
|
|
||||||
) bool {
|
|
||||||
var hasError bool
|
var hasError bool
|
||||||
for _, config := range configs {
|
for _, config := range configs {
|
||||||
fmt.Fprintf(dockerCli.Out(), "Removing config %s\n", config.Spec.Name)
|
fmt.Fprintf(dockerCli.Out(), "Removing config %s\n", config.Spec.Name)
|
||||||
|
@ -167,10 +151,10 @@ func terminalState(state swarm.TaskState) bool {
|
||||||
return numberedStates[state] > numberedStates[swarm.TaskStateRunning]
|
return numberedStates[state] > numberedStates[swarm.TaskStateRunning]
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitOnTasks(ctx context.Context, client apiclient.APIClient, namespace string) error {
|
func waitOnTasks(ctx context.Context, apiClient client.APIClient, namespace string) error {
|
||||||
terminalStatesReached := 0
|
terminalStatesReached := 0
|
||||||
for {
|
for {
|
||||||
tasks, err := getStackTasks(ctx, client, namespace)
|
tasks, err := getStackTasks(ctx, apiClient, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get tasks: %w", err)
|
return fmt.Errorf("failed to get tasks: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"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"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
|
@ -15,8 +16,8 @@ type fakeClient struct {
|
||||||
|
|
||||||
version string
|
version string
|
||||||
serverVersion func(ctx context.Context) (types.Version, error)
|
serverVersion func(ctx context.Context) (types.Version, error)
|
||||||
eventsFn func(context.Context, types.EventsOptions) (<-chan events.Message, <-chan error)
|
eventsFn func(context.Context, events.ListOptions) (<-chan events.Message, <-chan error)
|
||||||
containerPruneFunc func(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error)
|
containerPruneFunc func(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error)
|
||||||
networkPruneFunc func(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error)
|
networkPruneFunc func(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,15 +29,15 @@ func (cli *fakeClient) ClientVersion() string {
|
||||||
return cli.version
|
return cli.version
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *fakeClient) Events(ctx context.Context, opts types.EventsOptions) (<-chan events.Message, <-chan error) {
|
func (cli *fakeClient) Events(ctx context.Context, opts events.ListOptions) (<-chan events.Message, <-chan error) {
|
||||||
return cli.eventsFn(ctx, opts)
|
return cli.eventsFn(ctx, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *fakeClient) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) {
|
func (cli *fakeClient) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
|
||||||
if cli.containerPruneFunc != nil {
|
if cli.containerPruneFunc != nil {
|
||||||
return cli.containerPruneFunc(ctx, pruneFilters)
|
return cli.containerPruneFunc(ctx, pruneFilters)
|
||||||
}
|
}
|
||||||
return types.ContainersPruneReport{}, nil
|
return container.PruneReport{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *fakeClient) NetworksPrune(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error) {
|
func (cli *fakeClient) NetworksPrune(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error) {
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
flagsHelper "github.com/docker/cli/cli/flags"
|
flagsHelper "github.com/docker/cli/cli/flags"
|
||||||
"github.com/docker/cli/opts"
|
"github.com/docker/cli/opts"
|
||||||
"github.com/docker/cli/templates"
|
"github.com/docker/cli/templates"
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/events"
|
"github.com/docker/docker/api/types/events"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -63,7 +62,7 @@ func runEvents(ctx context.Context, dockerCli command.Cli, options *eventsOption
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
evts, errs := dockerCli.Client().Events(ctx, types.EventsOptions{
|
evts, errs := dockerCli.Client().Events(ctx, events.ListOptions{
|
||||||
Since: options.since,
|
Since: options.since,
|
||||||
Until: options.until,
|
Until: options.until,
|
||||||
Filters: options.filter.Value(),
|
Filters: options.filter.Value(),
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/cli/internal/test"
|
"github.com/docker/cli/internal/test"
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/events"
|
"github.com/docker/docker/api/types/events"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
"gotest.tools/v3/golden"
|
"gotest.tools/v3/golden"
|
||||||
|
@ -59,7 +58,7 @@ func TestEventsFormat(t *testing.T) {
|
||||||
// Set to UTC timezone as timestamps in output are
|
// Set to UTC timezone as timestamps in output are
|
||||||
// printed in the current timezone
|
// printed in the current timezone
|
||||||
t.Setenv("TZ", "UTC")
|
t.Setenv("TZ", "UTC")
|
||||||
cli := test.NewFakeCli(&fakeClient{eventsFn: func(context.Context, types.EventsOptions) (<-chan events.Message, <-chan error) {
|
cli := test.NewFakeCli(&fakeClient{eventsFn: func(context.Context, events.ListOptions) (<-chan events.Message, <-chan error) {
|
||||||
messages := make(chan events.Message)
|
messages := make(chan events.Message)
|
||||||
errs := make(chan error, 1)
|
errs := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/cli/cli/config/configfile"
|
"github.com/docker/cli/cli/config/configfile"
|
||||||
"github.com/docker/cli/internal/test"
|
"github.com/docker/cli/internal/test"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -60,8 +60,8 @@ func TestSystemPrunePromptTermination(t *testing.T) {
|
||||||
t.Cleanup(cancel)
|
t.Cleanup(cancel)
|
||||||
|
|
||||||
cli := test.NewFakeCli(&fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
containerPruneFunc: func(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) {
|
containerPruneFunc: func(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
|
||||||
return types.ContainersPruneReport{}, errors.New("fakeClient containerPruneFunc should not be called")
|
return container.PruneReport{}, errors.New("fakeClient containerPruneFunc should not be called")
|
||||||
},
|
},
|
||||||
networkPruneFunc: func(ctx context.Context, pruneFilters filters.Args) (network.PruneReport, error) {
|
networkPruneFunc: func(ctx context.Context, pruneFilters filters.Args) (network.PruneReport, error) {
|
||||||
return network.PruneReport{}, errors.New("fakeClient networkPruneFunc should not be called")
|
return network.PruneReport{}, errors.New("fakeClient networkPruneFunc should not be called")
|
||||||
|
|
|
@ -13,9 +13,9 @@ import (
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
"github.com/docker/docker/api/types/system"
|
"github.com/docker/docker/api/types/system"
|
||||||
apiclient "github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/theupdateframework/notary"
|
"github.com/theupdateframework/notary"
|
||||||
"github.com/theupdateframework/notary/client"
|
notaryclient "github.com/theupdateframework/notary/client"
|
||||||
"github.com/theupdateframework/notary/tuf/data"
|
"github.com/theupdateframework/notary/tuf/data"
|
||||||
"github.com/theupdateframework/notary/tuf/utils"
|
"github.com/theupdateframework/notary/tuf/utils"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
|
@ -26,7 +26,7 @@ import (
|
||||||
// TODO(n4ss): remove common tests with the regular inspect command
|
// TODO(n4ss): remove common tests with the regular inspect command
|
||||||
|
|
||||||
type fakeClient struct {
|
type fakeClient struct {
|
||||||
apiclient.Client
|
client.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeClient) Info(context.Context) (system.Info, error) {
|
func (c *fakeClient) Info(context.Context) (system.Info, error) {
|
||||||
|
@ -212,7 +212,7 @@ func mockDelegationRoleWithName(name string) data.DelegationRole {
|
||||||
|
|
||||||
func TestMatchEmptySignatures(t *testing.T) {
|
func TestMatchEmptySignatures(t *testing.T) {
|
||||||
// first try empty targets
|
// first try empty targets
|
||||||
emptyTgts := []client.TargetSignedStruct{}
|
emptyTgts := []notaryclient.TargetSignedStruct{}
|
||||||
|
|
||||||
matchedSigRows := matchReleasedSignatures(emptyTgts)
|
matchedSigRows := matchReleasedSignatures(emptyTgts)
|
||||||
assert.Check(t, is.Len(matchedSigRows, 0))
|
assert.Check(t, is.Len(matchedSigRows, 0))
|
||||||
|
@ -220,11 +220,11 @@ func TestMatchEmptySignatures(t *testing.T) {
|
||||||
|
|
||||||
func TestMatchUnreleasedSignatures(t *testing.T) {
|
func TestMatchUnreleasedSignatures(t *testing.T) {
|
||||||
// try an "unreleased" target with 3 signatures, 0 rows will appear
|
// try an "unreleased" target with 3 signatures, 0 rows will appear
|
||||||
unreleasedTgts := []client.TargetSignedStruct{}
|
unreleasedTgts := []notaryclient.TargetSignedStruct{}
|
||||||
|
|
||||||
tgt := client.Target{Name: "unreleased", Hashes: data.Hashes{notary.SHA256: []byte("hash")}}
|
tgt := notaryclient.Target{Name: "unreleased", Hashes: data.Hashes{notary.SHA256: []byte("hash")}}
|
||||||
for _, unreleasedRole := range []string{"targets/a", "targets/b", "targets/c"} {
|
for _, unreleasedRole := range []string{"targets/a", "targets/b", "targets/c"} {
|
||||||
unreleasedTgts = append(unreleasedTgts, client.TargetSignedStruct{Role: mockDelegationRoleWithName(unreleasedRole), Target: tgt})
|
unreleasedTgts = append(unreleasedTgts, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName(unreleasedRole), Target: tgt})
|
||||||
}
|
}
|
||||||
|
|
||||||
matchedSigRows := matchReleasedSignatures(unreleasedTgts)
|
matchedSigRows := matchReleasedSignatures(unreleasedTgts)
|
||||||
|
@ -233,16 +233,16 @@ func TestMatchUnreleasedSignatures(t *testing.T) {
|
||||||
|
|
||||||
func TestMatchOneReleasedSingleSignature(t *testing.T) {
|
func TestMatchOneReleasedSingleSignature(t *testing.T) {
|
||||||
// now try only 1 "released" target with no additional sigs, 1 row will appear with 0 signers
|
// now try only 1 "released" target with no additional sigs, 1 row will appear with 0 signers
|
||||||
oneReleasedTgt := []client.TargetSignedStruct{}
|
oneReleasedTgt := []notaryclient.TargetSignedStruct{}
|
||||||
|
|
||||||
// make and append the "released" target to our mock input
|
// make and append the "released" target to our mock input
|
||||||
releasedTgt := client.Target{Name: "released", Hashes: data.Hashes{notary.SHA256: []byte("released-hash")}}
|
releasedTgt := notaryclient.Target{Name: "released", Hashes: data.Hashes{notary.SHA256: []byte("released-hash")}}
|
||||||
oneReleasedTgt = append(oneReleasedTgt, client.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/releases"), Target: releasedTgt})
|
oneReleasedTgt = append(oneReleasedTgt, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/releases"), Target: releasedTgt})
|
||||||
|
|
||||||
// make and append 3 non-released signatures on the "unreleased" target
|
// make and append 3 non-released signatures on the "unreleased" target
|
||||||
unreleasedTgt := client.Target{Name: "unreleased", Hashes: data.Hashes{notary.SHA256: []byte("hash")}}
|
unreleasedTgt := notaryclient.Target{Name: "unreleased", Hashes: data.Hashes{notary.SHA256: []byte("hash")}}
|
||||||
for _, unreleasedRole := range []string{"targets/a", "targets/b", "targets/c"} {
|
for _, unreleasedRole := range []string{"targets/a", "targets/b", "targets/c"} {
|
||||||
oneReleasedTgt = append(oneReleasedTgt, client.TargetSignedStruct{Role: mockDelegationRoleWithName(unreleasedRole), Target: unreleasedTgt})
|
oneReleasedTgt = append(oneReleasedTgt, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName(unreleasedRole), Target: unreleasedTgt})
|
||||||
}
|
}
|
||||||
|
|
||||||
matchedSigRows := matchReleasedSignatures(oneReleasedTgt)
|
matchedSigRows := matchReleasedSignatures(oneReleasedTgt)
|
||||||
|
@ -257,17 +257,17 @@ func TestMatchOneReleasedSingleSignature(t *testing.T) {
|
||||||
|
|
||||||
func TestMatchOneReleasedMultiSignature(t *testing.T) {
|
func TestMatchOneReleasedMultiSignature(t *testing.T) {
|
||||||
// now try only 1 "released" target with 3 additional sigs, 1 row will appear with 3 signers
|
// now try only 1 "released" target with 3 additional sigs, 1 row will appear with 3 signers
|
||||||
oneReleasedTgt := []client.TargetSignedStruct{}
|
oneReleasedTgt := []notaryclient.TargetSignedStruct{}
|
||||||
|
|
||||||
// make and append the "released" target to our mock input
|
// make and append the "released" target to our mock input
|
||||||
releasedTgt := client.Target{Name: "released", Hashes: data.Hashes{notary.SHA256: []byte("released-hash")}}
|
releasedTgt := notaryclient.Target{Name: "released", Hashes: data.Hashes{notary.SHA256: []byte("released-hash")}}
|
||||||
oneReleasedTgt = append(oneReleasedTgt, client.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/releases"), Target: releasedTgt})
|
oneReleasedTgt = append(oneReleasedTgt, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/releases"), Target: releasedTgt})
|
||||||
|
|
||||||
// make and append 3 non-released signatures on both the "released" and "unreleased" targets
|
// make and append 3 non-released signatures on both the "released" and "unreleased" targets
|
||||||
unreleasedTgt := client.Target{Name: "unreleased", Hashes: data.Hashes{notary.SHA256: []byte("hash")}}
|
unreleasedTgt := notaryclient.Target{Name: "unreleased", Hashes: data.Hashes{notary.SHA256: []byte("hash")}}
|
||||||
for _, unreleasedRole := range []string{"targets/a", "targets/b", "targets/c"} {
|
for _, unreleasedRole := range []string{"targets/a", "targets/b", "targets/c"} {
|
||||||
oneReleasedTgt = append(oneReleasedTgt, client.TargetSignedStruct{Role: mockDelegationRoleWithName(unreleasedRole), Target: unreleasedTgt})
|
oneReleasedTgt = append(oneReleasedTgt, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName(unreleasedRole), Target: unreleasedTgt})
|
||||||
oneReleasedTgt = append(oneReleasedTgt, client.TargetSignedStruct{Role: mockDelegationRoleWithName(unreleasedRole), Target: releasedTgt})
|
oneReleasedTgt = append(oneReleasedTgt, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName(unreleasedRole), Target: releasedTgt})
|
||||||
}
|
}
|
||||||
|
|
||||||
matchedSigRows := matchReleasedSignatures(oneReleasedTgt)
|
matchedSigRows := matchReleasedSignatures(oneReleasedTgt)
|
||||||
|
@ -285,29 +285,29 @@ func TestMatchMultiReleasedMultiSignature(t *testing.T) {
|
||||||
// target-a is signed by targets/releases and targets/a - a will be the signer
|
// target-a is signed by targets/releases and targets/a - a will be the signer
|
||||||
// target-b is signed by targets/releases, targets/a, targets/b - a and b will be the signers
|
// target-b is signed by targets/releases, targets/a, targets/b - a and b will be the signers
|
||||||
// target-c is signed by targets/releases, targets/a, targets/b, targets/c - a, b, and c will be the signers
|
// target-c is signed by targets/releases, targets/a, targets/b, targets/c - a, b, and c will be the signers
|
||||||
multiReleasedTgts := []client.TargetSignedStruct{}
|
multiReleasedTgts := []notaryclient.TargetSignedStruct{}
|
||||||
// make target-a, target-b, and target-c
|
// make target-a, target-b, and target-c
|
||||||
targetA := client.Target{Name: "target-a", Hashes: data.Hashes{notary.SHA256: []byte("target-a-hash")}}
|
targetA := notaryclient.Target{Name: "target-a", Hashes: data.Hashes{notary.SHA256: []byte("target-a-hash")}}
|
||||||
targetB := client.Target{Name: "target-b", Hashes: data.Hashes{notary.SHA256: []byte("target-b-hash")}}
|
targetB := notaryclient.Target{Name: "target-b", Hashes: data.Hashes{notary.SHA256: []byte("target-b-hash")}}
|
||||||
targetC := client.Target{Name: "target-c", Hashes: data.Hashes{notary.SHA256: []byte("target-c-hash")}}
|
targetC := notaryclient.Target{Name: "target-c", Hashes: data.Hashes{notary.SHA256: []byte("target-c-hash")}}
|
||||||
|
|
||||||
// have targets/releases "sign" on all of these targets so they are released
|
// have targets/releases "sign" on all of these targets so they are released
|
||||||
multiReleasedTgts = append(multiReleasedTgts, client.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/releases"), Target: targetA})
|
multiReleasedTgts = append(multiReleasedTgts, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/releases"), Target: targetA})
|
||||||
multiReleasedTgts = append(multiReleasedTgts, client.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/releases"), Target: targetB})
|
multiReleasedTgts = append(multiReleasedTgts, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/releases"), Target: targetB})
|
||||||
multiReleasedTgts = append(multiReleasedTgts, client.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/releases"), Target: targetC})
|
multiReleasedTgts = append(multiReleasedTgts, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/releases"), Target: targetC})
|
||||||
|
|
||||||
// targets/a signs off on all three targets (target-a, target-b, target-c):
|
// targets/a signs off on all three targets (target-a, target-b, target-c):
|
||||||
for _, tgt := range []client.Target{targetA, targetB, targetC} {
|
for _, tgt := range []notaryclient.Target{targetA, targetB, targetC} {
|
||||||
multiReleasedTgts = append(multiReleasedTgts, client.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/a"), Target: tgt})
|
multiReleasedTgts = append(multiReleasedTgts, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/a"), Target: tgt})
|
||||||
}
|
}
|
||||||
|
|
||||||
// targets/b signs off on the final two targets (target-b, target-c):
|
// targets/b signs off on the final two targets (target-b, target-c):
|
||||||
for _, tgt := range []client.Target{targetB, targetC} {
|
for _, tgt := range []notaryclient.Target{targetB, targetC} {
|
||||||
multiReleasedTgts = append(multiReleasedTgts, client.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/b"), Target: tgt})
|
multiReleasedTgts = append(multiReleasedTgts, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/b"), Target: tgt})
|
||||||
}
|
}
|
||||||
|
|
||||||
// targets/c only signs off on the last target (target-c):
|
// targets/c only signs off on the last target (target-c):
|
||||||
multiReleasedTgts = append(multiReleasedTgts, client.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/c"), Target: targetC})
|
multiReleasedTgts = append(multiReleasedTgts, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName("targets/c"), Target: targetC})
|
||||||
|
|
||||||
matchedSigRows := matchReleasedSignatures(multiReleasedTgts)
|
matchedSigRows := matchReleasedSignatures(multiReleasedTgts)
|
||||||
assert.Check(t, is.Len(matchedSigRows, 3))
|
assert.Check(t, is.Len(matchedSigRows, 3))
|
||||||
|
@ -331,10 +331,10 @@ func TestMatchMultiReleasedMultiSignature(t *testing.T) {
|
||||||
|
|
||||||
func TestMatchReleasedSignatureFromTargets(t *testing.T) {
|
func TestMatchReleasedSignatureFromTargets(t *testing.T) {
|
||||||
// now try only 1 "released" target with no additional sigs, one rows will appear
|
// now try only 1 "released" target with no additional sigs, one rows will appear
|
||||||
oneReleasedTgt := []client.TargetSignedStruct{}
|
oneReleasedTgt := []notaryclient.TargetSignedStruct{}
|
||||||
// make and append the "released" target to our mock input
|
// make and append the "released" target to our mock input
|
||||||
releasedTgt := client.Target{Name: "released", Hashes: data.Hashes{notary.SHA256: []byte("released-hash")}}
|
releasedTgt := notaryclient.Target{Name: "released", Hashes: data.Hashes{notary.SHA256: []byte("released-hash")}}
|
||||||
oneReleasedTgt = append(oneReleasedTgt, client.TargetSignedStruct{Role: mockDelegationRoleWithName(data.CanonicalTargetsRole.String()), Target: releasedTgt})
|
oneReleasedTgt = append(oneReleasedTgt, notaryclient.TargetSignedStruct{Role: mockDelegationRoleWithName(data.CanonicalTargetsRole.String()), Target: releasedTgt})
|
||||||
matchedSigRows := matchReleasedSignatures(oneReleasedTgt)
|
matchedSigRows := matchReleasedSignatures(oneReleasedTgt)
|
||||||
assert.Check(t, is.Len(matchedSigRows, 1))
|
assert.Check(t, is.Len(matchedSigRows, 1))
|
||||||
outputRow := matchedSigRows[0]
|
outputRow := matchedSigRows[0]
|
||||||
|
@ -405,7 +405,7 @@ func TestFormatAdminRole(t *testing.T) {
|
||||||
},
|
},
|
||||||
Name: "targets/alice",
|
Name: "targets/alice",
|
||||||
}
|
}
|
||||||
aliceRoleWithSigs := client.RoleWithSignatures{Role: aliceRole, Signatures: nil}
|
aliceRoleWithSigs := notaryclient.RoleWithSignatures{Role: aliceRole, Signatures: nil}
|
||||||
assert.Check(t, is.Equal("", formatAdminRole(aliceRoleWithSigs)))
|
assert.Check(t, is.Equal("", formatAdminRole(aliceRoleWithSigs)))
|
||||||
|
|
||||||
releasesRole := data.Role{
|
releasesRole := data.Role{
|
||||||
|
@ -414,7 +414,7 @@ func TestFormatAdminRole(t *testing.T) {
|
||||||
},
|
},
|
||||||
Name: "targets/releases",
|
Name: "targets/releases",
|
||||||
}
|
}
|
||||||
releasesRoleWithSigs := client.RoleWithSignatures{Role: releasesRole, Signatures: nil}
|
releasesRoleWithSigs := notaryclient.RoleWithSignatures{Role: releasesRole, Signatures: nil}
|
||||||
assert.Check(t, is.Equal("", formatAdminRole(releasesRoleWithSigs)))
|
assert.Check(t, is.Equal("", formatAdminRole(releasesRoleWithSigs)))
|
||||||
|
|
||||||
timestampRole := data.Role{
|
timestampRole := data.Role{
|
||||||
|
@ -423,7 +423,7 @@ func TestFormatAdminRole(t *testing.T) {
|
||||||
},
|
},
|
||||||
Name: data.CanonicalTimestampRole,
|
Name: data.CanonicalTimestampRole,
|
||||||
}
|
}
|
||||||
timestampRoleWithSigs := client.RoleWithSignatures{Role: timestampRole, Signatures: nil}
|
timestampRoleWithSigs := notaryclient.RoleWithSignatures{Role: timestampRole, Signatures: nil}
|
||||||
assert.Check(t, is.Equal("", formatAdminRole(timestampRoleWithSigs)))
|
assert.Check(t, is.Equal("", formatAdminRole(timestampRoleWithSigs)))
|
||||||
|
|
||||||
snapshotRole := data.Role{
|
snapshotRole := data.Role{
|
||||||
|
@ -432,7 +432,7 @@ func TestFormatAdminRole(t *testing.T) {
|
||||||
},
|
},
|
||||||
Name: data.CanonicalSnapshotRole,
|
Name: data.CanonicalSnapshotRole,
|
||||||
}
|
}
|
||||||
snapshotRoleWithSigs := client.RoleWithSignatures{Role: snapshotRole, Signatures: nil}
|
snapshotRoleWithSigs := notaryclient.RoleWithSignatures{Role: snapshotRole, Signatures: nil}
|
||||||
assert.Check(t, is.Equal("", formatAdminRole(snapshotRoleWithSigs)))
|
assert.Check(t, is.Equal("", formatAdminRole(snapshotRoleWithSigs)))
|
||||||
|
|
||||||
rootRole := data.Role{
|
rootRole := data.Role{
|
||||||
|
@ -441,7 +441,7 @@ func TestFormatAdminRole(t *testing.T) {
|
||||||
},
|
},
|
||||||
Name: data.CanonicalRootRole,
|
Name: data.CanonicalRootRole,
|
||||||
}
|
}
|
||||||
rootRoleWithSigs := client.RoleWithSignatures{Role: rootRole, Signatures: nil}
|
rootRoleWithSigs := notaryclient.RoleWithSignatures{Role: rootRole, Signatures: nil}
|
||||||
assert.Check(t, is.Equal("Root Key:\tkey11\n", formatAdminRole(rootRoleWithSigs)))
|
assert.Check(t, is.Equal("Root Key:\tkey11\n", formatAdminRole(rootRoleWithSigs)))
|
||||||
|
|
||||||
targetsRole := data.Role{
|
targetsRole := data.Role{
|
||||||
|
@ -450,7 +450,7 @@ func TestFormatAdminRole(t *testing.T) {
|
||||||
},
|
},
|
||||||
Name: data.CanonicalTargetsRole,
|
Name: data.CanonicalTargetsRole,
|
||||||
}
|
}
|
||||||
targetsRoleWithSigs := client.RoleWithSignatures{Role: targetsRole, Signatures: nil}
|
targetsRoleWithSigs := notaryclient.RoleWithSignatures{Role: targetsRole, Signatures: nil}
|
||||||
assert.Check(t, is.Equal("Repository Key:\tabc, key11, key99\n", formatAdminRole(targetsRoleWithSigs)))
|
assert.Check(t, is.Equal("Repository Key:\tabc, key11, key99\n", formatAdminRole(targetsRoleWithSigs)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,10 @@ import (
|
||||||
"github.com/docker/cli/cli/trust"
|
"github.com/docker/cli/cli/trust"
|
||||||
imagetypes "github.com/docker/docker/api/types/image"
|
imagetypes "github.com/docker/docker/api/types/image"
|
||||||
registrytypes "github.com/docker/docker/api/types/registry"
|
registrytypes "github.com/docker/docker/api/types/registry"
|
||||||
apiclient "github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/theupdateframework/notary/client"
|
notaryclient "github.com/theupdateframework/notary/client"
|
||||||
"github.com/theupdateframework/notary/tuf/data"
|
"github.com/theupdateframework/notary/tuf/data"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ func runSignImage(ctx context.Context, dockerCLI command.Cli, options signOption
|
||||||
// get the latest repository metadata so we can figure out which roles to sign
|
// get the latest repository metadata so we can figure out which roles to sign
|
||||||
if _, err = notaryRepo.ListTargets(); err != nil {
|
if _, err = notaryRepo.ListTargets(); err != nil {
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
|
case notaryclient.ErrRepoNotInitialized, notaryclient.ErrRepositoryNotExist:
|
||||||
// before initializing a new repo, check that the image exists locally:
|
// before initializing a new repo, check that the image exists locally:
|
||||||
if err := checkLocalImageExistence(ctx, dockerCLI.Client(), imageName); err != nil {
|
if err := checkLocalImageExistence(ctx, dockerCLI.Client(), imageName); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -86,7 +86,7 @@ func runSignImage(ctx context.Context, dockerCLI command.Cli, options signOption
|
||||||
if err != nil || options.local {
|
if err != nil || options.local {
|
||||||
switch err := err.(type) {
|
switch err := err.(type) {
|
||||||
// If the error is nil then the local flag is set
|
// If the error is nil then the local flag is set
|
||||||
case client.ErrNoSuchTarget, client.ErrRepositoryNotExist, nil:
|
case notaryclient.ErrNoSuchTarget, notaryclient.ErrRepositoryNotExist, nil:
|
||||||
// Fail fast if the image doesn't exist locally
|
// Fail fast if the image doesn't exist locally
|
||||||
if err := checkLocalImageExistence(ctx, dockerCLI.Client(), imageName); err != nil {
|
if err := checkLocalImageExistence(ctx, dockerCLI.Client(), imageName); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -110,7 +110,7 @@ func runSignImage(ctx context.Context, dockerCLI command.Cli, options signOption
|
||||||
return signAndPublishToTarget(dockerCLI.Out(), imgRefAndAuth, notaryRepo, target)
|
return signAndPublishToTarget(dockerCLI.Out(), imgRefAndAuth, notaryRepo, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
func signAndPublishToTarget(out io.Writer, imgRefAndAuth trust.ImageRefAndAuth, notaryRepo client.Repository, target client.Target) error {
|
func signAndPublishToTarget(out io.Writer, imgRefAndAuth trust.ImageRefAndAuth, notaryRepo notaryclient.Repository, target notaryclient.Target) error {
|
||||||
tag := imgRefAndAuth.Tag()
|
tag := imgRefAndAuth.Tag()
|
||||||
fmt.Fprintf(out, "Signing and pushing trust metadata for %s\n", imgRefAndAuth.Name())
|
fmt.Fprintf(out, "Signing and pushing trust metadata for %s\n", imgRefAndAuth.Name())
|
||||||
existingSigInfo, err := getExistingSignatureInfoForReleasedTag(notaryRepo, tag)
|
existingSigInfo, err := getExistingSignatureInfoForReleasedTag(notaryRepo, tag)
|
||||||
|
@ -140,13 +140,13 @@ func validateTag(imgRefAndAuth trust.ImageRefAndAuth) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkLocalImageExistence(ctx context.Context, apiClient apiclient.APIClient, imageName string) error {
|
func checkLocalImageExistence(ctx context.Context, apiClient client.APIClient, imageName string) error {
|
||||||
_, _, err := apiClient.ImageInspectWithRaw(ctx, imageName)
|
_, _, err := apiClient.ImageInspectWithRaw(ctx, imageName)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTarget(notaryRepo client.Repository, tag string) (client.Target, error) {
|
func createTarget(notaryRepo notaryclient.Repository, tag string) (notaryclient.Target, error) {
|
||||||
target := &client.Target{}
|
target := ¬aryclient.Target{}
|
||||||
var err error
|
var err error
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
return *target, errors.New("no tag specified")
|
return *target, errors.New("no tag specified")
|
||||||
|
@ -156,7 +156,7 @@ func createTarget(notaryRepo client.Repository, tag string) (client.Target, erro
|
||||||
return *target, err
|
return *target, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSignedManifestHashAndSize(notaryRepo client.Repository, tag string) (data.Hashes, int64, error) {
|
func getSignedManifestHashAndSize(notaryRepo notaryclient.Repository, tag string) (data.Hashes, int64, error) {
|
||||||
targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
|
targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
@ -164,16 +164,16 @@ func getSignedManifestHashAndSize(notaryRepo client.Repository, tag string) (dat
|
||||||
return getReleasedTargetHashAndSize(targets, tag)
|
return getReleasedTargetHashAndSize(targets, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getReleasedTargetHashAndSize(targets []client.TargetSignedStruct, tag string) (data.Hashes, int64, error) {
|
func getReleasedTargetHashAndSize(targets []notaryclient.TargetSignedStruct, tag string) (data.Hashes, int64, error) {
|
||||||
for _, tgt := range targets {
|
for _, tgt := range targets {
|
||||||
if isReleasedTarget(tgt.Role.Name) {
|
if isReleasedTarget(tgt.Role.Name) {
|
||||||
return tgt.Target.Hashes, tgt.Target.Length, nil
|
return tgt.Target.Hashes, tgt.Target.Length, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, 0, client.ErrNoSuchTarget(tag)
|
return nil, 0, notaryclient.ErrNoSuchTarget(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExistingSignatureInfoForReleasedTag(notaryRepo client.Repository, tag string) (trustTagRow, error) {
|
func getExistingSignatureInfoForReleasedTag(notaryRepo notaryclient.Repository, tag string) (trustTagRow, error) {
|
||||||
targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
|
targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return trustTagRow{}, err
|
return trustTagRow{}, err
|
||||||
|
@ -191,7 +191,7 @@ func prettyPrintExistingSignatureInfo(out io.Writer, existingSigInfo trustTagRow
|
||||||
fmt.Fprintf(out, "Existing signatures for tag %s digest %s from:\n%s\n", existingSigInfo.SignedTag, existingSigInfo.Digest, joinedSigners)
|
fmt.Fprintf(out, "Existing signatures for tag %s digest %s from:\n%s\n", existingSigInfo.SignedTag, existingSigInfo.Digest, joinedSigners)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initNotaryRepoWithSigners(notaryRepo client.Repository, newSigner data.RoleName) error {
|
func initNotaryRepoWithSigners(notaryRepo notaryclient.Repository, newSigner data.RoleName) error {
|
||||||
rootKey, err := getOrGenerateNotaryKey(notaryRepo, data.CanonicalRootRole)
|
rootKey, err := getOrGenerateNotaryKey(notaryRepo, data.CanonicalRootRole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -215,7 +215,7 @@ func initNotaryRepoWithSigners(notaryRepo client.Repository, newSigner data.Role
|
||||||
}
|
}
|
||||||
|
|
||||||
// generates an ECDSA key without a GUN for the specified role
|
// generates an ECDSA key without a GUN for the specified role
|
||||||
func getOrGenerateNotaryKey(notaryRepo client.Repository, role data.RoleName) (data.PublicKey, error) {
|
func getOrGenerateNotaryKey(notaryRepo notaryclient.Repository, role data.RoleName) (data.PublicKey, error) {
|
||||||
// use the signer name in the PEM headers if this is a delegation key
|
// use the signer name in the PEM headers if this is a delegation key
|
||||||
if data.IsDelegation(role) {
|
if data.IsDelegation(role) {
|
||||||
role = data.RoleName(notaryRoleToSigner(role))
|
role = data.RoleName(notaryRoleToSigner(role))
|
||||||
|
@ -242,7 +242,7 @@ func getOrGenerateNotaryKey(notaryRepo client.Repository, role data.RoleName) (d
|
||||||
}
|
}
|
||||||
|
|
||||||
// stages changes to add a signer with the specified name and key(s). Adds to targets/<name> and targets/releases
|
// stages changes to add a signer with the specified name and key(s). Adds to targets/<name> and targets/releases
|
||||||
func addStagedSigner(notaryRepo client.Repository, newSigner data.RoleName, signerKeys []data.PublicKey) error {
|
func addStagedSigner(notaryRepo notaryclient.Repository, newSigner data.RoleName, signerKeys []data.PublicKey) error {
|
||||||
// create targets/<username>
|
// create targets/<username>
|
||||||
if err := notaryRepo.AddDelegationRoleAndKeys(newSigner, signerKeys); err != nil {
|
if err := notaryRepo.AddDelegationRoleAndKeys(newSigner, signerKeys); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -3,7 +3,6 @@ package volume
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/volume"
|
"github.com/docker/docker/api/types/volume"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
@ -15,7 +14,7 @@ type fakeClient struct {
|
||||||
volumeInspectFunc func(volumeID string) (volume.Volume, error)
|
volumeInspectFunc func(volumeID string) (volume.Volume, error)
|
||||||
volumeListFunc func(filter filters.Args) (volume.ListResponse, error)
|
volumeListFunc func(filter filters.Args) (volume.ListResponse, error)
|
||||||
volumeRemoveFunc func(volumeID string, force bool) error
|
volumeRemoveFunc func(volumeID string, force bool) error
|
||||||
volumePruneFunc func(filter filters.Args) (types.VolumesPruneReport, error)
|
volumePruneFunc func(filter filters.Args) (volume.PruneReport, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeClient) VolumeCreate(_ context.Context, options volume.CreateOptions) (volume.Volume, error) {
|
func (c *fakeClient) VolumeCreate(_ context.Context, options volume.CreateOptions) (volume.Volume, error) {
|
||||||
|
@ -39,11 +38,11 @@ func (c *fakeClient) VolumeList(_ context.Context, options volume.ListOptions) (
|
||||||
return volume.ListResponse{}, nil
|
return volume.ListResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeClient) VolumesPrune(_ context.Context, filter filters.Args) (types.VolumesPruneReport, error) {
|
func (c *fakeClient) VolumesPrune(_ context.Context, filter filters.Args) (volume.PruneReport, error) {
|
||||||
if c.volumePruneFunc != nil {
|
if c.volumePruneFunc != nil {
|
||||||
return c.volumePruneFunc(filter)
|
return c.volumePruneFunc(filter)
|
||||||
}
|
}
|
||||||
return types.VolumesPruneReport{}, nil
|
return volume.PruneReport{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeClient) VolumeRemove(_ context.Context, volumeID string, force bool) error {
|
func (c *fakeClient) VolumeRemove(_ context.Context, volumeID string, force bool) error {
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
|
|
||||||
"github.com/docker/cli/cli/streams"
|
"github.com/docker/cli/cli/streams"
|
||||||
"github.com/docker/cli/internal/test"
|
"github.com/docker/cli/internal/test"
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/docker/docker/api/types/volume"
|
||||||
"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"
|
||||||
|
@ -24,7 +24,7 @@ func TestVolumePruneErrors(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
flags map[string]string
|
flags map[string]string
|
||||||
volumePruneFunc func(args filters.Args) (types.VolumesPruneReport, error)
|
volumePruneFunc func(args filters.Args) (volume.PruneReport, error)
|
||||||
expectedError string
|
expectedError string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
@ -37,8 +37,8 @@ func TestVolumePruneErrors(t *testing.T) {
|
||||||
flags: map[string]string{
|
flags: map[string]string{
|
||||||
"force": "true",
|
"force": "true",
|
||||||
},
|
},
|
||||||
volumePruneFunc: func(args filters.Args) (types.VolumesPruneReport, error) {
|
volumePruneFunc: func(args filters.Args) (volume.PruneReport, error) {
|
||||||
return types.VolumesPruneReport{}, errors.Errorf("error pruning volumes")
|
return volume.PruneReport{}, errors.Errorf("error pruning volumes")
|
||||||
},
|
},
|
||||||
expectedError: "error pruning volumes",
|
expectedError: "error pruning volumes",
|
||||||
},
|
},
|
||||||
|
@ -75,31 +75,31 @@ func TestVolumePruneSuccess(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
input string
|
input string
|
||||||
volumePruneFunc func(args filters.Args) (types.VolumesPruneReport, error)
|
volumePruneFunc func(args filters.Args) (volume.PruneReport, error)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "all",
|
name: "all",
|
||||||
args: []string{"--all"},
|
args: []string{"--all"},
|
||||||
input: "y",
|
input: "y",
|
||||||
volumePruneFunc: func(pruneFilter filters.Args) (types.VolumesPruneReport, error) {
|
volumePruneFunc: func(pruneFilter filters.Args) (volume.PruneReport, error) {
|
||||||
assert.Check(t, is.DeepEqual([]string{"true"}, pruneFilter.Get("all")))
|
assert.Check(t, is.DeepEqual([]string{"true"}, pruneFilter.Get("all")))
|
||||||
return types.VolumesPruneReport{}, nil
|
return volume.PruneReport{}, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "all-forced",
|
name: "all-forced",
|
||||||
args: []string{"--all", "--force"},
|
args: []string{"--all", "--force"},
|
||||||
volumePruneFunc: func(pruneFilter filters.Args) (types.VolumesPruneReport, error) {
|
volumePruneFunc: func(pruneFilter filters.Args) (volume.PruneReport, error) {
|
||||||
return types.VolumesPruneReport{}, nil
|
return volume.PruneReport{}, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "label-filter",
|
name: "label-filter",
|
||||||
args: []string{"--filter", "label=foobar"},
|
args: []string{"--filter", "label=foobar"},
|
||||||
input: "y",
|
input: "y",
|
||||||
volumePruneFunc: func(pruneFilter filters.Args) (types.VolumesPruneReport, error) {
|
volumePruneFunc: func(pruneFilter filters.Args) (volume.PruneReport, error) {
|
||||||
assert.Check(t, is.DeepEqual([]string{"foobar"}, pruneFilter.Get("label")))
|
assert.Check(t, is.DeepEqual([]string{"foobar"}, pruneFilter.Get("label")))
|
||||||
return types.VolumesPruneReport{}, nil
|
return volume.PruneReport{}, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ func TestVolumePruneSuccess(t *testing.T) {
|
||||||
func TestVolumePruneForce(t *testing.T) {
|
func TestVolumePruneForce(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
volumePruneFunc func(args filters.Args) (types.VolumesPruneReport, error)
|
volumePruneFunc func(args filters.Args) (volume.PruneReport, error)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty",
|
name: "empty",
|
||||||
|
@ -178,8 +178,8 @@ func TestVolumePrunePromptNo(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func simplePruneFunc(filters.Args) (types.VolumesPruneReport, error) {
|
func simplePruneFunc(filters.Args) (volume.PruneReport, error) {
|
||||||
return types.VolumesPruneReport{
|
return volume.PruneReport{
|
||||||
VolumesDeleted: []string{
|
VolumesDeleted: []string{
|
||||||
"foo", "bar", "baz",
|
"foo", "bar", "baz",
|
||||||
},
|
},
|
||||||
|
@ -192,8 +192,8 @@ func TestVolumePrunePromptTerminate(t *testing.T) {
|
||||||
t.Cleanup(cancel)
|
t.Cleanup(cancel)
|
||||||
|
|
||||||
cli := test.NewFakeCli(&fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
volumePruneFunc: func(filter filters.Args) (types.VolumesPruneReport, error) {
|
volumePruneFunc: func(filter filters.Args) (volume.PruneReport, error) {
|
||||||
return types.VolumesPruneReport{}, errors.New("fakeClient volumePruneFunc should not be called")
|
return volume.PruneReport{}, errors.New("fakeClient volumePruneFunc should not be called")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ require (
|
||||||
github.com/creack/pty v1.1.21
|
github.com/creack/pty v1.1.21
|
||||||
github.com/distribution/reference v0.6.0
|
github.com/distribution/reference v0.6.0
|
||||||
github.com/docker/distribution v2.8.3+incompatible
|
github.com/docker/distribution v2.8.3+incompatible
|
||||||
github.com/docker/docker v26.1.1-0.20240607121412-59996a493cfc+incompatible // master (v27.0.0-dev)
|
github.com/docker/docker v26.1.1-0.20240610145149-a736d0701c41+incompatible // master (v27.0.0-dev)
|
||||||
github.com/docker/docker-credential-helpers v0.8.2
|
github.com/docker/docker-credential-helpers v0.8.2
|
||||||
github.com/docker/go-connections v0.5.0
|
github.com/docker/go-connections v0.5.0
|
||||||
github.com/docker/go-units v0.5.0
|
github.com/docker/go-units v0.5.0
|
||||||
|
|
|
@ -59,8 +59,8 @@ github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5
|
||||||
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.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v26.1.1-0.20240607121412-59996a493cfc+incompatible h1:MQR7fZxS7agfjACehtep/M6Bvz7/pFvbOcFvtTmvKlg=
|
github.com/docker/docker v26.1.1-0.20240610145149-a736d0701c41+incompatible h1:Kraon288jb3POkrmM5w6Xo979z2rrCtFzHycAjafRes=
|
||||||
github.com/docker/docker v26.1.1-0.20240607121412-59996a493cfc+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v26.1.1-0.20240610145149-a736d0701c41+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||||
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=
|
||||||
|
|
|
@ -1198,13 +1198,6 @@ definitions:
|
||||||
ContainerConfig:
|
ContainerConfig:
|
||||||
description: |
|
description: |
|
||||||
Configuration for a container that is portable between hosts.
|
Configuration for a container that is portable between hosts.
|
||||||
|
|
||||||
When used as `ContainerConfig` field in an image, `ContainerConfig` is an
|
|
||||||
optional field containing the configuration of the container that was last
|
|
||||||
committed when creating the image.
|
|
||||||
|
|
||||||
Previous versions of Docker builder used this field to store build cache,
|
|
||||||
and it is not in active use anymore.
|
|
||||||
type: "object"
|
type: "object"
|
||||||
properties:
|
properties:
|
||||||
Hostname:
|
Hostname:
|
||||||
|
@ -1363,6 +1356,277 @@ definitions:
|
||||||
type: "string"
|
type: "string"
|
||||||
example: ["/bin/sh", "-c"]
|
example: ["/bin/sh", "-c"]
|
||||||
|
|
||||||
|
ImageConfig:
|
||||||
|
description: |
|
||||||
|
Configuration of the image. These fields are used as defaults
|
||||||
|
when starting a container from the image.
|
||||||
|
type: "object"
|
||||||
|
properties:
|
||||||
|
Hostname:
|
||||||
|
description: |
|
||||||
|
The hostname to use for the container, as a valid RFC 1123 hostname.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Note**: this field is always empty and must not be used.
|
||||||
|
type: "string"
|
||||||
|
example: ""
|
||||||
|
Domainname:
|
||||||
|
description: |
|
||||||
|
The domain name to use for the container.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Note**: this field is always empty and must not be used.
|
||||||
|
type: "string"
|
||||||
|
example: ""
|
||||||
|
User:
|
||||||
|
description: "The user that commands are run as inside the container."
|
||||||
|
type: "string"
|
||||||
|
example: "web:web"
|
||||||
|
AttachStdin:
|
||||||
|
description: |
|
||||||
|
Whether to attach to `stdin`.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Note**: this field is always false and must not be used.
|
||||||
|
type: "boolean"
|
||||||
|
default: false
|
||||||
|
example: false
|
||||||
|
AttachStdout:
|
||||||
|
description: |
|
||||||
|
Whether to attach to `stdout`.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Note**: this field is always false and must not be used.
|
||||||
|
type: "boolean"
|
||||||
|
default: false
|
||||||
|
example: false
|
||||||
|
AttachStderr:
|
||||||
|
description: |
|
||||||
|
Whether to attach to `stderr`.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Note**: this field is always false and must not be used.
|
||||||
|
type: "boolean"
|
||||||
|
default: false
|
||||||
|
example: false
|
||||||
|
ExposedPorts:
|
||||||
|
description: |
|
||||||
|
An object mapping ports to an empty object in the form:
|
||||||
|
|
||||||
|
`{"<port>/<tcp|udp|sctp>": {}}`
|
||||||
|
type: "object"
|
||||||
|
x-nullable: true
|
||||||
|
additionalProperties:
|
||||||
|
type: "object"
|
||||||
|
enum:
|
||||||
|
- {}
|
||||||
|
default: {}
|
||||||
|
example: {
|
||||||
|
"80/tcp": {},
|
||||||
|
"443/tcp": {}
|
||||||
|
}
|
||||||
|
Tty:
|
||||||
|
description: |
|
||||||
|
Attach standard streams to a TTY, including `stdin` if it is not closed.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Note**: this field is always false and must not be used.
|
||||||
|
type: "boolean"
|
||||||
|
default: false
|
||||||
|
example: false
|
||||||
|
OpenStdin:
|
||||||
|
description: |
|
||||||
|
Open `stdin`
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Note**: this field is always false and must not be used.
|
||||||
|
type: "boolean"
|
||||||
|
default: false
|
||||||
|
example: false
|
||||||
|
StdinOnce:
|
||||||
|
description: |
|
||||||
|
Close `stdin` after one attached client disconnects.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Note**: this field is always false and must not be used.
|
||||||
|
type: "boolean"
|
||||||
|
default: false
|
||||||
|
example: false
|
||||||
|
Env:
|
||||||
|
description: |
|
||||||
|
A list of environment variables to set inside the container in the
|
||||||
|
form `["VAR=value", ...]`. A variable without `=` is removed from the
|
||||||
|
environment, rather than to have an empty value.
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
example:
|
||||||
|
- "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
Cmd:
|
||||||
|
description: |
|
||||||
|
Command to run specified as a string or an array of strings.
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
example: ["/bin/sh"]
|
||||||
|
Healthcheck:
|
||||||
|
$ref: "#/definitions/HealthConfig"
|
||||||
|
ArgsEscaped:
|
||||||
|
description: "Command is already escaped (Windows only)"
|
||||||
|
type: "boolean"
|
||||||
|
default: false
|
||||||
|
example: false
|
||||||
|
x-nullable: true
|
||||||
|
Image:
|
||||||
|
description: |
|
||||||
|
The name (or reference) of the image to use when creating the container,
|
||||||
|
or which was used when the container was created.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Note**: this field is always empty and must not be used.
|
||||||
|
type: "string"
|
||||||
|
default: ""
|
||||||
|
example: ""
|
||||||
|
Volumes:
|
||||||
|
description: |
|
||||||
|
An object mapping mount point paths inside the container to empty
|
||||||
|
objects.
|
||||||
|
type: "object"
|
||||||
|
additionalProperties:
|
||||||
|
type: "object"
|
||||||
|
enum:
|
||||||
|
- {}
|
||||||
|
default: {}
|
||||||
|
example:
|
||||||
|
"/app/data": {}
|
||||||
|
"/app/config": {}
|
||||||
|
WorkingDir:
|
||||||
|
description: "The working directory for commands to run in."
|
||||||
|
type: "string"
|
||||||
|
example: "/public/"
|
||||||
|
Entrypoint:
|
||||||
|
description: |
|
||||||
|
The entry point for the container as a string or an array of strings.
|
||||||
|
|
||||||
|
If the array consists of exactly one empty string (`[""]`) then the
|
||||||
|
entry point is reset to system default (i.e., the entry point used by
|
||||||
|
docker when there is no `ENTRYPOINT` instruction in the `Dockerfile`).
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
example: []
|
||||||
|
NetworkDisabled:
|
||||||
|
description: |
|
||||||
|
Disable networking for the container.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Note**: this field is always omitted and must not be used.
|
||||||
|
type: "boolean"
|
||||||
|
default: false
|
||||||
|
example: false
|
||||||
|
x-nullable: true
|
||||||
|
MacAddress:
|
||||||
|
description: |
|
||||||
|
MAC address of the container.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Deprecated**: this field is deprecated in API v1.44 and up. It is always omitted.
|
||||||
|
type: "string"
|
||||||
|
default: ""
|
||||||
|
example: ""
|
||||||
|
x-nullable: true
|
||||||
|
OnBuild:
|
||||||
|
description: |
|
||||||
|
`ONBUILD` metadata that were defined in the image's `Dockerfile`.
|
||||||
|
type: "array"
|
||||||
|
x-nullable: true
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
example: []
|
||||||
|
Labels:
|
||||||
|
description: "User-defined key/value metadata."
|
||||||
|
type: "object"
|
||||||
|
additionalProperties:
|
||||||
|
type: "string"
|
||||||
|
example:
|
||||||
|
com.example.some-label: "some-value"
|
||||||
|
com.example.some-other-label: "some-other-value"
|
||||||
|
StopSignal:
|
||||||
|
description: |
|
||||||
|
Signal to stop a container as a string or unsigned integer.
|
||||||
|
type: "string"
|
||||||
|
example: "SIGTERM"
|
||||||
|
x-nullable: true
|
||||||
|
StopTimeout:
|
||||||
|
description: |
|
||||||
|
Timeout to stop a container in seconds.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
> **Note**: this field is always omitted and must not be used.
|
||||||
|
type: "integer"
|
||||||
|
default: 10
|
||||||
|
x-nullable: true
|
||||||
|
Shell:
|
||||||
|
description: |
|
||||||
|
Shell for when `RUN`, `CMD`, and `ENTRYPOINT` uses a shell.
|
||||||
|
type: "array"
|
||||||
|
x-nullable: true
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
example: ["/bin/sh", "-c"]
|
||||||
|
# FIXME(thaJeztah): temporarily using a full example to remove some "omitempty" fields. Remove once the fields are removed.
|
||||||
|
example:
|
||||||
|
"Hostname": ""
|
||||||
|
"Domainname": ""
|
||||||
|
"User": "web:web"
|
||||||
|
"AttachStdin": false
|
||||||
|
"AttachStdout": false
|
||||||
|
"AttachStderr": false
|
||||||
|
"ExposedPorts": {
|
||||||
|
"80/tcp": {},
|
||||||
|
"443/tcp": {}
|
||||||
|
}
|
||||||
|
"Tty": false
|
||||||
|
"OpenStdin": false
|
||||||
|
"StdinOnce": false
|
||||||
|
"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"]
|
||||||
|
"Cmd": ["/bin/sh"]
|
||||||
|
"Healthcheck": {
|
||||||
|
"Test": ["string"],
|
||||||
|
"Interval": 0,
|
||||||
|
"Timeout": 0,
|
||||||
|
"Retries": 0,
|
||||||
|
"StartPeriod": 0,
|
||||||
|
"StartInterval": 0
|
||||||
|
}
|
||||||
|
"ArgsEscaped": true
|
||||||
|
"Image": ""
|
||||||
|
"Volumes": {
|
||||||
|
"/app/data": {},
|
||||||
|
"/app/config": {}
|
||||||
|
}
|
||||||
|
"WorkingDir": "/public/"
|
||||||
|
"Entrypoint": []
|
||||||
|
"OnBuild": []
|
||||||
|
"Labels": {
|
||||||
|
"com.example.some-label": "some-value",
|
||||||
|
"com.example.some-other-label": "some-other-value"
|
||||||
|
}
|
||||||
|
"StopSignal": "SIGTERM"
|
||||||
|
"Shell": ["/bin/sh", "-c"]
|
||||||
|
|
||||||
NetworkingConfig:
|
NetworkingConfig:
|
||||||
description: |
|
description: |
|
||||||
NetworkingConfig represents the container's networking configuration for
|
NetworkingConfig represents the container's networking configuration for
|
||||||
|
@ -1758,21 +2022,6 @@ definitions:
|
||||||
format: "dateTime"
|
format: "dateTime"
|
||||||
x-nullable: true
|
x-nullable: true
|
||||||
example: "2022-02-04T21:20:12.497794809Z"
|
example: "2022-02-04T21:20:12.497794809Z"
|
||||||
Container:
|
|
||||||
description: |
|
|
||||||
The ID of the container that was used to create the image.
|
|
||||||
|
|
||||||
Depending on how the image was created, this field may be empty.
|
|
||||||
|
|
||||||
**Deprecated**: this field is kept for backward compatibility, but
|
|
||||||
will be removed in API v1.45.
|
|
||||||
type: "string"
|
|
||||||
example: "65974bc86f1770ae4bff79f651ebdbce166ae9aada632ee3fa9af3a264911735"
|
|
||||||
ContainerConfig:
|
|
||||||
description: |
|
|
||||||
**Deprecated**: this field is kept for backward compatibility, but
|
|
||||||
will be removed in API v1.45.
|
|
||||||
$ref: "#/definitions/ContainerConfig"
|
|
||||||
DockerVersion:
|
DockerVersion:
|
||||||
description: |
|
description: |
|
||||||
The version of Docker that was used to build the image.
|
The version of Docker that was used to build the image.
|
||||||
|
@ -1789,7 +2038,7 @@ definitions:
|
||||||
x-nullable: false
|
x-nullable: false
|
||||||
example: ""
|
example: ""
|
||||||
Config:
|
Config:
|
||||||
$ref: "#/definitions/ContainerConfig"
|
$ref: "#/definitions/ImageConfig"
|
||||||
Architecture:
|
Architecture:
|
||||||
description: |
|
description: |
|
||||||
Hardware CPU architecture that the image runs on.
|
Hardware CPU architecture that the image runs on.
|
||||||
|
|
|
@ -12,29 +12,6 @@ import (
|
||||||
units "github.com/docker/go-units"
|
units "github.com/docker/go-units"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerExecInspect holds information returned by exec inspect.
|
|
||||||
type ContainerExecInspect struct {
|
|
||||||
ExecID string `json:"ID"`
|
|
||||||
ContainerID string
|
|
||||||
Running bool
|
|
||||||
ExitCode int
|
|
||||||
Pid int
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyToContainerOptions holds information
|
|
||||||
// about files to copy into a container
|
|
||||||
type CopyToContainerOptions struct {
|
|
||||||
AllowOverwriteDirWithFile bool
|
|
||||||
CopyUIDGID bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// EventsOptions holds parameters to filter events with.
|
|
||||||
type EventsOptions struct {
|
|
||||||
Since string
|
|
||||||
Until string
|
|
||||||
Filters filters.Args
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHijackedResponse intializes a HijackedResponse type
|
// NewHijackedResponse intializes a HijackedResponse type
|
||||||
func NewHijackedResponse(conn net.Conn, mediaType string) HijackedResponse {
|
func NewHijackedResponse(conn net.Conn, mediaType string) HijackedResponse {
|
||||||
return HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn), mediaType: mediaType}
|
return HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn), mediaType: mediaType}
|
||||||
|
@ -153,19 +130,6 @@ type ImageBuildResponse struct {
|
||||||
OSType string
|
OSType string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageImportSource holds source information for ImageImport
|
|
||||||
type ImageImportSource struct {
|
|
||||||
Source io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this.
|
|
||||||
SourceName string // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute.
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImageLoadResponse returns information to the client about a load process.
|
|
||||||
type ImageLoadResponse struct {
|
|
||||||
// Body must be closed to avoid a resource leak
|
|
||||||
Body io.ReadCloser
|
|
||||||
JSON bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestPrivilegeFunc is a function interface that
|
// RequestPrivilegeFunc is a function interface that
|
||||||
// clients can supply to retry operations after
|
// clients can supply to retry operations after
|
||||||
// getting an authorization error.
|
// getting an authorization error.
|
||||||
|
@ -174,14 +138,6 @@ type ImageLoadResponse struct {
|
||||||
// if the privilege request fails.
|
// if the privilege request fails.
|
||||||
type RequestPrivilegeFunc func(context.Context) (string, error)
|
type RequestPrivilegeFunc func(context.Context) (string, error)
|
||||||
|
|
||||||
// ImageSearchOptions holds parameters to search images with.
|
|
||||||
type ImageSearchOptions struct {
|
|
||||||
RegistryAuth string
|
|
||||||
PrivilegeFunc RequestPrivilegeFunc
|
|
||||||
Filters filters.Args
|
|
||||||
Limit int
|
|
||||||
}
|
|
||||||
|
|
||||||
// NodeListOptions holds parameters to list nodes with.
|
// NodeListOptions holds parameters to list nodes with.
|
||||||
type NodeListOptions struct {
|
type NodeListOptions struct {
|
||||||
Filters filters.Args
|
Filters filters.Args
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
package types // import "github.com/docker/docker/api/types"
|
|
||||||
|
|
||||||
// ExecConfig is a small subset of the Config struct that holds the configuration
|
|
||||||
// for the exec feature of docker.
|
|
||||||
type ExecConfig struct {
|
|
||||||
User string // User that will run the command
|
|
||||||
Privileged bool // Is the container in privileged mode
|
|
||||||
Tty bool // Attach standard streams to a tty.
|
|
||||||
ConsoleSize *[2]uint `json:",omitempty"` // Initial console size [height, width]
|
|
||||||
AttachStdin bool // Attach the standard input, makes possible user interaction
|
|
||||||
AttachStderr bool // Attach the standard error
|
|
||||||
AttachStdout bool // Attach the standard output
|
|
||||||
Detach bool // Execute in detach mode
|
|
||||||
DetachKeys string // Escape keys for detach
|
|
||||||
Env []string // Environment variables
|
|
||||||
WorkingDir string // Working directory
|
|
||||||
Cmd []string // Execution commands and args
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
package container // import "github.com/docker/docker/api/types/container"
|
package container // import "github.com/docker/docker/api/types/container"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/strslice"
|
"github.com/docker/docker/api/types/strslice"
|
||||||
|
@ -36,14 +35,6 @@ type StopOptions struct {
|
||||||
// HealthConfig holds configuration settings for the HEALTHCHECK feature.
|
// HealthConfig holds configuration settings for the HEALTHCHECK feature.
|
||||||
type HealthConfig = dockerspec.HealthcheckConfig
|
type HealthConfig = dockerspec.HealthcheckConfig
|
||||||
|
|
||||||
// ExecStartOptions holds the options to start container's exec.
|
|
||||||
type ExecStartOptions struct {
|
|
||||||
Stdin io.Reader
|
|
||||||
Stdout io.Writer
|
|
||||||
Stderr io.Writer
|
|
||||||
ConsoleSize *[2]uint `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config contains the configuration data about a container.
|
// Config contains the configuration data about a container.
|
||||||
// It should hold only portable information about the container.
|
// It should hold only portable information about the container.
|
||||||
// Here, "portable" means "independent from the host we are running on".
|
// Here, "portable" means "independent from the host we are running on".
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PruneReport contains the response for Engine API:
|
||||||
|
// POST "/containers/prune"
|
||||||
|
type PruneReport struct {
|
||||||
|
ContainersDeleted []string
|
||||||
|
SpaceReclaimed uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathStat is used to encode the header from
|
||||||
|
// GET "/containers/{name:.*}/archive"
|
||||||
|
// "Name" is the file or directory name.
|
||||||
|
type PathStat struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Mode os.FileMode `json:"mode"`
|
||||||
|
Mtime time.Time `json:"mtime"`
|
||||||
|
LinkTarget string `json:"linkTarget"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyToContainerOptions holds information
|
||||||
|
// about files to copy into a container
|
||||||
|
type CopyToContainerOptions struct {
|
||||||
|
AllowOverwriteDirWithFile bool
|
||||||
|
CopyUIDGID bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatsResponse contains response of Engine API:
|
||||||
|
// GET "/stats"
|
||||||
|
type StatsResponse struct {
|
||||||
|
Body io.ReadCloser `json:"body"`
|
||||||
|
OSType string `json:"ostype"`
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
// ExecOptions is a small subset of the Config struct that holds the configuration
|
||||||
|
// for the exec feature of docker.
|
||||||
|
type ExecOptions struct {
|
||||||
|
User string // User that will run the command
|
||||||
|
Privileged bool // Is the container in privileged mode
|
||||||
|
Tty bool // Attach standard streams to a tty.
|
||||||
|
ConsoleSize *[2]uint `json:",omitempty"` // Initial console size [height, width]
|
||||||
|
AttachStdin bool // Attach the standard input, makes possible user interaction
|
||||||
|
AttachStderr bool // Attach the standard error
|
||||||
|
AttachStdout bool // Attach the standard output
|
||||||
|
Detach bool // Execute in detach mode
|
||||||
|
DetachKeys string // Escape keys for detach
|
||||||
|
Env []string // Environment variables
|
||||||
|
WorkingDir string // Working directory
|
||||||
|
Cmd []string // Execution commands and args
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecStartOptions is a temp struct used by execStart
|
||||||
|
// Config fields is part of ExecConfig in runconfig package
|
||||||
|
type ExecStartOptions struct {
|
||||||
|
// ExecStart will first check if it's detached
|
||||||
|
Detach bool
|
||||||
|
// Check if there's a tty
|
||||||
|
Tty bool
|
||||||
|
// Terminal size [height, width], unused if Tty == false
|
||||||
|
ConsoleSize *[2]uint `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecAttachOptions is a temp struct used by execAttach.
|
||||||
|
//
|
||||||
|
// TODO(thaJeztah): make this a separate type; ContainerExecAttach does not use the Detach option, and cannot run detached.
|
||||||
|
type ExecAttachOptions = ExecStartOptions
|
||||||
|
|
||||||
|
// ExecInspect holds information returned by exec inspect.
|
||||||
|
type ExecInspect struct {
|
||||||
|
ExecID string `json:"ID"`
|
||||||
|
ContainerID string
|
||||||
|
Running bool
|
||||||
|
ExitCode int
|
||||||
|
Pid int
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
package events // import "github.com/docker/docker/api/types/events"
|
package events // import "github.com/docker/docker/api/types/events"
|
||||||
|
import "github.com/docker/docker/api/types/filters"
|
||||||
|
|
||||||
// Type is used for event-types.
|
// Type is used for event-types.
|
||||||
type Type string
|
type Type string
|
||||||
|
@ -125,3 +126,10 @@ type Message struct {
|
||||||
Time int64 `json:"time,omitempty"`
|
Time int64 `json:"time,omitempty"`
|
||||||
TimeNano int64 `json:"timeNano,omitempty"`
|
TimeNano int64 `json:"timeNano,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListOptions holds parameters to filter events with.
|
||||||
|
type ListOptions struct {
|
||||||
|
Since string
|
||||||
|
Until string
|
||||||
|
Filters filters.Args
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,47 @@
|
||||||
package image
|
package image
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// Metadata contains engine-local data about the image.
|
// Metadata contains engine-local data about the image.
|
||||||
type Metadata struct {
|
type Metadata struct {
|
||||||
// LastTagTime is the date and time at which the image was last tagged.
|
// LastTagTime is the date and time at which the image was last tagged.
|
||||||
LastTagTime time.Time `json:",omitempty"`
|
LastTagTime time.Time `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PruneReport contains the response for Engine API:
|
||||||
|
// POST "/images/prune"
|
||||||
|
type PruneReport struct {
|
||||||
|
ImagesDeleted []DeleteResponse
|
||||||
|
SpaceReclaimed uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadResponse returns information to the client about a load process.
|
||||||
|
//
|
||||||
|
// TODO(thaJeztah): remove this type, and just use an io.ReadCloser
|
||||||
|
//
|
||||||
|
// This type was added in https://github.com/moby/moby/pull/18878, related
|
||||||
|
// to https://github.com/moby/moby/issues/19177;
|
||||||
|
//
|
||||||
|
// Make docker load to output json when the response content type is json
|
||||||
|
// Swarm hijacks the response from docker load and returns JSON rather
|
||||||
|
// than plain text like the Engine does. This makes the API library to return
|
||||||
|
// information to figure that out.
|
||||||
|
//
|
||||||
|
// However the "load" endpoint unconditionally returns JSON;
|
||||||
|
// https://github.com/moby/moby/blob/7b9d2ef6e5518a3d3f3cc418459f8df786cfbbd1/api/server/router/image/image_routes.go#L248-L255
|
||||||
|
//
|
||||||
|
// PR https://github.com/moby/moby/pull/21959 made the response-type depend
|
||||||
|
// on whether "quiet" was set, but this logic got changed in a follow-up
|
||||||
|
// https://github.com/moby/moby/pull/25557, which made the JSON response-type
|
||||||
|
// unconditionally, but the output produced depend on whether"quiet" was set.
|
||||||
|
//
|
||||||
|
// We should deprecated the "quiet" option, as it's really a client
|
||||||
|
// responsibility.
|
||||||
|
type LoadResponse struct {
|
||||||
|
// Body must be closed to avoid a resource leak
|
||||||
|
Body io.ReadCloser
|
||||||
|
JSON bool
|
||||||
|
}
|
||||||
|
|
|
@ -2,10 +2,17 @@ package image
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ImportSource holds source information for ImageImport
|
||||||
|
type ImportSource struct {
|
||||||
|
Source io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this.
|
||||||
|
SourceName string // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute.
|
||||||
|
}
|
||||||
|
|
||||||
// ImportOptions holds information to import images from the client host.
|
// ImportOptions holds information to import images from the client host.
|
||||||
type ImportOptions struct {
|
type ImportOptions struct {
|
||||||
Tag string // Tag is the name to tag this image with. This attribute is deprecated.
|
Tag string // Tag is the name to tag this image with. This attribute is deprecated.
|
||||||
|
|
|
@ -84,32 +84,6 @@ type IndexInfo struct {
|
||||||
Official bool
|
Official bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchResult describes a search result returned from a registry
|
|
||||||
type SearchResult struct {
|
|
||||||
// StarCount indicates the number of stars this repository has
|
|
||||||
StarCount int `json:"star_count"`
|
|
||||||
// IsOfficial is true if the result is from an official repository.
|
|
||||||
IsOfficial bool `json:"is_official"`
|
|
||||||
// Name is the name of the repository
|
|
||||||
Name string `json:"name"`
|
|
||||||
// IsAutomated indicates whether the result is automated.
|
|
||||||
//
|
|
||||||
// Deprecated: the "is_automated" field is deprecated and will always be "false".
|
|
||||||
IsAutomated bool `json:"is_automated"`
|
|
||||||
// Description is a textual description of the repository
|
|
||||||
Description string `json:"description"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SearchResults lists a collection search results returned from a registry
|
|
||||||
type SearchResults struct {
|
|
||||||
// Query contains the query string that generated the search results
|
|
||||||
Query string `json:"query"`
|
|
||||||
// NumResults indicates the number of results the query returned
|
|
||||||
NumResults int `json:"num_results"`
|
|
||||||
// Results is a slice containing the actual results for the search
|
|
||||||
Results []SearchResult `json:"results"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DistributionInspect describes the result obtained from contacting the
|
// DistributionInspect describes the result obtained from contacting the
|
||||||
// registry to retrieve image metadata
|
// registry to retrieve image metadata
|
||||||
type DistributionInspect struct {
|
type DistributionInspect struct {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SearchOptions holds parameters to search images with.
|
||||||
|
type SearchOptions struct {
|
||||||
|
RegistryAuth string
|
||||||
|
|
||||||
|
// PrivilegeFunc is a [types.RequestPrivilegeFunc] the client can
|
||||||
|
// supply to retry operations after getting an authorization error.
|
||||||
|
//
|
||||||
|
// It must return the registry authentication header value in base64
|
||||||
|
// format, or an error if the privilege request fails.
|
||||||
|
PrivilegeFunc func(context.Context) (string, error)
|
||||||
|
Filters filters.Args
|
||||||
|
Limit int
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchResult describes a search result returned from a registry
|
||||||
|
type SearchResult struct {
|
||||||
|
// StarCount indicates the number of stars this repository has
|
||||||
|
StarCount int `json:"star_count"`
|
||||||
|
// IsOfficial is true if the result is from an official repository.
|
||||||
|
IsOfficial bool `json:"is_official"`
|
||||||
|
// Name is the name of the repository
|
||||||
|
Name string `json:"name"`
|
||||||
|
// IsAutomated indicates whether the result is automated.
|
||||||
|
//
|
||||||
|
// Deprecated: the "is_automated" field is deprecated and will always be "false".
|
||||||
|
IsAutomated bool `json:"is_automated"`
|
||||||
|
// Description is a textual description of the repository
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchResults lists a collection search results returned from a registry
|
||||||
|
type SearchResults struct {
|
||||||
|
// Query contains the query string that generated the search results
|
||||||
|
Query string `json:"query"`
|
||||||
|
// NumResults indicates the number of results the query returned
|
||||||
|
NumResults int `json:"num_results"`
|
||||||
|
// Results is a slice containing the actual results for the search
|
||||||
|
Results []SearchResult `json:"results"`
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
package types // import "github.com/docker/docker/api/types"
|
package types // import "github.com/docker/docker/api/types"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
|
@ -162,30 +160,6 @@ type Container struct {
|
||||||
Mounts []MountPoint
|
Mounts []MountPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyConfig contains request body of Engine API:
|
|
||||||
// POST "/containers/"+containerID+"/copy"
|
|
||||||
type CopyConfig struct {
|
|
||||||
Resource string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerPathStat is used to encode the header from
|
|
||||||
// GET "/containers/{name:.*}/archive"
|
|
||||||
// "Name" is the file or directory name.
|
|
||||||
type ContainerPathStat struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Size int64 `json:"size"`
|
|
||||||
Mode os.FileMode `json:"mode"`
|
|
||||||
Mtime time.Time `json:"mtime"`
|
|
||||||
LinkTarget string `json:"linkTarget"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerStats contains response of Engine API:
|
|
||||||
// GET "/stats"
|
|
||||||
type ContainerStats struct {
|
|
||||||
Body io.ReadCloser `json:"body"`
|
|
||||||
OSType string `json:"ostype"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ping contains response of Engine API:
|
// Ping contains response of Engine API:
|
||||||
// GET "/_ping"
|
// GET "/_ping"
|
||||||
type Ping struct {
|
type Ping struct {
|
||||||
|
@ -231,17 +205,6 @@ type Version struct {
|
||||||
BuildTime string `json:",omitempty"`
|
BuildTime string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecStartCheck is a temp struct used by execStart
|
|
||||||
// Config fields is part of ExecConfig in runconfig package
|
|
||||||
type ExecStartCheck struct {
|
|
||||||
// ExecStart will first check if it's detached
|
|
||||||
Detach bool
|
|
||||||
// Check if there's a tty
|
|
||||||
Tty bool
|
|
||||||
// Terminal size [height, width], unused if Tty == false
|
|
||||||
ConsoleSize *[2]uint `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// HealthcheckResult stores information about a single run of a healthcheck probe
|
// HealthcheckResult stores information about a single run of a healthcheck probe
|
||||||
type HealthcheckResult struct {
|
type HealthcheckResult struct {
|
||||||
Start time.Time // Start is the time this check started
|
Start time.Time // Start is the time this check started
|
||||||
|
@ -456,27 +419,6 @@ type DiskUsage struct {
|
||||||
BuilderSize int64 `json:",omitempty"` // Deprecated: deprecated in API 1.38, and no longer used since API 1.40.
|
BuilderSize int64 `json:",omitempty"` // Deprecated: deprecated in API 1.38, and no longer used since API 1.40.
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainersPruneReport contains the response for Engine API:
|
|
||||||
// POST "/containers/prune"
|
|
||||||
type ContainersPruneReport struct {
|
|
||||||
ContainersDeleted []string
|
|
||||||
SpaceReclaimed uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// VolumesPruneReport contains the response for Engine API:
|
|
||||||
// POST "/volumes/prune"
|
|
||||||
type VolumesPruneReport struct {
|
|
||||||
VolumesDeleted []string
|
|
||||||
SpaceReclaimed uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImagesPruneReport contains the response for Engine API:
|
|
||||||
// POST "/images/prune"
|
|
||||||
type ImagesPruneReport struct {
|
|
||||||
ImagesDeleted []image.DeleteResponse
|
|
||||||
SpaceReclaimed uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// BuildCachePruneReport contains the response for Engine API:
|
// BuildCachePruneReport contains the response for Engine API:
|
||||||
// POST "/build/prune"
|
// POST "/build/prune"
|
||||||
type BuildCachePruneReport struct {
|
type BuildCachePruneReport struct {
|
||||||
|
|
|
@ -1,9 +1,26 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/docker/api/types/events"
|
||||||
|
"github.com/docker/docker/api/types/image"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
|
"github.com/docker/docker/api/types/registry"
|
||||||
|
"github.com/docker/docker/api/types/volume"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ImagesPruneReport contains the response for Engine API:
|
||||||
|
// POST "/images/prune"
|
||||||
|
//
|
||||||
|
// Deprecated: use [image.PruneReport].
|
||||||
|
type ImagesPruneReport = image.PruneReport
|
||||||
|
|
||||||
|
// VolumesPruneReport contains the response for Engine API:
|
||||||
|
// POST "/volumes/prune".
|
||||||
|
//
|
||||||
|
// Deprecated: use [volume.PruneReport].
|
||||||
|
type VolumesPruneReport = volume.PruneReport
|
||||||
|
|
||||||
// NetworkCreateRequest is the request message sent to the server for network create call.
|
// NetworkCreateRequest is the request message sent to the server for network create call.
|
||||||
//
|
//
|
||||||
// Deprecated: use [network.CreateRequest].
|
// Deprecated: use [network.CreateRequest].
|
||||||
|
@ -54,3 +71,65 @@ type NetworkResource = network.Inspect
|
||||||
//
|
//
|
||||||
// Deprecated: use [network.PruneReport].
|
// Deprecated: use [network.PruneReport].
|
||||||
type NetworksPruneReport = network.PruneReport
|
type NetworksPruneReport = network.PruneReport
|
||||||
|
|
||||||
|
// ExecConfig is a small subset of the Config struct that holds the configuration
|
||||||
|
// for the exec feature of docker.
|
||||||
|
//
|
||||||
|
// Deprecated: use [container.ExecOptions].
|
||||||
|
type ExecConfig = container.ExecOptions
|
||||||
|
|
||||||
|
// ExecStartCheck is a temp struct used by execStart
|
||||||
|
// Config fields is part of ExecConfig in runconfig package
|
||||||
|
//
|
||||||
|
// Deprecated: use [container.ExecStartOptions] or [container.ExecAttachOptions].
|
||||||
|
type ExecStartCheck = container.ExecStartOptions
|
||||||
|
|
||||||
|
// ContainerExecInspect holds information returned by exec inspect.
|
||||||
|
//
|
||||||
|
// Deprecated: use [container.ExecInspect].
|
||||||
|
type ContainerExecInspect = container.ExecInspect
|
||||||
|
|
||||||
|
// ContainersPruneReport contains the response for Engine API:
|
||||||
|
// POST "/containers/prune"
|
||||||
|
//
|
||||||
|
// Deprecated: use [container.PruneReport].
|
||||||
|
type ContainersPruneReport = container.PruneReport
|
||||||
|
|
||||||
|
// ContainerPathStat is used to encode the header from
|
||||||
|
// GET "/containers/{name:.*}/archive"
|
||||||
|
// "Name" is the file or directory name.
|
||||||
|
//
|
||||||
|
// Deprecated: use [container.PathStat].
|
||||||
|
type ContainerPathStat = container.PathStat
|
||||||
|
|
||||||
|
// CopyToContainerOptions holds information
|
||||||
|
// about files to copy into a container.
|
||||||
|
//
|
||||||
|
// Deprecated: use [container.CopyToContainerOptions],
|
||||||
|
type CopyToContainerOptions = container.CopyToContainerOptions
|
||||||
|
|
||||||
|
// ContainerStats contains response of Engine API:
|
||||||
|
// GET "/stats"
|
||||||
|
//
|
||||||
|
// Deprecated: use [container.StatsResponse].
|
||||||
|
type ContainerStats = container.StatsResponse
|
||||||
|
|
||||||
|
// EventsOptions holds parameters to filter events with.
|
||||||
|
//
|
||||||
|
// Deprecated: use [events.ListOptions].
|
||||||
|
type EventsOptions = events.ListOptions
|
||||||
|
|
||||||
|
// ImageSearchOptions holds parameters to search images with.
|
||||||
|
//
|
||||||
|
// Deprecated: use [registry.SearchOptions].
|
||||||
|
type ImageSearchOptions = registry.SearchOptions
|
||||||
|
|
||||||
|
// ImageImportSource holds source information for ImageImport
|
||||||
|
//
|
||||||
|
// Deprecated: use [image.ImportSource].
|
||||||
|
type ImageImportSource image.ImportSource
|
||||||
|
|
||||||
|
// ImageLoadResponse returns information to the client about a load process.
|
||||||
|
//
|
||||||
|
// Deprecated: use [image.LoadResponse].
|
||||||
|
type ImageLoadResponse = image.LoadResponse
|
||||||
|
|
|
@ -6,3 +6,10 @@ import "github.com/docker/docker/api/types/filters"
|
||||||
type ListOptions struct {
|
type ListOptions struct {
|
||||||
Filters filters.Args
|
Filters filters.Args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PruneReport contains the response for Engine API:
|
||||||
|
// POST "/volumes/prune"
|
||||||
|
type PruneReport struct {
|
||||||
|
VolumesDeleted []string
|
||||||
|
SpaceReclaimed uint64
|
||||||
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerStatPath returns stat information about a path inside the container filesystem.
|
// ContainerStatPath returns stat information about a path inside the container filesystem.
|
||||||
func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path string) (types.ContainerPathStat, error) {
|
func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path string) (container.PathStat, error) {
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
query.Set("path", filepath.ToSlash(path)) // Normalize the paths used in the API.
|
query.Set("path", filepath.ToSlash(path)) // Normalize the paths used in the API.
|
||||||
|
|
||||||
|
@ -23,14 +23,14 @@ func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path stri
|
||||||
response, err := cli.head(ctx, urlStr, query, nil)
|
response, err := cli.head(ctx, urlStr, query, nil)
|
||||||
defer ensureReaderClosed(response)
|
defer ensureReaderClosed(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.ContainerPathStat{}, err
|
return container.PathStat{}, err
|
||||||
}
|
}
|
||||||
return getContainerPathStatFromHeader(response.header)
|
return getContainerPathStatFromHeader(response.header)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyToContainer copies content into the container filesystem.
|
// CopyToContainer copies content into the container filesystem.
|
||||||
// Note that `content` must be a Reader for a TAR archive
|
// Note that `content` must be a Reader for a TAR archive
|
||||||
func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath string, content io.Reader, options types.CopyToContainerOptions) error {
|
func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath string, content io.Reader, options container.CopyToContainerOptions) error {
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
query.Set("path", filepath.ToSlash(dstPath)) // Normalize the paths used in the API.
|
query.Set("path", filepath.ToSlash(dstPath)) // Normalize the paths used in the API.
|
||||||
// Do not allow for an existing directory to be overwritten by a non-directory and vice versa.
|
// Do not allow for an existing directory to be overwritten by a non-directory and vice versa.
|
||||||
|
@ -55,14 +55,14 @@ func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath str
|
||||||
|
|
||||||
// CopyFromContainer gets the content from the container and returns it as a Reader
|
// CopyFromContainer gets the content from the container and returns it as a Reader
|
||||||
// for a TAR archive to manipulate it in the host. It's up to the caller to close the reader.
|
// for a TAR archive to manipulate it in the host. It's up to the caller to close the reader.
|
||||||
func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
|
func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath string) (io.ReadCloser, container.PathStat, error) {
|
||||||
query := make(url.Values, 1)
|
query := make(url.Values, 1)
|
||||||
query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API.
|
query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API.
|
||||||
|
|
||||||
apiPath := "/containers/" + containerID + "/archive"
|
apiPath := "/containers/" + containerID + "/archive"
|
||||||
response, err := cli.get(ctx, apiPath, query, nil)
|
response, err := cli.get(ctx, apiPath, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.ContainerPathStat{}, err
|
return nil, container.PathStat{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// In order to get the copy behavior right, we need to know information
|
// In order to get the copy behavior right, we need to know information
|
||||||
|
@ -78,8 +78,8 @@ func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath s
|
||||||
return response.body, stat, err
|
return response.body, stat, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getContainerPathStatFromHeader(header http.Header) (types.ContainerPathStat, error) {
|
func getContainerPathStatFromHeader(header http.Header) (container.PathStat, error) {
|
||||||
var stat types.ContainerPathStat
|
var stat container.PathStat
|
||||||
|
|
||||||
encodedStat := header.Get("X-Docker-Container-Path-Stat")
|
encodedStat := header.Get("X-Docker-Container-Path-Stat")
|
||||||
statDecoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(encodedStat))
|
statDecoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(encodedStat))
|
||||||
|
|
|
@ -6,11 +6,12 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerExecCreate creates a new exec configuration to run an exec process.
|
// ContainerExecCreate creates a new exec configuration to run an exec process.
|
||||||
func (cli *Client) ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error) {
|
func (cli *Client) ContainerExecCreate(ctx context.Context, container string, options container.ExecOptions) (types.IDResponse, error) {
|
||||||
var response types.IDResponse
|
var response types.IDResponse
|
||||||
|
|
||||||
// Make sure we negotiated (if the client is configured to do so),
|
// Make sure we negotiated (if the client is configured to do so),
|
||||||
|
@ -22,14 +23,14 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, container string, co
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cli.NewVersionError(ctx, "1.25", "env"); len(config.Env) != 0 && err != nil {
|
if err := cli.NewVersionError(ctx, "1.25", "env"); len(options.Env) != 0 && err != nil {
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
if versions.LessThan(cli.ClientVersion(), "1.42") {
|
if versions.LessThan(cli.ClientVersion(), "1.42") {
|
||||||
config.ConsoleSize = nil
|
options.ConsoleSize = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, config, nil)
|
resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, options, nil)
|
||||||
defer ensureReaderClosed(resp)
|
defer ensureReaderClosed(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response, err
|
return response, err
|
||||||
|
@ -39,7 +40,7 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, container string, co
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerExecStart starts an exec process already created in the docker host.
|
// ContainerExecStart starts an exec process already created in the docker host.
|
||||||
func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error {
|
func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config container.ExecStartOptions) error {
|
||||||
if versions.LessThan(cli.ClientVersion(), "1.42") {
|
if versions.LessThan(cli.ClientVersion(), "1.42") {
|
||||||
config.ConsoleSize = nil
|
config.ConsoleSize = nil
|
||||||
}
|
}
|
||||||
|
@ -52,7 +53,7 @@ func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config
|
||||||
// It returns a types.HijackedConnection with the hijacked connection
|
// It returns a types.HijackedConnection with the hijacked connection
|
||||||
// and the a reader to get output. It's up to the called to close
|
// and the a reader to get output. It's up to the called to close
|
||||||
// the hijacked connection by calling types.HijackedResponse.Close.
|
// the hijacked connection by calling types.HijackedResponse.Close.
|
||||||
func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) {
|
func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config container.ExecAttachOptions) (types.HijackedResponse, error) {
|
||||||
if versions.LessThan(cli.ClientVersion(), "1.42") {
|
if versions.LessThan(cli.ClientVersion(), "1.42") {
|
||||||
config.ConsoleSize = nil
|
config.ConsoleSize = nil
|
||||||
}
|
}
|
||||||
|
@ -62,8 +63,8 @@ func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, confi
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerExecInspect returns information about a specific exec process on the docker host.
|
// ContainerExecInspect returns information about a specific exec process on the docker host.
|
||||||
func (cli *Client) ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error) {
|
func (cli *Client) ContainerExecInspect(ctx context.Context, execID string) (container.ExecInspect, error) {
|
||||||
var response types.ContainerExecInspect
|
var response container.ExecInspect
|
||||||
resp, err := cli.get(ctx, "/exec/"+execID+"/json", nil, nil)
|
resp, err := cli.get(ctx, "/exec/"+execID+"/json", nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response, err
|
return response, err
|
||||||
|
|
|
@ -5,13 +5,13 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainersPrune requests the daemon to delete unused data
|
// ContainersPrune requests the daemon to delete unused data
|
||||||
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) {
|
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
|
||||||
var report types.ContainersPruneReport
|
var report container.PruneReport
|
||||||
|
|
||||||
if err := cli.NewVersionError(ctx, "1.25", "container prune"); err != nil {
|
if err := cli.NewVersionError(ctx, "1.25", "container prune"); err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
|
|
|
@ -4,12 +4,12 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerStats returns near realtime stats for a given container.
|
// ContainerStats returns near realtime stats for a given container.
|
||||||
// It's up to the caller to close the io.ReadCloser returned.
|
// It's up to the caller to close the io.ReadCloser returned.
|
||||||
func (cli *Client) ContainerStats(ctx context.Context, containerID string, stream bool) (types.ContainerStats, error) {
|
func (cli *Client) ContainerStats(ctx context.Context, containerID string, stream bool) (container.StatsResponse, error) {
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
query.Set("stream", "0")
|
query.Set("stream", "0")
|
||||||
if stream {
|
if stream {
|
||||||
|
@ -18,10 +18,10 @@ func (cli *Client) ContainerStats(ctx context.Context, containerID string, strea
|
||||||
|
|
||||||
resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil)
|
resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.ContainerStats{}, err
|
return container.StatsResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.ContainerStats{
|
return container.StatsResponse{
|
||||||
Body: resp.body,
|
Body: resp.body,
|
||||||
OSType: getDockerOS(resp.header.Get("Server")),
|
OSType: getDockerOS(resp.header.Get("Server")),
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -29,17 +29,17 @@ func (cli *Client) ContainerStats(ctx context.Context, containerID string, strea
|
||||||
|
|
||||||
// ContainerStatsOneShot gets a single stat entry from a container.
|
// ContainerStatsOneShot gets a single stat entry from a container.
|
||||||
// It differs from `ContainerStats` in that the API should not wait to prime the stats
|
// It differs from `ContainerStats` in that the API should not wait to prime the stats
|
||||||
func (cli *Client) ContainerStatsOneShot(ctx context.Context, containerID string) (types.ContainerStats, error) {
|
func (cli *Client) ContainerStatsOneShot(ctx context.Context, containerID string) (container.StatsResponse, error) {
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
query.Set("stream", "0")
|
query.Set("stream", "0")
|
||||||
query.Set("one-shot", "1")
|
query.Set("one-shot", "1")
|
||||||
|
|
||||||
resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil)
|
resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.ContainerStats{}, err
|
return container.StatsResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.ContainerStats{
|
return container.StatsResponse{
|
||||||
Body: resp.body,
|
Body: resp.body,
|
||||||
OSType: getDockerOS(resp.header.Get("Server")),
|
OSType: getDockerOS(resp.header.Get("Server")),
|
||||||
}, nil
|
}, nil
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"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"
|
||||||
timetypes "github.com/docker/docker/api/types/time"
|
timetypes "github.com/docker/docker/api/types/time"
|
||||||
|
@ -16,7 +15,7 @@ import (
|
||||||
// by cancelling the context. Once the stream has been completely read an io.EOF error will
|
// by cancelling the context. Once the stream has been completely read an io.EOF error will
|
||||||
// be sent over the error channel. If an error is sent all processing will be stopped. It's up
|
// be sent over the error channel. If an error is sent all processing will be stopped. It's up
|
||||||
// to the caller to reopen the stream in the event of an error by reinvoking this method.
|
// to the caller to reopen the stream in the event of an error by reinvoking this method.
|
||||||
func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error) {
|
func (cli *Client) Events(ctx context.Context, options events.ListOptions) (<-chan events.Message, <-chan error) {
|
||||||
messages := make(chan events.Message)
|
messages := make(chan events.Message)
|
||||||
errs := make(chan error, 1)
|
errs := make(chan error, 1)
|
||||||
|
|
||||||
|
@ -68,7 +67,7 @@ func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-c
|
||||||
return messages, errs
|
return messages, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildEventsQueryParams(cliVersion string, options types.EventsOptions) (url.Values, error) {
|
func buildEventsQueryParams(cliVersion string, options events.ListOptions) (url.Values, error) {
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
ref := time.Now()
|
ref := time.Now()
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,12 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/distribution/reference"
|
"github.com/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageImport creates a new image based on the source options.
|
// ImageImport creates a new image based on the source options.
|
||||||
// It returns the JSON content in the response body.
|
// It returns the JSON content in the response body.
|
||||||
func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
func (cli *Client) ImageImport(ctx context.Context, source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
|
||||||
if ref != "" {
|
if ref != "" {
|
||||||
// Check if the given image name can be resolved
|
// Check if the given image name can be resolved
|
||||||
if _, err := reference.ParseNormalizedNamed(ref); err != nil {
|
if _, err := reference.ParseNormalizedNamed(ref); err != nil {
|
||||||
|
|
|
@ -6,13 +6,13 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageLoad loads an image in the docker host from the client host.
|
// ImageLoad loads an image in the docker host from the client host.
|
||||||
// It's up to the caller to close the io.ReadCloser in the
|
// It's up to the caller to close the io.ReadCloser in the
|
||||||
// ImageLoadResponse returned by this function.
|
// ImageLoadResponse returned by this function.
|
||||||
func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) {
|
func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (image.LoadResponse, error) {
|
||||||
v := url.Values{}
|
v := url.Values{}
|
||||||
v.Set("quiet", "0")
|
v.Set("quiet", "0")
|
||||||
if quiet {
|
if quiet {
|
||||||
|
@ -22,9 +22,9 @@ func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (
|
||||||
"Content-Type": {"application/x-tar"},
|
"Content-Type": {"application/x-tar"},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.ImageLoadResponse{}, err
|
return image.LoadResponse{}, err
|
||||||
}
|
}
|
||||||
return types.ImageLoadResponse{
|
return image.LoadResponse{
|
||||||
Body: resp.body,
|
Body: resp.body,
|
||||||
JSON: resp.header.Get("Content-Type") == "application/json",
|
JSON: resp.header.Get("Content-Type") == "application/json",
|
||||||
}, nil
|
}, nil
|
||||||
|
|
|
@ -5,13 +5,13 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/docker/docker/api/types/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImagesPrune requests the daemon to delete unused data
|
// ImagesPrune requests the daemon to delete unused data
|
||||||
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (types.ImagesPruneReport, error) {
|
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (image.PruneReport, error) {
|
||||||
var report types.ImagesPruneReport
|
var report image.PruneReport
|
||||||
|
|
||||||
if err := cli.NewVersionError(ctx, "1.25", "image prune"); err != nil {
|
if err := cli.NewVersionError(ctx, "1.25", "image prune"); err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/errdefs"
|
"github.com/docker/docker/errdefs"
|
||||||
|
@ -15,7 +14,7 @@ import (
|
||||||
|
|
||||||
// ImageSearch makes the docker host search by a term in a remote registry.
|
// ImageSearch makes the docker host search by a term in a remote registry.
|
||||||
// The list of results is not sorted in any fashion.
|
// The list of results is not sorted in any fashion.
|
||||||
func (cli *Client) ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error) {
|
func (cli *Client) ImageSearch(ctx context.Context, term string, options registry.SearchOptions) ([]registry.SearchResult, error) {
|
||||||
var results []registry.SearchResult
|
var results []registry.SearchResult
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
query.Set("term", term)
|
query.Set("term", term)
|
||||||
|
|
|
@ -50,11 +50,11 @@ type ContainerAPIClient interface {
|
||||||
ContainerCommit(ctx context.Context, container string, options container.CommitOptions) (types.IDResponse, error)
|
ContainerCommit(ctx context.Context, container string, options container.CommitOptions) (types.IDResponse, error)
|
||||||
ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error)
|
ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error)
|
||||||
ContainerDiff(ctx context.Context, container string) ([]container.FilesystemChange, error)
|
ContainerDiff(ctx context.Context, container string) ([]container.FilesystemChange, error)
|
||||||
ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error)
|
ContainerExecAttach(ctx context.Context, execID string, options container.ExecAttachOptions) (types.HijackedResponse, error)
|
||||||
ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error)
|
ContainerExecCreate(ctx context.Context, container string, options container.ExecOptions) (types.IDResponse, error)
|
||||||
ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error)
|
ContainerExecInspect(ctx context.Context, execID string) (container.ExecInspect, error)
|
||||||
ContainerExecResize(ctx context.Context, execID string, options container.ResizeOptions) error
|
ContainerExecResize(ctx context.Context, execID string, options container.ResizeOptions) error
|
||||||
ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error
|
ContainerExecStart(ctx context.Context, execID string, options container.ExecStartOptions) error
|
||||||
ContainerExport(ctx context.Context, container string) (io.ReadCloser, error)
|
ContainerExport(ctx context.Context, container string) (io.ReadCloser, error)
|
||||||
ContainerInspect(ctx context.Context, container string) (types.ContainerJSON, error)
|
ContainerInspect(ctx context.Context, container string) (types.ContainerJSON, error)
|
||||||
ContainerInspectWithRaw(ctx context.Context, container string, getSize bool) (types.ContainerJSON, []byte, error)
|
ContainerInspectWithRaw(ctx context.Context, container string, getSize bool) (types.ContainerJSON, []byte, error)
|
||||||
|
@ -66,18 +66,18 @@ type ContainerAPIClient interface {
|
||||||
ContainerRename(ctx context.Context, container, newContainerName string) error
|
ContainerRename(ctx context.Context, container, newContainerName string) error
|
||||||
ContainerResize(ctx context.Context, container string, options container.ResizeOptions) error
|
ContainerResize(ctx context.Context, container string, options container.ResizeOptions) error
|
||||||
ContainerRestart(ctx context.Context, container string, options container.StopOptions) error
|
ContainerRestart(ctx context.Context, container string, options container.StopOptions) error
|
||||||
ContainerStatPath(ctx context.Context, container, path string) (types.ContainerPathStat, error)
|
ContainerStatPath(ctx context.Context, container, path string) (container.PathStat, error)
|
||||||
ContainerStats(ctx context.Context, container string, stream bool) (types.ContainerStats, error)
|
ContainerStats(ctx context.Context, container string, stream bool) (container.StatsResponse, error)
|
||||||
ContainerStatsOneShot(ctx context.Context, container string) (types.ContainerStats, error)
|
ContainerStatsOneShot(ctx context.Context, container string) (container.StatsResponse, error)
|
||||||
ContainerStart(ctx context.Context, container string, options container.StartOptions) error
|
ContainerStart(ctx context.Context, container string, options container.StartOptions) error
|
||||||
ContainerStop(ctx context.Context, container string, options container.StopOptions) error
|
ContainerStop(ctx context.Context, container string, options container.StopOptions) error
|
||||||
ContainerTop(ctx context.Context, container string, arguments []string) (container.ContainerTopOKBody, error)
|
ContainerTop(ctx context.Context, container string, arguments []string) (container.ContainerTopOKBody, error)
|
||||||
ContainerUnpause(ctx context.Context, container string) error
|
ContainerUnpause(ctx context.Context, container string) error
|
||||||
ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error)
|
ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error)
|
||||||
ContainerWait(ctx context.Context, container string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error)
|
ContainerWait(ctx context.Context, container string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error)
|
||||||
CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
|
CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, container.PathStat, error)
|
||||||
CopyToContainer(ctx context.Context, container, path string, content io.Reader, options types.CopyToContainerOptions) error
|
CopyToContainer(ctx context.Context, container, path string, content io.Reader, options container.CopyToContainerOptions) error
|
||||||
ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error)
|
ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DistributionAPIClient defines API client methods for the registry
|
// DistributionAPIClient defines API client methods for the registry
|
||||||
|
@ -92,17 +92,17 @@ type ImageAPIClient interface {
|
||||||
BuildCancel(ctx context.Context, id string) error
|
BuildCancel(ctx context.Context, id string) error
|
||||||
ImageCreate(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error)
|
ImageCreate(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error)
|
||||||
ImageHistory(ctx context.Context, image string) ([]image.HistoryResponseItem, error)
|
ImageHistory(ctx context.Context, image string) ([]image.HistoryResponseItem, error)
|
||||||
ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
|
ImageImport(ctx context.Context, source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
|
||||||
ImageInspectWithRaw(ctx context.Context, image string) (types.ImageInspect, []byte, error)
|
ImageInspectWithRaw(ctx context.Context, image string) (types.ImageInspect, []byte, error)
|
||||||
ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error)
|
ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error)
|
||||||
ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error)
|
ImageLoad(ctx context.Context, input io.Reader, quiet bool) (image.LoadResponse, error)
|
||||||
ImagePull(ctx context.Context, ref string, options image.PullOptions) (io.ReadCloser, error)
|
ImagePull(ctx context.Context, ref string, options image.PullOptions) (io.ReadCloser, error)
|
||||||
ImagePush(ctx context.Context, ref string, options image.PushOptions) (io.ReadCloser, error)
|
ImagePush(ctx context.Context, ref string, options image.PushOptions) (io.ReadCloser, error)
|
||||||
ImageRemove(ctx context.Context, image string, options image.RemoveOptions) ([]image.DeleteResponse, error)
|
ImageRemove(ctx context.Context, image string, options image.RemoveOptions) ([]image.DeleteResponse, error)
|
||||||
ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error)
|
ImageSearch(ctx context.Context, term string, options registry.SearchOptions) ([]registry.SearchResult, error)
|
||||||
ImageSave(ctx context.Context, images []string) (io.ReadCloser, error)
|
ImageSave(ctx context.Context, images []string) (io.ReadCloser, error)
|
||||||
ImageTag(ctx context.Context, image, ref string) error
|
ImageTag(ctx context.Context, image, ref string) error
|
||||||
ImagesPrune(ctx context.Context, pruneFilter filters.Args) (types.ImagesPruneReport, error)
|
ImagesPrune(ctx context.Context, pruneFilter filters.Args) (image.PruneReport, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkAPIClient defines API client methods for the networks
|
// NetworkAPIClient defines API client methods for the networks
|
||||||
|
@ -165,7 +165,7 @@ type SwarmAPIClient interface {
|
||||||
|
|
||||||
// SystemAPIClient defines API client methods for the system
|
// SystemAPIClient defines API client methods for the system
|
||||||
type SystemAPIClient interface {
|
type SystemAPIClient interface {
|
||||||
Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error)
|
Events(ctx context.Context, options events.ListOptions) (<-chan events.Message, <-chan error)
|
||||||
Info(ctx context.Context) (system.Info, error)
|
Info(ctx context.Context) (system.Info, error)
|
||||||
RegistryLogin(ctx context.Context, auth registry.AuthConfig) (registry.AuthenticateOKBody, error)
|
RegistryLogin(ctx context.Context, auth registry.AuthConfig) (registry.AuthenticateOKBody, error)
|
||||||
DiskUsage(ctx context.Context, options types.DiskUsageOptions) (types.DiskUsage, error)
|
DiskUsage(ctx context.Context, options types.DiskUsageOptions) (types.DiskUsage, error)
|
||||||
|
@ -179,7 +179,7 @@ type VolumeAPIClient interface {
|
||||||
VolumeInspectWithRaw(ctx context.Context, volumeID string) (volume.Volume, []byte, error)
|
VolumeInspectWithRaw(ctx context.Context, volumeID string) (volume.Volume, []byte, error)
|
||||||
VolumeList(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error)
|
VolumeList(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error)
|
||||||
VolumeRemove(ctx context.Context, volumeID string, force bool) error
|
VolumeRemove(ctx context.Context, volumeID string, force bool) error
|
||||||
VolumesPrune(ctx context.Context, pruneFilter filters.Args) (types.VolumesPruneReport, error)
|
VolumesPrune(ctx context.Context, pruneFilter filters.Args) (volume.PruneReport, error)
|
||||||
VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error
|
VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,13 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/docker/docker/api/types/volume"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VolumesPrune requests the daemon to delete unused data
|
// VolumesPrune requests the daemon to delete unused data
|
||||||
func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (types.VolumesPruneReport, error) {
|
func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (volume.PruneReport, error) {
|
||||||
var report types.VolumesPruneReport
|
var report volume.PruneReport
|
||||||
|
|
||||||
if err := cli.NewVersionError(ctx, "1.25", "volume prune"); err != nil {
|
if err := cli.NewVersionError(ctx, "1.25", "volume prune"); err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
|
|
|
@ -56,7 +56,7 @@ 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 v26.1.1-0.20240607121412-59996a493cfc+incompatible
|
# github.com/docker/docker v26.1.1-0.20240610145149-a736d0701c41+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
|
||||||
|
|
Loading…
Reference in New Issue