docker_cli_volume_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "net/http"
  6. "os"
  7. "os/exec"
  8. "path/filepath"
  9. "strings"
  10. "github.com/docker/docker/integration-cli/checker"
  11. "github.com/docker/docker/integration-cli/request"
  12. icmd "github.com/docker/docker/pkg/testutil/cmd"
  13. "github.com/go-check/check"
  14. )
  15. func (s *DockerSuite) TestVolumeCLICreate(c *check.C) {
  16. dockerCmd(c, "volume", "create")
  17. _, _, err := dockerCmdWithError("volume", "create", "-d", "nosuchdriver")
  18. c.Assert(err, check.NotNil)
  19. // test using hidden --name option
  20. out, _ := dockerCmd(c, "volume", "create", "--name=test")
  21. name := strings.TrimSpace(out)
  22. c.Assert(name, check.Equals, "test")
  23. out, _ = dockerCmd(c, "volume", "create", "test2")
  24. name = strings.TrimSpace(out)
  25. c.Assert(name, check.Equals, "test2")
  26. }
  27. func (s *DockerSuite) TestVolumeCLIInspect(c *check.C) {
  28. c.Assert(
  29. exec.Command(dockerBinary, "volume", "inspect", "doesntexist").Run(),
  30. check.Not(check.IsNil),
  31. check.Commentf("volume inspect should error on non-existent volume"),
  32. )
  33. out, _ := dockerCmd(c, "volume", "create")
  34. name := strings.TrimSpace(out)
  35. out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Name }}", name)
  36. c.Assert(strings.TrimSpace(out), check.Equals, name)
  37. dockerCmd(c, "volume", "create", "test")
  38. out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Name }}", "test")
  39. c.Assert(strings.TrimSpace(out), check.Equals, "test")
  40. }
  41. func (s *DockerSuite) TestVolumeCLIInspectMulti(c *check.C) {
  42. dockerCmd(c, "volume", "create", "test1")
  43. dockerCmd(c, "volume", "create", "test2")
  44. dockerCmd(c, "volume", "create", "not-shown")
  45. result := dockerCmdWithResult("volume", "inspect", "--format={{ .Name }}", "test1", "test2", "doesntexist", "not-shown")
  46. c.Assert(result, icmd.Matches, icmd.Expected{
  47. ExitCode: 1,
  48. Err: "No such volume: doesntexist",
  49. })
  50. out := result.Stdout()
  51. outArr := strings.Split(strings.TrimSpace(out), "\n")
  52. c.Assert(len(outArr), check.Equals, 2, check.Commentf("\n%s", out))
  53. c.Assert(out, checker.Contains, "test1")
  54. c.Assert(out, checker.Contains, "test2")
  55. c.Assert(out, checker.Not(checker.Contains), "not-shown")
  56. }
  57. func (s *DockerSuite) TestVolumeCLILs(c *check.C) {
  58. prefix, _ := getPrefixAndSlashFromDaemonPlatform()
  59. dockerCmd(c, "volume", "create", "aaa")
  60. dockerCmd(c, "volume", "create", "test")
  61. dockerCmd(c, "volume", "create", "soo")
  62. dockerCmd(c, "run", "-v", "soo:"+prefix+"/foo", "busybox", "ls", "/")
  63. out, _ := dockerCmd(c, "volume", "ls")
  64. outArr := strings.Split(strings.TrimSpace(out), "\n")
  65. c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out))
  66. assertVolList(c, out, []string{"aaa", "soo", "test"})
  67. }
  68. func (s *DockerSuite) TestVolumeLsFormat(c *check.C) {
  69. dockerCmd(c, "volume", "create", "aaa")
  70. dockerCmd(c, "volume", "create", "test")
  71. dockerCmd(c, "volume", "create", "soo")
  72. out, _ := dockerCmd(c, "volume", "ls", "--format", "{{.Name}}")
  73. lines := strings.Split(strings.TrimSpace(string(out)), "\n")
  74. expected := []string{"aaa", "soo", "test"}
  75. var names []string
  76. names = append(names, lines...)
  77. c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
  78. }
  79. func (s *DockerSuite) TestVolumeLsFormatDefaultFormat(c *check.C) {
  80. dockerCmd(c, "volume", "create", "aaa")
  81. dockerCmd(c, "volume", "create", "test")
  82. dockerCmd(c, "volume", "create", "soo")
  83. config := `{
  84. "volumesFormat": "{{ .Name }} default"
  85. }`
  86. d, err := ioutil.TempDir("", "integration-cli-")
  87. c.Assert(err, checker.IsNil)
  88. defer os.RemoveAll(d)
  89. err = ioutil.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644)
  90. c.Assert(err, checker.IsNil)
  91. out, _ := dockerCmd(c, "--config", d, "volume", "ls")
  92. lines := strings.Split(strings.TrimSpace(string(out)), "\n")
  93. expected := []string{"aaa default", "soo default", "test default"}
  94. var names []string
  95. names = append(names, lines...)
  96. c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
  97. }
  98. // assertVolList checks volume retrieved with ls command
  99. // equals to expected volume list
  100. // note: out should be `volume ls [option]` result
  101. func assertVolList(c *check.C, out string, expectVols []string) {
  102. lines := strings.Split(out, "\n")
  103. var volList []string
  104. for _, line := range lines[1 : len(lines)-1] {
  105. volFields := strings.Fields(line)
  106. // wrap all volume name in volList
  107. volList = append(volList, volFields[1])
  108. }
  109. // volume ls should contains all expected volumes
  110. c.Assert(volList, checker.DeepEquals, expectVols)
  111. }
  112. func (s *DockerSuite) TestVolumeCLILsFilterDangling(c *check.C) {
  113. prefix, _ := getPrefixAndSlashFromDaemonPlatform()
  114. dockerCmd(c, "volume", "create", "testnotinuse1")
  115. dockerCmd(c, "volume", "create", "testisinuse1")
  116. dockerCmd(c, "volume", "create", "testisinuse2")
  117. // Make sure both "created" (but not started), and started
  118. // containers are included in reference counting
  119. dockerCmd(c, "run", "--name", "volume-test1", "-v", "testisinuse1:"+prefix+"/foo", "busybox", "true")
  120. dockerCmd(c, "create", "--name", "volume-test2", "-v", "testisinuse2:"+prefix+"/foo", "busybox", "true")
  121. out, _ := dockerCmd(c, "volume", "ls")
  122. // No filter, all volumes should show
  123. c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
  124. c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
  125. c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
  126. out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=false")
  127. // Explicitly disabling dangling
  128. c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
  129. c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
  130. c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
  131. out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=true")
  132. // Filter "dangling" volumes; only "dangling" (unused) volumes should be in the output
  133. c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
  134. c.Assert(out, check.Not(checker.Contains), "testisinuse1\n", check.Commentf("volume 'testisinuse1' in output, but not expected"))
  135. c.Assert(out, check.Not(checker.Contains), "testisinuse2\n", check.Commentf("volume 'testisinuse2' in output, but not expected"))
  136. out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=1")
  137. // Filter "dangling" volumes; only "dangling" (unused) volumes should be in the output, dangling also accept 1
  138. c.Assert(out, checker.Contains, "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
  139. c.Assert(out, check.Not(checker.Contains), "testisinuse1\n", check.Commentf("volume 'testisinuse1' in output, but not expected"))
  140. c.Assert(out, check.Not(checker.Contains), "testisinuse2\n", check.Commentf("volume 'testisinuse2' in output, but not expected"))
  141. out, _ = dockerCmd(c, "volume", "ls", "--filter", "dangling=0")
  142. // dangling=0 is same as dangling=false case
  143. c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
  144. c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
  145. c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
  146. out, _ = dockerCmd(c, "volume", "ls", "--filter", "name=testisin")
  147. c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
  148. c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("execpeted volume 'testisinuse1' in output"))
  149. c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
  150. }
  151. func (s *DockerSuite) TestVolumeCLILsErrorWithInvalidFilterName(c *check.C) {
  152. out, _, err := dockerCmdWithError("volume", "ls", "-f", "FOO=123")
  153. c.Assert(err, checker.NotNil)
  154. c.Assert(out, checker.Contains, "Invalid filter")
  155. }
  156. func (s *DockerSuite) TestVolumeCLILsWithIncorrectFilterValue(c *check.C) {
  157. out, _, err := dockerCmdWithError("volume", "ls", "-f", "dangling=invalid")
  158. c.Assert(err, check.NotNil)
  159. c.Assert(out, checker.Contains, "Invalid filter")
  160. }
  161. func (s *DockerSuite) TestVolumeCLIRm(c *check.C) {
  162. prefix, _ := getPrefixAndSlashFromDaemonPlatform()
  163. out, _ := dockerCmd(c, "volume", "create")
  164. id := strings.TrimSpace(out)
  165. dockerCmd(c, "volume", "create", "test")
  166. dockerCmd(c, "volume", "rm", id)
  167. dockerCmd(c, "volume", "rm", "test")
  168. out, _ = dockerCmd(c, "volume", "ls")
  169. outArr := strings.Split(strings.TrimSpace(out), "\n")
  170. c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
  171. volumeID := "testing"
  172. dockerCmd(c, "run", "-v", volumeID+":"+prefix+"/foo", "--name=test", "busybox", "sh", "-c", "echo hello > /foo/bar")
  173. icmd.RunCommand(dockerBinary, "volume", "rm", "testing").Assert(c, icmd.Expected{
  174. ExitCode: 1,
  175. Error: "exit status 1",
  176. })
  177. out, _ = dockerCmd(c, "run", "--volumes-from=test", "--name=test2", "busybox", "sh", "-c", "cat /foo/bar")
  178. c.Assert(strings.TrimSpace(out), check.Equals, "hello")
  179. dockerCmd(c, "rm", "-fv", "test2")
  180. dockerCmd(c, "volume", "inspect", volumeID)
  181. dockerCmd(c, "rm", "-f", "test")
  182. out, _ = dockerCmd(c, "run", "--name=test2", "-v", volumeID+":"+prefix+"/foo", "busybox", "sh", "-c", "cat /foo/bar")
  183. c.Assert(strings.TrimSpace(out), check.Equals, "hello", check.Commentf("volume data was removed"))
  184. dockerCmd(c, "rm", "test2")
  185. dockerCmd(c, "volume", "rm", volumeID)
  186. c.Assert(
  187. exec.Command("volume", "rm", "doesntexist").Run(),
  188. check.Not(check.IsNil),
  189. check.Commentf("volume rm should fail with non-existent volume"),
  190. )
  191. }
  192. // FIXME(vdemeester) should be a unit test in cli/command/volume package
  193. func (s *DockerSuite) TestVolumeCLINoArgs(c *check.C) {
  194. out, _ := dockerCmd(c, "volume")
  195. // no args should produce the cmd usage output
  196. usage := "Usage: docker volume COMMAND"
  197. c.Assert(out, checker.Contains, usage)
  198. // invalid arg should error and show the command usage on stderr
  199. icmd.RunCommand(dockerBinary, "volume", "somearg").Assert(c, icmd.Expected{
  200. ExitCode: 1,
  201. Error: "exit status 1",
  202. Err: usage,
  203. })
  204. // invalid flag should error and show the flag error and cmd usage
  205. result := icmd.RunCommand(dockerBinary, "volume", "--no-such-flag")
  206. result.Assert(c, icmd.Expected{
  207. ExitCode: 125,
  208. Error: "exit status 125",
  209. Err: usage,
  210. })
  211. c.Assert(result.Stderr(), checker.Contains, "unknown flag: --no-such-flag")
  212. }
  213. func (s *DockerSuite) TestVolumeCLIInspectTmplError(c *check.C) {
  214. out, _ := dockerCmd(c, "volume", "create")
  215. name := strings.TrimSpace(out)
  216. out, exitCode, err := dockerCmdWithError("volume", "inspect", "--format='{{ .FooBar }}'", name)
  217. c.Assert(err, checker.NotNil, check.Commentf("Output: %s", out))
  218. c.Assert(exitCode, checker.Equals, 1, check.Commentf("Output: %s", out))
  219. c.Assert(out, checker.Contains, "Template parsing error")
  220. }
  221. func (s *DockerSuite) TestVolumeCLICreateWithOpts(c *check.C) {
  222. testRequires(c, DaemonIsLinux)
  223. dockerCmd(c, "volume", "create", "-d", "local", "test", "--opt=type=tmpfs", "--opt=device=tmpfs", "--opt=o=size=1m,uid=1000")
  224. out, _ := dockerCmd(c, "run", "-v", "test:/foo", "busybox", "mount")
  225. mounts := strings.Split(out, "\n")
  226. var found bool
  227. for _, m := range mounts {
  228. if strings.Contains(m, "/foo") {
  229. found = true
  230. info := strings.Fields(m)
  231. // tmpfs on <path> type tmpfs (rw,relatime,size=1024k,uid=1000)
  232. c.Assert(info[0], checker.Equals, "tmpfs")
  233. c.Assert(info[2], checker.Equals, "/foo")
  234. c.Assert(info[4], checker.Equals, "tmpfs")
  235. c.Assert(info[5], checker.Contains, "uid=1000")
  236. c.Assert(info[5], checker.Contains, "size=1024k")
  237. break
  238. }
  239. }
  240. c.Assert(found, checker.Equals, true)
  241. }
  242. func (s *DockerSuite) TestVolumeCLICreateLabel(c *check.C) {
  243. testVol := "testvolcreatelabel"
  244. testLabel := "foo"
  245. testValue := "bar"
  246. out, _, err := dockerCmdWithError("volume", "create", "--label", testLabel+"="+testValue, testVol)
  247. c.Assert(err, check.IsNil)
  248. out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Labels."+testLabel+" }}", testVol)
  249. c.Assert(strings.TrimSpace(out), check.Equals, testValue)
  250. }
  251. func (s *DockerSuite) TestVolumeCLICreateLabelMultiple(c *check.C) {
  252. testVol := "testvolcreatelabel"
  253. testLabels := map[string]string{
  254. "foo": "bar",
  255. "baz": "foo",
  256. }
  257. args := []string{
  258. "volume",
  259. "create",
  260. testVol,
  261. }
  262. for k, v := range testLabels {
  263. args = append(args, "--label", k+"="+v)
  264. }
  265. out, _, err := dockerCmdWithError(args...)
  266. c.Assert(err, check.IsNil)
  267. for k, v := range testLabels {
  268. out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Labels."+k+" }}", testVol)
  269. c.Assert(strings.TrimSpace(out), check.Equals, v)
  270. }
  271. }
  272. func (s *DockerSuite) TestVolumeCLILsFilterLabels(c *check.C) {
  273. testVol1 := "testvolcreatelabel-1"
  274. out, _, err := dockerCmdWithError("volume", "create", "--label", "foo=bar1", testVol1)
  275. c.Assert(err, check.IsNil)
  276. testVol2 := "testvolcreatelabel-2"
  277. out, _, err = dockerCmdWithError("volume", "create", "--label", "foo=bar2", testVol2)
  278. c.Assert(err, check.IsNil)
  279. out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=foo")
  280. // filter with label=key
  281. c.Assert(out, checker.Contains, "testvolcreatelabel-1\n", check.Commentf("expected volume 'testvolcreatelabel-1' in output"))
  282. c.Assert(out, checker.Contains, "testvolcreatelabel-2\n", check.Commentf("expected volume 'testvolcreatelabel-2' in output"))
  283. out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=foo=bar1")
  284. // filter with label=key=value
  285. c.Assert(out, checker.Contains, "testvolcreatelabel-1\n", check.Commentf("expected volume 'testvolcreatelabel-1' in output"))
  286. c.Assert(out, check.Not(checker.Contains), "testvolcreatelabel-2\n", check.Commentf("expected volume 'testvolcreatelabel-2 in output"))
  287. out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=non-exist")
  288. outArr := strings.Split(strings.TrimSpace(out), "\n")
  289. c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
  290. out, _ = dockerCmd(c, "volume", "ls", "--filter", "label=foo=non-exist")
  291. outArr = strings.Split(strings.TrimSpace(out), "\n")
  292. c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
  293. }
  294. func (s *DockerSuite) TestVolumeCLILsFilterDrivers(c *check.C) {
  295. // using default volume driver local to create volumes
  296. testVol1 := "testvol-1"
  297. out, _, err := dockerCmdWithError("volume", "create", testVol1)
  298. c.Assert(err, check.IsNil)
  299. testVol2 := "testvol-2"
  300. out, _, err = dockerCmdWithError("volume", "create", testVol2)
  301. c.Assert(err, check.IsNil)
  302. // filter with driver=local
  303. out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=local")
  304. c.Assert(out, checker.Contains, "testvol-1\n", check.Commentf("expected volume 'testvol-1' in output"))
  305. c.Assert(out, checker.Contains, "testvol-2\n", check.Commentf("expected volume 'testvol-2' in output"))
  306. // filter with driver=invaliddriver
  307. out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=invaliddriver")
  308. outArr := strings.Split(strings.TrimSpace(out), "\n")
  309. c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
  310. // filter with driver=loca
  311. out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=loca")
  312. outArr = strings.Split(strings.TrimSpace(out), "\n")
  313. c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
  314. // filter with driver=
  315. out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=")
  316. outArr = strings.Split(strings.TrimSpace(out), "\n")
  317. c.Assert(len(outArr), check.Equals, 1, check.Commentf("\n%s", out))
  318. }
  319. func (s *DockerSuite) TestVolumeCLIRmForceUsage(c *check.C) {
  320. out, _ := dockerCmd(c, "volume", "create")
  321. id := strings.TrimSpace(out)
  322. dockerCmd(c, "volume", "rm", "-f", id)
  323. dockerCmd(c, "volume", "rm", "--force", "nonexist")
  324. out, _ = dockerCmd(c, "volume", "ls")
  325. outArr := strings.Split(strings.TrimSpace(out), "\n")
  326. c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
  327. }
  328. func (s *DockerSuite) TestVolumeCLIRmForce(c *check.C) {
  329. testRequires(c, SameHostDaemon, DaemonIsLinux)
  330. name := "test"
  331. out, _ := dockerCmd(c, "volume", "create", name)
  332. id := strings.TrimSpace(out)
  333. c.Assert(id, checker.Equals, name)
  334. out, _ = dockerCmd(c, "volume", "inspect", "--format", "{{.Mountpoint}}", name)
  335. c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  336. // Mountpoint is in the form of "/var/lib/docker/volumes/.../_data", removing `/_data`
  337. path := strings.TrimSuffix(strings.TrimSpace(out), "/_data")
  338. icmd.RunCommand("rm", "-rf", path).Assert(c, icmd.Success)
  339. dockerCmd(c, "volume", "rm", "-f", "test")
  340. out, _ = dockerCmd(c, "volume", "ls")
  341. c.Assert(out, checker.Not(checker.Contains), name)
  342. dockerCmd(c, "volume", "create", "test")
  343. out, _ = dockerCmd(c, "volume", "ls")
  344. c.Assert(out, checker.Contains, name)
  345. }
  346. func (s *DockerSuite) TestVolumeCliInspectWithVolumeOpts(c *check.C) {
  347. testRequires(c, DaemonIsLinux)
  348. // Without options
  349. name := "test1"
  350. dockerCmd(c, "volume", "create", "-d", "local", name)
  351. out, _ := dockerCmd(c, "volume", "inspect", "--format={{ .Options }}", name)
  352. c.Assert(strings.TrimSpace(out), checker.Contains, "map[]")
  353. // With options
  354. name = "test2"
  355. k1, v1 := "type", "tmpfs"
  356. k2, v2 := "device", "tmpfs"
  357. k3, v3 := "o", "size=1m,uid=1000"
  358. dockerCmd(c, "volume", "create", "-d", "local", name, "--opt", fmt.Sprintf("%s=%s", k1, v1), "--opt", fmt.Sprintf("%s=%s", k2, v2), "--opt", fmt.Sprintf("%s=%s", k3, v3))
  359. out, _ = dockerCmd(c, "volume", "inspect", "--format={{ .Options }}", name)
  360. c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k1, v1))
  361. c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k2, v2))
  362. c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k3, v3))
  363. }
  364. // Test case (1) for 21845: duplicate targets for --volumes-from
  365. func (s *DockerSuite) TestDuplicateMountpointsForVolumesFrom(c *check.C) {
  366. testRequires(c, DaemonIsLinux)
  367. image := "vimage"
  368. buildImageSuccessfully(c, image, withDockerfile(`
  369. FROM busybox
  370. VOLUME ["/tmp/data"]`))
  371. dockerCmd(c, "run", "--name=data1", image, "true")
  372. dockerCmd(c, "run", "--name=data2", image, "true")
  373. out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
  374. data1 := strings.TrimSpace(out)
  375. c.Assert(data1, checker.Not(checker.Equals), "")
  376. out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
  377. data2 := strings.TrimSpace(out)
  378. c.Assert(data2, checker.Not(checker.Equals), "")
  379. // Both volume should exist
  380. out, _ = dockerCmd(c, "volume", "ls", "-q")
  381. c.Assert(strings.TrimSpace(out), checker.Contains, data1)
  382. c.Assert(strings.TrimSpace(out), checker.Contains, data2)
  383. out, _, err := dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-d", "busybox", "top")
  384. c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))
  385. // Only the second volume will be referenced, this is backward compatible
  386. out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
  387. c.Assert(strings.TrimSpace(out), checker.Equals, data2)
  388. dockerCmd(c, "rm", "-f", "-v", "app")
  389. dockerCmd(c, "rm", "-f", "-v", "data1")
  390. dockerCmd(c, "rm", "-f", "-v", "data2")
  391. // Both volume should not exist
  392. out, _ = dockerCmd(c, "volume", "ls", "-q")
  393. c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
  394. c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
  395. }
  396. // Test case (2) for 21845: duplicate targets for --volumes-from and -v (bind)
  397. func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndBind(c *check.C) {
  398. testRequires(c, DaemonIsLinux)
  399. image := "vimage"
  400. buildImageSuccessfully(c, image, withDockerfile(`
  401. FROM busybox
  402. VOLUME ["/tmp/data"]`))
  403. dockerCmd(c, "run", "--name=data1", image, "true")
  404. dockerCmd(c, "run", "--name=data2", image, "true")
  405. out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
  406. data1 := strings.TrimSpace(out)
  407. c.Assert(data1, checker.Not(checker.Equals), "")
  408. out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
  409. data2 := strings.TrimSpace(out)
  410. c.Assert(data2, checker.Not(checker.Equals), "")
  411. // Both volume should exist
  412. out, _ = dockerCmd(c, "volume", "ls", "-q")
  413. c.Assert(strings.TrimSpace(out), checker.Contains, data1)
  414. c.Assert(strings.TrimSpace(out), checker.Contains, data2)
  415. out, _, err := dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-v", "/tmp/data:/tmp/data", "-d", "busybox", "top")
  416. c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))
  417. // No volume will be referenced (mount is /tmp/data), this is backward compatible
  418. out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
  419. c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
  420. c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
  421. dockerCmd(c, "rm", "-f", "-v", "app")
  422. dockerCmd(c, "rm", "-f", "-v", "data1")
  423. dockerCmd(c, "rm", "-f", "-v", "data2")
  424. // Both volume should not exist
  425. out, _ = dockerCmd(c, "volume", "ls", "-q")
  426. c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
  427. c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
  428. }
  429. // Test case (3) for 21845: duplicate targets for --volumes-from and `Mounts` (API only)
  430. func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndMounts(c *check.C) {
  431. testRequires(c, DaemonIsLinux)
  432. image := "vimage"
  433. buildImageSuccessfully(c, image, withDockerfile(`
  434. FROM busybox
  435. VOLUME ["/tmp/data"]`))
  436. dockerCmd(c, "run", "--name=data1", image, "true")
  437. dockerCmd(c, "run", "--name=data2", image, "true")
  438. out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
  439. data1 := strings.TrimSpace(out)
  440. c.Assert(data1, checker.Not(checker.Equals), "")
  441. out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
  442. data2 := strings.TrimSpace(out)
  443. c.Assert(data2, checker.Not(checker.Equals), "")
  444. // Both volume should exist
  445. out, _ = dockerCmd(c, "volume", "ls", "-q")
  446. c.Assert(strings.TrimSpace(out), checker.Contains, data1)
  447. c.Assert(strings.TrimSpace(out), checker.Contains, data2)
  448. // Mounts is available in API
  449. status, body, err := request.SockRequest("POST", "/containers/create?name=app", map[string]interface{}{
  450. "Image": "busybox",
  451. "Cmd": []string{"top"},
  452. "HostConfig": map[string]interface{}{
  453. "VolumesFrom": []string{
  454. "data1",
  455. "data2",
  456. },
  457. "Mounts": []map[string]interface{}{
  458. {
  459. "Type": "bind",
  460. "Source": "/tmp/data",
  461. "Target": "/tmp/data",
  462. },
  463. }},
  464. }, daemonHost())
  465. c.Assert(err, checker.IsNil, check.Commentf(string(body)))
  466. c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(body)))
  467. // No volume will be referenced (mount is /tmp/data), this is backward compatible
  468. out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
  469. c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
  470. c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
  471. dockerCmd(c, "rm", "-f", "-v", "app")
  472. dockerCmd(c, "rm", "-f", "-v", "data1")
  473. dockerCmd(c, "rm", "-f", "-v", "data2")
  474. // Both volume should not exist
  475. out, _ = dockerCmd(c, "volume", "ls", "-q")
  476. c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
  477. c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
  478. }