image prune: support removing external containers

Support removing external containers (e.g., build containers) during
image prune.

Fixes: #11472
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg
2021-09-24 14:39:36 +02:00
parent 340166876e
commit a9a54eefab
26 changed files with 208 additions and 70 deletions

View File

@ -2,6 +2,7 @@ package libimage
import (
"context"
"fmt"
"path/filepath"
"sort"
"strings"
@ -51,7 +52,7 @@ func (i *Image) reload() error {
logrus.Tracef("Reloading image %s", i.ID())
img, err := i.runtime.store.Image(i.ID())
if err != nil {
return errors.Wrap(err, "error reloading image")
return errors.Wrap(err, "reloading image")
}
i.storageImage = img
i.cached.imageSource = nil
@ -232,11 +233,15 @@ func (i *Image) Containers() ([]string, error) {
}
// removeContainers removes all containers using the image.
func (i *Image) removeContainers(fn RemoveContainerFunc) error {
// Execute the custom removal func if specified.
if fn != nil {
func (i *Image) removeContainers(options *RemoveImagesOptions) error {
if !options.Force && !options.ExternalContainers {
// Nothing to do.
return nil
}
if options.Force && options.RemoveContainerFunc != nil {
logrus.Debugf("Removing containers of image %s with custom removal function", i.ID())
if err := fn(i.ID()); err != nil {
if err := options.RemoveContainerFunc(i.ID()); err != nil {
return err
}
}
@ -246,6 +251,19 @@ func (i *Image) removeContainers(fn RemoveContainerFunc) error {
return err
}
if !options.Force && options.ExternalContainers {
// All containers must be external ones.
for _, cID := range containers {
isExternal, err := options.IsExternalContainerFunc(cID)
if err != nil {
return fmt.Errorf("checking if %s is an external container: %w", cID, err)
}
if !isExternal {
return fmt.Errorf("cannot remove container %s: not an external container", cID)
}
}
}
logrus.Debugf("Removing containers of image %s from the local containers storage", i.ID())
var multiE error
for _, cID := range containers {
@ -392,11 +410,9 @@ func (i *Image) removeRecursive(ctx context.Context, rmMap map[string]*RemoveIma
return processedIDs, nil
}
// Perform the actual removal. First, remove containers if needed.
if options.Force {
if err := i.removeContainers(options.RemoveContainerFunc); err != nil {
return processedIDs, err
}
// Perform the container removal, if needed.
if err := i.removeContainers(options); err != nil {
return processedIDs, err
}
// Podman/Docker compat: we only report an image as removed if it has
@ -406,7 +422,7 @@ func (i *Image) removeRecursive(ctx context.Context, rmMap map[string]*RemoveIma
if err != nil {
// We must be tolerant toward corrupted images.
// See containers/podman commit fd9dd7065d44.
logrus.Warnf("error determining if an image is a parent: %v, ignoring the error", err)
logrus.Warnf("Failed to determine if an image is a parent: %v, ignoring the error", err)
hasChildren = false
}
@ -416,7 +432,7 @@ func (i *Image) removeRecursive(ctx context.Context, rmMap map[string]*RemoveIma
if err != nil {
// We must be tolerant toward corrupted images.
// See containers/podman commit fd9dd7065d44.
logrus.Warnf("error determining parent of image: %v, ignoring the error", err)
logrus.Warnf("Failed to determine parent of image: %v, ignoring the error", err)
parent = nil
}
@ -440,7 +456,7 @@ func (i *Image) removeRecursive(ctx context.Context, rmMap map[string]*RemoveIma
if err != nil {
// See Podman commit fd9dd7065d44: we need to
// be tolerant toward corrupted images.
logrus.Warnf("error determining if an image is a parent: %v, ignoring the error", err)
logrus.Warnf("Failed to determine if an image is a parent: %v, ignoring the error", err)
danglingParent = false
}
if !danglingParent {
@ -462,7 +478,7 @@ func (i *Image) Tag(name string) error {
ref, err := NormalizeName(name)
if err != nil {
return errors.Wrapf(err, "error normalizing name %q", name)
return errors.Wrapf(err, "normalizing name %q", name)
}
if _, isDigested := ref.(reference.Digested); isDigested {
@ -499,7 +515,7 @@ func (i *Image) Untag(name string) error {
ref, err := NormalizeName(name)
if err != nil {
return errors.Wrapf(err, "error normalizing name %q", name)
return errors.Wrapf(err, "normalizing name %q", name)
}
// FIXME: this is breaking Podman CI but must be re-enabled once
@ -885,12 +901,12 @@ func getImageID(ctx context.Context, src types.ImageReference, sys *types.System
}
defer func() {
if err := newImg.Close(); err != nil {
logrus.Errorf("failed to close image: %q", err)
logrus.Errorf("Failed to close image: %q", err)
}
}()
imageDigest := newImg.ConfigInfo().Digest
if err = imageDigest.Validate(); err != nil {
return "", errors.Wrapf(err, "error getting config info")
return "", errors.Wrapf(err, "getting config info")
}
return "@" + imageDigest.Encoded(), nil
}