aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xAPI.md9
-rw-r--r--cmd/podman/images.go81
-rw-r--r--cmd/podman/varlink/io.podman.varlink5
-rw-r--r--libpod/image/filters.go (renamed from cmd/podman/imagefilters/filters.go)83
-rw-r--r--libpod/image/image.go13
-rw-r--r--pkg/adapter/runtime.go15
-rw-r--r--pkg/adapter/runtime_remote.go22
-rw-r--r--pkg/varlinkapi/images.go34
8 files changed, 167 insertions, 95 deletions
diff --git a/API.md b/API.md
index 3a66db83b..695f374d8 100755
--- a/API.md
+++ b/API.md
@@ -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)
@@ -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;">
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 6b16272f4..e42546a55 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -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"
@@ -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")
@@ -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{
@@ -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)
}
@@ -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
-}
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index a3fd27ed6..2251050c3 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -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)
diff --git a/cmd/podman/imagefilters/filters.go b/libpod/image/filters.go
index 0b08314ce..d545f1bfc 100644
--- a/cmd/podman/imagefilters/filters.go
+++ b/libpod/image/filters.go
@@ -1,29 +1,30 @@
-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)
}
}
@@ -31,14 +32,14 @@ func CreatedBeforeFilter(createTime time.Time) ResultFilter {
// 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()
}
@@ -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()
}
@@ -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]
@@ -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)
@@ -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 {
@@ -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
+}
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 129ccd376..c8583a1c5 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -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 {
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index 069283bde..ac843b655 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -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)
@@ -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
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index f9232897c..87b4999ce 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -200,6 +200,28 @@ func (r *LocalRuntime) GetRWImages() ([]*ContainerImage, error) {
return r.getImages(true)
}
+func (r *LocalRuntime) GetFilteredImages(filters []string, rwOnly bool) ([]*ContainerImage, error) {
+ var newImages []*ContainerImage
+ images, err := iopodman.ListImagesWithFilters().Call(r.Conn, filters)
+ if err != nil {
+ return nil, err
+ }
+ for _, i := range images {
+ if rwOnly && i.ReadOnly {
+ continue
+ }
+ name := i.Id
+ if len(i.RepoTags) > 1 {
+ name = i.RepoTags[0]
+ }
+ newImage, err := imageInListToContainerImage(i, name, r)
+ if err != nil {
+ return nil, err
+ }
+ newImages = append(newImages, newImage)
+ }
+ return newImages, nil
+}
func (r *LocalRuntime) getImages(rwOnly bool) ([]*ContainerImage, error) {
var newImages []*ContainerImage
images, err := iopodman.ListImages().Call(r.Conn)
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index 604a455a5..1d46c5b71 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -35,26 +35,34 @@ import (
"github.com/sirupsen/logrus"
)
-// ListImages lists all the images in the store
-// It requires no inputs.
-func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
- images, err := i.Runtime.ImageRuntime().GetImages()
+// ListImagesWithFilters returns a list of images that have been filtered
+func (i *LibpodAPI) ListImagesWithFilters(call iopodman.VarlinkCall, filters []string) error {
+ images, err := i.Runtime.ImageRuntime().GetImagesWithFilters(filters)
if err != nil {
return call.ReplyErrorOccurred(fmt.Sprintf("unable to get list of images %q", err))
}
+ imageList, err := imagesToImageList(images)
+ if err != nil {
+ return call.ReplyErrorOccurred(fmt.Sprintf("unable to parse response", err))
+ }
+ return call.ReplyListImagesWithFilters(imageList)
+}
+
+// imagesToImageList converts a slice of Images to an imagelist for varlink responses
+func imagesToImageList(images []*image.Image) ([]iopodman.Image, error) {
var imageList []iopodman.Image
for _, image := range images {
labels, _ := image.Labels(getContext())
containers, _ := image.Containers()
repoDigests, err := image.RepoDigests()
if err != nil {
- return err
+ return nil, err
}
size, _ := image.Size(getContext())
isParent, err := image.IsParent(context.TODO())
if err != nil {
- return call.ReplyErrorOccurred(err.Error())
+ return nil, err
}
i := iopodman.Image{
@@ -74,6 +82,20 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
}
imageList = append(imageList, i)
}
+ return imageList, nil
+}
+
+// ListImages lists all the images in the store
+// It requires no inputs.
+func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
+ images, err := i.Runtime.ImageRuntime().GetImages()
+ if err != nil {
+ return call.ReplyErrorOccurred(fmt.Sprintf("unable to get list of images %q", err))
+ }
+ imageList, err := imagesToImageList(images)
+ if err != nil {
+ return call.ReplyErrorOccurred(fmt.Sprintf("unable to parse response", err))
+ }
return call.ReplyListImages(imageList)
}