github.1git.de/docker/cli@v26.1.3+incompatible/cli/command/system/inspect.go (about)

     1  // FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
     2  //go:build go1.19
     3  
     4  package system
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"strings"
    10  
    11  	"github.com/docker/cli/cli"
    12  	"github.com/docker/cli/cli/command"
    13  	"github.com/docker/cli/cli/command/inspect"
    14  	flagsHelper "github.com/docker/cli/cli/flags"
    15  	"github.com/docker/docker/api/types"
    16  	"github.com/docker/docker/errdefs"
    17  	"github.com/pkg/errors"
    18  	"github.com/spf13/cobra"
    19  )
    20  
    21  type inspectOptions struct {
    22  	format      string
    23  	inspectType string
    24  	size        bool
    25  	ids         []string
    26  }
    27  
    28  // NewInspectCommand creates a new cobra.Command for `docker inspect`
    29  func NewInspectCommand(dockerCli command.Cli) *cobra.Command {
    30  	var opts inspectOptions
    31  
    32  	cmd := &cobra.Command{
    33  		Use:   "inspect [OPTIONS] NAME|ID [NAME|ID...]",
    34  		Short: "Return low-level information on Docker objects",
    35  		Args:  cli.RequiresMinArgs(1),
    36  		RunE: func(cmd *cobra.Command, args []string) error {
    37  			opts.ids = args
    38  			return runInspect(cmd.Context(), dockerCli, opts)
    39  		},
    40  	}
    41  
    42  	flags := cmd.Flags()
    43  	flags.StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp)
    44  	flags.StringVar(&opts.inspectType, "type", "", "Return JSON for specified type")
    45  	flags.BoolVarP(&opts.size, "size", "s", false, "Display total file sizes if the type is container")
    46  
    47  	return cmd
    48  }
    49  
    50  func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error {
    51  	var elementSearcher inspect.GetRefFunc
    52  	switch opts.inspectType {
    53  	case "", "container", "image", "node", "network", "service", "volume", "task", "plugin", "secret":
    54  		elementSearcher = inspectAll(ctx, dockerCli, opts.size, opts.inspectType)
    55  	default:
    56  		return errors.Errorf("%q is not a valid value for --type", opts.inspectType)
    57  	}
    58  	return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, elementSearcher)
    59  }
    60  
    61  func inspectContainers(ctx context.Context, dockerCli command.Cli, getSize bool) inspect.GetRefFunc {
    62  	return func(ref string) (any, []byte, error) {
    63  		return dockerCli.Client().ContainerInspectWithRaw(ctx, ref, getSize)
    64  	}
    65  }
    66  
    67  func inspectImages(ctx context.Context, dockerCli command.Cli) inspect.GetRefFunc {
    68  	return func(ref string) (any, []byte, error) {
    69  		return dockerCli.Client().ImageInspectWithRaw(ctx, ref)
    70  	}
    71  }
    72  
    73  func inspectNetwork(ctx context.Context, dockerCli command.Cli) inspect.GetRefFunc {
    74  	return func(ref string) (any, []byte, error) {
    75  		return dockerCli.Client().NetworkInspectWithRaw(ctx, ref, types.NetworkInspectOptions{})
    76  	}
    77  }
    78  
    79  func inspectNode(ctx context.Context, dockerCli command.Cli) inspect.GetRefFunc {
    80  	return func(ref string) (any, []byte, error) {
    81  		return dockerCli.Client().NodeInspectWithRaw(ctx, ref)
    82  	}
    83  }
    84  
    85  func inspectService(ctx context.Context, dockerCli command.Cli) inspect.GetRefFunc {
    86  	return func(ref string) (any, []byte, error) {
    87  		// Service inspect shows defaults values in empty fields.
    88  		return dockerCli.Client().ServiceInspectWithRaw(ctx, ref, types.ServiceInspectOptions{InsertDefaults: true})
    89  	}
    90  }
    91  
    92  func inspectTasks(ctx context.Context, dockerCli command.Cli) inspect.GetRefFunc {
    93  	return func(ref string) (any, []byte, error) {
    94  		return dockerCli.Client().TaskInspectWithRaw(ctx, ref)
    95  	}
    96  }
    97  
    98  func inspectVolume(ctx context.Context, dockerCli command.Cli) inspect.GetRefFunc {
    99  	return func(ref string) (any, []byte, error) {
   100  		return dockerCli.Client().VolumeInspectWithRaw(ctx, ref)
   101  	}
   102  }
   103  
   104  func inspectPlugin(ctx context.Context, dockerCli command.Cli) inspect.GetRefFunc {
   105  	return func(ref string) (any, []byte, error) {
   106  		return dockerCli.Client().PluginInspectWithRaw(ctx, ref)
   107  	}
   108  }
   109  
   110  func inspectSecret(ctx context.Context, dockerCli command.Cli) inspect.GetRefFunc {
   111  	return func(ref string) (any, []byte, error) {
   112  		return dockerCli.Client().SecretInspectWithRaw(ctx, ref)
   113  	}
   114  }
   115  
   116  func inspectAll(ctx context.Context, dockerCli command.Cli, getSize bool, typeConstraint string) inspect.GetRefFunc {
   117  	inspectAutodetect := []struct {
   118  		objectType      string
   119  		isSizeSupported bool
   120  		isSwarmObject   bool
   121  		objectInspector func(string) (any, []byte, error)
   122  	}{
   123  		{
   124  			objectType:      "container",
   125  			isSizeSupported: true,
   126  			objectInspector: inspectContainers(ctx, dockerCli, getSize),
   127  		},
   128  		{
   129  			objectType:      "image",
   130  			objectInspector: inspectImages(ctx, dockerCli),
   131  		},
   132  		{
   133  			objectType:      "network",
   134  			objectInspector: inspectNetwork(ctx, dockerCli),
   135  		},
   136  		{
   137  			objectType:      "volume",
   138  			objectInspector: inspectVolume(ctx, dockerCli),
   139  		},
   140  		{
   141  			objectType:      "service",
   142  			isSwarmObject:   true,
   143  			objectInspector: inspectService(ctx, dockerCli),
   144  		},
   145  		{
   146  			objectType:      "task",
   147  			isSwarmObject:   true,
   148  			objectInspector: inspectTasks(ctx, dockerCli),
   149  		},
   150  		{
   151  			objectType:      "node",
   152  			isSwarmObject:   true,
   153  			objectInspector: inspectNode(ctx, dockerCli),
   154  		},
   155  		{
   156  			objectType:      "plugin",
   157  			objectInspector: inspectPlugin(ctx, dockerCli),
   158  		},
   159  		{
   160  			objectType:      "secret",
   161  			isSwarmObject:   true,
   162  			objectInspector: inspectSecret(ctx, dockerCli),
   163  		},
   164  	}
   165  
   166  	// isSwarmManager does an Info API call to verify that the daemon is
   167  	// a swarm manager.
   168  	isSwarmManager := func() bool {
   169  		info, err := dockerCli.Client().Info(ctx)
   170  		if err != nil {
   171  			fmt.Fprintln(dockerCli.Err(), err)
   172  			return false
   173  		}
   174  		return info.Swarm.ControlAvailable
   175  	}
   176  
   177  	return func(ref string) (any, []byte, error) {
   178  		const (
   179  			swarmSupportUnknown = iota
   180  			swarmSupported
   181  			swarmUnsupported
   182  		)
   183  
   184  		isSwarmSupported := swarmSupportUnknown
   185  
   186  		for _, inspectData := range inspectAutodetect {
   187  			if typeConstraint != "" && inspectData.objectType != typeConstraint {
   188  				continue
   189  			}
   190  			if typeConstraint == "" && inspectData.isSwarmObject {
   191  				if isSwarmSupported == swarmSupportUnknown {
   192  					if isSwarmManager() {
   193  						isSwarmSupported = swarmSupported
   194  					} else {
   195  						isSwarmSupported = swarmUnsupported
   196  					}
   197  				}
   198  				if isSwarmSupported == swarmUnsupported {
   199  					continue
   200  				}
   201  			}
   202  			v, raw, err := inspectData.objectInspector(ref)
   203  			if err != nil {
   204  				if typeConstraint == "" && isErrSkippable(err) {
   205  					continue
   206  				}
   207  				return v, raw, err
   208  			}
   209  			if getSize && !inspectData.isSizeSupported {
   210  				fmt.Fprintf(dockerCli.Err(), "WARNING: --size ignored for %s\n", inspectData.objectType)
   211  			}
   212  			return v, raw, err
   213  		}
   214  		return nil, nil, errors.Errorf("Error: No such object: %s", ref)
   215  	}
   216  }
   217  
   218  func isErrSkippable(err error) bool {
   219  	return errdefs.IsNotFound(err) ||
   220  		strings.Contains(err.Error(), "not supported") ||
   221  		strings.Contains(err.Error(), "invalid reference format")
   222  }