diff options
author | Valentin Rothberg <rothberg@redhat.com> | 2021-09-24 14:39:36 +0200 |
---|---|---|
committer | Valentin Rothberg <rothberg@redhat.com> | 2021-09-28 10:24:16 +0200 |
commit | a9a54eefab34b25628906a786d6c4ca302f743b1 (patch) | |
tree | de48efeabf92b80e8cc69c456f33908124630769 /vendor | |
parent | 340166876eab09d3e363647213f162864a95d270 (diff) | |
download | podman-a9a54eefab34b25628906a786d6c4ca302f743b1.tar.gz podman-a9a54eefab34b25628906a786d6c4ca302f743b1.tar.bz2 podman-a9a54eefab34b25628906a786d6c4ca302f743b1.zip |
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>
Diffstat (limited to 'vendor')
12 files changed, 117 insertions, 52 deletions
diff --git a/vendor/github.com/containers/common/libimage/copier.go b/vendor/github.com/containers/common/libimage/copier.go index 42d3690b9..636b97bfd 100644 --- a/vendor/github.com/containers/common/libimage/copier.go +++ b/vendor/github.com/containers/common/libimage/copier.go @@ -304,7 +304,7 @@ func (r *Runtime) newCopier(options *CopyOptions) (*copier, error) { defaultContainerConfig, err := config.Default() if err != nil { - logrus.Warnf("failed to get container config for copy options: %v", err) + logrus.Warnf("Failed to get container config for copy options: %v", err) } else { c.imageCopyOptions.MaxParallelDownloads = defaultContainerConfig.Engine.ImageParallelCopies } diff --git a/vendor/github.com/containers/common/libimage/filters.go b/vendor/github.com/containers/common/libimage/filters.go index 0cc5cc311..833f940cc 100644 --- a/vendor/github.com/containers/common/libimage/filters.go +++ b/vendor/github.com/containers/common/libimage/filters.go @@ -47,11 +47,11 @@ func filterImages(images []*Image, filters []filterFunc) ([]*Image, error) { // compileImageFilters creates `filterFunc`s for the specified filters. The // 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, filters []string) ([]filterFunc, error) { - logrus.Tracef("Parsing image filters %s", filters) +func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOptions) ([]filterFunc, error) { + logrus.Tracef("Parsing image filters %s", options.Filters) filterFuncs := []filterFunc{} - for _, filter := range filters { + for _, filter := range options.Filters { var key, value string split := strings.SplitN(filter, "=", 2) if len(split) != 2 { @@ -77,11 +77,16 @@ func (r *Runtime) compileImageFilters(ctx context.Context, filters []string) ([] filterFuncs = append(filterFuncs, filterBefore(img.Created())) case "containers": - containers, err := strconv.ParseBool(value) - if err != nil { - return nil, errors.Wrapf(err, "non-boolean value %q for dangling filter", value) + switch value { + case "false", "true": + case "external": + if options.IsExternalContainerFunc == nil { + return nil, fmt.Errorf("libimage error: external containers filter without callback") + } + default: + return nil, fmt.Errorf("unsupported value %q for containers filter", value) } - filterFuncs = append(filterFuncs, filterContainers(containers)) + filterFuncs = append(filterFuncs, filterContainers(value, options.IsExternalContainerFunc)) case "dangling": dangling, err := strconv.ParseBool(value) @@ -190,13 +195,28 @@ func filterReadOnly(value bool) filterFunc { } // filterContainers creates a container filter for matching the specified value. -func filterContainers(value bool) filterFunc { +func filterContainers(value string, fn IsExternalContainerFunc) filterFunc { return func(img *Image) (bool, error) { ctrs, err := img.Containers() if err != nil { return false, err } - return (len(ctrs) > 0) == value, nil + if value != "external" { + boolValue := value == "true" + return (len(ctrs) > 0) == boolValue, nil + } + + // Check whether all associated containers are external ones. + for _, c := range ctrs { + isExternal, err := fn(c) + if err != nil { + return false, fmt.Errorf("checking if %s is an external container in filter: %w", c, err) + } + if !isExternal { + return isExternal, nil + } + } + return true, nil } } diff --git a/vendor/github.com/containers/common/libimage/image.go b/vendor/github.com/containers/common/libimage/image.go index 8456d5280..00a2d620e 100644 --- a/vendor/github.com/containers/common/libimage/image.go +++ b/vendor/github.com/containers/common/libimage/image.go @@ -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 } diff --git a/vendor/github.com/containers/common/libimage/manifests/manifests.go b/vendor/github.com/containers/common/libimage/manifests/manifests.go index 81b5343c0..8d1abfba9 100644 --- a/vendor/github.com/containers/common/libimage/manifests/manifests.go +++ b/vendor/github.com/containers/common/libimage/manifests/manifests.go @@ -125,19 +125,19 @@ func (l *list) SaveToImage(store storage.Store, imageID string, names []string, if err != nil { if created { if _, err2 := store.DeleteImage(img.ID, true); err2 != nil { - logrus.Errorf("error deleting image %q after failing to save manifest for it", img.ID) + logrus.Errorf("Deleting image %q after failing to save manifest for it", img.ID) } } - return "", errors.Wrapf(err, "error saving manifest list to image %q", imageID) + return "", errors.Wrapf(err, "saving manifest list to image %q", imageID) } err = store.SetImageBigData(imageID, instancesData, instancesBytes, nil) if err != nil { if created { if _, err2 := store.DeleteImage(img.ID, true); err2 != nil { - logrus.Errorf("error deleting image %q after failing to save instance locations for it", img.ID) + logrus.Errorf("Deleting image %q after failing to save instance locations for it", img.ID) } } - return "", errors.Wrapf(err, "error saving instance list to image %q", imageID) + return "", errors.Wrapf(err, "saving instance list to image %q", imageID) } return imageID, nil } @@ -200,7 +200,7 @@ func (l *list) Push(ctx context.Context, dest types.ImageReference, options Push } defer func() { if err2 := policyContext.Destroy(); err2 != nil { - logrus.Errorf("error destroying signature policy context: %v", err2) + logrus.Errorf("Destroying signature policy context: %v", err2) } }() diff --git a/vendor/github.com/containers/common/libimage/runtime.go b/vendor/github.com/containers/common/libimage/runtime.go index 42461014d..dabadbec0 100644 --- a/vendor/github.com/containers/common/libimage/runtime.go +++ b/vendor/github.com/containers/common/libimage/runtime.go @@ -2,6 +2,7 @@ package libimage import ( "context" + "fmt" "os" "strings" @@ -306,7 +307,7 @@ func (r *Runtime) lookupImageInLocalStorage(name, candidate string, options *Loo if errors.Cause(err) == os.ErrNotExist { // We must be tolerant toward corrupted images. // See containers/podman commit fd9dd7065d44. - logrus.Warnf("error determining if an image is a manifest list: %v, ignoring the error", err) + logrus.Warnf("Failed to determine if an image is a manifest list: %v, ignoring the error", err) return image, nil } return nil, err @@ -484,10 +485,16 @@ func (r *Runtime) imageReferenceMatchesContext(ref types.ImageReference, options return true, nil } +// IsExternalContainerFunc allows for checking whether the specified container +// is an external one. The definition of an external container can be set by +// callers. +type IsExternalContainerFunc func(containerID string) (bool, error) + // ListImagesOptions allow for customizing listing images. type ListImagesOptions struct { // Filters to filter the listed images. Supported filters are // * after,before,since=image + // * containers=true,false,external // * dangling=true,false // * intermediate=true,false (useful for pruning images) // * id=id @@ -495,6 +502,11 @@ type ListImagesOptions struct { // * readonly=true,false // * reference=name[:tag] (wildcards allowed) Filters []string + // IsExternalContainerFunc allows for checking whether the specified + // container is an external one (when containers=external filter is + // used). The definition of an external container can be set by + // callers. + IsExternalContainerFunc IsExternalContainerFunc } // ListImages lists images in the local container storage. If names are @@ -525,7 +537,7 @@ func (r *Runtime) ListImages(ctx context.Context, names []string, options *ListI var filters []filterFunc if len(options.Filters) > 0 { - compiledFilters, err := r.compileImageFilters(ctx, options.Filters) + compiledFilters, err := r.compileImageFilters(ctx, options) if err != nil { return nil, err } @@ -550,8 +562,17 @@ type RemoveImagesOptions struct { // containers using a specific image. By default, all containers in // the local containers storage will be removed (if Force is set). RemoveContainerFunc RemoveContainerFunc + // IsExternalContainerFunc allows for checking whether the specified + // container is an external one (when containers=external filter is + // used). The definition of an external container can be set by + // callers. + IsExternalContainerFunc IsExternalContainerFunc + // Remove external containers even when Force is false. Requires + // IsExternalContainerFunc to be specified. + ExternalContainers bool // Filters to filter the removed images. Supported filters are // * after,before,since=image + // * containers=true,false,external // * dangling=true,false // * intermediate=true,false (useful for pruning images) // * id=id @@ -581,6 +602,10 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem options = &RemoveImagesOptions{} } + if options.ExternalContainers && options.IsExternalContainerFunc == nil { + return nil, []error{fmt.Errorf("libimage error: cannot remove external containers without callback")} + } + // The logic here may require some explanation. Image removal is // surprisingly complex since it is recursive (intermediate parents are // removed) and since multiple items in `names` may resolve to the @@ -635,7 +660,11 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem } default: - filteredImages, err := r.ListImages(ctx, nil, &ListImagesOptions{Filters: options.Filters}) + options := &ListImagesOptions{ + IsExternalContainerFunc: options.IsExternalContainerFunc, + Filters: options.Filters, + } + filteredImages, err := r.ListImages(ctx, nil, options) if err != nil { appendError(err) return nil, rmErrors diff --git a/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go b/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go index 4f11e4ed2..735d19493 100644 --- a/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go +++ b/vendor/github.com/containers/common/pkg/apparmor/apparmor_linux.go @@ -97,22 +97,22 @@ func InstallDefault(name string) error { } if err := cmd.Start(); err != nil { if pipeErr := pipe.Close(); pipeErr != nil { - logrus.Errorf("unable to close AppArmor pipe: %q", pipeErr) + logrus.Errorf("Unable to close AppArmor pipe: %q", pipeErr) } return errors.Wrapf(err, "start %s command", apparmorParserPath) } if err := p.generateDefault(apparmorParserPath, pipe); err != nil { if pipeErr := pipe.Close(); pipeErr != nil { - logrus.Errorf("unable to close AppArmor pipe: %q", pipeErr) + logrus.Errorf("Unable to close AppArmor pipe: %q", pipeErr) } if cmdErr := cmd.Wait(); cmdErr != nil { - logrus.Errorf("unable to wait for AppArmor command: %q", cmdErr) + logrus.Errorf("Unable to wait for AppArmor command: %q", cmdErr) } return errors.Wrap(err, "generate default profile into pipe") } if pipeErr := pipe.Close(); pipeErr != nil { - logrus.Errorf("unable to close AppArmor pipe: %q", pipeErr) + logrus.Errorf("Unable to close AppArmor pipe: %q", pipeErr) } return errors.Wrap(cmd.Wait(), "wait for AppArmor command") @@ -252,7 +252,7 @@ func CheckProfileAndLoadDefault(name string) (string, error) { if name != "" { return "", errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name) } else { - logrus.Debug("skipping loading default AppArmor profile (rootless mode)") + logrus.Debug("Skipping loading default AppArmor profile (rootless mode)") return "", nil } } @@ -292,7 +292,7 @@ func CheckProfileAndLoadDefault(name string) (string, error) { if err != nil { return "", errors.Wrapf(err, "install profile %s", name) } - logrus.Infof("successfully loaded AppAmor profile %q", name) + logrus.Infof("Successfully loaded AppAmor profile %q", name) } else { logrus.Infof("AppAmor profile %q is already loaded", name) } diff --git a/vendor/github.com/containers/common/pkg/retry/retry.go b/vendor/github.com/containers/common/pkg/retry/retry.go index 8eb2da975..43e3a6688 100644 --- a/vendor/github.com/containers/common/pkg/retry/retry.go +++ b/vendor/github.com/containers/common/pkg/retry/retry.go @@ -30,7 +30,7 @@ func RetryIfNecessary(ctx context.Context, operation func() error, retryOptions if retryOptions.Delay != 0 { delay = retryOptions.Delay } - logrus.Warnf("failed, retrying in %s ... (%d/%d). Error: %v", delay, attempt+1, retryOptions.MaxRetry, err) + logrus.Warnf("Failed, retrying in %s ... (%d/%d). Error: %v", delay, attempt+1, retryOptions.MaxRetry, err) select { case <-time.After(delay): break diff --git a/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go index 4b7253b31..6c9321e73 100644 --- a/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go +++ b/vendor/github.com/containers/common/pkg/subscriptions/subscriptions.go @@ -114,13 +114,13 @@ func getMounts(filePath string) []string { file, err := os.Open(filePath) if err != nil { // This is expected on most systems - logrus.Debugf("file %q not found, skipping...", filePath) + logrus.Debugf("File %q not found, skipping...", filePath) return nil } defer file.Close() scanner := bufio.NewScanner(file) if err = scanner.Err(); err != nil { - logrus.Errorf("error reading file %q, %v skipping...", filePath, err) + logrus.Errorf("Reading file %q, %v skipping...", filePath, err) return nil } var mounts []string @@ -128,7 +128,7 @@ func getMounts(filePath string) []string { if strings.HasPrefix(strings.TrimSpace(scanner.Text()), "/") { mounts = append(mounts, scanner.Text()) } else { - logrus.Debugf("skipping unrecognized mount in %v: %q", + logrus.Debugf("Skipping unrecognized mount in %v: %q", filePath, scanner.Text()) } } @@ -176,7 +176,7 @@ func MountsWithUIDGID(mountLabel, containerWorkingDir, mountFile, mountPoint str if _, err := os.Stat(file); err == nil { mounts, err := addSubscriptionsFromMountsFile(file, mountLabel, containerWorkingDir, uid, gid) if err != nil { - logrus.Warnf("error mounting subscriptions, skipping entry in %s: %v", file, err) + logrus.Warnf("Failed to mount subscriptions, skipping entry in %s: %v", file, err) } subscriptionMounts = mounts break @@ -192,7 +192,7 @@ func MountsWithUIDGID(mountLabel, containerWorkingDir, mountFile, mountPoint str switch { case err == nil: if err := addFIPSModeSubscription(&subscriptionMounts, containerWorkingDir, mountPoint, mountLabel, uid, gid); err != nil { - logrus.Errorf("error adding FIPS mode subscription to container: %v", err) + logrus.Errorf("Adding FIPS mode subscription to container: %v", err) } case os.IsNotExist(err): logrus.Debug("/etc/system-fips does not exist on host, not mounting FIPS mode subscription") diff --git a/vendor/github.com/containers/common/pkg/supplemented/supplemented.go b/vendor/github.com/containers/common/pkg/supplemented/supplemented.go index a36c3eda4..196176a1c 100644 --- a/vendor/github.com/containers/common/pkg/supplemented/supplemented.go +++ b/vendor/github.com/containers/common/pkg/supplemented/supplemented.go @@ -83,12 +83,12 @@ func (s *supplementedImageReference) NewImageSource(ctx context.Context, sys *ty if iss != nil { // The composite source has been created. Use its Close method. if err2 := iss.Close(); err2 != nil { - logrus.Errorf("error opening image: %v", err2) + logrus.Errorf("Opening image: %v", err2) } } else if top != nil { // The composite source has not been created, but the top was already opened. Close it. if err2 := top.Close(); err2 != nil { - logrus.Errorf("error opening image: %v", err2) + logrus.Errorf("Closing image: %v", err2) } } } diff --git a/vendor/github.com/containers/common/pkg/sysinfo/sysinfo_linux.go b/vendor/github.com/containers/common/pkg/sysinfo/sysinfo_linux.go index 1935d71f1..6420ba274 100644 --- a/vendor/github.com/containers/common/pkg/sysinfo/sysinfo_linux.go +++ b/vendor/github.com/containers/common/pkg/sysinfo/sysinfo_linux.go @@ -237,7 +237,7 @@ func checkCgroupPids(cgMounts map[string]string, quiet bool) cgroupPids { _, ok := cgMounts["pids"] if !ok { if !quiet { - logrus.Warn("unable to find pids cgroup in mounts") + logrus.Warn("Unable to find pids cgroup in mounts") } return cgroupPids{} } diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go index 346b0a423..b6ceabce5 100644 --- a/vendor/github.com/containers/common/version/version.go +++ b/vendor/github.com/containers/common/version/version.go @@ -1,4 +1,4 @@ package version // Version is the version of the build. -const Version = "0.46.0" +const Version = "0.46.1-dev" diff --git a/vendor/modules.txt b/vendor/modules.txt index e79bbcc44..1fb03d302 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -97,7 +97,7 @@ github.com/containers/buildah/pkg/rusage github.com/containers/buildah/pkg/sshagent github.com/containers/buildah/pkg/util github.com/containers/buildah/util -# github.com/containers/common v0.46.0 +# github.com/containers/common v0.46.1-0.20210928081721-32e20295f1c6 github.com/containers/common/libimage github.com/containers/common/libimage/manifests github.com/containers/common/pkg/apparmor |