diff options
author | Matthew Heon <matthew.heon@pm.me> | 2020-06-11 16:31:19 -0400 |
---|---|---|
committer | Matthew Heon <matthew.heon@pm.me> | 2020-06-16 14:33:33 -0400 |
commit | 6589d75565db2c0546787a01e8381cee15edbdf5 (patch) | |
tree | 88196aec26e8d376f96b2705ea81c5a37aee3756 /cmd/podman/inspect | |
parent | 2c7b39ddb8961bf547a36420407adb461dd4c227 (diff) | |
download | podman-6589d75565db2c0546787a01e8381cee15edbdf5.tar.gz podman-6589d75565db2c0546787a01e8381cee15edbdf5.tar.bz2 podman-6589d75565db2c0546787a01e8381cee15edbdf5.zip |
Fix podman inspect on overlapping/missing objects
This started as a small fix to `podman inspect` where a container
and image, with the same name/tag, were present, and
`podman inspect` was run on that name. `podman inspect` in 1.9
(and `docker inspect`) will give you the container; in v2.0, we
gave the image. This was an easy fix (just reorder how we check
for image/container).
Unfortunately, in the process of testing this fix, I determined
that we regressed in a different area. When you run inspect on
a number of containers, some of which do not exist,
`podman inspect` should return an array of inspect results for
the objects that exist, then print a number of errors, one for
each object that could not be found. We were bailing after the
first error, and not printing output for the containers that
succeeded. (For reference, this applied to images as well). This
required a much more substantial set of changes to properly
handle - signatures for the inspect functions in ContainerEngine
and ImageEngine, plus the implementations of these interfaces,
plus the actual inspect frontend code needed to be adjusted to
use this.
Fixes #6556
Signed-off-by: Matthew Heon <matthew.heon@pm.me>
Diffstat (limited to 'cmd/podman/inspect')
-rw-r--r-- | cmd/podman/inspect/inspect.go | 56 |
1 files changed, 43 insertions, 13 deletions
diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go index 1ed033ec3..d80bbffdd 100644 --- a/cmd/podman/inspect/inspect.go +++ b/cmd/podman/inspect/inspect.go @@ -3,12 +3,14 @@ package inspect import ( "context" "fmt" + "os" "strings" "github.com/containers/buildah/pkg/formats" "github.com/containers/libpod/cmd/podman/registry" "github.com/containers/libpod/pkg/domain/entities" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -78,6 +80,7 @@ func newInspector(options entities.InspectOptions) (*inspector, error) { func (i *inspector) inspect(namesOrIDs []string) error { // data - dumping place for inspection results. var data []interface{} //nolint + var errs []error ctx := context.Background() if len(namesOrIDs) == 0 { @@ -97,24 +100,27 @@ func (i *inspector) inspect(namesOrIDs []string) error { // Inspect - note that AllType requires us to expensively query one-by-one. switch tmpType { case AllType: - all, err := i.inspectAll(ctx, namesOrIDs) + allData, allErrs, err := i.inspectAll(ctx, namesOrIDs) if err != nil { return err } - data = all + data = allData + errs = allErrs case ImageType: - imgData, err := i.imageEngine.Inspect(ctx, namesOrIDs, i.options) + imgData, allErrs, err := i.imageEngine.Inspect(ctx, namesOrIDs, i.options) if err != nil { return err } + errs = allErrs for i := range imgData { data = append(data, imgData[i]) } case ContainerType: - ctrData, err := i.containerEngine.ContainerInspect(ctx, namesOrIDs, i.options) + ctrData, allErrs, err := i.containerEngine.ContainerInspect(ctx, namesOrIDs, i.options) if err != nil { return err } + errs = allErrs for i := range ctrData { data = append(data, ctrData[i]) } @@ -122,30 +128,54 @@ func (i *inspector) inspect(namesOrIDs []string) error { return errors.Errorf("invalid type %q: must be %q, %q or %q", i.options.Type, ImageType, ContainerType, AllType) } + // Always print an empty array + if data == nil { + data = []interface{}{} + } + var out formats.Writer if i.options.Format == "json" || i.options.Format == "" { // "" for backwards compat out = formats.JSONStructArray{Output: data} } else { out = formats.StdoutTemplateArray{Output: data, Template: inspectFormat(i.options.Format)} } - return out.Out() + if err := out.Out(); err != nil { + logrus.Errorf("Error printing inspect output: %v", err) + } + if len(errs) > 0 { + if len(errs) > 1 { + for _, err := range errs[1:] { + fmt.Fprintf(os.Stderr, "error inspecting object: %v\n", err) + } + } + return errors.Errorf("error inspecting object: %v", errs[0]) + } + return nil } -func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]interface{}, error) { +func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]interface{}, []error, error) { var data []interface{} //nolint + allErrs := []error{} for _, name := range namesOrIDs { - imgData, err := i.imageEngine.Inspect(ctx, []string{name}, i.options) - if err == nil { - data = append(data, imgData[0]) + ctrData, errs, err := i.containerEngine.ContainerInspect(ctx, []string{name}, i.options) + if err != nil { + return nil, nil, err + } + if len(errs) == 0 { + data = append(data, ctrData[0]) continue } - ctrData, err := i.containerEngine.ContainerInspect(ctx, []string{name}, i.options) + imgData, errs, err := i.imageEngine.Inspect(ctx, []string{name}, i.options) if err != nil { - return nil, err + return nil, nil, err + } + if len(errs) > 0 { + allErrs = append(allErrs, errors.Errorf("no such object: %q", name)) + continue } - data = append(data, ctrData[0]) + data = append(data, imgData[0]) } - return data, nil + return data, allErrs, nil } func inspectFormat(row string) string { |