vendor: github.com/moby/moby/api, moby/moby/client master
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
@ -74,7 +74,7 @@ func RunAttach(ctx context.Context, dockerCLI command.Cli, containerID string, o
|
||||
|
||||
// request channel to wait for client
|
||||
waitCtx := context.WithoutCancel(ctx)
|
||||
resultC, errC := apiClient.ContainerWait(waitCtx, containerID, "")
|
||||
waitRes := apiClient.ContainerWait(waitCtx, containerID, client.ContainerWaitOptions{})
|
||||
|
||||
c, err := inspectContainerAndCheckState(ctx, apiClient, containerID)
|
||||
if err != nil {
|
||||
@ -152,19 +152,19 @@ func RunAttach(ctx context.Context, dockerCLI command.Cli, containerID string, o
|
||||
return err
|
||||
}
|
||||
|
||||
return getExitStatus(errC, resultC)
|
||||
return getExitStatus(waitRes)
|
||||
}
|
||||
|
||||
func getExitStatus(errC <-chan error, resultC <-chan container.WaitResponse) error {
|
||||
func getExitStatus(waitRes client.ContainerWaitResult) error {
|
||||
select {
|
||||
case result := <-resultC:
|
||||
case result := <-waitRes.Result:
|
||||
if result.Error != nil {
|
||||
return errors.New(result.Error.Message)
|
||||
}
|
||||
if result.StatusCode != 0 {
|
||||
return cli.StatusError{StatusCode: int(result.StatusCode)}
|
||||
}
|
||||
case err := <-errC:
|
||||
case err := <-waitRes.Error:
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -125,7 +125,10 @@ func TestGetExitStatus(t *testing.T) {
|
||||
resultC <- *testcase.result
|
||||
}
|
||||
|
||||
err := getExitStatus(errC, resultC)
|
||||
err := getExitStatus(client.ContainerWaitResult{
|
||||
Result: resultC,
|
||||
Error: errC,
|
||||
})
|
||||
|
||||
if testcase.expectedError == nil {
|
||||
assert.NilError(t, err)
|
||||
|
||||
@ -3,12 +3,35 @@ package container
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/moby/moby/api/types/container"
|
||||
"github.com/moby/moby/api/types/system"
|
||||
"github.com/moby/moby/client"
|
||||
)
|
||||
|
||||
func mockContainerExportResult(content string) client.ContainerExportResult {
|
||||
out := client.ContainerExportResult{}
|
||||
|
||||
// Set unexported field "rc"
|
||||
v := reflect.ValueOf(&out).Elem()
|
||||
f := v.FieldByName("rc")
|
||||
r := io.NopCloser(strings.NewReader(content))
|
||||
reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Elem().Set(reflect.ValueOf(r))
|
||||
return out
|
||||
}
|
||||
|
||||
func mockContainerLogsResult(content string) client.ContainerLogsResult {
|
||||
out := client.ContainerLogsResult{}
|
||||
|
||||
// Set unexported field "rc"
|
||||
v := reflect.ValueOf(&out).Elem()
|
||||
f := v.FieldByName("rc")
|
||||
r := io.NopCloser(strings.NewReader(content))
|
||||
reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Elem().Set(reflect.ValueOf(r))
|
||||
return out
|
||||
}
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
inspectFunc func(string) (client.ContainerInspectResult, error)
|
||||
@ -17,13 +40,13 @@ type fakeClient struct {
|
||||
createContainerFunc func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error)
|
||||
containerStartFunc func(containerID string, options client.ContainerStartOptions) (client.ContainerStartResult, error)
|
||||
imageCreateFunc func(ctx context.Context, parentReference string, options client.ImageCreateOptions) (client.ImageCreateResult, error)
|
||||
infoFunc func() (system.Info, error)
|
||||
containerStatPathFunc func(containerID, path string) (container.PathStat, error)
|
||||
containerCopyFromFunc func(containerID, srcPath string) (io.ReadCloser, container.PathStat, error)
|
||||
logFunc func(string, client.ContainerLogsOptions) (io.ReadCloser, error)
|
||||
waitFunc func(string) (<-chan container.WaitResponse, <-chan error)
|
||||
containerListFunc func(client.ContainerListOptions) ([]container.Summary, error)
|
||||
containerExportFunc func(string) (io.ReadCloser, error)
|
||||
infoFunc func() (client.SystemInfoResult, error)
|
||||
containerStatPathFunc func(containerID, path string) (client.ContainerStatPathResult, error)
|
||||
containerCopyFromFunc func(containerID, srcPath string) (client.CopyFromContainerResult, error)
|
||||
logFunc func(string, client.ContainerLogsOptions) (client.ContainerLogsResult, error)
|
||||
waitFunc func(string) client.ContainerWaitResult
|
||||
containerListFunc func(client.ContainerListOptions) (client.ContainerListResult, error)
|
||||
containerExportFunc func(string) (client.ContainerExportResult, error)
|
||||
containerExecResizeFunc func(id string, options client.ExecResizeOptions) (client.ExecResizeResult, error)
|
||||
containerRemoveFunc func(ctx context.Context, containerID string, options client.ContainerRemoveOptions) (client.ContainerRemoveResult, error)
|
||||
containerRestartFunc func(ctx context.Context, containerID string, options client.ContainerRestartOptions) (client.ContainerRestartResult, error)
|
||||
@ -38,14 +61,14 @@ type fakeClient struct {
|
||||
Version string
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerList(_ context.Context, options client.ContainerListOptions) ([]container.Summary, error) {
|
||||
func (f *fakeClient) ContainerList(_ context.Context, options client.ContainerListOptions) (client.ContainerListResult, error) {
|
||||
if f.containerListFunc != nil {
|
||||
return f.containerListFunc(options)
|
||||
}
|
||||
return []container.Summary{}, nil
|
||||
return client.ContainerListResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerInspect(_ context.Context, containerID string, options client.ContainerInspectOptions) (client.ContainerInspectResult, error) {
|
||||
func (f *fakeClient) ContainerInspect(_ context.Context, containerID string, _ client.ContainerInspectOptions) (client.ContainerInspectResult, error) {
|
||||
if f.inspectFunc != nil {
|
||||
return f.inspectFunc(containerID)
|
||||
}
|
||||
@ -91,43 +114,43 @@ func (f *fakeClient) ImageCreate(ctx context.Context, parentReference string, op
|
||||
return client.ImageCreateResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) Info(_ context.Context) (system.Info, error) {
|
||||
func (f *fakeClient) Info(context.Context, client.InfoOptions) (client.SystemInfoResult, error) {
|
||||
if f.infoFunc != nil {
|
||||
return f.infoFunc()
|
||||
}
|
||||
return system.Info{}, nil
|
||||
return client.SystemInfoResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerStatPath(_ context.Context, containerID, path string) (container.PathStat, error) {
|
||||
func (f *fakeClient) ContainerStatPath(_ context.Context, containerID string, options client.ContainerStatPathOptions) (client.ContainerStatPathResult, error) {
|
||||
if f.containerStatPathFunc != nil {
|
||||
return f.containerStatPathFunc(containerID, path)
|
||||
return f.containerStatPathFunc(containerID, options.Path)
|
||||
}
|
||||
return container.PathStat{}, nil
|
||||
return client.ContainerStatPathResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) CopyFromContainer(_ context.Context, containerID, srcPath string) (io.ReadCloser, container.PathStat, error) {
|
||||
func (f *fakeClient) CopyFromContainer(_ context.Context, containerID string, options client.CopyFromContainerOptions) (client.CopyFromContainerResult, error) {
|
||||
if f.containerCopyFromFunc != nil {
|
||||
return f.containerCopyFromFunc(containerID, srcPath)
|
||||
return f.containerCopyFromFunc(containerID, options.SourcePath)
|
||||
}
|
||||
return nil, container.PathStat{}, nil
|
||||
return client.CopyFromContainerResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerLogs(_ context.Context, containerID string, options client.ContainerLogsOptions) (io.ReadCloser, error) {
|
||||
func (f *fakeClient) ContainerLogs(_ context.Context, containerID string, options client.ContainerLogsOptions) (client.ContainerLogsResult, error) {
|
||||
if f.logFunc != nil {
|
||||
return f.logFunc(containerID, options)
|
||||
}
|
||||
return nil, nil
|
||||
return client.ContainerLogsResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ClientVersion() string {
|
||||
return f.Version
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerWait(_ context.Context, containerID string, _ container.WaitCondition) (<-chan container.WaitResponse, <-chan error) {
|
||||
func (f *fakeClient) ContainerWait(_ context.Context, containerID string, _ client.ContainerWaitOptions) client.ContainerWaitResult {
|
||||
if f.waitFunc != nil {
|
||||
return f.waitFunc(containerID)
|
||||
}
|
||||
return nil, nil
|
||||
return client.ContainerWaitResult{}
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerStart(_ context.Context, containerID string, options client.ContainerStartOptions) (client.ContainerStartResult, error) {
|
||||
@ -137,11 +160,11 @@ func (f *fakeClient) ContainerStart(_ context.Context, containerID string, optio
|
||||
return client.ContainerStartResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerExport(_ context.Context, containerID string) (io.ReadCloser, error) {
|
||||
func (f *fakeClient) ContainerExport(_ context.Context, containerID string, _ client.ContainerExportOptions) (client.ContainerExportResult, error) {
|
||||
if f.containerExportFunc != nil {
|
||||
return f.containerExportFunc(containerID)
|
||||
}
|
||||
return nil, nil
|
||||
return client.ContainerExportResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ExecResize(_ context.Context, id string, options client.ExecResizeOptions) (client.ExecResizeResult, error) {
|
||||
@ -194,12 +217,12 @@ func (f *fakeClient) ContainerDiff(ctx context.Context, containerID string, _ cl
|
||||
return client.ContainerDiffResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerRename(ctx context.Context, oldName, newName string) error {
|
||||
func (f *fakeClient) ContainerRename(ctx context.Context, oldName string, options client.ContainerRenameOptions) (client.ContainerRenameResult, error) {
|
||||
if f.containerRenameFunc != nil {
|
||||
return f.containerRenameFunc(ctx, oldName, newName)
|
||||
return client.ContainerRenameResult{}, f.containerRenameFunc(ctx, oldName, options.NewName)
|
||||
}
|
||||
|
||||
return nil
|
||||
return client.ContainerRenameResult{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerCommit(ctx context.Context, containerID string, options client.ContainerCommitOptions) (client.ContainerCommitResult, error) {
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/moby/moby/api/types/container"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/moby/sys/capability"
|
||||
"github.com/moby/sys/signal"
|
||||
"github.com/spf13/cobra"
|
||||
@ -186,11 +187,11 @@ func completeLink(dockerCLI completion.APIClientProvider) cobra.CompletionFunc {
|
||||
// of the build-in log drivers.
|
||||
func completeLogDriver(dockerCLI completion.APIClientProvider) cobra.CompletionFunc {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
info, err := dockerCLI.Client().Info(cmd.Context())
|
||||
res, err := dockerCLI.Client().Info(cmd.Context(), client.InfoOptions{})
|
||||
if err != nil {
|
||||
return builtInLogDrivers(), cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
drivers := info.Plugins.Log
|
||||
drivers := res.Info.Plugins.Log
|
||||
return drivers, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
}
|
||||
@ -279,12 +280,12 @@ func completeUlimit(_ *cobra.Command, _ []string, _ string) ([]string, cobra.She
|
||||
// completeVolumeDriver contacts the API to get the built-in and installed volume drivers.
|
||||
func completeVolumeDriver(dockerCLI completion.APIClientProvider) cobra.CompletionFunc {
|
||||
return func(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
|
||||
info, err := dockerCLI.Client().Info(cmd.Context())
|
||||
res, err := dockerCLI.Client().Info(cmd.Context(), client.InfoOptions{})
|
||||
if err != nil {
|
||||
// fallback: the built-in drivers
|
||||
return []string{"local"}, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
drivers := info.Plugins.Volume
|
||||
drivers := res.Info.Plugins.Volume
|
||||
return drivers, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ func TestCompleteLinuxCapabilityNames(t *testing.T) {
|
||||
|
||||
func TestCompletePid(t *testing.T) {
|
||||
tests := []struct {
|
||||
containerListFunc func(client.ContainerListOptions) ([]container.Summary, error)
|
||||
containerListFunc func(client.ContainerListOptions) (client.ContainerListResult, error)
|
||||
toComplete string
|
||||
expectedCompletions []string
|
||||
expectedDirective cobra.ShellCompDirective
|
||||
@ -43,10 +43,12 @@ func TestCompletePid(t *testing.T) {
|
||||
expectedDirective: cobra.ShellCompDirectiveNoSpace,
|
||||
},
|
||||
{
|
||||
containerListFunc: func(client.ContainerListOptions) ([]container.Summary, error) {
|
||||
return []container.Summary{
|
||||
*builders.Container("c1"),
|
||||
*builders.Container("c2"),
|
||||
containerListFunc: func(client.ContainerListOptions) (client.ContainerListResult, error) {
|
||||
return client.ContainerListResult{
|
||||
Items: []container.Summary{
|
||||
*builders.Container("c1"),
|
||||
*builders.Container("c2"),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
toComplete: "container:",
|
||||
|
||||
@ -230,11 +230,13 @@ func copyFromContainer(ctx context.Context, dockerCLI command.Cli, copyConfig cp
|
||||
// if client requests to follow symbol link, then must decide target file to be copied
|
||||
var rebaseName string
|
||||
if copyConfig.followLink {
|
||||
srcStat, err := apiClient.ContainerStatPath(ctx, copyConfig.container, srcPath)
|
||||
src, err := apiClient.ContainerStatPath(ctx, copyConfig.container, client.ContainerStatPathOptions{
|
||||
Path: srcPath,
|
||||
})
|
||||
|
||||
// If the destination is a symbolic link, we should follow it.
|
||||
if err == nil && srcStat.Mode&os.ModeSymlink != 0 {
|
||||
linkTarget := srcStat.LinkTarget
|
||||
if err == nil && src.Stat.Mode&os.ModeSymlink != 0 {
|
||||
linkTarget := src.Stat.LinkTarget
|
||||
if !isAbs(linkTarget) {
|
||||
// Join with the parent directory.
|
||||
srcParent, _ := archive.SplitPathDirEntry(srcPath)
|
||||
@ -249,11 +251,14 @@ func copyFromContainer(ctx context.Context, dockerCLI command.Cli, copyConfig cp
|
||||
ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
|
||||
defer cancel()
|
||||
|
||||
content, stat, err := apiClient.CopyFromContainer(ctx, copyConfig.container, srcPath)
|
||||
cpRes, err := apiClient.CopyFromContainer(ctx, copyConfig.container, client.CopyFromContainerOptions{
|
||||
SourcePath: srcPath,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer content.Close()
|
||||
content := cpRes.Content
|
||||
defer func() { _ = content.Close() }()
|
||||
|
||||
if dstPath == "-" {
|
||||
_, err = io.Copy(dockerCLI.Out(), content)
|
||||
@ -263,7 +268,7 @@ func copyFromContainer(ctx context.Context, dockerCLI command.Cli, copyConfig cp
|
||||
srcInfo := archive.CopyInfo{
|
||||
Path: srcPath,
|
||||
Exists: true,
|
||||
IsDir: stat.Mode.IsDir(),
|
||||
IsDir: cpRes.Stat.Mode.IsDir(),
|
||||
RebaseName: rebaseName,
|
||||
}
|
||||
|
||||
@ -315,10 +320,10 @@ func copyToContainer(ctx context.Context, dockerCLI command.Cli, copyConfig cpCo
|
||||
apiClient := dockerCLI.Client()
|
||||
// Prepare destination copy info by stat-ing the container path.
|
||||
dstInfo := archive.CopyInfo{Path: dstPath}
|
||||
if dstStat, err := apiClient.ContainerStatPath(ctx, copyConfig.container, dstPath); err == nil {
|
||||
if dst, err := apiClient.ContainerStatPath(ctx, copyConfig.container, client.ContainerStatPathOptions{Path: dstPath}); err == nil {
|
||||
// If the destination is a symbolic link, we should evaluate it.
|
||||
if dstStat.Mode&os.ModeSymlink != 0 {
|
||||
linkTarget := dstStat.LinkTarget
|
||||
if dst.Stat.Mode&os.ModeSymlink != 0 {
|
||||
linkTarget := dst.Stat.LinkTarget
|
||||
if !isAbs(linkTarget) {
|
||||
// Join with the parent directory.
|
||||
dstParent, _ := archive.SplitPathDirEntry(dstPath)
|
||||
@ -326,14 +331,14 @@ func copyToContainer(ctx context.Context, dockerCLI command.Cli, copyConfig cpCo
|
||||
}
|
||||
|
||||
dstInfo.Path = linkTarget
|
||||
dstStat, err = apiClient.ContainerStatPath(ctx, copyConfig.container, linkTarget)
|
||||
dst, err = apiClient.ContainerStatPath(ctx, copyConfig.container, client.ContainerStatPathOptions{Path: linkTarget})
|
||||
}
|
||||
// Validate the destination path
|
||||
if err == nil {
|
||||
if err := command.ValidateOutputPathFileMode(dstStat.Mode); err != nil {
|
||||
if err := command.ValidateOutputPathFileMode(dst.Stat.Mode); err != nil {
|
||||
return fmt.Errorf(`destination "%s:%s" must be a directory or a regular file: %w`, copyConfig.container, dstPath, err)
|
||||
}
|
||||
dstInfo.Exists, dstInfo.IsDir = true, dstStat.Mode.IsDir()
|
||||
dstInfo.Exists, dstInfo.IsDir = true, dst.Stat.Mode.IsDir()
|
||||
}
|
||||
|
||||
// Ignore any error and assume that the parent directory of the destination
|
||||
@ -399,22 +404,26 @@ func copyToContainer(ctx context.Context, dockerCLI command.Cli, copyConfig cpCo
|
||||
}
|
||||
|
||||
options := client.CopyToContainerOptions{
|
||||
CopyUIDGID: copyConfig.copyUIDGID,
|
||||
DestinationPath: resolvedDstPath,
|
||||
Content: content,
|
||||
CopyUIDGID: copyConfig.copyUIDGID,
|
||||
}
|
||||
|
||||
if copyConfig.quiet {
|
||||
return apiClient.CopyToContainer(ctx, copyConfig.container, resolvedDstPath, content, options)
|
||||
_, err := apiClient.CopyToContainer(ctx, copyConfig.container, options)
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
|
||||
restore, done := copyProgress(ctx, dockerCLI.Err(), copyToContainerHeader, &copiedSize)
|
||||
res := apiClient.CopyToContainer(ctx, copyConfig.container, resolvedDstPath, content, options)
|
||||
// TODO(thaJeztah): error-handling looks odd here; should it be handled differently?
|
||||
_, err := apiClient.CopyToContainer(ctx, copyConfig.container, options)
|
||||
cancel()
|
||||
<-done
|
||||
restore()
|
||||
_, _ = fmt.Fprintln(dockerCLI.Err(), "Successfully copied", progressHumanSize(copiedSize), "to", copyConfig.container+":"+dstInfo.Path)
|
||||
|
||||
return res
|
||||
return err
|
||||
}
|
||||
|
||||
// We use `:` as a delimiter between CONTAINER and PATH, but `:` could also be
|
||||
|
||||
@ -11,7 +11,7 @@ import (
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/go-archive"
|
||||
"github.com/moby/go-archive/compression"
|
||||
"github.com/moby/moby/api/types/container"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/fs"
|
||||
@ -52,9 +52,11 @@ func TestRunCopyFromContainerToStdout(t *testing.T) {
|
||||
tarContent := "the tar content"
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerCopyFromFunc: func(ctr, srcPath string) (io.ReadCloser, container.PathStat, error) {
|
||||
containerCopyFromFunc: func(ctr, srcPath string) (client.CopyFromContainerResult, error) {
|
||||
assert.Check(t, is.Equal("container", ctr))
|
||||
return io.NopCloser(strings.NewReader(tarContent)), container.PathStat{}, nil
|
||||
return client.CopyFromContainerResult{
|
||||
Content: io.NopCloser(strings.NewReader(tarContent)),
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
err := runCopy(context.TODO(), cli, copyOptions{
|
||||
@ -73,10 +75,12 @@ func TestRunCopyFromContainerToFilesystem(t *testing.T) {
|
||||
destDir := fs.NewDir(t, "cp-test")
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerCopyFromFunc: func(ctr, srcPath string) (io.ReadCloser, container.PathStat, error) {
|
||||
containerCopyFromFunc: func(ctr, srcPath string) (client.CopyFromContainerResult, error) {
|
||||
assert.Check(t, is.Equal("container", ctr))
|
||||
readCloser, err := archive.Tar(srcDir.Path(), compression.None)
|
||||
return readCloser, container.PathStat{}, err
|
||||
return client.CopyFromContainerResult{
|
||||
Content: readCloser,
|
||||
}, err
|
||||
},
|
||||
})
|
||||
err := runCopy(context.TODO(), cli, copyOptions{
|
||||
@ -99,10 +103,12 @@ func TestRunCopyFromContainerToFilesystemMissingDestinationDirectory(t *testing.
|
||||
defer destDir.Remove()
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerCopyFromFunc: func(ctr, srcPath string) (io.ReadCloser, container.PathStat, error) {
|
||||
containerCopyFromFunc: func(ctr, srcPath string) (client.CopyFromContainerResult, error) {
|
||||
assert.Check(t, is.Equal("container", ctr))
|
||||
readCloser, err := archive.TarWithOptions(destDir.Path(), &archive.TarOptions{})
|
||||
return readCloser, container.PathStat{}, err
|
||||
return client.CopyFromContainerResult{
|
||||
Content: readCloser,
|
||||
}, err
|
||||
},
|
||||
})
|
||||
err := runCopy(context.TODO(), cli, copyOptions{
|
||||
|
||||
@ -410,7 +410,7 @@ func validatePullOpt(val string) error {
|
||||
//
|
||||
// The path should be an absolute path in the container, commonly
|
||||
// /root/.docker/config.json.
|
||||
func copyDockerConfigIntoContainer(ctx context.Context, dockerAPI client.APIClient, containerID string, configPath string, config *configfile.ConfigFile) error {
|
||||
func copyDockerConfigIntoContainer(ctx context.Context, apiClient client.APIClient, containerID string, configPath string, config *configfile.ConfigFile) error {
|
||||
var configBuf bytes.Buffer
|
||||
if err := config.SaveToWriter(&configBuf); err != nil {
|
||||
return fmt.Errorf("saving creds: %w", err)
|
||||
@ -433,8 +433,11 @@ func copyDockerConfigIntoContainer(ctx context.Context, dockerAPI client.APIClie
|
||||
return fmt.Errorf("closing tar for config copy failed: %w", err)
|
||||
}
|
||||
|
||||
if err := dockerAPI.CopyToContainer(ctx, containerID, "/",
|
||||
&tarBuf, client.CopyToContainerOptions{}); err != nil {
|
||||
_, err := apiClient.CopyToContainer(ctx, containerID, client.CopyToContainerOptions{
|
||||
DestinationPath: "/",
|
||||
Content: &tarBuf,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("copying config.json into container failed: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@ -128,8 +128,10 @@ func TestCreateContainerImagePullPolicy(t *testing.T) {
|
||||
defer func() { pullCounter++ }()
|
||||
return client.ImageCreateResult{Body: io.NopCloser(strings.NewReader(""))}, nil
|
||||
},
|
||||
infoFunc: func() (system.Info, error) {
|
||||
return system.Info{IndexServerAddress: "https://indexserver.example.com"}, nil
|
||||
infoFunc: func() (client.SystemInfoResult, error) {
|
||||
return client.SystemInfoResult{
|
||||
Info: system.Info{IndexServerAddress: "https://indexserver.example.com"},
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
fakeCLI := test.NewFakeCli(apiClient)
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/moby/sys/atomicwriter"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -60,7 +61,7 @@ func runExport(ctx context.Context, dockerCLI command.Cli, opts exportOptions) e
|
||||
output = writer
|
||||
}
|
||||
|
||||
responseBody, err := dockerCLI.Client().ContainerExport(ctx, opts.container)
|
||||
responseBody, err := dockerCLI.Client().ContainerExport(ctx, opts.container, client.ContainerExportOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -2,10 +2,10 @@ package container
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/moby/moby/client"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/fs"
|
||||
)
|
||||
@ -15,8 +15,9 @@ func TestContainerExportOutputToFile(t *testing.T) {
|
||||
defer dir.Remove()
|
||||
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerExportFunc: func(container string) (io.ReadCloser, error) {
|
||||
return io.NopCloser(strings.NewReader("bar")), nil
|
||||
containerExportFunc: func(container string) (client.ContainerExportResult, error) {
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
return mockContainerExportResult("bar"), nil
|
||||
},
|
||||
})
|
||||
cmd := newExportCommand(cli)
|
||||
@ -33,8 +34,9 @@ func TestContainerExportOutputToFile(t *testing.T) {
|
||||
|
||||
func TestContainerExportOutputToIrregularFile(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerExportFunc: func(container string) (io.ReadCloser, error) {
|
||||
return io.NopCloser(strings.NewReader("foo")), nil
|
||||
containerExportFunc: func(container string) (client.ContainerExportResult, error) {
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
return mockContainerExportResult("foo"), nil
|
||||
},
|
||||
})
|
||||
cmd := newExportCommand(cli)
|
||||
|
||||
@ -68,8 +68,8 @@ func newListCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
return &cmd
|
||||
}
|
||||
|
||||
func buildContainerListOptions(options *psOptions) (*client.ContainerListOptions, error) {
|
||||
listOptions := &client.ContainerListOptions{
|
||||
func buildContainerListOptions(options *psOptions) (client.ContainerListOptions, error) {
|
||||
listOptions := client.ContainerListOptions{
|
||||
All: options.all,
|
||||
Limit: options.last,
|
||||
Size: options.size,
|
||||
@ -84,7 +84,7 @@ func buildContainerListOptions(options *psOptions) (*client.ContainerListOptions
|
||||
if len(options.format) > 0 {
|
||||
tmpl, err := templates.Parse(options.format)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse template: %w", err)
|
||||
return client.ContainerListOptions{}, fmt.Errorf("failed to parse template: %w", err)
|
||||
}
|
||||
|
||||
optionsProcessor := formatter.NewContainerContext()
|
||||
@ -92,7 +92,7 @@ func buildContainerListOptions(options *psOptions) (*client.ContainerListOptions
|
||||
// This shouldn't error out but swallowing the error makes it harder
|
||||
// to track down if preProcessor issues come up.
|
||||
if err := tmpl.Execute(io.Discard, optionsProcessor); err != nil {
|
||||
return nil, fmt.Errorf("failed to execute template: %w", err)
|
||||
return client.ContainerListOptions{}, fmt.Errorf("failed to execute template: %w", err)
|
||||
}
|
||||
|
||||
// if `size` was not explicitly set to false (with `--size=false`)
|
||||
@ -127,7 +127,7 @@ func runPs(ctx context.Context, dockerCLI command.Cli, options *psOptions) error
|
||||
return err
|
||||
}
|
||||
|
||||
containers, err := dockerCLI.Client().ContainerList(ctx, *listOptions)
|
||||
res, err := dockerCLI.Client().ContainerList(ctx, listOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -137,5 +137,5 @@ func runPs(ctx context.Context, dockerCLI command.Cli, options *psOptions) error
|
||||
Format: formatter.NewContainerFormat(options.format, options.quiet, listOptions.Size),
|
||||
Trunc: !options.noTrunc,
|
||||
}
|
||||
return formatter.ContainerWrite(containerCtx, containers)
|
||||
return formatter.ContainerWrite(containerCtx, res.Items)
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ func TestContainerListBuildContainerListOptions(t *testing.T) {
|
||||
func TestContainerListErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
flags map[string]string
|
||||
containerListFunc func(client.ContainerListOptions) ([]container.Summary, error)
|
||||
containerListFunc func(client.ContainerListOptions) (client.ContainerListResult, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
@ -125,8 +125,8 @@ func TestContainerListErrors(t *testing.T) {
|
||||
expectedError: `wrong number of args for join`,
|
||||
},
|
||||
{
|
||||
containerListFunc: func(_ client.ContainerListOptions) ([]container.Summary, error) {
|
||||
return nil, errors.New("error listing containers")
|
||||
containerListFunc: func(_ client.ContainerListOptions) (client.ContainerListResult, error) {
|
||||
return client.ContainerListResult{}, errors.New("error listing containers")
|
||||
},
|
||||
expectedError: "error listing containers",
|
||||
},
|
||||
@ -149,13 +149,15 @@ func TestContainerListErrors(t *testing.T) {
|
||||
|
||||
func TestContainerListWithoutFormat(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerListFunc: func(_ client.ContainerListOptions) ([]container.Summary, error) {
|
||||
return []container.Summary{
|
||||
*builders.Container("c1"),
|
||||
*builders.Container("c2", builders.WithName("foo")),
|
||||
*builders.Container("c3", builders.WithPort(80, 80, builders.TCP), builders.WithPort(81, 81, builders.TCP), builders.WithPort(82, 82, builders.TCP)),
|
||||
*builders.Container("c4", builders.WithPort(81, 81, builders.UDP)),
|
||||
*builders.Container("c5", builders.WithPort(82, 82, builders.IP("8.8.8.8"), builders.TCP)),
|
||||
containerListFunc: func(_ client.ContainerListOptions) (client.ContainerListResult, error) {
|
||||
return client.ContainerListResult{
|
||||
Items: []container.Summary{
|
||||
*builders.Container("c1"),
|
||||
*builders.Container("c2", builders.WithName("foo")),
|
||||
*builders.Container("c3", builders.WithPort(80, 80, builders.TCP), builders.WithPort(81, 81, builders.TCP), builders.WithPort(82, 82, builders.TCP)),
|
||||
*builders.Container("c4", builders.WithPort(81, 81, builders.UDP)),
|
||||
*builders.Container("c5", builders.WithPort(82, 82, builders.IP("8.8.8.8"), builders.TCP)),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -169,10 +171,12 @@ func TestContainerListWithoutFormat(t *testing.T) {
|
||||
|
||||
func TestContainerListNoTrunc(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerListFunc: func(_ client.ContainerListOptions) ([]container.Summary, error) {
|
||||
return []container.Summary{
|
||||
*builders.Container("c1"),
|
||||
*builders.Container("c2", builders.WithName("foo/bar")),
|
||||
containerListFunc: func(_ client.ContainerListOptions) (client.ContainerListResult, error) {
|
||||
return client.ContainerListResult{
|
||||
Items: []container.Summary{
|
||||
*builders.Container("c1"),
|
||||
*builders.Container("c2", builders.WithName("foo/bar")),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -188,10 +192,12 @@ func TestContainerListNoTrunc(t *testing.T) {
|
||||
// Test for GitHub issue docker/docker#21772
|
||||
func TestContainerListNamesMultipleTime(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerListFunc: func(_ client.ContainerListOptions) ([]container.Summary, error) {
|
||||
return []container.Summary{
|
||||
*builders.Container("c1"),
|
||||
*builders.Container("c2", builders.WithName("foo/bar")),
|
||||
containerListFunc: func(_ client.ContainerListOptions) (client.ContainerListResult, error) {
|
||||
return client.ContainerListResult{
|
||||
Items: []container.Summary{
|
||||
*builders.Container("c1"),
|
||||
*builders.Container("c2", builders.WithName("foo/bar")),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -207,10 +213,12 @@ func TestContainerListNamesMultipleTime(t *testing.T) {
|
||||
// Test for GitHub issue docker/docker#30291
|
||||
func TestContainerListFormatTemplateWithArg(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerListFunc: func(_ client.ContainerListOptions) ([]container.Summary, error) {
|
||||
return []container.Summary{
|
||||
*builders.Container("c1", builders.WithLabel("some.label", "value")),
|
||||
*builders.Container("c2", builders.WithName("foo/bar"), builders.WithLabel("foo", "bar")),
|
||||
containerListFunc: func(_ client.ContainerListOptions) (client.ContainerListResult, error) {
|
||||
return client.ContainerListResult{
|
||||
Items: []container.Summary{
|
||||
*builders.Container("c1", builders.WithLabel("some.label", "value")),
|
||||
*builders.Container("c2", builders.WithName("foo/bar"), builders.WithLabel("foo", "bar")),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -260,9 +268,9 @@ func TestContainerListFormatSizeSetsOption(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerListFunc: func(options client.ContainerListOptions) ([]container.Summary, error) {
|
||||
containerListFunc: func(options client.ContainerListOptions) (client.ContainerListResult, error) {
|
||||
assert.Check(t, is.Equal(options.Size, tc.sizeExpected))
|
||||
return []container.Summary{}, nil
|
||||
return client.ContainerListResult{}, nil
|
||||
},
|
||||
})
|
||||
cmd := newListCommand(cli)
|
||||
@ -280,10 +288,12 @@ func TestContainerListFormatSizeSetsOption(t *testing.T) {
|
||||
|
||||
func TestContainerListWithConfigFormat(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerListFunc: func(_ client.ContainerListOptions) ([]container.Summary, error) {
|
||||
return []container.Summary{
|
||||
*builders.Container("c1", builders.WithLabel("some.label", "value"), builders.WithSize(10700000)),
|
||||
*builders.Container("c2", builders.WithName("foo/bar"), builders.WithLabel("foo", "bar"), builders.WithSize(3200000)),
|
||||
containerListFunc: func(_ client.ContainerListOptions) (client.ContainerListResult, error) {
|
||||
return client.ContainerListResult{
|
||||
Items: []container.Summary{
|
||||
*builders.Container("c1", builders.WithLabel("some.label", "value"), builders.WithSize(10700000)),
|
||||
*builders.Container("c2", builders.WithName("foo/bar"), builders.WithLabel("foo", "bar"), builders.WithSize(3200000)),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -300,10 +310,12 @@ func TestContainerListWithConfigFormat(t *testing.T) {
|
||||
|
||||
func TestContainerListWithFormat(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{
|
||||
containerListFunc: func(_ client.ContainerListOptions) ([]container.Summary, error) {
|
||||
return []container.Summary{
|
||||
*builders.Container("c1", builders.WithLabel("some.label", "value")),
|
||||
*builders.Container("c2", builders.WithName("foo/bar"), builders.WithLabel("foo", "bar")),
|
||||
containerListFunc: func(_ client.ContainerListOptions) (client.ContainerListResult, error) {
|
||||
return client.ContainerListResult{
|
||||
Items: []container.Summary{
|
||||
*builders.Container("c1", builders.WithLabel("some.label", "value")),
|
||||
*builders.Container("c2", builders.WithName("foo/bar"), builders.WithLabel("foo", "bar")),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
|
||||
@ -59,7 +59,7 @@ func runLogs(ctx context.Context, dockerCli command.Cli, opts *logsOptions) erro
|
||||
return err
|
||||
}
|
||||
|
||||
responseBody, err := dockerCli.Client().ContainerLogs(ctx, c.Container.ID, client.ContainerLogsOptions{
|
||||
resp, err := dockerCli.Client().ContainerLogs(ctx, c.Container.ID, client.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
ShowStderr: true,
|
||||
Since: opts.since,
|
||||
@ -72,12 +72,12 @@ func runLogs(ctx context.Context, dockerCli command.Cli, opts *logsOptions) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseBody.Close()
|
||||
defer func() { _ = resp.Close() }()
|
||||
|
||||
if c.Container.Config.Tty {
|
||||
_, err = io.Copy(dockerCli.Out(), responseBody)
|
||||
_, err = io.Copy(dockerCli.Out(), resp)
|
||||
} else {
|
||||
_, err = stdcopy.StdCopy(dockerCli.Out(), dockerCli.Err(), responseBody)
|
||||
_, err = stdcopy.StdCopy(dockerCli.Out(), dockerCli.Err(), resp)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@ -2,8 +2,6 @@ package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
@ -13,12 +11,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
var logFn = func(expectedOut string) func(string, client.ContainerLogsOptions) (io.ReadCloser, error) {
|
||||
return func(container string, opts client.ContainerLogsOptions) (io.ReadCloser, error) {
|
||||
return io.NopCloser(strings.NewReader(expectedOut)), nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunLogs(t *testing.T) {
|
||||
inspectFn := func(containerID string) (client.ContainerInspectResult, error) {
|
||||
return client.ContainerInspectResult{
|
||||
@ -41,7 +33,13 @@ func TestRunLogs(t *testing.T) {
|
||||
doc: "successful logs",
|
||||
expectedOut: "foo",
|
||||
options: &logsOptions{},
|
||||
client: &fakeClient{logFunc: logFn("foo"), inspectFunc: inspectFn},
|
||||
client: &fakeClient{
|
||||
logFunc: func(container string, opts client.ContainerLogsOptions) (client.ContainerLogsResult, error) {
|
||||
// FIXME(thaJeztah): how to mock this?
|
||||
return mockContainerLogsResult("foo"), nil
|
||||
},
|
||||
inspectFunc: inspectFn,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -19,7 +18,18 @@ func newRenameCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
Short: "Rename a container",
|
||||
Args: cli.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runRename(cmd.Context(), dockerCLI, args[0], args[1])
|
||||
oldName, newName := args[0], args[1]
|
||||
if newName == "" {
|
||||
// TODO(thaJeztah): remove once https://github.com/moby/moby/pull/51336 is merged and vendored.
|
||||
return errors.New("new name cannot be blank")
|
||||
}
|
||||
_, err := dockerCLI.Client().ContainerRename(cmd.Context(), oldName, client.ContainerRenameOptions{
|
||||
NewName: newName,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to rename container: %w", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"aliases": "docker container rename, docker rename",
|
||||
@ -29,16 +39,3 @@ func newRenameCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runRename(ctx context.Context, dockerCLI command.Cli, oldName, newName string) error {
|
||||
newName = strings.TrimSpace(newName)
|
||||
if newName == "" {
|
||||
// TODO(thaJeztah): improve validation in ContainerRename and daemon; the daemon returns an obscure error when providing whitespace-only new-name:
|
||||
// Error response from daemon: Error when allocating new name: Invalid container name (/ ), only [a-zA-Z0-9][a-zA-Z0-9_.-] are allowed
|
||||
return errors.New("new name cannot be blank")
|
||||
}
|
||||
if err := dockerCLI.Client().ContainerRename(ctx, oldName, newName); err != nil {
|
||||
return fmt.Errorf("failed to rename container: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -89,14 +89,17 @@ func TestRunAttach(t *testing.T) {
|
||||
HijackedResponse: client.NewHijackedResponse(clientConn, types.MediaTypeRawStream),
|
||||
}, nil
|
||||
},
|
||||
waitFunc: func(_ string) (<-chan container.WaitResponse, <-chan error) {
|
||||
waitFunc: func(_ string) client.ContainerWaitResult {
|
||||
responseChan := make(chan container.WaitResponse, 1)
|
||||
errChan := make(chan error)
|
||||
|
||||
responseChan <- container.WaitResponse{
|
||||
StatusCode: 33,
|
||||
}
|
||||
return responseChan, errChan
|
||||
return client.ContainerWaitResult{
|
||||
Result: responseChan,
|
||||
Error: errChan,
|
||||
}
|
||||
},
|
||||
// use new (non-legacy) wait API
|
||||
// see: https://github.com/docker/cli/commit/38591f20d07795aaef45d400df89ca12f29c603b
|
||||
@ -166,14 +169,17 @@ func TestRunAttachTermination(t *testing.T) {
|
||||
HijackedResponse: client.NewHijackedResponse(clientConn, types.MediaTypeRawStream),
|
||||
}, nil
|
||||
},
|
||||
waitFunc: func(_ string) (<-chan container.WaitResponse, <-chan error) {
|
||||
waitFunc: func(_ string) client.ContainerWaitResult {
|
||||
responseChan := make(chan container.WaitResponse, 1)
|
||||
errChan := make(chan error)
|
||||
<-killCh
|
||||
responseChan <- container.WaitResponse{
|
||||
StatusCode: 130,
|
||||
}
|
||||
return responseChan, errChan
|
||||
return client.ContainerWaitResult{
|
||||
Result: responseChan,
|
||||
Error: errChan,
|
||||
}
|
||||
},
|
||||
// use new (non-legacy) wait API
|
||||
// see: https://github.com/docker/cli/commit/38591f20d07795aaef45d400df89ca12f29c603b
|
||||
|
||||
@ -183,7 +183,7 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
|
||||
// to list containers and to filter events, but the "type" filter
|
||||
// is not valid for filtering containers.
|
||||
f := options.Filters.Clone().Add("type", string(events.ContainerEventType))
|
||||
eventChan, errChan := apiClient.Events(ctx, client.EventsListOptions{
|
||||
res := apiClient.Events(ctx, client.EventsListOptions{
|
||||
Filters: f,
|
||||
})
|
||||
|
||||
@ -198,9 +198,9 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
|
||||
return
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case event := <-eventChan:
|
||||
case event := <-res.Messages:
|
||||
c <- event
|
||||
case err := <-errChan:
|
||||
case err := <-res.Err:
|
||||
// Prevent blocking if closeChan is full or unread
|
||||
select {
|
||||
case closeChan <- err:
|
||||
@ -229,7 +229,7 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ctr := range cs {
|
||||
for _, ctr := range cs.Items {
|
||||
if s := NewStats(ctr.ID); cStats.add(s) {
|
||||
waitFirst.Add(1)
|
||||
log.G(ctx).WithFields(map[string]any{
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/docker/cli/cli/command/formatter/tabwriter"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -45,17 +46,19 @@ func newTopCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
}
|
||||
|
||||
func runTop(ctx context.Context, dockerCli command.Cli, opts *topOptions) error {
|
||||
procList, err := dockerCli.Client().ContainerTop(ctx, opts.container, opts.args)
|
||||
procList, err := dockerCli.Client().ContainerTop(ctx, opts.container, client.ContainerTopOptions{
|
||||
Arguments: opts.args,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(dockerCli.Out(), 20, 1, 3, ' ', 0)
|
||||
fmt.Fprintln(w, strings.Join(procList.Titles, "\t"))
|
||||
_, _ = fmt.Fprintln(w, strings.Join(procList.Titles, "\t"))
|
||||
|
||||
for _, proc := range procList.Processes {
|
||||
fmt.Fprintln(w, strings.Join(proc, "\t"))
|
||||
_, _ = fmt.Fprintln(w, strings.Join(proc, "\t"))
|
||||
}
|
||||
w.Flush()
|
||||
_ = w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ func newUnpauseCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
func runUnpause(ctx context.Context, dockerCLI command.Cli, opts *unpauseOptions) error {
|
||||
apiClient := dockerCLI.Client()
|
||||
errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, container string) error {
|
||||
_, err := apiClient.ContainerUnpause(ctx, container, client.ContainerUnPauseOptions{})
|
||||
_, err := apiClient.ContainerUnpause(ctx, container, client.ContainerUnpauseOptions{})
|
||||
return err
|
||||
})
|
||||
var errs []error
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/docker/cli/opts"
|
||||
containertypes "github.com/moby/moby/api/types/container"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -60,9 +61,9 @@ func newUpdateCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
flags.Int64Var(&options.cpuPeriod, "cpu-period", 0, "Limit CPU CFS (Completely Fair Scheduler) period")
|
||||
flags.Int64Var(&options.cpuQuota, "cpu-quota", 0, "Limit CPU CFS (Completely Fair Scheduler) quota")
|
||||
flags.Int64Var(&options.cpuRealtimePeriod, "cpu-rt-period", 0, "Limit the CPU real-time period in microseconds")
|
||||
flags.SetAnnotation("cpu-rt-period", "version", []string{"1.25"})
|
||||
_ = flags.SetAnnotation("cpu-rt-period", "version", []string{"1.25"})
|
||||
flags.Int64Var(&options.cpuRealtimeRuntime, "cpu-rt-runtime", 0, "Limit the CPU real-time runtime in microseconds")
|
||||
flags.SetAnnotation("cpu-rt-runtime", "version", []string{"1.25"})
|
||||
_ = flags.SetAnnotation("cpu-rt-runtime", "version", []string{"1.25"})
|
||||
flags.StringVar(&options.cpusetCpus, "cpuset-cpus", "", "CPUs in which to allow execution (0-3, 0,1)")
|
||||
flags.StringVar(&options.cpusetMems, "cpuset-mems", "", "MEMs in which to allow execution (0-3, 0,1)")
|
||||
flags.Int64VarP(&options.cpuShares, "cpu-shares", "c", 0, "CPU shares (relative weight)")
|
||||
@ -72,10 +73,10 @@ func newUpdateCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
|
||||
flags.StringVar(&options.restartPolicy, "restart", "", "Restart policy to apply when a container exits")
|
||||
flags.Int64Var(&options.pidsLimit, "pids-limit", 0, `Tune container pids limit (set -1 for unlimited)`)
|
||||
flags.SetAnnotation("pids-limit", "version", []string{"1.40"})
|
||||
_ = flags.SetAnnotation("pids-limit", "version", []string{"1.40"})
|
||||
|
||||
flags.Var(&options.cpus, "cpus", "Number of CPUs")
|
||||
flags.SetAnnotation("cpus", "version", []string{"1.29"})
|
||||
_ = flags.SetAnnotation("cpus", "version", []string{"1.29"})
|
||||
|
||||
_ = cmd.RegisterFlagCompletionFunc("restart", completeRestartPolicies)
|
||||
|
||||
@ -107,8 +108,8 @@ func runUpdate(ctx context.Context, dockerCli command.Cli, options *updateOption
|
||||
pidsLimit = &options.pidsLimit
|
||||
}
|
||||
|
||||
updateConfig := containertypes.UpdateConfig{
|
||||
Resources: containertypes.Resources{
|
||||
updateConfig := client.ContainerUpdateOptions{
|
||||
Resources: &containertypes.Resources{
|
||||
BlkioWeight: options.blkioWeight,
|
||||
CpusetCpus: options.cpusetCpus,
|
||||
CpusetMems: options.cpusetMems,
|
||||
@ -123,7 +124,7 @@ func runUpdate(ctx context.Context, dockerCli command.Cli, options *updateOption
|
||||
NanoCPUs: options.cpus.Value(),
|
||||
PidsLimit: pidsLimit,
|
||||
},
|
||||
RestartPolicy: restartPolicy,
|
||||
RestartPolicy: &restartPolicy,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@ -20,7 +20,9 @@ func waitExitOrRemoved(ctx context.Context, apiClient client.APIClient, containe
|
||||
condition = container.WaitConditionRemoved
|
||||
}
|
||||
|
||||
resultC, errC := apiClient.ContainerWait(ctx, containerID, condition)
|
||||
waitRes := apiClient.ContainerWait(ctx, containerID, client.ContainerWaitOptions{
|
||||
Condition: condition,
|
||||
})
|
||||
|
||||
statusC := make(chan int)
|
||||
go func() {
|
||||
@ -28,14 +30,14 @@ func waitExitOrRemoved(ctx context.Context, apiClient client.APIClient, containe
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case result := <-resultC:
|
||||
case result := <-waitRes.Result:
|
||||
if result.Error != nil {
|
||||
logrus.Errorf("Error waiting for container: %v", result.Error.Message)
|
||||
statusC <- 125
|
||||
} else {
|
||||
statusC <- int(result.StatusCode)
|
||||
}
|
||||
case err := <-errC:
|
||||
case err := <-waitRes.Error:
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func waitFn(cid string) (<-chan container.WaitResponse, <-chan error) {
|
||||
func waitFn(cid string) client.ContainerWaitResult {
|
||||
resC := make(chan container.WaitResponse)
|
||||
errC := make(chan error, 1)
|
||||
var res container.WaitResponse
|
||||
@ -33,8 +33,10 @@ func waitFn(cid string) (<-chan container.WaitResponse, <-chan error) {
|
||||
resC <- res
|
||||
}
|
||||
}()
|
||||
|
||||
return resC, errC
|
||||
return client.ContainerWaitResult{
|
||||
Result: resC,
|
||||
Error: errC,
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitExitOrRemoved(t *testing.T) {
|
||||
|
||||
@ -4,10 +4,12 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/moby/moby/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -42,12 +44,12 @@ func runWait(ctx context.Context, dockerCLI command.Cli, opts *waitOptions) erro
|
||||
|
||||
var errs []error
|
||||
for _, ctr := range opts.containers {
|
||||
resultC, errC := apiClient.ContainerWait(ctx, ctr, "")
|
||||
res := apiClient.ContainerWait(ctx, ctr, client.ContainerWaitOptions{})
|
||||
|
||||
select {
|
||||
case result := <-resultC:
|
||||
_, _ = fmt.Fprintf(dockerCLI.Out(), "%d\n", result.StatusCode)
|
||||
case err := <-errC:
|
||||
case result := <-res.Result:
|
||||
_, _ = fmt.Fprintln(dockerCLI.Out(), strconv.FormatInt(result.StatusCode, 10))
|
||||
case err := <-res.Error:
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user