diff --git a/cli/command/system/inspect.go b/cli/command/system/inspect.go index a403685ee7..dee4efcfec 100644 --- a/cli/command/system/inspect.go +++ b/cli/command/system/inspect.go @@ -45,7 +45,7 @@ func NewInspectCommand(dockerCli *command.DockerCli) *cobra.Command { func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error { var elementSearcher inspect.GetRefFunc switch opts.inspectType { - case "", "container", "image", "node", "network", "service", "volume", "task": + case "", "container", "image", "node", "network", "service", "volume", "task", "plugin": elementSearcher = inspectAll(context.Background(), dockerCli, opts.size, opts.inspectType) default: 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 } } +func inspectPlugin(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc { + return func(ref string) (interface{}, []byte, error) { + return dockerCli.Client().PluginInspectWithRaw(ctx, ref) + } +} + func inspectAll(ctx context.Context, dockerCli *command.DockerCli, getSize bool, typeConstraint string) inspect.GetRefFunc { var inspectAutodetect = []struct { ObjectType string @@ -108,6 +114,7 @@ func inspectAll(ctx context.Context, dockerCli *command.DockerCli, getSize bool, {"service", false, inspectService(ctx, dockerCli)}, {"task", false, inspectTasks(ctx, dockerCli)}, {"node", false, inspectNode(ctx, dockerCli)}, + {"plugin", false, inspectPlugin(ctx, dockerCli)}, } isErrNotSwarmManager := func(err error) bool { diff --git a/client/errors.go b/client/errors.go index 854516669c..bf6923f134 100644 --- a/client/errors.go +++ b/client/errors.go @@ -255,3 +255,24 @@ func IsErrSecretNotFound(err error) bool { _, ok := err.(secretNotFoundError) return ok } + +// pluginNotFoundError implements an error returned when a plugin is not in the docker host. +type pluginNotFoundError struct { + name string +} + +// NotFound indicates that this error type is of NotFound +func (e pluginNotFoundError) NotFound() bool { + return true +} + +// Error returns a string representation of a pluginNotFoundError +func (e pluginNotFoundError) Error() string { + return fmt.Sprintf("Error: No such plugin: %s", e.name) +} + +// IsErrPluginNotFound returns true if the error is caused +// when a plugin is not found in the docker host. +func IsErrPluginNotFound(err error) bool { + return IsErrNotFound(err) +} diff --git a/client/plugin_inspect.go b/client/plugin_inspect.go index e9474b5a98..72900a1310 100644 --- a/client/plugin_inspect.go +++ b/client/plugin_inspect.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "io/ioutil" + "net/http" "github.com/docker/docker/api/types" "golang.org/x/net/context" @@ -13,6 +14,9 @@ import ( func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) { resp, err := cli.get(ctx, "/plugins/"+name, nil, nil) if err != nil { + if resp.statusCode == http.StatusNotFound { + return nil, nil, pluginNotFoundError{name} + } return nil, nil, err } diff --git a/integration-cli/docker_cli_inspect_test.go b/integration-cli/docker_cli_inspect_test.go index d99ae6d091..5d79ad1d85 100644 --- a/integration-cli/docker_cli_inspect_test.go +++ b/integration-cli/docker_cli_inspect_test.go @@ -417,3 +417,33 @@ func (s *DockerSuite) TestInspectAmpersand(c *check.C) { out, _ = dockerCmd(c, "inspect", name) c.Assert(out, checker.Contains, `soanni&rtr`) } + +func (s *DockerSuite) TestInspectPlugin(c *check.C) { + testRequires(c, DaemonIsLinux, Network) + _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag) + c.Assert(err, checker.IsNil) + + out, _, err := dockerCmdWithError("inspect", "--type", "plugin", "--format", "{{.Name}}", pNameWithTag) + c.Assert(err, checker.IsNil) + c.Assert(strings.TrimSpace(out), checker.Equals, pName) + + out, _, err = dockerCmdWithError("inspect", "--format", "{{.Name}}", pNameWithTag) + c.Assert(err, checker.IsNil) + c.Assert(strings.TrimSpace(out), checker.Equals, pName) + + // Even without tag the inspect still work + out, _, err = dockerCmdWithError("inspect", "--type", "plugin", "--format", "{{.Name}}", pName) + c.Assert(err, checker.IsNil) + c.Assert(strings.TrimSpace(out), checker.Equals, pName) + + out, _, err = dockerCmdWithError("inspect", "--format", "{{.Name}}", pName) + c.Assert(err, checker.IsNil) + c.Assert(strings.TrimSpace(out), checker.Equals, pName) + + _, _, err = dockerCmdWithError("plugin", "disable", pNameWithTag) + c.Assert(err, checker.IsNil) + + out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag) + c.Assert(err, checker.IsNil) + c.Assert(out, checker.Contains, pNameWithTag) +} diff --git a/integration-cli/docker_cli_rename_test.go b/integration-cli/docker_cli_rename_test.go index 9094e7d691..373d614b5e 100644 --- a/integration-cli/docker_cli_rename_test.go +++ b/integration-cli/docker_cli_rename_test.go @@ -62,10 +62,10 @@ func (s *DockerSuite) TestRenameCheckNames(c *check.C) { name := inspectField(c, newName, "Name") c.Assert(name, checker.Equals, "/"+newName, check.Commentf("Failed to rename container %s", name)) - result := dockerCmdWithResult("inspect", "-f={{.Name}}", "first_name") + result := dockerCmdWithResult("inspect", "-f={{.Name}}", "--type=container", "first_name") c.Assert(result, icmd.Matches, icmd.Expected{ ExitCode: 1, - Err: "No such object: first_name", + Err: "No such container: first_name", }) } diff --git a/plugin/backend_linux.go b/plugin/backend_linux.go index 8c1a152d9b..5ab9b4d6af 100644 --- a/plugin/backend_linux.go +++ b/plugin/backend_linux.go @@ -84,7 +84,7 @@ func (pm *Manager) Inspect(refOrID string) (tp types.Plugin, err error) { return tp, err } - return tp, fmt.Errorf("no plugin name or ID associated with %q", refOrID) + return tp, fmt.Errorf("no such plugin name or ID associated with %q", refOrID) } func (pm *Manager) pull(ref reference.Named, metaHeader http.Header, authConfig *types.AuthConfig, pluginID string) (types.PluginPrivileges, error) {