Skip to content

Commit 189032d

Browse files
committed
When checking IsDangling make sure image is not in manifest list
Currently when we run podman image prune or podman images --filter dangling It is pruning images that are in a local manifest. These images are not dangling because they are currently in use by a named manifest list. You can create this situation simply by doing echo "from scratch" > /tmp/Containerfile id=$(podman build /tmp) podman manifest create test $id podman image prune --force podman image exists $id Will return an error since the image was pruned. Now the local manifest test is broken. Signed-off-by: Daniel J Walsh <[email protected]>
1 parent 63cb298 commit 189032d

File tree

3 files changed

+28
-3
lines changed

3 files changed

+28
-3
lines changed

libimage/image.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,10 @@ func (i *Image) isDangling(ctx context.Context, tree *layerTree) (bool, error) {
206206
if err != nil {
207207
return false, err
208208
}
209-
return len(children) == 0, nil
209+
if len(children) != 0 {
210+
return false, nil
211+
}
212+
return !tree.manifestDigests[i.Digest()], nil
210213
}
211214

212215
// IsIntermediate returns true if the image is an intermediate image, that is

libimage/layer_tree.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/containers/storage"
1010
storageTypes "github.com/containers/storage/types"
11+
digest "github.com/opencontainers/go-digest"
1112
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
1213
"github.com/sirupsen/logrus"
1314
)
@@ -22,6 +23,8 @@ type layerTree struct {
2223
// emptyImages do not have any top-layer so we cannot create a
2324
// *layerNode for them.
2425
emptyImages []*Image
26+
27+
manifestDigests map[digest.Digest]bool
2528
}
2629

2730
// node returns a layerNode for the specified layerID.
@@ -102,8 +105,9 @@ func (r *Runtime) newFreshLayerTree() (*layerTree, error) {
102105
// The caller is responsible for (layers, images) being consistent.
103106
func (r *Runtime) newLayerTreeFromData(images []*Image, layers []storage.Layer) (*layerTree, error) {
104107
tree := layerTree{
105-
nodes: make(map[string]*layerNode),
106-
ociCache: make(map[string]*ociv1.Image),
108+
nodes: make(map[string]*layerNode),
109+
ociCache: make(map[string]*ociv1.Image),
110+
manifestDigests: make(map[digest.Digest]bool),
107111
}
108112

109113
// First build a tree purely based on layer information.
@@ -124,6 +128,15 @@ func (r *Runtime) newLayerTreeFromData(images []*Image, layers []storage.Layer)
124128
topLayer := img.TopLayer()
125129
if topLayer == "" {
126130
tree.emptyImages = append(tree.emptyImages, img)
131+
if manifestList, _ := img.IsManifestList(context.TODO()); manifestList {
132+
mlist, err := img.ToManifestList()
133+
if err != nil {
134+
return nil, err
135+
}
136+
for _, digest := range mlist.list.Digests() {
137+
tree.manifestDigests[digest] = true
138+
}
139+
}
127140
continue
128141
}
129142
node, exists := tree.nodes[topLayer]

pkg/manifests/manifests.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ type List interface {
5050

5151
findDocker(instanceDigest digest.Digest) (*manifest.Schema2ManifestDescriptor, error)
5252
findOCIv1(instanceDigest digest.Digest) (*v1.Descriptor, error)
53+
Digests() []digest.Digest
5354
}
5455

5556
type list struct {
@@ -677,3 +678,11 @@ func (l *list) Instances() []digest.Digest {
677678
}
678679
return instances
679680
}
681+
682+
func (l *list) Digests() []digest.Digest {
683+
var digests []digest.Digest
684+
for i := range l.docker.Manifests {
685+
digests = append(digests, l.docker.Manifests[i].Digest)
686+
}
687+
return digests
688+
}

0 commit comments

Comments
 (0)