github.com/containerd/nerdctl@v1.7.7/cmd/nerdctl/inspect.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	"github.com/containerd/nerdctl/pkg/api/types"
    24  	"github.com/containerd/nerdctl/pkg/clientutil"
    25  	"github.com/containerd/nerdctl/pkg/cmd/container"
    26  	"github.com/containerd/nerdctl/pkg/cmd/image"
    27  	"github.com/containerd/nerdctl/pkg/idutil/containerwalker"
    28  	"github.com/containerd/nerdctl/pkg/idutil/imagewalker"
    29  
    30  	"github.com/spf13/cobra"
    31  )
    32  
    33  func newInspectCommand() *cobra.Command {
    34  	var inspectCommand = &cobra.Command{
    35  		Use:               "inspect",
    36  		Short:             "Return low-level information on objects.",
    37  		Args:              cobra.MinimumNArgs(1),
    38  		RunE:              inspectAction,
    39  		ValidArgsFunction: inspectShellComplete,
    40  		SilenceUsage:      true,
    41  		SilenceErrors:     true,
    42  	}
    43  
    44  	addInspectFlags(inspectCommand)
    45  
    46  	return inspectCommand
    47  }
    48  
    49  var validInspectType = map[string]bool{
    50  	"container": true,
    51  	"image":     true,
    52  }
    53  
    54  func addInspectFlags(cmd *cobra.Command) {
    55  	cmd.Flags().StringP("format", "f", "", "Format the output using the given Go template, e.g, '{{json .}}'")
    56  	cmd.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
    57  		return []string{"json"}, cobra.ShellCompDirectiveNoFileComp
    58  	})
    59  	cmd.Flags().String("type", "", "Return JSON for specified type")
    60  	cmd.RegisterFlagCompletionFunc("type", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
    61  		return []string{"image", "container", ""}, cobra.ShellCompDirectiveNoFileComp
    62  	})
    63  	cmd.Flags().String("mode", "dockercompat", `Inspect mode, "dockercompat" for Docker-compatible output, "native" for containerd-native output`)
    64  	cmd.RegisterFlagCompletionFunc("mode", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
    65  		return []string{"dockercompat", "native"}, cobra.ShellCompDirectiveNoFileComp
    66  	})
    67  }
    68  
    69  func inspectAction(cmd *cobra.Command, args []string) error {
    70  	globalOptions, err := processRootCmdFlags(cmd)
    71  	if err != nil {
    72  		return err
    73  	}
    74  	namespace := globalOptions.Namespace
    75  	address := globalOptions.Address
    76  	inspectType, err := cmd.Flags().GetString("type")
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	if len(inspectType) > 0 && !validInspectType[inspectType] {
    82  		return fmt.Errorf("%q is not a valid value for --type", inspectType)
    83  	}
    84  
    85  	// container and image inspect can share the same client, since no `platform`
    86  	// flag will be passed for image inspect.
    87  	client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), namespace, address)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	defer cancel()
    92  
    93  	imagewalker := &imagewalker.ImageWalker{
    94  		Client: client,
    95  		OnFound: func(ctx context.Context, found imagewalker.Found) error {
    96  			return nil
    97  		},
    98  	}
    99  
   100  	containerwalker := &containerwalker.ContainerWalker{
   101  		Client: client,
   102  		OnFound: func(ctx context.Context, found containerwalker.Found) error {
   103  			return nil
   104  		},
   105  	}
   106  
   107  	inspectImage := len(inspectType) == 0 || inspectType == "image"
   108  	inspectContainer := len(inspectType) == 0 || inspectType == "container"
   109  
   110  	var imageInspectOptions types.ImageInspectOptions
   111  	var containerInspectOptions types.ContainerInspectOptions
   112  	if inspectImage {
   113  		platform := ""
   114  		imageInspectOptions, err = processImageInspectOptions(cmd, &platform)
   115  		if err != nil {
   116  			return err
   117  		}
   118  	}
   119  	if inspectContainer {
   120  		containerInspectOptions, err = processContainerInspectOptions(cmd)
   121  		if err != nil {
   122  			return err
   123  		}
   124  	}
   125  
   126  	var errs []error
   127  	for _, req := range args {
   128  		var ni int
   129  		var nc int
   130  
   131  		if inspectImage {
   132  			ni, err = imagewalker.Walk(ctx, req)
   133  			if err != nil {
   134  				return err
   135  			}
   136  		}
   137  		if inspectContainer {
   138  			nc, err = containerwalker.Walk(ctx, req)
   139  			if err != nil {
   140  				return err
   141  			}
   142  		}
   143  
   144  		if ni == 0 && nc == 0 {
   145  			errs = append(errs, fmt.Errorf("no such object %s", req))
   146  		} else if ni > 0 {
   147  			if err := image.Inspect(ctx, client, []string{req}, imageInspectOptions); err != nil {
   148  				errs = append(errs, err)
   149  			}
   150  		} else if nc > 0 {
   151  			if err := container.Inspect(ctx, client, []string{req}, containerInspectOptions); err != nil {
   152  				errs = append(errs, err)
   153  			}
   154  		}
   155  	}
   156  
   157  	if len(errs) > 0 {
   158  		return fmt.Errorf("%d errors: %v", len(errs), errs)
   159  	}
   160  
   161  	return nil
   162  }
   163  
   164  func inspectShellComplete(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
   165  	// show container names
   166  	containers, _ := shellCompleteContainerNames(cmd, nil)
   167  	// show image names
   168  	images, _ := shellCompleteImageNames(cmd)
   169  	return append(containers, images...), cobra.ShellCompDirectiveNoFileComp
   170  }