mirror of
https://github.com/containers/podman.git
synced 2025-06-24 19:42:56 +08:00
Add --all,-a flag to podman images
podman images will not show intermediate images by default. To view all images, including intermediate images created during a build, use the --all flag. Signed-off-by: umohnani8 <umohnani@redhat.com> Closes: #947 Approved by: rhatdan
This commit is contained in:
@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/containers/storage"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
digest "github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -43,6 +44,7 @@ type imagesOptions struct {
|
|||||||
format string
|
format string
|
||||||
outputformat string
|
outputformat string
|
||||||
sort string
|
sort string
|
||||||
|
all bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type declaration and functions for sorting the images output
|
// Type declaration and functions for sorting the images output
|
||||||
@ -178,6 +180,7 @@ func imagesCmd(c *cli.Context) error {
|
|||||||
digests: c.Bool("digests"),
|
digests: c.Bool("digests"),
|
||||||
format: c.String("format"),
|
format: c.String("format"),
|
||||||
sort: c.String("sort"),
|
sort: c.String("sort"),
|
||||||
|
all: c.Bool("all"),
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.outputformat = opts.setOutputFormat()
|
opts.outputformat = opts.setOutputFormat()
|
||||||
@ -256,8 +259,14 @@ func sortImagesOutput(sortBy string, imagesOutput imagesSorted) imagesSorted {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getImagesTemplateOutput returns the images information to be printed in human readable format
|
// 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, runtime *libpod.Runtime, images []*image.Image, opts imagesOptions, storageLayers []storage.Layer) (imagesOutput imagesSorted) {
|
||||||
for _, img := range images {
|
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
|
||||||
|
// is not set.
|
||||||
|
if !opts.all && len(img.Names()) == 0 && !layerIsLeaf(storageLayers, img.TopLayer()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
createdTime := img.Created()
|
createdTime := img.Created()
|
||||||
|
|
||||||
imageID := "sha256:" + img.ID()
|
imageID := "sha256:" + img.ID()
|
||||||
@ -316,13 +325,17 @@ func generateImagesOutput(ctx context.Context, runtime *libpod.Runtime, images [
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var out formats.Writer
|
var out formats.Writer
|
||||||
|
storageLayers, err := runtime.GetLayers()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "error getting layers from store")
|
||||||
|
}
|
||||||
|
|
||||||
switch opts.format {
|
switch opts.format {
|
||||||
case formats.JSONString:
|
case formats.JSONString:
|
||||||
imagesOutput := getImagesJSONOutput(ctx, runtime, images)
|
imagesOutput := getImagesJSONOutput(ctx, runtime, images)
|
||||||
out = formats.JSONStructArray{Output: imagesToGeneric([]imagesTemplateParams{}, imagesOutput)}
|
out = formats.JSONStructArray{Output: imagesToGeneric([]imagesTemplateParams{}, imagesOutput)}
|
||||||
default:
|
default:
|
||||||
imagesOutput := getImagesTemplateOutput(ctx, runtime, images, opts)
|
imagesOutput := getImagesTemplateOutput(ctx, runtime, images, opts, storageLayers)
|
||||||
out = formats.StdoutTemplateArray{Output: imagesToGeneric(imagesOutput, []imagesJSONParams{}), Template: opts.outputformat, Fields: imagesOutput[0].HeaderMap()}
|
out = formats.StdoutTemplateArray{Output: imagesToGeneric(imagesOutput, []imagesJSONParams{}), Template: opts.outputformat, Fields: imagesOutput[0].HeaderMap()}
|
||||||
}
|
}
|
||||||
return formats.Writer(out).Out()
|
return formats.Writer(out).Out()
|
||||||
@ -378,3 +391,14 @@ func CreateFilterFuncs(ctx context.Context, r *libpod.Runtime, c *cli.Context, i
|
|||||||
}
|
}
|
||||||
return filterFuncs, nil
|
return filterFuncs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// layerIsLeaf goes through the layers in the store and checks if "layer" is
|
||||||
|
// the parent of any other layer in store.
|
||||||
|
func layerIsLeaf(storageLayers []storage.Layer, layer string) bool {
|
||||||
|
for _, storeLayer := range storageLayers {
|
||||||
|
if storeLayer.Parent == layer {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@ -13,7 +13,7 @@ Displays locally stored images, their names, and their IDs.
|
|||||||
|
|
||||||
**--all, -a**
|
**--all, -a**
|
||||||
|
|
||||||
Show all images (by default filter out the intermediate image layers). The default is false. (This is a NOOP until podman build supports caching.)
|
Show all images (by default filter out the intermediate image layers). The default is false.
|
||||||
|
|
||||||
**--digests**
|
**--digests**
|
||||||
|
|
||||||
@ -133,6 +133,20 @@ registry.access.redhat.com/rhel7 latest 7a840db7f020 2 weeks ago
|
|||||||
registry.fedoraproject.org/fedora 27 801894bc0e43 6 weeks ago 246MB
|
registry.fedoraproject.org/fedora 27 801894bc0e43 6 weeks ago 246MB
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
# podman images
|
||||||
|
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||||
|
localhost/test latest 18f0c080cd72 4 seconds ago 4.42MB
|
||||||
|
docker.io/library/alpine latest 3fd9065eaf02 5 months ago 4.41MB
|
||||||
|
# podman images -a
|
||||||
|
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||||
|
localhost/test latest 18f0c080cd72 6 seconds ago 4.42MB
|
||||||
|
<none> <none> 270e70dc54c0 7 seconds ago 4.42MB
|
||||||
|
<none> <none> 4ed6fbe43414 8 seconds ago 4.41MB
|
||||||
|
<none> <none> 6b0df8e71508 8 seconds ago 4.41MB
|
||||||
|
docker.io/library/alpine latest 3fd9065eaf02 5 months ago 4.41MB
|
||||||
|
```
|
||||||
|
|
||||||
## SEE ALSO
|
## SEE ALSO
|
||||||
podman(1)
|
podman(1)
|
||||||
|
|
||||||
|
@ -666,3 +666,8 @@ func SaveDefaultConfig(path string) error {
|
|||||||
func (r *Runtime) ImageRuntime() *image.Runtime {
|
func (r *Runtime) ImageRuntime() *image.Runtime {
|
||||||
return r.imageRuntime
|
return r.imageRuntime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLayers returns the layers available in the store
|
||||||
|
func (r *Runtime) GetLayers() ([]storage.Layer, error) {
|
||||||
|
return r.store.Layers()
|
||||||
|
}
|
||||||
|
@ -100,7 +100,7 @@ var _ = Describe("Podman images", func() {
|
|||||||
It("podman images filter before image", func() {
|
It("podman images filter before image", func() {
|
||||||
dockerfile := `FROM docker.io/library/alpine:latest
|
dockerfile := `FROM docker.io/library/alpine:latest
|
||||||
`
|
`
|
||||||
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest")
|
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
|
||||||
result := podmanTest.Podman([]string{"images", "-q", "-f", "before=foobar.com/before:latest"})
|
result := podmanTest.Podman([]string{"images", "-q", "-f", "before=foobar.com/before:latest"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result.ExitCode()).To(Equal(0))
|
Expect(result.ExitCode()).To(Equal(0))
|
||||||
@ -114,7 +114,7 @@ var _ = Describe("Podman images", func() {
|
|||||||
|
|
||||||
dockerfile := `FROM docker.io/library/alpine:latest
|
dockerfile := `FROM docker.io/library/alpine:latest
|
||||||
`
|
`
|
||||||
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest")
|
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
|
||||||
result := podmanTest.Podman([]string{"images", "-q", "-f", "after=docker.io/library/alpine:latest"})
|
result := podmanTest.Podman([]string{"images", "-q", "-f", "after=docker.io/library/alpine:latest"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result.ExitCode()).To(Equal(0))
|
Expect(result.ExitCode()).To(Equal(0))
|
||||||
@ -124,8 +124,8 @@ var _ = Describe("Podman images", func() {
|
|||||||
It("podman images filter dangling", func() {
|
It("podman images filter dangling", func() {
|
||||||
dockerfile := `FROM docker.io/library/alpine:latest
|
dockerfile := `FROM docker.io/library/alpine:latest
|
||||||
`
|
`
|
||||||
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest")
|
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
|
||||||
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest")
|
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
|
||||||
result := podmanTest.Podman([]string{"images", "-q", "-f", "dangling=true"})
|
result := podmanTest.Podman([]string{"images", "-q", "-f", "dangling=true"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result.ExitCode()).To(Equal(0))
|
Expect(result.ExitCode()).To(Equal(0))
|
||||||
@ -165,4 +165,22 @@ var _ = Describe("Podman images", func() {
|
|||||||
return size1 < size2
|
return size1 < size2
|
||||||
})).To(BeTrue())
|
})).To(BeTrue())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman images --all flag", func() {
|
||||||
|
dockerfile := `FROM docker.io/library/alpine:latest
|
||||||
|
RUN mkdir hello
|
||||||
|
RUN touch test.txt
|
||||||
|
ENV foo=bar
|
||||||
|
`
|
||||||
|
podmanTest.BuildImage(dockerfile, "test", "true")
|
||||||
|
session := podmanTest.Podman([]string{"images"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(len(session.OutputToStringArray())).To(Equal(4))
|
||||||
|
|
||||||
|
session2 := podmanTest.Podman([]string{"images", "--all"})
|
||||||
|
session2.WaitWithDefaultTimeout()
|
||||||
|
Expect(session2.ExitCode()).To(Equal(0))
|
||||||
|
Expect(len(session2.OutputToStringArray())).To(Equal(6))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -593,11 +593,11 @@ func (p *PodmanTest) GetContainerStatus() string {
|
|||||||
|
|
||||||
// BuildImage uses podman build and buildah to build an image
|
// BuildImage uses podman build and buildah to build an image
|
||||||
// called imageName based on a string dockerfile
|
// called imageName based on a string dockerfile
|
||||||
func (p *PodmanTest) BuildImage(dockerfile, imageName string) {
|
func (p *PodmanTest) BuildImage(dockerfile, imageName string, layers string) {
|
||||||
dockerfilePath := filepath.Join(p.TempDir, "Dockerfile")
|
dockerfilePath := filepath.Join(p.TempDir, "Dockerfile")
|
||||||
err := ioutil.WriteFile(dockerfilePath, []byte(dockerfile), 0755)
|
err := ioutil.WriteFile(dockerfilePath, []byte(dockerfile), 0755)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
session := p.Podman([]string{"build", "-t", imageName, "--file", dockerfilePath, p.TempDir})
|
session := p.Podman([]string{"build", "--layers=" + layers, "-t", imageName, "--file", dockerfilePath, p.TempDir})
|
||||||
session.Wait(120)
|
session.Wait(120)
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ var _ = Describe("Podman run entrypoint", func() {
|
|||||||
ENTRYPOINT []
|
ENTRYPOINT []
|
||||||
CMD []
|
CMD []
|
||||||
`
|
`
|
||||||
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest")
|
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest", "false")
|
||||||
session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest"})
|
session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Equal(125))
|
Expect(session.ExitCode()).To(Equal(125))
|
||||||
@ -43,7 +43,7 @@ CMD []
|
|||||||
dockerfile := `FROM docker.io/library/alpine:latest
|
dockerfile := `FROM docker.io/library/alpine:latest
|
||||||
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
||||||
`
|
`
|
||||||
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest")
|
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest", "false")
|
||||||
session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest"})
|
session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
@ -55,7 +55,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
|||||||
CMD [ "-v"]
|
CMD [ "-v"]
|
||||||
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
||||||
`
|
`
|
||||||
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest")
|
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest", "false")
|
||||||
session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest"})
|
session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
@ -67,7 +67,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
|||||||
CMD [ "-v"]
|
CMD [ "-v"]
|
||||||
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
||||||
`
|
`
|
||||||
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest")
|
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest", "false")
|
||||||
session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest", "-i"})
|
session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest", "-i"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
@ -78,7 +78,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
|||||||
dockerfile := `FROM docker.io/library/alpine:latest
|
dockerfile := `FROM docker.io/library/alpine:latest
|
||||||
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
||||||
`
|
`
|
||||||
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest")
|
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest", "false")
|
||||||
session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest", "-i"})
|
session := podmanTest.Podman([]string{"run", "foobar.com/entrypoint:latest", "-i"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
@ -90,7 +90,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
|||||||
CMD ["-i"]
|
CMD ["-i"]
|
||||||
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
||||||
`
|
`
|
||||||
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest")
|
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest", "false")
|
||||||
session := podmanTest.Podman([]string{"run", "--entrypoint=uname", "foobar.com/entrypoint:latest"})
|
session := podmanTest.Podman([]string{"run", "--entrypoint=uname", "foobar.com/entrypoint:latest"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
@ -102,7 +102,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
|||||||
CMD ["-i"]
|
CMD ["-i"]
|
||||||
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
ENTRYPOINT ["grep", "Alpine", "/etc/os-release"]
|
||||||
`
|
`
|
||||||
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest")
|
podmanTest.BuildImage(dockerfile, "foobar.com/entrypoint:latest", "false")
|
||||||
session := podmanTest.Podman([]string{"run", "--entrypoint=uname", "foobar.com/entrypoint:latest", "-r"})
|
session := podmanTest.Podman([]string{"run", "--entrypoint=uname", "foobar.com/entrypoint:latest", "-r"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Reference in New Issue
Block a user