Skip to content

Commit f71a7a6

Browse files
Merge pull request #2400 from Luap99/list-manifest
libimage: fix manifest race during listing
2 parents 0b7e12a + 0ae438f commit f71a7a6

File tree

6 files changed

+26
-17
lines changed

6 files changed

+26
-17
lines changed

Diff for: libimage/history.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func (i *Image) History(ctx context.Context) ([]ImageHistory, error) {
2525
return nil, err
2626
}
2727

28-
layerTree, err := i.runtime.newFreshLayerTree(ctx)
28+
layerTree, err := i.runtime.newFreshLayerTree()
2929
if err != nil {
3030
return nil, err
3131
}

Diff for: libimage/image.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ func (i *Image) IsDangling(ctx context.Context) (bool, error) {
197197
if err != nil {
198198
return false, err
199199
}
200-
tree, err := i.runtime.newLayerTreeFromData(ctx, images, layers, true)
200+
tree, err := i.runtime.newLayerTreeFromData(images, layers, true)
201201
if err != nil {
202202
return false, err
203203
}
@@ -267,7 +267,7 @@ func (i *Image) TopLayer() string {
267267

268268
// Parent returns the parent image or nil if there is none
269269
func (i *Image) Parent(ctx context.Context) (*Image, error) {
270-
tree, err := i.runtime.newFreshLayerTree(ctx)
270+
tree, err := i.runtime.newFreshLayerTree()
271271
if err != nil {
272272
return nil, err
273273
}
@@ -301,7 +301,7 @@ func (i *Image) Children(ctx context.Context) ([]*Image, error) {
301301
// created for this invocation only.
302302
func (i *Image) getChildren(ctx context.Context, all bool, tree *layerTree) ([]*Image, error) {
303303
if tree == nil {
304-
t, err := i.runtime.newFreshLayerTree(ctx)
304+
t, err := i.runtime.newFreshLayerTree()
305305
if err != nil {
306306
return nil, err
307307
}

Diff for: libimage/image_tree.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func (i *Image) Tree(ctx context.Context, traverseChildren bool) (string, error)
3838
fmt.Fprintf(sb, "No Image Layers")
3939
}
4040

41-
layerTree, err := i.runtime.newFreshLayerTree(ctx)
41+
layerTree, err := i.runtime.newFreshLayerTree()
4242
if err != nil {
4343
return "", err
4444
}

Diff for: libimage/layer_tree.go

+19-10
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,17 @@ func (l *layerNode) repoTags() ([]string, error) {
9595
}
9696

9797
// newFreshLayerTree extracts a layerTree from consistent layers and images in the local storage.
98-
func (r *Runtime) newFreshLayerTree(ctx context.Context) (*layerTree, error) {
98+
func (r *Runtime) newFreshLayerTree() (*layerTree, error) {
9999
images, layers, err := r.getImagesAndLayers()
100100
if err != nil {
101101
return nil, err
102102
}
103-
return r.newLayerTreeFromData(ctx, images, layers, false)
103+
return r.newLayerTreeFromData(images, layers, false)
104104
}
105105

106106
// newLayerTreeFromData extracts a layerTree from the given the layers and images.
107107
// The caller is responsible for (layers, images) being consistent.
108-
func (r *Runtime) newLayerTreeFromData(ctx context.Context, images []*Image, layers []storage.Layer, generateManifestDigestList bool) (*layerTree, error) {
108+
func (r *Runtime) newLayerTreeFromData(images []*Image, layers []storage.Layer, generateManifestDigestList bool) (*layerTree, error) {
109109
tree := layerTree{
110110
nodes: make(map[string]*layerNode),
111111
ociCache: make(map[string]*ociv1.Image),
@@ -136,14 +136,23 @@ func (r *Runtime) newLayerTreeFromData(ctx context.Context, images []*Image, lay
136136
if !generateManifestDigestList {
137137
continue
138138
}
139-
if manifestList, _ := img.IsManifestList(ctx); manifestList {
140-
mlist, err := img.ToManifestList()
141-
if err != nil {
142-
return nil, err
143-
}
144-
for _, digest := range mlist.list.Instances() {
145-
tree.manifestListDigests[digest] = struct{}{}
139+
// ignore errors, common errors are
140+
// - image is not manifest
141+
// - image has been removed from the store in the meantime
142+
// In all cases we should ensure image listing still works and not error out.
143+
mlist, err := img.ToManifestList()
144+
if err != nil {
145+
// If it is not a manifest it likely is a regular image so just ignore it.
146+
// If the image is unknown that likely means there was a race where the image/manifest
147+
// was removed after out MultiList() call so we ignore that as well.
148+
if errors.Is(err, ErrNotAManifestList) || errors.Is(err, storageTypes.ErrImageUnknown) {
149+
continue
146150
}
151+
return nil, err
152+
}
153+
154+
for _, digest := range mlist.list.Instances() {
155+
tree.manifestListDigests[digest] = struct{}{}
147156
}
148157
continue
149158
}

Diff for: libimage/manifests/manifests.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ func LoadFromImage(store storage.Store, image string) (string, List, error) {
149149
}
150150
manifestList, err := manifests.FromBlob(manifestBytes)
151151
if err != nil {
152-
return "", nil, err
152+
return "", nil, fmt.Errorf("decoding manifest blob for image %q: %w", image, err)
153153
}
154154
list := &list{
155155
List: manifestList,

Diff for: libimage/runtime.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ func (r *Runtime) ListImages(ctx context.Context, options *ListImagesOptions) ([
634634

635635
var tree *layerTree
636636
if needsLayerTree {
637-
tree, err = r.newLayerTreeFromData(ctx, images, snapshot.Layers, true)
637+
tree, err = r.newLayerTreeFromData(images, snapshot.Layers, true)
638638
if err != nil {
639639
return nil, err
640640
}

0 commit comments

Comments
 (0)