mirror of
https://github.com/containers/podman.git
synced 2025-05-21 09:05:56 +08:00
Vendor c/common:8483ef6022b4
This commit vendor pre-release version of `c/common:8483ef6022b4`. It also adapts the code to the new `c/common/libimage` API, which fixes an image listing race that was listing false warnings. fixes: #23331 Signed-off-by: Jan Rodák <hony.com@seznam.cz>
This commit is contained in:
4
vendor/github.com/containers/common/libimage/disk_usage.go
generated
vendored
4
vendor/github.com/containers/common/libimage/disk_usage.go
generated
vendored
@ -31,12 +31,12 @@ type ImageDiskUsage struct {
|
||||
// storage. Note that a single image may yield multiple usage reports, one for
|
||||
// each repository tag.
|
||||
func (r *Runtime) DiskUsage(ctx context.Context) ([]ImageDiskUsage, int64, error) {
|
||||
images, err := r.ListImages(ctx, nil, nil)
|
||||
images, layers, err := r.getImagesAndLayers()
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
|
||||
layerTree, err := r.layerTree(ctx, images)
|
||||
layerTree, err := r.newLayerTreeFromData(images, layers)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
|
112
vendor/github.com/containers/common/libimage/filters.go
generated
vendored
112
vendor/github.com/containers/common/libimage/filters.go
generated
vendored
@ -19,13 +19,16 @@ import (
|
||||
|
||||
// filterFunc is a prototype for a positive image filter. Returning `true`
|
||||
// indicates that the image matches the criteria.
|
||||
type filterFunc func(*Image) (bool, error)
|
||||
type filterFunc func(*Image, *layerTree) (bool, error)
|
||||
|
||||
type compiledFilters map[string][]filterFunc
|
||||
|
||||
// Apply the specified filters. All filters of each key must apply.
|
||||
func (i *Image) applyFilters(ctx context.Context, filters map[string][]filterFunc) (bool, error) {
|
||||
// tree must be provided if compileImageFilters indicated it is necessary.
|
||||
func (i *Image) applyFilters(ctx context.Context, filters compiledFilters, tree *layerTree) (bool, error) {
|
||||
for key := range filters {
|
||||
for _, filter := range filters[key] {
|
||||
matches, err := filter(i)
|
||||
matches, err := filter(i, tree)
|
||||
if err != nil {
|
||||
// Some images may have been corrupted in the
|
||||
// meantime, so do an extra check and make the
|
||||
@ -47,18 +50,11 @@ func (i *Image) applyFilters(ctx context.Context, filters map[string][]filterFun
|
||||
|
||||
// filterImages returns a slice of images which are passing all specified
|
||||
// filters.
|
||||
func (r *Runtime) filterImages(ctx context.Context, images []*Image, options *ListImagesOptions) ([]*Image, error) {
|
||||
if len(options.Filters) == 0 || len(images) == 0 {
|
||||
return images, nil
|
||||
}
|
||||
|
||||
filters, err := r.compileImageFilters(ctx, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// tree must be provided if compileImageFilters indicated it is necessary.
|
||||
func (r *Runtime) filterImages(ctx context.Context, images []*Image, filters compiledFilters, tree *layerTree) ([]*Image, error) {
|
||||
result := []*Image{}
|
||||
for i := range images {
|
||||
match, err := images[i].applyFilters(ctx, filters)
|
||||
match, err := images[i].applyFilters(ctx, filters, tree)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -73,25 +69,19 @@ func (r *Runtime) filterImages(ctx context.Context, images []*Image, options *Li
|
||||
// required format is `key=value` with the following supported keys:
|
||||
//
|
||||
// after, since, before, containers, dangling, id, label, readonly, reference, intermediate
|
||||
func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOptions) (map[string][]filterFunc, error) {
|
||||
//
|
||||
// compileImageFilters returns: compiled filters, if LayerTree is needed, error
|
||||
func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOptions) (compiledFilters, bool, error) {
|
||||
logrus.Tracef("Parsing image filters %s", options.Filters)
|
||||
|
||||
var tree *layerTree
|
||||
getTree := func() (*layerTree, error) {
|
||||
if tree == nil {
|
||||
t, err := r.layerTree(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tree = t
|
||||
}
|
||||
return tree, nil
|
||||
if len(options.Filters) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
filterInvalidValue := `invalid image filter %q: must be in the format "filter=value or filter!=value"`
|
||||
|
||||
var wantedReferenceMatches, unwantedReferenceMatches []string
|
||||
filters := map[string][]filterFunc{}
|
||||
filters := compiledFilters{}
|
||||
needsLayerTree := false
|
||||
duplicate := map[string]string{}
|
||||
for _, f := range options.Filters {
|
||||
var key, value string
|
||||
@ -103,7 +93,7 @@ func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOp
|
||||
} else {
|
||||
split = strings.SplitN(f, "=", 2)
|
||||
if len(split) != 2 {
|
||||
return nil, fmt.Errorf(filterInvalidValue, f)
|
||||
return nil, false, fmt.Errorf(filterInvalidValue, f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +103,7 @@ func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOp
|
||||
case "after", "since":
|
||||
img, err := r.time(key, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
key = "since"
|
||||
filter = filterAfter(img.Created())
|
||||
@ -121,27 +111,23 @@ func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOp
|
||||
case "before":
|
||||
img, err := r.time(key, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
filter = filterBefore(img.Created())
|
||||
|
||||
case "containers":
|
||||
if err := r.containers(duplicate, key, value, options.IsExternalContainerFunc); err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
filter = filterContainers(value, options.IsExternalContainerFunc)
|
||||
|
||||
case "dangling":
|
||||
dangling, err := r.bool(duplicate, key, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
t, err := getTree()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filter = filterDangling(ctx, dangling, t)
|
||||
needsLayerTree = true
|
||||
filter = filterDangling(ctx, dangling)
|
||||
|
||||
case "id":
|
||||
filter = filterID(value)
|
||||
@ -149,35 +135,31 @@ func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOp
|
||||
case "digest":
|
||||
f, err := filterDigest(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
filter = f
|
||||
|
||||
case "intermediate":
|
||||
intermediate, err := r.bool(duplicate, key, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
t, err := getTree()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filter = filterIntermediate(ctx, intermediate, t)
|
||||
needsLayerTree = true
|
||||
filter = filterIntermediate(ctx, intermediate)
|
||||
|
||||
case "label":
|
||||
filter = filterLabel(ctx, value)
|
||||
case "readonly":
|
||||
readOnly, err := r.bool(duplicate, key, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
filter = filterReadOnly(readOnly)
|
||||
|
||||
case "manifest":
|
||||
manifest, err := r.bool(duplicate, key, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
filter = filterManifest(ctx, manifest)
|
||||
|
||||
@ -192,12 +174,12 @@ func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOp
|
||||
case "until":
|
||||
until, err := r.until(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
filter = filterBefore(until)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf(filterInvalidValue, key)
|
||||
return nil, false, fmt.Errorf(filterInvalidValue, key)
|
||||
}
|
||||
if negate {
|
||||
filter = negateFilter(filter)
|
||||
@ -210,12 +192,12 @@ func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOp
|
||||
filter := filterReferences(r, wantedReferenceMatches, unwantedReferenceMatches)
|
||||
filters["reference"] = append(filters["reference"], filter)
|
||||
|
||||
return filters, nil
|
||||
return filters, needsLayerTree, nil
|
||||
}
|
||||
|
||||
func negateFilter(f filterFunc) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
b, err := f(img)
|
||||
return func(img *Image, tree *layerTree) (bool, error) {
|
||||
b, err := f(img, tree)
|
||||
return !b, err
|
||||
}
|
||||
}
|
||||
@ -272,7 +254,7 @@ func (r *Runtime) bool(duplicate map[string]string, key, value string) (bool, er
|
||||
|
||||
// filterManifest filters whether or not the image is a manifest list
|
||||
func filterManifest(ctx context.Context, value bool) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
return func(img *Image, _ *layerTree) (bool, error) {
|
||||
isManifestList, err := img.IsManifestList(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -284,7 +266,7 @@ func filterManifest(ctx context.Context, value bool) filterFunc {
|
||||
// filterReferences creates a reference filter for matching the specified wantedReferenceMatches value (OR logic)
|
||||
// and for matching the unwantedReferenceMatches values (AND logic)
|
||||
func filterReferences(r *Runtime, wantedReferenceMatches, unwantedReferenceMatches []string) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
return func(img *Image, _ *layerTree) (bool, error) {
|
||||
// Empty reference filters, return true
|
||||
if len(wantedReferenceMatches) == 0 && len(unwantedReferenceMatches) == 0 {
|
||||
return true, nil
|
||||
@ -376,7 +358,7 @@ func imageMatchesReferenceFilter(r *Runtime, img *Image, value string) (bool, er
|
||||
|
||||
// filterLabel creates a label for matching the specified value.
|
||||
func filterLabel(ctx context.Context, value string) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
return func(img *Image, _ *layerTree) (bool, error) {
|
||||
labels, err := img.Labels(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -387,28 +369,28 @@ func filterLabel(ctx context.Context, value string) filterFunc {
|
||||
|
||||
// filterAfter creates an after filter for matching the specified value.
|
||||
func filterAfter(value time.Time) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
return func(img *Image, _ *layerTree) (bool, error) {
|
||||
return img.Created().After(value), nil
|
||||
}
|
||||
}
|
||||
|
||||
// filterBefore creates a before filter for matching the specified value.
|
||||
func filterBefore(value time.Time) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
return func(img *Image, _ *layerTree) (bool, error) {
|
||||
return img.Created().Before(value), nil
|
||||
}
|
||||
}
|
||||
|
||||
// filterReadOnly creates a readonly filter for matching the specified value.
|
||||
func filterReadOnly(value bool) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
return func(img *Image, _ *layerTree) (bool, error) {
|
||||
return img.IsReadOnly() == value, nil
|
||||
}
|
||||
}
|
||||
|
||||
// filterContainers creates a container filter for matching the specified value.
|
||||
func filterContainers(value string, fn IsExternalContainerFunc) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
return func(img *Image, _ *layerTree) (bool, error) {
|
||||
ctrs, err := img.Containers()
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -433,8 +415,8 @@ func filterContainers(value string, fn IsExternalContainerFunc) filterFunc {
|
||||
}
|
||||
|
||||
// filterDangling creates a dangling filter for matching the specified value.
|
||||
func filterDangling(ctx context.Context, value bool, tree *layerTree) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
func filterDangling(ctx context.Context, value bool) filterFunc {
|
||||
return func(img *Image, tree *layerTree) (bool, error) {
|
||||
isDangling, err := img.isDangling(ctx, tree)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -445,7 +427,7 @@ func filterDangling(ctx context.Context, value bool, tree *layerTree) filterFunc
|
||||
|
||||
// filterID creates an image-ID filter for matching the specified value.
|
||||
func filterID(value string) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
return func(img *Image, _ *layerTree) (bool, error) {
|
||||
return strings.HasPrefix(img.ID(), value), nil
|
||||
}
|
||||
}
|
||||
@ -455,7 +437,7 @@ func filterDigest(value string) (filterFunc, error) {
|
||||
if !strings.HasPrefix(value, "sha256:") {
|
||||
return nil, fmt.Errorf("invalid value %q for digest filter", value)
|
||||
}
|
||||
return func(img *Image) (bool, error) {
|
||||
return func(img *Image, _ *layerTree) (bool, error) {
|
||||
return img.containsDigestPrefix(value), nil
|
||||
}, nil
|
||||
}
|
||||
@ -463,8 +445,8 @@ func filterDigest(value string) (filterFunc, error) {
|
||||
// filterIntermediate creates an intermediate filter for images. An image is
|
||||
// considered to be an intermediate image if it is dangling (i.e., no tags) and
|
||||
// has no children (i.e., no other image depends on it).
|
||||
func filterIntermediate(ctx context.Context, value bool, tree *layerTree) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
func filterIntermediate(ctx context.Context, value bool) filterFunc {
|
||||
return func(img *Image, tree *layerTree) (bool, error) {
|
||||
isIntermediate, err := img.isIntermediate(ctx, tree)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
2
vendor/github.com/containers/common/libimage/history.go
generated
vendored
2
vendor/github.com/containers/common/libimage/history.go
generated
vendored
@ -25,7 +25,7 @@ func (i *Image) History(ctx context.Context) ([]ImageHistory, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
layerTree, err := i.runtime.layerTree(ctx, nil)
|
||||
layerTree, err := i.runtime.newFreshLayerTree()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
6
vendor/github.com/containers/common/libimage/image.go
generated
vendored
6
vendor/github.com/containers/common/libimage/image.go
generated
vendored
@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/containers/common/libimage/platform"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
@ -257,7 +257,7 @@ func (i *Image) TopLayer() string {
|
||||
|
||||
// Parent returns the parent image or nil if there is none
|
||||
func (i *Image) Parent(ctx context.Context) (*Image, error) {
|
||||
tree, err := i.runtime.layerTree(ctx, nil)
|
||||
tree, err := i.runtime.newFreshLayerTree()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -291,7 +291,7 @@ func (i *Image) Children(ctx context.Context) ([]*Image, error) {
|
||||
// created for this invocation only.
|
||||
func (i *Image) getChildren(ctx context.Context, all bool, tree *layerTree) ([]*Image, error) {
|
||||
if tree == nil {
|
||||
t, err := i.runtime.layerTree(ctx, nil)
|
||||
t, err := i.runtime.newFreshLayerTree()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
3
vendor/github.com/containers/common/libimage/image_tree.go
generated
vendored
3
vendor/github.com/containers/common/libimage/image_tree.go
generated
vendored
@ -3,7 +3,6 @@
|
||||
package libimage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@ -38,7 +37,7 @@ func (i *Image) Tree(traverseChildren bool) (string, error) {
|
||||
fmt.Fprintf(sb, "No Image Layers")
|
||||
}
|
||||
|
||||
layerTree, err := i.runtime.layerTree(context.Background(), nil)
|
||||
layerTree, err := i.runtime.newFreshLayerTree()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
19
vendor/github.com/containers/common/libimage/layer_tree.go
generated
vendored
19
vendor/github.com/containers/common/libimage/layer_tree.go
generated
vendored
@ -89,21 +89,18 @@ func (l *layerNode) repoTags() ([]string, error) {
|
||||
return orderedTags, nil
|
||||
}
|
||||
|
||||
// layerTree extracts a layerTree from the layers in the local storage and
|
||||
// relates them to the specified images.
|
||||
func (r *Runtime) layerTree(ctx context.Context, images []*Image) (*layerTree, error) {
|
||||
layers, err := r.store.Layers()
|
||||
// newFreshLayerTree extracts a layerTree from consistent layers and images in the local storage.
|
||||
func (r *Runtime) newFreshLayerTree() (*layerTree, error) {
|
||||
images, layers, err := r.getImagesAndLayers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.newLayerTreeFromData(images, layers)
|
||||
}
|
||||
|
||||
if images == nil {
|
||||
images, err = r.ListImages(ctx, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// newLayerTreeFromData extracts a layerTree from the given the layers and images.
|
||||
// The caller is responsible for (layers, images) being consistent.
|
||||
func (r *Runtime) newLayerTreeFromData(images []*Image, layers []storage.Layer) (*layerTree, error) {
|
||||
tree := layerTree{
|
||||
nodes: make(map[string]*layerNode),
|
||||
ociCache: make(map[string]*ociv1.Image),
|
||||
|
2
vendor/github.com/containers/common/libimage/manifest_list.go
generated
vendored
2
vendor/github.com/containers/common/libimage/manifest_list.go
generated
vendored
@ -139,7 +139,7 @@ func (m *ManifestList) LookupInstance(ctx context.Context, architecture, os, var
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allImages, err := m.image.runtime.ListImages(ctx, nil, nil)
|
||||
allImages, err := m.image.runtime.ListImages(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
2
vendor/github.com/containers/common/libimage/platform/platform.go
generated
vendored
2
vendor/github.com/containers/common/libimage/platform/platform.go
generated
vendored
@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/platforms"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
92
vendor/github.com/containers/common/libimage/runtime.go
generated
vendored
92
vendor/github.com/containers/common/libimage/runtime.go
generated
vendored
@ -161,6 +161,23 @@ func (r *Runtime) storageToImage(storageImage *storage.Image, ref types.ImageRef
|
||||
}
|
||||
}
|
||||
|
||||
// getImagesAndLayers obtains consistent slices of Image and storage.Layer
|
||||
func (r *Runtime) getImagesAndLayers() ([]*Image, []storage.Layer, error) {
|
||||
snapshot, err := r.store.MultiList(
|
||||
storage.MultiListOptions{
|
||||
Images: true,
|
||||
Layers: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
images := []*Image{}
|
||||
for i := range snapshot.Images {
|
||||
images = append(images, r.storageToImage(&snapshot.Images[i], nil))
|
||||
}
|
||||
return images, snapshot.Layers, nil
|
||||
}
|
||||
|
||||
// Exists returns true if the specified image exists in the local containers
|
||||
// storage. Note that it may return false if an image corrupted.
|
||||
func (r *Runtime) Exists(name string) (bool, error) {
|
||||
@ -479,7 +496,7 @@ func (r *Runtime) lookupImageInDigestsAndRepoTags(name string, possiblyUnqualifi
|
||||
return nil, "", fmt.Errorf("%s: %w (could not cast to tagged)", originalName, storage.ErrImageUnknown)
|
||||
}
|
||||
|
||||
allImages, err := r.ListImages(context.Background(), nil, nil)
|
||||
allImages, err := r.ListImages(context.Background(), nil)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@ -567,39 +584,46 @@ type ListImagesOptions struct {
|
||||
SetListData bool
|
||||
}
|
||||
|
||||
// ListImages lists images in the local container storage. If names are
|
||||
// specified, only images with the specified names are looked up and filtered.
|
||||
func (r *Runtime) ListImages(ctx context.Context, names []string, options *ListImagesOptions) ([]*Image, error) {
|
||||
// ListImagesByNames lists the images in the local container storage by specified names
|
||||
// The name lookups use the LookupImage semantics.
|
||||
func (r *Runtime) ListImagesByNames(names []string) ([]*Image, error) {
|
||||
images := []*Image{}
|
||||
for _, name := range names {
|
||||
image, _, err := r.LookupImage(name, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
images = append(images, image)
|
||||
}
|
||||
return images, nil
|
||||
}
|
||||
|
||||
// ListImages lists the images in the local container storage and filter the images by ListImagesOptions
|
||||
func (r *Runtime) ListImages(ctx context.Context, options *ListImagesOptions) ([]*Image, error) {
|
||||
if options == nil {
|
||||
options = &ListImagesOptions{}
|
||||
}
|
||||
|
||||
var images []*Image
|
||||
if len(names) > 0 {
|
||||
for _, name := range names {
|
||||
image, _, err := r.LookupImage(name, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
images = append(images, image)
|
||||
}
|
||||
} else {
|
||||
storageImages, err := r.store.Images()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range storageImages {
|
||||
images = append(images, r.storageToImage(&storageImages[i], nil))
|
||||
}
|
||||
}
|
||||
|
||||
filtered, err := r.filterImages(ctx, images, options)
|
||||
filters, needsLayerTree, err := r.compileImageFilters(ctx, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !options.SetListData {
|
||||
return filtered, nil
|
||||
if options.SetListData {
|
||||
needsLayerTree = true
|
||||
}
|
||||
|
||||
snapshot, err := r.store.MultiList(
|
||||
storage.MultiListOptions{
|
||||
Images: true,
|
||||
Layers: needsLayerTree,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
images := []*Image{}
|
||||
for i := range snapshot.Images {
|
||||
images = append(images, r.storageToImage(&snapshot.Images[i], nil))
|
||||
}
|
||||
|
||||
// If explicitly requested by the user, pre-compute and cache the
|
||||
@ -608,11 +632,23 @@ func (r *Runtime) ListImages(ctx context.Context, names []string, options *ListI
|
||||
// as the layer tree will computed once for all instead of once for
|
||||
// each individual image (see containers/podman/issues/17828).
|
||||
|
||||
tree, err := r.layerTree(ctx, images)
|
||||
var tree *layerTree
|
||||
if needsLayerTree {
|
||||
tree, err = r.newLayerTreeFromData(images, snapshot.Layers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
filtered, err := r.filterImages(ctx, images, filters, tree)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !options.SetListData {
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
for i := range filtered {
|
||||
isDangling, err := filtered[i].isDangling(ctx, tree)
|
||||
if err != nil {
|
||||
@ -753,7 +789,7 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem
|
||||
IsExternalContainerFunc: options.IsExternalContainerFunc,
|
||||
Filters: options.Filters,
|
||||
}
|
||||
filteredImages, err := r.ListImages(ctx, nil, options)
|
||||
filteredImages, err := r.ListImages(ctx, options)
|
||||
if err != nil {
|
||||
appendError(err)
|
||||
return nil, rmErrors
|
||||
|
2
vendor/github.com/containers/common/libnetwork/network/interface_cni.go
generated
vendored
2
vendor/github.com/containers/common/libnetwork/network/interface_cni.go
generated
vendored
@ -1,6 +1,4 @@
|
||||
//go:build (linux || freebsd) && cni
|
||||
// +build linux freebsd
|
||||
// +build cni
|
||||
|
||||
package network
|
||||
|
||||
|
2
vendor/github.com/containers/common/libnetwork/network/interface_cni_unsupported.go
generated
vendored
2
vendor/github.com/containers/common/libnetwork/network/interface_cni_unsupported.go
generated
vendored
@ -1,6 +1,4 @@
|
||||
//go:build (linux || freebsd) && !cni
|
||||
// +build linux freebsd
|
||||
// +build !cni
|
||||
|
||||
package network
|
||||
|
||||
|
2
vendor/github.com/containers/common/pkg/config/config_bsd.go
generated
vendored
2
vendor/github.com/containers/common/pkg/config/config_bsd.go
generated
vendored
@ -1,4 +1,4 @@
|
||||
//go:build (freebsd || netbsd || openbsd)
|
||||
//go:build freebsd || netbsd || openbsd
|
||||
|
||||
package config
|
||||
|
||||
|
2
vendor/github.com/containers/common/pkg/config/default_bsd.go
generated
vendored
2
vendor/github.com/containers/common/pkg/config/default_bsd.go
generated
vendored
@ -1,4 +1,4 @@
|
||||
//go:build (freebsd || netbsd || openbsd)
|
||||
//go:build freebsd || netbsd || openbsd
|
||||
|
||||
package config
|
||||
|
||||
|
7
vendor/github.com/containers/storage/Makefile
generated
vendored
7
vendor/github.com/containers/storage/Makefile
generated
vendored
@ -32,6 +32,11 @@ BUILDFLAGS := -tags "$(AUTOTAGS) $(TAGS)" $(FLAGS)
|
||||
GO ?= go
|
||||
TESTFLAGS := $(shell $(GO) test -race $(BUILDFLAGS) ./pkg/stringutils 2>&1 > /dev/null && echo -race)
|
||||
|
||||
# N/B: This value is managed by Renovate, manual changes are
|
||||
# possible, as long as they don't disturb the formatting
|
||||
# (i.e. DO NOT ADD A 'v' prefix!)
|
||||
GOLANGCI_LINT_VERSION := 1.60.2
|
||||
|
||||
default all: local-binary docs local-validate local-cross ## validate all checks, build and cross-build\nbinaries and docs
|
||||
|
||||
clean: ## remove all built files
|
||||
@ -74,7 +79,7 @@ local-validate validate: install.tools ## validate DCO on the host
|
||||
@./hack/git-validation.sh
|
||||
|
||||
install.tools:
|
||||
$(MAKE) -C tests/tools
|
||||
$(MAKE) -C tests/tools GOLANGCI_LINT_VERSION=$(GOLANGCI_LINT_VERSION)
|
||||
|
||||
install.docs: docs
|
||||
$(MAKE) -C docs install
|
||||
|
2
vendor/github.com/containers/storage/drivers/driver.go
generated
vendored
2
vendor/github.com/containers/storage/drivers/driver.go
generated
vendored
@ -496,7 +496,7 @@ func driverPut(driver ProtoDriver, id string, mainErr *error) {
|
||||
if *mainErr == nil {
|
||||
*mainErr = err
|
||||
} else {
|
||||
logrus.Errorf(err.Error())
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2
vendor/github.com/containers/storage/drivers/overlay/overlay.go
generated
vendored
2
vendor/github.com/containers/storage/drivers/overlay/overlay.go
generated
vendored
@ -1492,7 +1492,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||
if err := unix.Uname(&uts); err == nil {
|
||||
release = " " + string(uts.Release[:]) + " " + string(uts.Version[:])
|
||||
}
|
||||
logrus.StandardLogger().Logf(logLevel, "Ignoring global metacopy option, not supported with booted kernel"+release)
|
||||
logrus.StandardLogger().Logf(logLevel, "Ignoring global metacopy option, not supported with booted kernel %s", release)
|
||||
} else {
|
||||
logrus.Debugf("Ignoring global metacopy option, the mount program doesn't support it")
|
||||
}
|
||||
|
8
vendor/github.com/containers/storage/pkg/chrootarchive/archive.go
generated
vendored
8
vendor/github.com/containers/storage/pkg/chrootarchive/archive.go
generated
vendored
@ -83,6 +83,12 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions
|
||||
}
|
||||
}
|
||||
|
||||
destVal, err := newUnpackDestination(root, dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destVal.Close()
|
||||
|
||||
r := tarArchive
|
||||
if decompress {
|
||||
decompressedArchive, err := archive.DecompressStream(tarArchive)
|
||||
@ -93,7 +99,7 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions
|
||||
r = decompressedArchive
|
||||
}
|
||||
|
||||
return invokeUnpack(r, dest, options, root)
|
||||
return invokeUnpack(r, destVal, options)
|
||||
}
|
||||
|
||||
// Tar tars the requested path while chrooted to the specified root.
|
||||
|
22
vendor/github.com/containers/storage/pkg/chrootarchive/archive_darwin.go
generated
vendored
22
vendor/github.com/containers/storage/pkg/chrootarchive/archive_darwin.go
generated
vendored
@ -6,12 +6,26 @@ import (
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
)
|
||||
|
||||
type unpackDestination struct {
|
||||
dest string
|
||||
}
|
||||
|
||||
func (dst *unpackDestination) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// newUnpackDestination is a no-op on this platform
|
||||
func newUnpackDestination(root, dest string) (*unpackDestination, error) {
|
||||
return &unpackDestination{
|
||||
dest: dest,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func invokeUnpack(decompressedArchive io.Reader,
|
||||
dest string,
|
||||
options *archive.TarOptions, root string,
|
||||
dest *unpackDestination,
|
||||
options *archive.TarOptions,
|
||||
) error {
|
||||
_ = root // Restricting the operation to this root is not implemented on macOS
|
||||
return archive.Unpack(decompressedArchive, dest, options)
|
||||
return archive.Unpack(decompressedArchive, dest.dest, options)
|
||||
}
|
||||
|
||||
func invokePack(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) {
|
||||
|
89
vendor/github.com/containers/storage/pkg/chrootarchive/archive_unix.go
generated
vendored
89
vendor/github.com/containers/storage/pkg/chrootarchive/archive_unix.go
generated
vendored
@ -9,15 +9,41 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
"github.com/containers/storage/pkg/reexec"
|
||||
)
|
||||
|
||||
type unpackDestination struct {
|
||||
root *os.File
|
||||
dest string
|
||||
}
|
||||
|
||||
func (dst *unpackDestination) Close() error {
|
||||
return dst.root.Close()
|
||||
}
|
||||
|
||||
// tarOptionsDescriptor is passed as an extra file
|
||||
const tarOptionsDescriptor = 3
|
||||
|
||||
// rootFileDescriptor is passed as an extra file
|
||||
const rootFileDescriptor = 4
|
||||
|
||||
// procPathForFd gives us a string for a descriptor.
|
||||
// Note that while Linux supports actually *reading* this
|
||||
// path, FreeBSD and other platforms don't; but in this codebase
|
||||
// we only compare strings.
|
||||
func procPathForFd(fd int) string {
|
||||
return fmt.Sprintf("/proc/self/fd/%d", fd)
|
||||
}
|
||||
|
||||
// untar is the entry-point for storage-untar on re-exec. This is not used on
|
||||
// Windows as it does not support chroot, hence no point sandboxing through
|
||||
// chroot and rexec.
|
||||
@ -28,7 +54,7 @@ func untar() {
|
||||
var options archive.TarOptions
|
||||
|
||||
// read the options from the pipe "ExtraFiles"
|
||||
if err := json.NewDecoder(os.NewFile(3, "options")).Decode(&options); err != nil {
|
||||
if err := json.NewDecoder(os.NewFile(tarOptionsDescriptor, "options")).Decode(&options); err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
@ -38,7 +64,17 @@ func untar() {
|
||||
root = flag.Arg(1)
|
||||
}
|
||||
|
||||
if root == "" {
|
||||
// FreeBSD doesn't have proc/self, but we can handle it here
|
||||
if root == procPathForFd(rootFileDescriptor) {
|
||||
// Take ownership to ensure it's closed; no need to leak
|
||||
// this afterwards.
|
||||
rootFd := os.NewFile(rootFileDescriptor, "tar-root")
|
||||
defer rootFd.Close()
|
||||
if err := unix.Fchdir(int(rootFd.Fd())); err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
root = "."
|
||||
} else if root == "" {
|
||||
root = dst
|
||||
}
|
||||
|
||||
@ -57,11 +93,35 @@ func untar() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.TarOptions, root string) error {
|
||||
// newUnpackDestination takes a root directory and a destination which
|
||||
// must be underneath it, and returns an object that can unpack
|
||||
// in the target root using a file descriptor.
|
||||
func newUnpackDestination(root, dest string) (*unpackDestination, error) {
|
||||
if root == "" {
|
||||
return errors.New("must specify a root to chroot to")
|
||||
return nil, errors.New("must specify a root to chroot to")
|
||||
}
|
||||
relDest, err := filepath.Rel(root, dest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if relDest == "." {
|
||||
relDest = "/"
|
||||
}
|
||||
if relDest[0] != '/' {
|
||||
relDest = "/" + relDest
|
||||
}
|
||||
|
||||
rootfdRaw, err := unix.Open(root, unix.O_RDONLY|unix.O_DIRECTORY|unix.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, &fs.PathError{Op: "open", Path: root, Err: err}
|
||||
}
|
||||
return &unpackDestination{
|
||||
root: os.NewFile(uintptr(rootfdRaw), "rootfs"),
|
||||
dest: relDest,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func invokeUnpack(decompressedArchive io.Reader, dest *unpackDestination, options *archive.TarOptions) error {
|
||||
// We can't pass a potentially large exclude list directly via cmd line
|
||||
// because we easily overrun the kernel's max argument/environment size
|
||||
// when the full image list is passed (e.g. when this is used by
|
||||
@ -72,24 +132,13 @@ func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.T
|
||||
return fmt.Errorf("untar pipe failure: %w", err)
|
||||
}
|
||||
|
||||
if root != "" {
|
||||
relDest, err := filepath.Rel(root, dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if relDest == "." {
|
||||
relDest = "/"
|
||||
}
|
||||
if relDest[0] != '/' {
|
||||
relDest = "/" + relDest
|
||||
}
|
||||
dest = relDest
|
||||
}
|
||||
|
||||
cmd := reexec.Command("storage-untar", dest, root)
|
||||
cmd := reexec.Command("storage-untar", dest.dest, procPathForFd(rootFileDescriptor))
|
||||
cmd.Stdin = decompressedArchive
|
||||
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, r)
|
||||
// If you change this, change tarOptionsDescriptor above
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, r) // fd 3
|
||||
// If you change this, change rootFileDescriptor above too
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, dest.root) // fd 4
|
||||
output := bytes.NewBuffer(nil)
|
||||
cmd.Stdout = output
|
||||
cmd.Stderr = output
|
||||
|
21
vendor/github.com/containers/storage/pkg/chrootarchive/archive_windows.go
generated
vendored
21
vendor/github.com/containers/storage/pkg/chrootarchive/archive_windows.go
generated
vendored
@ -7,19 +7,34 @@ import (
|
||||
"github.com/containers/storage/pkg/longpath"
|
||||
)
|
||||
|
||||
type unpackDestination struct {
|
||||
dest string
|
||||
}
|
||||
|
||||
func (dst *unpackDestination) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// newUnpackDestination is a no-op on this platform
|
||||
func newUnpackDestination(root, dest string) (*unpackDestination, error) {
|
||||
return &unpackDestination{
|
||||
dest: dest,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// chroot is not supported by Windows
|
||||
func chroot(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func invokeUnpack(decompressedArchive io.Reader,
|
||||
dest string,
|
||||
options *archive.TarOptions, root string,
|
||||
dest *unpackDestination,
|
||||
options *archive.TarOptions,
|
||||
) error {
|
||||
// Windows is different to Linux here because Windows does not support
|
||||
// chroot. Hence there is no point sandboxing a chrooted process to
|
||||
// do the unpack. We call inline instead within the daemon process.
|
||||
return archive.Unpack(decompressedArchive, longpath.AddPrefix(dest), options)
|
||||
return archive.Unpack(decompressedArchive, longpath.AddPrefix(dest.dest), options)
|
||||
}
|
||||
|
||||
func invokePack(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) {
|
||||
|
28
vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go
generated
vendored
28
vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go
generated
vendored
@ -41,11 +41,10 @@ func getNextFreeLoopbackIndex() (int, error) {
|
||||
return index, err
|
||||
}
|
||||
|
||||
func openNextAvailableLoopback(sparseName string, sparseFile *os.File) (loopFile *os.File, err error) {
|
||||
func openNextAvailableLoopback(sparseName string, sparseFile *os.File) (*os.File, error) {
|
||||
// Read information about the loopback file.
|
||||
var st syscall.Stat_t
|
||||
err = syscall.Fstat(int(sparseFile.Fd()), &st)
|
||||
if err != nil {
|
||||
if err := syscall.Fstat(int(sparseFile.Fd()), &st); err != nil {
|
||||
logrus.Errorf("Reading information about loopback file %s: %v", sparseName, err)
|
||||
return nil, ErrAttachLoopbackDevice
|
||||
}
|
||||
@ -70,7 +69,7 @@ func openNextAvailableLoopback(sparseName string, sparseFile *os.File) (loopFile
|
||||
target := fmt.Sprintf("/dev/loop%d", index)
|
||||
|
||||
// OpenFile adds O_CLOEXEC
|
||||
loopFile, err = os.OpenFile(target, os.O_RDWR, 0o644)
|
||||
loopFile, err := os.OpenFile(target, os.O_RDWR, 0o644)
|
||||
if err != nil {
|
||||
// The kernel returns ENXIO when opening a device that is in the "deleting" or "rundown" state, so
|
||||
// just treat ENXIO as if the device does not exist.
|
||||
@ -100,13 +99,12 @@ func openNextAvailableLoopback(sparseName string, sparseFile *os.File) (loopFile
|
||||
loopFile.Close()
|
||||
|
||||
// If the error is EBUSY, then try the next loopback
|
||||
if err != syscall.EBUSY {
|
||||
logrus.Errorf("Cannot set up loopback device %s: %s", target, err)
|
||||
return nil, ErrAttachLoopbackDevice
|
||||
if err == syscall.EBUSY {
|
||||
continue
|
||||
}
|
||||
|
||||
// Otherwise, we keep going with the loop
|
||||
continue
|
||||
logrus.Errorf("Cannot set up loopback device %s: %s", target, err)
|
||||
return nil, ErrAttachLoopbackDevice
|
||||
}
|
||||
|
||||
// Check if the loopback driver and underlying filesystem agree on the loopback file's
|
||||
@ -119,18 +117,8 @@ func openNextAvailableLoopback(sparseName string, sparseFile *os.File) (loopFile
|
||||
if dev != uint64(st.Dev) || ino != st.Ino {
|
||||
logrus.Errorf("Loopback device and filesystem disagree on device/inode for %q: %#x(%d):%#x(%d) vs %#x(%d):%#x(%d)", sparseName, dev, dev, ino, ino, st.Dev, st.Dev, st.Ino, st.Ino)
|
||||
}
|
||||
|
||||
// In case of success, we finished. Break the loop.
|
||||
break
|
||||
return loopFile, nil
|
||||
}
|
||||
|
||||
// This can't happen, but let's be sure
|
||||
if loopFile == nil {
|
||||
logrus.Errorf("Unreachable code reached! Error attaching %s to a loopback device.", sparseFile.Name())
|
||||
return nil, ErrAttachLoopbackDevice
|
||||
}
|
||||
|
||||
return loopFile, nil
|
||||
}
|
||||
|
||||
// AttachLoopDevice attaches the given sparse file to the next
|
||||
|
52
vendor/github.com/containers/storage/storage.conf
generated
vendored
52
vendor/github.com/containers/storage/storage.conf
generated
vendored
@ -54,32 +54,31 @@ graphroot = "/var/lib/containers/storage"
|
||||
additionalimagestores = [
|
||||
]
|
||||
|
||||
# Allows specification of how storage is populated when pulling images. This
|
||||
# option can speed the pulling process of images compressed with format
|
||||
# zstd:chunked. Containers/storage looks for files within images that are being
|
||||
# pulled from a container registry that were previously pulled to the host. It
|
||||
# can copy or create a hard link to the existing file when it finds them,
|
||||
# eliminating the need to pull them from the container registry. These options
|
||||
# can deduplicate pulling of content, disk storage of content and can allow the
|
||||
# kernel to use less memory when running containers.
|
||||
# Options controlling how storage is populated when pulling images.
|
||||
[storage.options.pull_options]
|
||||
# Enable the "zstd:chunked" feature, which allows partial pulls, reusing
|
||||
# content that already exists on the system. This is enabled by default,
|
||||
# but can be explicitly disabled. For more on zstd:chunked, see
|
||||
# https://github.com/containers/storage/blob/main/docs/containers-storage-zstd-chunked.md
|
||||
# This is a "string bool": "false" | "true" (cannot be native TOML boolean)
|
||||
# enable_partial_images = "true"
|
||||
|
||||
# containers/storage supports four keys
|
||||
# * enable_partial_images="true" | "false"
|
||||
# Tells containers/storage to look for files previously pulled in storage
|
||||
# rather then always pulling them from the container registry.
|
||||
# * use_hard_links = "false" | "true"
|
||||
# Tells containers/storage to use hard links rather then create new files in
|
||||
# the image, if an identical file already existed in storage.
|
||||
# * ostree_repos = ""
|
||||
# Tells containers/storage where an ostree repository exists that might have
|
||||
# previously pulled content which can be used when attempting to avoid
|
||||
# pulling content from the container registry
|
||||
# * convert_images = "false" | "true"
|
||||
# If set to true, containers/storage will convert images to a
|
||||
# format compatible with partial pulls in order to take advantage
|
||||
# of local deduplication and hard linking. It is an expensive
|
||||
# operation so it is not enabled by default.
|
||||
pull_options = {enable_partial_images = "true", use_hard_links = "false", ostree_repos=""}
|
||||
# Tells containers/storage to use hard links rather then create new files in
|
||||
# the image, if an identical file already existed in storage.
|
||||
# This is a "string bool": "false" | "true" (cannot be native TOML boolean)
|
||||
# use_hard_links = "false"
|
||||
|
||||
# Path to an ostree repository that might have
|
||||
# previously pulled content which can be used when attempting to avoid
|
||||
# pulling content from the container registry
|
||||
# ostree_repos=""
|
||||
|
||||
# If set to "true", containers/storage will convert images to a
|
||||
# format compatible with partial pulls in order to take advantage
|
||||
# of local deduplication and hard linking. It is an expensive
|
||||
# operation so it is not enabled by default.
|
||||
# This is a "string bool": "false" | "true" (cannot be native TOML boolean)
|
||||
# convert_images = "false"
|
||||
|
||||
# Root-auto-userns-user is a user name which can be used to look up one or more UID/GID
|
||||
# ranges in the /etc/subuid and /etc/subgid file. These ranges will be partitioned
|
||||
@ -102,6 +101,7 @@ pull_options = {enable_partial_images = "true", use_hard_links = "false", ostree
|
||||
# squashed down to the default uid in the container. These images will have no
|
||||
# separation between the users in the container. Only supported for the overlay
|
||||
# and vfs drivers.
|
||||
# This is a "string bool": "false" | "true" (cannot be native TOML boolean)
|
||||
#ignore_chown_errors = "false"
|
||||
|
||||
# Inodes is used to set a maximum inodes of the container image.
|
||||
@ -115,9 +115,11 @@ pull_options = {enable_partial_images = "true", use_hard_links = "false", ostree
|
||||
mountopt = "nodev"
|
||||
|
||||
# Set to skip a PRIVATE bind mount on the storage home directory.
|
||||
# This is a "string bool": "false" | "true" (cannot be native TOML boolean)
|
||||
# skip_mount_home = "false"
|
||||
|
||||
# Set to use composefs to mount data layers with overlay.
|
||||
# This is a "string bool": "false" | "true" (cannot be native TOML boolean)
|
||||
# use_composefs = "false"
|
||||
|
||||
# Size is used to set a maximum size of the container image.
|
||||
|
72
vendor/github.com/containers/storage/store.go
generated
vendored
72
vendor/github.com/containers/storage/store.go
generated
vendored
@ -84,6 +84,20 @@ type ApplyStagedLayerOptions struct {
|
||||
DiffOptions *drivers.ApplyDiffWithDifferOpts // Mandatory
|
||||
}
|
||||
|
||||
// MultiListOptions contains options to pass to MultiList
|
||||
type MultiListOptions struct {
|
||||
Images bool // if true, Images will be listed in the result
|
||||
Layers bool // if true, layers will be listed in the result
|
||||
Containers bool // if true, containers will be listed in the result
|
||||
}
|
||||
|
||||
// MultiListResult contains slices of Images, Layers or Containers listed by MultiList method
|
||||
type MultiListResult struct {
|
||||
Images []Image
|
||||
Layers []Layer
|
||||
Containers []Container
|
||||
}
|
||||
|
||||
// An roBigDataStore wraps up the read-only big-data related methods of the
|
||||
// various types of file-based lookaside stores that we implement.
|
||||
type roBigDataStore interface {
|
||||
@ -561,6 +575,12 @@ type Store interface {
|
||||
// usually by deleting layers and images which are damaged. If the
|
||||
// right options are set, it will remove containers as well.
|
||||
Repair(report CheckReport, options *RepairOptions) []error
|
||||
|
||||
// MultiList returns a MultiListResult structure that contains layer, image, or container
|
||||
// extracts according to the values in MultiListOptions.
|
||||
// MultiList returns consistent values as of a single point in time.
|
||||
// WARNING: The values may already be out of date by the time they are returned to the caller.
|
||||
MultiList(MultiListOptions) (MultiListResult, error)
|
||||
}
|
||||
|
||||
// AdditionalLayer represents a layer that is contained in the additional layer store
|
||||
@ -3815,3 +3835,55 @@ func (s *store) GarbageCollect() error {
|
||||
|
||||
return firstErr
|
||||
}
|
||||
|
||||
// List returns a MultiListResult structure that contains layer, image, or container
|
||||
// extracts according to the values in MultiListOptions.
|
||||
func (s *store) MultiList(options MultiListOptions) (MultiListResult, error) {
|
||||
// TODO: Possible optimization: Deduplicate content from multiple stores.
|
||||
out := MultiListResult{}
|
||||
|
||||
if options.Layers {
|
||||
layerStores, err := s.allLayerStores()
|
||||
if err != nil {
|
||||
return MultiListResult{}, err
|
||||
}
|
||||
for _, roStore := range layerStores {
|
||||
if err := roStore.startReading(); err != nil {
|
||||
return MultiListResult{}, err
|
||||
}
|
||||
defer roStore.stopReading()
|
||||
layers, err := roStore.Layers()
|
||||
if err != nil {
|
||||
return MultiListResult{}, err
|
||||
}
|
||||
out.Layers = append(out.Layers, layers...)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Images {
|
||||
for _, roStore := range s.allImageStores() {
|
||||
if err := roStore.startReading(); err != nil {
|
||||
return MultiListResult{}, err
|
||||
}
|
||||
defer roStore.stopReading()
|
||||
|
||||
images, err := roStore.Images()
|
||||
if err != nil {
|
||||
return MultiListResult{}, err
|
||||
}
|
||||
out.Images = append(out.Images, images...)
|
||||
}
|
||||
}
|
||||
|
||||
if options.Containers {
|
||||
containers, _, err := readContainerStore(s, func() ([]Container, bool, error) {
|
||||
res, err := s.containerStore.Containers()
|
||||
return res, true, err
|
||||
})
|
||||
if err != nil {
|
||||
return MultiListResult{}, err
|
||||
}
|
||||
out.Containers = append(out.Containers, containers...)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user