From ebef4efb8824c516e70dd17c123360d20d23d7b9 Mon Sep 17 00:00:00 2001
From: Sebastiaan van Stijn <github@gone.nl>
Date: Sat, 26 Aug 2023 00:19:21 +0200
Subject: [PATCH] api/types: move ContainerLogsOptions to api/types/container

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
---
 api/server/httputils/write_log_stream.go      |  4 +--
 api/server/router/container/backend.go        |  2 +-
 .../router/container/container_routes.go      |  2 +-
 api/server/router/swarm/backend.go            |  3 ++-
 api/server/router/swarm/helpers.go            |  5 ++--
 api/types/client.go                           | 12 ---------
 api/types/container/options.go                | 12 +++++++++
 api/types/types_deprecated.go                 |  5 ++++
 client/container_logs.go                      |  4 +--
 client/container_logs_test.go                 | 26 +++++++++----------
 client/interface.go                           |  6 ++---
 client/service_logs.go                        |  4 +--
 client/service_logs_test.go                   | 18 ++++++-------
 client/task_logs.go                           |  4 +--
 daemon/cluster/executor/backend.go            |  2 +-
 daemon/cluster/executor/container/adapter.go  |  2 +-
 daemon/cluster/services.go                    |  3 ++-
 daemon/logs.go                                |  3 +--
 integration-cli/docker_api_logs_test.go       | 24 ++++++++++-------
 integration/build/build_squash_test.go        |  3 ++-
 integration/build/build_userns_linux_test.go  |  3 ++-
 .../capabilities/capabilities_linux_test.go   |  3 ++-
 integration/container/cdi_test.go             |  3 +--
 integration/container/logs_test.go            | 17 ++++++------
 integration/container/nat_test.go             |  4 +--
 integration/container/run_linux_test.go       |  7 +++--
 integration/container/stop_linux_test.go      |  3 +--
 integration/daemon/daemon_test.go             |  2 +-
 integration/plugin/logging/read_test.go       |  2 +-
 integration/service/create_test.go            |  4 +--
 30 files changed, 101 insertions(+), 91 deletions(-)

diff --git a/api/server/httputils/write_log_stream.go b/api/server/httputils/write_log_stream.go
index 22be5bb1c3..8faacc029e 100644
--- a/api/server/httputils/write_log_stream.go
+++ b/api/server/httputils/write_log_stream.go
@@ -7,8 +7,8 @@ import (
 	"net/url"
 	"sort"
 
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
+	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/pkg/jsonmessage"
 	"github.com/docker/docker/pkg/stdcopy"
@@ -16,7 +16,7 @@ import (
 
 // WriteLogStream writes an encoded byte stream of log messages from the
 // messages channel, multiplexing them with a stdcopy.Writer if mux is true
-func WriteLogStream(_ context.Context, w io.Writer, msgs <-chan *backend.LogMessage, config *types.ContainerLogsOptions, mux bool) {
+func WriteLogStream(_ context.Context, w io.Writer, msgs <-chan *backend.LogMessage, config *container.LogsOptions, mux bool) {
 	wf := ioutils.NewWriteFlusher(w)
 	defer wf.Close()
 
diff --git a/api/server/router/container/backend.go b/api/server/router/container/backend.go
index 4a83f1a124..0819911d9e 100644
--- a/api/server/router/container/backend.go
+++ b/api/server/router/container/backend.go
@@ -50,7 +50,7 @@ type stateBackend interface {
 type monitorBackend interface {
 	ContainerChanges(ctx context.Context, name string) ([]archive.Change, error)
 	ContainerInspect(ctx context.Context, name string, size bool, version string) (interface{}, error)
-	ContainerLogs(ctx context.Context, name string, config *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
+	ContainerLogs(ctx context.Context, name string, config *container.LogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
 	ContainerStats(ctx context.Context, name string, config *backend.ContainerStatsConfig) error
 	ContainerTop(name string, psArgs string) (*container.ContainerTopOKBody, error)
 	Containers(ctx context.Context, config *container.ListOptions) ([]*types.Container, error)
diff --git a/api/server/router/container/container_routes.go b/api/server/router/container/container_routes.go
index ee381bc574..530d2168e5 100644
--- a/api/server/router/container/container_routes.go
+++ b/api/server/router/container/container_routes.go
@@ -142,7 +142,7 @@ func (s *containerRouter) getContainersLogs(ctx context.Context, w http.Response
 	}
 
 	containerName := vars["name"]
-	logsConfig := &types.ContainerLogsOptions{
+	logsConfig := &container.LogsOptions{
 		Follow:     httputils.BoolValue(r, "follow"),
 		Timestamps: httputils.BoolValue(r, "timestamps"),
 		Since:      r.Form.Get("since"),
diff --git a/api/server/router/swarm/backend.go b/api/server/router/swarm/backend.go
index 3a1de28fc2..a340f5b0be 100644
--- a/api/server/router/swarm/backend.go
+++ b/api/server/router/swarm/backend.go
@@ -5,6 +5,7 @@ import (
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
+	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/swarm"
 )
 
@@ -22,7 +23,7 @@ type Backend interface {
 	CreateService(swarm.ServiceSpec, string, bool) (*swarm.ServiceCreateResponse, error)
 	UpdateService(string, uint64, swarm.ServiceSpec, types.ServiceUpdateOptions, bool) (*swarm.ServiceUpdateResponse, error)
 	RemoveService(string) error
-	ServiceLogs(context.Context, *backend.LogSelector, *types.ContainerLogsOptions) (<-chan *backend.LogMessage, error)
+	ServiceLogs(context.Context, *backend.LogSelector, *container.LogsOptions) (<-chan *backend.LogMessage, error)
 	GetNodes(types.NodeListOptions) ([]swarm.Node, error)
 	GetNode(string) (swarm.Node, error)
 	UpdateNode(string, uint64, swarm.NodeSpec) error
diff --git a/api/server/router/swarm/helpers.go b/api/server/router/swarm/helpers.go
index 16de015cda..816ba7c9fa 100644
--- a/api/server/router/swarm/helpers.go
+++ b/api/server/router/swarm/helpers.go
@@ -8,6 +8,7 @@ import (
 	"github.com/docker/docker/api/server/httputils"
 	basictypes "github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
+	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/swarm"
 	"github.com/docker/docker/api/types/versions"
 )
@@ -25,9 +26,9 @@ func (sr *swarmRouter) swarmLogs(ctx context.Context, w http.ResponseWriter, r *
 		return fmt.Errorf("Bad parameters: you must choose at least one stream")
 	}
 
-	// there is probably a neater way to manufacture the ContainerLogsOptions
+	// there is probably a neater way to manufacture the LogsOptions
 	// struct, probably in the caller, to eliminate the dependency on net/http
-	logsConfig := &basictypes.ContainerLogsOptions{
+	logsConfig := &container.LogsOptions{
 		Follow:     httputils.BoolValue(r, "follow"),
 		Timestamps: httputils.BoolValue(r, "timestamps"),
 		Since:      r.Form.Get("since"),
diff --git a/api/types/client.go b/api/types/client.go
index 904a7f859f..24b00a2759 100644
--- a/api/types/client.go
+++ b/api/types/client.go
@@ -20,18 +20,6 @@ type ContainerExecInspect struct {
 	Pid         int
 }
 
-// ContainerLogsOptions holds parameters to filter logs with.
-type ContainerLogsOptions struct {
-	ShowStdout bool
-	ShowStderr bool
-	Since      string
-	Until      string
-	Timestamps bool
-	Follow     bool
-	Tail       string
-	Details    bool
-}
-
 // CopyToContainerOptions holds information
 // about files to copy into a container
 type CopyToContainerOptions struct {
diff --git a/api/types/container/options.go b/api/types/container/options.go
index 7ddf33c687..7a23005769 100644
--- a/api/types/container/options.go
+++ b/api/types/container/options.go
@@ -53,3 +53,15 @@ type ListOptions struct {
 	Limit   int
 	Filters filters.Args
 }
+
+// LogsOptions holds parameters to filter logs with.
+type LogsOptions struct {
+	ShowStdout bool
+	ShowStderr bool
+	Since      string
+	Until      string
+	Timestamps bool
+	Follow     bool
+	Tail       string
+	Details    bool
+}
diff --git a/api/types/types_deprecated.go b/api/types/types_deprecated.go
index 7d4e919c3a..e332a7bb6d 100644
--- a/api/types/types_deprecated.go
+++ b/api/types/types_deprecated.go
@@ -119,6 +119,11 @@ type ContainerCommitOptions = container.CommitOptions
 // Deprecated: use [container.ListOptions].
 type ContainerListOptions = container.ListOptions
 
+// ContainerLogsOptions holds parameters to filter logs with.
+//
+// Deprecated: use [container.LogsOptions].
+type ContainerLogsOptions = container.LogsOptions
+
 // ContainerRemoveOptions holds parameters to remove containers.
 //
 // Deprecated: use [container.RemoveOptions].
diff --git a/client/container_logs.go b/client/container_logs.go
index 9bdf2b0fa6..61197d8407 100644
--- a/client/container_logs.go
+++ b/client/container_logs.go
@@ -6,7 +6,7 @@ import (
 	"net/url"
 	"time"
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/container"
 	timetypes "github.com/docker/docker/api/types/time"
 	"github.com/pkg/errors"
 )
@@ -33,7 +33,7 @@ import (
 //
 // You can use github.com/docker/docker/pkg/stdcopy.StdCopy to demultiplex this
 // stream.
-func (cli *Client) ContainerLogs(ctx context.Context, container string, options types.ContainerLogsOptions) (io.ReadCloser, error) {
+func (cli *Client) ContainerLogs(ctx context.Context, container string, options container.LogsOptions) (io.ReadCloser, error) {
 	query := url.Values{}
 	if options.ShowStdout {
 		query.Set("stdout", "1")
diff --git a/client/container_logs_test.go b/client/container_logs_test.go
index ce7a1bee55..4e04da253b 100644
--- a/client/container_logs_test.go
+++ b/client/container_logs_test.go
@@ -12,7 +12,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/errdefs"
 	"gotest.tools/v3/assert"
 	is "gotest.tools/v3/assert/cmp"
@@ -22,7 +22,7 @@ func TestContainerLogsNotFoundError(t *testing.T) {
 	client := &Client{
 		client: newMockClient(errorMock(http.StatusNotFound, "Not found")),
 	}
-	_, err := client.ContainerLogs(context.Background(), "container_id", types.ContainerLogsOptions{})
+	_, err := client.ContainerLogs(context.Background(), "container_id", container.LogsOptions{})
 	assert.Check(t, is.ErrorType(err, errdefs.IsNotFound))
 }
 
@@ -30,14 +30,14 @@ func TestContainerLogsError(t *testing.T) {
 	client := &Client{
 		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
 	}
-	_, err := client.ContainerLogs(context.Background(), "container_id", types.ContainerLogsOptions{})
+	_, err := client.ContainerLogs(context.Background(), "container_id", container.LogsOptions{})
 	assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
 
-	_, err = client.ContainerLogs(context.Background(), "container_id", types.ContainerLogsOptions{
+	_, err = client.ContainerLogs(context.Background(), "container_id", container.LogsOptions{
 		Since: "2006-01-02TZ",
 	})
 	assert.Check(t, is.ErrorContains(err, `parsing time "2006-01-02TZ"`))
-	_, err = client.ContainerLogs(context.Background(), "container_id", types.ContainerLogsOptions{
+	_, err = client.ContainerLogs(context.Background(), "container_id", container.LogsOptions{
 		Until: "2006-01-02TZ",
 	})
 	assert.Check(t, is.ErrorContains(err, `parsing time "2006-01-02TZ"`))
@@ -46,7 +46,7 @@ func TestContainerLogsError(t *testing.T) {
 func TestContainerLogs(t *testing.T) {
 	expectedURL := "/containers/container_id/logs"
 	cases := []struct {
-		options             types.ContainerLogsOptions
+		options             container.LogsOptions
 		expectedQueryParams map[string]string
 		expectedError       string
 	}{
@@ -56,7 +56,7 @@ func TestContainerLogs(t *testing.T) {
 			},
 		},
 		{
-			options: types.ContainerLogsOptions{
+			options: container.LogsOptions{
 				Tail: "any",
 			},
 			expectedQueryParams: map[string]string{
@@ -64,7 +64,7 @@ func TestContainerLogs(t *testing.T) {
 			},
 		},
 		{
-			options: types.ContainerLogsOptions{
+			options: container.LogsOptions{
 				ShowStdout: true,
 				ShowStderr: true,
 				Timestamps: true,
@@ -81,7 +81,7 @@ func TestContainerLogs(t *testing.T) {
 			},
 		},
 		{
-			options: types.ContainerLogsOptions{
+			options: container.LogsOptions{
 				// timestamp will be passed as is
 				Since: "1136073600.000000001",
 			},
@@ -91,7 +91,7 @@ func TestContainerLogs(t *testing.T) {
 			},
 		},
 		{
-			options: types.ContainerLogsOptions{
+			options: container.LogsOptions{
 				// timestamp will be passed as is
 				Until: "1136073600.000000001",
 			},
@@ -101,14 +101,14 @@ func TestContainerLogs(t *testing.T) {
 			},
 		},
 		{
-			options: types.ContainerLogsOptions{
+			options: container.LogsOptions{
 				// An complete invalid date will not be passed
 				Since: "invalid value",
 			},
 			expectedError: `invalid value for "since": failed to parse value as time or duration: "invalid value"`,
 		},
 		{
-			options: types.ContainerLogsOptions{
+			options: container.LogsOptions{
 				// An complete invalid date will not be passed
 				Until: "invalid value",
 			},
@@ -153,7 +153,7 @@ func ExampleClient_ContainerLogs_withTimeout() {
 	defer cancel()
 
 	client, _ := NewClientWithOpts(FromEnv)
-	reader, err := client.ContainerLogs(ctx, "container_id", types.ContainerLogsOptions{})
+	reader, err := client.ContainerLogs(ctx, "container_id", container.LogsOptions{})
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/client/interface.go b/client/interface.go
index 30b7d533e7..302f5fb13e 100644
--- a/client/interface.go
+++ b/client/interface.go
@@ -60,7 +60,7 @@ type ContainerAPIClient interface {
 	ContainerInspectWithRaw(ctx context.Context, container string, getSize bool) (types.ContainerJSON, []byte, error)
 	ContainerKill(ctx context.Context, container, signal string) error
 	ContainerList(ctx context.Context, options container.ListOptions) ([]types.Container, error)
-	ContainerLogs(ctx context.Context, container string, options types.ContainerLogsOptions) (io.ReadCloser, error)
+	ContainerLogs(ctx context.Context, container string, options container.LogsOptions) (io.ReadCloser, error)
 	ContainerPause(ctx context.Context, container string) error
 	ContainerRemove(ctx context.Context, container string, options container.RemoveOptions) error
 	ContainerRename(ctx context.Context, container, newContainerName string) error
@@ -146,8 +146,8 @@ type ServiceAPIClient interface {
 	ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error)
 	ServiceRemove(ctx context.Context, serviceID string) error
 	ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
-	ServiceLogs(ctx context.Context, serviceID string, options types.ContainerLogsOptions) (io.ReadCloser, error)
-	TaskLogs(ctx context.Context, taskID string, options types.ContainerLogsOptions) (io.ReadCloser, error)
+	ServiceLogs(ctx context.Context, serviceID string, options container.LogsOptions) (io.ReadCloser, error)
+	TaskLogs(ctx context.Context, taskID string, options container.LogsOptions) (io.ReadCloser, error)
 	TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error)
 	TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error)
 }
diff --git a/client/service_logs.go b/client/service_logs.go
index 906fd4059e..e9e30a2ab4 100644
--- a/client/service_logs.go
+++ b/client/service_logs.go
@@ -6,14 +6,14 @@ import (
 	"net/url"
 	"time"
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/container"
 	timetypes "github.com/docker/docker/api/types/time"
 	"github.com/pkg/errors"
 )
 
 // ServiceLogs returns the logs generated by a service in an io.ReadCloser.
 // It's up to the caller to close the stream.
-func (cli *Client) ServiceLogs(ctx context.Context, serviceID string, options types.ContainerLogsOptions) (io.ReadCloser, error) {
+func (cli *Client) ServiceLogs(ctx context.Context, serviceID string, options container.LogsOptions) (io.ReadCloser, error) {
 	query := url.Values{}
 	if options.ShowStdout {
 		query.Set("stdout", "1")
diff --git a/client/service_logs_test.go b/client/service_logs_test.go
index 7501e23be5..0c557685be 100644
--- a/client/service_logs_test.go
+++ b/client/service_logs_test.go
@@ -12,7 +12,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/errdefs"
 	"gotest.tools/v3/assert"
 	is "gotest.tools/v3/assert/cmp"
@@ -22,10 +22,10 @@ func TestServiceLogsError(t *testing.T) {
 	client := &Client{
 		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
 	}
-	_, err := client.ServiceLogs(context.Background(), "service_id", types.ContainerLogsOptions{})
+	_, err := client.ServiceLogs(context.Background(), "service_id", container.LogsOptions{})
 	assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
 
-	_, err = client.ServiceLogs(context.Background(), "service_id", types.ContainerLogsOptions{
+	_, err = client.ServiceLogs(context.Background(), "service_id", container.LogsOptions{
 		Since: "2006-01-02TZ",
 	})
 	assert.Check(t, is.ErrorContains(err, `parsing time "2006-01-02TZ"`))
@@ -34,7 +34,7 @@ func TestServiceLogsError(t *testing.T) {
 func TestServiceLogs(t *testing.T) {
 	expectedURL := "/services/service_id/logs"
 	cases := []struct {
-		options             types.ContainerLogsOptions
+		options             container.LogsOptions
 		expectedQueryParams map[string]string
 		expectedError       string
 	}{
@@ -44,7 +44,7 @@ func TestServiceLogs(t *testing.T) {
 			},
 		},
 		{
-			options: types.ContainerLogsOptions{
+			options: container.LogsOptions{
 				Tail: "any",
 			},
 			expectedQueryParams: map[string]string{
@@ -52,7 +52,7 @@ func TestServiceLogs(t *testing.T) {
 			},
 		},
 		{
-			options: types.ContainerLogsOptions{
+			options: container.LogsOptions{
 				ShowStdout: true,
 				ShowStderr: true,
 				Timestamps: true,
@@ -69,7 +69,7 @@ func TestServiceLogs(t *testing.T) {
 			},
 		},
 		{
-			options: types.ContainerLogsOptions{
+			options: container.LogsOptions{
 				// timestamp will be passed as is
 				Since: "1136073600.000000001",
 			},
@@ -79,7 +79,7 @@ func TestServiceLogs(t *testing.T) {
 			},
 		},
 		{
-			options: types.ContainerLogsOptions{
+			options: container.LogsOptions{
 				// An complete invalid date will not be passed
 				Since: "invalid value",
 			},
@@ -124,7 +124,7 @@ func ExampleClient_ServiceLogs_withTimeout() {
 	defer cancel()
 
 	client, _ := NewClientWithOpts(FromEnv)
-	reader, err := client.ServiceLogs(ctx, "service_id", types.ContainerLogsOptions{})
+	reader, err := client.ServiceLogs(ctx, "service_id", container.LogsOptions{})
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/client/task_logs.go b/client/task_logs.go
index 6222fab577..b8c20e71da 100644
--- a/client/task_logs.go
+++ b/client/task_logs.go
@@ -6,13 +6,13 @@ import (
 	"net/url"
 	"time"
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/container"
 	timetypes "github.com/docker/docker/api/types/time"
 )
 
 // TaskLogs returns the logs generated by a task in an io.ReadCloser.
 // It's up to the caller to close the stream.
-func (cli *Client) TaskLogs(ctx context.Context, taskID string, options types.ContainerLogsOptions) (io.ReadCloser, error) {
+func (cli *Client) TaskLogs(ctx context.Context, taskID string, options container.LogsOptions) (io.ReadCloser, error) {
 	query := url.Values{}
 	if options.ShowStdout {
 		query.Set("stdout", "1")
diff --git a/daemon/cluster/executor/backend.go b/daemon/cluster/executor/backend.go
index d24dbc28ae..3813fc1c50 100644
--- a/daemon/cluster/executor/backend.go
+++ b/daemon/cluster/executor/backend.go
@@ -41,7 +41,7 @@ type Backend interface {
 	CreateManagedContainer(ctx context.Context, config types.ContainerCreateConfig) (container.CreateResponse, error)
 	ContainerStart(ctx context.Context, name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
 	ContainerStop(ctx context.Context, name string, config container.StopOptions) error
-	ContainerLogs(ctx context.Context, name string, config *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
+	ContainerLogs(ctx context.Context, name string, config *container.LogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
 	ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
 	ActivateContainerServiceBinding(containerName string) error
 	DeactivateContainerServiceBinding(containerName string) error
diff --git a/daemon/cluster/executor/container/adapter.go b/daemon/cluster/executor/container/adapter.go
index e59648736a..32e1d3dbd0 100644
--- a/daemon/cluster/executor/container/adapter.go
+++ b/daemon/cluster/executor/container/adapter.go
@@ -489,7 +489,7 @@ func (c *containerAdapter) deactivateServiceBinding() error {
 }
 
 func (c *containerAdapter) logs(ctx context.Context, options api.LogSubscriptionOptions) (<-chan *backend.LogMessage, error) {
-	apiOptions := &types.ContainerLogsOptions{
+	apiOptions := &containertypes.LogsOptions{
 		Follow: options.Follow,
 
 		// Always say yes to Timestamps and Details. we make the decision
diff --git a/daemon/cluster/services.go b/daemon/cluster/services.go
index f05f23073c..5164cd0846 100644
--- a/daemon/cluster/services.go
+++ b/daemon/cluster/services.go
@@ -15,6 +15,7 @@ import (
 	"github.com/distribution/reference"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
+	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/registry"
 	"github.com/docker/docker/api/types/swarm"
 	timetypes "github.com/docker/docker/api/types/time"
@@ -422,7 +423,7 @@ func (c *Cluster) RemoveService(input string) error {
 }
 
 // ServiceLogs collects service logs and writes them back to `config.OutStream`
-func (c *Cluster) ServiceLogs(ctx context.Context, selector *backend.LogSelector, config *types.ContainerLogsOptions) (<-chan *backend.LogMessage, error) {
+func (c *Cluster) ServiceLogs(ctx context.Context, selector *backend.LogSelector, config *container.LogsOptions) (<-chan *backend.LogMessage, error) {
 	c.mu.RLock()
 	defer c.mu.RUnlock()
 
diff --git a/daemon/logs.go b/daemon/logs.go
index 6e1267212b..c48a77c987 100644
--- a/daemon/logs.go
+++ b/daemon/logs.go
@@ -6,7 +6,6 @@ import (
 	"time"
 
 	"github.com/containerd/log"
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
 	containertypes "github.com/docker/docker/api/types/container"
 	timetypes "github.com/docker/docker/api/types/time"
@@ -24,7 +23,7 @@ import (
 //
 // if it returns nil, the config channel will be active and return log
 // messages until it runs out or the context is canceled.
-func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, config *types.ContainerLogsOptions) (messages <-chan *backend.LogMessage, isTTY bool, retErr error) {
+func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, config *containertypes.LogsOptions) (messages <-chan *backend.LogMessage, isTTY bool, retErr error) {
 	lg := log.G(ctx).WithFields(log.Fields{
 		"module":    "daemon",
 		"method":    "(*Daemon).ContainerLogs",
diff --git a/integration-cli/docker_api_logs_test.go b/integration-cli/docker_api_logs_test.go
index 69fbe73de8..dc3c60b648 100644
--- a/integration-cli/docker_api_logs_test.go
+++ b/integration-cli/docker_api_logs_test.go
@@ -11,7 +11,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/client"
 	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/docker/docker/testutil"
@@ -62,7 +62,7 @@ func (s *DockerAPISuite) TestLogsAPINoStdoutNorStderr(c *testing.T) {
 	assert.NilError(c, err)
 	defer apiClient.Close()
 
-	_, err = apiClient.ContainerLogs(testutil.GetContext(c), name, types.ContainerLogsOptions{})
+	_, err = apiClient.ContainerLogs(testutil.GetContext(c), name, container.LogsOptions{})
 	assert.ErrorContains(c, err, "Bad parameters: you must choose at least one stream")
 }
 
@@ -105,8 +105,12 @@ func (s *DockerAPISuite) TestLogsAPIUntilFutureFollow(c *testing.T) {
 		c.Fatal(err)
 	}
 
-	cfg := types.ContainerLogsOptions{Until: until.Format(time.RFC3339Nano), Follow: true, ShowStdout: true, Timestamps: true}
-	reader, err := client.ContainerLogs(testutil.GetContext(c), name, cfg)
+	reader, err := client.ContainerLogs(testutil.GetContext(c), name, container.LogsOptions{
+		Until:      until.Format(time.RFC3339Nano),
+		Follow:     true,
+		ShowStdout: true,
+		Timestamps: true,
+	})
 	assert.NilError(c, err)
 
 	type logOut struct {
@@ -167,7 +171,7 @@ func (s *DockerAPISuite) TestLogsAPIUntil(c *testing.T) {
 		c.Fatal(err)
 	}
 
-	extractBody := func(c *testing.T, cfg types.ContainerLogsOptions) []string {
+	extractBody := func(c *testing.T, cfg container.LogsOptions) []string {
 		reader, err := client.ContainerLogs(testutil.GetContext(c), name, cfg)
 		assert.NilError(c, err)
 
@@ -180,7 +184,7 @@ func (s *DockerAPISuite) TestLogsAPIUntil(c *testing.T) {
 	}
 
 	// Get timestamp of second log line
-	allLogs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true})
+	allLogs := extractBody(c, container.LogsOptions{Timestamps: true, ShowStdout: true})
 	assert.Assert(c, len(allLogs) >= 3)
 
 	t, err := time.Parse(time.RFC3339Nano, strings.Split(allLogs[1], " ")[0])
@@ -188,7 +192,7 @@ func (s *DockerAPISuite) TestLogsAPIUntil(c *testing.T) {
 	until := t.Format(time.RFC3339Nano)
 
 	// Get logs until the timestamp of second line, i.e. first two lines
-	logs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true, Until: until})
+	logs := extractBody(c, container.LogsOptions{Timestamps: true, ShowStdout: true, Until: until})
 
 	// Ensure log lines after cut-off are excluded
 	logsString := strings.Join(logs, "\n")
@@ -204,7 +208,7 @@ func (s *DockerAPISuite) TestLogsAPIUntilDefaultValue(c *testing.T) {
 		c.Fatal(err)
 	}
 
-	extractBody := func(c *testing.T, cfg types.ContainerLogsOptions) []string {
+	extractBody := func(c *testing.T, cfg container.LogsOptions) []string {
 		reader, err := client.ContainerLogs(testutil.GetContext(c), name, cfg)
 		assert.NilError(c, err)
 
@@ -217,9 +221,9 @@ func (s *DockerAPISuite) TestLogsAPIUntilDefaultValue(c *testing.T) {
 	}
 
 	// Get timestamp of second log line
-	allLogs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true})
+	allLogs := extractBody(c, container.LogsOptions{Timestamps: true, ShowStdout: true})
 
 	// Test with default value specified and parameter omitted
-	defaultLogs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true, Until: "0"})
+	defaultLogs := extractBody(c, container.LogsOptions{Timestamps: true, ShowStdout: true, Until: "0"})
 	assert.DeepEqual(c, defaultLogs, allLogs)
 }
diff --git a/integration/build/build_squash_test.go b/integration/build/build_squash_test.go
index f9c830bd43..2a2d034e4d 100644
--- a/integration/build/build_squash_test.go
+++ b/integration/build/build_squash_test.go
@@ -7,6 +7,7 @@ import (
 	"testing"
 
 	"github.com/docker/docker/api/types"
+	containertypes "github.com/docker/docker/api/types/container"
 	dclient "github.com/docker/docker/client"
 	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/docker/pkg/stdcopy"
@@ -84,7 +85,7 @@ func TestBuildSquashParent(t *testing.T) {
 		container.WithImage(name),
 		container.WithCmd("/bin/sh", "-c", "cat /hello"),
 	)
-	reader, err := client.ContainerLogs(ctx, cid, types.ContainerLogsOptions{
+	reader, err := client.ContainerLogs(ctx, cid, containertypes.LogsOptions{
 		ShowStdout: true,
 	})
 	assert.NilError(t, err)
diff --git a/integration/build/build_userns_linux_test.go b/integration/build/build_userns_linux_test.go
index d465546aa8..0186429df6 100644
--- a/integration/build/build_userns_linux_test.go
+++ b/integration/build/build_userns_linux_test.go
@@ -9,6 +9,7 @@ import (
 	"testing"
 
 	"github.com/docker/docker/api/types"
+	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/docker/pkg/jsonmessage"
 	"github.com/docker/docker/pkg/stdcopy"
@@ -116,7 +117,7 @@ func TestBuildUserNamespaceValidateCapabilitiesAreV2(t *testing.T) {
 		container.WithImage(imageTag),
 		container.WithCmd("/sbin/getcap", "-n", "/bin/sleep"),
 	)
-	logReader, err := clientNoUserRemap.ContainerLogs(ctx, cid, types.ContainerLogsOptions{
+	logReader, err := clientNoUserRemap.ContainerLogs(ctx, cid, containertypes.LogsOptions{
 		ShowStdout: true,
 	})
 	assert.NilError(t, err)
diff --git a/integration/capabilities/capabilities_linux_test.go b/integration/capabilities/capabilities_linux_test.go
index 876ef1af05..3a661ddc93 100644
--- a/integration/capabilities/capabilities_linux_test.go
+++ b/integration/capabilities/capabilities_linux_test.go
@@ -8,6 +8,7 @@ import (
 	"time"
 
 	"github.com/docker/docker/api/types"
+	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/docker/docker/testutil"
@@ -83,7 +84,7 @@ func TestNoNewPrivileges(t *testing.T) {
 			poll.WaitOn(t, container.IsInState(ctx, client, cid, "exited"), poll.WithDelay(100*time.Millisecond))
 
 			// Assert on outputs
-			logReader, err := client.ContainerLogs(ctx, cid, types.ContainerLogsOptions{
+			logReader, err := client.ContainerLogs(ctx, cid, containertypes.LogsOptions{
 				ShowStdout: true,
 				ShowStderr: true,
 			})
diff --git a/integration/container/cdi_test.go b/integration/container/cdi_test.go
index 9c8b249ce3..95f80dc7db 100644
--- a/integration/container/cdi_test.go
+++ b/integration/container/cdi_test.go
@@ -9,7 +9,6 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/docker/docker/api/types"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/docker/pkg/stdcopy"
@@ -51,7 +50,7 @@ func TestCreateWithCDIDevices(t *testing.T) {
 	}
 	assert.Check(t, is.DeepEqual(inspect.HostConfig.DeviceRequests, expectedRequests))
 
-	reader, err := apiClient.ContainerLogs(ctx, id, types.ContainerLogsOptions{
+	reader, err := apiClient.ContainerLogs(ctx, id, containertypes.LogsOptions{
 		ShowStdout: true,
 	})
 	assert.NilError(t, err)
diff --git a/integration/container/logs_test.go b/integration/container/logs_test.go
index 171f5b7055..98ddbb777c 100644
--- a/integration/container/logs_test.go
+++ b/integration/container/logs_test.go
@@ -7,7 +7,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/docker/docker/api/types"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/daemon/logger/jsonfilelog"
 	"github.com/docker/docker/daemon/logger/local"
@@ -30,7 +29,7 @@ func TestLogsFollowTailEmpty(t *testing.T) {
 
 	id := container.Run(ctx, t, apiClient, container.WithCmd("sleep", "100000"))
 
-	logs, err := apiClient.ContainerLogs(ctx, id, types.ContainerLogsOptions{ShowStdout: true, Tail: "2"})
+	logs, err := apiClient.ContainerLogs(ctx, id, containertypes.LogsOptions{ShowStdout: true, Tail: "2"})
 	if logs != nil {
 		defer logs.Close()
 	}
@@ -56,7 +55,7 @@ func testLogs(t *testing.T, logDriver string) {
 
 	testCases := []struct {
 		desc        string
-		logOps      types.ContainerLogsOptions
+		logOps      containertypes.LogsOptions
 		expectedOut string
 		expectedErr string
 		tty         bool
@@ -65,7 +64,7 @@ func testLogs(t *testing.T, logDriver string) {
 		{
 			desc: "tty/stdout and stderr",
 			tty:  true,
-			logOps: types.ContainerLogsOptions{
+			logOps: containertypes.LogsOptions{
 				ShowStdout: true,
 				ShowStderr: true,
 			},
@@ -74,7 +73,7 @@ func testLogs(t *testing.T, logDriver string) {
 		{
 			desc: "tty/only stdout",
 			tty:  true,
-			logOps: types.ContainerLogsOptions{
+			logOps: containertypes.LogsOptions{
 				ShowStdout: true,
 				ShowStderr: false,
 			},
@@ -83,7 +82,7 @@ func testLogs(t *testing.T, logDriver string) {
 		{
 			desc: "tty/only stderr",
 			tty:  true,
-			logOps: types.ContainerLogsOptions{
+			logOps: containertypes.LogsOptions{
 				ShowStdout: false,
 				ShowStderr: true,
 			},
@@ -93,7 +92,7 @@ func testLogs(t *testing.T, logDriver string) {
 		{
 			desc: "without tty/stdout and stderr",
 			tty:  false,
-			logOps: types.ContainerLogsOptions{
+			logOps: containertypes.LogsOptions{
 				ShowStdout: true,
 				ShowStderr: true,
 			},
@@ -103,7 +102,7 @@ func testLogs(t *testing.T, logDriver string) {
 		{
 			desc: "without tty/only stdout",
 			tty:  false,
-			logOps: types.ContainerLogsOptions{
+			logOps: containertypes.LogsOptions{
 				ShowStdout: true,
 				ShowStderr: false,
 			},
@@ -113,7 +112,7 @@ func testLogs(t *testing.T, logDriver string) {
 		{
 			desc: "without tty/only stderr",
 			tty:  false,
-			logOps: types.ContainerLogsOptions{
+			logOps: containertypes.LogsOptions{
 				ShowStdout: false,
 				ShowStderr: true,
 			},
diff --git a/integration/container/nat_test.go b/integration/container/nat_test.go
index 492fe75ead..9506430dd3 100644
--- a/integration/container/nat_test.go
+++ b/integration/container/nat_test.go
@@ -10,7 +10,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/docker/docker/api/types"
+	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/go-connections/nat"
 	"gotest.tools/v3/assert"
@@ -77,7 +77,7 @@ func TestNetworkLoopbackNat(t *testing.T) {
 
 	poll.WaitOn(t, container.IsStopped(ctx, apiClient, cID), poll.WithDelay(100*time.Millisecond))
 
-	body, err := apiClient.ContainerLogs(ctx, cID, types.ContainerLogsOptions{
+	body, err := apiClient.ContainerLogs(ctx, cID, containertypes.LogsOptions{
 		ShowStdout: true,
 	})
 	assert.NilError(t, err)
diff --git a/integration/container/run_linux_test.go b/integration/container/run_linux_test.go
index 5ebacdc948..aedd8ef284 100644
--- a/integration/container/run_linux_test.go
+++ b/integration/container/run_linux_test.go
@@ -10,7 +10,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/docker/docker/api/types"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/versions"
 	"github.com/docker/docker/integration/internal/container"
@@ -191,7 +190,7 @@ func TestRunConsoleSize(t *testing.T) {
 
 	poll.WaitOn(t, container.IsStopped(ctx, apiClient, cID), poll.WithDelay(100*time.Millisecond))
 
-	out, err := apiClient.ContainerLogs(ctx, cID, types.ContainerLogsOptions{ShowStdout: true})
+	out, err := apiClient.ContainerLogs(ctx, cID, containertypes.LogsOptions{ShowStdout: true})
 	assert.NilError(t, err)
 	defer out.Close()
 
@@ -246,7 +245,7 @@ func TestRunWithAlternativeContainerdShim(t *testing.T) {
 
 	poll.WaitOn(t, container.IsStopped(ctx, apiClient, cID), poll.WithDelay(100*time.Millisecond))
 
-	out, err := apiClient.ContainerLogs(ctx, cID, types.ContainerLogsOptions{ShowStdout: true})
+	out, err := apiClient.ContainerLogs(ctx, cID, containertypes.LogsOptions{ShowStdout: true})
 	assert.NilError(t, err)
 	defer out.Close()
 
@@ -266,7 +265,7 @@ func TestRunWithAlternativeContainerdShim(t *testing.T) {
 
 	poll.WaitOn(t, container.IsStopped(ctx, apiClient, cID), poll.WithDelay(100*time.Millisecond))
 
-	out, err = apiClient.ContainerLogs(ctx, cID, types.ContainerLogsOptions{ShowStdout: true})
+	out, err = apiClient.ContainerLogs(ctx, cID, containertypes.LogsOptions{ShowStdout: true})
 	assert.NilError(t, err)
 	defer out.Close()
 
diff --git a/integration/container/stop_linux_test.go b/integration/container/stop_linux_test.go
index e5a0a7320f..fa7338da81 100644
--- a/integration/container/stop_linux_test.go
+++ b/integration/container/stop_linux_test.go
@@ -9,7 +9,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/docker/docker/api/types"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/client"
 	"github.com/docker/docker/errdefs"
@@ -128,7 +127,7 @@ func TestStopContainerWithTimeoutCancel(t *testing.T) {
 // logsContains verifies the container contains the given text in the log's stdout.
 func logsContains(ctx context.Context, client client.APIClient, containerID string, logString string) func(log poll.LogT) poll.Result {
 	return func(log poll.LogT) poll.Result {
-		logs, err := client.ContainerLogs(ctx, containerID, types.ContainerLogsOptions{
+		logs, err := client.ContainerLogs(ctx, containerID, containertypes.LogsOptions{
 			ShowStdout: true,
 		})
 		if err != nil {
diff --git a/integration/daemon/daemon_test.go b/integration/daemon/daemon_test.go
index d052fb4a04..0db0193bfc 100644
--- a/integration/daemon/daemon_test.go
+++ b/integration/daemon/daemon_test.go
@@ -493,7 +493,7 @@ func testLiveRestoreVolumeReferences(t *testing.T) {
 				assert.Check(t, is.Equal(inspect.State.ExitCode, 0), "volume doesn't have the same file")
 			}
 
-			logs, err := c.ContainerLogs(ctx, cID2, types.ContainerLogsOptions{ShowStdout: true})
+			logs, err := c.ContainerLogs(ctx, cID2, containertypes.LogsOptions{ShowStdout: true})
 			assert.NilError(t, err)
 			defer logs.Close()
 
diff --git a/integration/plugin/logging/read_test.go b/integration/plugin/logging/read_test.go
index ea61d50a9d..cb88e6c056 100644
--- a/integration/plugin/logging/read_test.go
+++ b/integration/plugin/logging/read_test.go
@@ -65,7 +65,7 @@ func TestReadPluginNoRead(t *testing.T) {
 			err = client.ContainerStart(ctx, c.ID, container.StartOptions{})
 			assert.Assert(t, err)
 
-			logs, err := client.ContainerLogs(ctx, c.ID, types.ContainerLogsOptions{ShowStdout: true})
+			logs, err := client.ContainerLogs(ctx, c.ID, container.LogsOptions{ShowStdout: true})
 			if !test.logsSupported {
 				assert.Assert(t, err != nil)
 				return
diff --git a/integration/service/create_test.go b/integration/service/create_test.go
index 6b56fc1c00..caeecf3f85 100644
--- a/integration/service/create_test.go
+++ b/integration/service/create_test.go
@@ -231,7 +231,7 @@ func TestCreateServiceSecretFileMode(t *testing.T) {
 
 	poll.WaitOn(t, swarm.RunningTasksCount(ctx, client, serviceID, instances), swarm.ServicePoll)
 
-	body, err := client.ServiceLogs(ctx, serviceID, types.ContainerLogsOptions{
+	body, err := client.ServiceLogs(ctx, serviceID, container.LogsOptions{
 		Tail:       "1",
 		ShowStdout: true,
 	})
@@ -288,7 +288,7 @@ func TestCreateServiceConfigFileMode(t *testing.T) {
 
 	poll.WaitOn(t, swarm.RunningTasksCount(ctx, client, serviceID, instances))
 
-	body, err := client.ServiceLogs(ctx, serviceID, types.ContainerLogsOptions{
+	body, err := client.ServiceLogs(ctx, serviceID, container.LogsOptions{
 		Tail:       "1",
 		ShowStdout: true,
 	})