mirror of
https://github.com/containers/podman.git
synced 2025-07-01 00:01:02 +08:00
Merge pull request #5548 from kunalkushwaha/image-prune
image prune skips images with child images.
This commit is contained in:
@ -11,6 +11,8 @@ podman-image-prune - Remove all unused images from the local store
|
||||
you can delete all unused images. Unused images are dangling images as well as any image that
|
||||
does not have any containers based on it.
|
||||
|
||||
The image prune command does not prune cache images that only use layers that are necessary for other images.
|
||||
|
||||
## OPTIONS
|
||||
**--all**, **-a**
|
||||
|
||||
|
@ -32,10 +32,10 @@ import (
|
||||
"github.com/containers/libpod/pkg/registries"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/containers/storage"
|
||||
"github.com/opencontainers/go-digest"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -847,6 +847,26 @@ func (i *Image) Dangling() bool {
|
||||
return len(i.Names()) == 0
|
||||
}
|
||||
|
||||
// Intermediate returns true if the image is cache or intermediate image.
|
||||
// Cache image has parent and child.
|
||||
func (i *Image) Intermediate(ctx context.Context) (bool, error) {
|
||||
parent, err := i.IsParent(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !parent {
|
||||
return false, nil
|
||||
}
|
||||
img, err := i.GetParent(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if img != nil {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Labels returns the image's labels
|
||||
func (i *Image) Labels(ctx context.Context) (map[string]string, error) {
|
||||
imgInspect, err := i.imageInspectInfo(ctx)
|
||||
|
@ -57,7 +57,7 @@ func generatePruneFilterFuncs(filter, filterValue string) (ImageFilter, error) {
|
||||
}
|
||||
|
||||
// GetPruneImages returns a slice of images that have no names/unused
|
||||
func (ir *Runtime) GetPruneImages(all bool, filterFuncs []ImageFilter) ([]*Image, error) {
|
||||
func (ir *Runtime) GetPruneImages(ctx context.Context, all bool, filterFuncs []ImageFilter) ([]*Image, error) {
|
||||
var (
|
||||
pruneImages []*Image
|
||||
)
|
||||
@ -74,10 +74,6 @@ func (ir *Runtime) GetPruneImages(all bool, filterFuncs []ImageFilter) ([]*Image
|
||||
}
|
||||
}
|
||||
|
||||
if len(i.Names()) == 0 {
|
||||
pruneImages = append(pruneImages, i)
|
||||
continue
|
||||
}
|
||||
if all {
|
||||
containers, err := i.Containers()
|
||||
if err != nil {
|
||||
@ -85,8 +81,22 @@ func (ir *Runtime) GetPruneImages(all bool, filterFuncs []ImageFilter) ([]*Image
|
||||
}
|
||||
if len(containers) < 1 {
|
||||
pruneImages = append(pruneImages, i)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
//skip the cache or intermediate images
|
||||
intermediate, err := i.Intermediate(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if intermediate {
|
||||
continue
|
||||
}
|
||||
|
||||
if i.Dangling() {
|
||||
pruneImages = append(pruneImages, i)
|
||||
}
|
||||
}
|
||||
return pruneImages, nil
|
||||
}
|
||||
@ -111,7 +121,7 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
|
||||
filterFuncs = append(filterFuncs, generatedFunc)
|
||||
}
|
||||
|
||||
pruneImages, err := ir.GetPruneImages(all, filterFuncs)
|
||||
pruneImages, err := ir.GetPruneImages(ctx, all, filterFuncs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get images to prune")
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ var _ = Describe("Podman prune", func() {
|
||||
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman image prune none images", func() {
|
||||
It("podman image prune skip cache images", func() {
|
||||
SkipIfRemote()
|
||||
podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
|
||||
|
||||
@ -105,10 +105,35 @@ var _ = Describe("Podman prune", func() {
|
||||
after.WaitWithDefaultTimeout()
|
||||
Expect(none.ExitCode()).To(Equal(0))
|
||||
hasNoneAfter, _ := after.GrepString("<none>")
|
||||
Expect(hasNoneAfter).To(BeFalse())
|
||||
Expect(hasNoneAfter).To(BeTrue())
|
||||
Expect(len(after.OutputToStringArray()) > 1).To(BeTrue())
|
||||
})
|
||||
|
||||
It("podman image prune dangling images", func() {
|
||||
SkipIfRemote()
|
||||
podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
|
||||
podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
|
||||
|
||||
none := podmanTest.Podman([]string{"images", "-a"})
|
||||
none.WaitWithDefaultTimeout()
|
||||
Expect(none.ExitCode()).To(Equal(0))
|
||||
hasNone, result := none.GrepString("<none>")
|
||||
Expect(len(result)).To(Equal(2))
|
||||
Expect(hasNone).To(BeTrue())
|
||||
|
||||
prune := podmanTest.Podman([]string{"image", "prune", "-f"})
|
||||
prune.WaitWithDefaultTimeout()
|
||||
Expect(prune.ExitCode()).To(Equal(0))
|
||||
|
||||
after := podmanTest.Podman([]string{"images", "-a"})
|
||||
after.WaitWithDefaultTimeout()
|
||||
Expect(none.ExitCode()).To(Equal(0))
|
||||
hasNoneAfter, result := none.GrepString("<none>")
|
||||
Expect(hasNoneAfter).To(BeTrue())
|
||||
Expect(len(after.OutputToStringArray()) > 1).To(BeTrue())
|
||||
Expect(len(result) > 0).To(BeTrue())
|
||||
})
|
||||
|
||||
It("podman image prune unused images", func() {
|
||||
podmanTest.RestoreAllArtifacts()
|
||||
prune := podmanTest.PodmanNoCache([]string{"image", "prune", "-af"})
|
||||
|
Reference in New Issue
Block a user