Browse code

add -f to plugin inspect

Signed-off-by: Victor Vieux <vieux@docker.com>

Signed-off-by: Victor Vieux <vieux@docker.com>

Victor Vieux authored on 2016/08/17 20:52:27
Showing 10 changed files
... ...
@@ -3,50 +3,57 @@
3 3
 package plugin
4 4
 
5 5
 import (
6
-	"encoding/json"
7 6
 	"fmt"
8 7
 
9 8
 	"github.com/docker/docker/api/client"
9
+	"github.com/docker/docker/api/client/inspect"
10 10
 	"github.com/docker/docker/cli"
11 11
 	"github.com/docker/docker/reference"
12 12
 	"github.com/spf13/cobra"
13 13
 	"golang.org/x/net/context"
14 14
 )
15 15
 
16
+type inspectOptions struct {
17
+	pluginNames []string
18
+	format      string
19
+}
20
+
16 21
 func newInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
22
+	var opts inspectOptions
23
+
17 24
 	cmd := &cobra.Command{
18 25
 		Use:   "inspect PLUGIN",
19 26
 		Short: "Inspect a plugin",
20
-		Args:  cli.ExactArgs(1),
27
+		Args:  cli.RequiresMinArgs(1),
21 28
 		RunE: func(cmd *cobra.Command, args []string) error {
22
-			return runInspect(dockerCli, args[0])
29
+			opts.pluginNames = args
30
+			return runInspect(dockerCli, opts)
23 31
 		},
24 32
 	}
25 33
 
34
+	flags := cmd.Flags()
35
+	flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template")
26 36
 	return cmd
27 37
 }
28 38
 
29
-func runInspect(dockerCli *client.DockerCli, name string) error {
30
-	named, err := reference.ParseNamed(name) // FIXME: validate
31
-	if err != nil {
32
-		return err
33
-	}
34
-	if reference.IsNameOnly(named) {
35
-		named = reference.WithDefaultTag(named)
36
-	}
37
-	ref, ok := named.(reference.NamedTagged)
38
-	if !ok {
39
-		return fmt.Errorf("invalid name: %s", named.String())
40
-	}
41
-	p, err := dockerCli.Client().PluginInspect(context.Background(), ref.String())
42
-	if err != nil {
43
-		return err
44
-	}
39
+func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error {
40
+	client := dockerCli.Client()
41
+	ctx := context.Background()
42
+	getRef := func(name string) (interface{}, []byte, error) {
43
+		named, err := reference.ParseNamed(name) // FIXME: validate
44
+		if err != nil {
45
+			return nil, nil, err
46
+		}
47
+		if reference.IsNameOnly(named) {
48
+			named = reference.WithDefaultTag(named)
49
+		}
50
+		ref, ok := named.(reference.NamedTagged)
51
+		if !ok {
52
+			return nil, nil, fmt.Errorf("invalid name: %s", named.String())
53
+		}
45 54
 
46
-	b, err := json.MarshalIndent(p, "", "\t")
47
-	if err != nil {
48
-		return err
55
+		return client.PluginInspectWithRaw(ctx, ref.String())
49 56
 	}
50
-	_, err = dockerCli.Out().Write(b)
51
-	return err
57
+
58
+	return inspect.Inspect(dockerCli.Out(), opts.pluginNames, opts.format, getRef)
52 59
 }
... ...
@@ -17,7 +17,8 @@ Usage:  docker plugin inspect PLUGIN
17 17
 Inspect a plugin
18 18
 
19 19
 Options:
20
-      --help   Print usage
20
+      -f, --format string   Format the output using the given go template
21
+          --help            Print usage
21 22
 ```
22 23
 
23 24
 Returns information about a plugin. By default, this command renders all results
... ...
@@ -138,6 +139,13 @@ $ docker plugin inspect tiborvass/no-remove:latest
138 138
 (output formatted for readability)
139 139
 
140 140
 
141
+```bash
142
+$ docker plugin inspect -f '{{.Id}}' tiborvass/no-remove:latest
143
+```
144
+```
145
+8c74c978c434745c3ade82f1bc0acf38d04990eaf494fa507c16d9f1daa99c21
146
+```
147
+
141 148
 
142 149
 ## Related information
143 150
 
... ...
@@ -61,7 +61,7 @@ clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://gith
61 61
 clone git github.com/docker/go-units eb879ae3e2b84e2a142af415b679ddeda47ec71c
62 62
 clone git github.com/docker/go-connections fa2850ff103453a9ad190da0df0af134f0314b3d
63 63
 
64
-clone git github.com/docker/engine-api 94a8f8f29307ab291abad6c6f2182d67089aae5d
64
+clone git github.com/docker/engine-api 8d8fffdf863b12d03c76abf6ca1377e6f8f4e549
65 65
 clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837
66 66
 clone git github.com/imdario/mergo 0.2.1
67 67
 
... ...
@@ -4,9 +4,7 @@ import (
4 4
 	"github.com/docker/docker/pkg/integration/checker"
5 5
 	"github.com/go-check/check"
6 6
 
7
-	"io/ioutil"
8 7
 	"os"
9
-	"os/exec"
10 8
 	"path/filepath"
11 9
 	"strings"
12 10
 )
... ...
@@ -28,17 +26,7 @@ func (s *DockerSuite) TestPluginBasicOps(c *check.C) {
28 28
 	c.Assert(out, checker.Contains, pTag)
29 29
 	c.Assert(out, checker.Contains, "true")
30 30
 
31
-	out, _, err = dockerCmdWithError("plugin", "inspect", pNameWithTag)
32
-	c.Assert(err, checker.IsNil)
33
-	tmpFile, err := ioutil.TempFile("", "inspect.json")
34
-	c.Assert(err, checker.IsNil)
35
-	defer tmpFile.Close()
36
-
37
-	if _, err := tmpFile.Write([]byte(out)); err != nil {
38
-		c.Fatal(err)
39
-	}
40
-	// FIXME: When `docker plugin inspect` takes a format as input, jq can be replaced.
41
-	id, err := exec.Command("jq", ".Id", "--raw-output", tmpFile.Name()).CombinedOutput()
31
+	id, _, err := dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", pNameWithTag)
42 32
 	c.Assert(err, checker.IsNil)
43 33
 
44 34
 	out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag)
... ...
@@ -51,7 +39,7 @@ func (s *DockerSuite) TestPluginBasicOps(c *check.C) {
51 51
 	c.Assert(err, checker.IsNil)
52 52
 	c.Assert(out, checker.Contains, pNameWithTag)
53 53
 
54
-	_, err = os.Stat(filepath.Join(dockerBasePath, "plugins", string(id)))
54
+	_, err = os.Stat(filepath.Join(dockerBasePath, "plugins", id))
55 55
 	if !os.IsNotExist(err) {
56 56
 		c.Fatal(err)
57 57
 	}
... ...
@@ -18,6 +18,8 @@ const DefaultVersion string = "1.23"
18 18
 // Client is the API client that performs all operations
19 19
 // against a docker server.
20 20
 type Client struct {
21
+	// host holds the server address to connect to
22
+	host string
21 23
 	// proto holds the client protocol i.e. unix.
22 24
 	proto string
23 25
 	// addr holds the client address.
... ...
@@ -90,6 +92,7 @@ func NewClient(host string, version string, client *http.Client, httpHeaders map
90 90
 	}
91 91
 
92 92
 	return &Client{
93
+		host:              host,
93 94
 		proto:             proto,
94 95
 		addr:              addr,
95 96
 		basePath:          basePath,
... ...
@@ -8,6 +8,11 @@ import (
8 8
 // ErrConnectionFailed is an error raised when the connection between the client and the server failed.
9 9
 var ErrConnectionFailed = errors.New("Cannot connect to the Docker daemon. Is the docker daemon running on this host?")
10 10
 
11
+// ErrorConnectionFailed returns an error with host in the error message when connection to docker daemon failed.
12
+func ErrorConnectionFailed(host string) error {
13
+	return fmt.Errorf("Cannot connect to the Docker daemon at %s. Is the docker daemon running?", host)
14
+}
15
+
11 16
 type notFound interface {
12 17
 	error
13 18
 	NotFound() bool // Is the error a NotFound error
... ...
@@ -30,7 +30,7 @@ type PluginAPIClient interface {
30 30
 	PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) error
31 31
 	PluginPush(ctx context.Context, name string, registryAuth string) error
32 32
 	PluginSet(ctx context.Context, name string, args []string) error
33
-	PluginInspect(ctx context.Context, name string) (*types.Plugin, error)
33
+	PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error)
34 34
 }
35 35
 
36 36
 // Ensure that Client always implements APIClient.
... ...
@@ -3,20 +3,28 @@
3 3
 package client
4 4
 
5 5
 import (
6
+	"bytes"
6 7
 	"encoding/json"
8
+	"io/ioutil"
7 9
 
8 10
 	"github.com/docker/engine-api/types"
9 11
 	"golang.org/x/net/context"
10 12
 )
11 13
 
12
-// PluginInspect inspects an existing plugin
13
-func (cli *Client) PluginInspect(ctx context.Context, name string) (*types.Plugin, error) {
14
-	var p types.Plugin
14
+// PluginInspectWithRaw inspects an existing plugin
15
+func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) {
15 16
 	resp, err := cli.get(ctx, "/plugins/"+name, nil, nil)
16 17
 	if err != nil {
17
-		return nil, err
18
+		return nil, nil, err
18 19
 	}
19
-	err = json.NewDecoder(resp.body).Decode(&p)
20
-	ensureReaderClosed(resp)
21
-	return &p, err
20
+
21
+	defer ensureReaderClosed(resp)
22
+	body, err := ioutil.ReadAll(resp.body)
23
+	if err != nil {
24
+		return nil, nil, err
25
+	}
26
+	var p types.Plugin
27
+	rdr := bytes.NewReader(body)
28
+	err = json.NewDecoder(rdr).Decode(&p)
29
+	return &p, body, err
22 30
 }
... ...
@@ -123,11 +123,11 @@ func (cli *Client) sendClientRequest(ctx context.Context, method, path string, q
123 123
 
124 124
 		if err, ok := err.(net.Error); ok {
125 125
 			if err.Timeout() {
126
-				return serverResp, ErrConnectionFailed
126
+				return serverResp, ErrorConnectionFailed(cli.host)
127 127
 			}
128 128
 			if !err.Temporary() {
129 129
 				if strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "dial unix") {
130
-					return serverResp, ErrConnectionFailed
130
+					return serverResp, ErrorConnectionFailed(cli.host)
131 131
 				}
132 132
 			}
133 133
 		}
... ...
@@ -38,6 +38,7 @@ const (
38 38
 type Task struct {
39 39
 	ID string
40 40
 	Meta
41
+	Annotations
41 42
 
42 43
 	Spec                TaskSpec            `json:",omitempty"`
43 44
 	ServiceID           string              `json:",omitempty"`