refine dangling filters

As discussed in github.com/containers/podman/issues/10832 the definition
of a "dangling" image in Podman has historically been incorrect.  While
the Docker docs describe a dangling image as an image without a tag, and
Podman implemented the filters as such, Docker actually implemented the
filters for images without a tag and without children.

Refine the dangling filters and hence `IsDangling()` to only return true
if an image is untagged and has no children.

Also correct the comments of `IsIntermediate()`.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg 2021-07-16 11:38:42 +02:00
parent d7be19edf4
commit e983ccadc6
3 changed files with 32 additions and 24 deletions

View File

@ -88,7 +88,7 @@ func (r *Runtime) compileImageFilters(ctx context.Context, filters []string) ([]
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "non-boolean value %q for dangling filter", value) return nil, errors.Wrapf(err, "non-boolean value %q for dangling filter", value)
} }
filterFuncs = append(filterFuncs, filterDangling(dangling)) filterFuncs = append(filterFuncs, filterDangling(ctx, dangling))
case "id": case "id":
filterFuncs = append(filterFuncs, filterID(value)) filterFuncs = append(filterFuncs, filterID(value))
@ -201,9 +201,13 @@ func filterContainers(value bool) filterFunc {
} }
// filterDangling creates a dangling filter for matching the specified value. // filterDangling creates a dangling filter for matching the specified value.
func filterDangling(value bool) filterFunc { func filterDangling(ctx context.Context, value bool) filterFunc {
return func(img *Image) (bool, error) { return func(img *Image) (bool, error) {
return img.IsDangling() == value, nil isDangling, err := img.IsDangling(ctx)
if err != nil {
return false, err
}
return isDangling == value, nil
} }
} }

View File

@ -121,24 +121,29 @@ func (i *Image) IsReadOnly() bool {
return i.storageImage.ReadOnly return i.storageImage.ReadOnly
} }
// IsDangling returns true if the image is dangling. An image is considered // IsDangling returns true if the image is dangling, that is an untagged image
// dangling if no names are associated with it in the containers storage. // without children.
func (i *Image) IsDangling() bool { func (i *Image) IsDangling(ctx context.Context) (bool, error) {
return len(i.Names()) == 0 if len(i.Names()) > 0 {
} return false, nil
}
// IsIntermediate returns true if the image is an intermediate image, that is children, err := i.getChildren(ctx, false)
// a dangling image without children. if err != nil {
func (i *Image) IsIntermediate(ctx context.Context) (bool, error) { return false, err
// If the image has tags, it's not an intermediate one. }
if !i.IsDangling() { return len(children) == 0, nil
}
// IsIntermediate returns true if the image is an intermediate image, that is
// an untagged image with children.
func (i *Image) IsIntermediate(ctx context.Context) (bool, error) {
if len(i.Names()) > 0 {
return false, nil return false, nil
} }
children, err := i.getChildren(ctx, false) children, err := i.getChildren(ctx, false)
if err != nil { if err != nil {
return false, err return false, err
} }
// No tags, no children -> intermediate!
return len(children) != 0, nil return len(children) != 0, nil
} }
@ -420,19 +425,16 @@ func (i *Image) remove(ctx context.Context, rmMap map[string]*RemoveImageReport,
return nil return nil
} }
if !parent.IsDangling() { // Only remove the parent if it's dangling, that is being untagged and
return nil // without children.
} danglingParent, err := parent.IsDangling(ctx)
// If the image has siblings, we don't remove the parent.
hasSiblings, err := parent.HasChildren(ctx)
if err != nil { if err != nil {
// See Podman commit fd9dd7065d44: we need to // See Podman commit fd9dd7065d44: we need to
// be tolerant toward corrupted images. // be tolerant toward corrupted images.
logrus.Warnf("error determining if an image is a parent: %v, ignoring the error", err) logrus.Warnf("error determining if an image is a parent: %v, ignoring the error", err)
hasSiblings = false danglingParent = false
} }
if hasSiblings { if !danglingParent {
return nil return nil
} }

View File

@ -64,7 +64,9 @@ func TestImageFunctions(t *testing.T) {
// Below mostly smoke tests. // Below mostly smoke tests.
require.False(t, image.IsReadOnly()) require.False(t, image.IsReadOnly())
require.False(t, image.IsDangling()) isDangling, err := image.IsDangling(ctx)
require.NoError(t, err)
require.False(t, isDangling)
isIntermediate, err := image.IsIntermediate(ctx) isIntermediate, err := image.IsIntermediate(ctx)
require.NoError(t, err) require.NoError(t, err)