Browse code

plugins: vendor engine-api to import new plugin types

Signed-off-by: Tibor Vass <tibor@docker.com>

Tibor Vass authored on 2016/06/14 14:01:08
Showing 14 changed files
... ...
@@ -60,7 +60,7 @@ clone git golang.org/x/net 2beffdc2e92c8a3027590f898fe88f69af48a3f8 https://gith
60 60
 clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git
61 61
 clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3
62 62
 clone git github.com/docker/go-connections fa2850ff103453a9ad190da0df0af134f0314b3d
63
-clone git github.com/docker/engine-api 6b2f24f16a7f1598635b6a99dbe38ec8a5eccaf8
63
+clone git github.com/docker/engine-api f3b5ad20d4576de14c96603db522dec530d03f62
64 64
 clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837
65 65
 clone git github.com/imdario/mergo 0.2.1
66 66
 
... ...
@@ -171,3 +171,18 @@ func IsErrTaskNotFound(err error) bool {
171 171
 	_, ok := err.(taskNotFoundError)
172 172
 	return ok
173 173
 }
174
+
175
+type pluginPermissionDenied struct {
176
+	name string
177
+}
178
+
179
+func (e pluginPermissionDenied) Error() string {
180
+	return "Permission denied while installing plugin " + e.name
181
+}
182
+
183
+// IsErrPluginPermissionDenied returns true if the error is caused
184
+// when a user denies a plugin's permissions
185
+func IsErrPluginPermissionDenied(err error) bool {
186
+	_, ok := err.(pluginPermissionDenied)
187
+	return ok
188
+}
... ...
@@ -4,18 +4,17 @@ import (
4 4
 	"io"
5 5
 	"time"
6 6
 
7
-	"golang.org/x/net/context"
8
-
9 7
 	"github.com/docker/engine-api/types"
10 8
 	"github.com/docker/engine-api/types/container"
11 9
 	"github.com/docker/engine-api/types/filters"
12 10
 	"github.com/docker/engine-api/types/network"
13 11
 	"github.com/docker/engine-api/types/registry"
14 12
 	"github.com/docker/engine-api/types/swarm"
13
+	"golang.org/x/net/context"
15 14
 )
16 15
 
17
-// APIClient is an interface that clients that talk with a docker server must implement.
18
-type APIClient interface {
16
+// CommonAPIClient is the common methods between stable and experimental versions of APIClient.
17
+type CommonAPIClient interface {
19 18
 	ClientVersion() string
20 19
 	CheckpointCreate(ctx context.Context, container string, options types.CheckpointCreateOptions) error
21 20
 	CheckpointDelete(ctx context.Context, container string, checkpointID string) error
... ...
@@ -97,6 +96,3 @@ type APIClient interface {
97 97
 	VolumeList(ctx context.Context, filter filters.Args) (types.VolumesListResponse, error)
98 98
 	VolumeRemove(ctx context.Context, volumeID string) error
99 99
 }
100
-
101
-// Ensure that Client always implements APIClient.
102
-var _ APIClient = &Client{}
103 100
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+// +build experimental
1
+
2
+package client
3
+
4
+import (
5
+	"io"
6
+
7
+	"github.com/docker/engine-api/types"
8
+	"golang.org/x/net/context"
9
+)
10
+
11
+// APIClient is an interface that clients that talk with a docker server must implement.
12
+type APIClient interface {
13
+	CommonAPIClient
14
+	PluginList(ctx context.Context) (types.PluginsListResponse, error)
15
+	PluginRemove(ctx context.Context, name string) error
16
+	PluginEnable(ctx context.Context, name string) error
17
+	PluginDisable(ctx context.Context, name string) error
18
+	PluginInstall(ctx context.Context, name, registryAuth string, acceptAllPermissions, noEnable bool, in io.ReadCloser, out io.Writer) error
19
+	PluginPush(ctx context.Context, name string, registryAuth string) error
20
+	PluginSet(ctx context.Context, name string, args []string) error
21
+	PluginInspect(ctx context.Context, name string) (*types.Plugin, error)
22
+}
23
+
24
+// Ensure that Client always implements APIClient.
25
+var _ APIClient = &Client{}
0 26
new file mode 100644
... ...
@@ -0,0 +1,11 @@
0
+// +build !experimental
1
+
2
+package client
3
+
4
+// APIClient is an interface that clients that talk with a docker server must implement.
5
+type APIClient interface {
6
+	CommonAPIClient
7
+}
8
+
9
+// Ensure that Client always implements APIClient.
10
+var _ APIClient = &Client{}
0 11
new file mode 100644
... ...
@@ -0,0 +1,14 @@
0
+// +build experimental
1
+
2
+package client
3
+
4
+import (
5
+	"golang.org/x/net/context"
6
+)
7
+
8
+// PluginDisable disables a plugin
9
+func (cli *Client) PluginDisable(ctx context.Context, name string) error {
10
+	resp, err := cli.post(ctx, "/plugins/"+name+"/disable", nil, nil, nil)
11
+	ensureReaderClosed(resp)
12
+	return err
13
+}
0 14
new file mode 100644
... ...
@@ -0,0 +1,14 @@
0
+// +build experimental
1
+
2
+package client
3
+
4
+import (
5
+	"golang.org/x/net/context"
6
+)
7
+
8
+// PluginEnable enables a plugin
9
+func (cli *Client) PluginEnable(ctx context.Context, name string) error {
10
+	resp, err := cli.post(ctx, "/plugins/"+name+"/enable", nil, nil, nil)
11
+	ensureReaderClosed(resp)
12
+	return err
13
+}
0 14
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+// +build experimental
1
+
2
+package client
3
+
4
+import (
5
+	"encoding/json"
6
+
7
+	"github.com/docker/engine-api/types"
8
+	"golang.org/x/net/context"
9
+)
10
+
11
+// PluginInspect inspects an existing plugin
12
+func (cli *Client) PluginInspect(ctx context.Context, name string) (*types.Plugin, error) {
13
+	var p types.Plugin
14
+	resp, err := cli.get(ctx, "/plugins/"+name, nil, nil)
15
+	if err != nil {
16
+		return nil, err
17
+	}
18
+	err = json.NewDecoder(resp.body).Decode(&p)
19
+	ensureReaderClosed(resp)
20
+	return &p, err
21
+}
0 22
new file mode 100644
... ...
@@ -0,0 +1,54 @@
0
+// +build experimental
1
+
2
+package client
3
+
4
+import (
5
+	"bufio"
6
+	"encoding/json"
7
+	"fmt"
8
+	"io"
9
+	"net/url"
10
+	"strings"
11
+
12
+	"github.com/docker/engine-api/types"
13
+	"golang.org/x/net/context"
14
+)
15
+
16
+// PluginInstall installs a plugin
17
+func (cli *Client) PluginInstall(ctx context.Context, name, registryAuth string, acceptAllPermissions, noEnable bool, in io.ReadCloser, out io.Writer) error {
18
+	headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
19
+	resp, err := cli.post(ctx, "/plugins/pull", url.Values{"name": []string{name}}, nil, headers)
20
+	if err != nil {
21
+		ensureReaderClosed(resp)
22
+		return err
23
+	}
24
+	var privileges types.PluginPrivileges
25
+	if err := json.NewDecoder(resp.body).Decode(&privileges); err != nil {
26
+		return err
27
+	}
28
+	ensureReaderClosed(resp)
29
+
30
+	if !acceptAllPermissions && len(privileges) > 0 {
31
+
32
+		fmt.Fprintf(out, "Plugin %q requested the following privileges:\n", name)
33
+		for _, privilege := range privileges {
34
+			fmt.Fprintf(out, " - %s: %v\n", privilege.Name, privilege.Value)
35
+		}
36
+
37
+		fmt.Fprint(out, "Do you grant the above permissions? [y/N] ")
38
+		reader := bufio.NewReader(in)
39
+		line, _, err := reader.ReadLine()
40
+		if err != nil {
41
+			return err
42
+		}
43
+		if strings.ToLower(string(line)) != "y" {
44
+			resp, _ := cli.delete(ctx, "/plugins/"+name, nil, nil)
45
+			ensureReaderClosed(resp)
46
+			return pluginPermissionDenied{name}
47
+		}
48
+	}
49
+	if noEnable {
50
+		return nil
51
+	}
52
+	return cli.PluginEnable(ctx, name)
53
+}
0 54
new file mode 100644
... ...
@@ -0,0 +1,23 @@
0
+// +build experimental
1
+
2
+package client
3
+
4
+import (
5
+	"encoding/json"
6
+
7
+	"github.com/docker/engine-api/types"
8
+	"golang.org/x/net/context"
9
+)
10
+
11
+// PluginList returns the installed plugins
12
+func (cli *Client) PluginList(ctx context.Context) (types.PluginsListResponse, error) {
13
+	var plugins types.PluginsListResponse
14
+	resp, err := cli.get(ctx, "/plugins", nil, nil)
15
+	if err != nil {
16
+		return plugins, err
17
+	}
18
+
19
+	err = json.NewDecoder(resp.body).Decode(&plugins)
20
+	ensureReaderClosed(resp)
21
+	return plugins, err
22
+}
0 23
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+// +build experimental
1
+
2
+package client
3
+
4
+import (
5
+	"golang.org/x/net/context"
6
+)
7
+
8
+// PluginPush pushes a plugin to a registry
9
+func (cli *Client) PluginPush(ctx context.Context, name string, registryAuth string) error {
10
+	headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
11
+	resp, err := cli.post(ctx, "/plugins/"+name+"/push", nil, nil, headers)
12
+	ensureReaderClosed(resp)
13
+	return err
14
+}
0 15
new file mode 100644
... ...
@@ -0,0 +1,14 @@
0
+// +build experimental
1
+
2
+package client
3
+
4
+import (
5
+	"golang.org/x/net/context"
6
+)
7
+
8
+// PluginRemove removes a plugin
9
+func (cli *Client) PluginRemove(ctx context.Context, name string) error {
10
+	resp, err := cli.delete(ctx, "/plugins/"+name, nil, nil)
11
+	ensureReaderClosed(resp)
12
+	return err
13
+}
0 14
new file mode 100644
... ...
@@ -0,0 +1,14 @@
0
+// +build experimental
1
+
2
+package client
3
+
4
+import (
5
+	"golang.org/x/net/context"
6
+)
7
+
8
+// PluginSet modifies settings for an existing plugin
9
+func (cli *Client) PluginSet(ctx context.Context, name string, args []string) error {
10
+	resp, err := cli.post(ctx, "/plugins/"+name+"/set", nil, args, nil)
11
+	ensureReaderClosed(resp)
12
+	return err
13
+}
0 14
new file mode 100644
... ...
@@ -0,0 +1,160 @@
0
+// +build experimental
1
+
2
+package types
3
+
4
+import (
5
+	"encoding/json"
6
+	"fmt"
7
+)
8
+
9
+// PluginConfig represents the values of settings potentially modifiable by a user
10
+type PluginConfig struct {
11
+	Mounts  []PluginMount
12
+	Env     []string
13
+	Args    []string
14
+	Devices []PluginDevice
15
+}
16
+
17
+// Plugin represents a Docker plugin for the remote API
18
+type Plugin struct {
19
+	ID       string `json:"Id,omitempty"`
20
+	Name     string
21
+	Tag      string
22
+	Active   bool
23
+	Config   PluginConfig
24
+	Manifest PluginManifest
25
+}
26
+
27
+// PluginsListResponse contains the response for the remote API
28
+type PluginsListResponse []*Plugin
29
+
30
+const (
31
+	authzDriver   = "AuthzDriver"
32
+	graphDriver   = "GraphDriver"
33
+	ipamDriver    = "IpamDriver"
34
+	networkDriver = "NetworkDriver"
35
+	volumeDriver  = "VolumeDriver"
36
+)
37
+
38
+// PluginInterfaceType represents a type that a plugin implements.
39
+type PluginInterfaceType struct {
40
+	Prefix     string // This is always "docker"
41
+	Capability string // Capability should be validated against the above list.
42
+	Version    string // Plugin API version. Depends on the capability
43
+}
44
+
45
+// UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType
46
+func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error {
47
+	versionIndex := len(p)
48
+	prefixIndex := 0
49
+	if len(p) < 2 || p[0] != '"' || p[len(p)-1] != '"' {
50
+		return fmt.Errorf("%q is not a plugin interface type", p)
51
+	}
52
+	p = p[1 : len(p)-1]
53
+loop:
54
+	for i, b := range p {
55
+		switch b {
56
+		case '.':
57
+			prefixIndex = i
58
+		case '/':
59
+			versionIndex = i
60
+			break loop
61
+		}
62
+	}
63
+	t.Prefix = string(p[:prefixIndex])
64
+	t.Capability = string(p[prefixIndex+1 : versionIndex])
65
+	if versionIndex < len(p) {
66
+		t.Version = string(p[versionIndex+1:])
67
+	}
68
+	return nil
69
+}
70
+
71
+// MarshalJSON implements json.Marshaler for PluginInterfaceType
72
+func (t *PluginInterfaceType) MarshalJSON() ([]byte, error) {
73
+	return json.Marshal(t.String())
74
+}
75
+
76
+// String implements fmt.Stringer for PluginInterfaceType
77
+func (t PluginInterfaceType) String() string {
78
+	return fmt.Sprintf("%s.%s/%s", t.Prefix, t.Capability, t.Version)
79
+}
80
+
81
+// PluginInterface describes the interface between Docker and plugin
82
+type PluginInterface struct {
83
+	Types  []PluginInterfaceType
84
+	Socket string
85
+}
86
+
87
+// PluginSetting is to be embedded in other structs, if they are supposed to be
88
+// modifiable by the user.
89
+type PluginSetting struct {
90
+	Name        string
91
+	Description string
92
+	Settable    []string
93
+}
94
+
95
+// PluginNetwork represents the network configuration for a plugin
96
+type PluginNetwork struct {
97
+	Type string
98
+}
99
+
100
+// PluginMount represents the mount configuration for a plugin
101
+type PluginMount struct {
102
+	PluginSetting
103
+	Source      *string
104
+	Destination string
105
+	Type        string
106
+	Options     []string
107
+}
108
+
109
+// PluginEnv represents an environment variable for a plugin
110
+type PluginEnv struct {
111
+	PluginSetting
112
+	Value *string
113
+}
114
+
115
+// PluginArgs represents the command line arguments for a plugin
116
+type PluginArgs struct {
117
+	PluginSetting
118
+	Value []string
119
+}
120
+
121
+// PluginDevice represents a device for a plugin
122
+type PluginDevice struct {
123
+	PluginSetting
124
+	Path *string
125
+}
126
+
127
+// PluginUser represents the user for the plugin's process
128
+type PluginUser struct {
129
+	UID uint32 `json:"Uid,omitempty"`
130
+	GID uint32 `json:"Gid,omitempty"`
131
+}
132
+
133
+// PluginManifest represents the manifest of a plugin
134
+type PluginManifest struct {
135
+	ManifestVersion string
136
+	Description     string
137
+	Documentation   string
138
+	Interface       PluginInterface
139
+	Entrypoint      []string
140
+	Workdir         string
141
+	User            PluginUser `json:",omitempty"`
142
+	Network         PluginNetwork
143
+	Capabilities    []string
144
+	Mounts          []PluginMount
145
+	Devices         []PluginDevice
146
+	Env             []PluginEnv
147
+	Args            PluginArgs
148
+}
149
+
150
+// PluginPrivilege describes a permission the user has to accept
151
+// upon installing a plugin.
152
+type PluginPrivilege struct {
153
+	Name        string
154
+	Description string
155
+	Value       []string
156
+}
157
+
158
+// PluginPrivileges is a list of PluginPrivilege
159
+type PluginPrivileges []PluginPrivilege