Inspect output should be in array form

Inspect should be able to inspect one or more containers depending
on the user input.  Therefore, inspect output should be in array
format so the consumer could potentially iterate it.  This PR allows
users to specify one more or containers|images|or a mix for
inspection.  The output, as stated, is therefore in array form.  This
holds true even for a singular image.

In the case that the user enters an invalid container|image "name", we
handle that gracefully.  Podman will output json for the valid names
until it reaches the invalid one.  For example:

In this case, podman will out the json for alpine and then print an
error about 123 being invalid.  It will not continute onto busybox.
This behavior imatates docker.

This addresses issue #360

Signed-off-by: baude <bbaude@redhat.com>

Closes: #371
Approved by: baude
This commit is contained in:
baude 2018-02-20 10:57:37 -06:00 committed by Atomic Bot
parent e929e7de4c
commit 6ce70a33c5
8 changed files with 125 additions and 84 deletions

View file

@ -43,7 +43,7 @@ var (
Description: inspectDescription,
Flags: inspectFlags,
Action: inspectCmd,
ArgsUsage: "CONTAINER-OR-IMAGE",
ArgsUsage: "CONTAINER-OR-IMAGE [CONTAINER-OR-IMAGE]...",
}
)
@ -51,12 +51,12 @@ func inspectCmd(c *cli.Context) error {
args := c.Args()
inspectType := c.String("type")
latestContainer := c.Bool("latest")
var name string
if len(args) == 0 && !latestContainer {
return errors.Errorf("container or image name must be specified: podman inspect [options [...]] name")
}
if len(args) > 1 {
return errors.Errorf("too many arguments specified")
if len(args) > 0 && latestContainer {
return errors.Errorf("you cannot provide additional arguements with --latest")
}
if err := validateFlags(c, inspectFlags); err != nil {
return err
@ -71,81 +71,103 @@ func inspectCmd(c *cli.Context) error {
if !libpod.StringInSlice(inspectType, []string{inspectTypeContainer, inspectTypeImage, inspectAll}) {
return errors.Errorf("the only recognized types are %q, %q, and %q", inspectTypeContainer, inspectTypeImage, inspectAll)
}
if !latestContainer {
name = args[0]
}
if latestContainer {
inspectType = inspectTypeContainer
}
outputFormat := c.String("format")
if strings.Contains(outputFormat, "{{.Id}}") {
outputFormat = strings.Replace(outputFormat, "{{.Id}}", formats.IDString, -1)
}
var data interface{}
switch inspectType {
case inspectTypeContainer:
var ctr *libpod.Container
var err error
if latestContainer {
ctr, err = runtime.GetLatestContainer()
} else {
ctr, err = runtime.LookupContainer(name)
}
if latestContainer {
lc, err := runtime.GetLatestContainer()
if err != nil {
return errors.Wrapf(err, "error looking up container %q", name)
}
libpodInspectData, err := ctr.Inspect(c.Bool("size"))
if err != nil {
return errors.Wrapf(err, "error getting libpod container inspect data %q", ctr.ID)
}
data, err = getCtrInspectInfo(ctr, libpodInspectData)
if err != nil {
return errors.Wrapf(err, "error parsing container data %q", ctr.ID())
}
case inspectTypeImage:
image, err := runtime.GetImage(name)
if err != nil {
return errors.Wrapf(err, "error getting image %q", name)
}
data, err = runtime.GetImageInspectInfo(*image)
if err != nil {
return errors.Wrapf(err, "error parsing image data %q", image.ID)
}
case inspectAll:
ctr, err := runtime.LookupContainer(name)
if err != nil {
image, err := runtime.GetImage(name)
if err != nil {
return errors.Wrapf(err, "error getting image %q", name)
}
data, err = runtime.GetImageInspectInfo(*image)
if err != nil {
return errors.Wrapf(err, "error parsing image data %q", image.ID)
}
} else {
libpodInspectData, err := ctr.Inspect(c.Bool("size"))
if err != nil {
return errors.Wrapf(err, "error getting libpod container inspect data %q", ctr.ID)
}
data, err = getCtrInspectInfo(ctr, libpodInspectData)
if err != nil {
return errors.Wrapf(err, "error parsing container data %q", ctr.ID)
}
return err
}
args = append(args, lc.ID())
inspectType = inspectTypeContainer
}
inspectedObjects, iterateErr := iterateInput(c, args, runtime, inspectType)
var out formats.Writer
if outputFormat != "" && outputFormat != formats.JSONString {
//template
out = formats.StdoutTemplate{Output: data, Template: outputFormat}
out = formats.StdoutTemplateArray{Output: inspectedObjects, Template: outputFormat}
} else {
// default is json output
out = formats.JSONStruct{Output: data}
out = formats.JSONStructArray{Output: inspectedObjects}
}
formats.Writer(out).Out()
return nil
return iterateErr
}
// func iterateInput iterates the images|containers the user has requested and returns the inspect data and error
func iterateInput(c *cli.Context, args []string, runtime *libpod.Runtime, inspectType string) ([]interface{}, error) {
var (
data interface{}
inspectedItems []interface{}
inspectError error
)
for _, input := range args {
switch inspectType {
case inspectTypeContainer:
ctr, err := runtime.LookupContainer(input)
if err != nil {
inspectError = errors.Wrapf(err, "error looking up container %q", input)
break
}
libpodInspectData, err := ctr.Inspect(c.Bool("size"))
if err != nil {
inspectError = errors.Wrapf(err, "error getting libpod container inspect data %q", ctr.ID)
break
}
data, err = getCtrInspectInfo(ctr, libpodInspectData)
if err != nil {
inspectError = errors.Wrapf(err, "error parsing container data %q", ctr.ID())
break
}
case inspectTypeImage:
image, err := runtime.GetImage(input)
if err != nil {
inspectError = errors.Wrapf(err, "error getting image %q", input)
break
}
data, err = runtime.GetImageInspectInfo(*image)
if err != nil {
inspectError = errors.Wrapf(err, "error parsing image data %q", image.ID)
break
}
case inspectAll:
ctr, err := runtime.LookupContainer(input)
if err != nil {
image, err := runtime.GetImage(input)
if err != nil {
inspectError = errors.Wrapf(err, "error getting image %q", input)
break
}
data, err = runtime.GetImageInspectInfo(*image)
if err != nil {
inspectError = errors.Wrapf(err, "error parsing image data %q", image.ID)
break
}
} else {
libpodInspectData, err := ctr.Inspect(c.Bool("size"))
if err != nil {
inspectError = errors.Wrapf(err, "error getting libpod container inspect data %q", ctr.ID)
break
}
data, err = getCtrInspectInfo(ctr, libpodInspectData)
if err != nil {
inspectError = errors.Wrapf(err, "error parsing container data %q", ctr.ID)
break
}
}
}
if inspectError == nil {
inspectedItems = append(inspectedItems, data)
}
}
return inspectedItems, inspectError
}
func getCtrInspectInfo(ctr *libpod.Container, ctrInspectData *inspect.ContainerInspectData) (*inspect.ContainerData, error) {

View file

@ -6,10 +6,12 @@
podman inspect - Display a container or image's configuration
## SYNOPSIS
**podman** **inspect** [*options* [...]] name
**podman** **inspect** [*options* [...]] name [...]
## DESCRIPTION
This displays the low-level information on containers and images identified by name or ID. By default, this will render all results in a JSON array. If the container and image have the same name, this will return container JSON for unspecified type. If a format is specified, the given template will be executed for each result.
This displays the low-level information on containers and images identified by name or ID. By default, this will render
all results in a JSON array. If the container and image have the same name, this will return container JSON for
unspecified type. If a format is specified, the given template will be executed for each result.
## OPTIONS

View file

@ -40,7 +40,7 @@ var _ = Describe("Podman commit", func() {
check := podmanTest.Podman([]string{"inspect", "foobar.com/test1-image:latest"})
check.WaitWithDefaultTimeout()
data := check.InspectImageJSON()
Expect(StringInSlice("foobar.com/test1-image:latest", data.RepoTags)).To(BeTrue())
Expect(StringInSlice("foobar.com/test1-image:latest", data[0].RepoTags)).To(BeTrue())
})
It("podman commit container with message", func() {
@ -55,7 +55,7 @@ var _ = Describe("Podman commit", func() {
check := podmanTest.Podman([]string{"inspect", "foobar.com/test1-image:latest"})
check.WaitWithDefaultTimeout()
data := check.InspectImageJSON()
Expect(data.Comment).To(Equal("testing-commit"))
Expect(data[0].Comment).To(Equal("testing-commit"))
})
It("podman commit container with author", func() {
@ -70,7 +70,7 @@ var _ = Describe("Podman commit", func() {
check := podmanTest.Podman([]string{"inspect", "foobar.com/test1-image:latest"})
check.WaitWithDefaultTimeout()
data := check.InspectImageJSON()
Expect(data.Author).To(Equal("snoopy"))
Expect(data[0].Author).To(Equal("snoopy"))
})
It("podman commit container with change flag", func() {
@ -88,7 +88,7 @@ var _ = Describe("Podman commit", func() {
check.WaitWithDefaultTimeout()
data := check.InspectImageJSON()
foundBlue := false
for _, i := range data.Labels {
for _, i := range data[0].Labels {
if i == "blue" {
foundBlue = true
break

View file

@ -38,7 +38,7 @@ var _ = Describe("Podman create", func() {
check := podmanTest.Podman([]string{"inspect", "-l"})
check.WaitWithDefaultTimeout()
data := check.InspectContainerToJSON()
Expect(data.ID).To(ContainSubstring(cid))
Expect(data[0].ID).To(ContainSubstring(cid))
})
It("podman create container based on a remote image", func() {

View file

@ -101,7 +101,7 @@ var _ = Describe("Podman import", func() {
results.WaitWithDefaultTimeout()
Expect(results.ExitCode()).To(Equal(0))
imageData := results.InspectImageJSON()
Expect(imageData.ContainerConfig.Cmd[0]).To(Equal("/bin/bash"))
Expect(imageData[0].ContainerConfig.Cmd[0]).To(Equal("/bin/bash"))
})
})

View file

@ -2,7 +2,6 @@ package integration
import (
"os"
"strings"
. "github.com/onsi/ginkgo"
@ -36,7 +35,7 @@ var _ = Describe("Podman inspect", func() {
Expect(session.ExitCode()).To(Equal(0))
Expect(session.IsJSONOutputValid()).To(BeTrue())
imageData := session.InspectImageJSON()
Expect(imageData.RepoTags[0]).To(Equal("docker.io/library/alpine:latest"))
Expect(imageData[0].RepoTags[0]).To(Equal("docker.io/library/alpine:latest"))
})
It("podman inspect bogus container", func() {
@ -70,6 +69,24 @@ var _ = Describe("Podman inspect", func() {
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
conData := result.InspectContainerToJSON()
Expect(conData.SizeRootFs).To(BeNumerically(">", 0))
Expect(conData[0].SizeRootFs).To(BeNumerically(">", 0))
})
It("podman inspect container and image", func() {
ls, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
cid := ls.OutputToString()
result := podmanTest.Podman([]string{"inspect", "--format={{.ID}}", cid, ALPINE})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
Expect(len(result.OutputToStringArray())).To(Equal(2))
})
It("podman inspect -l with additional input should fail", func() {
result := podmanTest.Podman([]string{"inspect", "-l", "1234foobar"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(125))
})
})

View file

@ -228,8 +228,8 @@ func (s *PodmanSession) IsJSONOutputValid() bool {
// InspectContainerToJSON takes the session output of an inspect
// container and returns json
func (s *PodmanSession) InspectContainerToJSON() inspect.ContainerData {
var i inspect.ContainerData
func (s *PodmanSession) InspectContainerToJSON() []inspect.ContainerData {
var i []inspect.ContainerData
err := json.Unmarshal(s.Out.Contents(), &i)
Expect(err).To(BeNil())
return i
@ -237,8 +237,8 @@ func (s *PodmanSession) InspectContainerToJSON() inspect.ContainerData {
// InspectImageJSON takes the session output of an inspect
// image and returns json
func (s *PodmanSession) InspectImageJSON() inspect.ImageData {
var i inspect.ImageData
func (s *PodmanSession) InspectImageJSON() []inspect.ImageData {
var i []inspect.ImageData
err := json.Unmarshal(s.Out.Contents(), &i)
Expect(err).To(BeNil())
return i

View file

@ -37,8 +37,8 @@ var _ = Describe("Podman tag", func() {
results.WaitWithDefaultTimeout()
Expect(results.ExitCode()).To(Equal(0))
inspectData := results.InspectImageJSON()
Expect(StringInSlice("docker.io/library/alpine:latest", inspectData.RepoTags)).To(BeTrue())
Expect(StringInSlice("foobar:latest", inspectData.RepoTags)).To(BeTrue())
Expect(StringInSlice("docker.io/library/alpine:latest", inspectData[0].RepoTags)).To(BeTrue())
Expect(StringInSlice("foobar:latest", inspectData[0].RepoTags)).To(BeTrue())
})
It("podman tag shortname", func() {
@ -50,8 +50,8 @@ var _ = Describe("Podman tag", func() {
results.WaitWithDefaultTimeout()
Expect(results.ExitCode()).To(Equal(0))
inspectData := results.InspectImageJSON()
Expect(StringInSlice("docker.io/library/alpine:latest", inspectData.RepoTags)).To(BeTrue())
Expect(StringInSlice("foobar:latest", inspectData.RepoTags)).To(BeTrue())
Expect(StringInSlice("docker.io/library/alpine:latest", inspectData[0].RepoTags)).To(BeTrue())
Expect(StringInSlice("foobar:latest", inspectData[0].RepoTags)).To(BeTrue())
})
It("podman tag shortname:tag", func() {
@ -63,7 +63,7 @@ var _ = Describe("Podman tag", func() {
results.WaitWithDefaultTimeout()
Expect(results.ExitCode()).To(Equal(0))
inspectData := results.InspectImageJSON()
Expect(StringInSlice("docker.io/library/alpine:latest", inspectData.RepoTags)).To(BeTrue())
Expect(StringInSlice("foobar:new", inspectData.RepoTags)).To(BeTrue())
Expect(StringInSlice("docker.io/library/alpine:latest", inspectData[0].RepoTags)).To(BeTrue())
Expect(StringInSlice("foobar:new", inspectData[0].RepoTags)).To(BeTrue())
})
})