Refactor docker inspect to work on all types

Signed-off-by: Arnaud Porterie (icecrime) <arnaud.porterie@docker.com>
This commit is contained in:
Arnaud Porterie (icecrime) 2016-06-15 21:41:54 -07:00
parent 15f3d060ac
commit 3db9f7afce
No known key found for this signature in database
GPG key ID: 3D78FAF1AF91D9E9
5 changed files with 98 additions and 63 deletions

View file

@ -36,68 +36,101 @@ func NewInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
flags := cmd.Flags()
flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template")
flags.StringVar(&opts.inspectType, "type", "", "Return JSON for specified type, (e.g image, container or task)")
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 *client.DockerCli, opts inspectOptions) error {
ctx := context.Background()
client := dockerCli.Client()
var getRefFunc inspect.GetRefFunc
var elementSearcher inspect.GetRefFunc
switch opts.inspectType {
case "container":
getRefFunc = func(ref string) (interface{}, []byte, error) {
return client.ContainerInspectWithRaw(ctx, ref, opts.size)
}
case "image":
getRefFunc = func(ref string) (interface{}, []byte, error) {
return client.ImageInspectWithRaw(ctx, ref)
}
case "task":
if opts.size {
fmt.Fprintln(dockerCli.Err(), "WARNING: --size ignored for tasks")
}
getRefFunc = func(ref string) (interface{}, []byte, error) {
return client.TaskInspectWithRaw(ctx, ref)
}
case "":
getRefFunc = inspectAll(ctx, dockerCli, opts.size)
case "", "container", "image", "node", "network", "service", "volume", "task":
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, getRefFunc)
return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, elementSearcher)
}
func inspectAll(ctx context.Context, dockerCli *client.DockerCli, getSize bool) inspect.GetRefFunc {
client := dockerCli.Client()
func inspectContainers(ctx context.Context, dockerCli *client.DockerCli, getSize bool) inspect.GetRefFunc {
return func(ref string) (interface{}, []byte, error) {
c, rawContainer, err := client.ContainerInspectWithRaw(ctx, ref, getSize)
if err == nil || !apiclient.IsErrNotFound(err) {
return c, rawContainer, err
}
// Search for image with that id if a container doesn't exist.
i, rawImage, err := client.ImageInspectWithRaw(ctx, ref)
if err == nil || !apiclient.IsErrNotFound(err) {
return i, rawImage, err
}
// Search for task with that id if an image doesn't exist.
t, rawTask, err := client.TaskInspectWithRaw(ctx, ref)
if err == nil || !(apiclient.IsErrNotFound(err) || isErrorNoSwarmMode(err)) {
if getSize {
fmt.Fprintln(dockerCli.Err(), "WARNING: --size ignored for tasks")
}
return t, rawTask, err
}
return nil, nil, fmt.Errorf("Error: No such container, image or task: %s", ref)
return dockerCli.Client().ContainerInspectWithRaw(ctx, ref, getSize)
}
}
func isErrorNoSwarmMode(err error) bool {
return strings.Contains(err.Error(), "This node is not a swarm manager")
func inspectImages(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
return func(ref string) (interface{}, []byte, error) {
return dockerCli.Client().ImageInspectWithRaw(ctx, ref)
}
}
func inspectNetwork(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
return func(ref string) (interface{}, []byte, error) {
return dockerCli.Client().NetworkInspectWithRaw(ctx, ref)
}
}
func inspectNode(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
return func(ref string) (interface{}, []byte, error) {
return dockerCli.Client().NodeInspectWithRaw(ctx, ref)
}
}
func inspectService(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
return func(ref string) (interface{}, []byte, error) {
return dockerCli.Client().ServiceInspectWithRaw(ctx, ref)
}
}
func inspectTasks(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
return func(ref string) (interface{}, []byte, error) {
return dockerCli.Client().TaskInspectWithRaw(ctx, ref)
}
}
func inspectVolume(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
return func(ref string) (interface{}, []byte, error) {
return dockerCli.Client().VolumeInspectWithRaw(ctx, ref)
}
}
func inspectAll(ctx context.Context, dockerCli *client.DockerCli, getSize bool, typeConstraint string) inspect.GetRefFunc {
var inspectAutodetect = []struct {
ObjectType string
IsSizeSupported bool
ObjectInspector func(string) (interface{}, []byte, error)
}{
{"container", true, inspectContainers(ctx, dockerCli, getSize)},
{"image", true, inspectImages(ctx, dockerCli)},
{"network", false, inspectNetwork(ctx, dockerCli)},
{"volume", false, inspectVolume(ctx, dockerCli)},
{"service", false, inspectService(ctx, dockerCli)},
{"task", false, inspectTasks(ctx, dockerCli)},
{"node", false, inspectNode(ctx, dockerCli)},
}
isErrNotSwarmManager := func(err error) bool {
return strings.Contains(err.Error(), "This node is not a swarm manager")
}
return func(ref string) (interface{}, []byte, error) {
for _, inspectData := range inspectAutodetect {
if typeConstraint != "" && inspectData.ObjectType != typeConstraint {
continue
}
v, raw, err := inspectData.ObjectInspector(ref)
if err != nil {
if typeConstraint == "" && (apiclient.IsErrNotFound(err) || isErrNotSwarmManager(err)) {
continue
}
return v, raw, err
}
if !inspectData.IsSizeSupported {
fmt.Fprintf(dockerCli.Err(), "WARNING: --size ignored for %s\n", inspectData.ObjectType)
}
return v, raw, err
}
return nil, nil, fmt.Errorf("Error: No such object: %s", ref)
}
}

View file

@ -11,15 +11,16 @@ parent = "smn_cli"
# inspect
```markdown
Usage: docker inspect [OPTIONS] CONTAINER|IMAGE|TASK [CONTAINER|IMAGE|TASK...]
Usage: docker inspect [OPTIONS] NAME|ID [NAME|ID...]
Return low-level information on a container, image or task
Return low-level information on one or multiple containers, images, volumes,
networks, nodes, services, or tasks identified by name or ID.
-f, --format Format the output using the given go template
--help Print usage
-s, --size Display total file sizes if the type is container
values are "image" or "container" or "task
--type Return JSON for specified type, (e.g image, container or task)
--type Return JSON for specified type
```
By default, this will render all results in a JSON array. If the container and

View file

@ -176,7 +176,7 @@ func (s *DockerRegistrySuite) TestRemoveImageByDigest(c *check.C) {
_, err = inspectFieldWithError(imageReference, "Id")
//unexpected nil err trying to inspect what should be a non-existent image
c.Assert(err, checker.NotNil)
c.Assert(err.Error(), checker.Contains, "No such container, image")
c.Assert(err.Error(), checker.Contains, "No such object")
}
func (s *DockerRegistrySuite) TestBuildByDigest(c *check.C) {

View file

@ -65,7 +65,7 @@ func (s *DockerSuite) TestRenameCheckNames(c *check.C) {
result := dockerCmdWithResult("inspect", "-f={{.Name}}", "first_name")
c.Assert(result, icmd.Matches, icmd.Expected{
ExitCode: 1,
Err: "No such container, image or task: first_name",
Err: "No such object: first_name",
})
}

View file

@ -2,23 +2,23 @@
% Docker Community
% JUNE 2014
# NAME
docker-inspect - Return low-level information on a container or image
docker-inspect - Return low-level information on docker objects
# SYNOPSIS
**docker inspect**
[**--help**]
[**-f**|**--format**[=*FORMAT*]]
[**-s**|**--size**]
[**--type**=*container*|*image*]
CONTAINER|IMAGE [CONTAINER|IMAGE...]
[**--type**=*container*|*image*|*network*|*node*|*service*|*task*|*volume*]
NAME|ID [NAME|ID...]
# DESCRIPTION
This displays all the information available in Docker for a given
container or image. By default, this will render all results in a JSON
array. If the container and image have the same name, this will return
container JSON for unspecified type. If a format is specified, the given
template will be executed for each result.
This displays all the information available in Docker for one or multiple given
containers, images, volumes, networks, nodes, services, or tasks. By default,
this will render all results in a JSON array. If the container and image have
the same name, this will return container JSON for unspecified type. If a format
is specified, the given template will be executed for each result.
# OPTIONS
**--help**
@ -30,8 +30,9 @@ template will be executed for each result.
**-s**, **--size**
Display total file sizes if the type is container.
**--type**="*container*|*image*"
Return JSON for specified type, permissible values are "image" or "container"
**--type**=*container*|*image*|*network*|*node*|*service*|*task*|*volume*
Return JSON for specified type, permissible values are "image", "container",
"network", "node", "service", "task", and "volume".
# EXAMPLES