Browse code

Merge pull request #51454 from thaJeztah/api_volumes_no_pointer

api/types/volume: change ListResponse.Volumes to a non-pointer slice

Paweł Gronowski authored on 2025/11/11 00:20:16
Showing 13 changed files
... ...
@@ -2149,6 +2149,7 @@ definitions:
2149 2149
   Volume:
2150 2150
     type: "object"
2151 2151
     required: [Name, Driver, Mountpoint, Labels, Scope, Options]
2152
+    x-nullable: false
2152 2153
     properties:
2153 2154
       Name:
2154 2155
         type: "string"
... ...
@@ -2149,6 +2149,7 @@ definitions:
2149 2149
   Volume:
2150 2150
     type: "object"
2151 2151
     required: [Name, Driver, Mountpoint, Labels, Scope, Options]
2152
+    x-nullable: false
2152 2153
     properties:
2153 2154
       Name:
2154 2155
         type: "string"
... ...
@@ -13,7 +13,7 @@ package volume
13 13
 type ListResponse struct {
14 14
 
15 15
 	// List of volumes
16
-	Volumes []*Volume `json:"Volumes"`
16
+	Volumes []Volume `json:"Volumes"`
17 17
 
18 18
 	// Warnings that occurred when fetching the list of volumes.
19 19
 	//
... ...
@@ -4,7 +4,6 @@ import (
4 4
 	"context"
5 5
 	"encoding/json"
6 6
 	"net/url"
7
-	"slices"
8 7
 
9 8
 	"github.com/moby/moby/api/types/volume"
10 9
 )
... ...
@@ -40,16 +39,8 @@ func (cli *Client) VolumeList(ctx context.Context, options VolumeListOptions) (V
40 40
 		return VolumeListResult{}, err
41 41
 	}
42 42
 
43
-	res := VolumeListResult{
44
-		Items:    make([]volume.Volume, 0, len(apiResp.Volumes)),
45
-		Warnings: slices.Clone(apiResp.Warnings),
46
-	}
47
-
48
-	for _, vol := range apiResp.Volumes {
49
-		if vol != nil {
50
-			res.Items = append(res.Items, *vol)
51
-		}
52
-	}
53
-
54
-	return res, nil
43
+	return VolumeListResult{
44
+		Items:    apiResp.Volumes,
45
+		Warnings: apiResp.Warnings,
46
+	}, nil
55 47
 }
... ...
@@ -1,7 +1,6 @@
1 1
 package client
2 2
 
3 3
 import (
4
-	"context"
5 4
 	"fmt"
6 5
 	"net/http"
7 6
 	"testing"
... ...
@@ -16,7 +15,7 @@ func TestVolumeListError(t *testing.T) {
16 16
 	client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
17 17
 	assert.NilError(t, err)
18 18
 
19
-	_, err = client.VolumeList(context.Background(), VolumeListOptions{})
19
+	_, err = client.VolumeList(t.Context(), VolumeListOptions{})
20 20
 	assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
21 21
 }
22 22
 
... ...
@@ -52,7 +51,7 @@ func TestVolumeList(t *testing.T) {
52 52
 				return nil, fmt.Errorf("filters not set in URL query properly. Expected '%s', got %s", listCase.expectedFilters, actualFilters)
53 53
 			}
54 54
 			return mockJSONResponse(http.StatusOK, nil, volume.ListResponse{
55
-				Volumes: []*volume.Volume{
55
+				Volumes: []volume.Volume{
56 56
 					{
57 57
 						Name:   "volume",
58 58
 						Driver: "local",
... ...
@@ -62,7 +61,7 @@ func TestVolumeList(t *testing.T) {
62 62
 		}))
63 63
 		assert.NilError(t, err)
64 64
 
65
-		result, err := client.VolumeList(context.Background(), VolumeListOptions{Filters: listCase.filters})
65
+		result, err := client.VolumeList(t.Context(), VolumeListOptions{Filters: listCase.filters})
66 66
 		assert.NilError(t, err)
67 67
 		assert.Check(t, is.Len(result.Items, 1))
68 68
 	}
... ...
@@ -30,9 +30,9 @@ func (c *Cluster) GetVolume(nameOrID string) (volumetypes.Volume, error) {
30 30
 	return convert.VolumeFromGRPC(volume), nil
31 31
 }
32 32
 
33
-// GetVolumes returns all of the volumes matching the given options from a swarm cluster.
34
-func (c *Cluster) GetVolumes(options volumebackend.ListOptions) ([]*volumetypes.Volume, error) {
35
-	var volumes []*volumetypes.Volume
33
+// GetVolumes returns all volumes matching the given options from a swarm cluster.
34
+func (c *Cluster) GetVolumes(options volumebackend.ListOptions) ([]volumetypes.Volume, error) {
35
+	var volumes []volumetypes.Volume
36 36
 	if err := c.lockedManagerAction(context.TODO(), func(ctx context.Context, state nodeState) error {
37 37
 		r, err := state.controlClient.ListVolumes(
38 38
 			ctx, &swarmapi.ListVolumesRequest{},
... ...
@@ -42,10 +42,9 @@ func (c *Cluster) GetVolumes(options volumebackend.ListOptions) ([]*volumetypes.
42 42
 			return err
43 43
 		}
44 44
 
45
-		volumes = make([]*volumetypes.Volume, 0, len(r.Volumes))
45
+		volumes = make([]volumetypes.Volume, 0, len(r.Volumes))
46 46
 		for _, volume := range r.Volumes {
47
-			v := convert.VolumeFromGRPC(volume)
48
-			volumes = append(volumes, &v)
47
+			volumes = append(volumes, convert.VolumeFromGRPC(volume))
49 48
 		}
50 49
 
51 50
 		return nil
... ...
@@ -127,7 +127,7 @@ func (daemon *Daemon) localVolumesSize(ctx context.Context, verbose bool) (*back
127 127
 		}
128 128
 
129 129
 		if verbose {
130
-			du.Items = sliceutil.Deref(volumes)
130
+			du.Items = volumes
131 131
 		}
132 132
 
133 133
 		return du, nil
... ...
@@ -12,7 +12,7 @@ import (
12 12
 // Backend is the methods that need to be implemented to provide
13 13
 // volume specific functionality
14 14
 type Backend interface {
15
-	List(ctx context.Context, filter filters.Args) ([]*volume.Volume, []string, error)
15
+	List(ctx context.Context, filter filters.Args) ([]volume.Volume, []string, error)
16 16
 	Get(ctx context.Context, name string, opts ...opts.GetOption) (*volume.Volume, error)
17 17
 	Create(ctx context.Context, name, driverName string, opts ...opts.CreateOption) (*volume.Volume, error)
18 18
 	Remove(ctx context.Context, name string, opts ...opts.RemoveOption) error
... ...
@@ -25,7 +25,7 @@ type Backend interface {
25 25
 // backends here.
26 26
 type ClusterBackend interface {
27 27
 	GetVolume(nameOrID string) (volume.Volume, error)
28
-	GetVolumes(options volumebackend.ListOptions) ([]*volume.Volume, error)
28
+	GetVolumes(options volumebackend.ListOptions) ([]volume.Volume, error)
29 29
 	CreateVolume(volume volume.CreateRequest) (*volume.Volume, error)
30 30
 	RemoveVolume(nameOrID string, force bool) error
31 31
 	UpdateVolume(nameOrID string, version uint64, volume volumebackend.UpdateOptions) error
... ...
@@ -589,10 +589,10 @@ type fakeVolumeBackend struct {
589 589
 	volumes map[string]*volume.Volume
590 590
 }
591 591
 
592
-func (b *fakeVolumeBackend) List(_ context.Context, _ filters.Args) ([]*volume.Volume, []string, error) {
593
-	var volumes []*volume.Volume
592
+func (b *fakeVolumeBackend) List(_ context.Context, _ filters.Args) ([]volume.Volume, []string, error) {
593
+	var volumes []volume.Volume
594 594
 	for _, v := range b.volumes {
595
-		volumes = append(volumes, v)
595
+		volumes = append(volumes, *v)
596 596
 	}
597 597
 	return volumes, nil, nil
598 598
 }
... ...
@@ -680,14 +680,14 @@ func (c *fakeClusterBackend) GetVolume(nameOrID string) (volume.Volume, error) {
680 680
 	return volume.Volume{}, errdefs.NotFound(fmt.Errorf("volume %s not found", nameOrID))
681 681
 }
682 682
 
683
-func (c *fakeClusterBackend) GetVolumes(_ volumebackend.ListOptions) ([]*volume.Volume, error) {
683
+func (c *fakeClusterBackend) GetVolumes(_ volumebackend.ListOptions) ([]volume.Volume, error) {
684 684
 	if err := c.checkSwarm(); err != nil {
685 685
 		return nil, err
686 686
 	}
687 687
 
688
-	var volumes []*volume.Volume
688
+	var volumes []volume.Volume
689 689
 	for _, v := range c.volumes {
690
-		volumes = append(volumes, v)
690
+		volumes = append(volumes, *v)
691 691
 	}
692 692
 	return volumes, nil
693 693
 }
... ...
@@ -31,9 +31,9 @@ type pathCacher interface {
31 31
 	CachedPath() string
32 32
 }
33 33
 
34
-func (s *VolumesService) volumesToAPI(ctx context.Context, volumes []volume.Volume, opts ...convertOpt) []*volumetypes.Volume {
34
+func (s *VolumesService) volumesToAPI(ctx context.Context, volumes []volume.Volume, opts ...convertOpt) []volumetypes.Volume {
35 35
 	var (
36
-		out        = make([]*volumetypes.Volume, 0, len(volumes))
36
+		out        = make([]volumetypes.Volume, 0, len(volumes))
37 37
 		getSize    bool
38 38
 		cachedPath bool
39 39
 	)
... ...
@@ -75,7 +75,7 @@ func (s *VolumesService) volumesToAPI(ctx context.Context, volumes []volume.Volu
75 75
 			apiV.UsageData = &volumetypes.UsageData{Size: sz, RefCount: int64(s.vs.CountReferences(v))}
76 76
 		}
77 77
 
78
-		out = append(out, &apiV)
78
+		out = append(out, apiV)
79 79
 	}
80 80
 	return out
81 81
 }
... ...
@@ -195,7 +195,7 @@ var acceptedListFilters = map[string]bool{
195 195
 // Note that this intentionally skips volumes which have mount options. Typically
196 196
 // volumes with mount options are not really local even if they are using the
197 197
 // local driver.
198
-func (s *VolumesService) LocalVolumesSize(ctx context.Context) ([]*volumetypes.Volume, error) {
198
+func (s *VolumesService) LocalVolumesSize(ctx context.Context) ([]volumetypes.Volume, error) {
199 199
 	ls, _, err := s.vs.Find(ctx, And(ByDriver(volume.DefaultDriverName), CustomFilter(func(v volume.Volume) bool {
200 200
 		dv, ok := v.(volume.DetailedVolume)
201 201
 		return ok && len(dv.Options()) == 0
... ...
@@ -262,7 +262,7 @@ func (s *VolumesService) Prune(ctx context.Context, filter filters.Args) (*volum
262 262
 
263 263
 // List gets the list of volumes which match the past in filters
264 264
 // If filters is nil or empty all volumes are returned.
265
-func (s *VolumesService) List(ctx context.Context, filter filters.Args) (volumes []*volumetypes.Volume, warnings []string, _ error) {
265
+func (s *VolumesService) List(ctx context.Context, filter filters.Args) (volumes []volumetypes.Volume, warnings []string, _ error) {
266 266
 	by, err := filtersToBy(filter, acceptedListFilters)
267 267
 	if err != nil {
268 268
 		return nil, nil, err
... ...
@@ -13,7 +13,7 @@ package volume
13 13
 type ListResponse struct {
14 14
 
15 15
 	// List of volumes
16
-	Volumes []*Volume `json:"Volumes"`
16
+	Volumes []Volume `json:"Volumes"`
17 17
 
18 18
 	// Warnings that occurred when fetching the list of volumes.
19 19
 	//
... ...
@@ -4,7 +4,6 @@ import (
4 4
 	"context"
5 5
 	"encoding/json"
6 6
 	"net/url"
7
-	"slices"
8 7
 
9 8
 	"github.com/moby/moby/api/types/volume"
10 9
 )
... ...
@@ -40,16 +39,8 @@ func (cli *Client) VolumeList(ctx context.Context, options VolumeListOptions) (V
40 40
 		return VolumeListResult{}, err
41 41
 	}
42 42
 
43
-	res := VolumeListResult{
44
-		Items:    make([]volume.Volume, 0, len(apiResp.Volumes)),
45
-		Warnings: slices.Clone(apiResp.Warnings),
46
-	}
47
-
48
-	for _, vol := range apiResp.Volumes {
49
-		if vol != nil {
50
-			res.Items = append(res.Items, *vol)
51
-		}
52
-	}
53
-
54
-	return res, nil
43
+	return VolumeListResult{
44
+		Items:    apiResp.Volumes,
45
+		Warnings: apiResp.Warnings,
46
+	}, nil
55 47
 }