This fix tries to address the proposal raised in 28946
to support plugins in `docker inspect`.
The command `docker inspect` already supports
"container", "image", "node", "network", "service", "volume", "task".
However, `--type plugin` is not supported yet at the moment.
This fix address this issue by adding the support of `--type plugin`
for `docker inspect`.
An additional integration test has been added to cover the changes.
This fix fixes 28946.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
... | ... |
@@ -45,7 +45,7 @@ func NewInspectCommand(dockerCli *command.DockerCli) *cobra.Command { |
45 | 45 |
func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error { |
46 | 46 |
var elementSearcher inspect.GetRefFunc |
47 | 47 |
switch opts.inspectType { |
48 |
- case "", "container", "image", "node", "network", "service", "volume", "task": |
|
48 |
+ case "", "container", "image", "node", "network", "service", "volume", "task", "plugin": |
|
49 | 49 |
elementSearcher = inspectAll(context.Background(), dockerCli, opts.size, opts.inspectType) |
50 | 50 |
default: |
51 | 51 |
return fmt.Errorf("%q is not a valid value for --type", opts.inspectType) |
... | ... |
@@ -95,6 +95,12 @@ func inspectVolume(ctx context.Context, dockerCli *command.DockerCli) inspect.Ge |
95 | 95 |
} |
96 | 96 |
} |
97 | 97 |
|
98 |
+func inspectPlugin(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc { |
|
99 |
+ return func(ref string) (interface{}, []byte, error) { |
|
100 |
+ return dockerCli.Client().PluginInspectWithRaw(ctx, ref) |
|
101 |
+ } |
|
102 |
+} |
|
103 |
+ |
|
98 | 104 |
func inspectAll(ctx context.Context, dockerCli *command.DockerCli, getSize bool, typeConstraint string) inspect.GetRefFunc { |
99 | 105 |
var inspectAutodetect = []struct { |
100 | 106 |
ObjectType string |
... | ... |
@@ -108,6 +114,7 @@ func inspectAll(ctx context.Context, dockerCli *command.DockerCli, getSize bool, |
108 | 108 |
{"service", false, inspectService(ctx, dockerCli)}, |
109 | 109 |
{"task", false, inspectTasks(ctx, dockerCli)}, |
110 | 110 |
{"node", false, inspectNode(ctx, dockerCli)}, |
111 |
+ {"plugin", false, inspectPlugin(ctx, dockerCli)}, |
|
111 | 112 |
} |
112 | 113 |
|
113 | 114 |
isErrNotSwarmManager := func(err error) bool { |
... | ... |
@@ -255,3 +255,24 @@ func IsErrSecretNotFound(err error) bool { |
255 | 255 |
_, ok := err.(secretNotFoundError) |
256 | 256 |
return ok |
257 | 257 |
} |
258 |
+ |
|
259 |
+// pluginNotFoundError implements an error returned when a plugin is not in the docker host. |
|
260 |
+type pluginNotFoundError struct { |
|
261 |
+ name string |
|
262 |
+} |
|
263 |
+ |
|
264 |
+// NotFound indicates that this error type is of NotFound |
|
265 |
+func (e pluginNotFoundError) NotFound() bool { |
|
266 |
+ return true |
|
267 |
+} |
|
268 |
+ |
|
269 |
+// Error returns a string representation of a pluginNotFoundError |
|
270 |
+func (e pluginNotFoundError) Error() string { |
|
271 |
+ return fmt.Sprintf("Error: No such plugin: %s", e.name) |
|
272 |
+} |
|
273 |
+ |
|
274 |
+// IsErrPluginNotFound returns true if the error is caused |
|
275 |
+// when a plugin is not found in the docker host. |
|
276 |
+func IsErrPluginNotFound(err error) bool { |
|
277 |
+ return IsErrNotFound(err) |
|
278 |
+} |
... | ... |
@@ -4,6 +4,7 @@ import ( |
4 | 4 |
"bytes" |
5 | 5 |
"encoding/json" |
6 | 6 |
"io/ioutil" |
7 |
+ "net/http" |
|
7 | 8 |
|
8 | 9 |
"github.com/docker/docker/api/types" |
9 | 10 |
"golang.org/x/net/context" |
... | ... |
@@ -13,6 +14,9 @@ import ( |
13 | 13 |
func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) { |
14 | 14 |
resp, err := cli.get(ctx, "/plugins/"+name, nil, nil) |
15 | 15 |
if err != nil { |
16 |
+ if resp.statusCode == http.StatusNotFound { |
|
17 |
+ return nil, nil, pluginNotFoundError{name} |
|
18 |
+ } |
|
16 | 19 |
return nil, nil, err |
17 | 20 |
} |
18 | 21 |
|
... | ... |
@@ -417,3 +417,33 @@ func (s *DockerSuite) TestInspectAmpersand(c *check.C) { |
417 | 417 |
out, _ = dockerCmd(c, "inspect", name) |
418 | 418 |
c.Assert(out, checker.Contains, `soanni&rtr`) |
419 | 419 |
} |
420 |
+ |
|
421 |
+func (s *DockerSuite) TestInspectPlugin(c *check.C) { |
|
422 |
+ testRequires(c, DaemonIsLinux, Network) |
|
423 |
+ _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag) |
|
424 |
+ c.Assert(err, checker.IsNil) |
|
425 |
+ |
|
426 |
+ out, _, err := dockerCmdWithError("inspect", "--type", "plugin", "--format", "{{.Name}}", pNameWithTag) |
|
427 |
+ c.Assert(err, checker.IsNil) |
|
428 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, pName) |
|
429 |
+ |
|
430 |
+ out, _, err = dockerCmdWithError("inspect", "--format", "{{.Name}}", pNameWithTag) |
|
431 |
+ c.Assert(err, checker.IsNil) |
|
432 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, pName) |
|
433 |
+ |
|
434 |
+ // Even without tag the inspect still work |
|
435 |
+ out, _, err = dockerCmdWithError("inspect", "--type", "plugin", "--format", "{{.Name}}", pName) |
|
436 |
+ c.Assert(err, checker.IsNil) |
|
437 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, pName) |
|
438 |
+ |
|
439 |
+ out, _, err = dockerCmdWithError("inspect", "--format", "{{.Name}}", pName) |
|
440 |
+ c.Assert(err, checker.IsNil) |
|
441 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, pName) |
|
442 |
+ |
|
443 |
+ _, _, err = dockerCmdWithError("plugin", "disable", pNameWithTag) |
|
444 |
+ c.Assert(err, checker.IsNil) |
|
445 |
+ |
|
446 |
+ out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag) |
|
447 |
+ c.Assert(err, checker.IsNil) |
|
448 |
+ c.Assert(out, checker.Contains, pNameWithTag) |
|
449 |
+} |
... | ... |
@@ -62,10 +62,10 @@ func (s *DockerSuite) TestRenameCheckNames(c *check.C) { |
62 | 62 |
name := inspectField(c, newName, "Name") |
63 | 63 |
c.Assert(name, checker.Equals, "/"+newName, check.Commentf("Failed to rename container %s", name)) |
64 | 64 |
|
65 |
- result := dockerCmdWithResult("inspect", "-f={{.Name}}", "first_name") |
|
65 |
+ result := dockerCmdWithResult("inspect", "-f={{.Name}}", "--type=container", "first_name") |
|
66 | 66 |
c.Assert(result, icmd.Matches, icmd.Expected{ |
67 | 67 |
ExitCode: 1, |
68 |
- Err: "No such object: first_name", |
|
68 |
+ Err: "No such container: first_name", |
|
69 | 69 |
}) |
70 | 70 |
} |
71 | 71 |
|
... | ... |
@@ -84,7 +84,7 @@ func (pm *Manager) Inspect(refOrID string) (tp types.Plugin, err error) { |
84 | 84 |
return tp, err |
85 | 85 |
} |
86 | 86 |
|
87 |
- return tp, fmt.Errorf("no plugin name or ID associated with %q", refOrID) |
|
87 |
+ return tp, fmt.Errorf("no such plugin name or ID associated with %q", refOrID) |
|
88 | 88 |
} |
89 | 89 |
|
90 | 90 |
func (pm *Manager) pull(ref reference.Named, metaHeader http.Header, authConfig *types.AuthConfig, pluginID string) (types.PluginPrivileges, error) { |