Browse code

move plugins out of experimental

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

Victor Vieux authored on 2016/11/10 10:49:09
Showing 28 changed files
... ...
@@ -16,7 +16,6 @@ func NewPluginCommand(dockerCli *command.DockerCli) *cobra.Command {
16 16
 			cmd.SetOutput(dockerCli.Err())
17 17
 			cmd.HelpFunc()(cmd, args)
18 18
 		},
19
-		Tags: map[string]string{"experimental": ""},
20 19
 	}
21 20
 
22 21
 	cmd.AddCommand(
... ...
@@ -21,6 +21,7 @@ type CommonAPIClient interface {
21 21
 	ImageAPIClient
22 22
 	NodeAPIClient
23 23
 	NetworkAPIClient
24
+	PluginAPIClient
24 25
 	ServiceAPIClient
25 26
 	SwarmAPIClient
26 27
 	SecretAPIClient
... ...
@@ -104,6 +105,19 @@ type NodeAPIClient interface {
104 104
 	NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error
105 105
 }
106 106
 
107
+// PluginAPIClient defines API client methods for the plugins
108
+type PluginAPIClient interface {
109
+	PluginList(ctx context.Context) (types.PluginsListResponse, error)
110
+	PluginRemove(ctx context.Context, name string, options types.PluginRemoveOptions) error
111
+	PluginEnable(ctx context.Context, name string) error
112
+	PluginDisable(ctx context.Context, name string) error
113
+	PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) error
114
+	PluginPush(ctx context.Context, name string, registryAuth string) error
115
+	PluginSet(ctx context.Context, name string, args []string) error
116
+	PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error)
117
+	PluginCreate(ctx context.Context, createContext io.Reader, options types.PluginCreateOptions) error
118
+}
119
+
107 120
 // ServiceAPIClient defines API client methods for the services
108 121
 type ServiceAPIClient interface {
109 122
 	ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options types.ServiceCreateOptions) (types.ServiceCreateResponse, error)
... ...
@@ -1,15 +1,12 @@
1 1
 package client
2 2
 
3 3
 import (
4
-	"io"
5
-
6 4
 	"github.com/docker/docker/api/types"
7 5
 	"golang.org/x/net/context"
8 6
 )
9 7
 
10 8
 type apiClientExperimental interface {
11 9
 	CheckpointAPIClient
12
-	PluginAPIClient
13 10
 }
14 11
 
15 12
 // CheckpointAPIClient defines API client methods for the checkpoints
... ...
@@ -18,16 +15,3 @@ type CheckpointAPIClient interface {
18 18
 	CheckpointDelete(ctx context.Context, container string, options types.CheckpointDeleteOptions) error
19 19
 	CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error)
20 20
 }
21
-
22
-// PluginAPIClient defines API client methods for the plugins
23
-type PluginAPIClient interface {
24
-	PluginList(ctx context.Context) (types.PluginsListResponse, error)
25
-	PluginRemove(ctx context.Context, name string, options types.PluginRemoveOptions) error
26
-	PluginEnable(ctx context.Context, name string) error
27
-	PluginDisable(ctx context.Context, name string) error
28
-	PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) error
29
-	PluginPush(ctx context.Context, name string, registryAuth string) error
30
-	PluginSet(ctx context.Context, name string, args []string) error
31
-	PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error)
32
-	PluginCreate(ctx context.Context, createContext io.Reader, options types.PluginCreateOptions) error
33
-}
... ...
@@ -19,6 +19,7 @@ import (
19 19
 	"github.com/docker/docker/api/server/router/container"
20 20
 	"github.com/docker/docker/api/server/router/image"
21 21
 	"github.com/docker/docker/api/server/router/network"
22
+	pluginrouter "github.com/docker/docker/api/server/router/plugin"
22 23
 	swarmrouter "github.com/docker/docker/api/server/router/swarm"
23 24
 	systemrouter "github.com/docker/docker/api/server/router/system"
24 25
 	"github.com/docker/docker/api/server/router/volume"
... ...
@@ -38,6 +39,7 @@ import (
38 38
 	"github.com/docker/docker/pkg/plugingetter"
39 39
 	"github.com/docker/docker/pkg/signal"
40 40
 	"github.com/docker/docker/pkg/system"
41
+	"github.com/docker/docker/plugin"
41 42
 	"github.com/docker/docker/registry"
42 43
 	"github.com/docker/docker/runconfig"
43 44
 	"github.com/docker/docker/utils"
... ...
@@ -457,6 +459,7 @@ func initRouter(s *apiserver.Server, d *daemon.Daemon, c *cluster.Cluster) {
457 457
 		volume.NewRouter(d),
458 458
 		build.NewRouter(dockerfile.NewBuildManager(d)),
459 459
 		swarmrouter.NewRouter(d, c),
460
+		pluginrouter.NewRouter(plugin.GetManager()),
460 461
 	}...)
461 462
 
462 463
 	if d.NetworkControllerEnabled() {
... ...
@@ -4,14 +4,12 @@ import (
4 4
 	"github.com/docker/docker/api/server/httputils"
5 5
 	"github.com/docker/docker/api/server/router"
6 6
 	checkpointrouter "github.com/docker/docker/api/server/router/checkpoint"
7
-	pluginrouter "github.com/docker/docker/api/server/router/plugin"
8 7
 	"github.com/docker/docker/daemon"
9
-	"github.com/docker/docker/plugin"
10 8
 )
11 9
 
12 10
 func addExperimentalRouters(routers []router.Router, d *daemon.Daemon, decoder httputils.ContainerDecoder) []router.Router {
13 11
 	if !d.HasExperimental() {
14 12
 		return []router.Router{}
15 13
 	}
16
-	return append(routers, checkpointrouter.NewRouter(d, decoder), pluginrouter.NewRouter(plugin.GetManager()))
14
+	return append(routers, checkpointrouter.NewRouter(d, decoder))
17 15
 }
... ...
@@ -29,6 +29,7 @@ import (
29 29
 	"github.com/docker/docker/daemon/events"
30 30
 	"github.com/docker/docker/daemon/exec"
31 31
 	"github.com/docker/docker/dockerversion"
32
+	"github.com/docker/docker/plugin"
32 33
 	"github.com/docker/libnetwork/cluster"
33 34
 	// register graph drivers
34 35
 	_ "github.com/docker/docker/daemon/graphdriver/register"
... ...
@@ -1267,3 +1268,16 @@ func (daemon *Daemon) GetCluster() Cluster {
1267 1267
 func (daemon *Daemon) SetCluster(cluster Cluster) {
1268 1268
 	daemon.cluster = cluster
1269 1269
 }
1270
+
1271
+func (daemon *Daemon) pluginInit(cfg *Config, remote libcontainerd.Remote) error {
1272
+	return plugin.Init(cfg.Root, daemon.PluginStore, remote, daemon.RegistryService, cfg.LiveRestoreEnabled, daemon.LogPluginEvent)
1273
+}
1274
+
1275
+func (daemon *Daemon) pluginShutdown() {
1276
+	manager := plugin.GetManager()
1277
+	// Check for a valid manager object. In error conditions, daemon init can fail
1278
+	// and shutdown called, before plugin manager is initialized.
1279
+	if manager != nil {
1280
+		manager.Shutdown()
1281
+	}
1282
+}
... ...
@@ -1,30 +1,7 @@
1 1
 package daemon
2 2
 
3
-import (
4
-	"github.com/docker/docker/api/types/container"
5
-	"github.com/docker/docker/libcontainerd"
6
-	"github.com/docker/docker/plugin"
7
-)
3
+import "github.com/docker/docker/api/types/container"
8 4
 
9 5
 func (daemon *Daemon) verifyExperimentalContainerSettings(hostConfig *container.HostConfig, config *container.Config) ([]string, error) {
10 6
 	return nil, nil
11 7
 }
12
-
13
-func (daemon *Daemon) pluginInit(cfg *Config, remote libcontainerd.Remote) error {
14
-	if !daemon.HasExperimental() {
15
-		return nil
16
-	}
17
-	return plugin.Init(cfg.Root, daemon.PluginStore, remote, daemon.RegistryService, cfg.LiveRestoreEnabled, daemon.LogPluginEvent)
18
-}
19
-
20
-func (daemon *Daemon) pluginShutdown() {
21
-	if !daemon.HasExperimental() {
22
-		return
23
-	}
24
-	manager := plugin.GetManager()
25
-	// Check for a valid manager object. In error conditions, daemon init can fail
26
-	// and shutdown called, before plugin manager is initialized.
27
-	if manager != nil {
28
-		manager.Shutdown()
29
-	}
30
-}
... ...
@@ -5,7 +5,6 @@ aliases: [
5 5
 title: "Plugin config"
6 6
 description: "How develop and use a plugin with the managed plugin system"
7 7
 keywords: "API, Usage, plugins, documentation, developer"
8
-advisory: "experimental"
9 8
 ---
10 9
 
11 10
 <!-- This file is maintained within the docker/docker Github
... ...
@@ -19,8 +18,8 @@ advisory: "experimental"
19 19
 
20 20
 # Plugin Config Version 0 of Plugin V2
21 21
 
22
-This document outlines the format of the V0 plugin config. The plugin
23
-config described herein was introduced in the Docker daemon (experimental version) in the [v1.12.0
22
+This document outlines the format of the V0 plugin configuration. The plugin
23
+config described herein was introduced in the Docker daemon in the [v1.12.0
24 24
 release](https://github.com/docker/docker/commit/f37117045c5398fd3dca8016ea8ca0cb47e7312b).
25 25
 
26 26
 Plugin configs describe the various constituents of a docker plugin. Plugin
... ...
@@ -171,7 +170,6 @@ Config provides the base accessible fields for working with V0 plugin format
171 171
 
172 172
 ```
173 173
 {
174
-       	"configVersion": "v0",
175 174
        	"description": "A test plugin for Docker",
176 175
        	"documentation": "https://docs.docker.com/engine/extend/plugins/",
177 176
        	"entrypoint": ["plugin-no-remove", "/data"],
... ...
@@ -1,5 +1,4 @@
1 1
 ---
2
-advisory: experimental
3 2
 aliases:
4 3
 - /engine/extend/
5 4
 description: Develop and use a plugin with the managed plugin system
... ...
@@ -18,9 +17,6 @@ title: Managed plugin system
18 18
 
19 19
 # Docker Engine managed plugin system
20 20
 
21
-This document describes the plugin system available today in the **experimental
22
-build** of Docker 1.12:
23
-
24 21
 * [Installing and using a plugin](index.md#installing-and-using-a-plugin)
25 22
 * [Developing a plugin](index.md#developing-a-plugin)
26 23
 
... ...
@@ -17,8 +17,8 @@ keywords: "Examples, Usage, plugins, docker, documentation, user guide"
17 17
 # Use Docker Engine plugins
18 18
 
19 19
 This document describes the Docker Engine plugins generally available in Docker
20
-Engine. To view information on plugins managed by Docker Engine currently in
21
-experimental status, refer to [Docker Engine plugin system](index.md).
20
+Engine. To view information on plugins managed by Docker,
21
+refer to [Docker Engine plugin system](index.md).
22 22
 
23 23
 You can extend the capabilities of the Docker Engine by loading third-party
24 24
 plugins. This page explains the types of plugins and provides links to several
... ...
@@ -19,8 +19,7 @@ Docker plugins are out-of-process extensions which add capabilities to the
19 19
 Docker Engine.
20 20
 
21 21
 This document describes the Docker Engine plugin API. To view information on
22
-plugins managed by Docker Engine currently in experimental status, refer to
23
-[Docker Engine plugin system](index.md).
22
+plugins managed by Docker Engine, refer to [Docker Engine plugin system](index.md).
24 23
 
25 24
 This page is intended for people who want to develop their own Docker plugin.
26 25
 If you just want to learn about or use Docker plugins, look
... ...
@@ -17,8 +17,8 @@ aliases: ["/engine/extend/authorization/"]
17 17
 # Create an authorization plugin
18 18
 
19 19
 This document describes the Docker Engine plugins generally available in Docker
20
-Engine. To view information on plugins managed by Docker Engine currently in
21
-experimental status, refer to [Docker Engine plugin system](index.md).
20
+Engine. To view information on plugins managed by Docker Engine,
21
+refer to [Docker Engine plugin system](index.md).
22 22
 
23 23
 Docker's out-of-the-box authorization model is all or nothing. Any user with
24 24
 permission to access the Docker daemon can run any Docker client command. The
... ...
@@ -184,6 +184,16 @@ This section lists each version from latest to oldest.  Each listing includes a
184 184
 * `POST /services/create` and `POST /services/(id or name)/update` now accept the `TTY` parameter, which allocate a pseudo-TTY in container.
185 185
 * `POST /services/create` and `POST /services/(id or name)/update` now accept the `DNSConfig` parameter, which specifies DNS related configurations in resolver configuration file (resolv.conf) through `Nameservers`, `Search`, and `Options`.
186 186
 * `GET /networks/(id or name)` now includes IP and name of all peers nodes for swarm mode overlay networks.
187
+* `GET /plugins` list plugins.
188
+* `POST /plugins/pull?name=<plugin name>` pulls a plugin.
189
+* `GET /plugins/(plugin name)` inspect a plugin.
190
+* `POST /plugins/(plugin name)/set` configure a plugin.
191
+* `POST /plugins/(plugin name)/enable` enable a plugin.
192
+* `POST /plugins/(plugin name)/disable` disable a plugin.
193
+* `POST /plugins/(plugin name)/push` push a pluging.
194
+* `POST /plugins/create?name=(plugin name)` create a plugin.
195
+* `DELETE /plugins/(plugin name)` delete a plugin.
196
+
187 197
 
188 198
 ### v1.24 API changes
189 199
 
... ...
@@ -4291,7 +4291,7 @@ Content-Type: application/json
4291 4291
 
4292 4292
 ### Configure a plugin
4293 4293
 
4294
-POST /plugins/(plugin name)/set`
4294
+`POST /plugins/(plugin name)/set`
4295 4295
 
4296 4296
 **Example request**:
4297 4297
 
... ...
@@ -4438,11 +4438,9 @@ Content-Type: text/plain; charset=utf-8
4438 4438
 -   **204** - no error
4439 4439
 -   **500** - server error
4440 4440
 
4441
-<!-- TODO Document "docker plugin push" endpoint once we have "plugin build"
4442
-
4443 4441
 ### Push a plugin
4444 4442
 
4445
-`POST /v1.25/plugins/tiborvass/(plugin name)/push HTTP/1.1`
4443
+`POST /v1.25/plugins/(plugin name)/push`
4446 4444
 
4447 4445
 Pushes a plugin to the registry.
4448 4446
 
... ...
@@ -4464,7 +4462,6 @@ an image](#create-an-image) section for more details.
4464 4464
 -   **200** - no error
4465 4465
 -   **404** - plugin not installed
4466 4466
 
4467 4467
 
4468 4468
 ## 3.7 Nodes
4469 4469
 
... ...
@@ -1,8 +1,7 @@
1 1
 ---
2
-title: "plugin create (experimental)"
2
+title: "plugin create"
3 3
 description: "the plugin create command description and usage"
4 4
 keywords: "plugin, create"
5
-advisory: "experimental"
6 5
 ---
7 6
 
8 7
 <!-- This file is maintained within the docker/docker Github
... ...
@@ -14,10 +13,12 @@ advisory: "experimental"
14 14
      will be rejected.
15 15
 -->
16 16
 
17
+# plugin create
18
+
17 19
 ```markdown
18 20
 Usage:  docker plugin create [OPTIONS] reponame[:tag] PATH-TO-ROOTFS
19 21
 
20
-create a plugin from the given PATH-TO-ROOTFS, which contains the plugin's root filesystem and the config file, config.json
22
+Create a plugin from a rootfs and configuration
21 23
 
22 24
 Options:
23 25
       --compress   Compress the context using gzip 
... ...
@@ -2,7 +2,6 @@
2 2
 title: "plugin disable"
3 3
 description: "the plugin disable command description and usage"
4 4
 keywords: "plugin, disable"
5
-advisory: "experimental"
6 5
 ---
7 6
 
8 7
 <!-- This file is maintained within the docker/docker Github
... ...
@@ -14,7 +13,7 @@ advisory: "experimental"
14 14
      will be rejected.
15 15
 -->
16 16
 
17
-# plugin disable (experimental)
17
+# plugin disable
18 18
 
19 19
 ```markdown
20 20
 Usage:  docker plugin disable PLUGIN
... ...
@@ -2,7 +2,6 @@
2 2
 title: "plugin enable"
3 3
 description: "the plugin enable command description and usage"
4 4
 keywords: "plugin, enable"
5
-advisory: "experimental"
6 5
 ---
7 6
 
8 7
 <!-- This file is maintained within the docker/docker Github
... ...
@@ -14,7 +13,7 @@ advisory: "experimental"
14 14
      will be rejected.
15 15
 -->
16 16
 
17
-# plugin enable (experimental)
17
+# plugin enable
18 18
 
19 19
 ```markdown
20 20
 Usage:  docker plugin enable PLUGIN
... ...
@@ -2,7 +2,6 @@
2 2
 title: "plugin inspect"
3 3
 description: "The plugin inspect command description and usage"
4 4
 keywords: "plugin, inspect"
5
-advisory: "experimental"
6 5
 ---
7 6
 
8 7
 <!-- This file is maintained within the docker/docker Github
... ...
@@ -14,7 +13,7 @@ advisory: "experimental"
14 14
      will be rejected.
15 15
 -->
16 16
 
17
-# plugin inspect (experimental)
17
+# plugin inspect
18 18
 
19 19
 ```markdown
20 20
 Usage:  docker plugin inspect [OPTIONS] PLUGIN [PLUGIN...]
... ...
@@ -2,7 +2,6 @@
2 2
 title: "plugin install"
3 3
 description: "the plugin install command description and usage"
4 4
 keywords: "plugin, install"
5
-advisory: "experimental"
6 5
 ---
7 6
 
8 7
 <!-- This file is maintained within the docker/docker Github
... ...
@@ -14,7 +13,7 @@ advisory: "experimental"
14 14
      will be rejected.
15 15
 -->
16 16
 
17
-# plugin install (experimental)
17
+# plugin install
18 18
 
19 19
 ```markdown
20 20
 Usage:  docker plugin install [OPTIONS] PLUGIN [KEY=VALUE...]
... ...
@@ -2,7 +2,6 @@
2 2
 title: "plugin ls"
3 3
 description: "The plugin ls command description and usage"
4 4
 keywords: "plugin, list"
5
-advisory: "experimental"
6 5
 ---
7 6
 
8 7
 <!-- This file is maintained within the docker/docker Github
... ...
@@ -14,7 +13,7 @@ advisory: "experimental"
14 14
      will be rejected.
15 15
 -->
16 16
 
17
-# plugin ls (experimental)
17
+# plugin ls
18 18
 
19 19
 ```markdown
20 20
 Usage:  docker plugin ls [OPTIONS]
... ...
@@ -2,7 +2,6 @@
2 2
 title: "plugin rm"
3 3
 description: "the plugin rm command description and usage"
4 4
 keywords: "plugin, rm"
5
-advisory: "experimental"
6 5
 ---
7 6
 
8 7
 <!-- This file is maintained within the docker/docker Github
... ...
@@ -14,7 +13,7 @@ advisory: "experimental"
14 14
      will be rejected.
15 15
 -->
16 16
 
17
-# plugin rm (experimental)
17
+# plugin rm
18 18
 
19 19
 ```markdown
20 20
 Usage:  docker plugin rm [OPTIONS] PLUGIN [PLUGIN...]
... ...
@@ -2,7 +2,6 @@
2 2
 title: "plugin set"
3 3
 description: "the plugin set command description and usage"
4 4
 keywords: "plugin, set"
5
-advisory: "experimental"
6 5
 ---
7 6
 
8 7
 <!-- This file is maintained within the docker/docker Github
... ...
@@ -14,7 +13,7 @@ advisory: "experimental"
14 14
      will be rejected.
15 15
 -->
16 16
 
17
-# plugin set (experimental)
17
+# plugin set
18 18
 
19 19
 ```markdown
20 20
 Usage:  docker plugin set PLUGIN KEY=VALUE [KEY=VALUE...]
... ...
@@ -30,7 +30,7 @@ type DockerAuthzV2Suite struct {
30 30
 }
31 31
 
32 32
 func (s *DockerAuthzV2Suite) SetUpTest(c *check.C) {
33
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
33
+	testRequires(c, DaemonIsLinux, Network)
34 34
 	s.d = NewDaemon(c)
35 35
 	c.Assert(s.d.Start(), check.IsNil)
36 36
 }
37 37
deleted file mode 100644
... ...
@@ -1,243 +0,0 @@
1
-// +build linux
2
-
3
-package main
4
-
5
-import (
6
-	"os"
7
-	"os/exec"
8
-	"path/filepath"
9
-	"strings"
10
-	"syscall"
11
-
12
-	"github.com/docker/docker/pkg/integration/checker"
13
-	"github.com/go-check/check"
14
-)
15
-
16
-var pluginName = "tiborvass/no-remove"
17
-
18
-// TestDaemonRestartWithPluginEnabled tests state restore for an enabled plugin
19
-func (s *DockerDaemonSuite) TestDaemonRestartWithPluginEnabled(c *check.C) {
20
-	testRequires(c, Network, ExperimentalDaemon)
21
-
22
-	if err := s.d.Start(); err != nil {
23
-		c.Fatalf("Could not start daemon: %v", err)
24
-	}
25
-
26
-	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
27
-		c.Fatalf("Could not install plugin: %v %s", err, out)
28
-	}
29
-
30
-	defer func() {
31
-		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
32
-			c.Fatalf("Could not disable plugin: %v %s", err, out)
33
-		}
34
-		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
35
-			c.Fatalf("Could not remove plugin: %v %s", err, out)
36
-		}
37
-	}()
38
-
39
-	if err := s.d.Restart(); err != nil {
40
-		c.Fatalf("Could not restart daemon: %v", err)
41
-	}
42
-
43
-	out, err := s.d.Cmd("plugin", "ls")
44
-	if err != nil {
45
-		c.Fatalf("Could not list plugins: %v %s", err, out)
46
-	}
47
-	c.Assert(out, checker.Contains, pluginName)
48
-	c.Assert(out, checker.Contains, "true")
49
-}
50
-
51
-// TestDaemonRestartWithPluginDisabled tests state restore for a disabled plugin
52
-func (s *DockerDaemonSuite) TestDaemonRestartWithPluginDisabled(c *check.C) {
53
-	testRequires(c, Network, ExperimentalDaemon)
54
-
55
-	if err := s.d.Start(); err != nil {
56
-		c.Fatalf("Could not start daemon: %v", err)
57
-	}
58
-
59
-	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName, "--disable"); err != nil {
60
-		c.Fatalf("Could not install plugin: %v %s", err, out)
61
-	}
62
-
63
-	defer func() {
64
-		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
65
-			c.Fatalf("Could not remove plugin: %v %s", err, out)
66
-		}
67
-	}()
68
-
69
-	if err := s.d.Restart(); err != nil {
70
-		c.Fatalf("Could not restart daemon: %v", err)
71
-	}
72
-
73
-	out, err := s.d.Cmd("plugin", "ls")
74
-	if err != nil {
75
-		c.Fatalf("Could not list plugins: %v %s", err, out)
76
-	}
77
-	c.Assert(out, checker.Contains, pluginName)
78
-	c.Assert(out, checker.Contains, "false")
79
-}
80
-
81
-// TestDaemonKillLiveRestoreWithPlugins SIGKILLs daemon started with --live-restore.
82
-// Plugins should continue to run.
83
-func (s *DockerDaemonSuite) TestDaemonKillLiveRestoreWithPlugins(c *check.C) {
84
-	testRequires(c, Network, ExperimentalDaemon)
85
-
86
-	if err := s.d.Start("--live-restore"); err != nil {
87
-		c.Fatalf("Could not start daemon: %v", err)
88
-	}
89
-	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
90
-		c.Fatalf("Could not install plugin: %v %s", err, out)
91
-	}
92
-	defer func() {
93
-		if err := s.d.Restart("--live-restore"); err != nil {
94
-			c.Fatalf("Could not restart daemon: %v", err)
95
-		}
96
-		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
97
-			c.Fatalf("Could not disable plugin: %v %s", err, out)
98
-		}
99
-		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
100
-			c.Fatalf("Could not remove plugin: %v %s", err, out)
101
-		}
102
-	}()
103
-
104
-	if err := s.d.Kill(); err != nil {
105
-		c.Fatalf("Could not kill daemon: %v", err)
106
-	}
107
-
108
-	cmd := exec.Command("pgrep", "-f", "plugin-no-remove")
109
-	if out, ec, err := runCommandWithOutput(cmd); ec != 0 {
110
-		c.Fatalf("Expected exit code '0', got %d err: %v output: %s ", ec, err, out)
111
-	}
112
-}
113
-
114
-// TestDaemonShutdownLiveRestoreWithPlugins SIGTERMs daemon started with --live-restore.
115
-// Plugins should continue to run.
116
-func (s *DockerDaemonSuite) TestDaemonShutdownLiveRestoreWithPlugins(c *check.C) {
117
-	testRequires(c, Network, ExperimentalDaemon)
118
-
119
-	if err := s.d.Start("--live-restore"); err != nil {
120
-		c.Fatalf("Could not start daemon: %v", err)
121
-	}
122
-	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
123
-		c.Fatalf("Could not install plugin: %v %s", err, out)
124
-	}
125
-	defer func() {
126
-		if err := s.d.Restart("--live-restore"); err != nil {
127
-			c.Fatalf("Could not restart daemon: %v", err)
128
-		}
129
-		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
130
-			c.Fatalf("Could not disable plugin: %v %s", err, out)
131
-		}
132
-		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
133
-			c.Fatalf("Could not remove plugin: %v %s", err, out)
134
-		}
135
-	}()
136
-
137
-	if err := s.d.cmd.Process.Signal(os.Interrupt); err != nil {
138
-		c.Fatalf("Could not kill daemon: %v", err)
139
-	}
140
-
141
-	cmd := exec.Command("pgrep", "-f", "plugin-no-remove")
142
-	if out, ec, err := runCommandWithOutput(cmd); ec != 0 {
143
-		c.Fatalf("Expected exit code '0', got %d err: %v output: %s ", ec, err, out)
144
-	}
145
-}
146
-
147
-// TestDaemonShutdownWithPlugins shuts down running plugins.
148
-func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) {
149
-	testRequires(c, Network, ExperimentalDaemon)
150
-
151
-	if err := s.d.Start(); err != nil {
152
-		c.Fatalf("Could not start daemon: %v", err)
153
-	}
154
-	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
155
-		c.Fatalf("Could not install plugin: %v %s", err, out)
156
-	}
157
-
158
-	defer func() {
159
-		if err := s.d.Restart(); err != nil {
160
-			c.Fatalf("Could not restart daemon: %v", err)
161
-		}
162
-		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
163
-			c.Fatalf("Could not disable plugin: %v %s", err, out)
164
-		}
165
-		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
166
-			c.Fatalf("Could not remove plugin: %v %s", err, out)
167
-		}
168
-	}()
169
-
170
-	if err := s.d.cmd.Process.Signal(os.Interrupt); err != nil {
171
-		c.Fatalf("Could not kill daemon: %v", err)
172
-	}
173
-
174
-	for {
175
-		if err := syscall.Kill(s.d.cmd.Process.Pid, 0); err == syscall.ESRCH {
176
-			break
177
-		}
178
-	}
179
-
180
-	cmd := exec.Command("pgrep", "-f", "plugin-no-remove")
181
-	if out, ec, err := runCommandWithOutput(cmd); ec != 1 {
182
-		c.Fatalf("Expected exit code '1', got %d err: %v output: %s ", ec, err, out)
183
-	}
184
-}
185
-
186
-// TestVolumePlugin tests volume creation using a plugin.
187
-func (s *DockerDaemonSuite) TestVolumePlugin(c *check.C) {
188
-	testRequires(c, Network, ExperimentalDaemon)
189
-
190
-	volName := "plugin-volume"
191
-	volRoot := "/data"
192
-	destDir := "/tmp/data/"
193
-	destFile := "foo"
194
-
195
-	if err := s.d.Start(); err != nil {
196
-		c.Fatalf("Could not start daemon: %v", err)
197
-	}
198
-	out, err := s.d.Cmd("plugin", "install", pluginName, "--grant-all-permissions")
199
-	if err != nil {
200
-		c.Fatalf("Could not install plugin: %v %s", err, out)
201
-	}
202
-	defer func() {
203
-		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
204
-			c.Fatalf("Could not disable plugin: %v %s", err, out)
205
-		}
206
-		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
207
-			c.Fatalf("Could not remove plugin: %v %s", err, out)
208
-		}
209
-	}()
210
-
211
-	out, err = s.d.Cmd("volume", "create", "-d", pluginName, volName)
212
-	if err != nil {
213
-		c.Fatalf("Could not create volume: %v %s", err, out)
214
-	}
215
-	defer func() {
216
-		if out, err := s.d.Cmd("volume", "remove", volName); err != nil {
217
-			c.Fatalf("Could not remove volume: %v %s", err, out)
218
-		}
219
-	}()
220
-
221
-	out, err = s.d.Cmd("volume", "ls")
222
-	if err != nil {
223
-		c.Fatalf("Could not list volume: %v %s", err, out)
224
-	}
225
-	c.Assert(out, checker.Contains, volName)
226
-	c.Assert(out, checker.Contains, pluginName)
227
-
228
-	mountPoint, err := s.d.Cmd("volume", "inspect", volName, "--format", "{{.Mountpoint}}")
229
-	if err != nil {
230
-		c.Fatalf("Could not inspect volume: %v %s", err, mountPoint)
231
-	}
232
-	mountPoint = strings.TrimSpace(mountPoint)
233
-
234
-	out, err = s.d.Cmd("run", "--rm", "-v", volName+":"+destDir, "busybox", "touch", destDir+destFile)
235
-	c.Assert(err, checker.IsNil, check.Commentf(out))
236
-	path := filepath.Join(mountPoint, destFile)
237
-	_, err = os.Lstat(path)
238
-	c.Assert(err, checker.IsNil)
239
-
240
-	// tiborvass/no-remove is a volume plugin that persists data on disk at /data,
241
-	// even after the volume is removed. So perform an explicit filesystem cleanup.
242
-	os.RemoveAll(volRoot)
243
-}
244 1
new file mode 100644
... ...
@@ -0,0 +1,243 @@
0
+// +build linux
1
+
2
+package main
3
+
4
+import (
5
+	"os"
6
+	"os/exec"
7
+	"path/filepath"
8
+	"strings"
9
+	"syscall"
10
+
11
+	"github.com/docker/docker/pkg/integration/checker"
12
+	"github.com/go-check/check"
13
+)
14
+
15
+var pluginName = "tiborvass/no-remove"
16
+
17
+// TestDaemonRestartWithPluginEnabled tests state restore for an enabled plugin
18
+func (s *DockerDaemonSuite) TestDaemonRestartWithPluginEnabled(c *check.C) {
19
+	testRequires(c, Network)
20
+
21
+	if err := s.d.Start(); err != nil {
22
+		c.Fatalf("Could not start daemon: %v", err)
23
+	}
24
+
25
+	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
26
+		c.Fatalf("Could not install plugin: %v %s", err, out)
27
+	}
28
+
29
+	defer func() {
30
+		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
31
+			c.Fatalf("Could not disable plugin: %v %s", err, out)
32
+		}
33
+		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
34
+			c.Fatalf("Could not remove plugin: %v %s", err, out)
35
+		}
36
+	}()
37
+
38
+	if err := s.d.Restart(); err != nil {
39
+		c.Fatalf("Could not restart daemon: %v", err)
40
+	}
41
+
42
+	out, err := s.d.Cmd("plugin", "ls")
43
+	if err != nil {
44
+		c.Fatalf("Could not list plugins: %v %s", err, out)
45
+	}
46
+	c.Assert(out, checker.Contains, pluginName)
47
+	c.Assert(out, checker.Contains, "true")
48
+}
49
+
50
+// TestDaemonRestartWithPluginDisabled tests state restore for a disabled plugin
51
+func (s *DockerDaemonSuite) TestDaemonRestartWithPluginDisabled(c *check.C) {
52
+	testRequires(c, Network)
53
+
54
+	if err := s.d.Start(); err != nil {
55
+		c.Fatalf("Could not start daemon: %v", err)
56
+	}
57
+
58
+	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName, "--disable"); err != nil {
59
+		c.Fatalf("Could not install plugin: %v %s", err, out)
60
+	}
61
+
62
+	defer func() {
63
+		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
64
+			c.Fatalf("Could not remove plugin: %v %s", err, out)
65
+		}
66
+	}()
67
+
68
+	if err := s.d.Restart(); err != nil {
69
+		c.Fatalf("Could not restart daemon: %v", err)
70
+	}
71
+
72
+	out, err := s.d.Cmd("plugin", "ls")
73
+	if err != nil {
74
+		c.Fatalf("Could not list plugins: %v %s", err, out)
75
+	}
76
+	c.Assert(out, checker.Contains, pluginName)
77
+	c.Assert(out, checker.Contains, "false")
78
+}
79
+
80
+// TestDaemonKillLiveRestoreWithPlugins SIGKILLs daemon started with --live-restore.
81
+// Plugins should continue to run.
82
+func (s *DockerDaemonSuite) TestDaemonKillLiveRestoreWithPlugins(c *check.C) {
83
+	testRequires(c, Network)
84
+
85
+	if err := s.d.Start("--live-restore"); err != nil {
86
+		c.Fatalf("Could not start daemon: %v", err)
87
+	}
88
+	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
89
+		c.Fatalf("Could not install plugin: %v %s", err, out)
90
+	}
91
+	defer func() {
92
+		if err := s.d.Restart("--live-restore"); err != nil {
93
+			c.Fatalf("Could not restart daemon: %v", err)
94
+		}
95
+		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
96
+			c.Fatalf("Could not disable plugin: %v %s", err, out)
97
+		}
98
+		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
99
+			c.Fatalf("Could not remove plugin: %v %s", err, out)
100
+		}
101
+	}()
102
+
103
+	if err := s.d.Kill(); err != nil {
104
+		c.Fatalf("Could not kill daemon: %v", err)
105
+	}
106
+
107
+	cmd := exec.Command("pgrep", "-f", "plugin-no-remove")
108
+	if out, ec, err := runCommandWithOutput(cmd); ec != 0 {
109
+		c.Fatalf("Expected exit code '0', got %d err: %v output: %s ", ec, err, out)
110
+	}
111
+}
112
+
113
+// TestDaemonShutdownLiveRestoreWithPlugins SIGTERMs daemon started with --live-restore.
114
+// Plugins should continue to run.
115
+func (s *DockerDaemonSuite) TestDaemonShutdownLiveRestoreWithPlugins(c *check.C) {
116
+	testRequires(c, Network)
117
+
118
+	if err := s.d.Start("--live-restore"); err != nil {
119
+		c.Fatalf("Could not start daemon: %v", err)
120
+	}
121
+	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
122
+		c.Fatalf("Could not install plugin: %v %s", err, out)
123
+	}
124
+	defer func() {
125
+		if err := s.d.Restart("--live-restore"); err != nil {
126
+			c.Fatalf("Could not restart daemon: %v", err)
127
+		}
128
+		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
129
+			c.Fatalf("Could not disable plugin: %v %s", err, out)
130
+		}
131
+		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
132
+			c.Fatalf("Could not remove plugin: %v %s", err, out)
133
+		}
134
+	}()
135
+
136
+	if err := s.d.cmd.Process.Signal(os.Interrupt); err != nil {
137
+		c.Fatalf("Could not kill daemon: %v", err)
138
+	}
139
+
140
+	cmd := exec.Command("pgrep", "-f", "plugin-no-remove")
141
+	if out, ec, err := runCommandWithOutput(cmd); ec != 0 {
142
+		c.Fatalf("Expected exit code '0', got %d err: %v output: %s ", ec, err, out)
143
+	}
144
+}
145
+
146
+// TestDaemonShutdownWithPlugins shuts down running plugins.
147
+func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) {
148
+	testRequires(c, Network)
149
+
150
+	if err := s.d.Start(); err != nil {
151
+		c.Fatalf("Could not start daemon: %v", err)
152
+	}
153
+	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
154
+		c.Fatalf("Could not install plugin: %v %s", err, out)
155
+	}
156
+
157
+	defer func() {
158
+		if err := s.d.Restart(); err != nil {
159
+			c.Fatalf("Could not restart daemon: %v", err)
160
+		}
161
+		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
162
+			c.Fatalf("Could not disable plugin: %v %s", err, out)
163
+		}
164
+		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
165
+			c.Fatalf("Could not remove plugin: %v %s", err, out)
166
+		}
167
+	}()
168
+
169
+	if err := s.d.cmd.Process.Signal(os.Interrupt); err != nil {
170
+		c.Fatalf("Could not kill daemon: %v", err)
171
+	}
172
+
173
+	for {
174
+		if err := syscall.Kill(s.d.cmd.Process.Pid, 0); err == syscall.ESRCH {
175
+			break
176
+		}
177
+	}
178
+
179
+	cmd := exec.Command("pgrep", "-f", "plugin-no-remove")
180
+	if out, ec, err := runCommandWithOutput(cmd); ec != 1 {
181
+		c.Fatalf("Expected exit code '1', got %d err: %v output: %s ", ec, err, out)
182
+	}
183
+}
184
+
185
+// TestVolumePlugin tests volume creation using a plugin.
186
+func (s *DockerDaemonSuite) TestVolumePlugin(c *check.C) {
187
+	testRequires(c, Network)
188
+
189
+	volName := "plugin-volume"
190
+	volRoot := "/data"
191
+	destDir := "/tmp/data/"
192
+	destFile := "foo"
193
+
194
+	if err := s.d.Start(); err != nil {
195
+		c.Fatalf("Could not start daemon: %v", err)
196
+	}
197
+	out, err := s.d.Cmd("plugin", "install", pluginName, "--grant-all-permissions")
198
+	if err != nil {
199
+		c.Fatalf("Could not install plugin: %v %s", err, out)
200
+	}
201
+	defer func() {
202
+		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
203
+			c.Fatalf("Could not disable plugin: %v %s", err, out)
204
+		}
205
+		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
206
+			c.Fatalf("Could not remove plugin: %v %s", err, out)
207
+		}
208
+	}()
209
+
210
+	out, err = s.d.Cmd("volume", "create", "-d", pluginName, volName)
211
+	if err != nil {
212
+		c.Fatalf("Could not create volume: %v %s", err, out)
213
+	}
214
+	defer func() {
215
+		if out, err := s.d.Cmd("volume", "remove", volName); err != nil {
216
+			c.Fatalf("Could not remove volume: %v %s", err, out)
217
+		}
218
+	}()
219
+
220
+	out, err = s.d.Cmd("volume", "ls")
221
+	if err != nil {
222
+		c.Fatalf("Could not list volume: %v %s", err, out)
223
+	}
224
+	c.Assert(out, checker.Contains, volName)
225
+	c.Assert(out, checker.Contains, pluginName)
226
+
227
+	mountPoint, err := s.d.Cmd("volume", "inspect", volName, "--format", "{{.Mountpoint}}")
228
+	if err != nil {
229
+		c.Fatalf("Could not inspect volume: %v %s", err, mountPoint)
230
+	}
231
+	mountPoint = strings.TrimSpace(mountPoint)
232
+
233
+	out, err = s.d.Cmd("run", "--rm", "-v", volName+":"+destDir, "busybox", "touch", destDir+destFile)
234
+	c.Assert(err, checker.IsNil, check.Commentf(out))
235
+	path := filepath.Join(mountPoint, destFile)
236
+	_, err = os.Lstat(path)
237
+	c.Assert(err, checker.IsNil)
238
+
239
+	// tiborvass/no-remove is a volume plugin that persists data on disk at /data,
240
+	// even after the volume is removed. So perform an explicit filesystem cleanup.
241
+	os.RemoveAll(volRoot)
242
+}
... ...
@@ -276,7 +276,7 @@ func (s *DockerSuite) TestEventsImageLoad(c *check.C) {
276 276
 }
277 277
 
278 278
 func (s *DockerSuite) TestEventsPluginOps(c *check.C) {
279
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon)
279
+	testRequires(c, DaemonIsLinux)
280 280
 
281 281
 	pluginName := "tiborvass/no-remove:latest"
282 282
 	since := daemonUnixTime(c)
... ...
@@ -769,7 +769,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *check.C) {
769 769
 }
770 770
 
771 771
 func (s *DockerNetworkSuite) TestDockerPluginV2NetworkDriver(c *check.C) {
772
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
772
+	testRequires(c, DaemonIsLinux, Network)
773 773
 
774 774
 	var (
775 775
 		npName        = "mavenugo/test-docker-netplugin"
... ...
@@ -16,7 +16,7 @@ var (
16 16
 )
17 17
 
18 18
 func (s *DockerSuite) TestPluginBasicOps(c *check.C) {
19
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
19
+	testRequires(c, DaemonIsLinux, Network)
20 20
 	_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
21 21
 	c.Assert(err, checker.IsNil)
22 22
 
... ...
@@ -47,7 +47,7 @@ func (s *DockerSuite) TestPluginBasicOps(c *check.C) {
47 47
 }
48 48
 
49 49
 func (s *DockerSuite) TestPluginForceRemove(c *check.C) {
50
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
50
+	testRequires(c, DaemonIsLinux, Network)
51 51
 	out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
52 52
 	c.Assert(err, checker.IsNil)
53 53
 
... ...
@@ -60,7 +60,7 @@ func (s *DockerSuite) TestPluginForceRemove(c *check.C) {
60 60
 }
61 61
 
62 62
 func (s *DockerSuite) TestPluginActive(c *check.C) {
63
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
63
+	testRequires(c, DaemonIsLinux, Network)
64 64
 	out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
65 65
 	c.Assert(err, checker.IsNil)
66 66
 
... ...
@@ -87,7 +87,7 @@ func (s *DockerSuite) TestPluginActive(c *check.C) {
87 87
 }
88 88
 
89 89
 func (s *DockerSuite) TestPluginInstallDisable(c *check.C) {
90
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
90
+	testRequires(c, DaemonIsLinux, Network)
91 91
 	out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", "--disable", pName)
92 92
 	c.Assert(err, checker.IsNil)
93 93
 	c.Assert(strings.TrimSpace(out), checker.Contains, pName)
... ...
@@ -110,7 +110,7 @@ func (s *DockerSuite) TestPluginInstallDisable(c *check.C) {
110 110
 }
111 111
 
112 112
 func (s *DockerSuite) TestPluginInstallDisableVolumeLs(c *check.C) {
113
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
113
+	testRequires(c, DaemonIsLinux, Network)
114 114
 	out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", "--disable", pName)
115 115
 	c.Assert(err, checker.IsNil)
116 116
 	c.Assert(strings.TrimSpace(out), checker.Contains, pName)
... ...
@@ -119,7 +119,7 @@ func (s *DockerSuite) TestPluginInstallDisableVolumeLs(c *check.C) {
119 119
 }
120 120
 
121 121
 func (s *DockerSuite) TestPluginSet(c *check.C) {
122
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
122
+	testRequires(c, DaemonIsLinux, Network)
123 123
 	out, _ := dockerCmd(c, "plugin", "install", "--grant-all-permissions", "--disable", pName)
124 124
 	c.Assert(strings.TrimSpace(out), checker.Contains, pName)
125 125
 
... ...
@@ -133,7 +133,7 @@ func (s *DockerSuite) TestPluginSet(c *check.C) {
133 133
 }
134 134
 
135 135
 func (s *DockerSuite) TestPluginInstallArgs(c *check.C) {
136
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
136
+	testRequires(c, DaemonIsLinux, Network)
137 137
 	out, _ := dockerCmd(c, "plugin", "install", "--grant-all-permissions", "--disable", pName, "DEBUG=1")
138 138
 	c.Assert(strings.TrimSpace(out), checker.Contains, pName)
139 139
 
... ...
@@ -142,14 +142,14 @@ func (s *DockerSuite) TestPluginInstallArgs(c *check.C) {
142 142
 }
143 143
 
144 144
 func (s *DockerSuite) TestPluginInstallImage(c *check.C) {
145
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon)
145
+	testRequires(c, DaemonIsLinux)
146 146
 	out, _, err := dockerCmdWithError("plugin", "install", "redis")
147 147
 	c.Assert(err, checker.NotNil)
148 148
 	c.Assert(out, checker.Contains, "content is not a plugin")
149 149
 }
150 150
 
151 151
 func (s *DockerSuite) TestPluginEnableDisableNegative(c *check.C) {
152
-	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
152
+	testRequires(c, DaemonIsLinux, Network)
153 153
 	out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pName)
154 154
 	c.Assert(err, checker.IsNil)
155 155
 	c.Assert(strings.TrimSpace(out), checker.Contains, pName)