github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/integration-cli/docker_cli_plugins_test.go (about) 1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 "os" 9 "path" 10 "path/filepath" 11 "strings" 12 "time" 13 14 "github.com/docker/docker/api/types" 15 "github.com/docker/docker/integration-cli/checker" 16 "github.com/docker/docker/integration-cli/cli" 17 "github.com/docker/docker/integration-cli/daemon" 18 "github.com/docker/docker/internal/test/fixtures/plugin" 19 "github.com/go-check/check" 20 ) 21 22 var ( 23 pluginProcessName = "sample-volume-plugin" 24 pName = "tiborvass/sample-volume-plugin" 25 npName = "tiborvass/test-docker-netplugin" 26 pTag = "latest" 27 pNameWithTag = pName + ":" + pTag 28 npNameWithTag = npName + ":" + pTag 29 ) 30 31 func (ps *DockerPluginSuite) TestPluginBasicOps(c *check.C) { 32 plugin := ps.getPluginRepoWithTag() 33 _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", plugin) 34 c.Assert(err, checker.IsNil) 35 36 out, _, err := dockerCmdWithError("plugin", "ls") 37 c.Assert(err, checker.IsNil) 38 c.Assert(out, checker.Contains, plugin) 39 c.Assert(out, checker.Contains, "true") 40 41 id, _, err := dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", plugin) 42 id = strings.TrimSpace(id) 43 c.Assert(err, checker.IsNil) 44 45 out, _, err = dockerCmdWithError("plugin", "remove", plugin) 46 c.Assert(err, checker.NotNil) 47 c.Assert(out, checker.Contains, "is enabled") 48 49 _, _, err = dockerCmdWithError("plugin", "disable", plugin) 50 c.Assert(err, checker.IsNil) 51 52 out, _, err = dockerCmdWithError("plugin", "remove", plugin) 53 c.Assert(err, checker.IsNil) 54 c.Assert(out, checker.Contains, plugin) 55 56 _, err = os.Stat(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "plugins", id)) 57 if !os.IsNotExist(err) { 58 c.Fatal(err) 59 } 60 } 61 62 func (ps *DockerPluginSuite) TestPluginForceRemove(c *check.C) { 63 pNameWithTag := ps.getPluginRepoWithTag() 64 65 _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag) 66 c.Assert(err, checker.IsNil) 67 68 out, _, _ := dockerCmdWithError("plugin", "remove", pNameWithTag) 69 c.Assert(out, checker.Contains, "is enabled") 70 71 out, _, err = dockerCmdWithError("plugin", "remove", "--force", pNameWithTag) 72 c.Assert(err, checker.IsNil) 73 c.Assert(out, checker.Contains, pNameWithTag) 74 } 75 76 func (s *DockerSuite) TestPluginActive(c *check.C) { 77 testRequires(c, DaemonIsLinux, IsAmd64, Network) 78 79 _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag) 80 c.Assert(err, checker.IsNil) 81 82 _, _, err = dockerCmdWithError("volume", "create", "-d", pNameWithTag, "--name", "testvol1") 83 c.Assert(err, checker.IsNil) 84 85 out, _, _ := dockerCmdWithError("plugin", "disable", pNameWithTag) 86 c.Assert(out, checker.Contains, "in use") 87 88 _, _, err = dockerCmdWithError("volume", "rm", "testvol1") 89 c.Assert(err, checker.IsNil) 90 91 _, _, err = dockerCmdWithError("plugin", "disable", pNameWithTag) 92 c.Assert(err, checker.IsNil) 93 94 out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag) 95 c.Assert(err, checker.IsNil) 96 c.Assert(out, checker.Contains, pNameWithTag) 97 } 98 99 func (s *DockerSuite) TestPluginActiveNetwork(c *check.C) { 100 testRequires(c, DaemonIsLinux, IsAmd64, Network) 101 _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", npNameWithTag) 102 c.Assert(err, checker.IsNil) 103 104 out, _, err := dockerCmdWithError("network", "create", "-d", npNameWithTag, "test") 105 c.Assert(err, checker.IsNil) 106 107 nID := strings.TrimSpace(out) 108 109 out, _, _ = dockerCmdWithError("plugin", "remove", npNameWithTag) 110 c.Assert(out, checker.Contains, "is in use") 111 112 _, _, err = dockerCmdWithError("network", "rm", nID) 113 c.Assert(err, checker.IsNil) 114 115 out, _, _ = dockerCmdWithError("plugin", "remove", npNameWithTag) 116 c.Assert(out, checker.Contains, "is enabled") 117 118 _, _, err = dockerCmdWithError("plugin", "disable", npNameWithTag) 119 c.Assert(err, checker.IsNil) 120 121 out, _, err = dockerCmdWithError("plugin", "remove", npNameWithTag) 122 c.Assert(err, checker.IsNil) 123 c.Assert(out, checker.Contains, npNameWithTag) 124 } 125 126 func (ps *DockerPluginSuite) TestPluginInstallDisable(c *check.C) { 127 pName := ps.getPluginRepoWithTag() 128 129 out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", "--disable", pName) 130 c.Assert(err, checker.IsNil) 131 c.Assert(strings.TrimSpace(out), checker.Contains, pName) 132 133 out, _, err = dockerCmdWithError("plugin", "ls") 134 c.Assert(err, checker.IsNil) 135 c.Assert(out, checker.Contains, "false") 136 137 out, _, err = dockerCmdWithError("plugin", "enable", pName) 138 c.Assert(err, checker.IsNil) 139 c.Assert(strings.TrimSpace(out), checker.Contains, pName) 140 141 out, _, err = dockerCmdWithError("plugin", "disable", pName) 142 c.Assert(err, checker.IsNil) 143 c.Assert(strings.TrimSpace(out), checker.Contains, pName) 144 145 out, _, err = dockerCmdWithError("plugin", "remove", pName) 146 c.Assert(err, checker.IsNil) 147 c.Assert(strings.TrimSpace(out), checker.Contains, pName) 148 } 149 150 func (s *DockerSuite) TestPluginInstallDisableVolumeLs(c *check.C) { 151 testRequires(c, DaemonIsLinux, IsAmd64, Network) 152 out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", "--disable", pName) 153 c.Assert(err, checker.IsNil) 154 c.Assert(strings.TrimSpace(out), checker.Contains, pName) 155 156 dockerCmd(c, "volume", "ls") 157 } 158 159 func (ps *DockerPluginSuite) TestPluginSet(c *check.C) { 160 client := testEnv.APIClient() 161 162 name := "test" 163 ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) 164 defer cancel() 165 166 initialValue := "0" 167 mntSrc := "foo" 168 devPath := "/dev/bar" 169 170 // Create a new plugin with extra settings 171 err := plugin.Create(ctx, client, name, func(cfg *plugin.Config) { 172 cfg.Env = []types.PluginEnv{{Name: "DEBUG", Value: &initialValue, Settable: []string{"value"}}} 173 cfg.Mounts = []types.PluginMount{ 174 {Name: "pmount1", Settable: []string{"source"}, Type: "none", Source: &mntSrc}, 175 {Name: "pmount2", Settable: []string{"source"}, Type: "none"}, // Mount without source is invalid. 176 } 177 cfg.Linux.Devices = []types.PluginDevice{ 178 {Name: "pdev1", Path: &devPath, Settable: []string{"path"}}, 179 {Name: "pdev2", Settable: []string{"path"}}, // Device without Path is invalid. 180 } 181 }) 182 c.Assert(err, checker.IsNil, check.Commentf("failed to create test plugin")) 183 184 env, _ := dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", name) 185 c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=0]") 186 187 dockerCmd(c, "plugin", "set", name, "DEBUG=1") 188 189 env, _ = dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", name) 190 c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=1]") 191 192 env, _ = dockerCmd(c, "plugin", "inspect", "-f", "{{with $mount := index .Settings.Mounts 0}}{{$mount.Source}}{{end}}", name) 193 c.Assert(strings.TrimSpace(env), checker.Contains, mntSrc) 194 195 dockerCmd(c, "plugin", "set", name, "pmount1.source=bar") 196 197 env, _ = dockerCmd(c, "plugin", "inspect", "-f", "{{with $mount := index .Settings.Mounts 0}}{{$mount.Source}}{{end}}", name) 198 c.Assert(strings.TrimSpace(env), checker.Contains, "bar") 199 200 out, _, err := dockerCmdWithError("plugin", "set", name, "pmount2.source=bar2") 201 c.Assert(err, checker.NotNil) 202 c.Assert(out, checker.Contains, "Plugin config has no mount source") 203 204 out, _, err = dockerCmdWithError("plugin", "set", name, "pdev2.path=/dev/bar2") 205 c.Assert(err, checker.NotNil) 206 c.Assert(out, checker.Contains, "Plugin config has no device path") 207 208 } 209 210 func (ps *DockerPluginSuite) TestPluginInstallArgs(c *check.C) { 211 pName := path.Join(ps.registryHost(), "plugin", "testplugininstallwithargs") 212 ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) 213 defer cancel() 214 215 plugin.CreateInRegistry(ctx, pName, nil, func(cfg *plugin.Config) { 216 cfg.Env = []types.PluginEnv{{Name: "DEBUG", Settable: []string{"value"}}} 217 }) 218 219 out, _ := dockerCmd(c, "plugin", "install", "--grant-all-permissions", "--disable", pName, "DEBUG=1") 220 c.Assert(strings.TrimSpace(out), checker.Contains, pName) 221 222 env, _ := dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", pName) 223 c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=1]") 224 } 225 226 func (ps *DockerPluginSuite) TestPluginInstallImage(c *check.C) { 227 testRequires(c, IsAmd64) 228 229 repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL) 230 // tag the image to upload it to the private registry 231 dockerCmd(c, "tag", "busybox", repoName) 232 // push the image to the registry 233 dockerCmd(c, "push", repoName) 234 235 out, _, err := dockerCmdWithError("plugin", "install", repoName) 236 c.Assert(err, checker.NotNil) 237 c.Assert(out, checker.Contains, `Encountered remote "application/vnd.docker.container.image.v1+json"(image) when fetching`) 238 } 239 240 func (ps *DockerPluginSuite) TestPluginEnableDisableNegative(c *check.C) { 241 pName := ps.getPluginRepoWithTag() 242 243 out, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pName) 244 c.Assert(err, checker.IsNil) 245 c.Assert(strings.TrimSpace(out), checker.Contains, pName) 246 247 out, _, err = dockerCmdWithError("plugin", "enable", pName) 248 c.Assert(err, checker.NotNil) 249 c.Assert(strings.TrimSpace(out), checker.Contains, "already enabled") 250 251 _, _, err = dockerCmdWithError("plugin", "disable", pName) 252 c.Assert(err, checker.IsNil) 253 254 out, _, err = dockerCmdWithError("plugin", "disable", pName) 255 c.Assert(err, checker.NotNil) 256 c.Assert(strings.TrimSpace(out), checker.Contains, "already disabled") 257 258 _, _, err = dockerCmdWithError("plugin", "remove", pName) 259 c.Assert(err, checker.IsNil) 260 } 261 262 func (ps *DockerPluginSuite) TestPluginCreate(c *check.C) { 263 name := "foo/bar-driver" 264 temp, err := ioutil.TempDir("", "foo") 265 c.Assert(err, checker.IsNil) 266 defer os.RemoveAll(temp) 267 268 data := `{"description": "foo plugin"}` 269 err = ioutil.WriteFile(filepath.Join(temp, "config.json"), []byte(data), 0644) 270 c.Assert(err, checker.IsNil) 271 272 err = os.MkdirAll(filepath.Join(temp, "rootfs"), 0700) 273 c.Assert(err, checker.IsNil) 274 275 out, _, err := dockerCmdWithError("plugin", "create", name, temp) 276 c.Assert(err, checker.IsNil) 277 c.Assert(out, checker.Contains, name) 278 279 out, _, err = dockerCmdWithError("plugin", "ls") 280 c.Assert(err, checker.IsNil) 281 c.Assert(out, checker.Contains, name) 282 283 out, _, err = dockerCmdWithError("plugin", "create", name, temp) 284 c.Assert(err, checker.NotNil) 285 c.Assert(out, checker.Contains, "already exist") 286 287 out, _, err = dockerCmdWithError("plugin", "ls") 288 c.Assert(err, checker.IsNil) 289 c.Assert(out, checker.Contains, name) 290 // The output will consists of one HEADER line and one line of foo/bar-driver 291 c.Assert(len(strings.Split(strings.TrimSpace(out), "\n")), checker.Equals, 2) 292 } 293 294 func (ps *DockerPluginSuite) TestPluginInspect(c *check.C) { 295 pNameWithTag := ps.getPluginRepoWithTag() 296 297 _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag) 298 c.Assert(err, checker.IsNil) 299 300 out, _, err := dockerCmdWithError("plugin", "ls") 301 c.Assert(err, checker.IsNil) 302 c.Assert(out, checker.Contains, pNameWithTag) 303 c.Assert(out, checker.Contains, "true") 304 305 // Find the ID first 306 out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", pNameWithTag) 307 c.Assert(err, checker.IsNil) 308 id := strings.TrimSpace(out) 309 c.Assert(id, checker.Not(checker.Equals), "") 310 311 // Long form 312 out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", id) 313 c.Assert(err, checker.IsNil) 314 c.Assert(strings.TrimSpace(out), checker.Equals, id) 315 316 // Short form 317 out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", id[:5]) 318 c.Assert(err, checker.IsNil) 319 c.Assert(strings.TrimSpace(out), checker.Equals, id) 320 321 // Name with tag form 322 out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", pNameWithTag) 323 c.Assert(err, checker.IsNil) 324 c.Assert(strings.TrimSpace(out), checker.Equals, id) 325 326 // Name without tag form 327 out, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", ps.getPluginRepo()) 328 c.Assert(err, checker.IsNil) 329 c.Assert(strings.TrimSpace(out), checker.Equals, id) 330 331 _, _, err = dockerCmdWithError("plugin", "disable", pNameWithTag) 332 c.Assert(err, checker.IsNil) 333 334 out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag) 335 c.Assert(err, checker.IsNil) 336 c.Assert(out, checker.Contains, pNameWithTag) 337 338 // After remove nothing should be found 339 _, _, err = dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", id[:5]) 340 c.Assert(err, checker.NotNil) 341 } 342 343 // Test case for https://github.com/docker/docker/pull/29186#discussion_r91277345 344 func (s *DockerSuite) TestPluginInspectOnWindows(c *check.C) { 345 // This test should work on Windows only 346 testRequires(c, DaemonIsWindows) 347 348 out, _, err := dockerCmdWithError("plugin", "inspect", "foobar") 349 c.Assert(err, checker.NotNil) 350 c.Assert(out, checker.Contains, "plugins are not supported on this platform") 351 c.Assert(err.Error(), checker.Contains, "plugins are not supported on this platform") 352 } 353 354 func (ps *DockerPluginSuite) TestPluginIDPrefix(c *check.C) { 355 name := "test" 356 client := testEnv.APIClient() 357 358 ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) 359 initialValue := "0" 360 err := plugin.Create(ctx, client, name, func(cfg *plugin.Config) { 361 cfg.Env = []types.PluginEnv{{Name: "DEBUG", Value: &initialValue, Settable: []string{"value"}}} 362 }) 363 cancel() 364 365 c.Assert(err, checker.IsNil, check.Commentf("failed to create test plugin")) 366 367 // Find ID first 368 id, _, err := dockerCmdWithError("plugin", "inspect", "-f", "{{.Id}}", name) 369 id = strings.TrimSpace(id) 370 c.Assert(err, checker.IsNil) 371 372 // List current state 373 out, _, err := dockerCmdWithError("plugin", "ls") 374 c.Assert(err, checker.IsNil) 375 c.Assert(out, checker.Contains, name) 376 c.Assert(out, checker.Contains, "false") 377 378 env, _ := dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", id[:5]) 379 c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=0]") 380 381 dockerCmd(c, "plugin", "set", id[:5], "DEBUG=1") 382 383 env, _ = dockerCmd(c, "plugin", "inspect", "-f", "{{.Settings.Env}}", id[:5]) 384 c.Assert(strings.TrimSpace(env), checker.Equals, "[DEBUG=1]") 385 386 // Enable 387 _, _, err = dockerCmdWithError("plugin", "enable", id[:5]) 388 c.Assert(err, checker.IsNil) 389 out, _, err = dockerCmdWithError("plugin", "ls") 390 c.Assert(err, checker.IsNil) 391 c.Assert(out, checker.Contains, name) 392 c.Assert(out, checker.Contains, "true") 393 394 // Disable 395 _, _, err = dockerCmdWithError("plugin", "disable", id[:5]) 396 c.Assert(err, checker.IsNil) 397 out, _, err = dockerCmdWithError("plugin", "ls") 398 c.Assert(err, checker.IsNil) 399 c.Assert(out, checker.Contains, name) 400 c.Assert(out, checker.Contains, "false") 401 402 // Remove 403 _, _, err = dockerCmdWithError("plugin", "remove", id[:5]) 404 c.Assert(err, checker.IsNil) 405 // List returns none 406 out, _, err = dockerCmdWithError("plugin", "ls") 407 c.Assert(err, checker.IsNil) 408 c.Assert(out, checker.Not(checker.Contains), name) 409 } 410 411 func (ps *DockerPluginSuite) TestPluginListDefaultFormat(c *check.C) { 412 config, err := ioutil.TempDir("", "config-file-") 413 c.Assert(err, check.IsNil) 414 defer os.RemoveAll(config) 415 416 err = ioutil.WriteFile(filepath.Join(config, "config.json"), []byte(`{"pluginsFormat": "raw"}`), 0644) 417 c.Assert(err, check.IsNil) 418 419 name := "test:latest" 420 client := testEnv.APIClient() 421 422 ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) 423 defer cancel() 424 err = plugin.Create(ctx, client, name, func(cfg *plugin.Config) { 425 cfg.Description = "test plugin" 426 }) 427 c.Assert(err, checker.IsNil, check.Commentf("failed to create test plugin")) 428 429 out, _ := dockerCmd(c, "plugin", "inspect", "--format", "{{.ID}}", name) 430 id := strings.TrimSpace(out) 431 432 // We expect the format to be in `raw + --no-trunc` 433 expectedOutput := fmt.Sprintf(`plugin_id: %s 434 name: %s 435 description: test plugin 436 enabled: false`, id, name) 437 438 out, _ = dockerCmd(c, "--config", config, "plugin", "ls", "--no-trunc") 439 c.Assert(strings.TrimSpace(out), checker.Contains, expectedOutput) 440 } 441 442 func (s *DockerSuite) TestPluginUpgrade(c *check.C) { 443 testRequires(c, DaemonIsLinux, Network, testEnv.IsLocalDaemon, IsAmd64, NotUserNamespace) 444 plugin := "cpuguy83/docker-volume-driver-plugin-local:latest" 445 pluginV2 := "cpuguy83/docker-volume-driver-plugin-local:v2" 446 447 dockerCmd(c, "plugin", "install", "--grant-all-permissions", plugin) 448 dockerCmd(c, "volume", "create", "--driver", plugin, "bananas") 449 dockerCmd(c, "run", "--rm", "-v", "bananas:/apple", "busybox", "sh", "-c", "touch /apple/core") 450 451 out, _, err := dockerCmdWithError("plugin", "upgrade", "--grant-all-permissions", plugin, pluginV2) 452 c.Assert(err, checker.NotNil, check.Commentf("%s", out)) 453 c.Assert(out, checker.Contains, "disabled before upgrading") 454 455 out, _ = dockerCmd(c, "plugin", "inspect", "--format={{.ID}}", plugin) 456 id := strings.TrimSpace(out) 457 458 // make sure "v2" does not exists 459 _, err = os.Stat(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "plugins", id, "rootfs", "v2")) 460 c.Assert(os.IsNotExist(err), checker.True, check.Commentf("%s", out)) 461 462 dockerCmd(c, "plugin", "disable", "-f", plugin) 463 dockerCmd(c, "plugin", "upgrade", "--grant-all-permissions", "--skip-remote-check", plugin, pluginV2) 464 465 // make sure "v2" file exists 466 _, err = os.Stat(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "plugins", id, "rootfs", "v2")) 467 c.Assert(err, checker.IsNil) 468 469 dockerCmd(c, "plugin", "enable", plugin) 470 dockerCmd(c, "volume", "inspect", "bananas") 471 dockerCmd(c, "run", "--rm", "-v", "bananas:/apple", "busybox", "sh", "-c", "ls -lh /apple/core") 472 } 473 474 func (s *DockerSuite) TestPluginMetricsCollector(c *check.C) { 475 testRequires(c, DaemonIsLinux, Network, testEnv.IsLocalDaemon, IsAmd64) 476 d := daemon.New(c, dockerBinary, dockerdBinary) 477 d.Start(c) 478 defer d.Stop(c) 479 480 name := "cpuguy83/docker-metrics-plugin-test:latest" 481 r := cli.Docker(cli.Args("plugin", "install", "--grant-all-permissions", name), cli.Daemon(d)) 482 c.Assert(r.Error, checker.IsNil, check.Commentf(r.Combined())) 483 484 // plugin lisens on localhost:19393 and proxies the metrics 485 resp, err := http.Get("http://localhost:19393/metrics") 486 c.Assert(err, checker.IsNil) 487 defer resp.Body.Close() 488 489 b, err := ioutil.ReadAll(resp.Body) 490 c.Assert(err, checker.IsNil) 491 // check that a known metric is there... don't expect this metric to change over time.. probably safe 492 c.Assert(string(b), checker.Contains, "container_actions") 493 }