Browse code

Testing: Use local plugins, not from hub

Use the (new) plugin fixtures for plugin tests rather than pulling
plugins from hub.

This removes the restriction for platforms/archs since plugin binaries
get built in the test environment.

Future work would be to add test plugins for the various subsystems so
tests that are actually using plugins (e.g. volumes, networks) can be
ported to use the fixtures as well.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2017/07/13 05:31:13
Showing 6 changed files
... ...
@@ -5,21 +5,26 @@ import (
5 5
 	"net/http/httptest"
6 6
 	"os"
7 7
 	"os/exec"
8
+	"path"
8 9
 	"path/filepath"
9 10
 	"strings"
10 11
 	"sync"
11 12
 	"syscall"
12 13
 	"testing"
14
+	"time"
13 15
 
14 16
 	"github.com/docker/docker/api/types/swarm"
15 17
 	"github.com/docker/docker/cli/config"
18
+	"github.com/docker/docker/integration-cli/checker"
16 19
 	"github.com/docker/docker/integration-cli/cli"
17 20
 	"github.com/docker/docker/integration-cli/cli/build/fakestorage"
18 21
 	"github.com/docker/docker/integration-cli/daemon"
19 22
 	"github.com/docker/docker/integration-cli/environment"
23
+	"github.com/docker/docker/integration-cli/fixtures/plugin"
20 24
 	"github.com/docker/docker/integration-cli/registry"
21 25
 	"github.com/docker/docker/pkg/reexec"
22 26
 	"github.com/go-check/check"
27
+	"golang.org/x/net/context"
23 28
 )
24 29
 
25 30
 const (
... ...
@@ -442,3 +447,50 @@ func (s *DockerTrustedSwarmSuite) TearDownTest(c *check.C) {
442 442
 func (s *DockerTrustedSwarmSuite) OnTimeout(c *check.C) {
443 443
 	s.swarmSuite.OnTimeout(c)
444 444
 }
445
+
446
+func init() {
447
+	check.Suite(&DockerPluginSuite{
448
+		ds: &DockerSuite{},
449
+	})
450
+}
451
+
452
+type DockerPluginSuite struct {
453
+	ds       *DockerSuite
454
+	registry *registry.V2
455
+}
456
+
457
+func (ps *DockerPluginSuite) registryHost() string {
458
+	return privateRegistryURL
459
+}
460
+
461
+func (ps *DockerPluginSuite) getPluginRepo() string {
462
+	return path.Join(ps.registryHost(), "plugin", "basic")
463
+}
464
+func (ps *DockerPluginSuite) getPluginRepoWithTag() string {
465
+	return ps.getPluginRepo() + ":" + "latest"
466
+}
467
+
468
+func (ps *DockerPluginSuite) SetUpSuite(c *check.C) {
469
+	testRequires(c, DaemonIsLinux)
470
+	ps.registry = setupRegistry(c, false, "", "")
471
+
472
+	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
473
+	defer cancel()
474
+
475
+	err := plugin.CreateInRegistry(ctx, ps.getPluginRepo(), nil)
476
+	c.Assert(err, checker.IsNil, check.Commentf("failed to create plugin"))
477
+}
478
+
479
+func (ps *DockerPluginSuite) TearDownSuite(c *check.C) {
480
+	if ps.registry != nil {
481
+		ps.registry.Close()
482
+	}
483
+}
484
+
485
+func (ps *DockerPluginSuite) TearDownTest(c *check.C) {
486
+	ps.ds.TearDownTest(c)
487
+}
488
+
489
+func (ps *DockerPluginSuite) OnTimeout(c *check.C) {
490
+	ps.ds.OnTimeout(c)
491
+}
... ...
@@ -5,14 +5,20 @@ import (
5 5
 	"io/ioutil"
6 6
 	"net/http"
7 7
 	"os"
8
+	"path"
8 9
 	"path/filepath"
9 10
 	"strings"
11
+	"time"
10 12
 
13
+	"github.com/docker/docker/api/types"
11 14
 	"github.com/docker/docker/integration-cli/checker"
12 15
 	"github.com/docker/docker/integration-cli/cli"
13 16
 	"github.com/docker/docker/integration-cli/daemon"
17
+	"github.com/docker/docker/integration-cli/fixtures/plugin"
18
+	"github.com/docker/docker/integration-cli/request"
14 19
 	icmd "github.com/docker/docker/pkg/testutil/cmd"
15 20
 	"github.com/go-check/check"
21
+	"golang.org/x/net/context"
16 22
 )
17 23
 
18 24
 var (
... ...
@@ -24,31 +30,30 @@ var (
24 24
 	npNameWithTag     = npName + ":" + pTag
25 25
 )
26 26
 
27
-func (s *DockerSuite) TestPluginBasicOps(c *check.C) {
28
-	testRequires(c, DaemonIsLinux, IsAmd64, Network)
29
-	_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
27
+func (ps *DockerPluginSuite) TestPluginBasicOps(c *check.C) {
28
+	plugin := ps.getPluginRepoWithTag()
29
+	_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", plugin)
30 30
 	c.Assert(err, checker.IsNil)
31 31
 
32 32
 	out, _, err := dockerCmdWithError("plugin", "ls")
33 33
 	c.Assert(err, checker.IsNil)
34
-	c.Assert(out, checker.Contains, pName)
35
-	c.Assert(out, checker.Contains, pTag)
34
+	c.Assert(out, checker.Contains, plugin)
36 35
 	c.Assert(out, checker.Contains, "true")
37 36
 
38
-	id, _, err := dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", pNameWithTag)
37
+	id, _, err := dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", plugin)
39 38
 	id = strings.TrimSpace(id)
40 39
 	c.Assert(err, checker.IsNil)
41 40
 
42
-	out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag)
41
+	out, _, err = dockerCmdWithError("plugin", "remove", plugin)
43 42
 	c.Assert(err, checker.NotNil)
44 43
 	c.Assert(out, checker.Contains, "is enabled")
45 44
 
46
-	_, _, err = dockerCmdWithError("plugin", "disable", pNameWithTag)
45
+	_, _, err = dockerCmdWithError("plugin", "disable", plugin)
47 46
 	c.Assert(err, checker.IsNil)
48 47
 
49
-	out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag)
48
+	out, _, err = dockerCmdWithError("plugin", "remove", plugin)
50 49
 	c.Assert(err, checker.IsNil)
51
-	c.Assert(out, checker.Contains, pNameWithTag)
50
+	c.Assert(out, checker.Contains, plugin)
52 51
 
53 52
 	_, err = os.Stat(filepath.Join(testEnv.DockerBasePath(), "plugins", id))
54 53
 	if !os.IsNotExist(err) {
... ...
@@ -56,8 +61,9 @@ func (s *DockerSuite) TestPluginBasicOps(c *check.C) {
56 56
 	}
57 57
 }
58 58
 
59
-func (s *DockerSuite) TestPluginForceRemove(c *check.C) {
60
-	testRequires(c, DaemonIsLinux, IsAmd64, Network)
59
+func (ps *DockerPluginSuite) TestPluginForceRemove(c *check.C) {
60
+	pNameWithTag := ps.getPluginRepoWithTag()
61
+
61 62
 	out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
62 63
 	c.Assert(err, checker.IsNil)
63 64
 
... ...
@@ -71,6 +77,7 @@ func (s *DockerSuite) TestPluginForceRemove(c *check.C) {
71 71
 
72 72
 func (s *DockerSuite) TestPluginActive(c *check.C) {
73 73
 	testRequires(c, DaemonIsLinux, IsAmd64, Network)
74
+
74 75
 	_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
75 76
 	c.Assert(err, checker.IsNil)
76 77
 
... ...
@@ -118,8 +125,9 @@ func (s *DockerSuite) TestPluginActiveNetwork(c *check.C) {
118 118
 	c.Assert(out, checker.Contains, npNameWithTag)
119 119
 }
120 120
 
121
-func (s *DockerSuite) TestPluginInstallDisable(c *check.C) {
122
-	testRequires(c, DaemonIsLinux, IsAmd64, Network)
121
+func (ps *DockerPluginSuite) TestPluginInstallDisable(c *check.C) {
122
+	pName := ps.getPluginRepoWithTag()
123
+
123 124
 	out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", "--disable", pName)
124 125
 	c.Assert(err, checker.IsNil)
125 126
 	c.Assert(strings.TrimSpace(out), checker.Contains, pName)
... ...
@@ -150,22 +158,39 @@ func (s *DockerSuite) TestPluginInstallDisableVolumeLs(c *check.C) {
150 150
 	dockerCmd(c, "volume", "ls")
151 151
 }
152 152
 
153
-func (s *DockerSuite) TestPluginSet(c *check.C) {
154
-	testRequires(c, DaemonIsLinux, IsAmd64, Network)
155
-	out, _ := dockerCmd(c, "plugin", "install", "--grant-all-permissions", "--disable", pName)
156
-	c.Assert(strings.TrimSpace(out), checker.Contains, pName)
153
+func (ps *DockerPluginSuite) TestPluginSet(c *check.C) {
154
+	// Create a new plugin with extra settings
155
+	client, err := request.NewClient()
156
+	c.Assert(err, checker.IsNil, check.Commentf("failed to create test client"))
157 157
 
158
-	env, _ := dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", pName)
158
+	name := "test"
159
+	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
160
+	defer cancel()
161
+
162
+	initialValue := "0"
163
+	err = plugin.Create(ctx, client, name, func(cfg *plugin.Config) {
164
+		cfg.Env = []types.PluginEnv{{Name: "DEBUG", Value: &initialValue, Settable: []string{"value"}}}
165
+	})
166
+	c.Assert(err, checker.IsNil, check.Commentf("failed to create test plugin"))
167
+
168
+	env, _ := dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", name)
159 169
 	c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=0]")
160 170
 
161
-	dockerCmd(c, "plugin", "set", pName, "DEBUG=1")
171
+	dockerCmd(c, "plugin", "set", name, "DEBUG=1")
162 172
 
163
-	env, _ = dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", pName)
173
+	env, _ = dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", name)
164 174
 	c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=1]")
165 175
 }
166 176
 
167
-func (s *DockerSuite) TestPluginInstallArgs(c *check.C) {
168
-	testRequires(c, DaemonIsLinux, IsAmd64, Network)
177
+func (ps *DockerPluginSuite) TestPluginInstallArgs(c *check.C) {
178
+	pName := path.Join(ps.registryHost(), "plugin", "testplugininstallwithargs")
179
+	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
180
+	defer cancel()
181
+
182
+	plugin.CreateInRegistry(ctx, pName, nil, func(cfg *plugin.Config) {
183
+		cfg.Env = []types.PluginEnv{{Name: "DEBUG", Settable: []string{"value"}}}
184
+	})
185
+
169 186
 	out, _ := dockerCmd(c, "plugin", "install", "--grant-all-permissions", "--disable", pName, "DEBUG=1")
170 187
 	c.Assert(strings.TrimSpace(out), checker.Contains, pName)
171 188
 
... ...
@@ -173,8 +198,8 @@ func (s *DockerSuite) TestPluginInstallArgs(c *check.C) {
173 173
 	c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=1]")
174 174
 }
175 175
 
176
-func (s *DockerRegistrySuite) TestPluginInstallImage(c *check.C) {
177
-	testRequires(c, DaemonIsLinux, IsAmd64)
176
+func (ps *DockerPluginSuite) TestPluginInstallImage(c *check.C) {
177
+	testRequires(c, IsAmd64)
178 178
 
179 179
 	repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
180 180
 	// tag the image to upload it to the private registry
... ...
@@ -187,8 +212,9 @@ func (s *DockerRegistrySuite) TestPluginInstallImage(c *check.C) {
187 187
 	c.Assert(out, checker.Contains, `Encountered remote "application/vnd.docker.container.image.v1+json"(image) when fetching`)
188 188
 }
189 189
 
190
-func (s *DockerSuite) TestPluginEnableDisableNegative(c *check.C) {
191
-	testRequires(c, DaemonIsLinux, IsAmd64, Network)
190
+func (ps *DockerPluginSuite) TestPluginEnableDisableNegative(c *check.C) {
191
+	pName := ps.getPluginRepoWithTag()
192
+
192 193
 	out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pName)
193 194
 	c.Assert(err, checker.IsNil)
194 195
 	c.Assert(strings.TrimSpace(out), checker.Contains, pName)
... ...
@@ -208,9 +234,7 @@ func (s *DockerSuite) TestPluginEnableDisableNegative(c *check.C) {
208 208
 	c.Assert(err, checker.IsNil)
209 209
 }
210 210
 
211
-func (s *DockerSuite) TestPluginCreate(c *check.C) {
212
-	testRequires(c, DaemonIsLinux, IsAmd64, Network)
213
-
211
+func (ps *DockerPluginSuite) TestPluginCreate(c *check.C) {
214 212
 	name := "foo/bar-driver"
215 213
 	temp, err := ioutil.TempDir("", "foo")
216 214
 	c.Assert(err, checker.IsNil)
... ...
@@ -242,15 +266,15 @@ func (s *DockerSuite) TestPluginCreate(c *check.C) {
242 242
 	c.Assert(len(strings.Split(strings.TrimSpace(out), "\n")), checker.Equals, 2)
243 243
 }
244 244
 
245
-func (s *DockerSuite) TestPluginInspect(c *check.C) {
246
-	testRequires(c, DaemonIsLinux, IsAmd64, Network)
245
+func (ps *DockerPluginSuite) TestPluginInspect(c *check.C) {
246
+	pNameWithTag := ps.getPluginRepoWithTag()
247
+
247 248
 	_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
248 249
 	c.Assert(err, checker.IsNil)
249 250
 
250 251
 	out, _, err := dockerCmdWithError("plugin", "ls")
251 252
 	c.Assert(err, checker.IsNil)
252
-	c.Assert(out, checker.Contains, pName)
253
-	c.Assert(out, checker.Contains, pTag)
253
+	c.Assert(out, checker.Contains, pNameWithTag)
254 254
 	c.Assert(out, checker.Contains, "true")
255 255
 
256 256
 	// Find the ID first
... ...
@@ -275,7 +299,7 @@ func (s *DockerSuite) TestPluginInspect(c *check.C) {
275 275
 	c.Assert(strings.TrimSpace(out), checker.Equals, id)
276 276
 
277 277
 	// Name without tag form
278
-	out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", pName)
278
+	out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", ps.getPluginRepo())
279 279
 	c.Assert(err, checker.IsNil)
280 280
 	c.Assert(strings.TrimSpace(out), checker.Equals, id)
281 281
 
... ...
@@ -347,21 +371,29 @@ func (s *DockerTrustSuite) TestPluginUntrustedInstall(c *check.C) {
347 347
 	})
348 348
 }
349 349
 
350
-func (s *DockerSuite) TestPluginIDPrefix(c *check.C) {
351
-	testRequires(c, DaemonIsLinux, IsAmd64, Network)
352
-	_, _, err := dockerCmdWithError("plugin", "install", "--disable", "--grant-all-permissions", pNameWithTag)
353
-	c.Assert(err, checker.IsNil)
350
+func (ps *DockerPluginSuite) TestPluginIDPrefix(c *check.C) {
351
+	name := "test"
352
+	client, err := request.NewClient()
353
+	c.Assert(err, checker.IsNil, check.Commentf("error creating test client"))
354
+
355
+	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
356
+	initialValue := "0"
357
+	err = plugin.Create(ctx, client, name, func(cfg *plugin.Config) {
358
+		cfg.Env = []types.PluginEnv{{Name: "DEBUG", Value: &initialValue, Settable: []string{"value"}}}
359
+	})
360
+	cancel()
361
+
362
+	c.Assert(err, checker.IsNil, check.Commentf("failed to create test plugin"))
354 363
 
355 364
 	// Find ID first
356
-	id, _, err := dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", pNameWithTag)
365
+	id, _, err := dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", name)
357 366
 	id = strings.TrimSpace(id)
358 367
 	c.Assert(err, checker.IsNil)
359 368
 
360 369
 	// List current state
361 370
 	out, _, err := dockerCmdWithError("plugin", "ls")
362 371
 	c.Assert(err, checker.IsNil)
363
-	c.Assert(out, checker.Contains, pName)
364
-	c.Assert(out, checker.Contains, pTag)
372
+	c.Assert(out, checker.Contains, name)
365 373
 	c.Assert(out, checker.Contains, "false")
366 374
 
367 375
 	env, _ := dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", id[:5])
... ...
@@ -377,8 +409,7 @@ func (s *DockerSuite) TestPluginIDPrefix(c *check.C) {
377 377
 	c.Assert(err, checker.IsNil)
378 378
 	out, _, err = dockerCmdWithError("plugin", "ls")
379 379
 	c.Assert(err, checker.IsNil)
380
-	c.Assert(out, checker.Contains, pName)
381
-	c.Assert(out, checker.Contains, pTag)
380
+	c.Assert(out, checker.Contains, name)
382 381
 	c.Assert(out, checker.Contains, "true")
383 382
 
384 383
 	// Disable
... ...
@@ -386,8 +417,7 @@ func (s *DockerSuite) TestPluginIDPrefix(c *check.C) {
386 386
 	c.Assert(err, checker.IsNil)
387 387
 	out, _, err = dockerCmdWithError("plugin", "ls")
388 388
 	c.Assert(err, checker.IsNil)
389
-	c.Assert(out, checker.Contains, pName)
390
-	c.Assert(out, checker.Contains, pTag)
389
+	c.Assert(out, checker.Contains, name)
391 390
 	c.Assert(out, checker.Contains, "false")
392 391
 
393 392
 	// Remove
... ...
@@ -396,13 +426,10 @@ func (s *DockerSuite) TestPluginIDPrefix(c *check.C) {
396 396
 	// List returns none
397 397
 	out, _, err = dockerCmdWithError("plugin", "ls")
398 398
 	c.Assert(err, checker.IsNil)
399
-	c.Assert(out, checker.Not(checker.Contains), pName)
400
-	c.Assert(out, checker.Not(checker.Contains), pTag)
399
+	c.Assert(out, checker.Not(checker.Contains), name)
401 400
 }
402 401
 
403
-func (s *DockerSuite) TestPluginListDefaultFormat(c *check.C) {
404
-	testRequires(c, DaemonIsLinux, Network, IsAmd64)
405
-
402
+func (ps *DockerPluginSuite) TestPluginListDefaultFormat(c *check.C) {
406 403
 	config, err := ioutil.TempDir("", "config-file-")
407 404
 	c.Assert(err, check.IsNil)
408 405
 	defer os.RemoveAll(config)
... ...
@@ -410,17 +437,25 @@ func (s *DockerSuite) TestPluginListDefaultFormat(c *check.C) {
410 410
 	err = ioutil.WriteFile(filepath.Join(config, "config.json"), []byte(`{"pluginsFormat": "raw"}`), 0644)
411 411
 	c.Assert(err, check.IsNil)
412 412
 
413
-	out, _ := dockerCmd(c, "plugin", "install", "--grant-all-permissions", pName)
414
-	c.Assert(strings.TrimSpace(out), checker.Contains, pName)
413
+	name := "test:latest"
414
+	client, err := request.NewClient()
415
+	c.Assert(err, checker.IsNil, check.Commentf("error creating test client"))
416
+
417
+	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
418
+	defer cancel()
419
+	err = plugin.Create(ctx, client, name, func(cfg *plugin.Config) {
420
+		cfg.Description = "test plugin"
421
+	})
422
+	c.Assert(err, checker.IsNil, check.Commentf("failed to create test plugin"))
415 423
 
416
-	out, _ = dockerCmd(c, "plugin", "inspect", "--format", "{{.ID}}", pNameWithTag)
424
+	out, _ := dockerCmd(c, "plugin", "inspect", "--format", "{{.ID}}", name)
417 425
 	id := strings.TrimSpace(out)
418 426
 
419 427
 	// We expect the format to be in `raw + --no-trunc`
420 428
 	expectedOutput := fmt.Sprintf(`plugin_id: %s
421 429
 name: %s
422
-description: A sample volume plugin for Docker
423
-enabled: true`, id, pNameWithTag)
430
+description: test plugin
431
+enabled: false`, id, name)
424 432
 
425 433
 	out, _ = dockerCmd(c, "--config", config, "plugin", "ls", "--no-trunc")
426 434
 	c.Assert(strings.TrimSpace(out), checker.Contains, expectedOutput)
... ...
@@ -1,20 +1,9 @@
1 1
 package plugin
2 2
 
3 3
 import (
4
-	"encoding/json"
5 4
 	"io"
6
-	"io/ioutil"
7
-	"os"
8
-	"os/exec"
9
-	"path/filepath"
10
-	"time"
11 5
 
12 6
 	"github.com/docker/docker/api/types"
13
-	"github.com/docker/docker/libcontainerd"
14
-	"github.com/docker/docker/pkg/archive"
15
-	"github.com/docker/docker/plugin"
16
-	"github.com/docker/docker/registry"
17
-	"github.com/pkg/errors"
18 7
 	"golang.org/x/net/context"
19 8
 )
20 9
 
... ...
@@ -43,141 +32,3 @@ func WithBinary(bin string) CreateOpt {
43 43
 type CreateClient interface {
44 44
 	PluginCreate(context.Context, io.Reader, types.PluginCreateOptions) error
45 45
 }
46
-
47
-// Create creates a new plugin with the specified name
48
-func Create(ctx context.Context, c CreateClient, name string, opts ...CreateOpt) error {
49
-	tmpDir, err := ioutil.TempDir("", "create-test-plugin")
50
-	if err != nil {
51
-		return err
52
-	}
53
-	defer os.RemoveAll(tmpDir)
54
-
55
-	tar, err := makePluginBundle(tmpDir, opts...)
56
-	if err != nil {
57
-		return err
58
-	}
59
-	defer tar.Close()
60
-
61
-	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
62
-	defer cancel()
63
-
64
-	return c.PluginCreate(ctx, tar, types.PluginCreateOptions{RepoName: name})
65
-}
66
-
67
-// TODO(@cpuguy83): we really shouldn't have to do this...
68
-// The manager panics on init when `Executor` is not set.
69
-type dummyExecutor struct{}
70
-
71
-func (dummyExecutor) Client(libcontainerd.Backend) (libcontainerd.Client, error) { return nil, nil }
72
-func (dummyExecutor) Cleanup()                                                   {}
73
-func (dummyExecutor) UpdateOptions(...libcontainerd.RemoteOption) error          { return nil }
74
-
75
-// CreateInRegistry makes a plugin (locally) and pushes it to a registry.
76
-// This does not use a dockerd instance to create or push the plugin.
77
-// If you just want to create a plugin in some daemon, use `Create`.
78
-//
79
-// This can be useful when testing plugins on swarm where you don't really want
80
-// the plugin to exist on any of the daemons (immediately) and there needs to be
81
-// some way to distribute the plugin.
82
-func CreateInRegistry(ctx context.Context, repo string, auth *types.AuthConfig, opts ...CreateOpt) error {
83
-	tmpDir, err := ioutil.TempDir("", "create-test-plugin-local")
84
-	if err != nil {
85
-		return err
86
-	}
87
-	defer os.RemoveAll(tmpDir)
88
-
89
-	inPath := filepath.Join(tmpDir, "plugin")
90
-	if err := os.MkdirAll(inPath, 0755); err != nil {
91
-		return errors.Wrap(err, "error creating plugin root")
92
-	}
93
-
94
-	tar, err := makePluginBundle(inPath, opts...)
95
-	if err != nil {
96
-		return err
97
-	}
98
-	defer tar.Close()
99
-
100
-	managerConfig := plugin.ManagerConfig{
101
-		Store:           plugin.NewStore(),
102
-		RegistryService: registry.NewService(registry.ServiceOptions{V2Only: true}),
103
-		Root:            filepath.Join(tmpDir, "root"),
104
-		ExecRoot:        "/run/docker", // manager init fails if not set
105
-		Executor:        dummyExecutor{},
106
-		LogPluginEvent:  func(id, name, action string) {}, // panics when not set
107
-	}
108
-	manager, err := plugin.NewManager(managerConfig)
109
-	if err != nil {
110
-		return errors.Wrap(err, "error creating plugin manager")
111
-	}
112
-
113
-	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
114
-	defer cancel()
115
-	if err := manager.CreateFromContext(ctx, tar, &types.PluginCreateOptions{RepoName: repo}); err != nil {
116
-		return err
117
-	}
118
-
119
-	if auth == nil {
120
-		auth = &types.AuthConfig{}
121
-	}
122
-	err = manager.Push(ctx, repo, nil, auth, ioutil.Discard)
123
-	return errors.Wrap(err, "error pushing plugin")
124
-}
125
-
126
-func makePluginBundle(inPath string, opts ...CreateOpt) (io.ReadCloser, error) {
127
-	p := &types.PluginConfig{
128
-		Interface: types.PluginConfigInterface{
129
-			Socket: "basic.sock",
130
-			Types:  []types.PluginInterfaceType{{Capability: "docker.dummy/1.0"}},
131
-		},
132
-		Entrypoint: []string{"/basic"},
133
-	}
134
-	cfg := &Config{
135
-		PluginConfig: p,
136
-	}
137
-	for _, o := range opts {
138
-		o(cfg)
139
-	}
140
-	if cfg.binPath == "" {
141
-		binPath, err := ensureBasicPluginBin()
142
-		if err != nil {
143
-			return nil, err
144
-		}
145
-		cfg.binPath = binPath
146
-	}
147
-
148
-	configJSON, err := json.Marshal(p)
149
-	if err != nil {
150
-		return nil, err
151
-	}
152
-	if err := ioutil.WriteFile(filepath.Join(inPath, "config.json"), configJSON, 0644); err != nil {
153
-		return nil, err
154
-	}
155
-	if err := os.MkdirAll(filepath.Join(inPath, "rootfs", filepath.Dir(p.Entrypoint[0])), 0755); err != nil {
156
-		return nil, errors.Wrap(err, "error creating plugin rootfs dir")
157
-	}
158
-	if err := archive.NewDefaultArchiver().CopyFileWithTar(cfg.binPath, filepath.Join(inPath, "rootfs", p.Entrypoint[0])); err != nil {
159
-		return nil, errors.Wrap(err, "error copying plugin binary to rootfs path")
160
-	}
161
-	tar, err := archive.Tar(inPath, archive.Uncompressed)
162
-	return tar, errors.Wrap(err, "error making plugin archive")
163
-}
164
-
165
-func ensureBasicPluginBin() (string, error) {
166
-	name := "docker-basic-plugin"
167
-	p, err := exec.LookPath(name)
168
-	if err == nil {
169
-		return p, nil
170
-	}
171
-
172
-	goBin, err := exec.LookPath("go")
173
-	if err != nil {
174
-		return "", err
175
-	}
176
-	installPath := filepath.Join(os.Getenv("GOPATH"), "bin", name)
177
-	cmd := exec.Command(goBin, "build", "-o", installPath, "./"+filepath.Join("fixtures", "plugin", "basic"))
178
-	cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
179
-	if out, err := cmd.CombinedOutput(); err != nil {
180
-		return "", errors.Wrapf(err, "error building basic plugin bin: %s", string(out))
181
-	}
182
-	return installPath, nil
183
-}
184 46
new file mode 100644
... ...
@@ -0,0 +1,157 @@
0
+package plugin
1
+
2
+import (
3
+	"encoding/json"
4
+	"io"
5
+	"io/ioutil"
6
+	"os"
7
+	"os/exec"
8
+	"path/filepath"
9
+	"time"
10
+
11
+	"github.com/docker/docker/api/types"
12
+	"github.com/docker/docker/libcontainerd"
13
+	"github.com/docker/docker/pkg/archive"
14
+	"github.com/docker/docker/plugin"
15
+	"github.com/docker/docker/registry"
16
+	"github.com/pkg/errors"
17
+	"golang.org/x/net/context"
18
+)
19
+
20
+// Create creates a new plugin with the specified name
21
+func Create(ctx context.Context, c CreateClient, name string, opts ...CreateOpt) error {
22
+	tmpDir, err := ioutil.TempDir("", "create-test-plugin")
23
+	if err != nil {
24
+		return err
25
+	}
26
+	defer os.RemoveAll(tmpDir)
27
+
28
+	tar, err := makePluginBundle(tmpDir, opts...)
29
+	if err != nil {
30
+		return err
31
+	}
32
+	defer tar.Close()
33
+
34
+	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
35
+	defer cancel()
36
+
37
+	return c.PluginCreate(ctx, tar, types.PluginCreateOptions{RepoName: name})
38
+}
39
+
40
+// TODO(@cpuguy83): we really shouldn't have to do this...
41
+// The manager panics on init when `Executor` is not set.
42
+type dummyExecutor struct{}
43
+
44
+func (dummyExecutor) Client(libcontainerd.Backend) (libcontainerd.Client, error) { return nil, nil }
45
+func (dummyExecutor) Cleanup()                                                   {}
46
+func (dummyExecutor) UpdateOptions(...libcontainerd.RemoteOption) error          { return nil }
47
+
48
+// CreateInRegistry makes a plugin (locally) and pushes it to a registry.
49
+// This does not use a dockerd instance to create or push the plugin.
50
+// If you just want to create a plugin in some daemon, use `Create`.
51
+//
52
+// This can be useful when testing plugins on swarm where you don't really want
53
+// the plugin to exist on any of the daemons (immediately) and there needs to be
54
+// some way to distribute the plugin.
55
+func CreateInRegistry(ctx context.Context, repo string, auth *types.AuthConfig, opts ...CreateOpt) error {
56
+	tmpDir, err := ioutil.TempDir("", "create-test-plugin-local")
57
+	if err != nil {
58
+		return err
59
+	}
60
+	defer os.RemoveAll(tmpDir)
61
+
62
+	inPath := filepath.Join(tmpDir, "plugin")
63
+	if err := os.MkdirAll(inPath, 0755); err != nil {
64
+		return errors.Wrap(err, "error creating plugin root")
65
+	}
66
+
67
+	tar, err := makePluginBundle(inPath, opts...)
68
+	if err != nil {
69
+		return err
70
+	}
71
+	defer tar.Close()
72
+
73
+	managerConfig := plugin.ManagerConfig{
74
+		Store:           plugin.NewStore(),
75
+		RegistryService: registry.NewService(registry.ServiceOptions{V2Only: true}),
76
+		Root:            filepath.Join(tmpDir, "root"),
77
+		ExecRoot:        "/run/docker", // manager init fails if not set
78
+		Executor:        dummyExecutor{},
79
+		LogPluginEvent:  func(id, name, action string) {}, // panics when not set
80
+	}
81
+	manager, err := plugin.NewManager(managerConfig)
82
+	if err != nil {
83
+		return errors.Wrap(err, "error creating plugin manager")
84
+	}
85
+
86
+	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
87
+	defer cancel()
88
+	if err := manager.CreateFromContext(ctx, tar, &types.PluginCreateOptions{RepoName: repo}); err != nil {
89
+		return err
90
+	}
91
+
92
+	if auth == nil {
93
+		auth = &types.AuthConfig{}
94
+	}
95
+	err = manager.Push(ctx, repo, nil, auth, ioutil.Discard)
96
+	return errors.Wrap(err, "error pushing plugin")
97
+}
98
+
99
+func makePluginBundle(inPath string, opts ...CreateOpt) (io.ReadCloser, error) {
100
+	p := &types.PluginConfig{
101
+		Interface: types.PluginConfigInterface{
102
+			Socket: "basic.sock",
103
+			Types:  []types.PluginInterfaceType{{Capability: "docker.dummy/1.0"}},
104
+		},
105
+		Entrypoint: []string{"/basic"},
106
+	}
107
+	cfg := &Config{
108
+		PluginConfig: p,
109
+	}
110
+	for _, o := range opts {
111
+		o(cfg)
112
+	}
113
+	if cfg.binPath == "" {
114
+		binPath, err := ensureBasicPluginBin()
115
+		if err != nil {
116
+			return nil, err
117
+		}
118
+		cfg.binPath = binPath
119
+	}
120
+
121
+	configJSON, err := json.Marshal(p)
122
+	if err != nil {
123
+		return nil, err
124
+	}
125
+	if err := ioutil.WriteFile(filepath.Join(inPath, "config.json"), configJSON, 0644); err != nil {
126
+		return nil, err
127
+	}
128
+	if err := os.MkdirAll(filepath.Join(inPath, "rootfs", filepath.Dir(p.Entrypoint[0])), 0755); err != nil {
129
+		return nil, errors.Wrap(err, "error creating plugin rootfs dir")
130
+	}
131
+	if err := archive.NewDefaultArchiver().CopyFileWithTar(cfg.binPath, filepath.Join(inPath, "rootfs", p.Entrypoint[0])); err != nil {
132
+		return nil, errors.Wrap(err, "error copying plugin binary to rootfs path")
133
+	}
134
+	tar, err := archive.Tar(inPath, archive.Uncompressed)
135
+	return tar, errors.Wrap(err, "error making plugin archive")
136
+}
137
+
138
+func ensureBasicPluginBin() (string, error) {
139
+	name := "docker-basic-plugin"
140
+	p, err := exec.LookPath(name)
141
+	if err == nil {
142
+		return p, nil
143
+	}
144
+
145
+	goBin, err := exec.LookPath("go")
146
+	if err != nil {
147
+		return "", err
148
+	}
149
+	installPath := filepath.Join(os.Getenv("GOPATH"), "bin", name)
150
+	cmd := exec.Command(goBin, "build", "-o", installPath, "./"+filepath.Join("fixtures", "plugin", "basic"))
151
+	cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
152
+	if out, err := cmd.CombinedOutput(); err != nil {
153
+		return "", errors.Wrapf(err, "error building basic plugin bin: %s", string(out))
154
+	}
155
+	return installPath, nil
156
+}
0 157
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+// +build !linux
1
+
2
+package plugin
3
+
4
+import (
5
+	"github.com/docker/docker/api/types"
6
+	"github.com/pkg/errors"
7
+	"golang.org/x/net/context"
8
+)
9
+
10
+// Create is not supported on this platform
11
+func Create(ctx context.Context, c CreateClient, name string, opts ...CreateOpt) error {
12
+	return errors.New("not supported on this platform")
13
+}
14
+
15
+// CreateInRegistry is not supported on this platform
16
+func CreateInRegistry(ctx context.Context, repo string, auth *types.AuthConfig, opts ...CreateOpt) error {
17
+	return errors.New("not supported on this platform")
18
+}
... ...
@@ -1,6 +1,7 @@
1 1
 package main
2 2
 
3 3
 import (
4
+	"context"
4 5
 	"fmt"
5 6
 	"io/ioutil"
6 7
 	"net"
... ...
@@ -11,9 +12,12 @@ import (
11 11
 	"strings"
12 12
 	"time"
13 13
 
14
+	"github.com/docker/docker/api/types"
14 15
 	cliconfig "github.com/docker/docker/cli/config"
15 16
 	"github.com/docker/docker/integration-cli/checker"
16 17
 	"github.com/docker/docker/integration-cli/cli"
18
+	"github.com/docker/docker/integration-cli/fixtures/plugin"
19
+	"github.com/docker/docker/integration-cli/request"
17 20
 	icmd "github.com/docker/docker/pkg/testutil/cmd"
18 21
 	"github.com/docker/go-connections/tlsconfig"
19 22
 	"github.com/go-check/check"
... ...
@@ -225,10 +229,23 @@ func (s *DockerTrustSuite) setupTrustedImage(c *check.C, name string) string {
225 225
 
226 226
 func (s *DockerTrustSuite) setupTrustedplugin(c *check.C, source, name string) string {
227 227
 	repoName := fmt.Sprintf("%v/dockercli/%s:latest", privateRegistryURL, name)
228
+
229
+	client, err := request.NewClient()
230
+	c.Assert(err, checker.IsNil, check.Commentf("could not create test client"))
231
+
232
+	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
233
+	err = plugin.Create(ctx, client, repoName)
234
+	cancel()
235
+	c.Assert(err, checker.IsNil, check.Commentf("could not create test plugin"))
236
+
228 237
 	// tag the image and upload it to the private registry
229
-	cli.DockerCmd(c, "plugin", "install", "--grant-all-permissions", "--alias", repoName, source)
238
+	// TODO: shouldn't need to use the CLI to do trust
230 239
 	cli.Docker(cli.Args("plugin", "push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
231
-	cli.DockerCmd(c, "plugin", "rm", "-f", repoName)
240
+
241
+	ctx, cancel = context.WithTimeout(context.Background(), 60*time.Second)
242
+	err = client.PluginRemove(ctx, repoName, types.PluginRemoveOptions{Force: true})
243
+	cancel()
244
+	c.Assert(err, checker.IsNil, check.Commentf("failed to cleanup test plugin for trust suite"))
232 245
 	return repoName
233 246
 }
234 247