mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
daemon: reduce use of pointer-slices in backend
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
@@ -51,7 +51,7 @@ type Backend interface {
|
|||||||
SetContainerSecretReferences(name string, refs []*swarm.SecretReference) error
|
SetContainerSecretReferences(name string, refs []*swarm.SecretReference) error
|
||||||
SetContainerConfigReferences(name string, refs []*swarm.ConfigReference) error
|
SetContainerConfigReferences(name string, refs []*swarm.ConfigReference) error
|
||||||
SystemInfo(context.Context) (*system.Info, error)
|
SystemInfo(context.Context) (*system.Info, error)
|
||||||
Containers(ctx context.Context, config *backend.ContainerListOptions) ([]*container.Summary, error)
|
Containers(ctx context.Context, config *backend.ContainerListOptions) ([]container.Summary, error)
|
||||||
SetNetworkBootstrapKeys([]*networktypes.EncryptionKey) error
|
SetNetworkBootstrapKeys([]*networktypes.EncryptionKey) error
|
||||||
DaemonJoinsCluster(provider cluster.Provider)
|
DaemonJoinsCluster(provider cluster.Provider)
|
||||||
DaemonLeavesCluster()
|
DaemonLeavesCluster()
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ var acceptedImageFilterTags = map[string]bool{
|
|||||||
|
|
||||||
// byCreated is a temporary type used to sort a list of images by creation
|
// byCreated is a temporary type used to sort a list of images by creation
|
||||||
// time.
|
// time.
|
||||||
type byCreated []*imagetypes.Summary
|
type byCreated []imagetypes.Summary
|
||||||
|
|
||||||
func (r byCreated) Len() int { return len(r) }
|
func (r byCreated) Len() int { return len(r) }
|
||||||
func (r byCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
func (r byCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||||
@@ -62,7 +62,7 @@ func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
|
|||||||
//
|
//
|
||||||
// TODO(thaJeztah): verify behavior of `RepoDigests` and `RepoTags` for images without (untagged) or multiple tags; see https://github.com/moby/moby/issues/43861
|
// TODO(thaJeztah): verify behavior of `RepoDigests` and `RepoTags` for images without (untagged) or multiple tags; see https://github.com/moby/moby/issues/43861
|
||||||
// TODO(thaJeztah): verify "Size" vs "VirtualSize" in images; see https://github.com/moby/moby/issues/43862
|
// TODO(thaJeztah): verify "Size" vs "VirtualSize" in images; see https://github.com/moby/moby/issues/43862
|
||||||
func (i *ImageService) Images(ctx context.Context, opts imagebackend.ListOptions) ([]*imagetypes.Summary, error) {
|
func (i *ImageService) Images(ctx context.Context, opts imagebackend.ListOptions) ([]imagetypes.Summary, error) {
|
||||||
if err := opts.Filters.Validate(acceptedImageFilterTags); err != nil {
|
if err := opts.Filters.Validate(acceptedImageFilterTags); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -150,7 +150,7 @@ func (i *ImageService) Images(ctx context.Context, opts imagebackend.ListOptions
|
|||||||
eg.SetLimit(runtime.NumCPU() * 2)
|
eg.SetLimit(runtime.NumCPU() * 2)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
summaries = make([]*imagetypes.Summary, 0, len(imgs))
|
summaries = make([]imagetypes.Summary, 0, len(imgs))
|
||||||
root []*[]digest.Digest
|
root []*[]digest.Digest
|
||||||
layers map[digest.Digest]int
|
layers map[digest.Digest]int
|
||||||
)
|
)
|
||||||
@@ -174,7 +174,7 @@ func (i *ImageService) Images(ctx context.Context, opts imagebackend.ListOptions
|
|||||||
image.Manifests = nil
|
image.Manifests = nil
|
||||||
}
|
}
|
||||||
resultsMut.Lock()
|
resultsMut.Lock()
|
||||||
summaries = append(summaries, image)
|
summaries = append(summaries, *image)
|
||||||
|
|
||||||
if opts.SharedSize {
|
if opts.SharedSize {
|
||||||
root = append(root, &multiSummary.AllChainIDs)
|
root = append(root, &multiSummary.AllChainIDs)
|
||||||
@@ -452,11 +452,12 @@ func (i *ImageService) singlePlatformImage(ctx context.Context, contentStore con
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshotUsage, err := imageManifest.SnapshotUsage(ctx, i.snapshotterService(i.snapshotter))
|
var unpackedSize int64
|
||||||
if err != nil {
|
if snapshotUsage, err := imageManifest.SnapshotUsage(ctx, i.snapshotterService(i.snapshotter)); err != nil {
|
||||||
log.G(ctx).WithFields(log.Fields{"image": imageManifest.Name(), "error": err}).Warn("failed to calculate unpacked size of image")
|
log.G(ctx).WithFields(log.Fields{"image": imageManifest.Name(), "error": err}).Warn("failed to calculate unpacked size of image")
|
||||||
|
} else {
|
||||||
|
unpackedSize = snapshotUsage.Size
|
||||||
}
|
}
|
||||||
unpackedSize := snapshotUsage.Size
|
|
||||||
|
|
||||||
contentSize, err := imageManifest.PresentContentSize(ctx)
|
contentSize, err := imageManifest.PresentContentSize(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -242,12 +242,12 @@ func TestImageList(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
images []c8dimages.Image
|
images []c8dimages.Image
|
||||||
|
|
||||||
check func(*testing.T, []*imagetypes.Summary)
|
check func(*testing.T, []imagetypes.Summary)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "one multi-layer image",
|
name: "one multi-layer image",
|
||||||
images: []c8dimages.Image{multilayer},
|
images: []c8dimages.Image{multilayer},
|
||||||
check: func(t *testing.T, all []*imagetypes.Summary) {
|
check: func(t *testing.T, all []imagetypes.Summary) {
|
||||||
assert.Check(t, is.Len(all, 1))
|
assert.Check(t, is.Len(all, 1))
|
||||||
|
|
||||||
if assert.Check(t, all[0].Descriptor != nil) {
|
if assert.Check(t, all[0].Descriptor != nil) {
|
||||||
@@ -264,7 +264,7 @@ func TestImageList(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "one image with two platforms is still one entry",
|
name: "one image with two platforms is still one entry",
|
||||||
images: []c8dimages.Image{twoplatform},
|
images: []c8dimages.Image{twoplatform},
|
||||||
check: func(t *testing.T, all []*imagetypes.Summary) {
|
check: func(t *testing.T, all []imagetypes.Summary) {
|
||||||
assert.Check(t, is.Len(all, 1))
|
assert.Check(t, is.Len(all, 1))
|
||||||
|
|
||||||
if assert.Check(t, all[0].Descriptor != nil) {
|
if assert.Check(t, all[0].Descriptor != nil) {
|
||||||
@@ -290,7 +290,7 @@ func TestImageList(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "two images are two entries",
|
name: "two images are two entries",
|
||||||
images: []c8dimages.Image{multilayer, twoplatform},
|
images: []c8dimages.Image{multilayer, twoplatform},
|
||||||
check: func(t *testing.T, all []*imagetypes.Summary) {
|
check: func(t *testing.T, all []imagetypes.Summary) {
|
||||||
assert.Check(t, is.Len(all, 2))
|
assert.Check(t, is.Len(all, 2))
|
||||||
|
|
||||||
if assert.Check(t, all[0].Descriptor != nil) {
|
if assert.Check(t, all[0].Descriptor != nil) {
|
||||||
@@ -319,14 +319,14 @@ func TestImageList(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "three images, one is an empty index",
|
name: "three images, one is an empty index",
|
||||||
images: []c8dimages.Image{multilayer, emptyIndex, twoplatform},
|
images: []c8dimages.Image{multilayer, emptyIndex, twoplatform},
|
||||||
check: func(t *testing.T, all []*imagetypes.Summary) {
|
check: func(t *testing.T, all []imagetypes.Summary) {
|
||||||
assert.Check(t, is.Len(all, 3))
|
assert.Check(t, is.Len(all, 3))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "one good image, second has config as a target",
|
name: "one good image, second has config as a target",
|
||||||
images: []c8dimages.Image{multilayer, configTarget},
|
images: []c8dimages.Image{multilayer, configTarget},
|
||||||
check: func(t *testing.T, all []*imagetypes.Summary) {
|
check: func(t *testing.T, all []imagetypes.Summary) {
|
||||||
assert.Check(t, is.Len(all, 2))
|
assert.Check(t, is.Len(all, 2))
|
||||||
|
|
||||||
sort.Slice(all, func(i, j int) bool {
|
sort.Slice(all, func(i, j int) bool {
|
||||||
@@ -349,7 +349,7 @@ func TestImageList(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "a non-container image manifest",
|
name: "a non-container image manifest",
|
||||||
images: []c8dimages.Image{textplain},
|
images: []c8dimages.Image{textplain},
|
||||||
check: func(t *testing.T, all []*imagetypes.Summary) {
|
check: func(t *testing.T, all []imagetypes.Summary) {
|
||||||
assert.Check(t, is.Len(all, 1))
|
assert.Check(t, is.Len(all, 1))
|
||||||
|
|
||||||
if assert.Check(t, all[0].Descriptor != nil) {
|
if assert.Check(t, all[0].Descriptor != nil) {
|
||||||
@@ -363,7 +363,7 @@ func TestImageList(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "multi-platform with no platforms available locally",
|
name: "multi-platform with no platforms available locally",
|
||||||
images: []c8dimages.Image{missingMultiPlatform},
|
images: []c8dimages.Image{missingMultiPlatform},
|
||||||
check: func(t *testing.T, all []*imagetypes.Summary) {
|
check: func(t *testing.T, all []imagetypes.Summary) {
|
||||||
assert.Assert(t, is.Len(all, 1))
|
assert.Assert(t, is.Len(all, 1))
|
||||||
assert.Check(t, is.Len(all[0].Manifests, 2))
|
assert.Check(t, is.Len(all[0].Manifests, 2))
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/moby/moby/v2/daemon/internal/filters"
|
"github.com/moby/moby/v2/daemon/internal/filters"
|
||||||
"github.com/moby/moby/v2/daemon/server/backend"
|
"github.com/moby/moby/v2/daemon/server/backend"
|
||||||
"github.com/moby/moby/v2/daemon/server/imagebackend"
|
"github.com/moby/moby/v2/daemon/server/imagebackend"
|
||||||
"github.com/moby/moby/v2/internal/sliceutil"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
@@ -26,30 +25,27 @@ func (daemon *Daemon) containerDiskUsage(ctx context.Context, verbose bool) (*ba
|
|||||||
return nil, fmt.Errorf("failed to retrieve container list: %v", err)
|
return nil, fmt.Errorf("failed to retrieve container list: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
isActive := func(ctr *container.Summary) bool {
|
|
||||||
return ctr.State == container.StateRunning ||
|
|
||||||
ctr.State == container.StatePaused ||
|
|
||||||
ctr.State == container.StateRestarting
|
|
||||||
}
|
|
||||||
|
|
||||||
du := &backend.ContainerDiskUsage{
|
du := &backend.ContainerDiskUsage{
|
||||||
ActiveCount: int64(len(containers)),
|
ActiveCount: int64(len(containers)),
|
||||||
TotalCount: int64(len(containers)),
|
TotalCount: int64(len(containers)),
|
||||||
}
|
}
|
||||||
for _, ctr := range containers {
|
for i := range containers {
|
||||||
du.TotalSize += ctr.SizeRw
|
du.TotalSize += containers[i].SizeRw
|
||||||
if !isActive(ctr) {
|
switch containers[i].State {
|
||||||
du.Reclaimable += ctr.SizeRw
|
case container.StateRunning, container.StatePaused, container.StateRestarting:
|
||||||
|
// active
|
||||||
|
default:
|
||||||
|
du.Reclaimable += containers[i].SizeRw
|
||||||
du.ActiveCount--
|
du.ActiveCount--
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove image manifest descriptor from the result as it should not be included.
|
// Remove image manifest descriptor from the result as it should not be included.
|
||||||
// https://github.com/moby/moby/pull/49407#discussion_r1954396666
|
// https://github.com/moby/moby/pull/49407#discussion_r1954396666
|
||||||
ctr.ImageManifestDescriptor = nil
|
containers[i].ImageManifestDescriptor = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
du.Items = sliceutil.Deref(containers)
|
du.Items = containers
|
||||||
}
|
}
|
||||||
|
|
||||||
return du, nil
|
return du, nil
|
||||||
@@ -94,7 +90,7 @@ func (daemon *Daemon) imageDiskUsage(ctx context.Context, verbose bool) (*backen
|
|||||||
}
|
}
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
du.Items = sliceutil.Deref(images)
|
du.Items = images
|
||||||
}
|
}
|
||||||
|
|
||||||
return du, nil
|
return du, nil
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ type ImageService interface {
|
|||||||
ImageDelete(ctx context.Context, imageRef string, options imagebackend.RemoveOptions) ([]imagetype.DeleteResponse, error)
|
ImageDelete(ctx context.Context, imageRef string, options imagebackend.RemoveOptions) ([]imagetype.DeleteResponse, error)
|
||||||
ExportImage(ctx context.Context, names []string, platformList []ocispec.Platform, outStream io.Writer) error
|
ExportImage(ctx context.Context, names []string, platformList []ocispec.Platform, outStream io.Writer) error
|
||||||
LoadImage(ctx context.Context, inTar io.ReadCloser, platformList []ocispec.Platform, outStream io.Writer, quiet bool) error
|
LoadImage(ctx context.Context, inTar io.ReadCloser, platformList []ocispec.Platform, outStream io.Writer, quiet bool) error
|
||||||
Images(ctx context.Context, opts imagebackend.ListOptions) ([]*imagetype.Summary, error)
|
Images(ctx context.Context, opts imagebackend.ListOptions) ([]imagetype.Summary, error)
|
||||||
LogImageEvent(ctx context.Context, imageID, refName string, action events.Action)
|
LogImageEvent(ctx context.Context, imageID, refName string, action events.Action)
|
||||||
CountImages(ctx context.Context) int
|
CountImages(ctx context.Context) int
|
||||||
ImagePrune(ctx context.Context, pruneFilters filters.Args) (*imagetype.PruneReport, error)
|
ImagePrune(ctx context.Context, pruneFilters filters.Args) (*imagetype.PruneReport, error)
|
||||||
|
|||||||
@@ -27,14 +27,14 @@ var acceptedImageFilterTags = map[string]bool{
|
|||||||
|
|
||||||
// byCreated is a temporary type used to sort a list of images by creation
|
// byCreated is a temporary type used to sort a list of images by creation
|
||||||
// time.
|
// time.
|
||||||
type byCreated []*imagetypes.Summary
|
type byCreated []imagetypes.Summary
|
||||||
|
|
||||||
func (r byCreated) Len() int { return len(r) }
|
func (r byCreated) Len() int { return len(r) }
|
||||||
func (r byCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
func (r byCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||||
func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
|
func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
|
||||||
|
|
||||||
// Images returns a filtered list of images.
|
// Images returns a filtered list of images.
|
||||||
func (i *ImageService) Images(ctx context.Context, opts imagebackend.ListOptions) ([]*imagetypes.Summary, error) {
|
func (i *ImageService) Images(ctx context.Context, opts imagebackend.ListOptions) ([]imagetypes.Summary, error) {
|
||||||
if err := opts.Filters.Validate(acceptedImageFilterTags); err != nil {
|
if err := opts.Filters.Validate(acceptedImageFilterTags); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -103,8 +103,8 @@ func (i *ImageService) Images(ctx context.Context, opts imagebackend.ListOptions
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
summaries = make([]*imagetypes.Summary, 0, len(selectedImages))
|
summaries = make([]imagetypes.Summary, 0, len(selectedImages))
|
||||||
summaryMap = make(map[*image.Image]*imagetypes.Summary, len(selectedImages))
|
summaryMap = make(map[*image.Image]imagetypes.Summary, len(selectedImages))
|
||||||
allContainers []*container.Container
|
allContainers []*container.Container
|
||||||
)
|
)
|
||||||
for id, img := range selectedImages {
|
for id, img := range selectedImages {
|
||||||
@@ -210,8 +210,8 @@ func (i *ImageService) Images(ctx context.Context, opts imagebackend.ListOptions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
summary.Containers = containersCount
|
summary.Containers = containersCount
|
||||||
summaryMap[img] = summary
|
summaryMap[img] = *summary
|
||||||
summaries = append(summaries, summary)
|
summaries = append(summaries, *summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.SharedSize {
|
if opts.SharedSize {
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ func (r byCreatedDescending) Less(i, j int) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Containers returns the list of containers to show given the user's filtering.
|
// Containers returns the list of containers to show given the user's filtering.
|
||||||
func (daemon *Daemon) Containers(ctx context.Context, config *backend.ContainerListOptions) ([]*containertypes.Summary, error) {
|
func (daemon *Daemon) Containers(ctx context.Context, config *backend.ContainerListOptions) ([]containertypes.Summary, error) {
|
||||||
if err := config.Filters.Validate(acceptedPsFilterTags); err != nil {
|
if err := config.Filters.Validate(acceptedPsFilterTags); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ func (daemon *Daemon) Containers(ctx context.Context, config *backend.ContainerL
|
|||||||
|
|
||||||
// shortcut if there are no containers
|
// shortcut if there are no containers
|
||||||
if numContainers == 0 {
|
if numContainers == 0 {
|
||||||
return []*containertypes.Summary{}, nil
|
return []containertypes.Summary{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the info for each container in the list; this can be slow so we
|
// Get the info for each container in the list; this can be slow so we
|
||||||
@@ -140,7 +140,7 @@ func (daemon *Daemon) Containers(ctx context.Context, config *backend.ContainerL
|
|||||||
}
|
}
|
||||||
|
|
||||||
resultsMut := sync.Mutex{}
|
resultsMut := sync.Mutex{}
|
||||||
results := make([]*containertypes.Summary, numContainers)
|
results := make([]containertypes.Summary, numContainers)
|
||||||
|
|
||||||
g, ctx := errgroup.WithContext(ctx)
|
g, ctx := errgroup.WithContext(ctx)
|
||||||
g.SetLimit(numWorkers)
|
g.SetLimit(numWorkers)
|
||||||
@@ -174,7 +174,7 @@ func (daemon *Daemon) Containers(ctx context.Context, config *backend.ContainerL
|
|||||||
// insert the result at the given index (so the output is in the
|
// insert the result at the given index (so the output is in the
|
||||||
// same order as containerList above).
|
// same order as containerList above).
|
||||||
resultsMut.Lock()
|
resultsMut.Lock()
|
||||||
results[idx] = newC
|
results[idx] = *newC
|
||||||
resultsMut.Unlock()
|
resultsMut.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ func setupContainerWithName(t *testing.T, name string, daemon *Daemon) *containe
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func containerListContainsName(containers []*containertypes.Summary, name string) bool {
|
func containerListContainsName(containers []containertypes.Summary, name string) bool {
|
||||||
for _, ctr := range containers {
|
for _, ctr := range containers {
|
||||||
for _, containerName := range ctr.Names {
|
for _, containerName := range ctr.Names {
|
||||||
if containerName == name {
|
if containerName == name {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ type monitorBackend interface {
|
|||||||
ContainerLogs(ctx context.Context, name string, config *backend.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
|
ContainerLogs(ctx context.Context, name string, config *backend.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
|
||||||
ContainerStats(ctx context.Context, name string, config *backend.ContainerStatsConfig) error
|
ContainerStats(ctx context.Context, name string, config *backend.ContainerStatsConfig) error
|
||||||
ContainerTop(name string, psArgs string) (*container.TopResponse, error)
|
ContainerTop(name string, psArgs string) (*container.TopResponse, error)
|
||||||
Containers(ctx context.Context, config *backend.ContainerListOptions) ([]*container.Summary, error)
|
Containers(ctx context.Context, config *backend.ContainerListOptions) ([]container.Summary, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// attachBackend includes function to implement to provide container attaching functionality.
|
// attachBackend includes function to implement to provide container attaching functionality.
|
||||||
|
|||||||
@@ -101,23 +101,23 @@ func (c *containerRouter) getContainersJSON(ctx context.Context, w http.Response
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
config := &backend.ContainerListOptions{
|
var limit int
|
||||||
|
if tmpLimit := r.Form.Get("limit"); tmpLimit != "" {
|
||||||
|
val, err := strconv.Atoi(tmpLimit)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
limit = val
|
||||||
|
}
|
||||||
|
|
||||||
|
containers, err := c.backend.Containers(ctx, &backend.ContainerListOptions{
|
||||||
All: httputils.BoolValue(r, "all"),
|
All: httputils.BoolValue(r, "all"),
|
||||||
Size: httputils.BoolValue(r, "size"),
|
Size: httputils.BoolValue(r, "size"),
|
||||||
Since: r.Form.Get("since"),
|
Since: r.Form.Get("since"),
|
||||||
Before: r.Form.Get("before"),
|
Before: r.Form.Get("before"),
|
||||||
|
Limit: limit,
|
||||||
Filters: filter,
|
Filters: filter,
|
||||||
}
|
})
|
||||||
|
|
||||||
if tmpLimit := r.Form.Get("limit"); tmpLimit != "" {
|
|
||||||
limit, err := strconv.Atoi(tmpLimit)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
config.Limit = limit
|
|
||||||
}
|
|
||||||
|
|
||||||
containers, err := c.backend.Containers(ctx, config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -125,22 +125,22 @@ func (c *containerRouter) getContainersJSON(ctx context.Context, w http.Response
|
|||||||
version := httputils.VersionFromContext(ctx)
|
version := httputils.VersionFromContext(ctx)
|
||||||
|
|
||||||
if versions.LessThan(version, "1.46") {
|
if versions.LessThan(version, "1.46") {
|
||||||
for _, c := range containers {
|
for i := range containers {
|
||||||
// Ignore HostConfig.Annotations because it was added in API v1.46.
|
// Ignore HostConfig.Annotations because it was added in API v1.46.
|
||||||
c.HostConfig.Annotations = nil
|
containers[i].HostConfig.Annotations = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if versions.LessThan(version, "1.48") {
|
if versions.LessThan(version, "1.48") {
|
||||||
// ImageManifestDescriptor information was added in API 1.48
|
// ImageManifestDescriptor information was added in API 1.48
|
||||||
for _, c := range containers {
|
for i := range containers {
|
||||||
c.ImageManifestDescriptor = nil
|
containers[i].ImageManifestDescriptor = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if versions.LessThan(version, "1.52") {
|
if versions.LessThan(version, "1.52") {
|
||||||
for _, c := range containers {
|
for i := range containers {
|
||||||
c.Health = nil
|
containers[i].Health = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ type Backend interface {
|
|||||||
type imageBackend interface {
|
type imageBackend interface {
|
||||||
ImageDelete(ctx context.Context, imageRef string, options imagebackend.RemoveOptions) ([]image.DeleteResponse, error)
|
ImageDelete(ctx context.Context, imageRef string, options imagebackend.RemoveOptions) ([]image.DeleteResponse, error)
|
||||||
ImageHistory(ctx context.Context, imageName string, platform *ocispec.Platform) ([]*image.HistoryResponseItem, error)
|
ImageHistory(ctx context.Context, imageName string, platform *ocispec.Platform) ([]*image.HistoryResponseItem, error)
|
||||||
Images(ctx context.Context, opts imagebackend.ListOptions) ([]*image.Summary, error)
|
Images(ctx context.Context, opts imagebackend.ListOptions) ([]image.Summary, error)
|
||||||
GetImage(ctx context.Context, refOrID string, options imagebackend.GetImageOpts) (*dockerimage.Image, error)
|
GetImage(ctx context.Context, refOrID string, options imagebackend.GetImageOpts) (*dockerimage.Image, error)
|
||||||
ImageInspect(ctx context.Context, refOrID string, options imagebackend.ImageInspectOpts) (*imagebackend.InspectData, error)
|
ImageInspect(ctx context.Context, refOrID string, options imagebackend.ImageInspectOpts) (*imagebackend.InspectData, error)
|
||||||
TagImage(ctx context.Context, id dockerimage.ID, newRef reference.Named) error
|
TagImage(ctx context.Context, id dockerimage.ID, newRef reference.Named) error
|
||||||
|
|||||||
@@ -508,25 +508,25 @@ func (ir *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
|||||||
useNone := versions.LessThan(version, "1.43")
|
useNone := versions.LessThan(version, "1.43")
|
||||||
noDescriptor := versions.LessThan(version, "1.48")
|
noDescriptor := versions.LessThan(version, "1.48")
|
||||||
noContainers := versions.LessThan(version, "1.51")
|
noContainers := versions.LessThan(version, "1.51")
|
||||||
for _, img := range images {
|
for i := range images {
|
||||||
if useNone {
|
if useNone {
|
||||||
if len(img.RepoTags) == 0 && len(img.RepoDigests) == 0 {
|
if len(images[i].RepoTags) == 0 && len(images[i].RepoDigests) == 0 {
|
||||||
img.RepoTags = append(img.RepoTags, "<none>:<none>")
|
images[i].RepoTags = append(images[i].RepoTags, "<none>:<none>")
|
||||||
img.RepoDigests = append(img.RepoDigests, "<none>@<none>")
|
images[i].RepoDigests = append(images[i].RepoDigests, "<none>@<none>")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if img.RepoTags == nil {
|
if images[i].RepoTags == nil {
|
||||||
img.RepoTags = []string{}
|
images[i].RepoTags = []string{}
|
||||||
}
|
}
|
||||||
if img.RepoDigests == nil {
|
if images[i].RepoDigests == nil {
|
||||||
img.RepoDigests = []string{}
|
images[i].RepoDigests = []string{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if noDescriptor {
|
if noDescriptor {
|
||||||
img.Descriptor = nil
|
images[i].Descriptor = nil
|
||||||
}
|
}
|
||||||
if noContainers {
|
if noContainers {
|
||||||
img.Containers = -1
|
images[i].Containers = -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ func TestGetVolumeByNameNotFound(t *testing.T) {
|
|||||||
func TestGetVolumeByNameFoundRegular(t *testing.T) {
|
func TestGetVolumeByNameFoundRegular(t *testing.T) {
|
||||||
v := &volumeRouter{
|
v := &volumeRouter{
|
||||||
backend: &fakeVolumeBackend{
|
backend: &fakeVolumeBackend{
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"volume1": {
|
"volume1": {
|
||||||
Name: "volume1",
|
Name: "volume1",
|
||||||
},
|
},
|
||||||
@@ -99,7 +99,7 @@ func TestGetVolumeByNameFoundSwarm(t *testing.T) {
|
|||||||
cluster: &fakeClusterBackend{
|
cluster: &fakeClusterBackend{
|
||||||
swarm: true,
|
swarm: true,
|
||||||
manager: true,
|
manager: true,
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"volume1": {
|
"volume1": {
|
||||||
Name: "volume1",
|
Name: "volume1",
|
||||||
},
|
},
|
||||||
@@ -114,7 +114,7 @@ func TestGetVolumeByNameFoundSwarm(t *testing.T) {
|
|||||||
func TestListVolumes(t *testing.T) {
|
func TestListVolumes(t *testing.T) {
|
||||||
v := &volumeRouter{
|
v := &volumeRouter{
|
||||||
backend: &fakeVolumeBackend{
|
backend: &fakeVolumeBackend{
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"v1": {Name: "v1"},
|
"v1": {Name: "v1"},
|
||||||
"v2": {Name: "v2"},
|
"v2": {Name: "v2"},
|
||||||
},
|
},
|
||||||
@@ -122,7 +122,7 @@ func TestListVolumes(t *testing.T) {
|
|||||||
cluster: &fakeClusterBackend{
|
cluster: &fakeClusterBackend{
|
||||||
swarm: true,
|
swarm: true,
|
||||||
manager: true,
|
manager: true,
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"v3": {Name: "v3"},
|
"v3": {Name: "v3"},
|
||||||
"v4": {Name: "v4"},
|
"v4": {Name: "v4"},
|
||||||
},
|
},
|
||||||
@@ -142,7 +142,7 @@ func TestListVolumes(t *testing.T) {
|
|||||||
func TestListVolumesNoSwarm(t *testing.T) {
|
func TestListVolumesNoSwarm(t *testing.T) {
|
||||||
v := &volumeRouter{
|
v := &volumeRouter{
|
||||||
backend: &fakeVolumeBackend{
|
backend: &fakeVolumeBackend{
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"v1": {Name: "v1"},
|
"v1": {Name: "v1"},
|
||||||
"v2": {Name: "v2"},
|
"v2": {Name: "v2"},
|
||||||
},
|
},
|
||||||
@@ -157,7 +157,7 @@ func TestListVolumesNoSwarm(t *testing.T) {
|
|||||||
func TestListVolumesNoManager(t *testing.T) {
|
func TestListVolumesNoManager(t *testing.T) {
|
||||||
v := &volumeRouter{
|
v := &volumeRouter{
|
||||||
backend: &fakeVolumeBackend{
|
backend: &fakeVolumeBackend{
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"v1": {Name: "v1"},
|
"v1": {Name: "v1"},
|
||||||
"v2": {Name: "v2"},
|
"v2": {Name: "v2"},
|
||||||
},
|
},
|
||||||
@@ -319,7 +319,7 @@ func TestUpdateVolume(t *testing.T) {
|
|||||||
c := &fakeClusterBackend{
|
c := &fakeClusterBackend{
|
||||||
swarm: true,
|
swarm: true,
|
||||||
manager: true,
|
manager: true,
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"vol1": {
|
"vol1": {
|
||||||
Name: "vo1",
|
Name: "vo1",
|
||||||
ClusterVolume: &volume.ClusterVolume{
|
ClusterVolume: &volume.ClusterVolume{
|
||||||
@@ -387,7 +387,7 @@ func TestUpdateVolumeNotFound(t *testing.T) {
|
|||||||
c := &fakeClusterBackend{
|
c := &fakeClusterBackend{
|
||||||
swarm: true,
|
swarm: true,
|
||||||
manager: true,
|
manager: true,
|
||||||
volumes: map[string]*volume.Volume{},
|
volumes: map[string]volume.Volume{},
|
||||||
}
|
}
|
||||||
|
|
||||||
v := &volumeRouter{
|
v := &volumeRouter{
|
||||||
@@ -416,7 +416,7 @@ func TestUpdateVolumeNotFound(t *testing.T) {
|
|||||||
|
|
||||||
func TestVolumeRemove(t *testing.T) {
|
func TestVolumeRemove(t *testing.T) {
|
||||||
b := &fakeVolumeBackend{
|
b := &fakeVolumeBackend{
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"vol1": {
|
"vol1": {
|
||||||
Name: "vol1",
|
Name: "vol1",
|
||||||
},
|
},
|
||||||
@@ -443,7 +443,7 @@ func TestVolumeRemoveSwarm(t *testing.T) {
|
|||||||
c := &fakeClusterBackend{
|
c := &fakeClusterBackend{
|
||||||
swarm: true,
|
swarm: true,
|
||||||
manager: true,
|
manager: true,
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"vol1": {
|
"vol1": {
|
||||||
Name: "vol1",
|
Name: "vol1",
|
||||||
ClusterVolume: &volume.ClusterVolume{},
|
ClusterVolume: &volume.ClusterVolume{},
|
||||||
@@ -501,7 +501,7 @@ func TestVolumeRemoveNotFoundNoManager(t *testing.T) {
|
|||||||
|
|
||||||
func TestVolumeRemoveFoundNoSwarm(t *testing.T) {
|
func TestVolumeRemoveFoundNoSwarm(t *testing.T) {
|
||||||
b := &fakeVolumeBackend{
|
b := &fakeVolumeBackend{
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"vol1": {
|
"vol1": {
|
||||||
Name: "vol1",
|
Name: "vol1",
|
||||||
},
|
},
|
||||||
@@ -525,7 +525,7 @@ func TestVolumeRemoveFoundNoSwarm(t *testing.T) {
|
|||||||
|
|
||||||
func TestVolumeRemoveNoSwarmInUse(t *testing.T) {
|
func TestVolumeRemoveNoSwarmInUse(t *testing.T) {
|
||||||
b := &fakeVolumeBackend{
|
b := &fakeVolumeBackend{
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"inuse": {
|
"inuse": {
|
||||||
Name: "inuse",
|
Name: "inuse",
|
||||||
},
|
},
|
||||||
@@ -551,7 +551,7 @@ func TestVolumeRemoveSwarmForce(t *testing.T) {
|
|||||||
c := &fakeClusterBackend{
|
c := &fakeClusterBackend{
|
||||||
swarm: true,
|
swarm: true,
|
||||||
manager: true,
|
manager: true,
|
||||||
volumes: map[string]*volume.Volume{
|
volumes: map[string]volume.Volume{
|
||||||
"vol1": {
|
"vol1": {
|
||||||
Name: "vol1",
|
Name: "vol1",
|
||||||
ClusterVolume: &volume.ClusterVolume{},
|
ClusterVolume: &volume.ClusterVolume{},
|
||||||
@@ -586,20 +586,20 @@ func TestVolumeRemoveSwarmForce(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type fakeVolumeBackend struct {
|
type fakeVolumeBackend struct {
|
||||||
volumes map[string]*volume.Volume
|
volumes map[string]volume.Volume
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *fakeVolumeBackend) List(_ context.Context, _ filters.Args) ([]volume.Volume, []string, error) {
|
func (b *fakeVolumeBackend) List(_ context.Context, _ filters.Args) ([]volume.Volume, []string, error) {
|
||||||
var volumes []volume.Volume
|
var volumes []volume.Volume
|
||||||
for _, v := range b.volumes {
|
for _, v := range b.volumes {
|
||||||
volumes = append(volumes, *v)
|
volumes = append(volumes, v)
|
||||||
}
|
}
|
||||||
return volumes, nil, nil
|
return volumes, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *fakeVolumeBackend) Get(_ context.Context, name string, _ ...opts.GetOption) (*volume.Volume, error) {
|
func (b *fakeVolumeBackend) Get(_ context.Context, name string, _ ...opts.GetOption) (*volume.Volume, error) {
|
||||||
if v, ok := b.volumes[name]; ok {
|
if v, ok := b.volumes[name]; ok {
|
||||||
return v, nil
|
return &v, nil
|
||||||
}
|
}
|
||||||
return nil, errdefs.NotFound(fmt.Errorf("volume %s not found", name))
|
return nil, errdefs.NotFound(fmt.Errorf("volume %s not found", name))
|
||||||
}
|
}
|
||||||
@@ -610,19 +610,19 @@ func (b *fakeVolumeBackend) Create(_ context.Context, name, driverName string, _
|
|||||||
return nil, errors.New("already exists")
|
return nil, errors.New("already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
v := &volume.Volume{
|
v := volume.Volume{
|
||||||
Name: name,
|
Name: name,
|
||||||
Driver: driverName,
|
Driver: driverName,
|
||||||
}
|
}
|
||||||
if b.volumes == nil {
|
if b.volumes == nil {
|
||||||
b.volumes = map[string]*volume.Volume{
|
b.volumes = map[string]volume.Volume{
|
||||||
name: v,
|
name: v,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
b.volumes[name] = v
|
b.volumes[name] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
return v, nil
|
return &v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *fakeVolumeBackend) Remove(_ context.Context, name string, o ...opts.RemoveOption) error {
|
func (b *fakeVolumeBackend) Remove(_ context.Context, name string, o ...opts.RemoveOption) error {
|
||||||
@@ -652,7 +652,7 @@ type fakeClusterBackend struct {
|
|||||||
swarm bool
|
swarm bool
|
||||||
manager bool
|
manager bool
|
||||||
idCount int
|
idCount int
|
||||||
volumes map[string]*volume.Volume
|
volumes map[string]volume.Volume
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeClusterBackend) checkSwarm() error {
|
func (c *fakeClusterBackend) checkSwarm() error {
|
||||||
@@ -675,7 +675,7 @@ func (c *fakeClusterBackend) GetVolume(nameOrID string) (volume.Volume, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := c.volumes[nameOrID]; ok {
|
if v, ok := c.volumes[nameOrID]; ok {
|
||||||
return *v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
return volume.Volume{}, errdefs.NotFound(fmt.Errorf("volume %s not found", nameOrID))
|
return volume.Volume{}, errdefs.NotFound(fmt.Errorf("volume %s not found", nameOrID))
|
||||||
}
|
}
|
||||||
@@ -687,7 +687,7 @@ func (c *fakeClusterBackend) GetVolumes(_ volumebackend.ListOptions) ([]volume.V
|
|||||||
|
|
||||||
var volumes []volume.Volume
|
var volumes []volume.Volume
|
||||||
for _, v := range c.volumes {
|
for _, v := range c.volumes {
|
||||||
volumes = append(volumes, *v)
|
volumes = append(volumes, v)
|
||||||
}
|
}
|
||||||
return volumes, nil
|
return volumes, nil
|
||||||
}
|
}
|
||||||
@@ -702,29 +702,28 @@ func (c *fakeClusterBackend) CreateVolume(volumeCreate volume.CreateRequest) (*v
|
|||||||
return nil, errors.New("already exists")
|
return nil, errors.New("already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
v := &volume.Volume{
|
v := volume.Volume{
|
||||||
Name: volumeCreate.Name,
|
Name: volumeCreate.Name,
|
||||||
Driver: volumeCreate.Driver,
|
Driver: volumeCreate.Driver,
|
||||||
Labels: volumeCreate.Labels,
|
Labels: volumeCreate.Labels,
|
||||||
Options: volumeCreate.DriverOpts,
|
Options: volumeCreate.DriverOpts,
|
||||||
Scope: "global",
|
Scope: "global",
|
||||||
}
|
ClusterVolume: &volume.ClusterVolume{
|
||||||
|
|
||||||
v.ClusterVolume = &volume.ClusterVolume{
|
|
||||||
ID: fmt.Sprintf("cluster_%d", c.idCount),
|
ID: fmt.Sprintf("cluster_%d", c.idCount),
|
||||||
Spec: *volumeCreate.ClusterVolumeSpec,
|
Spec: *volumeCreate.ClusterVolumeSpec,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
c.idCount = c.idCount + 1
|
c.idCount = c.idCount + 1
|
||||||
if c.volumes == nil {
|
if c.volumes == nil {
|
||||||
c.volumes = map[string]*volume.Volume{
|
c.volumes = map[string]volume.Volume{
|
||||||
v.Name: v,
|
v.Name: v,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.volumes[v.Name] = v
|
c.volumes[v.Name] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
return v, nil
|
return &v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeClusterBackend) RemoveVolume(nameOrID string, force bool) error {
|
func (c *fakeClusterBackend) RemoveVolume(nameOrID string, force bool) error {
|
||||||
|
|||||||
@@ -47,22 +47,27 @@ func TestContainerList(t *testing.T) {
|
|||||||
func TestContainerList_Annotations(t *testing.T) {
|
func TestContainerList_Annotations(t *testing.T) {
|
||||||
ctx := setupTest(t)
|
ctx := setupTest(t)
|
||||||
|
|
||||||
annotations := map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
"io.kubernetes.docker.type": "container",
|
|
||||||
}
|
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
apiVersion string
|
apiVersion string
|
||||||
expectedAnnotations map[string]string
|
expectedAnnotations map[string]string
|
||||||
}{
|
}{
|
||||||
{apiVersion: "1.44", expectedAnnotations: nil},
|
{
|
||||||
{apiVersion: "1.46", expectedAnnotations: annotations},
|
apiVersion: "1.44",
|
||||||
|
expectedAnnotations: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
apiVersion: "1.46",
|
||||||
|
expectedAnnotations: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"io.kubernetes.docker.type": "container",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testcases {
|
for _, tc := range testcases {
|
||||||
t.Run(fmt.Sprintf("run with version v%s", tc.apiVersion), func(t *testing.T) {
|
t.Run(fmt.Sprintf("run with version v%s", tc.apiVersion), func(t *testing.T) {
|
||||||
apiClient := request.NewAPIClient(t, client.WithAPIVersion(tc.apiVersion))
|
apiClient := request.NewAPIClient(t, client.WithAPIVersion(tc.apiVersion))
|
||||||
id := container.Create(ctx, t, apiClient, container.WithAnnotations(annotations))
|
id := container.Create(ctx, t, apiClient, container.WithAnnotations(tc.expectedAnnotations))
|
||||||
defer container.Remove(ctx, t, apiClient, id, client.ContainerRemoveOptions{Force: true})
|
defer container.Remove(ctx, t, apiClient, id, client.ContainerRemoveOptions{Force: true})
|
||||||
|
|
||||||
list, err := apiClient.ContainerList(ctx, client.ContainerListOptions{
|
list, err := apiClient.ContainerList(ctx, client.ContainerListOptions{
|
||||||
|
|||||||
Reference in New Issue
Block a user