Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 64 additions & 21 deletions cli/command/system/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/inspect"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/docker/api/types"
Expand All @@ -20,13 +21,42 @@ import (
"github.com/docker/docker/errdefs"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

type objectType = string

const (
typeConfig objectType = "config"
typeContainer objectType = "container"
typeImage objectType = "image"
typeNetwork objectType = "network"
typeNode objectType = "node"
typePlugin objectType = "plugin"
typeSecret objectType = "secret"
typeService objectType = "service"
typeTask objectType = "task"
typeVolume objectType = "volume"
)

var allTypes = []objectType{
typeConfig,
typeContainer,
typeImage,
typeNetwork,
typeNode,
typePlugin,
typeSecret,
typeService,
typeTask,
typeVolume,
}

type inspectOptions struct {
format string
inspectType string
size bool
ids []string
format string
objectType objectType
size bool
ids []string
}

// NewInspectCommand creates a new cobra.Command for `docker inspect`
Expand All @@ -39,25 +69,38 @@ func NewInspectCommand(dockerCli command.Cli) *cobra.Command {
Args: cli.RequiresMinArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.ids = args
if cmd.Flags().Changed("type") && opts.objectType == "" {
return fmt.Errorf(`type is empty: must be one of "%s"`, strings.Join(allTypes, `", "`))
}
return runInspect(cmd.Context(), dockerCli, opts)
},
// TODO(thaJeztah): should we consider adding completion for common object-types? (images, containers?)
ValidArgsFunction: completion.NoComplete,
}

flags := cmd.Flags()
flags.StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp)
flags.StringVar(&opts.inspectType, "type", "", "Return JSON for specified type")
flags.StringVar(&opts.objectType, "type", "", "Only inspect objects of the given type")
flags.BoolVarP(&opts.size, "size", "s", false, "Display total file sizes if the type is container")

_ = cmd.RegisterFlagCompletionFunc("type", completion.FromList(allTypes...))
flags.VisitAll(func(flag *pflag.Flag) {
// Set a default completion function if none was set. We don't look
// up if it does already have one set, because Cobra does this for
// us, and returns an error (which we ignore for this reason).
_ = cmd.RegisterFlagCompletionFunc(flag.Name, completion.NoComplete)
})
return cmd
}

func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error {
var elementSearcher inspect.GetRefFunc
switch opts.inspectType {
case "", "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume":
elementSearcher = inspectAll(ctx, dockerCli, opts.size, opts.inspectType)
switch opts.objectType {
case "", typeConfig, typeContainer, typeImage, typeNetwork, typeNode,
typePlugin, typeSecret, typeService, typeTask, typeVolume:
elementSearcher = inspectAll(ctx, dockerCli, opts.size, opts.objectType)
default:
return errors.Errorf("%q is not a valid value for --type", opts.inspectType)
return errors.Errorf(`unknown type: %q: must be one of "%s"`, opts.objectType, strings.Join(allTypes, `", "`))
}
return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, elementSearcher)
}
Expand Down Expand Up @@ -128,56 +171,56 @@ func inspectConfig(ctx context.Context, dockerCLI command.Cli) inspect.GetRefFun
}
}

func inspectAll(ctx context.Context, dockerCLI command.Cli, getSize bool, typeConstraint string) inspect.GetRefFunc {
func inspectAll(ctx context.Context, dockerCLI command.Cli, getSize bool, typeConstraint objectType) inspect.GetRefFunc {
inspectAutodetect := []struct {
objectType string
objectType objectType
isSizeSupported bool
isSwarmObject bool
objectInspector func(string) (any, []byte, error)
}{
{
objectType: "container",
objectType: typeContainer,
isSizeSupported: true,
objectInspector: inspectContainers(ctx, dockerCLI, getSize),
},
{
objectType: "image",
objectType: typeImage,
objectInspector: inspectImages(ctx, dockerCLI),
},
{
objectType: "network",
objectType: typeNetwork,
objectInspector: inspectNetwork(ctx, dockerCLI),
},
{
objectType: "volume",
objectType: typeVolume,
objectInspector: inspectVolume(ctx, dockerCLI),
},
{
objectType: "service",
objectType: typeService,
isSwarmObject: true,
objectInspector: inspectService(ctx, dockerCLI),
},
{
objectType: "task",
objectType: typeTask,
isSwarmObject: true,
objectInspector: inspectTasks(ctx, dockerCLI),
},
{
objectType: "node",
objectType: typeNode,
isSwarmObject: true,
objectInspector: inspectNode(ctx, dockerCLI),
},
{
objectType: "plugin",
objectType: typePlugin,
objectInspector: inspectPlugin(ctx, dockerCLI),
},
{
objectType: "secret",
objectType: typeSecret,
isSwarmObject: true,
objectInspector: inspectSecret(ctx, dockerCLI),
},
{
objectType: "config",
objectType: typeConfig,
isSwarmObject: true,
objectInspector: inspectConfig(ctx, dockerCLI),
},
Expand Down
48 changes: 48 additions & 0 deletions cli/command/system/inspect_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package system

import (
"io"
"testing"

"github.com/docker/cli/internal/test"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)

func TestInspectValidateFlagsAndArgs(t *testing.T) {
for _, tc := range []struct {
name string
args []string
expectedErr string
}{
{
name: "empty type",
args: []string{"--type", "", "something"},
expectedErr: `type is empty: must be one of "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume"`,
},
{
name: "unknown type",
args: []string{"--type", "unknown", "something"},
expectedErr: `unknown type: "unknown": must be one of "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume"`,
},
{
name: "no arg",
args: []string{},
expectedErr: `inspect: 'inspect' requires at least 1 argument`,
},
} {
t.Run(tc.name, func(t *testing.T) {
cmd := NewInspectCommand(test.NewFakeCli(&fakeClient{}))
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
cmd.SetArgs(tc.args)

err := cmd.Execute()
if tc.expectedErr != "" {
assert.Check(t, is.ErrorContains(err, tc.expectedErr))
} else {
assert.Check(t, is.Nil(err))
}
})
}
}
2 changes: 1 addition & 1 deletion docs/reference/commandline/inspect.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Return low-level information on Docker objects
|:---------------------------------------|:---------|:--------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`-f`](#format), [`--format`](#format) | `string` | | Format output using a custom template:<br>'json': Print in JSON format<br>'TEMPLATE': Print output using the given Go template.<br>Refer to https://docs.docker.com/go/formatting/ for more information about formatting output with templates |
| [`-s`](#size), [`--size`](#size) | `bool` | | Display total file sizes if the type is container |
| [`--type`](#type) | `string` | | Return JSON for specified type |
| [`--type`](#type) | `string` | | Only inspect objects of the given type |


<!---MARKER_GEN_END-->
Expand Down
Loading