Skip to content

Commit

Permalink
Merge pull request #4664 from baude/movefilters
Browse files Browse the repository at this point in the history
move image filters under libpod/images
  • Loading branch information
openshift-merge-robot authored Dec 11, 2019
2 parents 668d77a + 8be7b46 commit dd64038
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 95 deletions.
9 changes: 9 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in

[func ListImages() Image](#ListImages)

[func ListImagesWithFilters(filters: []string) Image](#ListImagesWithFilters)

[func ListPods() ListPodData](#ListPods)

[func LoadImage(name: string, inputFile: string, quiet: bool, deleteFile: bool) MoreResponse](#LoadImage)
Expand Down Expand Up @@ -892,6 +894,13 @@ See also [GetContainer](#GetContainer).
method ListImages() [Image](#Image)</div>
ListImages returns information about the images that are currently in storage.
See also [InspectImage](#InspectImage).
### <a name="ListImagesWithFilters"></a>func ListImagesWithFilters
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">

method ListImagesWithFilters(filters: [[]string](#[]string)) [Image](#Image)</div>
ListImagesWithFilters returns information about the images that are currently in storage
after one or more filters has been applied.
See also [InspectImage](#InspectImage).
### <a name="ListPods"></a>func ListPods
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">

Expand Down
81 changes: 7 additions & 74 deletions cmd/podman/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ import (
"fmt"
"reflect"
"sort"
"strconv"
"strings"
"time"
"unicode"

"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/imagefilters"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/adapter"
"github.com/docker/go-units"
Expand Down Expand Up @@ -138,10 +136,10 @@ func init() {

func imagesCmd(c *cliconfig.ImagesValues) error {
var (
filterFuncs []imagefilters.ResultFilter
image string
image string
)

ctx := getContext()
runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "Could not get runtime")
Expand All @@ -156,15 +154,9 @@ func imagesCmd(c *cliconfig.ImagesValues) error {
if len(c.Filter) > 0 && image != "" {
return errors.New("can not specify an image and a filter")
}
ctx := getContext()

if len(c.Filter) > 0 {
filterFuncs, err = CreateFilterFuncs(ctx, runtime, c.Filter, nil)
} else {
filterFuncs, err = CreateFilterFuncs(ctx, runtime, []string{fmt.Sprintf("reference=%s", image)}, nil)
}
if err != nil {
return err
filters := c.Filter
if len(filters) < 1 {
filters = append(filters, fmt.Sprintf("reference=%s", image))
}

opts := imagesOptions{
Expand All @@ -179,26 +171,17 @@ func imagesCmd(c *cliconfig.ImagesValues) error {
}

opts.outputformat = opts.setOutputFormat()
images, err := runtime.GetImages()
filteredImages, err := runtime.GetFilteredImages(filters, false)
if err != nil {
return errors.Wrapf(err, "unable to get images")
}

for _, image := range images {
for _, image := range filteredImages {
if image.IsReadOnly() {
opts.outputformat += "{{.ReadOnly}}\t"
break
}
}

var filteredImages []*adapter.ContainerImage
//filter the images
if len(c.Filter) > 0 || len(c.InputArgs) == 1 {
filteredImages = imagefilters.FilterImages(images, filterFuncs)
} else {
filteredImages = images
}

return generateImagesOutput(ctx, filteredImages, opts)
}

Expand Down Expand Up @@ -392,53 +375,3 @@ func GenImageOutputMap() map[string]string {
}
return values
}

// CreateFilterFuncs returns an array of filter functions based on the user inputs
// and is later used to filter images for output
func CreateFilterFuncs(ctx context.Context, r *adapter.LocalRuntime, filters []string, img *adapter.ContainerImage) ([]imagefilters.ResultFilter, error) {
var filterFuncs []imagefilters.ResultFilter
for _, filter := range filters {
splitFilter := strings.Split(filter, "=")
if len(splitFilter) < 2 {
return nil, errors.Errorf("invalid filter syntax %s", filter)
}
switch splitFilter[0] {
case "before":
before, err := r.NewImageFromLocal(splitFilter[1])
if err != nil {
return nil, errors.Wrapf(err, "unable to find image %s in local stores", splitFilter[1])
}
filterFuncs = append(filterFuncs, imagefilters.CreatedBeforeFilter(before.Created()))
case "after":
after, err := r.NewImageFromLocal(splitFilter[1])
if err != nil {
return nil, errors.Wrapf(err, "unable to find image %s in local stores", splitFilter[1])
}
filterFuncs = append(filterFuncs, imagefilters.CreatedAfterFilter(after.Created()))
case "readonly":
readonly, err := strconv.ParseBool(splitFilter[1])
if err != nil {
return nil, errors.Wrapf(err, "invalid filter readonly=%s", splitFilter[1])
}
filterFuncs = append(filterFuncs, imagefilters.ReadOnlyFilter(readonly))
case "dangling":
danglingImages, err := strconv.ParseBool(splitFilter[1])
if err != nil {
return nil, errors.Wrapf(err, "invalid filter dangling=%s", splitFilter[1])
}
filterFuncs = append(filterFuncs, imagefilters.DanglingFilter(danglingImages))
case "label":
labelFilter := strings.Join(splitFilter[1:], "=")
filterFuncs = append(filterFuncs, imagefilters.LabelFilter(ctx, labelFilter))
case "reference":
referenceFilter := strings.Join(splitFilter[1:], "=")
filterFuncs = append(filterFuncs, imagefilters.ReferenceFilter(ctx, referenceFilter))
default:
return nil, errors.Errorf("invalid filter %s ", splitFilter[0])
}
}
if img != nil {
filterFuncs = append(filterFuncs, imagefilters.OutputImageFilter(img))
}
return filterFuncs, nil
}
5 changes: 5 additions & 0 deletions cmd/podman/varlink/io.podman.varlink
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,11 @@ method DeleteStoppedContainers() -> (containers: []string)
# See also [InspectImage](#InspectImage).
method ListImages() -> (images: []Image)

# ListImagesWithFilters returns information about the images that are currently in storage
# after one or more filters has been applied.
# See also [InspectImage](#InspectImage).
method ListImagesWithFilters(filters: []string) -> (images: []Image)

# GetImage returns information about a single image in storage.
# If the image caGetImage returns be found, [ImageNotFound](#ImageNotFound) will be returned.
method GetImage(id: string) -> (image: Image)
Expand Down
83 changes: 69 additions & 14 deletions cmd/podman/imagefilters/filters.go → libpod/image/filters.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,45 @@
package imagefilters
package image

import (
"context"
"fmt"
"github.com/pkg/errors"
"path/filepath"
"strconv"
"strings"
"time"

"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/inspect"
"github.com/sirupsen/logrus"
)

// ResultFilter is a mock function for image filtering
type ResultFilter func(*adapter.ContainerImage) bool
type ResultFilter func(*Image) bool

// Filter is a function to determine whether an 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 Filter func(*adapter.ContainerImage, *inspect.ImageData) bool
type Filter func(*Image, *inspect.ImageData) bool

// CreatedBeforeFilter allows you to filter on images created before
// the given time.Time
func CreatedBeforeFilter(createTime time.Time) ResultFilter {
return func(i *adapter.ContainerImage) bool {
return func(i *Image) bool {
return i.Created().Before(createTime)
}
}

// CreatedAfterFilter allows you to filter on images created after
// the given time.Time
func CreatedAfterFilter(createTime time.Time) ResultFilter {
return func(i *adapter.ContainerImage) bool {
return func(i *Image) bool {
return i.Created().After(createTime)
}
}

// DanglingFilter allows you to filter images for dangling images
func DanglingFilter(danglingImages bool) ResultFilter {
return func(i *adapter.ContainerImage) bool {
return func(i *Image) bool {
if danglingImages {
return i.Dangling()
}
Expand All @@ -48,7 +49,7 @@ func DanglingFilter(danglingImages bool) ResultFilter {

// ReadOnlyFilter allows you to filter images based on read/only and read/write
func ReadOnlyFilter(readOnly bool) ResultFilter {
return func(i *adapter.ContainerImage) bool {
return func(i *Image) bool {
if readOnly {
return i.IsReadOnly()
}
Expand All @@ -59,7 +60,7 @@ func ReadOnlyFilter(readOnly bool) ResultFilter {
// LabelFilter allows you to filter by images labels key and/or value
func LabelFilter(ctx context.Context, labelfilter string) ResultFilter {
// We need to handle both label=key and label=key=value
return func(i *adapter.ContainerImage) bool {
return func(i *Image) bool {
var value string
splitFilter := strings.Split(labelfilter, "=")
key := splitFilter[0]
Expand All @@ -83,7 +84,10 @@ func LabelFilter(ctx context.Context, labelfilter string) ResultFilter {
func ReferenceFilter(ctx context.Context, referenceFilter string) ResultFilter {
filter := fmt.Sprintf("*%s*", referenceFilter)
filter = strings.Replace(filter, "/", "|", -1)
return func(i *adapter.ContainerImage) bool {
return func(i *Image) bool {
if len(referenceFilter) < 1 {
return true
}
for _, name := range i.Names() {
newName := strings.Replace(name, "/", "|", -1)
match, err := filepath.Match(filter, newName)
Expand All @@ -99,15 +103,15 @@ func ReferenceFilter(ctx context.Context, referenceFilter string) ResultFilter {
}

// OutputImageFilter allows you to filter by an a specific image name
func OutputImageFilter(userImage *adapter.ContainerImage) ResultFilter {
return func(i *adapter.ContainerImage) bool {
func OutputImageFilter(userImage *Image) ResultFilter {
return func(i *Image) bool {
return userImage.ID() == i.ID()
}
}

// FilterImages filters images using a set of predefined filter funcs
func FilterImages(images []*adapter.ContainerImage, filters []ResultFilter) []*adapter.ContainerImage {
var filteredImages []*adapter.ContainerImage
func FilterImages(images []*Image, filters []ResultFilter) []*Image {
var filteredImages []*Image
for _, image := range images {
include := true
for _, filter := range filters {
Expand All @@ -119,3 +123,54 @@ func FilterImages(images []*adapter.ContainerImage, filters []ResultFilter) []*a
}
return filteredImages
}

// createFilterFuncs returns an array of filter functions based on the user inputs
// and is later used to filter images for output
func (ir *Runtime) createFilterFuncs(filters []string, img *Image) ([]ResultFilter, error) {
var filterFuncs []ResultFilter
ctx := context.Background()
for _, filter := range filters {
splitFilter := strings.Split(filter, "=")
if len(splitFilter) < 2 {
return nil, errors.Errorf("invalid filter syntax %s", filter)
}
switch splitFilter[0] {
case "before":
before, err := ir.NewFromLocal(splitFilter[1])
if err != nil {
return nil, errors.Wrapf(err, "unable to find image %s in local stores", splitFilter[1])
}
filterFuncs = append(filterFuncs, CreatedBeforeFilter(before.Created()))
case "after":
after, err := ir.NewFromLocal(splitFilter[1])
if err != nil {
return nil, errors.Wrapf(err, "unable to find image %s in local stores", splitFilter[1])
}
filterFuncs = append(filterFuncs, CreatedAfterFilter(after.Created()))
case "readonly":
readonly, err := strconv.ParseBool(splitFilter[1])
if err != nil {
return nil, errors.Wrapf(err, "invalid filter readonly=%s", splitFilter[1])
}
filterFuncs = append(filterFuncs, ReadOnlyFilter(readonly))
case "dangling":
danglingImages, err := strconv.ParseBool(splitFilter[1])
if err != nil {
return nil, errors.Wrapf(err, "invalid filter dangling=%s", splitFilter[1])
}
filterFuncs = append(filterFuncs, DanglingFilter(danglingImages))
case "label":
labelFilter := strings.Join(splitFilter[1:], "=")
filterFuncs = append(filterFuncs, LabelFilter(ctx, labelFilter))
case "reference":
referenceFilter := strings.Join(splitFilter[1:], "=")
filterFuncs = append(filterFuncs, ReferenceFilter(ctx, referenceFilter))
default:
return nil, errors.Errorf("invalid filter %s ", splitFilter[0])
}
}
if img != nil {
filterFuncs = append(filterFuncs, OutputImageFilter(img))
}
return filterFuncs, nil
}
13 changes: 13 additions & 0 deletions libpod/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,19 @@ func (ir *Runtime) Shutdown(force bool) error {
return err
}

// GetImagesWithFilters gets images with a series of filters applied
func (ir *Runtime) GetImagesWithFilters(filters []string) ([]*Image, error) {
filterFuncs, err := ir.createFilterFuncs(filters, nil)
if err != nil {
return nil, err
}
images, err := ir.GetImages()
if err != nil {
return nil, err
}
return FilterImages(images, filterFuncs), nil
}

func (i *Image) reloadImage() error {
newImage, err := i.imageruntime.getImage(i.ID())
if err != nil {
Expand Down
15 changes: 14 additions & 1 deletion pkg/adapter/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ func getRuntime(runtime *libpod.Runtime) (*LocalRuntime, error) {
}, nil
}

// GetFilterImages returns a slice of images in containerimages that are "filtered"
func (r *LocalRuntime) GetFilteredImages(filters []string, rwOnly bool) ([]*ContainerImage, error) {
images, err := r.ImageRuntime().GetImagesWithFilters(filters)
if err != nil {
return nil, err
}
return r.ImagestoContainerImages(images, rwOnly)
}

// GetImages returns a slice of images in containerimages
func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) {
return r.getImages(false)
Expand All @@ -95,11 +104,15 @@ func (r *LocalRuntime) GetRWImages() ([]*ContainerImage, error) {
}

func (r *LocalRuntime) getImages(rwOnly bool) ([]*ContainerImage, error) {
var containerImages []*ContainerImage
images, err := r.Runtime.ImageRuntime().GetImages()
if err != nil {
return nil, err
}
return r.ImagestoContainerImages(images, rwOnly)
}

func (r *LocalRuntime) ImagestoContainerImages(images []*image.Image, rwOnly bool) ([]*ContainerImage, error) {
var containerImages []*ContainerImage
for _, i := range images {
if rwOnly && i.IsReadOnly() {
continue
Expand Down
Loading

0 comments on commit dd64038

Please sign in to comment.