2016-09-08 13:11:39 -04:00
|
|
|
package system
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2016-12-07 10:38:18 -05:00
|
|
|
"strings"
|
2016-09-08 13:11:39 -04:00
|
|
|
|
|
|
|
"golang.org/x/net/context"
|
|
|
|
|
|
|
|
"github.com/docker/docker/cli"
|
|
|
|
"github.com/docker/docker/cli/command"
|
|
|
|
"github.com/docker/docker/cli/command/inspect"
|
|
|
|
apiclient "github.com/docker/docker/client"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
|
|
|
type inspectOptions struct {
|
|
|
|
format string
|
|
|
|
inspectType string
|
|
|
|
size bool
|
|
|
|
ids []string
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewInspectCommand creates a new cobra.Command for `docker inspect`
|
|
|
|
func NewInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|
|
|
var opts inspectOptions
|
|
|
|
|
|
|
|
cmd := &cobra.Command{
|
2016-11-03 15:46:28 -04:00
|
|
|
Use: "inspect [OPTIONS] NAME|ID [NAME|ID...]",
|
|
|
|
Short: "Return low-level information on Docker objects",
|
|
|
|
Args: cli.RequiresMinArgs(1),
|
2016-09-08 13:11:39 -04:00
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
opts.ids = args
|
|
|
|
return runInspect(dockerCli, opts)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
flags := cmd.Flags()
|
2016-10-18 06:50:11 -04:00
|
|
|
flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")
|
2016-09-08 13:11:39 -04:00
|
|
|
flags.StringVar(&opts.inspectType, "type", "", "Return JSON for specified type")
|
|
|
|
flags.BoolVarP(&opts.size, "size", "s", false, "Display total file sizes if the type is container")
|
|
|
|
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
|
|
|
|
var elementSearcher inspect.GetRefFunc
|
|
|
|
switch opts.inspectType {
|
2016-11-29 20:31:29 -05:00
|
|
|
case "", "container", "image", "node", "network", "service", "volume", "task", "plugin":
|
2016-09-08 13:11:39 -04:00
|
|
|
elementSearcher = inspectAll(context.Background(), dockerCli, opts.size, opts.inspectType)
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("%q is not a valid value for --type", opts.inspectType)
|
|
|
|
}
|
|
|
|
return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, elementSearcher)
|
|
|
|
}
|
|
|
|
|
|
|
|
func inspectContainers(ctx context.Context, dockerCli *command.DockerCli, getSize bool) inspect.GetRefFunc {
|
|
|
|
return func(ref string) (interface{}, []byte, error) {
|
|
|
|
return dockerCli.Client().ContainerInspectWithRaw(ctx, ref, getSize)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func inspectImages(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
|
|
|
|
return func(ref string) (interface{}, []byte, error) {
|
|
|
|
return dockerCli.Client().ImageInspectWithRaw(ctx, ref)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func inspectNetwork(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
|
|
|
|
return func(ref string) (interface{}, []byte, error) {
|
|
|
|
return dockerCli.Client().NetworkInspectWithRaw(ctx, ref)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func inspectNode(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
|
|
|
|
return func(ref string) (interface{}, []byte, error) {
|
|
|
|
return dockerCli.Client().NodeInspectWithRaw(ctx, ref)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func inspectService(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
|
|
|
|
return func(ref string) (interface{}, []byte, error) {
|
|
|
|
return dockerCli.Client().ServiceInspectWithRaw(ctx, ref)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func inspectTasks(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
|
|
|
|
return func(ref string) (interface{}, []byte, error) {
|
|
|
|
return dockerCli.Client().TaskInspectWithRaw(ctx, ref)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func inspectVolume(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
|
|
|
|
return func(ref string) (interface{}, []byte, error) {
|
|
|
|
return dockerCli.Client().VolumeInspectWithRaw(ctx, ref)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-29 20:31:29 -05:00
|
|
|
func inspectPlugin(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
|
|
|
|
return func(ref string) (interface{}, []byte, error) {
|
|
|
|
return dockerCli.Client().PluginInspectWithRaw(ctx, ref)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-08 13:11:39 -04:00
|
|
|
func inspectAll(ctx context.Context, dockerCli *command.DockerCli, getSize bool, typeConstraint string) inspect.GetRefFunc {
|
|
|
|
var inspectAutodetect = []struct {
|
2016-12-08 06:04:22 -05:00
|
|
|
objectType string
|
|
|
|
isSizeSupported bool
|
|
|
|
isSwarmObject bool
|
|
|
|
objectInspector func(string) (interface{}, []byte, error)
|
2016-09-08 13:11:39 -04:00
|
|
|
}{
|
2016-12-08 06:04:22 -05:00
|
|
|
{
|
|
|
|
objectType: "container",
|
|
|
|
isSizeSupported: true,
|
|
|
|
objectInspector: inspectContainers(ctx, dockerCli, getSize),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
objectType: "image",
|
|
|
|
objectInspector: inspectImages(ctx, dockerCli),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
objectType: "network",
|
|
|
|
objectInspector: inspectNetwork(ctx, dockerCli),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
objectType: "volume",
|
|
|
|
objectInspector: inspectVolume(ctx, dockerCli),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
objectType: "service",
|
|
|
|
isSwarmObject: true,
|
|
|
|
objectInspector: inspectService(ctx, dockerCli),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
objectType: "task",
|
|
|
|
isSwarmObject: true,
|
|
|
|
objectInspector: inspectTasks(ctx, dockerCli),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
objectType: "node",
|
|
|
|
isSwarmObject: true,
|
|
|
|
objectInspector: inspectNode(ctx, dockerCli),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
objectType: "plugin",
|
|
|
|
objectInspector: inspectPlugin(ctx, dockerCli),
|
|
|
|
},
|
2016-09-08 13:11:39 -04:00
|
|
|
}
|
|
|
|
|
2016-12-08 06:04:22 -05:00
|
|
|
// isSwarmManager does an Info API call to verify that the daemon is
|
|
|
|
// a swarm manager.
|
|
|
|
isSwarmManager := func() bool {
|
|
|
|
info, err := dockerCli.Client().Info(ctx)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintln(dockerCli.Err(), err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return info.Swarm.ControlAvailable
|
2016-09-08 13:11:39 -04:00
|
|
|
}
|
|
|
|
|
2016-12-07 10:38:18 -05:00
|
|
|
isErrNotSupported := func(err error) bool {
|
|
|
|
return strings.Contains(err.Error(), "not supported")
|
|
|
|
}
|
|
|
|
|
2016-09-08 13:11:39 -04:00
|
|
|
return func(ref string) (interface{}, []byte, error) {
|
2016-12-08 06:04:22 -05:00
|
|
|
const (
|
|
|
|
swarmSupportUnknown = iota
|
|
|
|
swarmSupported
|
|
|
|
swarmUnsupported
|
|
|
|
)
|
|
|
|
|
|
|
|
isSwarmSupported := swarmSupportUnknown
|
|
|
|
|
2016-09-08 13:11:39 -04:00
|
|
|
for _, inspectData := range inspectAutodetect {
|
2016-12-08 06:04:22 -05:00
|
|
|
if typeConstraint != "" && inspectData.objectType != typeConstraint {
|
2016-09-08 13:11:39 -04:00
|
|
|
continue
|
|
|
|
}
|
2016-12-08 06:04:22 -05:00
|
|
|
if typeConstraint == "" && inspectData.isSwarmObject {
|
|
|
|
if isSwarmSupported == swarmSupportUnknown {
|
|
|
|
if isSwarmManager() {
|
|
|
|
isSwarmSupported = swarmSupported
|
|
|
|
} else {
|
|
|
|
isSwarmSupported = swarmUnsupported
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if isSwarmSupported == swarmUnsupported {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
v, raw, err := inspectData.objectInspector(ref)
|
2016-09-08 13:11:39 -04:00
|
|
|
if err != nil {
|
2016-12-07 10:38:18 -05:00
|
|
|
if typeConstraint == "" && (apiclient.IsErrNotFound(err) || isErrNotSupported(err)) {
|
2016-09-08 13:11:39 -04:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
return v, raw, err
|
|
|
|
}
|
2016-12-08 06:04:22 -05:00
|
|
|
if getSize && !inspectData.isSizeSupported {
|
|
|
|
fmt.Fprintf(dockerCli.Err(), "WARNING: --size ignored for %s\n", inspectData.objectType)
|
2016-09-08 13:11:39 -04:00
|
|
|
}
|
|
|
|
return v, raw, err
|
|
|
|
}
|
|
|
|
return nil, nil, fmt.Errorf("Error: No such object: %s", ref)
|
|
|
|
}
|
|
|
|
}
|