浏览代码

Refactor `docker inspect` to work on all types

Signed-off-by: Arnaud Porterie (icecrime) <arnaud.porterie@docker.com>
Arnaud Porterie (icecrime) 9 年之前
父节点
当前提交
3db9f7afce

+ 78 - 45
api/client/system/inspect.go

@@ -36,68 +36,101 @@ func NewInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
 
 
 	flags := cmd.Flags()
 	flags := cmd.Flags()
 	flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template")
 	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")
 	flags.BoolVarP(&opts.size, "size", "s", false, "Display total file sizes if the type is container")
 
 
 	return cmd
 	return cmd
 }
 }
 
 
 func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error {
 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 {
 	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:
 	default:
 		return fmt.Errorf("%q is not a valid value for --type", opts.inspectType)
 		return fmt.Errorf("%q is not a valid value for --type", opts.inspectType)
 	}
 	}
+	return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, elementSearcher)
+}
 
 
-	return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, getRefFunc)
+func inspectContainers(ctx context.Context, dockerCli *client.DockerCli, getSize bool) inspect.GetRefFunc {
+	return func(ref string) (interface{}, []byte, error) {
+		return dockerCli.Client().ContainerInspectWithRaw(ctx, ref, getSize)
+	}
 }
 }
 
 
-func inspectAll(ctx context.Context, dockerCli *client.DockerCli, getSize bool) inspect.GetRefFunc {
-	client := dockerCli.Client()
+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 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
-		}
+		return dockerCli.Client().NetworkInspectWithRaw(ctx, ref)
+	}
+}
 
 
-		// 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)
+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 isErrorNoSwarmMode(err error) bool {
-	return strings.Contains(err.Error(), "This node is not a swarm manager")
+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)
+	}
 }
 }

+ 4 - 3
docs/reference/commandline/inspect.md

@@ -11,15 +11,16 @@ parent = "smn_cli"
 # inspect
 # inspect
 
 
 ```markdown
 ```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
   -f, --format       Format the output using the given go template
   --help             Print usage
   --help             Print usage
   -s, --size         Display total file sizes if the type is container
   -s, --size         Display total file sizes if the type is container
                      values are "image" or "container" or "task
                      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
 By default, this will render all results in a JSON array. If the container and

+ 1 - 1
integration-cli/docker_cli_by_digest_test.go

@@ -176,7 +176,7 @@ func (s *DockerRegistrySuite) TestRemoveImageByDigest(c *check.C) {
 	_, err = inspectFieldWithError(imageReference, "Id")
 	_, err = inspectFieldWithError(imageReference, "Id")
 	//unexpected nil err trying to inspect what should be a non-existent image
 	//unexpected nil err trying to inspect what should be a non-existent image
 	c.Assert(err, checker.NotNil)
 	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) {
 func (s *DockerRegistrySuite) TestBuildByDigest(c *check.C) {

+ 1 - 1
integration-cli/docker_cli_rename_test.go

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

+ 11 - 10
man/docker-inspect.1.md

@@ -2,23 +2,23 @@
 % Docker Community
 % Docker Community
 % JUNE 2014
 % JUNE 2014
 # NAME
 # NAME
-docker-inspect - Return low-level information on a container or image
+docker-inspect - Return low-level information on docker objects
 
 
 # SYNOPSIS
 # SYNOPSIS
 **docker inspect**
 **docker inspect**
 [**--help**]
 [**--help**]
 [**-f**|**--format**[=*FORMAT*]]
 [**-f**|**--format**[=*FORMAT*]]
 [**-s**|**--size**]
 [**-s**|**--size**]
-[**--type**=*container*|*image*]
-CONTAINER|IMAGE [CONTAINER|IMAGE...]
+[**--type**=*container*|*image*|*network*|*node*|*service*|*task*|*volume*]
+NAME|ID [NAME|ID...]
 
 
 # DESCRIPTION
 # 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
 # OPTIONS
 **--help**
 **--help**
@@ -30,8 +30,9 @@ template will be executed for each result.
 **-s**, **--size**
 **-s**, **--size**
     Display total file sizes if the type is container.
     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
 # EXAMPLES