diff options
-rw-r--r-- | cmd/podman/imagefilters/filters.go (renamed from libpod/image/filters.go) | 23 | ||||
-rw-r--r-- | cmd/podman/images.go | 56 | ||||
-rw-r--r-- | cmd/podman/varlink/io.podman.varlink | 3 | ||||
-rw-r--r-- | libpod/adapter/images_remote.go | 17 | ||||
-rw-r--r-- | libpod/adapter/runtime.go | 29 | ||||
-rw-r--r-- | libpod/adapter/runtime_remote.go | 151 | ||||
-rw-r--r-- | libpod/image/image.go | 6 | ||||
-rw-r--r-- | libpod/image/parts.go | 36 | ||||
-rw-r--r-- | libpod/image/parts_test.go | 4 | ||||
-rw-r--r-- | libpod/image/pull.go | 4 | ||||
-rw-r--r-- | libpod/image/utils.go | 6 | ||||
-rw-r--r-- | pkg/varlinkapi/images.go | 5 |
12 files changed, 273 insertions, 67 deletions
diff --git a/libpod/image/filters.go b/cmd/podman/imagefilters/filters.go index d0c3adfb5..366510202 100644 --- a/libpod/image/filters.go +++ b/cmd/podman/imagefilters/filters.go @@ -1,25 +1,26 @@ -package image +package imagefilters import ( "context" "strings" "time" + "github.com/containers/libpod/libpod/adapter" "github.com/containers/libpod/pkg/inspect" ) // ResultFilter is a mock function for image filtering -type ResultFilter func(*Image) bool +type ResultFilter func(*adapter.ContainerImage) 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(*Image, *inspect.ImageData) bool +type Filter func(*adapter.ContainerImage, *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 *Image) bool { + return func(i *adapter.ContainerImage) bool { return i.Created().Before(createTime) } } @@ -27,14 +28,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 *Image) bool { + return func(i *adapter.ContainerImage) bool { return i.Created().After(createTime) } } // DanglingFilter allows you to filter images for dangling images func DanglingFilter() ResultFilter { - return func(i *Image) bool { + return func(i *adapter.ContainerImage) bool { return i.Dangling() } } @@ -42,7 +43,7 @@ func DanglingFilter() 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 *Image) bool { + return func(i *adapter.ContainerImage) bool { var value string splitFilter := strings.Split(labelfilter, "=") key := splitFilter[0] @@ -61,15 +62,15 @@ func LabelFilter(ctx context.Context, labelfilter string) ResultFilter { } // OutputImageFilter allows you to filter by an a specific image name -func OutputImageFilter(userImage *Image) ResultFilter { - return func(i *Image) bool { +func OutputImageFilter(userImage *adapter.ContainerImage) ResultFilter { + return func(i *adapter.ContainerImage) bool { return userImage.ID() == i.ID() } } // FilterImages filters images using a set of predefined filter funcs -func FilterImages(images []*Image, filters []ResultFilter) []*Image { - var filteredImages []*Image +func FilterImages(images []*adapter.ContainerImage, filters []ResultFilter) []*adapter.ContainerImage { + var filteredImages []*adapter.ContainerImage for _, image := range images { include := true for _, filter := range filters { diff --git a/cmd/podman/images.go b/cmd/podman/images.go index 522863b1b..8b8ce78bd 100644 --- a/cmd/podman/images.go +++ b/cmd/podman/images.go @@ -2,6 +2,8 @@ package main import ( "context" + "github.com/containers/libpod/cmd/podman/imagefilters" + "github.com/containers/libpod/libpod/adapter" "reflect" "sort" "strings" @@ -9,11 +11,9 @@ import ( "unicode" "github.com/containers/libpod/cmd/podman/formats" - "github.com/containers/libpod/cmd/podman/libpodruntime" - "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/image" "github.com/docker/go-units" - digest "github.com/opencontainers/go-digest" + "github.com/opencontainers/go-digest" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -145,20 +145,20 @@ var ( func imagesCmd(c *cli.Context) error { var ( - filterFuncs []image.ResultFilter - newImage *image.Image + filterFuncs []imagefilters.ResultFilter + newImage *adapter.ContainerImage ) if err := validateFlags(c, imagesFlags); err != nil { return err } - runtime, err := libpodruntime.GetRuntime(c) + localRuntime, err := adapter.GetRuntime(c) if err != nil { return errors.Wrapf(err, "Could not get runtime") } - defer runtime.Shutdown(false) + defer localRuntime.Runtime.Shutdown(false) if len(c.Args()) == 1 { - newImage, err = runtime.ImageRuntime().NewFromLocal(c.Args().Get(0)) + newImage, err = localRuntime.NewImageFromLocal(c.Args().Get(0)) if err != nil { return err } @@ -171,7 +171,7 @@ func imagesCmd(c *cli.Context) error { ctx := getContext() if len(c.StringSlice("filter")) > 0 || newImage != nil { - filterFuncs, err = CreateFilterFuncs(ctx, runtime, c, newImage) + filterFuncs, err = CreateFilterFuncs(ctx, localRuntime, c, newImage) if err != nil { return err } @@ -195,20 +195,20 @@ func imagesCmd(c *cli.Context) error { children to the image once built. until buildah supports caching builds, it will not generate these intermediate images. */ - images, err := runtime.ImageRuntime().GetImages() + images, err := localRuntime.GetImages() if err != nil { return errors.Wrapf(err, "unable to get images") } - var filteredImages []*image.Image - // filter the images + var filteredImages []*adapter.ContainerImage + //filter the images if len(c.StringSlice("filter")) > 0 || newImage != nil { - filteredImages = image.FilterImages(images, filterFuncs) + filteredImages = imagefilters.FilterImages(images, filterFuncs) } else { filteredImages = images } - return generateImagesOutput(ctx, runtime, filteredImages, opts) + return generateImagesOutput(ctx, filteredImages, opts) } func (i imagesOptions) setOutputFormat() string { @@ -263,7 +263,7 @@ func sortImagesOutput(sortBy string, imagesOutput imagesSorted) imagesSorted { } // getImagesTemplateOutput returns the images information to be printed in human readable format -func getImagesTemplateOutput(ctx context.Context, runtime *libpod.Runtime, images []*image.Image, opts imagesOptions) (imagesOutput imagesSorted) { +func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerImage, opts imagesOptions) (imagesOutput imagesSorted) { for _, img := range images { // If all is false and the image doesn't have a name, check to see if the top layer of the image is a parent // to another image's top layer. If it is, then it is an intermediate image so don't print out if the --all flag @@ -319,7 +319,7 @@ func getImagesTemplateOutput(ctx context.Context, runtime *libpod.Runtime, image } // getImagesJSONOutput returns the images information in its raw form -func getImagesJSONOutput(ctx context.Context, runtime *libpod.Runtime, images []*image.Image) (imagesOutput []imagesJSONParams) { +func getImagesJSONOutput(ctx context.Context, images []*adapter.ContainerImage) (imagesOutput []imagesJSONParams) { for _, img := range images { size, err := img.Size(ctx) if err != nil { @@ -339,7 +339,7 @@ func getImagesJSONOutput(ctx context.Context, runtime *libpod.Runtime, images [] // generateImagesOutput generates the images based on the format provided -func generateImagesOutput(ctx context.Context, runtime *libpod.Runtime, images []*image.Image, opts imagesOptions) error { +func generateImagesOutput(ctx context.Context, images []*adapter.ContainerImage, opts imagesOptions) error { if len(images) == 0 { return nil } @@ -347,10 +347,10 @@ func generateImagesOutput(ctx context.Context, runtime *libpod.Runtime, images [ switch opts.format { case formats.JSONString: - imagesOutput := getImagesJSONOutput(ctx, runtime, images) + imagesOutput := getImagesJSONOutput(ctx, images) out = formats.JSONStructArray{Output: imagesToGeneric([]imagesTemplateParams{}, imagesOutput)} default: - imagesOutput := getImagesTemplateOutput(ctx, runtime, images, opts) + imagesOutput := getImagesTemplateOutput(ctx, images, opts) out = formats.StdoutTemplateArray{Output: imagesToGeneric(imagesOutput, []imagesJSONParams{}), Template: opts.outputformat, Fields: imagesOutput[0].HeaderMap()} } return formats.Writer(out).Out() @@ -375,34 +375,34 @@ func (i *imagesTemplateParams) HeaderMap() map[string]string { // 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 *libpod.Runtime, c *cli.Context, img *image.Image) ([]image.ResultFilter, error) { - var filterFuncs []image.ResultFilter +func CreateFilterFuncs(ctx context.Context, r *adapter.LocalRuntime, c *cli.Context, img *adapter.ContainerImage) ([]imagefilters.ResultFilter, error) { + var filterFuncs []imagefilters.ResultFilter for _, filter := range c.StringSlice("filter") { splitFilter := strings.Split(filter, "=") switch splitFilter[0] { case "before": - before, err := r.ImageRuntime().NewFromLocal(splitFilter[1]) + 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, image.CreatedBeforeFilter(before.Created())) + filterFuncs = append(filterFuncs, imagefilters.CreatedBeforeFilter(before.Created())) case "after": - after, err := r.ImageRuntime().NewFromLocal(splitFilter[1]) + 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, image.CreatedAfterFilter(after.Created())) + filterFuncs = append(filterFuncs, imagefilters.CreatedAfterFilter(after.Created())) case "dangling": - filterFuncs = append(filterFuncs, image.DanglingFilter()) + filterFuncs = append(filterFuncs, imagefilters.DanglingFilter()) case "label": labelFilter := strings.Join(splitFilter[1:], "=") - filterFuncs = append(filterFuncs, image.LabelFilter(ctx, labelFilter)) + filterFuncs = append(filterFuncs, imagefilters.LabelFilter(ctx, labelFilter)) default: return nil, errors.Errorf("invalid filter %s ", splitFilter[0]) } } if img != nil { - filterFuncs = append(filterFuncs, image.OutputImageFilter(img)) + 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 4e8b69faf..b7972a918 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -37,7 +37,8 @@ type ImageInList ( size: int, virtualSize: int, containers: int, - labels: [string]string + labels: [string]string, + isParent: bool ) # ImageHistory describes the returned structure from ImageHistory. diff --git a/libpod/adapter/images_remote.go b/libpod/adapter/images_remote.go new file mode 100644 index 000000000..77b0629a7 --- /dev/null +++ b/libpod/adapter/images_remote.go @@ -0,0 +1,17 @@ +// +build remoteclient + +package adapter + +import ( + "github.com/containers/libpod/libpod" +) + +// Images returns information for the host system and its components +func (r RemoteRuntime) Images() ([]libpod.InfoData, error) { + conn, err := r.Connect() + if err != nil { + return nil, err + } + _ = conn + return nil, nil +} diff --git a/libpod/adapter/runtime.go b/libpod/adapter/runtime.go index b6db51071..13141f886 100644 --- a/libpod/adapter/runtime.go +++ b/libpod/adapter/runtime.go @@ -5,6 +5,7 @@ package adapter import ( "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/image" "github.com/urfave/cli" ) @@ -14,6 +15,11 @@ type LocalRuntime struct { Remote bool } +// ContainerImage ... +type ContainerImage struct { + *image.Image +} + // GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it func GetRuntime(c *cli.Context) (*LocalRuntime, error) { runtime, err := libpodruntime.GetRuntime(c) @@ -24,3 +30,26 @@ func GetRuntime(c *cli.Context) (*LocalRuntime, error) { Runtime: runtime, }, nil } + +// GetImages returns a slice of images in containerimages +func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) { + var containerImages []*ContainerImage + images, err := r.Runtime.ImageRuntime().GetImages() + if err != nil { + return nil, err + } + for _, i := range images { + containerImages = append(containerImages, &ContainerImage{i}) + } + return containerImages, nil + +} + +// NewImageFromLocal returns a containerimage representation of a image from local storage +func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) { + img, err := r.Runtime.ImageRuntime().NewFromLocal(name) + if err != nil { + return nil, err + } + return &ContainerImage{img}, nil +} diff --git a/libpod/adapter/runtime_remote.go b/libpod/adapter/runtime_remote.go index 715728d21..2f22dd36b 100644 --- a/libpod/adapter/runtime_remote.go +++ b/libpod/adapter/runtime_remote.go @@ -2,23 +2,43 @@ package adapter -import "github.com/urfave/cli" +import ( + "context" + "fmt" + "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/libpod/image" + "github.com/opencontainers/go-digest" + "github.com/urfave/cli" + "github.com/varlink/go/varlink" + "strings" + "time" +) + +// ImageRuntime is wrapper for image runtime +type RemoteImageRuntime struct{} // RemoteRuntime describes a wrapper runtime struct -type RemoteRuntime struct{} +type RemoteRuntime struct { +} // LocalRuntime describes a typical libpod runtime type LocalRuntime struct { Runtime *RemoteRuntime Remote bool + Conn *varlink.Connection } // GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it func GetRuntime(c *cli.Context) (*LocalRuntime, error) { runtime := RemoteRuntime{} + conn, err := runtime.Connect() + if err != nil { + return nil, err + } return &LocalRuntime{ Runtime: &runtime, Remote: true, + Conn: conn, }, nil } @@ -26,3 +46,130 @@ func GetRuntime(c *cli.Context) (*LocalRuntime, error) { func (r RemoteRuntime) Shutdown(force bool) error { return nil } + +// ContainerImage +type ContainerImage struct { + remoteImage +} + +type remoteImage struct { + ID string + Labels map[string]string + RepoTags []string + RepoDigests []string + Parent string + Size int64 + Tag string + Repository string + Created time.Time + InputName string + Names []string + Digest digest.Digest + isParent bool +} + +// GetImages returns a slice of containerimages over a varlink connection +func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) { + var newImages []*ContainerImage + images, err := iopodman.ListImages().Call(r.Conn) + if err != nil { + return nil, err + } + for _, i := range images { + name := i.Id + if len(i.RepoTags) > 1 { + name = i.RepoTags[0] + } + newImage, err := imageInListToContainerImage(i, name) + if err != nil { + return nil, err + } + newImages = append(newImages, newImage) + } + return newImages, nil +} + +func imageInListToContainerImage(i iopodman.ImageInList, name string) (*ContainerImage, error) { + imageParts, err := image.DecomposeString(name) + if err != nil { + return nil, err + } + created, err := splitStringDate(i.Created) + if err != nil { + return nil, err + } + ri := remoteImage{ + InputName: name, + ID: i.Id, + Labels: i.Labels, + RepoTags: i.RepoTags, + RepoDigests: i.RepoTags, + Parent: i.ParentId, + Size: i.Size, + Created: created, + Tag: imageParts.Tag, + Repository: imageParts.Registry, + Names: i.RepoTags, + isParent: i.IsParent, + } + return &ContainerImage{ri}, nil +} + +// NewImageFromLocal returns a container image representation of a image over varlink +func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) { + img, err := iopodman.GetImage().Call(r.Conn, name) + if err != nil { + return nil, err + } + return imageInListToContainerImage(img, name) + +} + +func splitStringDate(d string) (time.Time, error) { + fields := strings.Fields(d) + t := fmt.Sprintf("%sT%sZ", fields[0], fields[1]) + return time.ParseInLocation(time.RFC3339Nano, t, time.UTC) +} + +// IsParent goes through the layers in the store and checks if i.TopLayer is +// the parent of any other layer in store. Double check that image with that +// layer exists as well. +func (ci *ContainerImage) IsParent() (bool, error) { + return ci.remoteImage.isParent, nil +} + +// ID returns the image ID as a string +func (ci *ContainerImage) ID() string { + return ci.remoteImage.ID +} + +// Names returns a string array of names associated with the image +func (ci *ContainerImage) Names() []string { + return ci.remoteImage.Names +} + +// Created returns the time the image was created +func (ci *ContainerImage) Created() time.Time { + return ci.remoteImage.Created +} + +// Size returns the size of the image +func (ci *ContainerImage) Size(ctx context.Context) (*uint64, error) { + usize := uint64(ci.remoteImage.Size) + return &usize, nil +} + +// Digest returns the image's digest +func (ci *ContainerImage) Digest() digest.Digest { + return ci.remoteImage.Digest +} + +// Labels returns a map of the image's labels +func (ci *ContainerImage) Labels(ctx context.Context) (map[string]string, error) { + return ci.remoteImage.Labels, nil +} + +// Dangling returns a bool if the image is "dangling" +func (ci *ContainerImage) Dangling() bool { + return len(ci.Names()) == 0 +} diff --git a/libpod/image/image.go b/libpod/image/image.go index 2e12adb70..dda753385 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -460,7 +460,7 @@ func normalizeTag(tag string) (string, error) { } // If the input does not have a tag, we need to add one (latest) if !decomposedTag.isTagged { - tag = fmt.Sprintf("%s:%s", tag, decomposedTag.tag) + tag = fmt.Sprintf("%s:%s", tag, decomposedTag.Tag) } // If the input doesn't specify a registry, set the registry to localhost if !decomposedTag.hasRegistry { @@ -937,7 +937,7 @@ func (i *Image) MatchRepoTag(input string) (string, error) { if err != nil { return "", err } - if dcRepoName.registry == dcImage.registry && dcImage.registry != "" { + if dcRepoName.Registry == dcImage.Registry && dcImage.Registry != "" { count++ } if dcRepoName.name == dcImage.name && dcImage.name != "" { @@ -945,7 +945,7 @@ func (i *Image) MatchRepoTag(input string) (string, error) { } else if splitString(dcRepoName.name) == splitString(dcImage.name) { count++ } - if dcRepoName.tag == dcImage.tag { + if dcRepoName.Tag == dcImage.Tag { count++ } results[count] = append(results[count], repoName) diff --git a/libpod/image/parts.go b/libpod/image/parts.go index 9adf26fb9..b2a69f26c 100644 --- a/libpod/image/parts.go +++ b/libpod/image/parts.go @@ -7,12 +7,12 @@ import ( "github.com/containers/image/docker/reference" ) -// imageParts describes the parts of an image's name -type imageParts struct { +// Parts describes the parts of an image's name +type Parts struct { transport string - registry string + Registry string name string - tag string + Tag string isTagged bool hasRegistry bool } @@ -34,10 +34,16 @@ func GetImageBaseName(input string) (string, error) { return splitImageName[len(splitImageName)-1], nil } +// DecomposeString decomposes a string name into imageParts description. This +// is a wrapper for decompose +func DecomposeString(input string) (Parts, error) { + return decompose(input) +} + // decompose breaks an input name into an imageParts description -func decompose(input string) (imageParts, error) { +func decompose(input string) (Parts, error) { var ( - parts imageParts + parts Parts hasRegistry bool tag string ) @@ -56,7 +62,7 @@ func decompose(input string) (imageParts, error) { } registry := reference.Domain(imgRef.(reference.Named)) imageName := reference.Path(imgRef.(reference.Named)) - // Is this a registry or a repo? + // Is this a Registry or a repo? if isRegistry(registry) { hasRegistry = true } else { @@ -65,27 +71,27 @@ func decompose(input string) (imageParts, error) { registry = "" } } - return imageParts{ - registry: registry, + return Parts{ + Registry: registry, hasRegistry: hasRegistry, name: imageName, - tag: tag, + Tag: tag, isTagged: isTagged, transport: DefaultTransport, }, nil } // assemble concatenates an image's parts into a string -func (ip *imageParts) assemble() string { - spec := fmt.Sprintf("%s:%s", ip.name, ip.tag) +func (ip *Parts) assemble() string { + spec := fmt.Sprintf("%s:%s", ip.name, ip.Tag) - if ip.registry != "" { - spec = fmt.Sprintf("%s/%s", ip.registry, spec) + if ip.Registry != "" { + spec = fmt.Sprintf("%s/%s", ip.Registry, spec) } return spec } // assemble concatenates an image's parts with transport into a string -func (ip *imageParts) assembleWithTransport() string { +func (ip *Parts) assembleWithTransport() string { return fmt.Sprintf("%s%s", ip.transport, ip.assemble()) } diff --git a/libpod/image/parts_test.go b/libpod/image/parts_test.go index 518538f0b..1e01c85d3 100644 --- a/libpod/image/parts_test.go +++ b/libpod/image/parts_test.go @@ -55,9 +55,9 @@ func TestDecompose(t *testing.T) { } else { assert.NoError(t, err, c.input) assert.Equal(t, c.transport, parts.transport, c.input) - assert.Equal(t, c.registry, parts.registry, c.input) + assert.Equal(t, c.registry, parts.Registry, c.input) assert.Equal(t, c.name, parts.name, c.input) - assert.Equal(t, c.tag, parts.tag, c.input) + assert.Equal(t, c.tag, parts.Tag, c.input) assert.Equal(t, c.isTagged, parts.isTagged, c.input) assert.Equal(t, c.hasRegistry, parts.hasRegistry, c.input) assert.Equal(t, c.assembled, parts.assemble(), c.input) diff --git a/libpod/image/pull.go b/libpod/image/pull.go index 09935fe7c..203e94310 100644 --- a/libpod/image/pull.go +++ b/libpod/image/pull.go @@ -76,7 +76,7 @@ func (ir *Runtime) getPullRefPair(srcRef types.ImageReference, destName string) decomposedDest, err := decompose(destName) if err == nil && !decomposedDest.hasRegistry { // If the image doesn't have a registry, set it as the default repo - decomposedDest.registry = DefaultLocalRegistry + decomposedDest.Registry = DefaultLocalRegistry decomposedDest.hasRegistry = true destName = decomposedDest.assemble() } @@ -317,7 +317,7 @@ func (ir *Runtime) pullGoalFromPossiblyUnqualifiedName(inputName string) (*pullG } var refPairs []pullRefPair for _, registry := range searchRegistries { - decomposedImage.registry = registry + decomposedImage.Registry = registry imageName := decomposedImage.assembleWithTransport() if hasShaInInputName(inputName) { imageName = fmt.Sprintf("%s%s/%s", decomposedImage.transport, registry, inputName) diff --git a/libpod/image/utils.go b/libpod/image/utils.go index b944de1bb..135b47008 100644 --- a/libpod/image/utils.go +++ b/libpod/image/utils.go @@ -16,7 +16,7 @@ import ( // findImageInRepotags takes an imageParts struct and searches images' repotags for // a match on name:tag -func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, error) { +func findImageInRepotags(search Parts, images []*Image) (*storage.Image, error) { var results []*storage.Image for _, image := range images { for _, name := range image.Names() { @@ -25,12 +25,12 @@ func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, er if err != nil { continue } - if d.name == search.name && d.tag == search.tag { + if d.name == search.name && d.Tag == search.Tag { results = append(results, image.image) continue } // account for registry:/somedir/image - if strings.HasSuffix(d.name, search.name) && d.tag == search.tag { + if strings.HasSuffix(d.name, search.name) && d.Tag == search.Tag { results = append(results, image.image) continue } diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go index 8f8934025..370fd091a 100644 --- a/pkg/varlinkapi/images.go +++ b/pkg/varlinkapi/images.go @@ -47,6 +47,10 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error { } size, _ := image.Size(getContext()) + isParent, err := image.IsParent() + if err != nil { + return call.ReplyErrorOccurred(err.Error()) + } i := iopodman.ImageInList{ Id: image.ID(), @@ -58,6 +62,7 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error { VirtualSize: image.VirtualSize, Containers: int64(len(containers)), Labels: labels, + IsParent: isParent, } imageList = append(imageList, i) } |