Browse code

Refactor `docker inspect` to work on all types

Signed-off-by: Arnaud Porterie (icecrime) <arnaud.porterie@docker.com>

Arnaud Porterie (icecrime) authored on 2016/06/16 13:41:54
Showing 5 changed files
... ...
@@ -36,68 +36,101 @@ func NewInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
36 36
 
37 37
 	flags := cmd.Flags()
38 38
 	flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template")
39
-	flags.StringVar(&opts.inspectType, "type", "", "Return JSON for specified type, (e.g image, container or task)")
39
+	flags.StringVar(&opts.inspectType, "type", "", "Return JSON for specified type")
40 40
 	flags.BoolVarP(&opts.size, "size", "s", false, "Display total file sizes if the type is container")
41 41
 
42 42
 	return cmd
43 43
 }
44 44
 
45 45
 func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error {
46
-	ctx := context.Background()
47
-	client := dockerCli.Client()
48
-
49
-	var getRefFunc inspect.GetRefFunc
46
+	var elementSearcher inspect.GetRefFunc
50 47
 	switch opts.inspectType {
51
-	case "container":
52
-		getRefFunc = func(ref string) (interface{}, []byte, error) {
53
-			return client.ContainerInspectWithRaw(ctx, ref, opts.size)
54
-		}
55
-	case "image":
56
-		getRefFunc = func(ref string) (interface{}, []byte, error) {
57
-			return client.ImageInspectWithRaw(ctx, ref)
58
-		}
59
-	case "task":
60
-		if opts.size {
61
-			fmt.Fprintln(dockerCli.Err(), "WARNING: --size ignored for tasks")
62
-		}
63
-		getRefFunc = func(ref string) (interface{}, []byte, error) {
64
-			return client.TaskInspectWithRaw(ctx, ref)
65
-		}
66
-	case "":
67
-		getRefFunc = inspectAll(ctx, dockerCli, opts.size)
48
+	case "", "container", "image", "node", "network", "service", "volume", "task":
49
+		elementSearcher = inspectAll(context.Background(), dockerCli, opts.size, opts.inspectType)
68 50
 	default:
69 51
 		return fmt.Errorf("%q is not a valid value for --type", opts.inspectType)
70 52
 	}
53
+	return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, elementSearcher)
54
+}
71 55
 
72
-	return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, getRefFunc)
56
+func inspectContainers(ctx context.Context, dockerCli *client.DockerCli, getSize bool) inspect.GetRefFunc {
57
+	return func(ref string) (interface{}, []byte, error) {
58
+		return dockerCli.Client().ContainerInspectWithRaw(ctx, ref, getSize)
59
+	}
73 60
 }
74 61
 
75
-func inspectAll(ctx context.Context, dockerCli *client.DockerCli, getSize bool) inspect.GetRefFunc {
76
-	client := dockerCli.Client()
62
+func inspectImages(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
63
+	return func(ref string) (interface{}, []byte, error) {
64
+		return dockerCli.Client().ImageInspectWithRaw(ctx, ref)
65
+	}
66
+}
77 67
 
68
+func inspectNetwork(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
78 69
 	return func(ref string) (interface{}, []byte, error) {
79
-		c, rawContainer, err := client.ContainerInspectWithRaw(ctx, ref, getSize)
80
-		if err == nil || !apiclient.IsErrNotFound(err) {
81
-			return c, rawContainer, err
82
-		}
83
-		// Search for image with that id if a container doesn't exist.
84
-		i, rawImage, err := client.ImageInspectWithRaw(ctx, ref)
85
-		if err == nil || !apiclient.IsErrNotFound(err) {
86
-			return i, rawImage, err
87
-		}
70
+		return dockerCli.Client().NetworkInspectWithRaw(ctx, ref)
71
+	}
72
+}
88 73
 
89
-		// Search for task with that id if an image doesn't exist.
90
-		t, rawTask, err := client.TaskInspectWithRaw(ctx, ref)
91
-		if err == nil || !(apiclient.IsErrNotFound(err) || isErrorNoSwarmMode(err)) {
92
-			if getSize {
93
-				fmt.Fprintln(dockerCli.Err(), "WARNING: --size ignored for tasks")
94
-			}
95
-			return t, rawTask, err
96
-		}
97
-		return nil, nil, fmt.Errorf("Error: No such container, image or task: %s", ref)
74
+func inspectNode(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
75
+	return func(ref string) (interface{}, []byte, error) {
76
+		return dockerCli.Client().NodeInspectWithRaw(ctx, ref)
77
+	}
78
+}
79
+
80
+func inspectService(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
81
+	return func(ref string) (interface{}, []byte, error) {
82
+		return dockerCli.Client().ServiceInspectWithRaw(ctx, ref)
83
+	}
84
+}
85
+
86
+func inspectTasks(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
87
+	return func(ref string) (interface{}, []byte, error) {
88
+		return dockerCli.Client().TaskInspectWithRaw(ctx, ref)
89
+	}
90
+}
91
+
92
+func inspectVolume(ctx context.Context, dockerCli *client.DockerCli) inspect.GetRefFunc {
93
+	return func(ref string) (interface{}, []byte, error) {
94
+		return dockerCli.Client().VolumeInspectWithRaw(ctx, ref)
98 95
 	}
99 96
 }
100 97
 
101
-func isErrorNoSwarmMode(err error) bool {
102
-	return strings.Contains(err.Error(), "This node is not a swarm manager")
98
+func inspectAll(ctx context.Context, dockerCli *client.DockerCli, getSize bool, typeConstraint string) inspect.GetRefFunc {
99
+	var inspectAutodetect = []struct {
100
+		ObjectType      string
101
+		IsSizeSupported bool
102
+		ObjectInspector func(string) (interface{}, []byte, error)
103
+	}{
104
+		{"container", true, inspectContainers(ctx, dockerCli, getSize)},
105
+		{"image", true, inspectImages(ctx, dockerCli)},
106
+		{"network", false, inspectNetwork(ctx, dockerCli)},
107
+		{"volume", false, inspectVolume(ctx, dockerCli)},
108
+		{"service", false, inspectService(ctx, dockerCli)},
109
+		{"task", false, inspectTasks(ctx, dockerCli)},
110
+		{"node", false, inspectNode(ctx, dockerCli)},
111
+	}
112
+
113
+	isErrNotSwarmManager := func(err error) bool {
114
+		return strings.Contains(err.Error(), "This node is not a swarm manager")
115
+	}
116
+
117
+	return func(ref string) (interface{}, []byte, error) {
118
+		for _, inspectData := range inspectAutodetect {
119
+			if typeConstraint != "" && inspectData.ObjectType != typeConstraint {
120
+				continue
121
+			}
122
+			v, raw, err := inspectData.ObjectInspector(ref)
123
+			if err != nil {
124
+				if typeConstraint == "" && (apiclient.IsErrNotFound(err) || isErrNotSwarmManager(err)) {
125
+					continue
126
+				}
127
+				return v, raw, err
128
+			}
129
+			if !inspectData.IsSizeSupported {
130
+				fmt.Fprintf(dockerCli.Err(), "WARNING: --size ignored for %s\n", inspectData.ObjectType)
131
+			}
132
+			return v, raw, err
133
+		}
134
+		return nil, nil, fmt.Errorf("Error: No such object: %s", ref)
135
+	}
103 136
 }
... ...
@@ -11,15 +11,16 @@ parent = "smn_cli"
11 11
 # inspect
12 12
 
13 13
 ```markdown
14
-Usage:  docker inspect [OPTIONS] CONTAINER|IMAGE|TASK [CONTAINER|IMAGE|TASK...]
14
+Usage:  docker inspect [OPTIONS] NAME|ID [NAME|ID...]
15 15
 
16
-Return low-level information on a container, image or task
16
+Return low-level information on one or multiple containers, images, volumes,
17
+networks, nodes, services, or tasks identified by name or ID.
17 18
 
18 19
   -f, --format       Format the output using the given go template
19 20
   --help             Print usage
20 21
   -s, --size         Display total file sizes if the type is container
21 22
                      values are "image" or "container" or "task
22
-  --type             Return JSON for specified type, (e.g image, container or task)
23
+  --type             Return JSON for specified type
23 24
 ```
24 25
 
25 26
 By default, this will render all results in a JSON array. If the container and
... ...
@@ -176,7 +176,7 @@ func (s *DockerRegistrySuite) TestRemoveImageByDigest(c *check.C) {
176 176
 	_, err = inspectFieldWithError(imageReference, "Id")
177 177
 	//unexpected nil err trying to inspect what should be a non-existent image
178 178
 	c.Assert(err, checker.NotNil)
179
-	c.Assert(err.Error(), checker.Contains, "No such container, image")
179
+	c.Assert(err.Error(), checker.Contains, "No such object")
180 180
 }
181 181
 
182 182
 func (s *DockerRegistrySuite) TestBuildByDigest(c *check.C) {
... ...
@@ -65,7 +65,7 @@ func (s *DockerSuite) TestRenameCheckNames(c *check.C) {
65 65
 	result := dockerCmdWithResult("inspect", "-f={{.Name}}", "first_name")
66 66
 	c.Assert(result, icmd.Matches, icmd.Expected{
67 67
 		ExitCode: 1,
68
-		Err:      "No such container, image or task: first_name",
68
+		Err:      "No such object: first_name",
69 69
 	})
70 70
 }
71 71
 
... ...
@@ -2,23 +2,23 @@
2 2
 % Docker Community
3 3
 % JUNE 2014
4 4
 # NAME
5
-docker-inspect - Return low-level information on a container or image
5
+docker-inspect - Return low-level information on docker objects
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker inspect**
9 9
 [**--help**]
10 10
 [**-f**|**--format**[=*FORMAT*]]
11 11
 [**-s**|**--size**]
12
-[**--type**=*container*|*image*]
13
-CONTAINER|IMAGE [CONTAINER|IMAGE...]
12
+[**--type**=*container*|*image*|*network*|*node*|*service*|*task*|*volume*]
13
+NAME|ID [NAME|ID...]
14 14
 
15 15
 # DESCRIPTION
16 16
 
17
-This displays all the information available in Docker for a given
18
-container or image. By default, this will render all results in a JSON
19
-array. If the container and image have the same name, this will return
20
-container JSON for unspecified type. If a format is specified, the given
21
-template will be executed for each result.
17
+This displays all the information available in Docker for one or multiple given
18
+containers, images, volumes, networks, nodes, services, or tasks. By default,
19
+this will render all results in a JSON array. If the container and image have
20
+the same name, this will return container JSON for unspecified type. If a format
21
+is specified, the given template will be executed for each result.
22 22
 
23 23
 # OPTIONS
24 24
 **--help**
... ...
@@ -30,8 +30,9 @@ template will be executed for each result.
30 30
 **-s**, **--size**
31 31
     Display total file sizes if the type is container.
32 32
 
33
-**--type**="*container*|*image*"
34
-    Return JSON for specified type, permissible values are "image" or "container"
33
+**--type**=*container*|*image*|*network*|*node*|*service*|*task*|*volume*
34
+    Return JSON for specified type, permissible values are "image", "container",
35
+    "network", "node", "service", "task", and "volume".
35 36
 
36 37
 # EXAMPLES
37 38