Browse code

client/container_update: Wrap options and result

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>

Paweł Gronowski authored on 2025/10/29 20:13:02
Showing 7 changed files
... ...
@@ -73,7 +73,7 @@ type ContainerAPIClient interface {
73 73
 	ContainerStop(ctx context.Context, container string, options ContainerStopOptions) (ContainerStopResult, error)
74 74
 	ContainerTop(ctx context.Context, container string, options ContainerTopOptions) (ContainerTopResult, error)
75 75
 	ContainerUnpause(ctx context.Context, container string, options ContainerUnpauseOptions) (ContainerUnpauseResult, error)
76
-	ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.UpdateResponse, error)
76
+	ContainerUpdate(ctx context.Context, container string, updateConfig ContainerUpdateOptions) (ContainerUpdateResult, error)
77 77
 	ContainerWait(ctx context.Context, container string, options ContainerWaitOptions) ContainerWaitResult
78 78
 	CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, container.PathStat, error)
79 79
 	CopyToContainer(ctx context.Context, container, path string, content io.Reader, options CopyToContainerOptions) error
... ...
@@ -7,20 +7,40 @@ import (
7 7
 	"github.com/moby/moby/api/types/container"
8 8
 )
9 9
 
10
+// ContainerUpdateOptions holds options for [Client.ContainerUpdate].
11
+type ContainerUpdateOptions struct {
12
+	Resources     *container.Resources
13
+	RestartPolicy *container.RestartPolicy
14
+}
15
+
16
+// ContainerUpdateResult is the result from updating a container.
17
+type ContainerUpdateResult struct {
18
+	// Warnings encountered when updating the container.
19
+	Warnings []string
20
+}
21
+
10 22
 // ContainerUpdate updates the resources of a container.
11
-func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.UpdateResponse, error) {
23
+func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, options ContainerUpdateOptions) (ContainerUpdateResult, error) {
12 24
 	containerID, err := trimID("container", containerID)
13 25
 	if err != nil {
14
-		return container.UpdateResponse{}, err
26
+		return ContainerUpdateResult{}, err
27
+	}
28
+
29
+	updateConfig := container.UpdateConfig{}
30
+	if options.Resources != nil {
31
+		updateConfig.Resources = *options.Resources
32
+	}
33
+	if options.RestartPolicy != nil {
34
+		updateConfig.RestartPolicy = *options.RestartPolicy
15 35
 	}
16 36
 
17 37
 	resp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil)
18 38
 	defer ensureReaderClosed(resp)
19 39
 	if err != nil {
20
-		return container.UpdateResponse{}, err
40
+		return ContainerUpdateResult{}, err
21 41
 	}
22 42
 
23 43
 	var response container.UpdateResponse
24 44
 	err = json.NewDecoder(resp.Body).Decode(&response)
25
-	return response, err
45
+	return ContainerUpdateResult{Warnings: response.Warnings}, err
26 46
 }
... ...
@@ -14,14 +14,14 @@ import (
14 14
 func TestContainerUpdateError(t *testing.T) {
15 15
 	client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
16 16
 	assert.NilError(t, err)
17
-	_, err = client.ContainerUpdate(context.Background(), "nothing", container.UpdateConfig{})
17
+	_, err = client.ContainerUpdate(context.Background(), "nothing", ContainerUpdateOptions{})
18 18
 	assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
19 19
 
20
-	_, err = client.ContainerUpdate(context.Background(), "", container.UpdateConfig{})
20
+	_, err = client.ContainerUpdate(context.Background(), "", ContainerUpdateOptions{})
21 21
 	assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
22 22
 	assert.Check(t, is.ErrorContains(err, "value is empty"))
23 23
 
24
-	_, err = client.ContainerUpdate(context.Background(), "    ", container.UpdateConfig{})
24
+	_, err = client.ContainerUpdate(context.Background(), "    ", ContainerUpdateOptions{})
25 25
 	assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
26 26
 	assert.Check(t, is.ErrorContains(err, "value is empty"))
27 27
 }
... ...
@@ -37,11 +37,11 @@ func TestContainerUpdate(t *testing.T) {
37 37
 	}))
38 38
 	assert.NilError(t, err)
39 39
 
40
-	_, err = client.ContainerUpdate(context.Background(), "container_id", container.UpdateConfig{
41
-		Resources: container.Resources{
40
+	_, err = client.ContainerUpdate(context.Background(), "container_id", ContainerUpdateOptions{
41
+		Resources: &container.Resources{
42 42
 			CPUPeriod: 1,
43 43
 		},
44
-		RestartPolicy: container.RestartPolicy{
44
+		RestartPolicy: &container.RestartPolicy{
45 45
 			Name: "always",
46 46
 		},
47 47
 	})
... ...
@@ -37,8 +37,8 @@ func TestUpdateMemory(t *testing.T) {
37 37
 		setMemorySwap int64 = 524288000
38 38
 	)
39 39
 
40
-	_, err := apiClient.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
41
-		Resources: containertypes.Resources{
40
+	_, err := apiClient.ContainerUpdate(ctx, cID, client.ContainerUpdateOptions{
41
+		Resources: &containertypes.Resources{
42 42
 			Memory:     setMemory,
43 43
 			MemorySwap: setMemorySwap,
44 44
 		},
... ...
@@ -100,16 +100,16 @@ func TestUpdateCPUQuota(t *testing.T) {
100 100
 			// On v2, specifying CPUQuota without CPUPeriod is currently broken:
101 101
 			// https://github.com/opencontainers/runc/issues/2456
102 102
 			// As a workaround we set them together.
103
-			_, err := apiClient.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
104
-				Resources: containertypes.Resources{
103
+			_, err := apiClient.ContainerUpdate(ctx, cID, client.ContainerUpdateOptions{
104
+				Resources: &containertypes.Resources{
105 105
 					CPUQuota:  test.update,
106 106
 					CPUPeriod: 100000,
107 107
 				},
108 108
 			})
109 109
 			assert.NilError(t, err)
110 110
 		} else {
111
-			_, err := apiClient.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
112
-				Resources: containertypes.Resources{
111
+			_, err := apiClient.ContainerUpdate(ctx, cID, client.ContainerUpdateOptions{
112
+				Resources: &containertypes.Resources{
113 113
 					CPUQuota: test.update,
114 114
 				},
115 115
 			})
... ...
@@ -185,8 +185,8 @@ func TestUpdatePidsLimit(t *testing.T) {
185 185
 			// Using "network=host" to speed up creation (13.96s vs 6.54s)
186 186
 			cID := container.Run(ctx, t, apiClient, container.WithPidsLimit(test.initial), container.WithNetworkMode("host"))
187 187
 
188
-			_, err := c.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
189
-				Resources: containertypes.Resources{
188
+			_, err := c.ContainerUpdate(ctx, cID, client.ContainerUpdateOptions{
189
+				Resources: &containertypes.Resources{
190 190
 					PidsLimit: test.update,
191 191
 				},
192 192
 			})
... ...
@@ -24,8 +24,8 @@ func TestUpdateRestartPolicy(t *testing.T) {
24 24
 		}
25 25
 	})
26 26
 
27
-	_, err := apiClient.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
28
-		RestartPolicy: containertypes.RestartPolicy{
27
+	_, err := apiClient.ContainerUpdate(ctx, cID, client.ContainerUpdateOptions{
28
+		RestartPolicy: &containertypes.RestartPolicy{
29 29
 			Name:              "on-failure",
30 30
 			MaximumRetryCount: 5,
31 31
 		},
... ...
@@ -51,8 +51,8 @@ func TestUpdateRestartWithAutoRemove(t *testing.T) {
51 51
 
52 52
 	cID := container.Run(ctx, t, apiClient, container.WithAutoRemove)
53 53
 
54
-	_, err := apiClient.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{
55
-		RestartPolicy: containertypes.RestartPolicy{
54
+	_, err := apiClient.ContainerUpdate(ctx, cID, client.ContainerUpdateOptions{
55
+		RestartPolicy: &containertypes.RestartPolicy{
56 56
 			Name: "always",
57 57
 		},
58 58
 	})
... ...
@@ -73,7 +73,7 @@ type ContainerAPIClient interface {
73 73
 	ContainerStop(ctx context.Context, container string, options ContainerStopOptions) (ContainerStopResult, error)
74 74
 	ContainerTop(ctx context.Context, container string, options ContainerTopOptions) (ContainerTopResult, error)
75 75
 	ContainerUnpause(ctx context.Context, container string, options ContainerUnpauseOptions) (ContainerUnpauseResult, error)
76
-	ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.UpdateResponse, error)
76
+	ContainerUpdate(ctx context.Context, container string, updateConfig ContainerUpdateOptions) (ContainerUpdateResult, error)
77 77
 	ContainerWait(ctx context.Context, container string, options ContainerWaitOptions) ContainerWaitResult
78 78
 	CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, container.PathStat, error)
79 79
 	CopyToContainer(ctx context.Context, container, path string, content io.Reader, options CopyToContainerOptions) error
... ...
@@ -7,20 +7,40 @@ import (
7 7
 	"github.com/moby/moby/api/types/container"
8 8
 )
9 9
 
10
+// ContainerUpdateOptions holds options for [Client.ContainerUpdate].
11
+type ContainerUpdateOptions struct {
12
+	Resources     *container.Resources
13
+	RestartPolicy *container.RestartPolicy
14
+}
15
+
16
+// ContainerUpdateResult is the result from updating a container.
17
+type ContainerUpdateResult struct {
18
+	// Warnings encountered when updating the container.
19
+	Warnings []string
20
+}
21
+
10 22
 // ContainerUpdate updates the resources of a container.
11
-func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.UpdateResponse, error) {
23
+func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, options ContainerUpdateOptions) (ContainerUpdateResult, error) {
12 24
 	containerID, err := trimID("container", containerID)
13 25
 	if err != nil {
14
-		return container.UpdateResponse{}, err
26
+		return ContainerUpdateResult{}, err
27
+	}
28
+
29
+	updateConfig := container.UpdateConfig{}
30
+	if options.Resources != nil {
31
+		updateConfig.Resources = *options.Resources
32
+	}
33
+	if options.RestartPolicy != nil {
34
+		updateConfig.RestartPolicy = *options.RestartPolicy
15 35
 	}
16 36
 
17 37
 	resp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil)
18 38
 	defer ensureReaderClosed(resp)
19 39
 	if err != nil {
20
-		return container.UpdateResponse{}, err
40
+		return ContainerUpdateResult{}, err
21 41
 	}
22 42
 
23 43
 	var response container.UpdateResponse
24 44
 	err = json.NewDecoder(resp.Body).Decode(&response)
25
-	return response, err
45
+	return ContainerUpdateResult{Warnings: response.Warnings}, err
26 46
 }