Browse code

api/types/system: change legacyDiskUsage to a non-pointer slice

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

Sebastiaan van Stijn authored on 2025/11/06 18:34:56
Showing 10 changed files
... ...
@@ -37,14 +37,14 @@ type LegacyDiskUsage struct {
37 37
 	LayersSize int64 `json:"LayersSize,omitempty"`
38 38
 
39 39
 	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.Items] instead.
40
-	Images []*image.Summary `json:"Images,omitempty"`
40
+	Images []image.Summary `json:"Images,omitzero"`
41 41
 
42 42
 	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ContainersDiskUsage.Items] instead.
43
-	Containers []*container.Summary `json:"Containers,omitempty"`
43
+	Containers []container.Summary `json:"Containers,omitzero"`
44 44
 
45 45
 	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [VolumesDiskUsage.Items] instead.
46
-	Volumes []*volume.Volume `json:"Volumes,omitempty"`
46
+	Volumes []volume.Volume `json:"Volumes,omitzero"`
47 47
 
48 48
 	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [BuildCacheDiskUsage.Items] instead.
49
-	BuildCache []*build.CacheRecord `json:"BuildCache,omitempty"`
49
+	BuildCache []build.CacheRecord `json:"BuildCache,omitzero"`
50 50
 }
... ...
@@ -171,13 +171,7 @@ func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (Dis
171 171
 		}
172 172
 
173 173
 		if options.Verbose {
174
-			r.Images.Items = slices.Collect(func(yield func(image.Summary) bool) {
175
-				for _, i := range du.Images {
176
-					if !yield(*i) {
177
-						return
178
-					}
179
-				}
180
-			})
174
+			r.Images.Items = du.Images
181 175
 		}
182 176
 	}
183 177
 
... ...
@@ -194,13 +188,7 @@ func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (Dis
194 194
 		}
195 195
 	} else if du.Containers != nil && options.Verbose {
196 196
 		// Fallback for legacy response.
197
-		r.Containers.Items = slices.Collect(func(yield func(container.Summary) bool) {
198
-			for _, c := range du.Containers {
199
-				if !yield(*c) {
200
-					return
201
-				}
202
-			}
203
-		})
197
+		r.Containers.Items = du.Containers
204 198
 	}
205 199
 
206 200
 	if du.BuildCacheUsage != nil {
... ...
@@ -216,13 +204,7 @@ func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (Dis
216 216
 		}
217 217
 	} else if du.BuildCache != nil && options.Verbose {
218 218
 		// Fallback for legacy response.
219
-		r.BuildCache.Items = slices.Collect(func(yield func(build.CacheRecord) bool) {
220
-			for _, b := range du.BuildCache {
221
-				if !yield(*b) {
222
-					return
223
-				}
224
-			}
225
-		})
219
+		r.BuildCache.Items = du.BuildCache
226 220
 	}
227 221
 
228 222
 	if du.VolumeUsage != nil {
... ...
@@ -238,13 +220,7 @@ func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (Dis
238 238
 		}
239 239
 	} else if du.Volumes != nil && options.Verbose {
240 240
 		// Fallback for legacy response.
241
-		r.Volumes.Items = slices.Collect(func(yield func(volume.Volume) bool) {
242
-			for _, v := range du.Volumes {
243
-				if !yield(*v) {
244
-					return
245
-				}
246
-			}
247
-		})
241
+		r.Volumes.Items = du.Volumes
248 242
 	}
249 243
 
250 244
 	return r, nil
... ...
@@ -140,7 +140,7 @@ func TestLegacyDiskUsage(t *testing.T) {
140 140
 		return mockJSONResponse(http.StatusOK, nil, system.DiskUsage{
141 141
 			LegacyDiskUsage: system.LegacyDiskUsage{
142 142
 				LayersSize: 4096,
143
-				Images:     []*image.Summary{},
143
+				Images:     []image.Summary{},
144 144
 			},
145 145
 		})(req)
146 146
 	}))
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"github.com/moby/moby/v2/daemon/internal/filters"
9 9
 	"github.com/moby/moby/v2/daemon/server/backend"
10 10
 	"github.com/moby/moby/v2/daemon/server/imagebackend"
11
+	"github.com/moby/moby/v2/internal/sliceutil"
11 12
 	"github.com/pkg/errors"
12 13
 	"golang.org/x/sync/errgroup"
13 14
 )
... ...
@@ -51,7 +52,7 @@ func (daemon *Daemon) containerDiskUsage(ctx context.Context, verbose bool) (*ba
51 51
 		du.ActiveCount = activeCount
52 52
 
53 53
 		if verbose {
54
-			du.Items = containers
54
+			du.Items = sliceutil.Deref(containers)
55 55
 		}
56 56
 
57 57
 		return du, nil
... ...
@@ -96,7 +97,7 @@ func (daemon *Daemon) imageDiskUsage(ctx context.Context, verbose bool) (*backen
96 96
 		du.ActiveCount = activeCount
97 97
 
98 98
 		if verbose {
99
-			du.Items = images
99
+			du.Items = sliceutil.Deref(images)
100 100
 		}
101 101
 
102 102
 		return du, nil
... ...
@@ -130,7 +131,7 @@ func (daemon *Daemon) localVolumesSize(ctx context.Context, verbose bool) (*back
130 130
 		du.ActiveCount = activeCount
131 131
 
132 132
 		if verbose {
133
-			du.Items = volumes
133
+			du.Items = sliceutil.Deref(volumes)
134 134
 		}
135 135
 
136 136
 		return du, nil
... ...
@@ -150,15 +150,15 @@ func (b *Builder) Cancel(ctx context.Context, id string) error {
150 150
 }
151 151
 
152 152
 // DiskUsage returns a report about space used by build cache
153
-func (b *Builder) DiskUsage(ctx context.Context) ([]*build.CacheRecord, error) {
153
+func (b *Builder) DiskUsage(ctx context.Context) ([]build.CacheRecord, error) {
154 154
 	duResp, err := b.controller.DiskUsage(ctx, &controlapi.DiskUsageRequest{})
155 155
 	if err != nil {
156 156
 		return nil, err
157 157
 	}
158 158
 
159
-	var items []*build.CacheRecord
159
+	var items []build.CacheRecord
160 160
 	for _, r := range duResp.Record {
161
-		items = append(items, &build.CacheRecord{
161
+		items = append(items, build.CacheRecord{
162 162
 			ID:          r.ID,
163 163
 			Parents:     r.Parents,
164 164
 			Type:        r.RecordType,
... ...
@@ -37,7 +37,7 @@ type BuildCacheDiskUsage struct {
37 37
 	TotalCount  int64
38 38
 	TotalSize   int64
39 39
 	Reclaimable int64
40
-	Items       []*build.CacheRecord
40
+	Items       []build.CacheRecord
41 41
 }
42 42
 
43 43
 // ContainerDiskUsage contains disk usage for containers.
... ...
@@ -46,7 +46,7 @@ type ContainerDiskUsage struct {
46 46
 	TotalCount  int64
47 47
 	TotalSize   int64
48 48
 	Reclaimable int64
49
-	Items       []*container.Summary
49
+	Items       []container.Summary
50 50
 }
51 51
 
52 52
 // ImageDiskUsage contains disk usage for images.
... ...
@@ -55,7 +55,7 @@ type ImageDiskUsage struct {
55 55
 	TotalCount  int64
56 56
 	TotalSize   int64
57 57
 	Reclaimable int64
58
-	Items       []*image.Summary
58
+	Items       []image.Summary
59 59
 }
60 60
 
61 61
 // VolumeDiskUsage contains disk usage for volumes.
... ...
@@ -64,5 +64,5 @@ type VolumeDiskUsage struct {
64 64
 	TotalCount  int64
65 65
 	TotalSize   int64
66 66
 	Reclaimable int64
67
-	Items       []*volume.Volume
67
+	Items       []volume.Volume
68 68
 }
... ...
@@ -32,7 +32,7 @@ type ClusterBackend interface {
32 32
 
33 33
 // BuildBackend provides build specific system information.
34 34
 type BuildBackend interface {
35
-	DiskUsage(context.Context) ([]*build.CacheRecord, error)
35
+	DiskUsage(context.Context) ([]build.CacheRecord, error)
36 36
 }
37 37
 
38 38
 // StatusProvider provides methods to get the swarm status of the current node.
... ...
@@ -5,7 +5,6 @@ import (
5 5
 	"encoding/json"
6 6
 	"fmt"
7 7
 	"net/http"
8
-	"slices"
9 8
 	"strconv"
10 9
 	"time"
11 10
 
... ...
@@ -197,7 +196,7 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
197 197
 		})
198 198
 	}
199 199
 
200
-	var buildCache []*buildtypes.CacheRecord
200
+	var buildCache []buildtypes.CacheRecord
201 201
 	if getBuildCache {
202 202
 		eg.Go(func() error {
203 203
 			var err error
... ...
@@ -205,11 +204,6 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
205 205
 			if err != nil {
206 206
 				return errors.Wrap(err, "error getting build cache usage")
207 207
 			}
208
-			if buildCache == nil {
209
-				// Ensure empty `BuildCache` field is represented as empty JSON array(`[]`)
210
-				// instead of `null` to be consistent with `Images`, `Containers` etc.
211
-				buildCache = []*buildtypes.CacheRecord{}
212
-			}
213 208
 			return nil
214 209
 		})
215 210
 	}
... ...
@@ -228,16 +222,10 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
228 228
 		}
229 229
 
230 230
 		if legacyFields {
231
-			v.LayersSize = systemDiskUsage.Images.TotalSize //nolint: staticcheck,SA1019: v.LayersSize is deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.TotalSize] instead.
232
-			v.Images = systemDiskUsage.Images.Items         //nolint: staticcheck,SA1019: v.Images is deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.Items] instead.
231
+			v.LayersSize = systemDiskUsage.Images.TotalSize      //nolint: staticcheck,SA1019: v.LayersSize is deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.TotalSize] instead.
232
+			v.Images = nonNilSlice(systemDiskUsage.Images.Items) //nolint: staticcheck,SA1019: v.Images is deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.Items] instead.
233 233
 		} else if verbose {
234
-			v.ImageUsage.Items = slices.Collect(func(yield func(image.Summary) bool) {
235
-				for _, i := range systemDiskUsage.Images.Items {
236
-					if !yield(*i) {
237
-						return
238
-					}
239
-				}
240
-			})
234
+			v.ImageUsage.Items = systemDiskUsage.Images.Items
241 235
 		}
242 236
 	}
243 237
 	if systemDiskUsage != nil && systemDiskUsage.Containers != nil {
... ...
@@ -249,15 +237,9 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
249 249
 		}
250 250
 
251 251
 		if legacyFields {
252
-			v.Containers = systemDiskUsage.Containers.Items //nolint: staticcheck,SA1019: v.Containers is deprecated: kept to maintain backwards compatibility with API < v1.52, use [ContainersDiskUsage.Items] instead.
252
+			v.Containers = nonNilSlice(systemDiskUsage.Containers.Items) //nolint: staticcheck,SA1019: v.Containers is deprecated: kept to maintain backwards compatibility with API < v1.52, use [ContainersDiskUsage.Items] instead.
253 253
 		} else if verbose {
254
-			v.ContainerUsage.Items = slices.Collect(func(yield func(container.Summary) bool) {
255
-				for _, c := range systemDiskUsage.Containers.Items {
256
-					if !yield(*c) {
257
-						return
258
-					}
259
-				}
260
-			})
254
+			v.ContainerUsage.Items = systemDiskUsage.Containers.Items
261 255
 		}
262 256
 	}
263 257
 	if systemDiskUsage != nil && systemDiskUsage.Volumes != nil {
... ...
@@ -269,15 +251,9 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
269 269
 		}
270 270
 
271 271
 		if legacyFields {
272
-			v.Volumes = systemDiskUsage.Volumes.Items //nolint: staticcheck,SA1019: v.Volumes is deprecated: kept to maintain backwards compatibility with API < v1.52, use [VolumesDiskUsage.Items] instead.
272
+			v.Volumes = nonNilSlice(systemDiskUsage.Volumes.Items) //nolint: staticcheck,SA1019: v.Volumes is deprecated: kept to maintain backwards compatibility with API < v1.52, use [VolumesDiskUsage.Items] instead.
273 273
 		} else if verbose {
274
-			v.VolumeUsage.Items = slices.Collect(func(yield func(volume.Volume) bool) {
275
-				for _, v := range systemDiskUsage.Volumes.Items {
276
-					if !yield(*v) {
277
-						return
278
-					}
279
-				}
280
-			})
274
+			v.VolumeUsage.Items = systemDiskUsage.Volumes.Items
281 275
 		}
282 276
 	}
283 277
 	if getBuildCache {
... ...
@@ -306,20 +282,23 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
306 306
 		v.BuildCacheUsage.Reclaimable = reclaimable
307 307
 
308 308
 		if legacyFields {
309
-			v.BuildCache = buildCache //nolint: staticcheck,SA1019: v.BuildCache is deprecated: kept to maintain backwards compatibility with API < v1.52, use [BuildCacheDiskUsage.Items] instead.
309
+			v.BuildCache = nonNilSlice(buildCache) //nolint: staticcheck,SA1019: v.BuildCache is deprecated: kept to maintain backwards compatibility with API < v1.52, use [BuildCacheDiskUsage.Items] instead.
310 310
 		} else if verbose {
311
-			v.BuildCacheUsage.Items = slices.Collect(func(yield func(buildtypes.CacheRecord) bool) {
312
-				for _, b := range buildCache {
313
-					if !yield(*b) {
314
-						return
315
-					}
316
-				}
317
-			})
311
+			v.BuildCacheUsage.Items = buildCache
318 312
 		}
319 313
 	}
320 314
 	return httputils.WriteJSON(w, http.StatusOK, v)
321 315
 }
322 316
 
317
+// nonNilSlice is used for the legacy fields, which are either omitted
318
+// entirely, or (if set), must return an empty slice in the response.
319
+func nonNilSlice[T any](s []T) []T {
320
+	if s == nil {
321
+		return []T{}
322
+	}
323
+	return s
324
+}
325
+
323 326
 type invalidRequestError struct {
324 327
 	Err error
325 328
 }
... ...
@@ -37,14 +37,14 @@ type LegacyDiskUsage struct {
37 37
 	LayersSize int64 `json:"LayersSize,omitempty"`
38 38
 
39 39
 	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.Items] instead.
40
-	Images []*image.Summary `json:"Images,omitempty"`
40
+	Images []image.Summary `json:"Images,omitzero"`
41 41
 
42 42
 	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ContainersDiskUsage.Items] instead.
43
-	Containers []*container.Summary `json:"Containers,omitempty"`
43
+	Containers []container.Summary `json:"Containers,omitzero"`
44 44
 
45 45
 	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [VolumesDiskUsage.Items] instead.
46
-	Volumes []*volume.Volume `json:"Volumes,omitempty"`
46
+	Volumes []volume.Volume `json:"Volumes,omitzero"`
47 47
 
48 48
 	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [BuildCacheDiskUsage.Items] instead.
49
-	BuildCache []*build.CacheRecord `json:"BuildCache,omitempty"`
49
+	BuildCache []build.CacheRecord `json:"BuildCache,omitzero"`
50 50
 }
... ...
@@ -171,13 +171,7 @@ func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (Dis
171 171
 		}
172 172
 
173 173
 		if options.Verbose {
174
-			r.Images.Items = slices.Collect(func(yield func(image.Summary) bool) {
175
-				for _, i := range du.Images {
176
-					if !yield(*i) {
177
-						return
178
-					}
179
-				}
180
-			})
174
+			r.Images.Items = du.Images
181 175
 		}
182 176
 	}
183 177
 
... ...
@@ -194,13 +188,7 @@ func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (Dis
194 194
 		}
195 195
 	} else if du.Containers != nil && options.Verbose {
196 196
 		// Fallback for legacy response.
197
-		r.Containers.Items = slices.Collect(func(yield func(container.Summary) bool) {
198
-			for _, c := range du.Containers {
199
-				if !yield(*c) {
200
-					return
201
-				}
202
-			}
203
-		})
197
+		r.Containers.Items = du.Containers
204 198
 	}
205 199
 
206 200
 	if du.BuildCacheUsage != nil {
... ...
@@ -216,13 +204,7 @@ func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (Dis
216 216
 		}
217 217
 	} else if du.BuildCache != nil && options.Verbose {
218 218
 		// Fallback for legacy response.
219
-		r.BuildCache.Items = slices.Collect(func(yield func(build.CacheRecord) bool) {
220
-			for _, b := range du.BuildCache {
221
-				if !yield(*b) {
222
-					return
223
-				}
224
-			}
225
-		})
219
+		r.BuildCache.Items = du.BuildCache
226 220
 	}
227 221
 
228 222
 	if du.VolumeUsage != nil {
... ...
@@ -238,13 +220,7 @@ func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (Dis
238 238
 		}
239 239
 	} else if du.Volumes != nil && options.Verbose {
240 240
 		// Fallback for legacy response.
241
-		r.Volumes.Items = slices.Collect(func(yield func(volume.Volume) bool) {
242
-			for _, v := range du.Volumes {
243
-				if !yield(*v) {
244
-					return
245
-				}
246
-			}
247
-		})
241
+		r.Volumes.Items = du.Volumes
248 242
 	}
249 243
 
250 244
 	return r, nil