Browse code

api/types: move ExecConfig to api/types/container

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2024/06/09 01:56:54
Showing 17 changed files
... ...
@@ -14,7 +14,7 @@ import (
14 14
 
15 15
 // execBackend includes functions to implement to provide exec functionality.
16 16
 type execBackend interface {
17
-	ContainerExecCreate(name string, config *types.ExecConfig) (string, error)
17
+	ContainerExecCreate(name string, options *container.ExecOptions) (string, error)
18 18
 	ContainerExecInspect(id string) (*backend.ExecInspect, error)
19 19
 	ContainerExecResize(name string, height, width int) error
20 20
 	ContainerExecStart(ctx context.Context, name string, options container.ExecStartOptions) error
... ...
@@ -38,7 +38,7 @@ func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.Re
38 38
 		return err
39 39
 	}
40 40
 
41
-	execConfig := &types.ExecConfig{}
41
+	execConfig := &container.ExecOptions{}
42 42
 	if err := httputils.ReadJSON(r, execConfig); err != nil {
43 43
 		return err
44 44
 	}
45 45
deleted file mode 100644
... ...
@@ -1,18 +0,0 @@
1
-package types // import "github.com/docker/docker/api/types"
2
-
3
-// ExecConfig is a small subset of the Config struct that holds the configuration
4
-// for the exec feature of docker.
5
-type ExecConfig struct {
6
-	User         string   // User that will run the command
7
-	Privileged   bool     // Is the container in privileged mode
8
-	Tty          bool     // Attach standard streams to a tty.
9
-	ConsoleSize  *[2]uint `json:",omitempty"` // Initial console size [height, width]
10
-	AttachStdin  bool     // Attach the standard input, makes possible user interaction
11
-	AttachStderr bool     // Attach the standard error
12
-	AttachStdout bool     // Attach the standard output
13
-	Detach       bool     // Execute in detach mode
14
-	DetachKeys   string   // Escape keys for detach
15
-	Env          []string // Environment variables
16
-	WorkingDir   string   // Working directory
17
-	Cmd          []string // Execution commands and args
18
-}
19 1
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+package container
1
+
2
+// ExecOptions is a small subset of the Config struct that holds the configuration
3
+// for the exec feature of docker.
4
+type ExecOptions struct {
5
+	User         string   // User that will run the command
6
+	Privileged   bool     // Is the container in privileged mode
7
+	Tty          bool     // Attach standard streams to a tty.
8
+	ConsoleSize  *[2]uint `json:",omitempty"` // Initial console size [height, width]
9
+	AttachStdin  bool     // Attach the standard input, makes possible user interaction
10
+	AttachStderr bool     // Attach the standard error
11
+	AttachStdout bool     // Attach the standard output
12
+	Detach       bool     // Execute in detach mode
13
+	DetachKeys   string   // Escape keys for detach
14
+	Env          []string // Environment variables
15
+	WorkingDir   string   // Working directory
16
+	Cmd          []string // Execution commands and args
17
+}
... ...
@@ -1,6 +1,7 @@
1 1
 package types
2 2
 
3 3
 import (
4
+	"github.com/docker/docker/api/types/container"
4 5
 	"github.com/docker/docker/api/types/network"
5 6
 )
6 7
 
... ...
@@ -54,3 +55,9 @@ type NetworkResource = network.Inspect
54 54
 //
55 55
 // Deprecated: use [network.PruneReport].
56 56
 type NetworksPruneReport = network.PruneReport
57
+
58
+// ExecConfig is a small subset of the Config struct that holds the configuration
59
+// for the exec feature of docker.
60
+//
61
+// Deprecated: use [container.ExecOptions].
62
+type ExecConfig = container.ExecOptions
... ...
@@ -6,11 +6,12 @@ import (
6 6
 	"net/http"
7 7
 
8 8
 	"github.com/docker/docker/api/types"
9
+	"github.com/docker/docker/api/types/container"
9 10
 	"github.com/docker/docker/api/types/versions"
10 11
 )
11 12
 
12 13
 // ContainerExecCreate creates a new exec configuration to run an exec process.
13
-func (cli *Client) ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error) {
14
+func (cli *Client) ContainerExecCreate(ctx context.Context, container string, options container.ExecOptions) (types.IDResponse, error) {
14 15
 	var response types.IDResponse
15 16
 
16 17
 	// Make sure we negotiated (if the client is configured to do so),
... ...
@@ -22,14 +23,14 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, container string, co
22 22
 		return response, err
23 23
 	}
24 24
 
25
-	if err := cli.NewVersionError(ctx, "1.25", "env"); len(config.Env) != 0 && err != nil {
25
+	if err := cli.NewVersionError(ctx, "1.25", "env"); len(options.Env) != 0 && err != nil {
26 26
 		return response, err
27 27
 	}
28 28
 	if versions.LessThan(cli.ClientVersion(), "1.42") {
29
-		config.ConsoleSize = nil
29
+		options.ConsoleSize = nil
30 30
 	}
31 31
 
32
-	resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, config, nil)
32
+	resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, options, nil)
33 33
 	defer ensureReaderClosed(resp)
34 34
 	if err != nil {
35 35
 		return response, err
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"testing"
12 12
 
13 13
 	"github.com/docker/docker/api/types"
14
+	"github.com/docker/docker/api/types/container"
14 15
 	"github.com/docker/docker/errdefs"
15 16
 	"gotest.tools/v3/assert"
16 17
 	is "gotest.tools/v3/assert/cmp"
... ...
@@ -20,7 +21,7 @@ func TestContainerExecCreateError(t *testing.T) {
20 20
 	client := &Client{
21 21
 		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
22 22
 	}
23
-	_, err := client.ContainerExecCreate(context.Background(), "container_id", types.ExecConfig{})
23
+	_, err := client.ContainerExecCreate(context.Background(), "container_id", container.ExecOptions{})
24 24
 	assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
25 25
 }
26 26
 
... ...
@@ -32,7 +33,7 @@ func TestContainerExecCreateConnectionError(t *testing.T) {
32 32
 	client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
33 33
 	assert.NilError(t, err)
34 34
 
35
-	_, err = client.ContainerExecCreate(context.Background(), "", types.ExecConfig{})
35
+	_, err = client.ContainerExecCreate(context.Background(), "", container.ExecOptions{})
36 36
 	assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
37 37
 }
38 38
 
... ...
@@ -50,7 +51,7 @@ func TestContainerExecCreate(t *testing.T) {
50 50
 			if err := req.ParseForm(); err != nil {
51 51
 				return nil, err
52 52
 			}
53
-			execConfig := &types.ExecConfig{}
53
+			execConfig := &container.ExecOptions{}
54 54
 			if err := json.NewDecoder(req.Body).Decode(execConfig); err != nil {
55 55
 				return nil, err
56 56
 			}
... ...
@@ -70,7 +71,7 @@ func TestContainerExecCreate(t *testing.T) {
70 70
 		}),
71 71
 	}
72 72
 
73
-	r, err := client.ContainerExecCreate(context.Background(), "container_id", types.ExecConfig{
73
+	r, err := client.ContainerExecCreate(context.Background(), "container_id", container.ExecOptions{
74 74
 		User: "user",
75 75
 	})
76 76
 	if err != nil {
... ...
@@ -51,7 +51,7 @@ type ContainerAPIClient interface {
51 51
 	ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error)
52 52
 	ContainerDiff(ctx context.Context, container string) ([]container.FilesystemChange, error)
53 53
 	ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error)
54
-	ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error)
54
+	ContainerExecCreate(ctx context.Context, container string, options container.ExecOptions) (types.IDResponse, error)
55 55
 	ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error)
56 56
 	ContainerExecResize(ctx context.Context, execID string, options container.ResizeOptions) error
57 57
 	ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error
... ...
@@ -11,7 +11,6 @@ import (
11 11
 
12 12
 	"github.com/containerd/containerd"
13 13
 	"github.com/containerd/log"
14
-	"github.com/docker/docker/api/types"
15 14
 	containertypes "github.com/docker/docker/api/types/container"
16 15
 	"github.com/docker/docker/api/types/events"
17 16
 	"github.com/docker/docker/api/types/strslice"
... ...
@@ -94,42 +93,42 @@ func (daemon *Daemon) getActiveContainer(name string) (*container.Container, err
94 94
 }
95 95
 
96 96
 // ContainerExecCreate sets up an exec in a running container.
97
-func (daemon *Daemon) ContainerExecCreate(name string, config *types.ExecConfig) (string, error) {
97
+func (daemon *Daemon) ContainerExecCreate(name string, options *containertypes.ExecOptions) (string, error) {
98 98
 	cntr, err := daemon.getActiveContainer(name)
99 99
 	if err != nil {
100 100
 		return "", err
101 101
 	}
102 102
 
103
-	cmd := strslice.StrSlice(config.Cmd)
103
+	cmd := strslice.StrSlice(options.Cmd)
104 104
 	entrypoint, args := daemon.getEntrypointAndArgs(strslice.StrSlice{}, cmd)
105 105
 
106 106
 	keys := []byte{}
107
-	if config.DetachKeys != "" {
108
-		keys, err = term.ToBytes(config.DetachKeys)
107
+	if options.DetachKeys != "" {
108
+		keys, err = term.ToBytes(options.DetachKeys)
109 109
 		if err != nil {
110
-			err = fmt.Errorf("Invalid escape keys (%s) provided", config.DetachKeys)
110
+			err = fmt.Errorf("Invalid escape keys (%s) provided", options.DetachKeys)
111 111
 			return "", err
112 112
 		}
113 113
 	}
114 114
 
115 115
 	execConfig := container.NewExecConfig(cntr)
116
-	execConfig.OpenStdin = config.AttachStdin
117
-	execConfig.OpenStdout = config.AttachStdout
118
-	execConfig.OpenStderr = config.AttachStderr
116
+	execConfig.OpenStdin = options.AttachStdin
117
+	execConfig.OpenStdout = options.AttachStdout
118
+	execConfig.OpenStderr = options.AttachStderr
119 119
 	execConfig.DetachKeys = keys
120 120
 	execConfig.Entrypoint = entrypoint
121 121
 	execConfig.Args = args
122
-	execConfig.Tty = config.Tty
123
-	execConfig.ConsoleSize = config.ConsoleSize
124
-	execConfig.Privileged = config.Privileged
125
-	execConfig.User = config.User
126
-	execConfig.WorkingDir = config.WorkingDir
122
+	execConfig.Tty = options.Tty
123
+	execConfig.ConsoleSize = options.ConsoleSize
124
+	execConfig.Privileged = options.Privileged
125
+	execConfig.User = options.User
126
+	execConfig.WorkingDir = options.WorkingDir
127 127
 
128 128
 	linkedEnv, err := daemon.setupLinkedContainers(cntr)
129 129
 	if err != nil {
130 130
 		return "", err
131 131
 	}
132
-	execConfig.Env = container.ReplaceOrAppendEnvValues(cntr.CreateDaemonEnvironment(config.Tty, linkedEnv), config.Env)
132
+	execConfig.Env = container.ReplaceOrAppendEnvValues(cntr.CreateDaemonEnvironment(options.Tty, linkedEnv), options.Env)
133 133
 	if len(execConfig.User) == 0 {
134 134
 		execConfig.User = cntr.Config.User
135 135
 	}
... ...
@@ -12,7 +12,7 @@ import (
12 12
 	"testing"
13 13
 	"time"
14 14
 
15
-	"github.com/docker/docker/api/types"
15
+	"github.com/docker/docker/api/types/container"
16 16
 	"github.com/docker/docker/client"
17 17
 	"github.com/docker/docker/integration-cli/checker"
18 18
 	"github.com/docker/docker/integration-cli/cli"
... ...
@@ -65,10 +65,9 @@ func (s *DockerAPISuite) TestExecAPICreateContainerPaused(c *testing.T) {
65 65
 	assert.NilError(c, err)
66 66
 	defer apiClient.Close()
67 67
 
68
-	config := types.ExecConfig{
68
+	_, err = apiClient.ContainerExecCreate(testutil.GetContext(c), name, container.ExecOptions{
69 69
 		Cmd: []string{"true"},
70
-	}
71
-	_, err = apiClient.ContainerExecCreate(testutil.GetContext(c), name, config)
70
+	})
72 71
 	assert.ErrorContains(c, err, "Container "+name+" is paused, unpause the container before exec", "Expected message when creating exec command with Container %s is paused", name)
73 72
 }
74 73
 
... ...
@@ -126,16 +125,14 @@ func (s *DockerAPISuite) TestExecAPIStartWithDetach(c *testing.T) {
126 126
 
127 127
 	ctx := testutil.GetContext(c)
128 128
 
129
-	config := types.ExecConfig{
130
-		Cmd:          []string{"true"},
131
-		AttachStderr: true,
132
-	}
133
-
134 129
 	apiClient, err := client.NewClientWithOpts(client.FromEnv)
135 130
 	assert.NilError(c, err)
136 131
 	defer apiClient.Close()
137 132
 
138
-	createResp, err := apiClient.ContainerExecCreate(ctx, name, config)
133
+	createResp, err := apiClient.ContainerExecCreate(ctx, name, container.ExecOptions{
134
+		Cmd:          []string{"true"},
135
+		AttachStderr: true,
136
+	})
139 137
 	assert.NilError(c, err)
140 138
 
141 139
 	_, body, err := request.Post(ctx, fmt.Sprintf("/exec/%s/start", createResp.ID), request.RawString(`{"Detach": true}`), request.JSON)
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"time"
10 10
 
11 11
 	"github.com/docker/docker/api/types"
12
+	"github.com/docker/docker/api/types/container"
12 13
 	"github.com/docker/docker/api/types/filters"
13 14
 	swarmtypes "github.com/docker/docker/api/types/swarm"
14 15
 	"github.com/docker/docker/client"
... ...
@@ -313,7 +314,7 @@ func TestTemplatedConfig(t *testing.T) {
313 313
 	tasks := swarm.GetRunningTasks(ctx, t, c, serviceID)
314 314
 	assert.Assert(t, len(tasks) > 0, "no running tasks found for service %s", serviceID)
315 315
 
316
-	attach := swarm.ExecTask(ctx, t, d, tasks[0], types.ExecConfig{
316
+	attach := swarm.ExecTask(ctx, t, d, tasks[0], container.ExecOptions{
317 317
 		Cmd:          []string{"/bin/cat", "/templated_config"},
318 318
 		AttachStdout: true,
319 319
 		AttachStderr: true,
... ...
@@ -324,7 +325,7 @@ func TestTemplatedConfig(t *testing.T) {
324 324
 		"this is a config\n"
325 325
 	assertAttachedStream(t, attach, expect)
326 326
 
327
-	attach = swarm.ExecTask(ctx, t, d, tasks[0], types.ExecConfig{
327
+	attach = swarm.ExecTask(ctx, t, d, tasks[0], container.ExecOptions{
328 328
 		Cmd:          []string{"mount"},
329 329
 		AttachStdout: true,
330 330
 		AttachStderr: true,
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"strings"
5 5
 	"testing"
6 6
 
7
-	"github.com/docker/docker/api/types"
7
+	containertypes "github.com/docker/docker/api/types/container"
8 8
 	"github.com/docker/docker/api/types/versions"
9 9
 	"github.com/docker/docker/integration/internal/container"
10 10
 	"gotest.tools/v3/assert"
... ...
@@ -21,7 +21,7 @@ func TestExecConsoleSize(t *testing.T) {
21 21
 	cID := container.Run(ctx, t, apiClient, container.WithImage("busybox"))
22 22
 
23 23
 	result, err := container.Exec(ctx, apiClient, cID, []string{"stty", "size"},
24
-		func(ec *types.ExecConfig) {
24
+		func(ec *containertypes.ExecOptions) {
25 25
 			ec.Tty = true
26 26
 			ec.ConsoleSize = &[2]uint{57, 123}
27 27
 		},
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"time"
8 8
 
9 9
 	"github.com/docker/docker/api/types"
10
+	containertypes "github.com/docker/docker/api/types/container"
10 11
 	"github.com/docker/docker/integration/internal/container"
11 12
 	"gotest.tools/v3/assert"
12 13
 	is "gotest.tools/v3/assert/cmp"
... ...
@@ -24,7 +25,7 @@ func TestExecWithCloseStdin(t *testing.T) {
24 24
 	cID := container.Run(ctx, t, apiClient)
25 25
 
26 26
 	const expected = "closeIO"
27
-	execResp, err := apiClient.ContainerExecCreate(ctx, cID, types.ExecConfig{
27
+	execResp, err := apiClient.ContainerExecCreate(ctx, cID, containertypes.ExecOptions{
28 28
 		AttachStdin:  true,
29 29
 		AttachStdout: true,
30 30
 		Cmd:          []string{"sh", "-c", "cat && echo " + expected},
... ...
@@ -79,7 +80,7 @@ func TestExec(t *testing.T) {
79 79
 
80 80
 	cID := container.Run(ctx, t, apiClient, container.WithTty(true), container.WithWorkingDir("/root"))
81 81
 
82
-	id, err := apiClient.ContainerExecCreate(ctx, cID, types.ExecConfig{
82
+	id, err := apiClient.ContainerExecCreate(ctx, cID, containertypes.ExecOptions{
83 83
 		WorkingDir:   "/tmp",
84 84
 		Env:          []string{"FOO=BAR"},
85 85
 		AttachStdout: true,
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	"testing"
7 7
 
8 8
 	"github.com/docker/docker/api/types"
9
+	"github.com/docker/docker/api/types/container"
9 10
 	"github.com/docker/docker/client"
10 11
 )
11 12
 
... ...
@@ -47,19 +48,19 @@ func (res ExecResult) AssertSuccess(t testing.TB) {
47 47
 // containing stdout, stderr, and exit code. Note:
48 48
 //   - this is a synchronous operation;
49 49
 //   - cmd stdin is closed.
50
-func Exec(ctx context.Context, apiClient client.APIClient, id string, cmd []string, ops ...func(*types.ExecConfig)) (ExecResult, error) {
50
+func Exec(ctx context.Context, apiClient client.APIClient, id string, cmd []string, ops ...func(*container.ExecOptions)) (ExecResult, error) {
51 51
 	// prepare exec
52
-	execConfig := types.ExecConfig{
52
+	execOptions := container.ExecOptions{
53 53
 		AttachStdout: true,
54 54
 		AttachStderr: true,
55 55
 		Cmd:          cmd,
56 56
 	}
57 57
 
58 58
 	for _, op := range ops {
59
-		op(&execConfig)
59
+		op(&execOptions)
60 60
 	}
61 61
 
62
-	cresp, err := apiClient.ContainerExecCreate(ctx, id, execConfig)
62
+	cresp, err := apiClient.ContainerExecCreate(ctx, id, execOptions)
63 63
 	if err != nil {
64 64
 		return ExecResult{}, err
65 65
 	}
... ...
@@ -87,7 +88,7 @@ func Exec(ctx context.Context, apiClient client.APIClient, id string, cmd []stri
87 87
 }
88 88
 
89 89
 // ExecT calls Exec() and aborts the test if an error occurs.
90
-func ExecT(ctx context.Context, t testing.TB, apiClient client.APIClient, id string, cmd []string, ops ...func(*types.ExecConfig)) ExecResult {
90
+func ExecT(ctx context.Context, t testing.TB, apiClient client.APIClient, id string, cmd []string, ops ...func(*container.ExecOptions)) ExecResult {
91 91
 	t.Helper()
92 92
 	res, err := Exec(ctx, apiClient, id, cmd, ops...)
93 93
 	if err != nil {
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"time"
8 8
 
9 9
 	"github.com/docker/docker/api/types"
10
+	"github.com/docker/docker/api/types/container"
10 11
 	"github.com/docker/docker/api/types/filters"
11 12
 	swarmtypes "github.com/docker/docker/api/types/swarm"
12 13
 	"github.com/docker/docker/client"
... ...
@@ -211,12 +212,12 @@ func GetRunningTasks(ctx context.Context, t *testing.T, c client.ServiceAPIClien
211 211
 }
212 212
 
213 213
 // ExecTask runs the passed in exec config on the given task
214
-func ExecTask(ctx context.Context, t *testing.T, d *daemon.Daemon, task swarmtypes.Task, config types.ExecConfig) types.HijackedResponse {
214
+func ExecTask(ctx context.Context, t *testing.T, d *daemon.Daemon, task swarmtypes.Task, options container.ExecOptions) types.HijackedResponse {
215 215
 	t.Helper()
216 216
 	apiClient := d.NewClientT(t)
217 217
 	defer apiClient.Close()
218 218
 
219
-	resp, err := apiClient.ContainerExecCreate(ctx, task.Status.ContainerStatus.ContainerID, config)
219
+	resp, err := apiClient.ContainerExecCreate(ctx, task.Status.ContainerStatus.ContainerID, options)
220 220
 	assert.NilError(t, err, "error creating exec")
221 221
 
222 222
 	attach, err := apiClient.ContainerExecAttach(ctx, resp.ID, types.ExecStartCheck{})
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"time"
10 10
 
11 11
 	"github.com/docker/docker/api/types"
12
+	"github.com/docker/docker/api/types/container"
12 13
 	"github.com/docker/docker/api/types/filters"
13 14
 	swarmtypes "github.com/docker/docker/api/types/swarm"
14 15
 	"github.com/docker/docker/client"
... ...
@@ -313,7 +314,7 @@ func TestTemplatedSecret(t *testing.T) {
313 313
 	tasks := swarm.GetRunningTasks(ctx, t, c, serviceID)
314 314
 	assert.Assert(t, len(tasks) > 0, "no running tasks found for service %s", serviceID)
315 315
 
316
-	attach := swarm.ExecTask(ctx, t, d, tasks[0], types.ExecConfig{
316
+	attach := swarm.ExecTask(ctx, t, d, tasks[0], container.ExecOptions{
317 317
 		Cmd:          []string{"/bin/cat", "/run/secrets/templated_secret"},
318 318
 		AttachStdout: true,
319 319
 		AttachStderr: true,
... ...
@@ -324,7 +325,7 @@ func TestTemplatedSecret(t *testing.T) {
324 324
 		"this is a config\n"
325 325
 	assertAttachedStream(t, attach, expect)
326 326
 
327
-	attach = swarm.ExecTask(ctx, t, d, tasks[0], types.ExecConfig{
327
+	attach = swarm.ExecTask(ctx, t, d, tasks[0], container.ExecOptions{
328 328
 		Cmd:          []string{"mount"},
329 329
 		AttachStdout: true,
330 330
 		AttachStderr: true,
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"time"
13 13
 
14 14
 	"github.com/docker/docker/api/types"
15
+	containertypes "github.com/docker/docker/api/types/container"
15 16
 	"github.com/docker/docker/api/types/events"
16 17
 	"github.com/docker/docker/api/types/filters"
17 18
 	"github.com/docker/docker/api/types/mount"
... ...
@@ -32,11 +33,9 @@ func TestEventsExecDie(t *testing.T) {
32 32
 
33 33
 	cID := container.Run(ctx, t, client)
34 34
 
35
-	id, err := client.ContainerExecCreate(ctx, cID,
36
-		types.ExecConfig{
37
-			Cmd: []string{"echo", "hello"},
38
-		},
39
-	)
35
+	id, err := client.ContainerExecCreate(ctx, cID, containertypes.ExecOptions{
36
+		Cmd: []string{"echo", "hello"},
37
+	})
40 38
 	assert.NilError(t, err)
41 39
 
42 40
 	msg, errs := client.Events(ctx, types.EventsOptions{