mirror of
https://github.com/containers/podman.git
synced 2025-07-04 10:10:32 +08:00
filter added to image pruge command.
filter option accepts two filters. - label - until label supports "label=value" or "label=key=value" format until supports all golang compatible time/duration formats. Signed-off-by: Kunal Kushwaha <kunal.kushwaha@gmail.com>
This commit is contained in:
4
API.md
4
API.md
@ -95,7 +95,7 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
|
||||
|
||||
[func ImageSave(options: ImageSaveOptions) MoreResponse](#ImageSave)
|
||||
|
||||
[func ImagesPrune(all: bool) []string](#ImagesPrune)
|
||||
[func ImagesPrune(all: bool, filter: []string) []string](#ImagesPrune)
|
||||
|
||||
[func ImportImage(source: string, reference: string, message: string, changes: []string, delete: bool) string](#ImportImage)
|
||||
|
||||
@ -766,7 +766,7 @@ ImageSave allows you to save an image from the local image storage to a tarball
|
||||
### <a name="ImagesPrune"></a>func ImagesPrune
|
||||
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
|
||||
|
||||
method ImagesPrune(all: [bool](https://godoc.org/builtin#bool)) [[]string](#[]string)</div>
|
||||
method ImagesPrune(all: [bool](https://godoc.org/builtin#bool), filter: [[]string](#[]string)) [[]string](#[]string)</div>
|
||||
ImagesPrune removes all unused images from the local store. Upon successful pruning,
|
||||
the IDs of the removed images are returned.
|
||||
### <a name="ImportImage"></a>func ImportImage
|
||||
|
@ -175,8 +175,9 @@ type HistoryValues struct {
|
||||
}
|
||||
type PruneImagesValues struct {
|
||||
PodmanCommand
|
||||
All bool
|
||||
Force bool
|
||||
All bool
|
||||
Force bool
|
||||
Filter []string
|
||||
}
|
||||
|
||||
type PruneContainersValues struct {
|
||||
|
@ -38,6 +38,7 @@ func init() {
|
||||
flags := pruneImagesCommand.Flags()
|
||||
flags.BoolVarP(&pruneImagesCommand.All, "all", "a", false, "Remove all unused images, not just dangling ones")
|
||||
flags.BoolVarP(&pruneImagesCommand.Force, "force", "f", false, "Do not prompt for confirmation")
|
||||
flags.StringArrayVar(&pruneImagesCommand.Filter, "filter", []string{}, "Provide filter values (e.g. 'label=<key>=<value>')")
|
||||
}
|
||||
|
||||
func pruneImagesCmd(c *cliconfig.PruneImagesValues) error {
|
||||
@ -62,7 +63,7 @@ Are you sure you want to continue? [y/N] `)
|
||||
|
||||
// Call prune; if any cids are returned, print them and then
|
||||
// return err in case an error also came up
|
||||
pruneCids, err := runtime.PruneImages(getContext(), c.All)
|
||||
pruneCids, err := runtime.PruneImages(getContext(), c.All, c.Filter)
|
||||
if len(pruneCids) > 0 {
|
||||
for _, cid := range pruneCids {
|
||||
fmt.Println(cid)
|
||||
|
@ -117,7 +117,8 @@ Are you sure you want to continue? [y/N] `, volumeString)
|
||||
|
||||
// Call prune; if any cids are returned, print them and then
|
||||
// return err in case an error also came up
|
||||
pruneCids, err := runtime.PruneImages(ctx, c.All)
|
||||
// TODO: support for filters in system prune
|
||||
pruneCids, err := runtime.PruneImages(ctx, c.All, []string{})
|
||||
if len(pruneCids) > 0 {
|
||||
fmt.Println("Deleted Images")
|
||||
for _, cid := range pruneCids {
|
||||
|
@ -1217,7 +1217,7 @@ method UnmountContainer(name: string, force: bool) -> ()
|
||||
|
||||
# ImagesPrune removes all unused images from the local store. Upon successful pruning,
|
||||
# the IDs of the removed images are returned.
|
||||
method ImagesPrune(all: bool) -> (pruned: []string)
|
||||
method ImagesPrune(all: bool, filter: []string) -> (pruned: []string)
|
||||
|
||||
# This function is not implemented yet.
|
||||
# method ListContainerPorts(name: string) -> (notimplemented: NotImplemented)
|
||||
|
@ -74,6 +74,11 @@ type InfoImage struct {
|
||||
Layers []LayerInfo
|
||||
}
|
||||
|
||||
// ImageFilter is a function to determine whether a image is included
|
||||
// in command output. Images to be outputted are tested using the function.
|
||||
// A true return will include the image, a false return will exclude it.
|
||||
type ImageFilter func(*Image) bool //nolint
|
||||
|
||||
// ErrRepoTagNotFound is the error returned when the image id given doesn't match a rep tag in store
|
||||
var ErrRepoTagNotFound = stderrors.New("unable to match user input to any specific repotag")
|
||||
|
||||
|
@ -2,23 +2,78 @@ package image
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/libpod/libpod/events"
|
||||
"github.com/containers/libpod/pkg/timetype"
|
||||
"github.com/containers/storage"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func generatePruneFilterFuncs(filter, filterValue string) (ImageFilter, error) {
|
||||
switch filter {
|
||||
case "label":
|
||||
var filterArray = strings.SplitN(filterValue, "=", 2)
|
||||
var filterKey = filterArray[0]
|
||||
if len(filterArray) > 1 {
|
||||
filterValue = filterArray[1]
|
||||
} else {
|
||||
filterValue = ""
|
||||
}
|
||||
return func(i *Image) bool {
|
||||
labels, err := i.Labels(context.Background())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for labelKey, labelValue := range labels {
|
||||
if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}, nil
|
||||
|
||||
case "until":
|
||||
ts, err := timetype.GetTimestamp(filterValue, time.Now())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
until := time.Unix(seconds, nanoseconds)
|
||||
return func(i *Image) bool {
|
||||
if !until.IsZero() && i.Created().After((until)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}, nil
|
||||
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetPruneImages returns a slice of images that have no names/unused
|
||||
func (ir *Runtime) GetPruneImages(all bool) ([]*Image, error) {
|
||||
func (ir *Runtime) GetPruneImages(all bool, filterFuncs []ImageFilter) ([]*Image, error) {
|
||||
var (
|
||||
pruneImages []*Image
|
||||
)
|
||||
|
||||
allImages, err := ir.GetRWImages()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, i := range allImages {
|
||||
// filter the images based on this.
|
||||
for _, filterFunc := range filterFuncs {
|
||||
if !filterFunc(i) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if len(i.Names()) == 0 {
|
||||
pruneImages = append(pruneImages, i)
|
||||
continue
|
||||
@ -38,9 +93,25 @@ func (ir *Runtime) GetPruneImages(all bool) ([]*Image, error) {
|
||||
|
||||
// PruneImages prunes dangling and optionally all unused images from the local
|
||||
// image store
|
||||
func (ir *Runtime) PruneImages(ctx context.Context, all bool) ([]string, error) {
|
||||
var prunedCids []string
|
||||
pruneImages, err := ir.GetPruneImages(all)
|
||||
func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) ([]string, error) {
|
||||
var (
|
||||
prunedCids []string
|
||||
filterFuncs []ImageFilter
|
||||
)
|
||||
for _, f := range filter {
|
||||
filterSplit := strings.SplitN(f, "=", 2)
|
||||
if len(filterSplit) < 2 {
|
||||
return nil, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
|
||||
}
|
||||
|
||||
generatedFunc, err := generatePruneFilterFuncs(filterSplit[0], filterSplit[1])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "invalid filter")
|
||||
}
|
||||
filterFuncs = append(filterFuncs, generatedFunc)
|
||||
}
|
||||
|
||||
pruneImages, err := ir.GetPruneImages(all, filterFuncs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get images to prune")
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import (
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// LocalRuntime describes a typical libpod runtime
|
||||
@ -147,8 +147,8 @@ func (r *LocalRuntime) RemoveImage(ctx context.Context, img *ContainerImage, for
|
||||
}
|
||||
|
||||
// PruneImages is wrapper into PruneImages within the image pkg
|
||||
func (r *LocalRuntime) PruneImages(ctx context.Context, all bool) ([]string, error) {
|
||||
return r.ImageRuntime().PruneImages(ctx, all)
|
||||
func (r *LocalRuntime) PruneImages(ctx context.Context, all bool, filter []string) ([]string, error) {
|
||||
return r.ImageRuntime().PruneImages(ctx, all, filter)
|
||||
}
|
||||
|
||||
// Export is a wrapper to container export to a tarfile
|
||||
|
@ -415,8 +415,8 @@ func (ci *ContainerImage) History(ctx context.Context) ([]*image.History, error)
|
||||
}
|
||||
|
||||
// PruneImages is the wrapper call for a remote-client to prune images
|
||||
func (r *LocalRuntime) PruneImages(ctx context.Context, all bool) ([]string, error) {
|
||||
return iopodman.ImagesPrune().Call(r.Conn, all)
|
||||
func (r *LocalRuntime) PruneImages(ctx context.Context, all bool, filter []string) ([]string, error) {
|
||||
return iopodman.ImagesPrune().Call(r.Conn, all, filter)
|
||||
}
|
||||
|
||||
// Export is a wrapper to container export to a tarfile
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
"github.com/containers/image/v5/transports/alltransports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/libpod/cmd/podman/shared"
|
||||
"github.com/containers/libpod/cmd/podman/varlink"
|
||||
iopodman "github.com/containers/libpod/cmd/podman/varlink"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/libpod/define"
|
||||
"github.com/containers/libpod/libpod/image"
|
||||
@ -29,7 +29,7 @@ import (
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/containers/libpod/utils"
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -740,8 +740,8 @@ func (i *LibpodAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman.
|
||||
}
|
||||
|
||||
// ImagesPrune ....
|
||||
func (i *LibpodAPI) ImagesPrune(call iopodman.VarlinkCall, all bool) error {
|
||||
prunedImages, err := i.Runtime.ImageRuntime().PruneImages(context.TODO(), all)
|
||||
func (i *LibpodAPI) ImagesPrune(call iopodman.VarlinkCall, all bool, filter []string) error {
|
||||
prunedImages, err := i.Runtime.ImageRuntime().PruneImages(context.TODO(), all, []string{})
|
||||
if err != nil {
|
||||
return call.ReplyErrorOccurred(err.Error())
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ var _ = Describe("Podman prune", func() {
|
||||
hasNone, _ := none.GrepString("<none>")
|
||||
Expect(hasNone).To(BeTrue())
|
||||
|
||||
prune := podmanTest.Podman([]string{"image", "prune"})
|
||||
prune := podmanTest.Podman([]string{"image", "prune", "-f"})
|
||||
prune.WaitWithDefaultTimeout()
|
||||
Expect(prune.ExitCode()).To(Equal(0))
|
||||
|
||||
@ -78,7 +78,7 @@ var _ = Describe("Podman prune", func() {
|
||||
|
||||
It("podman image prune unused images", func() {
|
||||
podmanTest.RestoreAllArtifacts()
|
||||
prune := podmanTest.PodmanNoCache([]string{"image", "prune", "-a"})
|
||||
prune := podmanTest.PodmanNoCache([]string{"image", "prune", "-af"})
|
||||
prune.WaitWithDefaultTimeout()
|
||||
Expect(prune.ExitCode()).To(Equal(0))
|
||||
|
||||
|
Reference in New Issue
Block a user