diff --git a/cli/command/completion/functions.go b/cli/command/completion/functions.go index a85b9f1f8..d8a5a71d3 100644 --- a/cli/command/completion/functions.go +++ b/cli/command/completion/functions.go @@ -115,7 +115,7 @@ func VolumeNames(dockerCLI APIClientProvider) cobra.CompletionFunc { return nil, cobra.ShellCompDirectiveError } var names []string - for _, vol := range res.Items.Volumes { + for _, vol := range res.Items { names = append(names, vol.Name) } return names, cobra.ShellCompDirectiveNoFileComp diff --git a/cli/command/completion/functions_test.go b/cli/command/completion/functions_test.go index ed426be60..67803f9a0 100644 --- a/cli/command/completion/functions_test.go +++ b/cli/command/completion/functions_test.go @@ -310,7 +310,7 @@ func TestCompletePlatforms(t *testing.T) { func TestCompleteVolumeNames(t *testing.T) { tests := []struct { doc string - volumes []*volume.Volume + volumes []volume.Volume expOut []string expDirective cobra.ShellCompDirective }{ @@ -320,7 +320,7 @@ func TestCompleteVolumeNames(t *testing.T) { }, { doc: "with results", - volumes: []*volume.Volume{ + volumes: []volume.Volume{ {Name: "volume-c"}, {Name: "volume-b"}, {Name: "volume-a"}, @@ -341,7 +341,7 @@ func TestCompleteVolumeNames(t *testing.T) { if tc.expDirective == cobra.ShellCompDirectiveError { return client.VolumeListResult{}, errors.New("some error occurred") } - return client.VolumeListResult{Items: volume.ListResponse{Volumes: tc.volumes}}, nil + return client.VolumeListResult{Items: tc.volumes}, nil }, }}) diff --git a/cli/command/container/attach.go b/cli/command/container/attach.go index 57dcf446b..8386219ff 100644 --- a/cli/command/container/attach.go +++ b/cli/command/container/attach.go @@ -114,11 +114,11 @@ func RunAttach(ctx context.Context, dockerCLI command.Cli, containerID string, o defer signal.StopCatch(sigc) } - resp, errAttach := apiClient.ContainerAttach(ctx, containerID, options) - if errAttach != nil { - return errAttach + res, err := apiClient.ContainerAttach(ctx, containerID, options) + if err != nil { + return err } - defer resp.Close() + defer res.HijackedResponse.Close() // If use docker attach command to attach to a stop container, it will return // "You cannot attach to a stopped container" error, it's ok, but when @@ -142,7 +142,7 @@ func RunAttach(ctx context.Context, dockerCLI command.Cli, containerID string, o inputStream: in, outputStream: dockerCLI.Out(), errorStream: dockerCLI.Err(), - resp: resp, + resp: res.HijackedResponse, tty: c.Config.Tty, detachKeys: options.DetachKeys, } diff --git a/cli/command/container/client_test.go b/cli/command/container/client_test.go index 4911148f5..8825ddce4 100644 --- a/cli/command/container/client_test.go +++ b/cli/command/container/client_test.go @@ -5,22 +5,16 @@ import ( "io" "github.com/moby/moby/api/types/container" - "github.com/moby/moby/api/types/network" "github.com/moby/moby/api/types/system" "github.com/moby/moby/client" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) type fakeClient struct { client.Client - inspectFunc func(string) (container.InspectResponse, error) - execInspectFunc func(execID string) (client.ExecInspectResult, error) - execCreateFunc func(containerID string, options client.ExecCreateOptions) (client.ExecCreateResult, error) - createContainerFunc func(config *container.Config, - hostConfig *container.HostConfig, - networkingConfig *network.NetworkingConfig, - platform *ocispec.Platform, - containerName string) (container.CreateResponse, error) + inspectFunc func(string) (container.InspectResponse, error) + execInspectFunc func(execID string) (client.ExecInspectResult, error) + execCreateFunc func(containerID string, options client.ExecCreateOptions) (client.ExecCreateResult, error) + createContainerFunc func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) containerStartFunc func(containerID string, options client.ContainerStartOptions) error imageCreateFunc func(ctx context.Context, parentReference string, options client.ImageCreateOptions) (client.ImageCreateResult, error) infoFunc func() (system.Info, error) @@ -36,10 +30,10 @@ type fakeClient struct { containerStopFunc func(ctx context.Context, containerID string, options client.ContainerStopOptions) error containerKillFunc func(ctx context.Context, containerID, signal string) error containerPruneFunc func(ctx context.Context, options client.ContainerPruneOptions) (client.ContainerPruneResult, error) - containerAttachFunc func(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.HijackedResponse, error) - containerDiffFunc func(ctx context.Context, containerID string) ([]container.FilesystemChange, error) + containerAttachFunc func(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.ContainerAttachResult, error) + containerDiffFunc func(ctx context.Context, containerID string) (client.ContainerDiffResult, error) containerRenameFunc func(ctx context.Context, oldName, newName string) error - containerCommitFunc func(ctx context.Context, container string, options client.ContainerCommitOptions) (container.CommitResponse, error) + containerCommitFunc func(ctx context.Context, container string, options client.ContainerCommitOptions) (client.ContainerCommitResult, error) containerPauseFunc func(ctx context.Context, container string) error Version string } @@ -76,18 +70,11 @@ func (*fakeClient) ExecStart(context.Context, string, client.ExecStartOptions) ( return client.ExecStartResult{}, nil } -func (f *fakeClient) ContainerCreate( - _ context.Context, - config *container.Config, - hostConfig *container.HostConfig, - networkingConfig *network.NetworkingConfig, - platform *ocispec.Platform, - containerName string, -) (container.CreateResponse, error) { +func (f *fakeClient) ContainerCreate(_ context.Context, options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { if f.createContainerFunc != nil { - return f.createContainerFunc(config, hostConfig, networkingConfig, platform, containerName) + return f.createContainerFunc(options) } - return container.CreateResponse{}, nil + return client.ContainerCreateResult{}, nil } func (f *fakeClient) ContainerRemove(ctx context.Context, containerID string, options client.ContainerRemoveOptions) error { @@ -192,19 +179,19 @@ func (f *fakeClient) ContainerStop(ctx context.Context, containerID string, opti return nil } -func (f *fakeClient) ContainerAttach(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.HijackedResponse, error) { +func (f *fakeClient) ContainerAttach(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.ContainerAttachResult, error) { if f.containerAttachFunc != nil { return f.containerAttachFunc(ctx, containerID, options) } - return client.HijackedResponse{}, nil + return client.ContainerAttachResult{}, nil } -func (f *fakeClient) ContainerDiff(ctx context.Context, containerID string) ([]container.FilesystemChange, error) { +func (f *fakeClient) ContainerDiff(ctx context.Context, containerID string, _ client.ContainerDiffOptions) (client.ContainerDiffResult, error) { if f.containerDiffFunc != nil { return f.containerDiffFunc(ctx, containerID) } - return []container.FilesystemChange{}, nil + return client.ContainerDiffResult{}, nil } func (f *fakeClient) ContainerRename(ctx context.Context, oldName, newName string) error { @@ -215,11 +202,11 @@ func (f *fakeClient) ContainerRename(ctx context.Context, oldName, newName strin return nil } -func (f *fakeClient) ContainerCommit(ctx context.Context, containerID string, options client.ContainerCommitOptions) (container.CommitResponse, error) { +func (f *fakeClient) ContainerCommit(ctx context.Context, containerID string, options client.ContainerCommitOptions) (client.ContainerCommitResult, error) { if f.containerCommitFunc != nil { return f.containerCommitFunc(ctx, containerID, options) } - return container.CommitResponse{}, nil + return client.ContainerCommitResult{}, nil } func (f *fakeClient) ContainerPause(ctx context.Context, containerID string) error { diff --git a/cli/command/container/commit_test.go b/cli/command/container/commit_test.go index c01d49b72..fa8164d02 100644 --- a/cli/command/container/commit_test.go +++ b/cli/command/container/commit_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/moby/moby/api/types/container" "github.com/moby/moby/client" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" @@ -15,18 +14,14 @@ import ( func TestRunCommit(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ - containerCommitFunc: func( - ctx context.Context, - ctr string, - options client.ContainerCommitOptions, - ) (container.CommitResponse, error) { + containerCommitFunc: func(ctx context.Context, ctr string, options client.ContainerCommitOptions) (client.ContainerCommitResult, error) { assert.Check(t, is.Equal(options.Author, "Author Name ")) assert.Check(t, is.DeepEqual(options.Changes, []string{"EXPOSE 80"})) assert.Check(t, is.Equal(options.Comment, "commit message")) assert.Check(t, is.Equal(options.NoPause, true)) assert.Check(t, is.Equal(ctr, "container-id")) - return container.CommitResponse{ID: "image-id"}, nil + return client.ContainerCommitResult{ID: "image-id"}, nil }, }) @@ -52,12 +47,8 @@ func TestRunCommitClientError(t *testing.T) { clientError := errors.New("client error") cli := test.NewFakeCli(&fakeClient{ - containerCommitFunc: func( - ctx context.Context, - ctr string, - options client.ContainerCommitOptions, - ) (container.CommitResponse, error) { - return container.CommitResponse{}, clientError + containerCommitFunc: func(ctx context.Context, ctr string, options client.ContainerCommitOptions) (client.ContainerCommitResult, error) { + return client.ContainerCommitResult{}, clientError }, }) diff --git a/cli/command/container/create.go b/cli/command/container/create.go index a8969e4f1..a645b4998 100644 --- a/cli/command/container/create.go +++ b/cli/command/container/create.go @@ -332,7 +332,14 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c hostConfig.ConsoleSize[0], hostConfig.ConsoleSize[1] = dockerCli.Out().GetTtySize() - response, err := dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, platform, options.name) + response, err := dockerCli.Client().ContainerCreate(ctx, client.ContainerCreateOptions{ + Name: options.name, + // Image: config.Image, // TODO(thaJeztah): pass image-ref separate + Platform: platform, + Config: config, + HostConfig: hostConfig, + NetworkingConfig: networkingConfig, + }) if err != nil { // Pull image if it does not exist locally and we have the PullImageMissing option. Default behavior. if errdefs.IsNotFound(err) && namedRef != nil && options.pull == PullImageMissing { @@ -346,7 +353,14 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c } var retryErr error - response, retryErr = dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, platform, options.name) + response, retryErr = dockerCli.Client().ContainerCreate(ctx, client.ContainerCreateOptions{ + Name: options.name, + // Image: config.Image, // TODO(thaJeztah): pass image-ref separate + Platform: platform, + Config: config, + HostConfig: hostConfig, + NetworkingConfig: networkingConfig, + }) if retryErr != nil { return "", retryErr } diff --git a/cli/command/container/create_test.go b/cli/command/container/create_test.go index 3f13477b1..234b6bca4 100644 --- a/cli/command/container/create_test.go +++ b/cli/command/container/create_test.go @@ -16,10 +16,8 @@ import ( "github.com/docker/cli/internal/test/notary" "github.com/google/go-cmp/cmp" "github.com/moby/moby/api/types/container" - "github.com/moby/moby/api/types/network" "github.com/moby/moby/api/types/system" "github.com/moby/moby/client" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/spf13/pflag" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" @@ -117,19 +115,13 @@ func TestCreateContainerImagePullPolicy(t *testing.T) { pullCounter := 0 apiClient := &fakeClient{ - createContainerFunc: func( - config *container.Config, - hostConfig *container.HostConfig, - networkingConfig *network.NetworkingConfig, - platform *ocispec.Platform, - containerName string, - ) (container.CreateResponse, error) { + createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { defer func() { tc.ResponseCounter++ }() switch tc.ResponseCounter { case 0: - return container.CreateResponse{}, fakeNotFound{} + return client.ContainerCreateResult{}, fakeNotFound{} default: - return container.CreateResponse{ID: containerID}, nil + return client.ContainerCreateResult{ID: containerID}, nil } }, imageCreateFunc: func(ctx context.Context, parentReference string, options client.ImageCreateOptions) (client.ImageCreateResult, error) { @@ -251,13 +243,8 @@ func TestNewCreateCommandWithContentTrustErrors(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Setenv("DOCKER_CONTENT_TRUST", "true") fakeCLI := test.NewFakeCli(&fakeClient{ - createContainerFunc: func(config *container.Config, - hostConfig *container.HostConfig, - networkingConfig *network.NetworkingConfig, - platform *ocispec.Platform, - containerName string, - ) (container.CreateResponse, error) { - return container.CreateResponse{}, errors.New("shouldn't try to pull image") + createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { + return client.ContainerCreateResult{}, errors.New("shouldn't try to pull image") }, }) fakeCLI.SetNotaryClient(tc.notaryFunc) @@ -296,13 +283,8 @@ func TestNewCreateCommandWithWarnings(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { fakeCLI := test.NewFakeCli(&fakeClient{ - createContainerFunc: func(config *container.Config, - hostConfig *container.HostConfig, - networkingConfig *network.NetworkingConfig, - platform *ocispec.Platform, - containerName string, - ) (container.CreateResponse, error) { - return container.CreateResponse{Warnings: tc.warnings}, nil + createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { + return client.ContainerCreateResult{Warnings: tc.warnings}, nil }, }) cmd := newCreateCommand(fakeCLI) @@ -335,15 +317,10 @@ func TestCreateContainerWithProxyConfig(t *testing.T) { sort.Strings(expected) fakeCLI := test.NewFakeCli(&fakeClient{ - createContainerFunc: func(config *container.Config, - hostConfig *container.HostConfig, - networkingConfig *network.NetworkingConfig, - platform *ocispec.Platform, - containerName string, - ) (container.CreateResponse, error) { - sort.Strings(config.Env) - assert.DeepEqual(t, config.Env, expected) - return container.CreateResponse{}, nil + createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { + sort.Strings(options.Config.Env) + assert.DeepEqual(t, options.Config.Env, expected) + return client.ContainerCreateResult{}, nil }, }) fakeCLI.SetConfigFile(&configfile.ConfigFile{ diff --git a/cli/command/container/diff.go b/cli/command/container/diff.go index 164ebf02a..feb0f843e 100644 --- a/cli/command/container/diff.go +++ b/cli/command/container/diff.go @@ -7,6 +7,7 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/completion" "github.com/docker/cli/cli/command/formatter" + "github.com/moby/moby/client" "github.com/spf13/cobra" ) @@ -28,7 +29,7 @@ func newDiffCommand(dockerCLI command.Cli) *cobra.Command { } func runDiff(ctx context.Context, dockerCLI command.Cli, containerID string) error { - changes, err := dockerCLI.Client().ContainerDiff(ctx, containerID) + res, err := dockerCLI.Client().ContainerDiff(ctx, containerID, client.ContainerDiffOptions{}) if err != nil { return err } @@ -36,5 +37,5 @@ func runDiff(ctx context.Context, dockerCLI command.Cli, containerID string) err Output: dockerCLI.Out(), Format: newDiffFormat("{{.Type}} {{.Path}}"), } - return diffFormatWrite(diffCtx, changes) + return diffFormatWrite(diffCtx, res) } diff --git a/cli/command/container/diff_test.go b/cli/command/container/diff_test.go index d2504858b..1e941d974 100644 --- a/cli/command/container/diff_test.go +++ b/cli/command/container/diff_test.go @@ -9,28 +9,28 @@ import ( "github.com/docker/cli/internal/test" "github.com/moby/moby/api/types/container" + "github.com/moby/moby/client" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) func TestRunDiff(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ - containerDiffFunc: func( - ctx context.Context, - containerID string, - ) ([]container.FilesystemChange, error) { - return []container.FilesystemChange{ - { - Kind: container.ChangeModify, - Path: "/path/to/file0", - }, - { - Kind: container.ChangeAdd, - Path: "/path/to/file1", - }, - { - Kind: container.ChangeDelete, - Path: "/path/to/file2", + containerDiffFunc: func(ctx context.Context, containerID string) (client.ContainerDiffResult, error) { + return client.ContainerDiffResult{ + Changes: []container.FilesystemChange{ + { + Kind: container.ChangeModify, + Path: "/path/to/file0", + }, + { + Kind: container.ChangeAdd, + Path: "/path/to/file1", + }, + { + Kind: container.ChangeDelete, + Path: "/path/to/file2", + }, }, }, nil }, @@ -60,11 +60,8 @@ func TestRunDiffClientError(t *testing.T) { clientError := errors.New("client error") cli := test.NewFakeCli(&fakeClient{ - containerDiffFunc: func( - ctx context.Context, - containerID string, - ) ([]container.FilesystemChange, error) { - return nil, clientError + containerDiffFunc: func(ctx context.Context, containerID string) (client.ContainerDiffResult, error) { + return client.ContainerDiffResult{}, clientError }, }) diff --git a/cli/command/container/exec_test.go b/cli/command/container/exec_test.go index f344a218e..5a86c2262 100644 --- a/cli/command/container/exec_test.go +++ b/cli/command/container/exec_test.go @@ -119,7 +119,7 @@ TWO=2 }, options: func() ExecOptions { o := withDefaultOpts(ExecOptions{}) - o.EnvFile.Set(tmpFile.Path()) + _ = o.EnvFile.Set(tmpFile.Path()) return o }(), }, @@ -132,8 +132,8 @@ TWO=2 }, options: func() ExecOptions { o := withDefaultOpts(ExecOptions{}) - o.EnvFile.Set(tmpFile.Path()) - o.Env.Set("ONE=override") + _ = o.EnvFile.Set(tmpFile.Path()) + _ = o.Env.Set("ONE=override") return o }(), }, @@ -150,7 +150,7 @@ TWO=2 func TestParseExecNoSuchFile(t *testing.T) { execOpts := withDefaultOpts(ExecOptions{}) - execOpts.EnvFile.Set("no-such-env-file") + assert.Check(t, execOpts.EnvFile.Set("no-such-env-file")) execConfig, err := parseExec(execOpts, &configfile.ConfigFile{}) assert.ErrorContains(t, err, "no-such-env-file") assert.Check(t, os.IsNotExist(err)) @@ -195,7 +195,7 @@ func TestRunExec(t *testing.T) { t.Run(testcase.doc, func(t *testing.T) { fakeCLI := test.NewFakeCli(testcase.client) - err := RunExec(context.TODO(), fakeCLI, "thecontainer", testcase.options) + err := RunExec(context.TODO(), fakeCLI, "the-container", testcase.options) if testcase.expectedError != "" { assert.ErrorContains(t, err, testcase.expectedError) } else if !assert.Check(t, err) { @@ -208,7 +208,7 @@ func TestRunExec(t *testing.T) { } func execCreateWithID(_ string, _ client.ExecCreateOptions) (client.ExecCreateResult, error) { - return client.ExecCreateResult{ExecCreateResponse: container.ExecCreateResponse{ID: "execid"}}, nil + return client.ExecCreateResult{ID: "exec-id"}, nil } func TestGetExecExitStatus(t *testing.T) { @@ -238,9 +238,7 @@ func TestGetExecExitStatus(t *testing.T) { apiClient := &fakeClient{ execInspectFunc: func(id string) (client.ExecInspectResult, error) { assert.Check(t, is.Equal(execID, id)) - return client.ExecInspectResult{ - ExecInspect: client.ExecInspect{ExitCode: testcase.exitCode}, - }, testcase.inspectError + return client.ExecInspectResult{ExitCode: testcase.exitCode}, testcase.inspectError }, } err := getExecExitStatus(context.Background(), apiClient, execID) diff --git a/cli/command/container/formatter_diff.go b/cli/command/container/formatter_diff.go index a62552b6f..35c48d5d1 100644 --- a/cli/command/container/formatter_diff.go +++ b/cli/command/container/formatter_diff.go @@ -3,6 +3,7 @@ package container import ( "github.com/docker/cli/cli/command/formatter" "github.com/moby/moby/api/types/container" + "github.com/moby/moby/client" ) const ( @@ -21,9 +22,9 @@ func newDiffFormat(source string) formatter.Format { } // diffFormatWrite writes formatted diff using the [formatter.Context]. -func diffFormatWrite(fmtCtx formatter.Context, changes []container.FilesystemChange) error { +func diffFormatWrite(fmtCtx formatter.Context, changes client.ContainerDiffResult) error { return fmtCtx.Write(newDiffContext(), func(format func(subContext formatter.SubContext) error) error { - for _, change := range changes { + for _, change := range changes.Changes { if err := format(&diffContext{c: change}); err != nil { return err } diff --git a/cli/command/container/formatter_diff_test.go b/cli/command/container/formatter_diff_test.go index c6d10de94..0d2849d25 100644 --- a/cli/command/container/formatter_diff_test.go +++ b/cli/command/container/formatter_diff_test.go @@ -6,6 +6,7 @@ import ( "github.com/docker/cli/cli/command/formatter" "github.com/moby/moby/api/types/container" + "github.com/moby/moby/client" "gotest.tools/v3/assert" ) @@ -40,10 +41,12 @@ D: /usr/app/old_app.js }, } - diffs := []container.FilesystemChange{ - {Kind: container.ChangeModify, Path: "/var/log/app.log"}, - {Kind: container.ChangeAdd, Path: "/usr/app/app.js"}, - {Kind: container.ChangeDelete, Path: "/usr/app/old_app.js"}, + diffs := client.ContainerDiffResult{ + Changes: []container.FilesystemChange{ + {Kind: container.ChangeModify, Path: "/var/log/app.log"}, + {Kind: container.ChangeAdd, Path: "/usr/app/app.js"}, + {Kind: container.ChangeDelete, Path: "/usr/app/old_app.js"}, + }, } for _, tc := range cases { diff --git a/cli/command/container/run.go b/cli/command/container/run.go index f2c634fd0..64836b0a9 100644 --- a/cli/command/container/run.go +++ b/cli/command/container/run.go @@ -290,7 +290,7 @@ func attachContainer(ctx context.Context, dockerCli command.Cli, containerID str inputStream: in, outputStream: out, errorStream: cerr, - resp: resp, + resp: resp.HijackedResponse, tty: config.Tty, detachKeys: options.DetachKeys, } @@ -301,7 +301,7 @@ func attachContainer(ctx context.Context, dockerCli command.Cli, containerID str return errAttach }() }() - return resp.Close, nil + return resp.HijackedResponse.Close, nil } // withHelp decorates the error with a suggestion to use "--help". diff --git a/cli/command/container/run_test.go b/cli/command/container/run_test.go index c853766a4..94f31d2c8 100644 --- a/cli/command/container/run_test.go +++ b/cli/command/container/run_test.go @@ -18,9 +18,7 @@ import ( "github.com/moby/moby/api/pkg/streamformatter" "github.com/moby/moby/api/types" "github.com/moby/moby/api/types/container" - "github.com/moby/moby/api/types/network" "github.com/moby/moby/client" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/spf13/pflag" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" @@ -56,10 +54,8 @@ func TestRunValidateFlags(t *testing.T) { func TestRunLabel(t *testing.T) { fakeCLI := test.NewFakeCli(&fakeClient{ - createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *ocispec.Platform, _ string) (container.CreateResponse, error) { - return container.CreateResponse{ - ID: "id", - }, nil + createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { + return client.ContainerCreateResult{ID: "id"}, nil }, Version: client.MaxAPIVersion, }) @@ -79,19 +75,19 @@ func TestRunAttach(t *testing.T) { var conn net.Conn attachCh := make(chan struct{}) fakeCLI := test.NewFakeCli(&fakeClient{ - createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *ocispec.Platform, _ string) (container.CreateResponse, error) { - return container.CreateResponse{ - ID: "id", - }, nil + createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { + return client.ContainerCreateResult{ID: "id"}, nil }, - containerAttachFunc: func(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.HijackedResponse, error) { + containerAttachFunc: func(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.ContainerAttachResult, error) { server, clientConn := net.Pipe() conn = server t.Cleanup(func() { _ = server.Close() }) attachCh <- struct{}{} - return client.NewHijackedResponse(clientConn, types.MediaTypeRawStream), nil + return client.ContainerAttachResult{ + HijackedResponse: client.NewHijackedResponse(clientConn, types.MediaTypeRawStream), + }, nil }, waitFunc: func(_ string) (<-chan container.WaitResponse, <-chan error) { responseChan := make(chan container.WaitResponse, 1) @@ -150,10 +146,8 @@ func TestRunAttachTermination(t *testing.T) { killCh := make(chan struct{}) attachCh := make(chan struct{}) fakeCLI := test.NewFakeCli(&fakeClient{ - createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *ocispec.Platform, _ string) (container.CreateResponse, error) { - return container.CreateResponse{ - ID: "id", - }, nil + createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { + return client.ContainerCreateResult{ID: "id"}, nil }, containerKillFunc: func(ctx context.Context, containerID, sig string) error { if sig == "TERM" { @@ -161,14 +155,16 @@ func TestRunAttachTermination(t *testing.T) { } return nil }, - containerAttachFunc: func(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.HijackedResponse, error) { + containerAttachFunc: func(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.ContainerAttachResult, error) { server, clientConn := net.Pipe() conn = server t.Cleanup(func() { _ = server.Close() }) attachCh <- struct{}{} - return client.NewHijackedResponse(clientConn, types.MediaTypeRawStream), nil + return client.ContainerAttachResult{ + HijackedResponse: client.NewHijackedResponse(clientConn, types.MediaTypeRawStream), + }, nil }, waitFunc: func(_ string) (<-chan container.WaitResponse, <-chan error) { responseChan := make(chan container.WaitResponse, 1) @@ -227,13 +223,11 @@ func TestRunPullTermination(t *testing.T) { attachCh := make(chan struct{}) fakeCLI := test.NewFakeCli(&fakeClient{ - createContainerFunc: func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, - platform *ocispec.Platform, containerName string, - ) (container.CreateResponse, error) { - return container.CreateResponse{}, errors.New("shouldn't try to create a container") + createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { + return client.ContainerCreateResult{}, errors.New("shouldn't try to create a container") }, - containerAttachFunc: func(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.HijackedResponse, error) { - return client.HijackedResponse{}, errors.New("shouldn't try to attach to a container") + containerAttachFunc: func(ctx context.Context, containerID string, options client.ContainerAttachOptions) (client.ContainerAttachResult, error) { + return client.ContainerAttachResult{}, errors.New("shouldn't try to attach to a container") }, imageCreateFunc: func(ctx context.Context, parentReference string, options client.ImageCreateOptions) (client.ImageCreateResult, error) { server, respReader := net.Pipe() @@ -325,13 +319,8 @@ func TestRunCommandWithContentTrustErrors(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Setenv("DOCKER_CONTENT_TRUST", "true") fakeCLI := test.NewFakeCli(&fakeClient{ - createContainerFunc: func(config *container.Config, - hostConfig *container.HostConfig, - networkingConfig *network.NetworkingConfig, - platform *ocispec.Platform, - containerName string, - ) (container.CreateResponse, error) { - return container.CreateResponse{}, errors.New("shouldn't try to pull image") + createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { + return client.ContainerCreateResult{}, errors.New("shouldn't try to pull image") }, }) fakeCLI.SetNotaryClient(tc.notaryFunc) diff --git a/cli/command/container/start.go b/cli/command/container/start.go index 5e4d61298..7912f1a19 100644 --- a/cli/command/container/start.go +++ b/cli/command/container/start.go @@ -116,7 +116,7 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er if errAttach != nil { return errAttach } - defer resp.Close() + defer resp.HijackedResponse.Close() cErr := make(chan error, 1) @@ -127,7 +127,7 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er inputStream: in, outputStream: dockerCli.Out(), errorStream: dockerCli.Err(), - resp: resp, + resp: resp.HijackedResponse, tty: c.Config.Tty, detachKeys: options.DetachKeys, } @@ -166,7 +166,8 @@ func RunStart(ctx context.Context, dockerCli command.Cli, opts *StartOptions) er } } if attachErr := <-cErr; attachErr != nil { - if _, ok := attachErr.(term.EscapeError); ok { + var escapeError term.EscapeError + if errors.As(attachErr, &escapeError) { // The user entered the detach escape sequence. return nil } diff --git a/cli/command/formatter/volume.go b/cli/command/formatter/volume.go index 584ca89bf..e3d4b1922 100644 --- a/cli/command/formatter/volume.go +++ b/cli/command/formatter/volume.go @@ -40,10 +40,10 @@ func NewVolumeFormat(source string, quiet bool) Format { } // VolumeWrite writes formatted volumes using the Context -func VolumeWrite(ctx Context, volumes []*volume.Volume) error { +func VolumeWrite(ctx Context, volumes []volume.Volume) error { render := func(format func(subContext SubContext) error) error { for _, vol := range volumes { - if err := format(&volumeContext{v: *vol}); err != nil { + if err := format(&volumeContext{v: vol}); err != nil { return err } } diff --git a/cli/command/formatter/volume_test.go b/cli/command/formatter/volume_test.go index f0569cc13..c25044c04 100644 --- a/cli/command/formatter/volume_test.go +++ b/cli/command/formatter/volume_test.go @@ -124,7 +124,7 @@ foobar_bar }, } - volumes := []*volume.Volume{ + volumes := []volume.Volume{ {Name: "foobar_baz", Driver: "foo"}, {Name: "foobar_bar", Driver: "bar"}, } @@ -144,7 +144,7 @@ foobar_bar } func TestVolumeContextWriteJSON(t *testing.T) { - volumes := []*volume.Volume{ + volumes := []volume.Volume{ {Driver: "foo", Name: "foobar_baz"}, {Driver: "bar", Name: "foobar_bar"}, } @@ -167,7 +167,7 @@ func TestVolumeContextWriteJSON(t *testing.T) { } func TestVolumeContextWriteJSONField(t *testing.T) { - volumes := []*volume.Volume{ + volumes := []volume.Volume{ {Driver: "foo", Name: "foobar_baz"}, {Driver: "bar", Name: "foobar_bar"}, } diff --git a/cli/command/image/import_test.go b/cli/command/image/import_test.go index cb75769c4..131233a23 100644 --- a/cli/command/image/import_test.go +++ b/cli/command/image/import_test.go @@ -50,7 +50,6 @@ func TestNewImportCommandInvalidFile(t *testing.T) { } func TestNewImportCommandSuccess(t *testing.T) { - t.Skip("FIXME(thaJeztah): how to mock this?") testCases := []struct { name string args []string diff --git a/cli/command/image/load_test.go b/cli/command/image/load_test.go index e81f8c671..0140012cf 100644 --- a/cli/command/image/load_test.go +++ b/cli/command/image/load_test.go @@ -97,7 +97,7 @@ func TestNewLoadCommandSuccess(t *testing.T) { // Body: io.NopCloser(strings.NewReader(`{"ID": "1"}`)), // JSON: true, // }, nil - return client.ImageLoadResult{}, nil + return client.ImageLoadResult{JSON: true}, nil }, }, { diff --git a/cli/command/image/remove.go b/cli/command/image/remove.go index 28069c920..ea9e513ed 100644 --- a/cli/command/image/remove.go +++ b/cli/command/image/remove.go @@ -86,7 +86,7 @@ func runRemove(ctx context.Context, dockerCLI command.Cli, opts removeOptions, i } errs = append(errs, err) } else { - for _, del := range res.Deleted { + for _, del := range res.Items { if del.Deleted != "" { _, _ = fmt.Fprintln(dockerCLI.Out(), "Deleted:", del.Deleted) } else { diff --git a/cli/command/image/remove_test.go b/cli/command/image/remove_test.go index 28ec4e932..8d6ebe825 100644 --- a/cli/command/image/remove_test.go +++ b/cli/command/image/remove_test.go @@ -88,7 +88,7 @@ func TestNewRemoveCommandSuccess(t *testing.T) { imageRemoveFunc: func(img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error) { assert.Check(t, is.Equal("image1", img)) return client.ImageRemoveResult{ - Deleted: []image.DeleteResponse{{Deleted: img}}, + Items: []image.DeleteResponse{{Deleted: img}}, }, nil }, }, @@ -109,7 +109,7 @@ func TestNewRemoveCommandSuccess(t *testing.T) { imageRemoveFunc: func(img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error) { assert.Check(t, is.Equal("image1", img)) return client.ImageRemoveResult{ - Deleted: []image.DeleteResponse{{Untagged: img}}, + Items: []image.DeleteResponse{{Untagged: img}}, }, nil }, }, @@ -119,11 +119,11 @@ func TestNewRemoveCommandSuccess(t *testing.T) { imageRemoveFunc: func(img string, options client.ImageRemoveOptions) (client.ImageRemoveResult, error) { if img == "image1" { return client.ImageRemoveResult{ - Deleted: []image.DeleteResponse{{Untagged: img}}, + Items: []image.DeleteResponse{{Untagged: img}}, }, nil } return client.ImageRemoveResult{ - Deleted: []image.DeleteResponse{{Deleted: img}}, + Items: []image.DeleteResponse{{Deleted: img}}, }, nil }, }, diff --git a/cli/command/node/demote_test.go b/cli/command/node/demote_test.go index 97a92883b..494de911e 100644 --- a/cli/command/node/demote_test.go +++ b/cli/command/node/demote_test.go @@ -59,8 +59,8 @@ func TestNodeDemoteNoChange(t *testing.T) { }, nil }, nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) { - if options.Node.Role != swarm.NodeRoleWorker { - return client.NodeUpdateResult{}, errors.New("expected role worker, got " + string(options.Node.Role)) + if options.Spec.Role != swarm.NodeRoleWorker { + return client.NodeUpdateResult{}, errors.New("expected role worker, got " + string(options.Spec.Role)) } return client.NodeUpdateResult{}, nil }, @@ -78,8 +78,8 @@ func TestNodeDemoteMultipleNode(t *testing.T) { }, nil }, nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) { - if options.Node.Role != swarm.NodeRoleWorker { - return client.NodeUpdateResult{}, errors.New("expected role worker, got " + string(options.Node.Role)) + if options.Spec.Role != swarm.NodeRoleWorker { + return client.NodeUpdateResult{}, errors.New("expected role worker, got " + string(options.Spec.Role)) } return client.NodeUpdateResult{}, nil }, diff --git a/cli/command/node/promote_test.go b/cli/command/node/promote_test.go index 83bbabec3..d91169acc 100644 --- a/cli/command/node/promote_test.go +++ b/cli/command/node/promote_test.go @@ -59,8 +59,8 @@ func TestNodePromoteNoChange(t *testing.T) { }, nil }, nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) { - if options.Node.Role != swarm.NodeRoleManager { - return client.NodeUpdateResult{}, errors.New("expected role manager, got" + string(options.Node.Role)) + if options.Spec.Role != swarm.NodeRoleManager { + return client.NodeUpdateResult{}, errors.New("expected role manager, got" + string(options.Spec.Role)) } return client.NodeUpdateResult{}, nil }, @@ -78,8 +78,8 @@ func TestNodePromoteMultipleNode(t *testing.T) { }, nil }, nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) { - if options.Node.Role != swarm.NodeRoleManager { - return client.NodeUpdateResult{}, errors.New("expected role manager, got" + string(options.Node.Role)) + if options.Spec.Role != swarm.NodeRoleManager { + return client.NodeUpdateResult{}, errors.New("expected role manager, got" + string(options.Spec.Role)) } return client.NodeUpdateResult{}, nil }, diff --git a/cli/command/node/update.go b/cli/command/node/update.go index 874dca33c..1bfd4949e 100644 --- a/cli/command/node/update.go +++ b/cli/command/node/update.go @@ -66,7 +66,7 @@ func updateNodes(ctx context.Context, apiClient client.NodeAPIClient, nodes []st } _, err = apiClient.NodeUpdate(ctx, res.Node.ID, client.NodeUpdateOptions{ Version: res.Node.Version, - Node: res.Node.Spec, + Spec: res.Node.Spec, }) if err != nil { return err diff --git a/cli/command/node/update_test.go b/cli/command/node/update_test.go index fd1fbb484..2ce4b6593 100644 --- a/cli/command/node/update_test.go +++ b/cli/command/node/update_test.go @@ -91,8 +91,8 @@ func TestNodeUpdate(t *testing.T) { }, nil }, nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) { - if options.Node.Role != swarm.NodeRoleManager { - return client.NodeUpdateResult{}, errors.New("expected role manager, got " + string(options.Node.Role)) + if options.Spec.Role != swarm.NodeRoleManager { + return client.NodeUpdateResult{}, errors.New("expected role manager, got " + string(options.Spec.Role)) } return client.NodeUpdateResult{}, nil }, @@ -108,8 +108,8 @@ func TestNodeUpdate(t *testing.T) { }, nil }, nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) { - if options.Node.Availability != swarm.NodeAvailabilityDrain { - return client.NodeUpdateResult{}, errors.New("expected drain availability, got " + string(options.Node.Availability)) + if options.Spec.Availability != swarm.NodeAvailabilityDrain { + return client.NodeUpdateResult{}, errors.New("expected drain availability, got " + string(options.Spec.Availability)) } return client.NodeUpdateResult{}, nil }, @@ -125,8 +125,8 @@ func TestNodeUpdate(t *testing.T) { }, nil }, nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) { - if _, present := options.Node.Annotations.Labels["lbl"]; !present { - return client.NodeUpdateResult{}, fmt.Errorf("expected 'lbl' label, got %v", options.Node.Annotations.Labels) + if _, present := options.Spec.Annotations.Labels["lbl"]; !present { + return client.NodeUpdateResult{}, fmt.Errorf("expected 'lbl' label, got %v", options.Spec.Annotations.Labels) } return client.NodeUpdateResult{}, nil }, @@ -142,8 +142,8 @@ func TestNodeUpdate(t *testing.T) { }, nil }, nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) { - if value, present := options.Node.Annotations.Labels["key"]; !present || value != "value" { - return client.NodeUpdateResult{}, fmt.Errorf("expected 'key' label to be 'value', got %v", options.Node.Annotations.Labels) + if value, present := options.Spec.Annotations.Labels["key"]; !present || value != "value" { + return client.NodeUpdateResult{}, fmt.Errorf("expected 'key' label to be 'value', got %v", options.Spec.Annotations.Labels) } return client.NodeUpdateResult{}, nil }, @@ -161,8 +161,8 @@ func TestNodeUpdate(t *testing.T) { }, nil }, nodeUpdateFunc: func(nodeID string, options client.NodeUpdateOptions) (client.NodeUpdateResult, error) { - if len(options.Node.Annotations.Labels) > 0 { - return client.NodeUpdateResult{}, fmt.Errorf("expected no labels, got %v", options.Node.Annotations.Labels) + if len(options.Spec.Annotations.Labels) > 0 { + return client.NodeUpdateResult{}, fmt.Errorf("expected no labels, got %v", options.Spec.Annotations.Labels) } return client.NodeUpdateResult{}, nil }, diff --git a/cli/command/plugin/client_test.go b/cli/command/plugin/client_test.go index feefb9048..455af0b43 100644 --- a/cli/command/plugin/client_test.go +++ b/cli/command/plugin/client_test.go @@ -3,6 +3,7 @@ package plugin import ( "context" "io" + "strings" "github.com/moby/moby/api/types/system" "github.com/moby/moby/client" @@ -78,5 +79,5 @@ func (c *fakeClient) PluginUpgrade(_ context.Context, name string, options clien return c.pluginUpgradeFunc(name, options) } // FIXME(thaJeztah): how to mock this? - return nil, nil + return io.NopCloser(strings.NewReader("")), nil } diff --git a/cli/command/service/client_test.go b/cli/command/service/client_test.go index 8573b546e..0e72b13a8 100644 --- a/cli/command/service/client_test.go +++ b/cli/command/service/client_test.go @@ -12,7 +12,7 @@ import ( type fakeClient struct { client.Client serviceInspectFunc func(ctx context.Context, serviceID string, options client.ServiceInspectOptions) (client.ServiceInspectResult, error) - serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) + serviceUpdateFunc func(ctx context.Context, serviceID string, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) serviceListFunc func(context.Context, client.ServiceListOptions) (client.ServiceListResult, error) taskListFunc func(context.Context, client.TaskListOptions) (client.TaskListResult, error) infoFunc func(ctx context.Context) (system.Info, error) @@ -52,9 +52,9 @@ func (f *fakeClient) ServiceList(ctx context.Context, options client.ServiceList return client.ServiceListResult{}, nil } -func (f *fakeClient) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) { +func (f *fakeClient) ServiceUpdate(ctx context.Context, serviceID string, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) { if f.serviceUpdateFunc != nil { - return f.serviceUpdateFunc(ctx, serviceID, version, service, options) + return f.serviceUpdateFunc(ctx, serviceID, options) } return client.ServiceUpdateResult{}, nil diff --git a/cli/command/service/create.go b/cli/command/service/create.go index c3c9565b1..cea9a91d1 100644 --- a/cli/command/service/create.go +++ b/cli/command/service/create.go @@ -95,7 +95,6 @@ func newCreateCommand(dockerCLI command.Cli) *cobra.Command { func runCreate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, opts *serviceOptions) error { apiClient := dockerCLI.Client() - createOpts := client.ServiceCreateOptions{} service, err := opts.ToService(ctx, apiClient, flags) if err != nil { @@ -121,19 +120,22 @@ func runCreate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, } // only send auth if flag was set + var encodedAuth string if opts.registryAuth { // Retrieve encoded auth token from the image reference - encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCLI.ConfigFile(), opts.image) + var err error + encodedAuth, err = command.RetrieveAuthTokenFromImage(dockerCLI.ConfigFile(), opts.image) if err != nil { return err } - createOpts.EncodedRegistryAuth = encodedAuth } - // query registry if flag disabling it was not set - createOpts.QueryRegistry = !opts.noResolveImage + response, err := apiClient.ServiceCreate(ctx, client.ServiceCreateOptions{ + Spec: service, - response, err := apiClient.ServiceCreate(ctx, service, createOpts) + EncodedRegistryAuth: encodedAuth, + QueryRegistry: !opts.noResolveImage, // query registry if flag disabling it was not set. + }) if err != nil { return err } diff --git a/cli/command/service/rollback.go b/cli/command/service/rollback.go index f99c83fdf..e3ca98e23 100644 --- a/cli/command/service/rollback.go +++ b/cli/command/service/rollback.go @@ -40,7 +40,9 @@ func runRollback(ctx context.Context, dockerCLI command.Cli, options *serviceOpt return err } - response, err := apiClient.ServiceUpdate(ctx, res.Service.ID, res.Service.Version, res.Service.Spec, client.ServiceUpdateOptions{ + response, err := apiClient.ServiceUpdate(ctx, res.Service.ID, client.ServiceUpdateOptions{ + Version: res.Service.Version, + Spec: res.Service.Spec, Rollback: "previous", // TODO(thaJeztah): this should have a const defined }) if err != nil { diff --git a/cli/command/service/rollback_test.go b/cli/command/service/rollback_test.go index e41904c38..19842888b 100644 --- a/cli/command/service/rollback_test.go +++ b/cli/command/service/rollback_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/moby/moby/api/types/swarm" "github.com/moby/moby/client" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" @@ -18,7 +17,7 @@ func TestRollback(t *testing.T) { testCases := []struct { name string args []string - serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) + serviceUpdateFunc func(ctx context.Context, serviceID string, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) expectedDockerCliErr string }{ { @@ -28,7 +27,7 @@ func TestRollback(t *testing.T) { { name: "rollback-service-with-warnings", args: []string{"service-id"}, - serviceUpdateFunc: func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) { + serviceUpdateFunc: func(ctx context.Context, serviceID string, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) { return client.ServiceUpdateResult{ Warnings: []string{ "- warning 1", @@ -59,7 +58,7 @@ func TestRollbackWithErrors(t *testing.T) { name string args []string serviceInspectFunc func(ctx context.Context, serviceID string, options client.ServiceInspectOptions) (client.ServiceInspectResult, error) - serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, opts client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) + serviceUpdateFunc func(ctx context.Context, serviceID string, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) expectedError string }{ { @@ -82,7 +81,7 @@ func TestRollbackWithErrors(t *testing.T) { { name: "service-update-failed", args: []string{"service-id"}, - serviceUpdateFunc: func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) { + serviceUpdateFunc: func(ctx context.Context, serviceID string, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) { return client.ServiceUpdateResult{}, fmt.Errorf("no such services: %s", serviceID) }, expectedError: "no such services: service-id", diff --git a/cli/command/service/scale.go b/cli/command/service/scale.go index 8f3df7b2d..a2555ab98 100644 --- a/cli/command/service/scale.go +++ b/cli/command/service/scale.go @@ -108,7 +108,10 @@ func runServiceScale(ctx context.Context, apiClient client.ServiceAPIClient, ser return nil, errors.New("scale can only be used with replicated or replicated-job mode") } - response, err := apiClient.ServiceUpdate(ctx, res.Service.ID, res.Service.Version, res.Service.Spec, client.ServiceUpdateOptions{}) + response, err := apiClient.ServiceUpdate(ctx, res.Service.ID, client.ServiceUpdateOptions{ + Version: res.Service.Version, + Spec: res.Service.Spec, + }) if err != nil { return nil, err } diff --git a/cli/command/service/update.go b/cli/command/service/update.go index fa4ae5dd2..38913e3d2 100644 --- a/cli/command/service/update.go +++ b/cli/command/service/update.go @@ -46,14 +46,14 @@ func newUpdateCommand(dockerCLI command.Cli) *cobra.Command { flags.String("image", "", "Service image tag") flags.Var(&ShlexOpt{}, "args", "Service command args") flags.Bool(flagRollback, false, "Rollback to previous specification") - flags.SetAnnotation(flagRollback, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagRollback, "version", []string{"1.25"}) flags.Bool("force", false, "Force update even if no changes require it") - flags.SetAnnotation("force", "version", []string{"1.25"}) + _ = flags.SetAnnotation("force", "version", []string{"1.25"}) addServiceFlags(flags, options, nil) flags.Var(newListOptsVar(), flagEnvRemove, "Remove an environment variable") flags.Var(newListOptsVar(), flagGroupRemove, "Remove a previously added supplementary user group from the container") - flags.SetAnnotation(flagGroupRemove, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagGroupRemove, "version", []string{"1.25"}) flags.Var(newListOptsVar(), flagLabelRemove, "Remove a label by its key") flags.Var(newListOptsVar(), flagContainerLabelRemove, "Remove a container label by its key") flags.Var(newListOptsVar(), flagMountRemove, "Remove a mount by its target path") @@ -61,65 +61,65 @@ func newUpdateCommand(dockerCLI command.Cli) *cobra.Command { flags.Var(&swarmopts.PortOpt{}, flagPublishRemove, "Remove a published port by its target port") flags.Var(newListOptsVar(), flagConstraintRemove, "Remove a constraint") flags.Var(newListOptsVar(), flagDNSRemove, "Remove a custom DNS server") - flags.SetAnnotation(flagDNSRemove, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagDNSRemove, "version", []string{"1.25"}) flags.Var(newListOptsVar(), flagDNSOptionRemove, "Remove a DNS option") - flags.SetAnnotation(flagDNSOptionRemove, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagDNSOptionRemove, "version", []string{"1.25"}) flags.Var(newListOptsVar(), flagDNSSearchRemove, "Remove a DNS search domain") - flags.SetAnnotation(flagDNSSearchRemove, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagDNSSearchRemove, "version", []string{"1.25"}) flags.Var(newListOptsVar(), flagHostRemove, `Remove a custom host-to-IP mapping ("host:ip")`) - flags.SetAnnotation(flagHostRemove, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagHostRemove, "version", []string{"1.25"}) flags.Var(&options.labels, flagLabelAdd, "Add or update a service label") flags.Var(&options.containerLabels, flagContainerLabelAdd, "Add or update a container label") flags.Var(&options.env, flagEnvAdd, "Add or update an environment variable") flags.Var(newListOptsVar(), flagSecretRemove, "Remove a secret") - flags.SetAnnotation(flagSecretRemove, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagSecretRemove, "version", []string{"1.25"}) flags.Var(&options.secrets, flagSecretAdd, "Add or update a secret on a service") - flags.SetAnnotation(flagSecretAdd, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagSecretAdd, "version", []string{"1.25"}) flags.Var(newListOptsVar(), flagConfigRemove, "Remove a configuration file") - flags.SetAnnotation(flagConfigRemove, "version", []string{"1.30"}) + _ = flags.SetAnnotation(flagConfigRemove, "version", []string{"1.30"}) flags.Var(&options.configs, flagConfigAdd, "Add or update a config file on a service") - flags.SetAnnotation(flagConfigAdd, "version", []string{"1.30"}) + _ = flags.SetAnnotation(flagConfigAdd, "version", []string{"1.30"}) flags.Var(&options.mounts, flagMountAdd, "Add or update a mount on a service") flags.Var(&options.constraints, flagConstraintAdd, "Add or update a placement constraint") flags.Var(&options.placementPrefs, flagPlacementPrefAdd, "Add a placement preference") - flags.SetAnnotation(flagPlacementPrefAdd, "version", []string{"1.28"}) + _ = flags.SetAnnotation(flagPlacementPrefAdd, "version", []string{"1.28"}) flags.Var(&placementPrefOpts{}, flagPlacementPrefRemove, "Remove a placement preference") - flags.SetAnnotation(flagPlacementPrefRemove, "version", []string{"1.28"}) + _ = flags.SetAnnotation(flagPlacementPrefRemove, "version", []string{"1.28"}) flags.Var(&options.networks, flagNetworkAdd, "Add a network") - flags.SetAnnotation(flagNetworkAdd, "version", []string{"1.29"}) + _ = flags.SetAnnotation(flagNetworkAdd, "version", []string{"1.29"}) flags.Var(newListOptsVar(), flagNetworkRemove, "Remove a network") - flags.SetAnnotation(flagNetworkRemove, "version", []string{"1.29"}) + _ = flags.SetAnnotation(flagNetworkRemove, "version", []string{"1.29"}) flags.Var(&options.endpoint.publishPorts, flagPublishAdd, "Add or update a published port") flags.Var(&options.groups, flagGroupAdd, "Add an additional supplementary user group to the container") - flags.SetAnnotation(flagGroupAdd, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagGroupAdd, "version", []string{"1.25"}) flags.Var(&options.dns, flagDNSAdd, "Add or update a custom DNS server") - flags.SetAnnotation(flagDNSAdd, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagDNSAdd, "version", []string{"1.25"}) flags.Var(&options.dnsOption, flagDNSOptionAdd, "Add or update a DNS option") - flags.SetAnnotation(flagDNSOptionAdd, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagDNSOptionAdd, "version", []string{"1.25"}) flags.Var(&options.dnsSearch, flagDNSSearchAdd, "Add or update a custom DNS search domain") - flags.SetAnnotation(flagDNSSearchAdd, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagDNSSearchAdd, "version", []string{"1.25"}) flags.Var(&options.hosts, flagHostAdd, `Add a custom host-to-IP mapping ("host:ip")`) - flags.SetAnnotation(flagHostAdd, "version", []string{"1.25"}) + _ = flags.SetAnnotation(flagHostAdd, "version", []string{"1.25"}) flags.BoolVar(&options.init, flagInit, false, "Use an init inside each service container to forward signals and reap processes") - flags.SetAnnotation(flagInit, "version", []string{"1.37"}) + _ = flags.SetAnnotation(flagInit, "version", []string{"1.37"}) flags.Var(&options.sysctls, flagSysCtlAdd, "Add or update a Sysctl option") - flags.SetAnnotation(flagSysCtlAdd, "version", []string{"1.40"}) + _ = flags.SetAnnotation(flagSysCtlAdd, "version", []string{"1.40"}) flags.Var(newListOptsVar(), flagSysCtlRemove, "Remove a Sysctl option") - flags.SetAnnotation(flagSysCtlRemove, "version", []string{"1.40"}) + _ = flags.SetAnnotation(flagSysCtlRemove, "version", []string{"1.40"}) flags.Var(&options.ulimits, flagUlimitAdd, "Add or update a ulimit option") - flags.SetAnnotation(flagUlimitAdd, "version", []string{"1.41"}) + _ = flags.SetAnnotation(flagUlimitAdd, "version", []string{"1.41"}) flags.Var(newListOptsVar(), flagUlimitRemove, "Remove a ulimit option") - flags.SetAnnotation(flagUlimitRemove, "version", []string{"1.41"}) + _ = flags.SetAnnotation(flagUlimitRemove, "version", []string{"1.41"}) flags.Int64Var(&options.oomScoreAdj, flagOomScoreAdj, 0, "Tune host's OOM preferences (-1000 to 1000) ") - flags.SetAnnotation(flagOomScoreAdj, "version", []string{"1.46"}) + _ = flags.SetAnnotation(flagOomScoreAdj, "version", []string{"1.46"}) // Add needs parsing, Remove only needs the key flags.Var(newListOptsVar(), flagGenericResourcesRemove, "Remove a Generic resource") - flags.SetAnnotation(flagGenericResourcesRemove, "version", []string{"1.32"}) + _ = flags.SetAnnotation(flagGenericResourcesRemove, "version", []string{"1.32"}) flags.Var(newListOptsVarWithValidator(ValidateSingleGenericResource), flagGenericResourcesAdd, "Add a Generic resource") - flags.SetAnnotation(flagGenericResourcesAdd, "version", []string{"1.32"}) + _ = flags.SetAnnotation(flagGenericResourcesAdd, "version", []string{"1.32"}) // TODO(thaJeztah): add completion for capabilities, stop-signal (currently non-exported in container package) // _ = cmd.RegisterFlagCompletionFunc(flagCapAdd, completeLinuxCapabilityNames) @@ -164,7 +164,6 @@ func runUpdate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, return err } - spec := &res.Service.Spec if rollback { // Rollback can't be combined with other flags. otherFlagsPassed := false @@ -182,10 +181,12 @@ func runUpdate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, } updateOpts := client.ServiceUpdateOptions{} + rollbackAction := "none" if rollback { - updateOpts.Rollback = "previous" + rollbackAction = "previous" } + spec := &res.Service.Spec err = updateService(ctx, apiClient, flags, spec) if err != nil { return err @@ -202,14 +203,12 @@ func runUpdate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, if err != nil { return err } - spec.TaskTemplate.ContainerSpec.Secrets = updatedSecrets updatedConfigs, err := getUpdatedConfigs(ctx, apiClient, flags, spec.TaskTemplate.ContainerSpec) if err != nil { return err } - spec.TaskTemplate.ContainerSpec.Configs = updatedConfigs // set the credential spec value after get the updated configs, because we @@ -218,24 +217,31 @@ func runUpdate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, updateCredSpecConfig(flags, spec.TaskTemplate.ContainerSpec) // only send auth if flag was set - sendAuth, err := flags.GetBool(flagRegistryAuth) - if err != nil { + var encodedAuth string + var registryAuthFrom string + if ok, err := flags.GetBool(flagRegistryAuth); err != nil { return err - } - if sendAuth { + } else if ok { // Retrieve encoded auth token from the image reference // This would be the old image if it didn't change in this update - image := spec.TaskTemplate.ContainerSpec.Image - encodedAuth, err := command.RetrieveAuthTokenFromImage(dockerCLI.ConfigFile(), image) + var err error + encodedAuth, err = command.RetrieveAuthTokenFromImage(dockerCLI.ConfigFile(), spec.TaskTemplate.ContainerSpec.Image) if err != nil { return err } updateOpts.EncodedRegistryAuth = encodedAuth } else { - updateOpts.RegistryAuthFrom = swarm.RegistryAuthFromSpec + registryAuthFrom = swarm.RegistryAuthFromSpec } - response, err := apiClient.ServiceUpdate(ctx, res.Service.ID, res.Service.Version, *spec, updateOpts) + response, err := apiClient.ServiceUpdate(ctx, res.Service.ID, client.ServiceUpdateOptions{ + Version: res.Service.Version, + Spec: *spec, + + EncodedRegistryAuth: encodedAuth, + RegistryAuthFrom: registryAuthFrom, + Rollback: rollbackAction, + }) if err != nil { return err } diff --git a/cli/command/stack/client_test.go b/cli/command/stack/client_test.go index 95b271740..2855583f5 100644 --- a/cli/command/stack/client_test.go +++ b/cli/command/stack/client_test.go @@ -31,7 +31,7 @@ type fakeClient struct { nodeListFunc func(options client.NodeListOptions) (client.NodeListResult, error) taskListFunc func(options client.TaskListOptions) (client.TaskListResult, error) nodeInspectFunc func(ref string) (client.NodeInspectResult, error) - serviceUpdateFunc func(serviceID string, version swarm.Version, service swarm.ServiceSpec, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) + serviceUpdateFunc func(serviceID string, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) serviceRemoveFunc func(serviceID string) (client.ServiceRemoveResult, error) networkRemoveFunc func(networkID string) error secretRemoveFunc func(secretID string) (client.SecretRemoveResult, error) @@ -130,9 +130,9 @@ func (cli *fakeClient) NodeInspect(_ context.Context, ref string, _ client.NodeI return client.NodeInspectResult{}, nil } -func (cli *fakeClient) ServiceUpdate(_ context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) { +func (cli *fakeClient) ServiceUpdate(_ context.Context, serviceID string, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) { if cli.serviceUpdateFunc != nil { - return cli.serviceUpdateFunc(serviceID, version, service, options) + return cli.serviceUpdateFunc(serviceID, options) } return client.ServiceUpdateResult{}, nil diff --git a/cli/command/stack/deploy_composefile.go b/cli/command/stack/deploy_composefile.go index a6c190881..ad8576513 100644 --- a/cli/command/stack/deploy_composefile.go +++ b/cli/command/stack/deploy_composefile.go @@ -233,7 +233,10 @@ func deployServices(ctx context.Context, dockerCLI command.Cli, services map[str if svc, exists := existingServiceMap[name]; exists { _, _ = fmt.Fprintf(out, "Updating service %s (id: %s)\n", name, svc.ID) - updateOpts := client.ServiceUpdateOptions{EncodedRegistryAuth: encodedAuth} + updateOpts := client.ServiceUpdateOptions{ + Version: svc.Version, + EncodedRegistryAuth: encodedAuth, + } switch resolveImage { case resolveImageAlways: @@ -265,7 +268,8 @@ func deployServices(ctx context.Context, dockerCLI command.Cli, services map[str // TODO move this to API client? serviceSpec.TaskTemplate.ForceUpdate = svc.Spec.TaskTemplate.ForceUpdate - response, err := apiClient.ServiceUpdate(ctx, svc.ID, svc.Version, serviceSpec, updateOpts) + updateOpts.Spec = serviceSpec + response, err := apiClient.ServiceUpdate(ctx, svc.ID, updateOpts) if err != nil { return nil, fmt.Errorf("failed to update service %s: %w", name, err) } @@ -281,7 +285,8 @@ func deployServices(ctx context.Context, dockerCLI command.Cli, services map[str // query registry if flag disabling it was not set queryRegistry := resolveImage == resolveImageAlways || resolveImage == resolveImageChanged - response, err := apiClient.ServiceCreate(ctx, serviceSpec, client.ServiceCreateOptions{ + response, err := apiClient.ServiceCreate(ctx, client.ServiceCreateOptions{ + Spec: serviceSpec, EncodedRegistryAuth: encodedAuth, QueryRegistry: queryRegistry, }) diff --git a/cli/command/stack/deploy_test.go b/cli/command/stack/deploy_test.go index 6aad4d0e4..a0fb1fd0c 100644 --- a/cli/command/stack/deploy_test.go +++ b/cli/command/stack/deploy_test.go @@ -42,10 +42,7 @@ func TestPruneServices(t *testing.T) { func TestServiceUpdateResolveImageChanged(t *testing.T) { namespace := convert.NewNamespace("mystack") - var ( - receivedOptions client.ServiceUpdateOptions - receivedService swarm.ServiceSpec - ) + var receivedOptions client.ServiceUpdateOptions fakeCli := test.NewFakeCli(&fakeClient{ serviceListFunc: func(options client.ServiceListOptions) (client.ServiceListResult, error) { @@ -68,9 +65,8 @@ func TestServiceUpdateResolveImageChanged(t *testing.T) { }, }, nil }, - serviceUpdateFunc: func(serviceID string, version swarm.Version, service swarm.ServiceSpec, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) { + serviceUpdateFunc: func(serviceID string, options client.ServiceUpdateOptions) (client.ServiceUpdateResult, error) { receivedOptions = options - receivedService = service return client.ServiceUpdateResult{}, nil }, }) @@ -113,10 +109,9 @@ func TestServiceUpdateResolveImageChanged(t *testing.T) { _, err := deployServices(ctx, fakeCli, spec, namespace, false, resolveImageChanged) assert.NilError(t, err) assert.Check(t, is.Equal(receivedOptions.QueryRegistry, tc.expectedQueryRegistry)) - assert.Check(t, is.Equal(receivedService.TaskTemplate.ContainerSpec.Image, tc.expectedImage)) - assert.Check(t, is.Equal(receivedService.TaskTemplate.ForceUpdate, tc.expectedForceUpdate)) + assert.Check(t, is.Equal(receivedOptions.Spec.TaskTemplate.ContainerSpec.Image, tc.expectedImage)) + assert.Check(t, is.Equal(receivedOptions.Spec.TaskTemplate.ForceUpdate, tc.expectedForceUpdate)) - receivedService = swarm.ServiceSpec{} receivedOptions = client.ServiceUpdateOptions{} }) } diff --git a/cli/command/swarm/ca.go b/cli/command/swarm/ca.go index 2e4578d0a..749afd860 100644 --- a/cli/command/swarm/ca.go +++ b/cli/command/swarm/ca.go @@ -84,8 +84,9 @@ func runCA(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, opt } updateSwarmSpec(&res.Swarm.Spec, flags, opts) - if _, err := apiClient.SwarmUpdate(ctx, res.Swarm.Version, client.SwarmUpdateOptions{ - Swarm: res.Swarm.Spec, + if _, err := apiClient.SwarmUpdate(ctx, client.SwarmUpdateOptions{ + Version: res.Swarm.Version, + Spec: res.Swarm.Spec, }); err != nil { return err } diff --git a/cli/command/swarm/ca_test.go b/cli/command/swarm/ca_test.go index 904f405ee..870f9b49f 100644 --- a/cli/command/swarm/ca_test.go +++ b/cli/command/swarm/ca_test.go @@ -173,7 +173,7 @@ type swarmUpdateRecorder struct { } func (s *swarmUpdateRecorder) swarmUpdate(opts client.SwarmUpdateOptions) (client.SwarmUpdateResult, error) { - s.spec = opts.Swarm + s.spec = opts.Spec return client.SwarmUpdateResult{}, nil } diff --git a/cli/command/swarm/client_test.go b/cli/command/swarm/client_test.go index 8682a5827..8c5a42a88 100644 --- a/cli/command/swarm/client_test.go +++ b/cli/command/swarm/client_test.go @@ -3,7 +3,6 @@ package swarm import ( "context" - "github.com/moby/moby/api/types/swarm" "github.com/moby/moby/api/types/system" "github.com/moby/moby/client" ) @@ -70,7 +69,7 @@ func (cli *fakeClient) SwarmLeave(context.Context, client.SwarmLeaveOptions) (cl return client.SwarmLeaveResult{}, nil } -func (cli *fakeClient) SwarmUpdate(_ context.Context, _ swarm.Version, options client.SwarmUpdateOptions) (client.SwarmUpdateResult, error) { +func (cli *fakeClient) SwarmUpdate(_ context.Context, options client.SwarmUpdateOptions) (client.SwarmUpdateResult, error) { if cli.swarmUpdateFunc != nil { return cli.swarmUpdateFunc(options) } diff --git a/cli/command/swarm/join_token.go b/cli/command/swarm/join_token.go index 364f61602..4639035c7 100644 --- a/cli/command/swarm/join_token.go +++ b/cli/command/swarm/join_token.go @@ -58,8 +58,9 @@ func runJoinToken(ctx context.Context, dockerCLI command.Cli, opts joinTokenOpti return err } - _, err = apiClient.SwarmUpdate(ctx, res.Swarm.Version, client.SwarmUpdateOptions{ - Swarm: res.Swarm.Spec, + _, err = apiClient.SwarmUpdate(ctx, client.SwarmUpdateOptions{ + Version: res.Swarm.Version, + Spec: res.Swarm.Spec, RotateWorkerToken: worker, RotateManagerToken: manager, }) diff --git a/cli/command/swarm/unlock_key.go b/cli/command/swarm/unlock_key.go index 6e6cba2b1..a8df5089e 100644 --- a/cli/command/swarm/unlock_key.go +++ b/cli/command/swarm/unlock_key.go @@ -55,8 +55,10 @@ func runUnlockKey(ctx context.Context, dockerCLI command.Cli, opts unlockKeyOpti return errors.New("cannot rotate because autolock is not turned on") } - _, err = apiClient.SwarmUpdate(ctx, res.Swarm.Version, client.SwarmUpdateOptions{ - Swarm: res.Swarm.Spec, + _, err = apiClient.SwarmUpdate(ctx, client.SwarmUpdateOptions{ + Version: res.Swarm.Version, + Spec: res.Swarm.Spec, + RotateManagerUnlockKey: true, }) if err != nil { diff --git a/cli/command/swarm/update.go b/cli/command/swarm/update.go index c691a7fc9..9dc373211 100644 --- a/cli/command/swarm/update.go +++ b/cli/command/swarm/update.go @@ -54,8 +54,9 @@ func runUpdate(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, curAutoLock := sw.Swarm.Spec.EncryptionConfig.AutoLockManagers - _, err = apiClient.SwarmUpdate(ctx, sw.Swarm.Version, client.SwarmUpdateOptions{ - Swarm: sw.Swarm.Spec, + _, err = apiClient.SwarmUpdate(ctx, client.SwarmUpdateOptions{ + Version: sw.Swarm.Version, + Spec: sw.Swarm.Spec, }) if err != nil { return err diff --git a/cli/command/swarm/update_test.go b/cli/command/swarm/update_test.go index 58cf9febb..c611b269f 100644 --- a/cli/command/swarm/update_test.go +++ b/cli/command/swarm/update_test.go @@ -120,33 +120,33 @@ func TestSwarmUpdate(t *testing.T) { }, nil }, swarmUpdateFunc: func(options client.SwarmUpdateOptions) (client.SwarmUpdateResult, error) { - if *options.Swarm.Orchestration.TaskHistoryRetentionLimit != 10 { + if *options.Spec.Orchestration.TaskHistoryRetentionLimit != 10 { return client.SwarmUpdateResult{}, errors.New("historyLimit not correctly set") } heartbeatDuration, err := time.ParseDuration("10s") if err != nil { return client.SwarmUpdateResult{}, err } - if options.Swarm.Dispatcher.HeartbeatPeriod != heartbeatDuration { + if options.Spec.Dispatcher.HeartbeatPeriod != heartbeatDuration { return client.SwarmUpdateResult{}, errors.New("heartbeatPeriodLimit not correctly set") } certExpiryDuration, err := time.ParseDuration("20s") if err != nil { return client.SwarmUpdateResult{}, err } - if options.Swarm.CAConfig.NodeCertExpiry != certExpiryDuration { + if options.Spec.CAConfig.NodeCertExpiry != certExpiryDuration { return client.SwarmUpdateResult{}, errors.New("certExpiry not correctly set") } - if len(options.Swarm.CAConfig.ExternalCAs) != 1 || options.Swarm.CAConfig.ExternalCAs[0].CACert != "trust-root" { + if len(options.Spec.CAConfig.ExternalCAs) != 1 || options.Spec.CAConfig.ExternalCAs[0].CACert != "trust-root" { return client.SwarmUpdateResult{}, errors.New("externalCA not correctly set") } - if *options.Swarm.Raft.KeepOldSnapshots != 10 { + if *options.Spec.Raft.KeepOldSnapshots != 10 { return client.SwarmUpdateResult{}, errors.New("keepOldSnapshots not correctly set") } - if options.Swarm.Raft.SnapshotInterval != 100 { + if options.Spec.Raft.SnapshotInterval != 100 { return client.SwarmUpdateResult{}, errors.New("snapshotInterval not correctly set") } - if !options.Swarm.EncryptionConfig.AutoLockManagers { + if !options.Spec.EncryptionConfig.AutoLockManagers { return client.SwarmUpdateResult{}, errors.New("auto-lock not correctly set") } return client.SwarmUpdateResult{}, nil @@ -159,7 +159,7 @@ func TestSwarmUpdate(t *testing.T) { flagAutolock: "true", }, swarmUpdateFunc: func(options client.SwarmUpdateOptions) (client.SwarmUpdateResult, error) { - if *options.Swarm.Orchestration.TaskHistoryRetentionLimit != 10 { + if *options.Spec.Orchestration.TaskHistoryRetentionLimit != 10 { return client.SwarmUpdateResult{}, errors.New("historyLimit not correctly set") } return client.SwarmUpdateResult{}, nil diff --git a/cli/command/system/completion.go b/cli/command/system/completion.go index 122aaf0bf..55540de07 100644 --- a/cli/command/system/completion.go +++ b/cli/command/system/completion.go @@ -309,8 +309,8 @@ func volumeNames(dockerCLI completion.APIClientProvider, cmd *cobra.Command) []s if err != nil { return []string{} } - names := make([]string, 0, len(res.Items.Volumes)) - for _, v := range res.Items.Volumes { + names := make([]string, 0, len(res.Items)) + for _, v := range res.Items { names = append(names, v.Name) } return names diff --git a/cli/command/system/completion_test.go b/cli/command/system/completion_test.go index d6acacc89..48890dc71 100644 --- a/cli/command/system/completion_test.go +++ b/cli/command/system/completion_test.go @@ -139,11 +139,9 @@ func TestCompleteEventFilter(t *testing.T) { client: &fakeClient{ volumeListFunc: func(ctx context.Context, options client.VolumeListOptions) (client.VolumeListResult, error) { return client.VolumeListResult{ - Items: volume.ListResponse{ - Volumes: []*volume.Volume{ - builders.Volume(builders.VolumeName("v1")), - builders.Volume(builders.VolumeName("v2")), - }, + Items: []volume.Volume{ + builders.Volume(builders.VolumeName("v1")), + builders.Volume(builders.VolumeName("v2")), }, }, nil }, diff --git a/cli/command/volume/inspect_test.go b/cli/command/volume/inspect_test.go index 90cd97349..e56d0a4fa 100644 --- a/cli/command/volume/inspect_test.go +++ b/cli/command/volume/inspect_test.go @@ -84,7 +84,7 @@ func TestVolumeInspectWithoutFormat(t *testing.T) { return client.VolumeInspectResult{}, fmt.Errorf("invalid volumeID, expected %s, got %s", "foo", volumeID) } return client.VolumeInspectResult{ - Volume: *builders.Volume(), + Volume: builders.Volume(), }, nil }, }, @@ -93,7 +93,7 @@ func TestVolumeInspectWithoutFormat(t *testing.T) { args: []string{"foo", "bar"}, volumeInspectFunc: func(volumeID string) (client.VolumeInspectResult, error) { return client.VolumeInspectResult{ - Volume: *builders.Volume(builders.VolumeName(volumeID), builders.VolumeLabels(map[string]string{ + Volume: builders.Volume(builders.VolumeName(volumeID), builders.VolumeLabels(map[string]string{ "foo": "bar", })), }, nil @@ -114,7 +114,7 @@ func TestVolumeInspectWithoutFormat(t *testing.T) { func TestVolumeInspectWithFormat(t *testing.T) { volumeInspectFunc := func(volumeID string) (client.VolumeInspectResult, error) { return client.VolumeInspectResult{ - Volume: *builders.Volume(builders.VolumeLabels(map[string]string{ + Volume: builders.Volume(builders.VolumeLabels(map[string]string{ "foo": "bar", })), }, nil diff --git a/cli/command/volume/list.go b/cli/command/volume/list.go index 3d797111f..1e0df1f84 100644 --- a/cli/command/volume/list.go +++ b/cli/command/volume/list.go @@ -71,13 +71,13 @@ func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) er // trick for filtering in place n := 0 - for _, vol := range res.Items.Volumes { + for _, vol := range res.Items { if vol.ClusterVolume != nil { - res.Items.Volumes[n] = vol + res.Items[n] = vol n++ } } - res.Items.Volumes = res.Items.Volumes[:n] + res.Items = res.Items[:n] if !options.quiet { format = clusterTableFormat } else { @@ -85,13 +85,13 @@ func runList(ctx context.Context, dockerCLI command.Cli, options listOptions) er } } - sort.Slice(res.Items.Volumes, func(i, j int) bool { - return sortorder.NaturalLess(res.Items.Volumes[i].Name, res.Items.Volumes[j].Name) + sort.Slice(res.Items, func(i, j int) bool { + return sortorder.NaturalLess(res.Items[i].Name, res.Items[j].Name) }) volumeCtx := formatter.Context{ Output: dockerCLI.Out(), Format: formatter.NewVolumeFormat(format, options.quiet), } - return formatter.VolumeWrite(volumeCtx, res.Items.Volumes) + return formatter.VolumeWrite(volumeCtx, res.Items) } diff --git a/cli/command/volume/list_test.go b/cli/command/volume/list_test.go index 7176c58e0..5535aafea 100644 --- a/cli/command/volume/list_test.go +++ b/cli/command/volume/list_test.go @@ -52,14 +52,12 @@ func TestVolumeListWithoutFormat(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ volumeListFunc: func(client.VolumeListOptions) (client.VolumeListResult, error) { return client.VolumeListResult{ - Items: volume.ListResponse{ - Volumes: []*volume.Volume{ - builders.Volume(), - builders.Volume(builders.VolumeName("foo"), builders.VolumeDriver("bar")), - builders.Volume(builders.VolumeName("baz"), builders.VolumeLabels(map[string]string{ - "foo": "bar", - })), - }, + Items: []volume.Volume{ + builders.Volume(), + builders.Volume(builders.VolumeName("foo"), builders.VolumeDriver("bar")), + builders.Volume(builders.VolumeName("baz"), builders.VolumeLabels(map[string]string{ + "foo": "bar", + })), }, }, nil }, @@ -73,14 +71,12 @@ func TestVolumeListWithConfigFormat(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ volumeListFunc: func(client.VolumeListOptions) (client.VolumeListResult, error) { return client.VolumeListResult{ - Items: volume.ListResponse{ - Volumes: []*volume.Volume{ - builders.Volume(), - builders.Volume(builders.VolumeName("foo"), builders.VolumeDriver("bar")), - builders.Volume(builders.VolumeName("baz"), builders.VolumeLabels(map[string]string{ - "foo": "bar", - })), - }, + Items: []volume.Volume{ + builders.Volume(), + builders.Volume(builders.VolumeName("foo"), builders.VolumeDriver("bar")), + builders.Volume(builders.VolumeName("baz"), builders.VolumeLabels(map[string]string{ + "foo": "bar", + })), }, }, nil }, @@ -97,14 +93,12 @@ func TestVolumeListWithFormat(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ volumeListFunc: func(client.VolumeListOptions) (client.VolumeListResult, error) { return client.VolumeListResult{ - Items: volume.ListResponse{ - Volumes: []*volume.Volume{ - builders.Volume(), - builders.Volume(builders.VolumeName("foo"), builders.VolumeDriver("bar")), - builders.Volume(builders.VolumeName("baz"), builders.VolumeLabels(map[string]string{ - "foo": "bar", - })), - }, + Items: []volume.Volume{ + builders.Volume(), + builders.Volume(builders.VolumeName("foo"), builders.VolumeDriver("bar")), + builders.Volume(builders.VolumeName("baz"), builders.VolumeLabels(map[string]string{ + "foo": "bar", + })), }, }, nil }, @@ -119,12 +113,10 @@ func TestVolumeListSortOrder(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ volumeListFunc: func(client.VolumeListOptions) (client.VolumeListResult, error) { return client.VolumeListResult{ - Items: volume.ListResponse{ - Volumes: []*volume.Volume{ - builders.Volume(builders.VolumeName("volume-2-foo")), - builders.Volume(builders.VolumeName("volume-10-foo")), - builders.Volume(builders.VolumeName("volume-1-foo")), - }, + Items: []volume.Volume{ + builders.Volume(builders.VolumeName("volume-2-foo")), + builders.Volume(builders.VolumeName("volume-10-foo")), + builders.Volume(builders.VolumeName("volume-1-foo")), }, }, nil }, @@ -139,101 +131,99 @@ func TestClusterVolumeList(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ volumeListFunc: func(client.VolumeListOptions) (client.VolumeListResult, error) { return client.VolumeListResult{ - Items: volume.ListResponse{ - Volumes: []*volume.Volume{ - { - Name: "volume1", - Scope: "global", - Driver: "driver1", - ClusterVolume: &volume.ClusterVolume{ - Spec: volume.ClusterVolumeSpec{ - Group: "group1", - AccessMode: &volume.AccessMode{ - Scope: volume.ScopeSingleNode, - Sharing: volume.SharingOneWriter, - MountVolume: &volume.TypeMount{}, - }, - Availability: volume.AvailabilityActive, + Items: []volume.Volume{ + { + Name: "volume1", + Scope: "global", + Driver: "driver1", + ClusterVolume: &volume.ClusterVolume{ + Spec: volume.ClusterVolumeSpec{ + Group: "group1", + AccessMode: &volume.AccessMode{ + Scope: volume.ScopeSingleNode, + Sharing: volume.SharingOneWriter, + MountVolume: &volume.TypeMount{}, }, + Availability: volume.AvailabilityActive, }, }, - { - Name: "volume2", - Scope: "global", - Driver: "driver1", - ClusterVolume: &volume.ClusterVolume{ - Spec: volume.ClusterVolumeSpec{ - Group: "group1", - AccessMode: &volume.AccessMode{ - Scope: volume.ScopeSingleNode, - Sharing: volume.SharingOneWriter, - MountVolume: &volume.TypeMount{}, - }, - Availability: volume.AvailabilityPause, - }, - Info: &volume.Info{ - CapacityBytes: 100000000, - VolumeID: "driver1vol2", - }, - }, - }, - { - Name: "volume3", - Scope: "global", - Driver: "driver2", - ClusterVolume: &volume.ClusterVolume{ - Spec: volume.ClusterVolumeSpec{ - Group: "group2", - AccessMode: &volume.AccessMode{ - Scope: volume.ScopeMultiNode, - Sharing: volume.SharingAll, - MountVolume: &volume.TypeMount{}, - }, - Availability: volume.AvailabilityActive, - }, - PublishStatus: []*volume.PublishStatus{ - { - NodeID: "nodeid1", - State: volume.StatePublished, - }, - }, - Info: &volume.Info{ - CapacityBytes: 100000000, - VolumeID: "driver1vol3", - }, - }, - }, - { - Name: "volume4", - Scope: "global", - Driver: "driver2", - ClusterVolume: &volume.ClusterVolume{ - Spec: volume.ClusterVolumeSpec{ - Group: "group2", - AccessMode: &volume.AccessMode{ - Scope: volume.ScopeMultiNode, - Sharing: volume.SharingAll, - MountVolume: &volume.TypeMount{}, - }, - Availability: volume.AvailabilityActive, - }, - PublishStatus: []*volume.PublishStatus{ - { - NodeID: "nodeid1", - State: volume.StatePublished, - }, { - NodeID: "nodeid2", - State: volume.StatePublished, - }, - }, - Info: &volume.Info{ - CapacityBytes: 100000000, - VolumeID: "driver1vol4", - }, - }, - }, - builders.Volume(builders.VolumeName("volume-local-1")), }, + { + Name: "volume2", + Scope: "global", + Driver: "driver1", + ClusterVolume: &volume.ClusterVolume{ + Spec: volume.ClusterVolumeSpec{ + Group: "group1", + AccessMode: &volume.AccessMode{ + Scope: volume.ScopeSingleNode, + Sharing: volume.SharingOneWriter, + MountVolume: &volume.TypeMount{}, + }, + Availability: volume.AvailabilityPause, + }, + Info: &volume.Info{ + CapacityBytes: 100000000, + VolumeID: "driver1vol2", + }, + }, + }, + { + Name: "volume3", + Scope: "global", + Driver: "driver2", + ClusterVolume: &volume.ClusterVolume{ + Spec: volume.ClusterVolumeSpec{ + Group: "group2", + AccessMode: &volume.AccessMode{ + Scope: volume.ScopeMultiNode, + Sharing: volume.SharingAll, + MountVolume: &volume.TypeMount{}, + }, + Availability: volume.AvailabilityActive, + }, + PublishStatus: []*volume.PublishStatus{ + { + NodeID: "nodeid1", + State: volume.StatePublished, + }, + }, + Info: &volume.Info{ + CapacityBytes: 100000000, + VolumeID: "driver1vol3", + }, + }, + }, + { + Name: "volume4", + Scope: "global", + Driver: "driver2", + ClusterVolume: &volume.ClusterVolume{ + Spec: volume.ClusterVolumeSpec{ + Group: "group2", + AccessMode: &volume.AccessMode{ + Scope: volume.ScopeMultiNode, + Sharing: volume.SharingAll, + MountVolume: &volume.TypeMount{}, + }, + Availability: volume.AvailabilityActive, + }, + PublishStatus: []*volume.PublishStatus{ + { + NodeID: "nodeid1", + State: volume.StatePublished, + }, { + NodeID: "nodeid2", + State: volume.StatePublished, + }, + }, + Info: &volume.Info{ + CapacityBytes: 100000000, + VolumeID: "driver1vol4", + }, + }, + }, + builders.Volume(builders.VolumeName("volume-local-1")), }, }, nil }, diff --git a/cli/compose/loader/loader.go b/cli/compose/loader/loader.go index 92fff4fa2..8f1c62434 100644 --- a/cli/compose/loader/loader.go +++ b/cli/compose/loader/loader.go @@ -26,7 +26,7 @@ import ( "github.com/go-viper/mapstructure/v2" "github.com/google/shlex" "github.com/moby/moby/api/types/network" - "github.com/moby/moby/api/types/versions" + "github.com/moby/moby/client/pkg/versions" "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" ) diff --git a/cmd/docker/docker.go b/cmd/docker/docker.go index 9846dc3f7..5450ea05e 100644 --- a/cmd/docker/docker.go +++ b/cmd/docker/docker.go @@ -20,7 +20,7 @@ import ( cliflags "github.com/docker/cli/cli/flags" "github.com/docker/cli/cli/version" platformsignals "github.com/docker/cli/cmd/docker/internal/signals" - "github.com/moby/moby/api/types/versions" + "github.com/moby/moby/client/pkg/versions" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/pflag" diff --git a/e2e/container/run_test.go b/e2e/container/run_test.go index af0486fde..5e469abff 100644 --- a/e2e/container/run_test.go +++ b/e2e/container/run_test.go @@ -14,7 +14,7 @@ import ( "github.com/creack/pty" "github.com/docker/cli/e2e/internal/fixtures" "github.com/docker/cli/internal/test/environment" - "github.com/moby/moby/api/types/versions" + "github.com/moby/moby/client/pkg/versions" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" "gotest.tools/v3/golden" diff --git a/internal/test/builders/volume.go b/internal/test/builders/volume.go index 82cf3a8e3..ed5bab27b 100644 --- a/internal/test/builders/volume.go +++ b/internal/test/builders/volume.go @@ -4,8 +4,8 @@ import "github.com/moby/moby/api/types/volume" // Volume creates a volume with default values. // Any number of volume function builder can be passed to augment it. -func Volume(builders ...func(vol *volume.Volume)) *volume.Volume { - vol := &volume.Volume{ +func Volume(builders ...func(vol *volume.Volume)) volume.Volume { + vol := volume.Volume{ Name: "volume", Driver: "local", Mountpoint: "/data/volume", @@ -13,7 +13,7 @@ func Volume(builders ...func(vol *volume.Volume)) *volume.Volume { } for _, builder := range builders { - builder(vol) + builder(&vol) } return vol diff --git a/vendor.mod b/vendor.mod index 0044114ad..b58c8af64 100644 --- a/vendor.mod +++ b/vendor.mod @@ -28,8 +28,8 @@ require ( github.com/google/uuid v1.6.0 github.com/mattn/go-runewidth v0.0.17 github.com/moby/go-archive v0.1.0 - github.com/moby/moby/api v1.52.0-beta.2.0.20251023134003-dcd668d5796b // master - github.com/moby/moby/client v0.1.0-beta.2.0.20251023134003-dcd668d5796b // master + github.com/moby/moby/api v1.52.0-beta.2.0.20251024193508-be8d6e2f2825 // master + github.com/moby/moby/client v0.1.0-beta.2.0.20251024193508-be8d6e2f2825 // master github.com/moby/patternmatcher v0.6.0 github.com/moby/swarmkit/v2 v2.1.0 github.com/moby/sys/atomicwriter v0.1.0 diff --git a/vendor.sum b/vendor.sum index 426343441..826a7e5bb 100644 --- a/vendor.sum +++ b/vendor.sum @@ -170,10 +170,10 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= -github.com/moby/moby/api v1.52.0-beta.2.0.20251023134003-dcd668d5796b h1:2y00KCjD3Dt6CFi8Zr7kh0ew32S2784EWbyKAXqQw2Q= -github.com/moby/moby/api v1.52.0-beta.2.0.20251023134003-dcd668d5796b/go.mod h1:/ou52HkRydg4+odrUR3vFsGgjIyHvprrpEQEkweL10s= -github.com/moby/moby/client v0.1.0-beta.2.0.20251023134003-dcd668d5796b h1:+JMltOoDeSwWJv4AMXE9e3dSe1h4LD4+bt6tqNO5h0s= -github.com/moby/moby/client v0.1.0-beta.2.0.20251023134003-dcd668d5796b/go.mod h1:sxVfwGqVgh7n+tdxA4gFToQ/lf+bM7zATnvQjVnsKT4= +github.com/moby/moby/api v1.52.0-beta.2.0.20251024193508-be8d6e2f2825 h1:hIQtHzNpFguJCWlgZ4z9L83YjLYpf9uP9+3cSYXP9hg= +github.com/moby/moby/api v1.52.0-beta.2.0.20251024193508-be8d6e2f2825/go.mod h1:/ou52HkRydg4+odrUR3vFsGgjIyHvprrpEQEkweL10s= +github.com/moby/moby/client v0.1.0-beta.2.0.20251024193508-be8d6e2f2825 h1:7kbhU8foMePfI9vB24bSld1RzJQpbquW8sZarquRHbY= +github.com/moby/moby/client v0.1.0-beta.2.0.20251024193508-be8d6e2f2825/go.mod h1:sxVfwGqVgh7n+tdxA4gFToQ/lf+bM7zATnvQjVnsKT4= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/swarmkit/v2 v2.1.0 h1:u+cJ5hSyF3HnzsyI+NtegYxdIPQIuibk7IbpXNxuISM= diff --git a/vendor/github.com/moby/moby/api/types/swarm/task.go b/vendor/github.com/moby/moby/api/types/swarm/task.go index 1dcbc4d6f..f61190683 100644 --- a/vendor/github.com/moby/moby/api/types/swarm/task.go +++ b/vendor/github.com/moby/moby/api/types/swarm/task.go @@ -138,6 +138,17 @@ type DiscreteGenericResource struct { type ResourceRequirements struct { Limits *Limit `json:",omitempty"` Reservations *Resources `json:",omitempty"` + + // Amount of swap in bytes - can only be used together with a memory limit + // -1 means unlimited + // a null pointer keeps the default behaviour of granting twice the memory + // amount in swap + SwapBytes *int64 `json:"SwapBytes,omitzero"` + + // Tune container memory swappiness (0 to 100) - if not specified, defaults + // to the container OS's default - generally 60, or the value predefined in + // the image; set to -1 to unset a previously set value + MemorySwappiness *int64 `json:MemorySwappiness,omitzero"` } // Placement represents orchestration parameters. diff --git a/vendor/github.com/moby/moby/client/build_prune.go b/vendor/github.com/moby/moby/client/build_prune.go index ec17b5a6f..a22e9685e 100644 --- a/vendor/github.com/moby/moby/client/build_prune.go +++ b/vendor/github.com/moby/moby/client/build_prune.go @@ -8,7 +8,7 @@ import ( "strconv" "github.com/moby/moby/api/types/build" - "github.com/moby/moby/api/types/versions" + "github.com/moby/moby/client/pkg/versions" ) // BuildCachePruneOptions hold parameters to prune the build cache. diff --git a/vendor/github.com/moby/moby/client/client.go b/vendor/github.com/moby/moby/client/client.go index 02bfa8747..643dfbdf8 100644 --- a/vendor/github.com/moby/moby/client/client.go +++ b/vendor/github.com/moby/moby/client/client.go @@ -56,7 +56,7 @@ import ( cerrdefs "github.com/containerd/errdefs" "github.com/docker/go-connections/sockets" - "github.com/moby/moby/api/types/versions" + "github.com/moby/moby/client/pkg/versions" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) diff --git a/vendor/github.com/moby/moby/client/client_interfaces.go b/vendor/github.com/moby/moby/client/client_interfaces.go index 67f880f3b..a038c33c6 100644 --- a/vendor/github.com/moby/moby/client/client_interfaces.go +++ b/vendor/github.com/moby/moby/client/client_interfaces.go @@ -12,7 +12,6 @@ import ( "github.com/moby/moby/api/types/registry" "github.com/moby/moby/api/types/swarm" "github.com/moby/moby/api/types/system" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // APIClient is an interface that clients that talk with a docker server must implement. @@ -58,10 +57,10 @@ type HijackDialer interface { // ContainerAPIClient defines API client methods for the containers type ContainerAPIClient interface { - ContainerAttach(ctx context.Context, container string, options ContainerAttachOptions) (HijackedResponse, error) - ContainerCommit(ctx context.Context, container string, options ContainerCommitOptions) (container.CommitResponse, 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) + ContainerAttach(ctx context.Context, container string, options ContainerAttachOptions) (ContainerAttachResult, error) + ContainerCommit(ctx context.Context, container string, options ContainerCommitOptions) (ContainerCommitResult, error) + ContainerCreate(ctx context.Context, options ContainerCreateOptions) (ContainerCreateResult, error) + ContainerDiff(ctx context.Context, container string, options ContainerDiffOptions) (ContainerDiffResult, error) ExecAPIClient ContainerExport(ctx context.Context, container string) (io.ReadCloser, error) ContainerInspect(ctx context.Context, container string) (container.InspectResponse, error) @@ -158,11 +157,11 @@ type PluginAPIClient interface { // ServiceAPIClient defines API client methods for the services type ServiceAPIClient interface { - ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options ServiceCreateOptions) (ServiceCreateResult, error) + ServiceCreate(ctx context.Context, options ServiceCreateOptions) (ServiceCreateResult, error) ServiceInspect(ctx context.Context, serviceID string, options ServiceInspectOptions) (ServiceInspectResult, error) ServiceList(ctx context.Context, options ServiceListOptions) (ServiceListResult, error) ServiceRemove(ctx context.Context, serviceID string, options ServiceRemoveOptions) (ServiceRemoveResult, error) - ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options ServiceUpdateOptions) (ServiceUpdateResult, error) + ServiceUpdate(ctx context.Context, serviceID string, options ServiceUpdateOptions) (ServiceUpdateResult, error) ServiceLogs(ctx context.Context, serviceID string, options ServiceLogsOptions) (ServiceLogsResult, error) TaskLogs(ctx context.Context, taskID string, options TaskLogsOptions) (TaskLogsResult, error) TaskInspect(ctx context.Context, taskID string, options TaskInspectOptions) (TaskInspectResult, error) @@ -177,7 +176,7 @@ type SwarmAPIClient interface { SwarmUnlock(ctx context.Context, options SwarmUnlockOptions) (SwarmUnlockResult, error) SwarmLeave(ctx context.Context, options SwarmLeaveOptions) (SwarmLeaveResult, error) SwarmInspect(ctx context.Context, options SwarmInspectOptions) (SwarmInspectResult, error) - SwarmUpdate(ctx context.Context, version swarm.Version, options SwarmUpdateOptions) (SwarmUpdateResult, error) + SwarmUpdate(ctx context.Context, options SwarmUpdateOptions) (SwarmUpdateResult, error) } // SystemAPIClient defines API client methods for the system diff --git a/vendor/github.com/moby/moby/client/config_inspect.go b/vendor/github.com/moby/moby/client/config_inspect.go index f1aaf68d9..0bf0ff791 100644 --- a/vendor/github.com/moby/moby/client/config_inspect.go +++ b/vendor/github.com/moby/moby/client/config_inspect.go @@ -2,6 +2,7 @@ package client import ( "context" + "encoding/json" "github.com/moby/moby/api/types/swarm" ) @@ -14,7 +15,7 @@ type ConfigInspectOptions struct { // ConfigInspectResult holds the result from the ConfigInspect method. type ConfigInspectResult struct { Config swarm.Config - Raw []byte + Raw json.RawMessage } // ConfigInspect returns the config information with raw data @@ -24,7 +25,6 @@ func (cli *Client) ConfigInspect(ctx context.Context, id string, options ConfigI return ConfigInspectResult{}, err } resp, err := cli.get(ctx, "/configs/"+id, nil, nil) - defer ensureReaderClosed(resp) if err != nil { return ConfigInspectResult{}, err } diff --git a/vendor/github.com/moby/moby/client/container_attach.go b/vendor/github.com/moby/moby/client/container_attach.go index a4ffb3e64..fa3a2efcc 100644 --- a/vendor/github.com/moby/moby/client/container_attach.go +++ b/vendor/github.com/moby/moby/client/container_attach.go @@ -16,6 +16,11 @@ type ContainerAttachOptions struct { Logs bool } +// ContainerAttachResult is the result from attaching to a container. +type ContainerAttachResult struct { + HijackedResponse +} + // ContainerAttach attaches a connection to a container in the server. // It returns a [HijackedResponse] with the hijacked connection // and a reader to get output. It's up to the called to close @@ -44,10 +49,10 @@ type ContainerAttachOptions struct { // [stdcopy.StdType]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdType // [Stdout]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#Stdout // [Stderr]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#Stderr -func (cli *Client) ContainerAttach(ctx context.Context, containerID string, options ContainerAttachOptions) (HijackedResponse, error) { +func (cli *Client) ContainerAttach(ctx context.Context, containerID string, options ContainerAttachOptions) (ContainerAttachResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return HijackedResponse{}, err + return ContainerAttachResult{}, err } query := url.Values{} @@ -70,7 +75,12 @@ func (cli *Client) ContainerAttach(ctx context.Context, containerID string, opti query.Set("logs", "1") } - return cli.postHijacked(ctx, "/containers/"+containerID+"/attach", query, nil, http.Header{ + hijacked, err := cli.postHijacked(ctx, "/containers/"+containerID+"/attach", query, nil, http.Header{ "Content-Type": {"text/plain"}, }) + if err != nil { + return ContainerAttachResult{}, err + } + + return ContainerAttachResult{HijackedResponse: hijacked}, nil } diff --git a/vendor/github.com/moby/moby/client/container_commit.go b/vendor/github.com/moby/moby/client/container_commit.go index d948fbd41..79da44a54 100644 --- a/vendor/github.com/moby/moby/client/container_commit.go +++ b/vendor/github.com/moby/moby/client/container_commit.go @@ -20,22 +20,27 @@ type ContainerCommitOptions struct { Config *container.Config } +// ContainerCommitResult is the result from committing a container. +type ContainerCommitResult struct { + ID string +} + // ContainerCommit applies changes to a container and creates a new tagged image. -func (cli *Client) ContainerCommit(ctx context.Context, containerID string, options ContainerCommitOptions) (container.CommitResponse, error) { +func (cli *Client) ContainerCommit(ctx context.Context, containerID string, options ContainerCommitOptions) (ContainerCommitResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return container.CommitResponse{}, err + return ContainerCommitResult{}, err } var repository, tag string if options.Reference != "" { ref, err := reference.ParseNormalizedNamed(options.Reference) if err != nil { - return container.CommitResponse{}, err + return ContainerCommitResult{}, err } if _, ok := ref.(reference.Digested); ok { - return container.CommitResponse{}, errors.New("refusing to create a tag with a digest reference") + return ContainerCommitResult{}, errors.New("refusing to create a tag with a digest reference") } ref = reference.TagNameOnly(ref) @@ -62,9 +67,9 @@ func (cli *Client) ContainerCommit(ctx context.Context, containerID string, opti resp, err := cli.post(ctx, "/commit", query, options.Config, nil) defer ensureReaderClosed(resp) if err != nil { - return response, err + return ContainerCommitResult{}, err } err = json.NewDecoder(resp.Body).Decode(&response) - return response, err + return ContainerCommitResult{ID: response.ID}, err } diff --git a/vendor/github.com/moby/moby/client/container_create.go b/vendor/github.com/moby/moby/client/container_create.go index 9d72c636e..d941a3720 100644 --- a/vendor/github.com/moby/moby/client/container_create.go +++ b/vendor/github.com/moby/moby/client/container_create.go @@ -10,49 +10,63 @@ import ( cerrdefs "github.com/containerd/errdefs" "github.com/moby/moby/api/types/container" - "github.com/moby/moby/api/types/network" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // ContainerCreate creates a new container based on the given configuration. // It can be associated with a name, but it's not mandatory. -func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error) { - if config == nil { - return container.CreateResponse{}, cerrdefs.ErrInvalidArgument.WithMessage("config is nil") +func (cli *Client) ContainerCreate(ctx context.Context, options ContainerCreateOptions) (ContainerCreateResult, error) { + cfg := options.Config + + if cfg == nil { + cfg = &container.Config{} + } + + if options.Image != "" { + if cfg.Image != "" { + return ContainerCreateResult{}, cerrdefs.ErrInvalidArgument.WithMessage("either Image or config.Image should be set") + } + newCfg := *cfg + newCfg.Image = options.Image + cfg = &newCfg + } + + if cfg.Image == "" { + return ContainerCreateResult{}, cerrdefs.ErrInvalidArgument.WithMessage("config.Image or Image is required") } var response container.CreateResponse - if hostConfig != nil { - hostConfig.CapAdd = normalizeCapabilities(hostConfig.CapAdd) - hostConfig.CapDrop = normalizeCapabilities(hostConfig.CapDrop) + if options.HostConfig != nil { + options.HostConfig.CapAdd = normalizeCapabilities(options.HostConfig.CapAdd) + options.HostConfig.CapDrop = normalizeCapabilities(options.HostConfig.CapDrop) } query := url.Values{} - if platform != nil { - if p := formatPlatform(*platform); p != "unknown" { + if options.Platform != nil { + if p := formatPlatform(*options.Platform); p != "unknown" { query.Set("platform", p) } } - if containerName != "" { - query.Set("name", containerName) + if options.Name != "" { + query.Set("name", options.Name) } body := container.CreateRequest{ - Config: config, - HostConfig: hostConfig, - NetworkingConfig: networkingConfig, + Config: cfg, + HostConfig: options.HostConfig, + NetworkingConfig: options.NetworkingConfig, } resp, err := cli.post(ctx, "/containers/create", query, body, nil) defer ensureReaderClosed(resp) if err != nil { - return response, err + return ContainerCreateResult{}, err } err = json.NewDecoder(resp.Body).Decode(&response) - return response, err + return ContainerCreateResult{ID: response.ID, Warnings: response.Warnings}, err } // formatPlatform returns a formatted string representing platform (e.g., "linux/arm/v7"). diff --git a/vendor/github.com/moby/moby/client/container_create_opts.go b/vendor/github.com/moby/moby/client/container_create_opts.go new file mode 100644 index 000000000..8580e20d3 --- /dev/null +++ b/vendor/github.com/moby/moby/client/container_create_opts.go @@ -0,0 +1,25 @@ +package client + +import ( + "github.com/moby/moby/api/types/container" + "github.com/moby/moby/api/types/network" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +// ContainerCreateOptions holds parameters to create a container. +type ContainerCreateOptions struct { + Config *container.Config + HostConfig *container.HostConfig + NetworkingConfig *network.NetworkingConfig + Platform *ocispec.Platform + Name string + + // Image is a shortcut for Config.Image - only one of Image or Config.Image should be set. + Image string +} + +// ContainerCreateResult is the result from creating a container. +type ContainerCreateResult struct { + ID string + Warnings []string +} diff --git a/vendor/github.com/moby/moby/client/container_diff.go b/vendor/github.com/moby/moby/client/container_diff.go index c87c6e4be..ec904337e 100644 --- a/vendor/github.com/moby/moby/client/container_diff.go +++ b/vendor/github.com/moby/moby/client/container_diff.go @@ -9,22 +9,22 @@ import ( ) // ContainerDiff shows differences in a container filesystem since it was started. -func (cli *Client) ContainerDiff(ctx context.Context, containerID string) ([]container.FilesystemChange, error) { +func (cli *Client) ContainerDiff(ctx context.Context, containerID string, options ContainerDiffOptions) (ContainerDiffResult, error) { containerID, err := trimID("container", containerID) if err != nil { - return nil, err + return ContainerDiffResult{}, err } resp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil) defer ensureReaderClosed(resp) if err != nil { - return nil, err + return ContainerDiffResult{}, err } var changes []container.FilesystemChange err = json.NewDecoder(resp.Body).Decode(&changes) if err != nil { - return nil, err + return ContainerDiffResult{}, err } - return changes, err + return ContainerDiffResult{Changes: changes}, err } diff --git a/vendor/github.com/moby/moby/client/container_diff_opts.go b/vendor/github.com/moby/moby/client/container_diff_opts.go new file mode 100644 index 000000000..5e3c37ab4 --- /dev/null +++ b/vendor/github.com/moby/moby/client/container_diff_opts.go @@ -0,0 +1,13 @@ +package client + +import "github.com/moby/moby/api/types/container" + +// ContainerDiffOptions holds parameters to show differences in a container filesystem. +type ContainerDiffOptions struct { + // Currently no options, but this allows for future extensibility +} + +// ContainerDiffResult is the result from showing differences in a container filesystem. +type ContainerDiffResult struct { + Changes []container.FilesystemChange +} diff --git a/vendor/github.com/moby/moby/client/container_exec.go b/vendor/github.com/moby/moby/client/container_exec.go index 3b23de487..bda89110a 100644 --- a/vendor/github.com/moby/moby/client/container_exec.go +++ b/vendor/github.com/moby/moby/client/container_exec.go @@ -26,7 +26,7 @@ type ExecCreateOptions struct { // ExecCreateResult holds the result of creating a container exec. type ExecCreateResult struct { - container.ExecCreateResponse + ID string } // ExecCreate creates a new exec configuration to run an exec process. @@ -58,7 +58,7 @@ func (cli *Client) ExecCreate(ctx context.Context, containerID string, options E var response container.ExecCreateResponse err = json.NewDecoder(resp.Body).Decode(&response) - return ExecCreateResult{ExecCreateResponse: response}, err + return ExecCreateResult{ID: response.ID}, err } type execStartAttachOptions struct { @@ -127,26 +127,21 @@ func (cli *Client) ExecAttach(ctx context.Context, execID string, options ExecAt return ExecAttachResult{HijackedResponse: response}, err } -// ExecInspect holds information returned by exec inspect. -// -// It provides a subset of the information included in [container.ExecInspectResponse]. -// -// TODO(thaJeztah): include all fields of [container.ExecInspectResponse] ? -type ExecInspect struct { - ExecID string `json:"ID"` - ContainerID string `json:"ContainerID"` - Running bool `json:"Running"` - ExitCode int `json:"ExitCode"` - Pid int `json:"Pid"` -} - // ExecInspectOptions holds options for inspecting a container exec. type ExecInspectOptions struct { } // ExecInspectResult holds the result of inspecting a container exec. +// +// It provides a subset of the information included in [container.ExecInspectResponse]. +// +// TODO(thaJeztah): include all fields of [container.ExecInspectResponse] ? type ExecInspectResult struct { - ExecInspect + ID string + ContainerID string + Running bool + ExitCode int + PID int } // ExecInspect returns information about a specific exec process on the docker host. @@ -168,11 +163,11 @@ func (cli *Client) ExecInspect(ctx context.Context, execID string, options ExecI ec = *response.ExitCode } - return ExecInspectResult{ExecInspect: ExecInspect{ - ExecID: response.ID, + return ExecInspectResult{ + ID: response.ID, ContainerID: response.ContainerID, Running: response.Running, ExitCode: ec, - Pid: response.Pid, - }}, nil + PID: response.Pid, + }, nil } diff --git a/vendor/github.com/moby/moby/client/errors.go b/vendor/github.com/moby/moby/client/errors.go index 81a9f4eb1..4980d7cad 100644 --- a/vendor/github.com/moby/moby/client/errors.go +++ b/vendor/github.com/moby/moby/client/errors.go @@ -8,7 +8,7 @@ import ( cerrdefs "github.com/containerd/errdefs" "github.com/containerd/errdefs/pkg/errhttp" - "github.com/moby/moby/api/types/versions" + "github.com/moby/moby/client/pkg/versions" ) // errConnectionFailed implements an error returned when connection failed. diff --git a/vendor/github.com/moby/moby/client/image_import.go b/vendor/github.com/moby/moby/client/image_import.go index ca0fa1d0f..b8f1ccb50 100644 --- a/vendor/github.com/moby/moby/client/image_import.go +++ b/vendor/github.com/moby/moby/client/image_import.go @@ -42,5 +42,5 @@ func (cli *Client) ImageImport(ctx context.Context, source ImageImportSource, re if err != nil { return ImageImportResult{}, err } - return ImageImportResult{body: resp.Body}, nil + return ImageImportResult{rc: resp.Body}, nil } diff --git a/vendor/github.com/moby/moby/client/image_import_opts.go b/vendor/github.com/moby/moby/client/image_import_opts.go index 44ea0e2ca..2ba5b593e 100644 --- a/vendor/github.com/moby/moby/client/image_import_opts.go +++ b/vendor/github.com/moby/moby/client/image_import_opts.go @@ -20,16 +20,19 @@ type ImageImportOptions struct { // ImageImportResult holds the response body returned by the daemon for image import. type ImageImportResult struct { - body io.ReadCloser + rc io.ReadCloser } func (r ImageImportResult) Read(p []byte) (n int, err error) { - return r.body.Read(p) + if r.rc == nil { + return 0, io.EOF + } + return r.rc.Read(p) } func (r ImageImportResult) Close() error { - if r.body == nil { + if r.rc == nil { return nil } - return r.body.Close() + return r.rc.Close() } diff --git a/vendor/github.com/moby/moby/client/image_list.go b/vendor/github.com/moby/moby/client/image_list.go index 955422c13..6df3c66e1 100644 --- a/vendor/github.com/moby/moby/client/image_list.go +++ b/vendor/github.com/moby/moby/client/image_list.go @@ -6,7 +6,7 @@ import ( "net/url" "github.com/moby/moby/api/types/image" - "github.com/moby/moby/api/types/versions" + "github.com/moby/moby/client/pkg/versions" ) // ImageList returns a list of images in the docker host. diff --git a/vendor/github.com/moby/moby/client/image_remove.go b/vendor/github.com/moby/moby/client/image_remove.go index 17ed75741..095b4f04c 100644 --- a/vendor/github.com/moby/moby/client/image_remove.go +++ b/vendor/github.com/moby/moby/client/image_remove.go @@ -35,5 +35,5 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options Imag var dels []image.DeleteResponse err = json.NewDecoder(resp.Body).Decode(&dels) - return ImageRemoveResult{Deleted: dels}, err + return ImageRemoveResult{Items: dels}, err } diff --git a/vendor/github.com/moby/moby/client/image_remove_opts.go b/vendor/github.com/moby/moby/client/image_remove_opts.go index d028f4608..3b5d8a77f 100644 --- a/vendor/github.com/moby/moby/client/image_remove_opts.go +++ b/vendor/github.com/moby/moby/client/image_remove_opts.go @@ -14,5 +14,5 @@ type ImageRemoveOptions struct { // ImageRemoveResult holds the delete responses returned by the daemon. type ImageRemoveResult struct { - Deleted []image.DeleteResponse + Items []image.DeleteResponse } diff --git a/vendor/github.com/moby/moby/client/network_inspect.go b/vendor/github.com/moby/moby/client/network_inspect.go index 165aa5b46..775780527 100644 --- a/vendor/github.com/moby/moby/client/network_inspect.go +++ b/vendor/github.com/moby/moby/client/network_inspect.go @@ -2,6 +2,7 @@ package client import ( "context" + "encoding/json" "net/url" "github.com/moby/moby/api/types/network" @@ -10,7 +11,7 @@ import ( // NetworkInspectResult contains the result of a network inspection. type NetworkInspectResult struct { Network network.Inspect - Raw []byte + Raw json.RawMessage } // NetworkInspect returns the information for a specific network configured in the docker host. @@ -28,7 +29,6 @@ func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options } resp, err := cli.get(ctx, "/networks/"+networkID, query, nil) - defer ensureReaderClosed(resp) if err != nil { return NetworkInspectResult{}, err } diff --git a/vendor/github.com/moby/moby/client/node_inspect.go b/vendor/github.com/moby/moby/client/node_inspect.go index b6ba94fb6..cd4ce0119 100644 --- a/vendor/github.com/moby/moby/client/node_inspect.go +++ b/vendor/github.com/moby/moby/client/node_inspect.go @@ -9,9 +9,12 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// NodeInspectOptions holds parameters to inspect nodes with. +type NodeInspectOptions struct{} + type NodeInspectResult struct { Node swarm.Node - Raw []byte + Raw json.RawMessage } // NodeInspect returns the node information. diff --git a/vendor/github.com/moby/moby/client/node_list.go b/vendor/github.com/moby/moby/client/node_list.go index 6952d5fe2..1a1b57922 100644 --- a/vendor/github.com/moby/moby/client/node_list.go +++ b/vendor/github.com/moby/moby/client/node_list.go @@ -8,6 +8,11 @@ import ( "github.com/moby/moby/api/types/swarm" ) +// NodeListOptions holds parameters to list nodes with. +type NodeListOptions struct { + Filters Filters +} + type NodeListResult struct { Items []swarm.Node } diff --git a/vendor/github.com/moby/moby/client/node_remove.go b/vendor/github.com/moby/moby/client/node_remove.go index c7f6d7ea8..56c39d67a 100644 --- a/vendor/github.com/moby/moby/client/node_remove.go +++ b/vendor/github.com/moby/moby/client/node_remove.go @@ -5,6 +5,10 @@ import ( "net/url" ) +// NodeRemoveOptions holds parameters to remove nodes with. +type NodeRemoveOptions struct { + Force bool +} type NodeRemoveResult struct{} // NodeRemove removes a Node. diff --git a/vendor/github.com/moby/moby/client/node_update.go b/vendor/github.com/moby/moby/client/node_update.go index 8f9caa441..4bc7c3b69 100644 --- a/vendor/github.com/moby/moby/client/node_update.go +++ b/vendor/github.com/moby/moby/client/node_update.go @@ -3,8 +3,16 @@ package client import ( "context" "net/url" + + "github.com/moby/moby/api/types/swarm" ) +// NodeUpdateOptions holds parameters to update nodes with. +type NodeUpdateOptions struct { + Version swarm.Version + Spec swarm.NodeSpec +} + type NodeUpdateResult struct{} // NodeUpdate updates a Node. @@ -16,7 +24,7 @@ func (cli *Client) NodeUpdate(ctx context.Context, nodeID string, options NodeUp query := url.Values{} query.Set("version", options.Version.String()) - resp, err := cli.post(ctx, "/nodes/"+nodeID+"/update", query, options.Node, nil) + resp, err := cli.post(ctx, "/nodes/"+nodeID+"/update", query, options.Spec, nil) defer ensureReaderClosed(resp) return NodeUpdateResult{}, err } diff --git a/vendor/github.com/moby/moby/api/types/versions/compare.go b/vendor/github.com/moby/moby/client/pkg/versions/compare.go similarity index 100% rename from vendor/github.com/moby/moby/api/types/versions/compare.go rename to vendor/github.com/moby/moby/client/pkg/versions/compare.go diff --git a/vendor/github.com/moby/moby/client/plugin_inspect.go b/vendor/github.com/moby/moby/client/plugin_inspect.go index e6853e644..8caf06a8e 100644 --- a/vendor/github.com/moby/moby/client/plugin_inspect.go +++ b/vendor/github.com/moby/moby/client/plugin_inspect.go @@ -2,6 +2,7 @@ package client import ( "context" + "encoding/json" "github.com/moby/moby/api/types/plugin" ) @@ -13,8 +14,8 @@ type PluginInspectOptions struct { // PluginInspectResult holds the result from the [Client.PluginInspect] method. type PluginInspectResult struct { - Raw []byte Plugin plugin.Plugin + Raw json.RawMessage } // PluginInspect inspects an existing plugin @@ -24,7 +25,6 @@ func (cli *Client) PluginInspect(ctx context.Context, name string, options Plugi return PluginInspectResult{}, err } resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil) - defer ensureReaderClosed(resp) if err != nil { return PluginInspectResult{}, err } diff --git a/vendor/github.com/moby/moby/client/secret_inspect.go b/vendor/github.com/moby/moby/client/secret_inspect.go index 360085215..fefd4cd23 100644 --- a/vendor/github.com/moby/moby/client/secret_inspect.go +++ b/vendor/github.com/moby/moby/client/secret_inspect.go @@ -2,6 +2,7 @@ package client import ( "context" + "encoding/json" "github.com/moby/moby/api/types/swarm" ) @@ -14,7 +15,7 @@ type SecretInspectOptions struct { // SecretInspectResult holds the result from the [Client.SecretInspect]. method. type SecretInspectResult struct { Secret swarm.Secret - Raw []byte + Raw json.RawMessage } // SecretInspect returns the secret information with raw data. @@ -24,7 +25,6 @@ func (cli *Client) SecretInspect(ctx context.Context, id string, options SecretI return SecretInspectResult{}, err } resp, err := cli.get(ctx, "/secrets/"+id, nil, nil) - defer ensureReaderClosed(resp) if err != nil { return SecretInspectResult{}, err } diff --git a/vendor/github.com/moby/moby/client/service_create.go b/vendor/github.com/moby/moby/client/service_create.go index 9155d508a..204d21816 100644 --- a/vendor/github.com/moby/moby/client/service_create.go +++ b/vendor/github.com/moby/moby/client/service_create.go @@ -16,6 +16,8 @@ import ( // ServiceCreateOptions contains the options to use when creating a service. type ServiceCreateOptions struct { + Spec swarm.ServiceSpec + // EncodedRegistryAuth is the encoded registry authorization credentials to // use when updating the service. // @@ -39,33 +41,33 @@ type ServiceCreateResult struct { } // ServiceCreate creates a new service. -func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options ServiceCreateOptions) (ServiceCreateResult, error) { +func (cli *Client) ServiceCreate(ctx context.Context, options ServiceCreateOptions) (ServiceCreateResult, error) { // Make sure containerSpec is not nil when no runtime is set or the runtime is set to container - if service.TaskTemplate.ContainerSpec == nil && (service.TaskTemplate.Runtime == "" || service.TaskTemplate.Runtime == swarm.RuntimeContainer) { - service.TaskTemplate.ContainerSpec = &swarm.ContainerSpec{} + if options.Spec.TaskTemplate.ContainerSpec == nil && (options.Spec.TaskTemplate.Runtime == "" || options.Spec.TaskTemplate.Runtime == swarm.RuntimeContainer) { + options.Spec.TaskTemplate.ContainerSpec = &swarm.ContainerSpec{} } - if err := validateServiceSpec(service); err != nil { + if err := validateServiceSpec(options.Spec); err != nil { return ServiceCreateResult{}, err } // ensure that the image is tagged var warnings []string switch { - case service.TaskTemplate.ContainerSpec != nil: - if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" { - service.TaskTemplate.ContainerSpec.Image = taggedImg + case options.Spec.TaskTemplate.ContainerSpec != nil: + if taggedImg := imageWithTagString(options.Spec.TaskTemplate.ContainerSpec.Image); taggedImg != "" { + options.Spec.TaskTemplate.ContainerSpec.Image = taggedImg } if options.QueryRegistry { - resolveWarning := resolveContainerSpecImage(ctx, cli, &service.TaskTemplate, options.EncodedRegistryAuth) + resolveWarning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth) warnings = append(warnings, resolveWarning) } - case service.TaskTemplate.PluginSpec != nil: - if taggedImg := imageWithTagString(service.TaskTemplate.PluginSpec.Remote); taggedImg != "" { - service.TaskTemplate.PluginSpec.Remote = taggedImg + case options.Spec.TaskTemplate.PluginSpec != nil: + if taggedImg := imageWithTagString(options.Spec.TaskTemplate.PluginSpec.Remote); taggedImg != "" { + options.Spec.TaskTemplate.PluginSpec.Remote = taggedImg } if options.QueryRegistry { - resolveWarning := resolvePluginSpecRemote(ctx, cli, &service.TaskTemplate, options.EncodedRegistryAuth) + resolveWarning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth) warnings = append(warnings, resolveWarning) } } @@ -74,7 +76,7 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec, if options.EncodedRegistryAuth != "" { headers[registry.AuthHeader] = []string{options.EncodedRegistryAuth} } - resp, err := cli.post(ctx, "/services/create", nil, service, headers) + resp, err := cli.post(ctx, "/services/create", nil, options.Spec, headers) defer ensureReaderClosed(resp) if err != nil { return ServiceCreateResult{}, err diff --git a/vendor/github.com/moby/moby/client/service_inspect.go b/vendor/github.com/moby/moby/client/service_inspect.go index fabae9fb0..9bda43f86 100644 --- a/vendor/github.com/moby/moby/client/service_inspect.go +++ b/vendor/github.com/moby/moby/client/service_inspect.go @@ -2,6 +2,7 @@ package client import ( "context" + "encoding/json" "fmt" "net/url" @@ -16,7 +17,7 @@ type ServiceInspectOptions struct { // ServiceInspectResult represents the result of a service inspect operation. type ServiceInspectResult struct { Service swarm.Service - Raw []byte + Raw json.RawMessage } // ServiceInspect retrieves detailed information about a specific service by its ID. @@ -29,7 +30,6 @@ func (cli *Client) ServiceInspect(ctx context.Context, serviceID string, options query := url.Values{} query.Set("insertDefaults", fmt.Sprintf("%v", options.InsertDefaults)) resp, err := cli.get(ctx, "/services/"+serviceID, query, nil) - defer ensureReaderClosed(resp) if err != nil { return ServiceInspectResult{}, err } diff --git a/vendor/github.com/moby/moby/client/service_update.go b/vendor/github.com/moby/moby/client/service_update.go index 3910d2bc5..36061c9d1 100644 --- a/vendor/github.com/moby/moby/client/service_update.go +++ b/vendor/github.com/moby/moby/client/service_update.go @@ -12,6 +12,9 @@ import ( // ServiceUpdateOptions contains the options to be used for updating services. type ServiceUpdateOptions struct { + Version swarm.Version + Spec swarm.ServiceSpec + // EncodedRegistryAuth is the encoded registry authorization credentials to // use when updating the service. // @@ -50,13 +53,13 @@ type ServiceUpdateResult struct { // conflicting writes. It must be the value as set *before* the update. // You can find this value in the [swarm.Service.Meta] field, which can // be found using [Client.ServiceInspectWithRaw]. -func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options ServiceUpdateOptions) (ServiceUpdateResult, error) { +func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, options ServiceUpdateOptions) (ServiceUpdateResult, error) { serviceID, err := trimID("service", serviceID) if err != nil { return ServiceUpdateResult{}, err } - if err := validateServiceSpec(service); err != nil { + if err := validateServiceSpec(options.Spec); err != nil { return ServiceUpdateResult{}, err } @@ -69,25 +72,25 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version query.Set("rollback", options.Rollback) } - query.Set("version", version.String()) + query.Set("version", options.Version.String()) // ensure that the image is tagged var warnings []string switch { - case service.TaskTemplate.ContainerSpec != nil: - if taggedImg := imageWithTagString(service.TaskTemplate.ContainerSpec.Image); taggedImg != "" { - service.TaskTemplate.ContainerSpec.Image = taggedImg + case options.Spec.TaskTemplate.ContainerSpec != nil: + if taggedImg := imageWithTagString(options.Spec.TaskTemplate.ContainerSpec.Image); taggedImg != "" { + options.Spec.TaskTemplate.ContainerSpec.Image = taggedImg } if options.QueryRegistry { - resolveWarning := resolveContainerSpecImage(ctx, cli, &service.TaskTemplate, options.EncodedRegistryAuth) + resolveWarning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth) warnings = append(warnings, resolveWarning) } - case service.TaskTemplate.PluginSpec != nil: - if taggedImg := imageWithTagString(service.TaskTemplate.PluginSpec.Remote); taggedImg != "" { - service.TaskTemplate.PluginSpec.Remote = taggedImg + case options.Spec.TaskTemplate.PluginSpec != nil: + if taggedImg := imageWithTagString(options.Spec.TaskTemplate.PluginSpec.Remote); taggedImg != "" { + options.Spec.TaskTemplate.PluginSpec.Remote = taggedImg } if options.QueryRegistry { - resolveWarning := resolvePluginSpecRemote(ctx, cli, &service.TaskTemplate, options.EncodedRegistryAuth) + resolveWarning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth) warnings = append(warnings, resolveWarning) } } @@ -96,7 +99,7 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version if options.EncodedRegistryAuth != "" { headers.Set(registry.AuthHeader, options.EncodedRegistryAuth) } - resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, service, headers) + resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, options.Spec, headers) defer ensureReaderClosed(resp) if err != nil { return ServiceUpdateResult{}, err diff --git a/vendor/github.com/moby/moby/client/swarm_node_inspect_opts.go b/vendor/github.com/moby/moby/client/swarm_node_inspect_opts.go deleted file mode 100644 index 5423f5c67..000000000 --- a/vendor/github.com/moby/moby/client/swarm_node_inspect_opts.go +++ /dev/null @@ -1,4 +0,0 @@ -package client - -// NodeInspectOptions holds parameters to inspect nodes with. -type NodeInspectOptions struct{} diff --git a/vendor/github.com/moby/moby/client/swarm_node_list_opts.go b/vendor/github.com/moby/moby/client/swarm_node_list_opts.go deleted file mode 100644 index c5293cd17..000000000 --- a/vendor/github.com/moby/moby/client/swarm_node_list_opts.go +++ /dev/null @@ -1,6 +0,0 @@ -package client - -// NodeListOptions holds parameters to list nodes with. -type NodeListOptions struct { - Filters Filters -} diff --git a/vendor/github.com/moby/moby/client/swarm_node_remove_opts.go b/vendor/github.com/moby/moby/client/swarm_node_remove_opts.go deleted file mode 100644 index 85bc12f81..000000000 --- a/vendor/github.com/moby/moby/client/swarm_node_remove_opts.go +++ /dev/null @@ -1,6 +0,0 @@ -package client - -// NodeRemoveOptions holds parameters to remove nodes with. -type NodeRemoveOptions struct { - Force bool -} diff --git a/vendor/github.com/moby/moby/client/swarm_node_update_opts.go b/vendor/github.com/moby/moby/client/swarm_node_update_opts.go deleted file mode 100644 index 738b9f871..000000000 --- a/vendor/github.com/moby/moby/client/swarm_node_update_opts.go +++ /dev/null @@ -1,9 +0,0 @@ -package client - -import "github.com/moby/moby/api/types/swarm" - -// NodeUpdateOptions holds parameters to update nodes with. -type NodeUpdateOptions struct { - Version swarm.Version - Node swarm.NodeSpec -} diff --git a/vendor/github.com/moby/moby/client/swarm_update.go b/vendor/github.com/moby/moby/client/swarm_update.go index 8f62876a5..81f62b2c0 100644 --- a/vendor/github.com/moby/moby/client/swarm_update.go +++ b/vendor/github.com/moby/moby/client/swarm_update.go @@ -10,7 +10,8 @@ import ( // SwarmUpdateOptions contains options for updating a swarm. type SwarmUpdateOptions struct { - Swarm swarm.Spec + Version swarm.Version + Spec swarm.Spec RotateWorkerToken bool RotateManagerToken bool RotateManagerUnlockKey bool @@ -20,13 +21,13 @@ type SwarmUpdateOptions struct { type SwarmUpdateResult struct{} // SwarmUpdate updates the swarm. -func (cli *Client) SwarmUpdate(ctx context.Context, version swarm.Version, options SwarmUpdateOptions) (SwarmUpdateResult, error) { +func (cli *Client) SwarmUpdate(ctx context.Context, options SwarmUpdateOptions) (SwarmUpdateResult, error) { query := url.Values{} - query.Set("version", version.String()) + query.Set("version", options.Version.String()) query.Set("rotateWorkerToken", strconv.FormatBool(options.RotateWorkerToken)) query.Set("rotateManagerToken", strconv.FormatBool(options.RotateManagerToken)) query.Set("rotateManagerUnlockKey", strconv.FormatBool(options.RotateManagerUnlockKey)) - resp, err := cli.post(ctx, "/swarm/update", query, options.Swarm, nil) + resp, err := cli.post(ctx, "/swarm/update", query, options.Spec, nil) defer ensureReaderClosed(resp) return SwarmUpdateResult{}, err } diff --git a/vendor/github.com/moby/moby/client/task_inspect.go b/vendor/github.com/moby/moby/client/task_inspect.go index 277b00ff4..96edcb09f 100644 --- a/vendor/github.com/moby/moby/client/task_inspect.go +++ b/vendor/github.com/moby/moby/client/task_inspect.go @@ -2,6 +2,7 @@ package client import ( "context" + "encoding/json" "github.com/moby/moby/api/types/swarm" ) @@ -14,7 +15,7 @@ type TaskInspectOptions struct { // TaskInspectResult contains the result of a task inspection. type TaskInspectResult struct { Task swarm.Task - Raw []byte + Raw json.RawMessage } // TaskInspect returns the task information and its raw representation. @@ -25,7 +26,6 @@ func (cli *Client) TaskInspect(ctx context.Context, taskID string, options TaskI } resp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil) - defer ensureReaderClosed(resp) if err != nil { return TaskInspectResult{}, err } diff --git a/vendor/github.com/moby/moby/client/utils.go b/vendor/github.com/moby/moby/client/utils.go index 1da948b6c..54d0deef1 100644 --- a/vendor/github.com/moby/moby/client/utils.go +++ b/vendor/github.com/moby/moby/client/utils.go @@ -70,11 +70,11 @@ func encodePlatform(platform *ocispec.Platform) (string, error) { return string(p), nil } -func decodeWithRaw[T any](resp *http.Response, out *T) (raw []byte, _ error) { +func decodeWithRaw[T any](resp *http.Response, out *T) (raw json.RawMessage, _ error) { if resp == nil || resp.Body == nil { return nil, errors.New("empty response") } - defer resp.Body.Close() + defer ensureReaderClosed(resp) var buf bytes.Buffer tr := io.TeeReader(resp.Body, &buf) diff --git a/vendor/github.com/moby/moby/client/volume_inspect.go b/vendor/github.com/moby/moby/client/volume_inspect.go index 1fa62bd9e..cf00236a2 100644 --- a/vendor/github.com/moby/moby/client/volume_inspect.go +++ b/vendor/github.com/moby/moby/client/volume_inspect.go @@ -2,6 +2,7 @@ package client import ( "context" + "encoding/json" "github.com/moby/moby/api/types/volume" ) @@ -13,8 +14,8 @@ type VolumeInspectOptions struct { // VolumeInspectResult holds the result from the [Client.VolumeInspect] method. type VolumeInspectResult struct { - Raw []byte Volume volume.Volume + Raw json.RawMessage } // VolumeInspect returns the information about a specific volume in the docker host. @@ -25,7 +26,6 @@ func (cli *Client) VolumeInspect(ctx context.Context, volumeID string, options V } resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil) - defer ensureReaderClosed(resp) if err != nil { return VolumeInspectResult{}, err } diff --git a/vendor/github.com/moby/moby/client/volume_list.go b/vendor/github.com/moby/moby/client/volume_list.go index 0c5bd7e61..802f104ea 100644 --- a/vendor/github.com/moby/moby/client/volume_list.go +++ b/vendor/github.com/moby/moby/client/volume_list.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "net/url" + "slices" "github.com/moby/moby/api/types/volume" ) @@ -15,7 +16,11 @@ type VolumeListOptions struct { // VolumeListResult holds the result from the [Client.VolumeList] method. type VolumeListResult struct { - Items volume.ListResponse + // List of volumes. + Items []volume.Volume + + // Warnings that occurred when fetching the list of volumes. + Warnings []string } // VolumeList returns the volumes configured in the docker host. @@ -29,7 +34,22 @@ func (cli *Client) VolumeList(ctx context.Context, options VolumeListOptions) (V return VolumeListResult{}, err } - var res VolumeListResult - err = json.NewDecoder(resp.Body).Decode(&res.Items) - return res, err + var apiResp volume.ListResponse + err = json.NewDecoder(resp.Body).Decode(&apiResp) + if err != nil { + return VolumeListResult{}, err + } + + res := VolumeListResult{ + Items: make([]volume.Volume, 0, len(apiResp.Volumes)), + Warnings: slices.Clone(apiResp.Warnings), + } + + for _, vol := range apiResp.Volumes { + if vol != nil { + res.Items = append(res.Items, *vol) + } + } + + return res, nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index b3b3acdb1..b417a7725 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -168,7 +168,7 @@ github.com/moby/docker-image-spec/specs-go/v1 github.com/moby/go-archive github.com/moby/go-archive/compression github.com/moby/go-archive/tarheader -# github.com/moby/moby/api v1.52.0-beta.2.0.20251023134003-dcd668d5796b +# github.com/moby/moby/api v1.52.0-beta.2.0.20251024193508-be8d6e2f2825 ## explicit; go 1.23.0 github.com/moby/moby/api/pkg/authconfig github.com/moby/moby/api/pkg/progress @@ -191,9 +191,8 @@ github.com/moby/moby/api/types/registry github.com/moby/moby/api/types/storage github.com/moby/moby/api/types/swarm github.com/moby/moby/api/types/system -github.com/moby/moby/api/types/versions github.com/moby/moby/api/types/volume -# github.com/moby/moby/client v0.1.0-beta.2.0.20251023134003-dcd668d5796b +# github.com/moby/moby/client v0.1.0-beta.2.0.20251024193508-be8d6e2f2825 ## explicit; go 1.23.0 github.com/moby/moby/client github.com/moby/moby/client/internal @@ -201,6 +200,7 @@ github.com/moby/moby/client/internal/timestamp github.com/moby/moby/client/pkg/jsonmessage github.com/moby/moby/client/pkg/security github.com/moby/moby/client/pkg/stringid +github.com/moby/moby/client/pkg/versions # github.com/moby/patternmatcher v0.6.0 ## explicit; go 1.19 github.com/moby/patternmatcher