github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podman/inspect.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  
     7  	"github.com/containers/buildah/pkg/formats"
     8  	"github.com/containers/libpod/cmd/podman/cliconfig"
     9  	"github.com/containers/libpod/pkg/adapter"
    10  	"github.com/containers/libpod/pkg/util"
    11  	"github.com/pkg/errors"
    12  	"github.com/spf13/cobra"
    13  )
    14  
    15  const (
    16  	inspectTypeContainer = "container"
    17  	inspectTypeImage     = "image"
    18  	inspectAll           = "all"
    19  )
    20  
    21  var (
    22  	inspectCommand cliconfig.InspectValues
    23  
    24  	inspectDescription = `This displays the low-level information on containers and images identified by name or ID.
    25  
    26    If given a name that matches both a container and an image, this command inspects the container.  By default, this will render all results in a JSON array.`
    27  	_inspectCommand = cobra.Command{
    28  		Use:   "inspect [flags] CONTAINER | IMAGE",
    29  		Short: "Display the configuration of a container or image",
    30  		Long:  inspectDescription,
    31  		RunE: func(cmd *cobra.Command, args []string) error {
    32  			inspectCommand.InputArgs = args
    33  			inspectCommand.GlobalFlags = MainGlobalOpts
    34  			inspectCommand.Remote = remoteclient
    35  			return inspectCmd(&inspectCommand)
    36  		},
    37  		Example: `podman inspect alpine
    38    podman inspect --format "imageId: {{.Id}} size: {{.Size}}" alpine
    39    podman inspect --format "image: {{.ImageName}} driver: {{.Driver}}" myctr`,
    40  	}
    41  )
    42  
    43  func inspectInit(command *cliconfig.InspectValues) {
    44  	command.SetHelpTemplate(HelpTemplate())
    45  	command.SetUsageTemplate(UsageTemplate())
    46  	flags := command.Flags()
    47  	flags.StringVarP(&command.Format, "format", "f", "", "Change the output format to a Go template")
    48  
    49  	// -t flag applicable only to 'podman inspect', not 'image/container inspect'
    50  	ambiguous := strings.Contains(command.Use, "|")
    51  	if ambiguous {
    52  		flags.StringVarP(&command.TypeObject, "type", "t", inspectAll, "Return JSON for specified type, (image or container)")
    53  	}
    54  
    55  	if strings.Contains(command.Use, "CONTAINER") {
    56  		containers_only := " (containers only)"
    57  		if !ambiguous {
    58  			containers_only = ""
    59  			command.TypeObject = inspectTypeContainer
    60  		}
    61  		flags.BoolVarP(&command.Latest, "latest", "l", false, "Act on the latest container podman is aware of"+containers_only)
    62  		flags.BoolVarP(&command.Size, "size", "s", false, "Display total file size"+containers_only)
    63  		markFlagHiddenForRemoteClient("latest", flags)
    64  	} else {
    65  		command.TypeObject = inspectTypeImage
    66  	}
    67  }
    68  func init() {
    69  	inspectCommand.Command = &_inspectCommand
    70  	inspectInit(&inspectCommand)
    71  }
    72  
    73  func inspectCmd(c *cliconfig.InspectValues) error {
    74  	args := c.InputArgs
    75  	inspectType := c.TypeObject
    76  	latestContainer := c.Latest
    77  	if len(args) == 0 && !latestContainer {
    78  		return errors.Errorf("container or image name must be specified: podman inspect [options [...]] name")
    79  	}
    80  
    81  	if len(args) > 0 && latestContainer {
    82  		return errors.Errorf("you cannot provide additional arguments with --latest")
    83  	}
    84  
    85  	runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
    86  	if err != nil {
    87  		return errors.Wrapf(err, "error creating libpod runtime")
    88  	}
    89  	defer runtime.DeferredShutdown(false)
    90  
    91  	if !util.StringInSlice(inspectType, []string{inspectTypeContainer, inspectTypeImage, inspectAll}) {
    92  		return errors.Errorf("the only recognized types are %q, %q, and %q", inspectTypeContainer, inspectTypeImage, inspectAll)
    93  	}
    94  
    95  	outputFormat := c.Format
    96  	if strings.Contains(outputFormat, "{{.Id}}") {
    97  		outputFormat = strings.Replace(outputFormat, "{{.Id}}", formats.IDString, -1)
    98  	}
    99  	// These fields were renamed, so we need to provide backward compat for
   100  	// the old names.
   101  	if strings.Contains(outputFormat, ".Src") {
   102  		outputFormat = strings.Replace(outputFormat, ".Src", ".Source", -1)
   103  	}
   104  	if strings.Contains(outputFormat, ".Dst") {
   105  		outputFormat = strings.Replace(outputFormat, ".Dst", ".Destination", -1)
   106  	}
   107  	if strings.Contains(outputFormat, ".ImageID") {
   108  		outputFormat = strings.Replace(outputFormat, ".ImageID", ".Image", -1)
   109  	}
   110  	if latestContainer {
   111  		lc, err := runtime.GetLatestContainer()
   112  		if err != nil {
   113  			return err
   114  		}
   115  		args = append(args, lc.ID())
   116  		inspectType = inspectTypeContainer
   117  	}
   118  
   119  	inspectedObjects, iterateErr := iterateInput(getContext(), c.Size, args, runtime, inspectType)
   120  	if iterateErr != nil {
   121  		return iterateErr
   122  	}
   123  
   124  	var out formats.Writer
   125  	if outputFormat != "" && outputFormat != formats.JSONString {
   126  		//template
   127  		out = formats.StdoutTemplateArray{Output: inspectedObjects, Template: outputFormat}
   128  	} else {
   129  		// default is json output
   130  		out = formats.JSONStructArray{Output: inspectedObjects}
   131  	}
   132  
   133  	return out.Out()
   134  }
   135  
   136  // func iterateInput iterates the images|containers the user has requested and returns the inspect data and error
   137  func iterateInput(ctx context.Context, size bool, args []string, runtime *adapter.LocalRuntime, inspectType string) ([]interface{}, error) {
   138  	var (
   139  		data           interface{}
   140  		inspectedItems []interface{}
   141  		inspectError   error
   142  	)
   143  
   144  	for _, input := range args {
   145  		switch inspectType {
   146  		case inspectTypeContainer:
   147  			ctr, err := runtime.LookupContainer(input)
   148  			if err != nil {
   149  				inspectError = errors.Wrapf(err, "error looking up container %q", input)
   150  				break
   151  			}
   152  			data, err = ctr.Inspect(size)
   153  			if err != nil {
   154  				inspectError = errors.Wrapf(err, "error inspecting container %s", ctr.ID())
   155  				break
   156  			}
   157  		case inspectTypeImage:
   158  			image, err := runtime.NewImageFromLocal(input)
   159  			if err != nil {
   160  				inspectError = errors.Wrapf(err, "error getting image %q", input)
   161  				break
   162  			}
   163  			data, err = image.Inspect(ctx)
   164  			if err != nil {
   165  				inspectError = errors.Wrapf(err, "error parsing image data %q", image.ID())
   166  				break
   167  			}
   168  		case inspectAll:
   169  			ctr, err := runtime.LookupContainer(input)
   170  			if err != nil {
   171  				image, err := runtime.NewImageFromLocal(input)
   172  				if err != nil {
   173  					inspectError = errors.Wrapf(err, "error getting image %q", input)
   174  					break
   175  				}
   176  				data, err = image.Inspect(ctx)
   177  				if err != nil {
   178  					inspectError = errors.Wrapf(err, "error parsing image data %q", image.ID())
   179  					break
   180  				}
   181  			} else {
   182  				data, err = ctr.Inspect(size)
   183  				if err != nil {
   184  					inspectError = errors.Wrapf(err, "error inspecting container %s", ctr.ID())
   185  					break
   186  				}
   187  			}
   188  		}
   189  		if inspectError == nil {
   190  			inspectedItems = append(inspectedItems, data)
   191  		}
   192  	}
   193  	return inspectedItems, inspectError
   194  }