Add pod, volume, network to inspect package

podman inspect only had the capabilities to inspect containers and images. if a user wanted to inspect a pod, volume, or network, they would have to use `podman network inspect`, `podman pod inspect` etc. Docker's cli allowed users to inspect both volumes and networks using regular inspect, so this commit gives the user the functionality

If the inspect type is not specified using --type, the order of inspection is:

containers
images
volumes
networks
pods

meaning if container that has the same name as an image, podman inspect would return the container inspect.

To avoid duplicate code, podman network inspect and podman volume inspect now use the inspect package as well. Podman pod inspect does not because podman pod inspect returns a single json object while podman inspect can return multiple)

Signed-off-by: Ashley Cui <acui@redhat.com>
This commit is contained in:
Ashley Cui
2020-10-15 09:23:26 -04:00
parent 5c0849534d
commit 61deec451f
17 changed files with 360 additions and 127 deletions

View File

@ -12,6 +12,7 @@ import (
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/validate"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -19,12 +20,18 @@ import (
)
const (
// ImageType is the image type.
ImageType = "image"
// ContainerType is the container type.
ContainerType = "container"
// AllType can be of type ImageType or ContainerType.
AllType = "all"
// ContainerType is the container type.
ContainerType = "container"
// ImageType is the image type.
ImageType = "image"
//NetworkType is the network type
NetworkType = "network"
//PodType is the pod type.
PodType = "pod"
//VolumeType is the volume type
VolumeType = "volume"
)
// Pull in configured json library
@ -58,15 +65,16 @@ type inspector struct {
containerEngine entities.ContainerEngine
imageEngine entities.ImageEngine
options entities.InspectOptions
podOptions entities.PodInspectOptions
}
// newInspector creates a new inspector based on the specified options.
func newInspector(options entities.InspectOptions) (*inspector, error) {
switch options.Type {
case ImageType, ContainerType, AllType:
case ImageType, ContainerType, AllType, PodType, NetworkType, VolumeType:
// Valid types.
default:
return nil, errors.Errorf("invalid type %q: must be %q, %q or %q", options.Type, ImageType, ContainerType, AllType)
return nil, errors.Errorf("invalid type %q: must be %q, %q, %q, %q, %q, or %q", options.Type, ImageType, ContainerType, PodType, NetworkType, VolumeType, AllType)
}
if options.Type == ImageType {
if options.Latest {
@ -76,10 +84,18 @@ func newInspector(options entities.InspectOptions) (*inspector, error) {
return nil, errors.Errorf("size is not supported for type %q", ImageType)
}
}
if options.Type == PodType && options.Size {
return nil, errors.Errorf("size is not supported for type %q", PodType)
}
podOpts := entities.PodInspectOptions{
Latest: options.Latest,
Format: options.Format,
}
return &inspector{
containerEngine: registry.ContainerEngine(),
imageEngine: registry.ImageEngine(),
options: options,
podOptions: podOpts,
}, nil
}
@ -91,17 +107,19 @@ func (i *inspector) inspect(namesOrIDs []string) error {
ctx := context.Background()
if len(namesOrIDs) == 0 {
if !i.options.Latest {
return errors.New("no containers or images specified")
if !i.options.Latest && !i.options.All {
return errors.New("no names or ids specified")
}
}
tmpType := i.options.Type
if i.options.Latest {
if len(namesOrIDs) > 0 {
return errors.New("--latest and containers cannot be used together")
return errors.New("--latest and arguments cannot be used together")
}
if i.options.Type == AllType {
tmpType = ContainerType // -l works with --type=all, defaults to containertype
}
tmpType = ContainerType // -l works with --type=all
}
// Inspect - note that AllType requires us to expensively query one-by-one.
@ -131,10 +149,57 @@ func (i *inspector) inspect(namesOrIDs []string) error {
for i := range ctrData {
data = append(data, ctrData[i])
}
default:
return errors.Errorf("invalid type %q: must be %q, %q or %q", i.options.Type, ImageType, ContainerType, AllType)
case PodType:
for _, pod := range namesOrIDs {
i.podOptions.NameOrID = pod
podData, err := i.containerEngine.PodInspect(ctx, i.podOptions)
if err != nil {
cause := errors.Cause(err)
if !strings.Contains(cause.Error(), define.ErrNoSuchPod.Error()) {
errs = []error{err}
} else {
return err
}
} else {
errs = nil
data = append(data, podData)
}
}
if i.podOptions.Latest { //latest means there are no names in the namesOrID array
podData, err := i.containerEngine.PodInspect(ctx, i.podOptions)
if err != nil {
cause := errors.Cause(err)
if !strings.Contains(cause.Error(), define.ErrNoSuchPod.Error()) {
errs = []error{err}
} else {
return err
}
} else {
errs = nil
data = append(data, podData)
}
}
case NetworkType:
networkData, allErrs, err := registry.ContainerEngine().NetworkInspect(ctx, namesOrIDs, i.options)
if err != nil {
return err
}
errs = allErrs
for i := range networkData {
data = append(data, networkData[i])
}
case VolumeType:
volumeData, allErrs, err := i.containerEngine.VolumeInspect(ctx, namesOrIDs, i.options)
if err != nil {
return err
}
errs = allErrs
for i := range volumeData {
data = append(data, volumeData[i])
}
default:
return errors.Errorf("invalid type %q: must be %q, %q, %q, %q, %q, or %q", i.options.Type, ImageType, ContainerType, PodType, NetworkType, VolumeType, AllType)
}
// Always print an empty array
if data == nil {
data = []interface{}{}
@ -195,11 +260,41 @@ func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]inte
if err != nil {
return nil, nil, err
}
if len(errs) == 0 {
data = append(data, imgData[0])
continue
}
volumeData, errs, err := i.containerEngine.VolumeInspect(ctx, []string{name}, i.options)
if err != nil {
return nil, nil, err
}
if len(errs) == 0 {
data = append(data, volumeData[0])
continue
}
networkData, errs, err := registry.ContainerEngine().NetworkInspect(ctx, namesOrIDs, i.options)
if err != nil {
return nil, nil, err
}
if len(errs) == 0 {
data = append(data, networkData[0])
continue
}
i.podOptions.NameOrID = name
podData, err := i.containerEngine.PodInspect(ctx, i.podOptions)
if err != nil {
cause := errors.Cause(err)
if !strings.Contains(cause.Error(), define.ErrNoSuchPod.Error()) {
return nil, nil, err
}
} else {
data = append(data, podData)
continue
}
if len(errs) > 0 {
allErrs = append(allErrs, errors.Errorf("no such object: %q", name))
continue
}
data = append(data, imgData[0])
}
return data, allErrs, nil
}

View File

@ -1,13 +1,7 @@
package network
import (
"encoding/json"
"fmt"
"os"
"text/tabwriter"
"text/template"
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v2/cmd/podman/inspect"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/spf13/cobra"
@ -23,10 +17,7 @@ var (
Example: `podman network inspect podman`,
Args: cobra.MinimumNArgs(1),
}
)
var (
networkInspectOptions entities.NetworkInspectOptions
inspectOpts *entities.InspectOptions
)
func init() {
@ -35,36 +26,13 @@ func init() {
Command: networkinspectCommand,
Parent: networkCmd,
})
inspectOpts = new(entities.InspectOptions)
flags := networkinspectCommand.Flags()
flags.StringVarP(&networkInspectOptions.Format, "format", "f", "", "Pretty-print network to JSON or using a Go template")
flags.StringVarP(&inspectOpts.Format, "format", "f", "", "Pretty-print network to JSON or using a Go template")
}
func networkInspect(_ *cobra.Command, args []string) error {
responses, err := registry.ContainerEngine().NetworkInspect(registry.Context(), args, entities.NetworkInspectOptions{})
if err != nil {
return err
}
inspectOpts.Type = inspect.NetworkType
return inspect.Inspect(args, *inspectOpts)
switch {
case report.IsJSON(networkInspectOptions.Format) || networkInspectOptions.Format == "":
b, err := json.MarshalIndent(responses, "", " ")
if err != nil {
return err
}
fmt.Println(string(b))
default:
row := report.NormalizeFormat(networkInspectOptions.Format)
// There can be more than 1 in the inspect output.
row = "{{range . }}" + row + "{{end}}"
tmpl, err := template.New("inspectNetworks").Parse(row)
if err != nil {
return err
}
w := tabwriter.NewWriter(os.Stdout, 8, 2, 0, ' ', 0)
defer w.Flush()
return tmpl.Execute(w, responses)
}
return nil
}

View File

@ -1,16 +1,11 @@
package volumes
import (
"fmt"
"os"
"text/template"
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v2/cmd/podman/inspect"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)
var (
@ -21,7 +16,7 @@ var (
Use: "inspect [options] VOLUME [VOLUME...]",
Short: "Display detailed information on one or more volumes",
Long: volumeInspectDescription,
RunE: inspect,
RunE: volumeInspect,
Example: `podman volume inspect myvol
podman volume inspect --all
podman volume inspect --format "{{.Driver}} {{.Scope}}" myvol`,
@ -29,8 +24,7 @@ var (
)
var (
inspectOpts = entities.VolumeInspectOptions{}
inspectFormat string
inspectOpts *entities.InspectOptions
)
func init() {
@ -39,34 +33,16 @@ func init() {
Command: inspectCommand,
Parent: volumeCmd,
})
inspectOpts = new(entities.InspectOptions)
flags := inspectCommand.Flags()
flags.BoolVarP(&inspectOpts.All, "all", "a", false, "Inspect all volumes")
flags.StringVarP(&inspectFormat, "format", "f", "json", "Format volume output using Go template")
flags.StringVarP(&inspectOpts.Format, "format", "f", "json", "Format volume output using Go template")
}
func inspect(cmd *cobra.Command, args []string) error {
func volumeInspect(cmd *cobra.Command, args []string) error {
if (inspectOpts.All && len(args) > 0) || (!inspectOpts.All && len(args) < 1) {
return errors.New("provide one or more volume names or use --all")
}
responses, err := registry.ContainerEngine().VolumeInspect(context.Background(), args, inspectOpts)
if err != nil {
return err
}
switch {
case report.IsJSON(inspectFormat), inspectFormat == "":
jsonOut, err := json.MarshalIndent(responses, "", " ")
if err != nil {
return errors.Wrapf(err, "error marshalling inspect JSON")
}
fmt.Println(string(jsonOut))
default:
row := "{{range . }}" + report.NormalizeFormat(inspectFormat) + "{{end}}"
tmpl, err := template.New("volumeInspect").Parse(row)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, responses)
}
return nil
inspectOpts.Type = inspect.VolumeType
return inspect.Inspect(args, *inspectOpts)
}

View File

@ -1,7 +1,7 @@
% podman-inspect(1)
## NAME
podman\-inspect - Display a container or image's configuration
podman\-inspect - Display a container, image, volume, network, or pod's configuration
## SYNOPSIS
**podman inspect** [*options*] *name* [...]
@ -9,8 +9,9 @@ podman\-inspect - Display a container or image's configuration
## 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.
all results in a JSON array. If the inspect type is all, the order of inspection is: containers, images, volumes, network, pods.
So, if a container has the same name as an image, then the container JSON will be returned, and so on.
If a format is specified, the given template will be executed for each result.
For more inspection options, see:
@ -25,7 +26,7 @@ For more inspection options, see:
**--type**, **-t**=*type*
Return JSON for the specified type. Type can be 'container', 'image' or 'all' (default: all)
Return JSON for the specified type. Type can be 'container', 'image', 'volume', 'network', 'pod', or 'all' (default: all)
(Only meaningful when invoked as *podman inspect*)
**--format**, **-f**=*format*
@ -38,6 +39,8 @@ The keys of the returned JSON can be used as the values for the --format flag (s
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
This option can be used to inspect the latest pod created when used with --type pod
The latest option is not supported on the remote client or when invoked as *podman image inspect*.
**--size**, **-s**
@ -148,6 +151,20 @@ podman container inspect --latest --format {{.EffectiveCaps}}
[CAP_CHOWN CAP_DAC_OVERRIDE CAP_FSETID CAP_FOWNER CAP_MKNOD CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SETFCAP CAP_SETPCAP CAP_NET_BIND_SERVICE CAP_SYS_CHROOT CAP_KILL CAP_AUDIT_WRITE]
```
```
# podman inspect myPod --type pod --format "{{.Name}}"
myPod
```
```
# podman inspect myVolume --type volume --format "{{.Name}}"
myVolume
```
```
# podman inspect nyNetwork --type network --format "{{.name}}"
myNetwork
```
## SEE ALSO
podman(1)

View File

@ -220,7 +220,7 @@ the exit codes follow the `chroot` standard, see below:
| [podman-import(1)](podman-import.1.md) | Import a tarball and save it as a filesystem image. |
| [podman-info(1)](podman-info.1.md) | Displays Podman related system information. |
| [podman-init(1)](podman-init.1.md) | Initialize one or more containers |
| [podman-inspect(1)](podman-inspect.1.md) | Display a container or image's configuration. |
| [podman-inspect(1)](podman-inspect.1.md) | Display a container, image, volume, network, or pod's configuration. |
| [podman-kill(1)](podman-kill.1.md) | Kill the main process in one or more containers. |
| [podman-load(1)](podman-load.1.md) | Load an image from a container image archive into container storage. |
| [podman-login(1)](podman-login.1.md) | Login to a container registry. |

1
go.mod
View File

@ -63,7 +63,6 @@ require (
github.com/vishvananda/netlink v1.1.0
go.etcd.io/bbolt v1.3.5
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f

View File

@ -113,15 +113,15 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
return
}
name := utils.GetName(r)
options := entities.NetworkInspectOptions{}
options := entities.InspectOptions{}
ic := abi.ContainerEngine{Libpod: runtime}
reports, err := ic.NetworkInspect(r.Context(), []string{name}, options)
if err != nil {
reports, errs, err := ic.NetworkInspect(r.Context(), []string{name}, options)
// If the network cannot be found, we return a 404.
if errors.Cause(err) == define.ErrNoSuchNetwork {
utils.Error(w, "Something went wrong", http.StatusNotFound, err)
if len(errs) > 0 {
utils.Error(w, "Something went wrong", http.StatusNotFound, define.ErrNoSuchNetwork)
return
}
if err != nil {
utils.InternalServerError(w, err)
return
}

View File

@ -51,7 +51,7 @@ type ContainerEngine interface {
HealthCheckRun(ctx context.Context, nameOrID string, options HealthCheckOptions) (*define.HealthCheckResults, error)
Info(ctx context.Context) (*define.Info, error)
NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (*NetworkCreateReport, error)
NetworkInspect(ctx context.Context, namesOrIds []string, options NetworkInspectOptions) ([]NetworkInspectReport, error)
NetworkInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]NetworkInspectReport, []error, error)
NetworkList(ctx context.Context, options NetworkListOptions) ([]*NetworkListReport, error)
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error)
@ -76,7 +76,7 @@ type ContainerEngine interface {
VarlinkService(ctx context.Context, opts ServiceOptions) error
Version(ctx context.Context) (*SystemVersionReport, error)
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error)
VolumeInspect(ctx context.Context, namesOrIds []string, opts VolumeInspectOptions) ([]*VolumeInspectReport, error)
VolumeInspect(ctx context.Context, namesOrIds []string, opts InspectOptions) ([]*VolumeInspectReport, []error, error)
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
VolumePrune(ctx context.Context) ([]*VolumePruneReport, error)
VolumeRm(ctx context.Context, namesOrIds []string, opts VolumeRmOptions) ([]*VolumeRmReport, error)

View File

@ -18,11 +18,6 @@ type NetworkListReport struct {
*libcni.NetworkConfigList
}
// NetworkInspectOptions describes options for inspect networks
type NetworkInspectOptions struct {
Format string
}
// NetworkInspectReport describes the results from inspect networks
type NetworkInspectReport map[string]interface{}

View File

@ -56,6 +56,8 @@ type InspectOptions struct {
Size bool `json:",omitempty"`
// Type -- return JSON for specified type.
Type string `json:",omitempty"`
// All -- inspect all
All bool `json:",omitempty"`
}
// All API and CLI diff commands and diff sub-commands use the same options

View File

@ -105,10 +105,6 @@ type VolumeRmReport struct {
Id string //nolint
}
type VolumeInspectOptions struct {
All bool
}
type VolumeInspectReport struct {
*VolumeConfigResponse
}

View File

@ -43,21 +43,26 @@ func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.Net
return reports, nil
}
func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.NetworkInspectOptions) ([]entities.NetworkInspectReport, error) {
func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) {
config, err := ic.Libpod.GetConfig()
if err != nil {
return nil, err
return nil, nil, err
}
var errs []error
rawCNINetworks := make([]entities.NetworkInspectReport, 0, len(namesOrIds))
for _, name := range namesOrIds {
rawList, err := network.InspectNetwork(config, name)
if err != nil {
return nil, err
if errors.Cause(err) == define.ErrNoSuchNetwork {
errs = append(errs, errors.Errorf("no such network %s", name))
continue
} else {
return nil, nil, errors.Wrapf(err, "error inspecting network %s", name)
}
}
rawCNINetworks = append(rawCNINetworks, rawList)
}
return rawCNINetworks, nil
return rawCNINetworks, errs, nil
}
func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
@ -71,9 +72,10 @@ func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, op
return reports, nil
}
func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.VolumeInspectOptions) ([]*entities.VolumeInspectReport, error) {
func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]*entities.VolumeInspectReport, []error, error) {
var (
err error
errs []error
vols []*libpod.Volume
)
@ -82,13 +84,18 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
if opts.All {
vols, err = ic.Libpod.GetAllVolumes()
if err != nil {
return nil, err
return nil, nil, err
}
} else {
for _, v := range namesOrIds {
vol, err := ic.Libpod.LookupVolume(v)
if err != nil {
return nil, errors.Wrapf(err, "error inspecting volume %s", v)
if errors.Cause(err) == define.ErrNoSuchVolume {
errs = append(errs, errors.Errorf("no such volume %s", v))
continue
} else {
return nil, nil, errors.Wrapf(err, "error inspecting volume %s", v)
}
}
vols = append(vols, vol)
}
@ -98,11 +105,11 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
var uid, gid int
uid, err = v.UID()
if err != nil {
return nil, err
return nil, nil, err
}
gid, err = v.GID()
if err != nil {
return nil, err
return nil, nil, err
}
config := entities.VolumeConfigResponse{
Name: v.Name(),
@ -117,7 +124,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
}
reports = append(reports, &entities.VolumeInspectReport{VolumeConfigResponse: &config})
}
return reports, nil
return reports, errs, nil
}
func (ic *ContainerEngine) VolumePrune(ctx context.Context) ([]*entities.VolumePruneReport, error) {

View File

@ -5,22 +5,34 @@ import (
"github.com/containers/podman/v2/pkg/bindings/network"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/pkg/errors"
)
func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.NetworkListOptions) ([]*entities.NetworkListReport, error) {
return network.List(ic.ClientCxt, options)
}
func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.NetworkInspectOptions) ([]entities.NetworkInspectReport, error) {
reports := make([]entities.NetworkInspectReport, 0, len(namesOrIds))
func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) {
var (
reports = make([]entities.NetworkInspectReport, 0, len(namesOrIds))
errs = []error{}
)
for _, name := range namesOrIds {
report, err := network.Inspect(ic.ClientCxt, name)
if err != nil {
return nil, err
errModel, ok := err.(entities.ErrorModel)
if !ok {
return nil, nil, err
}
if errModel.ResponseCode == 404 {
errs = append(errs, errors.Errorf("no such network %q", name))
continue
}
return nil, nil, err
}
reports = append(reports, report...)
}
return reports, nil
return reports, errs, nil
}
func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {

View File

@ -5,6 +5,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings/volumes"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/pkg/errors"
)
func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.VolumeCreateOptions) (*entities.IDOrNameResponse, error) {
@ -35,25 +36,36 @@ func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, op
return reports, nil
}
func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.VolumeInspectOptions) ([]*entities.VolumeInspectReport, error) {
func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]*entities.VolumeInspectReport, []error, error) {
var (
reports = make([]*entities.VolumeInspectReport, 0, len(namesOrIds))
errs = []error{}
)
if opts.All {
vols, err := volumes.List(ic.ClientCxt, nil)
if err != nil {
return nil, err
return nil, nil, err
}
for _, v := range vols {
namesOrIds = append(namesOrIds, v.Name)
}
}
reports := make([]*entities.VolumeInspectReport, 0, len(namesOrIds))
for _, id := range namesOrIds {
data, err := volumes.Inspect(ic.ClientCxt, id)
if err != nil {
return nil, err
errModel, ok := err.(entities.ErrorModel)
if !ok {
return nil, nil, err
}
if errModel.ResponseCode == 404 {
errs = append(errs, errors.Errorf("no such volume %q", id))
continue
}
return nil, nil, err
}
reports = append(reports, &entities.VolumeInspectReport{VolumeConfigResponse: data})
}
return reports, nil
return reports, errs, nil
}
func (ic *ContainerEngine) VolumePrune(ctx context.Context) ([]*entities.VolumePruneReport, error) {

View File

@ -515,6 +515,14 @@ func (s *PodmanSessionIntegration) InspectPodToJSON() define.InspectPodData {
return i
}
// InspectPodToJSON takes the sessions output from an inspect and returns json
func (s *PodmanSessionIntegration) InspectPodArrToJSON() []define.InspectPodData {
var i []define.InspectPodData
err := jsoniter.Unmarshal(s.Out.Contents(), &i)
Expect(err).To(BeNil())
return i
}
// CreatePod creates a pod with no infra container
// it optionally takes a pod name
func (p *PodmanTestIntegration) CreatePod(name string) (*PodmanSessionIntegration, int, string) {

View File

@ -289,4 +289,145 @@ var _ = Describe("Podman inspect", func() {
Expect(baseJSON[0].HostConfig.SecurityOpt).To(Equal([]string{"label=type:spc_t,label=level:s0", "seccomp=unconfined"}))
})
It("podman inspect pod", func() {
podName := "testpod"
create := podmanTest.PodmanNoCache([]string{"pod", "create", "--name", podName})
create.WaitWithDefaultTimeout()
Expect(create.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"inspect", podName})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
Expect(inspect.IsJSONOutputValid()).To(BeTrue())
podData := inspect.InspectPodArrToJSON()
Expect(podData[0].Name).To(Equal(podName))
})
It("podman inspect pod with type", func() {
podName := "testpod"
create := podmanTest.PodmanNoCache([]string{"pod", "create", "--name", podName})
create.WaitWithDefaultTimeout()
Expect(create.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"inspect", "--type", "pod", podName})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
Expect(inspect.IsJSONOutputValid()).To(BeTrue())
podData := inspect.InspectPodArrToJSON()
Expect(podData[0].Name).To(Equal(podName))
})
It("podman inspect latest pod", func() {
SkipIfRemote("--latest flag n/a")
podName := "testpod"
create := podmanTest.PodmanNoCache([]string{"pod", "create", "--name", podName})
create.WaitWithDefaultTimeout()
Expect(create.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"inspect", "--type", "pod", "--latest"})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
Expect(inspect.IsJSONOutputValid()).To(BeTrue())
podData := inspect.InspectPodArrToJSON()
Expect(podData[0].Name).To(Equal(podName))
})
It("podman inspect latest defaults to latest container", func() {
SkipIfRemote("--latest flag n/a")
podName := "testpod"
pod := podmanTest.PodmanNoCache([]string{"pod", "create", "--name", podName})
pod.WaitWithDefaultTimeout()
Expect(pod.ExitCode()).To(Equal(0))
inspect1 := podmanTest.Podman([]string{"inspect", "--type", "pod", podName})
inspect1.WaitWithDefaultTimeout()
Expect(inspect1.ExitCode()).To(Equal(0))
Expect(inspect1.IsJSONOutputValid()).To(BeTrue())
podData := inspect1.InspectPodArrToJSON()
infra := podData[0].Containers[0].Name
inspect := podmanTest.Podman([]string{"inspect", "--latest"})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
Expect(inspect.IsJSONOutputValid()).To(BeTrue())
containerData := inspect.InspectContainerToJSON()
Expect(containerData[0].Name).To(Equal(infra))
})
It("podman inspect network", func() {
name, path := generateNetworkConfig(podmanTest)
defer removeConf(path)
session := podmanTest.Podman([]string{"inspect", name, "--format", "{{.cniVersion}}"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.LineInOutputContains("0.3.0")).To(BeTrue())
})
It("podman inspect a volume", func() {
session := podmanTest.Podman([]string{"volume", "create", "myvol"})
session.WaitWithDefaultTimeout()
volName := session.OutputToString()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"inspect", volName})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.IsJSONOutputValid()).To(BeTrue())
})
It("podman inspect a volume with --format", func() {
session := podmanTest.Podman([]string{"volume", "create", "myvol"})
session.WaitWithDefaultTimeout()
volName := session.OutputToString()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"inspect", "--format", "{{.Name}}", volName})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal(volName))
})
It("podman inspect --type container on a pod should fail", func() {
podName := "testpod"
create := podmanTest.PodmanNoCache([]string{"pod", "create", "--name", podName})
create.WaitWithDefaultTimeout()
Expect(create.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"inspect", "--type", "container", podName})
inspect.WaitWithDefaultTimeout()
Expect(inspect).To(ExitWithError())
})
It("podman inspect --type network on a container should fail", func() {
ctrName := "testctr"
create := podmanTest.PodmanNoCache([]string{"create", "--name", ctrName, ALPINE})
create.WaitWithDefaultTimeout()
Expect(create.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"inspect", "--type", "network", ctrName})
inspect.WaitWithDefaultTimeout()
Expect(inspect).To(ExitWithError())
})
It("podman inspect --type pod on a container should fail", func() {
ctrName := "testctr"
create := podmanTest.PodmanNoCache([]string{"create", "--name", ctrName, ALPINE})
create.WaitWithDefaultTimeout()
Expect(create.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"inspect", "--type", "pod", ctrName})
inspect.WaitWithDefaultTimeout()
Expect(inspect).To(ExitWithError())
})
It("podman inspect --type volume on a container should fail", func() {
ctrName := "testctr"
create := podmanTest.PodmanNoCache([]string{"create", "--name", ctrName, ALPINE})
create.WaitWithDefaultTimeout()
Expect(create.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"inspect", "--type", "volume", ctrName})
inspect.WaitWithDefaultTimeout()
Expect(inspect).To(ExitWithError())
})
})