docker_cli_ps_test.go 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. package main
  2. import (
  3. "fmt"
  4. "sort"
  5. "strconv"
  6. "strings"
  7. "testing"
  8. "time"
  9. "github.com/docker/docker/api/types/versions"
  10. "github.com/docker/docker/integration-cli/checker"
  11. "github.com/docker/docker/integration-cli/cli"
  12. "github.com/docker/docker/integration-cli/cli/build"
  13. "github.com/docker/docker/pkg/stringid"
  14. "github.com/go-check/check"
  15. "gotest.tools/assert"
  16. is "gotest.tools/assert/cmp"
  17. "gotest.tools/icmd"
  18. )
  19. func (s *DockerSuite) TestPsListContainersBase(c *testing.T) {
  20. existingContainers := ExistingContainerIDs(c)
  21. out := runSleepingContainer(c, "-d")
  22. firstID := strings.TrimSpace(out)
  23. out = runSleepingContainer(c, "-d")
  24. secondID := strings.TrimSpace(out)
  25. // not long running
  26. out, _ = dockerCmd(c, "run", "-d", "busybox", "true")
  27. thirdID := strings.TrimSpace(out)
  28. out = runSleepingContainer(c, "-d")
  29. fourthID := strings.TrimSpace(out)
  30. // make sure the second is running
  31. assert.Assert(c, waitRun(secondID) == nil)
  32. // make sure third one is not running
  33. dockerCmd(c, "wait", thirdID)
  34. // make sure the forth is running
  35. assert.Assert(c, waitRun(fourthID) == nil)
  36. // all
  37. out, _ = dockerCmd(c, "ps", "-a")
  38. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), []string{fourthID, thirdID, secondID, firstID}), true, check.Commentf("ALL: Container list is not in the correct order: \n%s", out))
  39. // running
  40. out, _ = dockerCmd(c, "ps")
  41. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), []string{fourthID, secondID, firstID}), true, check.Commentf("RUNNING: Container list is not in the correct order: \n%s", out))
  42. // limit
  43. out, _ = dockerCmd(c, "ps", "-n=2", "-a")
  44. expected := []string{fourthID, thirdID}
  45. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("LIMIT & ALL: Container list is not in the correct order: \n%s", out))
  46. out, _ = dockerCmd(c, "ps", "-n=2")
  47. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("LIMIT: Container list is not in the correct order: \n%s", out))
  48. // filter since
  49. out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-a")
  50. expected = []string{fourthID, thirdID, secondID}
  51. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("SINCE filter & ALL: Container list is not in the correct order: \n%s", out))
  52. out, _ = dockerCmd(c, "ps", "-f", "since="+firstID)
  53. expected = []string{fourthID, secondID}
  54. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("SINCE filter: Container list is not in the correct order: \n%s", out))
  55. out, _ = dockerCmd(c, "ps", "-f", "since="+thirdID)
  56. expected = []string{fourthID}
  57. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("SINCE filter: Container list is not in the correct order: \n%s", out))
  58. // filter before
  59. out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-a")
  60. expected = []string{thirdID, secondID, firstID}
  61. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("BEFORE filter & ALL: Container list is not in the correct order: \n%s", out))
  62. out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID)
  63. expected = []string{secondID, firstID}
  64. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("BEFORE filter: Container list is not in the correct order: \n%s", out))
  65. out, _ = dockerCmd(c, "ps", "-f", "before="+thirdID)
  66. expected = []string{secondID, firstID}
  67. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("SINCE filter: Container list is not in the correct order: \n%s", out))
  68. // filter since & before
  69. out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-a")
  70. expected = []string{thirdID, secondID}
  71. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("SINCE filter, BEFORE filter & ALL: Container list is not in the correct order: \n%s", out))
  72. out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID)
  73. expected = []string{secondID}
  74. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("SINCE filter, BEFORE filter: Container list is not in the correct order: \n%s", out))
  75. // filter since & limit
  76. out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2", "-a")
  77. expected = []string{fourthID, thirdID}
  78. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("SINCE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
  79. out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2")
  80. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("SINCE filter, LIMIT: Container list is not in the correct order: \n%s", out))
  81. // filter before & limit
  82. out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1", "-a")
  83. expected = []string{thirdID}
  84. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("BEFORE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
  85. out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1")
  86. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("BEFORE filter, LIMIT: Container list is not in the correct order: \n%s", out))
  87. // filter since & filter before & limit
  88. out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1", "-a")
  89. expected = []string{thirdID}
  90. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("SINCE filter, BEFORE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
  91. out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1")
  92. assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, check.Commentf("SINCE filter, BEFORE filter, LIMIT: Container list is not in the correct order: \n%s", out))
  93. }
  94. func assertContainerList(out string, expected []string) bool {
  95. lines := strings.Split(strings.Trim(out, "\n "), "\n")
  96. if len(lines)-1 != len(expected) {
  97. return false
  98. }
  99. containerIDIndex := strings.Index(lines[0], "CONTAINER ID")
  100. for i := 0; i < len(expected); i++ {
  101. foundID := lines[i+1][containerIDIndex : containerIDIndex+12]
  102. if foundID != expected[i][:12] {
  103. return false
  104. }
  105. }
  106. return true
  107. }
  108. func (s *DockerSuite) TestPsListContainersSize(c *testing.T) {
  109. // Problematic on Windows as it doesn't report the size correctly @swernli
  110. testRequires(c, DaemonIsLinux)
  111. dockerCmd(c, "run", "-d", "busybox")
  112. baseOut, _ := dockerCmd(c, "ps", "-s", "-n=1")
  113. baseLines := strings.Split(strings.Trim(baseOut, "\n "), "\n")
  114. baseSizeIndex := strings.Index(baseLines[0], "SIZE")
  115. baseFoundsize := baseLines[1][baseSizeIndex:]
  116. baseBytes, err := strconv.Atoi(strings.Split(baseFoundsize, "B")[0])
  117. assert.NilError(c, err)
  118. name := "test_size"
  119. dockerCmd(c, "run", "--name", name, "busybox", "sh", "-c", "echo 1 > test")
  120. id := getIDByName(c, name)
  121. var result *icmd.Result
  122. wait := make(chan struct{})
  123. go func() {
  124. result = icmd.RunCommand(dockerBinary, "ps", "-s", "-n=1")
  125. close(wait)
  126. }()
  127. select {
  128. case <-wait:
  129. case <-time.After(3 * time.Second):
  130. c.Fatalf("Calling \"docker ps -s\" timed out!")
  131. }
  132. result.Assert(c, icmd.Success)
  133. lines := strings.Split(strings.Trim(result.Combined(), "\n "), "\n")
  134. assert.Equal(c, len(lines), 2, "Expected 2 lines for 'ps -s -n=1' output, got %d", len(lines))
  135. sizeIndex := strings.Index(lines[0], "SIZE")
  136. idIndex := strings.Index(lines[0], "CONTAINER ID")
  137. foundID := lines[1][idIndex : idIndex+12]
  138. assert.Equal(c, foundID, id[:12], check.Commentf("Expected id %s, got %s", id[:12], foundID))
  139. expectedSize := fmt.Sprintf("%dB", 2+baseBytes)
  140. foundSize := lines[1][sizeIndex:]
  141. assert.Assert(c, foundSize, checker.Contains, expectedSize, check.Commentf("Expected size %q, got %q", expectedSize, foundSize))
  142. }
  143. func (s *DockerSuite) TestPsListContainersFilterStatus(c *testing.T) {
  144. existingContainers := ExistingContainerIDs(c)
  145. // start exited container
  146. out := cli.DockerCmd(c, "run", "-d", "busybox").Combined()
  147. firstID := strings.TrimSpace(out)
  148. // make sure the exited container is not running
  149. cli.DockerCmd(c, "wait", firstID)
  150. // start running container
  151. out = cli.DockerCmd(c, "run", "-itd", "busybox").Combined()
  152. secondID := strings.TrimSpace(out)
  153. // filter containers by exited
  154. out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter=status=exited").Combined()
  155. containerOut := strings.TrimSpace(out)
  156. assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), firstID)
  157. out = cli.DockerCmd(c, "ps", "-a", "--no-trunc", "-q", "--filter=status=running").Combined()
  158. containerOut = strings.TrimSpace(out)
  159. assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), secondID)
  160. result := cli.Docker(cli.Args("ps", "-a", "-q", "--filter=status=rubbish"), cli.WithTimeout(time.Second*60))
  161. err := "Invalid filter 'status=rubbish'"
  162. if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
  163. err = "Unrecognised filter value for status: rubbish"
  164. }
  165. result.Assert(c, icmd.Expected{
  166. ExitCode: 1,
  167. Err: err,
  168. })
  169. // Windows doesn't support pausing of containers
  170. if testEnv.OSType != "windows" {
  171. // pause running container
  172. out = cli.DockerCmd(c, "run", "-itd", "busybox").Combined()
  173. pausedID := strings.TrimSpace(out)
  174. cli.DockerCmd(c, "pause", pausedID)
  175. // make sure the container is unpaused to let the daemon stop it properly
  176. defer func() { cli.DockerCmd(c, "unpause", pausedID) }()
  177. out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter=status=paused").Combined()
  178. containerOut = strings.TrimSpace(out)
  179. assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), pausedID)
  180. }
  181. }
  182. func (s *DockerSuite) TestPsListContainersFilterHealth(c *testing.T) {
  183. existingContainers := ExistingContainerIDs(c)
  184. // Test legacy no health check
  185. out := runSleepingContainer(c, "--name=none_legacy")
  186. containerID := strings.TrimSpace(out)
  187. cli.WaitRun(c, containerID)
  188. out = cli.DockerCmd(c, "ps", "-q", "-l", "--no-trunc", "--filter=health=none").Combined()
  189. containerOut := strings.TrimSpace(out)
  190. assert.Equal(c, containerOut, containerID, check.Commentf("Expected id %s, got %s for legacy none filter, output: %q", containerID, containerOut, out))
  191. // Test no health check specified explicitly
  192. out = runSleepingContainer(c, "--name=none", "--no-healthcheck")
  193. containerID = strings.TrimSpace(out)
  194. cli.WaitRun(c, containerID)
  195. out = cli.DockerCmd(c, "ps", "-q", "-l", "--no-trunc", "--filter=health=none").Combined()
  196. containerOut = strings.TrimSpace(out)
  197. assert.Equal(c, containerOut, containerID, check.Commentf("Expected id %s, got %s for none filter, output: %q", containerID, containerOut, out))
  198. // Test failing health check
  199. out = runSleepingContainer(c, "--name=failing_container", "--health-cmd=exit 1", "--health-interval=1s")
  200. containerID = strings.TrimSpace(out)
  201. waitForHealthStatus(c, "failing_container", "starting", "unhealthy")
  202. out = cli.DockerCmd(c, "ps", "-q", "--no-trunc", "--filter=health=unhealthy").Combined()
  203. containerOut = strings.TrimSpace(out)
  204. assert.Equal(c, containerOut, containerID, check.Commentf("Expected containerID %s, got %s for unhealthy filter, output: %q", containerID, containerOut, out))
  205. // Check passing healthcheck
  206. out = runSleepingContainer(c, "--name=passing_container", "--health-cmd=exit 0", "--health-interval=1s")
  207. containerID = strings.TrimSpace(out)
  208. waitForHealthStatus(c, "passing_container", "starting", "healthy")
  209. out = cli.DockerCmd(c, "ps", "-q", "--no-trunc", "--filter=health=healthy").Combined()
  210. containerOut = strings.TrimSpace(RemoveOutputForExistingElements(out, existingContainers))
  211. assert.Equal(c, containerOut, containerID, check.Commentf("Expected containerID %s, got %s for healthy filter, output: %q", containerID, containerOut, out))
  212. }
  213. func (s *DockerSuite) TestPsListContainersFilterID(c *testing.T) {
  214. // start container
  215. out, _ := dockerCmd(c, "run", "-d", "busybox")
  216. firstID := strings.TrimSpace(out)
  217. // start another container
  218. runSleepingContainer(c)
  219. // filter containers by id
  220. out, _ = dockerCmd(c, "ps", "-a", "-q", "--filter=id="+firstID)
  221. containerOut := strings.TrimSpace(out)
  222. assert.Equal(c, containerOut, firstID[:12], check.Commentf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out))
  223. }
  224. func (s *DockerSuite) TestPsListContainersFilterName(c *testing.T) {
  225. // start container
  226. dockerCmd(c, "run", "--name=a_name_to_match", "busybox")
  227. id := getIDByName(c, "a_name_to_match")
  228. // start another container
  229. runSleepingContainer(c, "--name=b_name_to_match")
  230. // filter containers by name
  231. out, _ := dockerCmd(c, "ps", "-a", "-q", "--filter=name=a_name_to_match")
  232. containerOut := strings.TrimSpace(out)
  233. assert.Equal(c, containerOut, id[:12], check.Commentf("Expected id %s, got %s for exited filter, output: %q", id[:12], containerOut, out))
  234. }
  235. // Test for the ancestor filter for ps.
  236. // There is also the same test but with image:tag@digest in docker_cli_by_digest_test.go
  237. //
  238. // What the test setups :
  239. // - Create 2 image based on busybox using the same repository but different tags
  240. // - Create an image based on the previous image (images_ps_filter_test2)
  241. // - Run containers for each of those image (busybox, images_ps_filter_test1, images_ps_filter_test2)
  242. // - Filter them out :P
  243. func (s *DockerSuite) TestPsListContainersFilterAncestorImage(c *testing.T) {
  244. existingContainers := ExistingContainerIDs(c)
  245. // Build images
  246. imageName1 := "images_ps_filter_test1"
  247. buildImageSuccessfully(c, imageName1, build.WithDockerfile(`FROM busybox
  248. LABEL match me 1`))
  249. imageID1 := getIDByName(c, imageName1)
  250. imageName1Tagged := "images_ps_filter_test1:tag"
  251. buildImageSuccessfully(c, imageName1Tagged, build.WithDockerfile(`FROM busybox
  252. LABEL match me 1 tagged`))
  253. imageID1Tagged := getIDByName(c, imageName1Tagged)
  254. imageName2 := "images_ps_filter_test2"
  255. buildImageSuccessfully(c, imageName2, build.WithDockerfile(fmt.Sprintf(`FROM %s
  256. LABEL match me 2`, imageName1)))
  257. imageID2 := getIDByName(c, imageName2)
  258. // start containers
  259. dockerCmd(c, "run", "--name=first", "busybox", "echo", "hello")
  260. firstID := getIDByName(c, "first")
  261. // start another container
  262. dockerCmd(c, "run", "--name=second", "busybox", "echo", "hello")
  263. secondID := getIDByName(c, "second")
  264. // start third container
  265. dockerCmd(c, "run", "--name=third", imageName1, "echo", "hello")
  266. thirdID := getIDByName(c, "third")
  267. // start fourth container
  268. dockerCmd(c, "run", "--name=fourth", imageName1Tagged, "echo", "hello")
  269. fourthID := getIDByName(c, "fourth")
  270. // start fifth container
  271. dockerCmd(c, "run", "--name=fifth", imageName2, "echo", "hello")
  272. fifthID := getIDByName(c, "fifth")
  273. var filterTestSuite = []struct {
  274. filterName string
  275. expectedIDs []string
  276. }{
  277. // non existent stuff
  278. {"nonexistent", []string{}},
  279. {"nonexistent:tag", []string{}},
  280. // image
  281. {"busybox", []string{firstID, secondID, thirdID, fourthID, fifthID}},
  282. {imageName1, []string{thirdID, fifthID}},
  283. {imageName2, []string{fifthID}},
  284. // image:tag
  285. {fmt.Sprintf("%s:latest", imageName1), []string{thirdID, fifthID}},
  286. {imageName1Tagged, []string{fourthID}},
  287. // short-id
  288. {stringid.TruncateID(imageID1), []string{thirdID, fifthID}},
  289. {stringid.TruncateID(imageID2), []string{fifthID}},
  290. // full-id
  291. {imageID1, []string{thirdID, fifthID}},
  292. {imageID1Tagged, []string{fourthID}},
  293. {imageID2, []string{fifthID}},
  294. }
  295. var out string
  296. for _, filter := range filterTestSuite {
  297. out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=ancestor="+filter.filterName)
  298. checkPsAncestorFilterOutput(c, RemoveOutputForExistingElements(out, existingContainers), filter.filterName, filter.expectedIDs)
  299. }
  300. // Multiple ancestor filter
  301. out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=ancestor="+imageName2, "--filter=ancestor="+imageName1Tagged)
  302. checkPsAncestorFilterOutput(c, RemoveOutputForExistingElements(out, existingContainers), imageName2+","+imageName1Tagged, []string{fourthID, fifthID})
  303. }
  304. func checkPsAncestorFilterOutput(c *testing.T, out string, filterName string, expectedIDs []string) {
  305. var actualIDs []string
  306. if out != "" {
  307. actualIDs = strings.Split(out[:len(out)-1], "\n")
  308. }
  309. sort.Strings(actualIDs)
  310. sort.Strings(expectedIDs)
  311. assert.Equal(c, len(actualIDs), len(expectedIDs), check.Commentf("Expected filtered container(s) for %s ancestor filter to be %v:%v, got %v:%v", filterName, len(expectedIDs), expectedIDs, len(actualIDs), actualIDs))
  312. if len(expectedIDs) > 0 {
  313. same := true
  314. for i := range expectedIDs {
  315. if actualIDs[i] != expectedIDs[i] {
  316. c.Logf("%s, %s", actualIDs[i], expectedIDs[i])
  317. same = false
  318. break
  319. }
  320. }
  321. assert.Equal(c, same, true, check.Commentf("Expected filtered container(s) for %s ancestor filter to be %v, got %v", filterName, expectedIDs, actualIDs))
  322. }
  323. }
  324. func (s *DockerSuite) TestPsListContainersFilterLabel(c *testing.T) {
  325. // start container
  326. dockerCmd(c, "run", "--name=first", "-l", "match=me", "-l", "second=tag", "busybox")
  327. firstID := getIDByName(c, "first")
  328. // start another container
  329. dockerCmd(c, "run", "--name=second", "-l", "match=me too", "busybox")
  330. secondID := getIDByName(c, "second")
  331. // start third container
  332. dockerCmd(c, "run", "--name=third", "-l", "nomatch=me", "busybox")
  333. thirdID := getIDByName(c, "third")
  334. // filter containers by exact match
  335. out, _ := dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me")
  336. containerOut := strings.TrimSpace(out)
  337. assert.Equal(c, containerOut, firstID, check.Commentf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out))
  338. // filter containers by two labels
  339. out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me", "--filter=label=second=tag")
  340. containerOut = strings.TrimSpace(out)
  341. assert.Equal(c, containerOut, firstID, check.Commentf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out))
  342. // filter containers by two labels, but expect not found because of AND behavior
  343. out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me", "--filter=label=second=tag-no")
  344. containerOut = strings.TrimSpace(out)
  345. assert.Equal(c, containerOut, "", check.Commentf("Expected nothing, got %s for exited filter, output: %q", containerOut, out))
  346. // filter containers by exact key
  347. out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match")
  348. containerOut = strings.TrimSpace(out)
  349. assert.Assert(c, containerOut, checker.Contains, firstID)
  350. assert.Assert(c, containerOut, checker.Contains, secondID)
  351. assert.Assert(c, !strings.Contains(containerOut, thirdID))
  352. }
  353. func (s *DockerSuite) TestPsListContainersFilterExited(c *testing.T) {
  354. runSleepingContainer(c, "--name=sleep")
  355. firstZero, _ := dockerCmd(c, "run", "-d", "busybox", "true")
  356. secondZero, _ := dockerCmd(c, "run", "-d", "busybox", "true")
  357. out, _, err := dockerCmdWithError("run", "--name", "nonzero1", "busybox", "false")
  358. assert.Assert(c, err != nil, check.Commentf("Should fail. out: %s", out))
  359. firstNonZero := getIDByName(c, "nonzero1")
  360. out, _, err = dockerCmdWithError("run", "--name", "nonzero2", "busybox", "false")
  361. assert.Assert(c, err != nil, check.Commentf("Should fail. out: %s", out))
  362. secondNonZero := getIDByName(c, "nonzero2")
  363. // filter containers by exited=0
  364. out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=exited=0")
  365. assert.Assert(c, out, checker.Contains, strings.TrimSpace(firstZero))
  366. assert.Assert(c, out, checker.Contains, strings.TrimSpace(secondZero))
  367. assert.Assert(c, !strings.Contains(out, strings.TrimSpace(firstNonZero)))
  368. assert.Assert(c, !strings.Contains(out, strings.TrimSpace(secondNonZero)))
  369. out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=exited=1")
  370. assert.Assert(c, out, checker.Contains, strings.TrimSpace(firstNonZero))
  371. assert.Assert(c, out, checker.Contains, strings.TrimSpace(secondNonZero))
  372. assert.Assert(c, !strings.Contains(out, strings.TrimSpace(firstZero)))
  373. assert.Assert(c, !strings.Contains(out, strings.TrimSpace(secondZero)))
  374. }
  375. func (s *DockerSuite) TestPsRightTagName(c *testing.T) {
  376. // TODO Investigate further why this fails on Windows to Windows CI
  377. testRequires(c, DaemonIsLinux)
  378. existingContainers := ExistingContainerNames(c)
  379. tag := "asybox:shmatest"
  380. dockerCmd(c, "tag", "busybox", tag)
  381. var id1 string
  382. out := runSleepingContainer(c)
  383. id1 = strings.TrimSpace(string(out))
  384. var id2 string
  385. out = runSleepingContainerInImage(c, tag)
  386. id2 = strings.TrimSpace(string(out))
  387. var imageID string
  388. out = inspectField(c, "busybox", "Id")
  389. imageID = strings.TrimSpace(string(out))
  390. var id3 string
  391. out = runSleepingContainerInImage(c, imageID)
  392. id3 = strings.TrimSpace(string(out))
  393. out, _ = dockerCmd(c, "ps", "--no-trunc")
  394. lines := strings.Split(strings.TrimSpace(string(out)), "\n")
  395. lines = RemoveLinesForExistingElements(lines, existingContainers)
  396. // skip header
  397. lines = lines[1:]
  398. assert.Equal(c, len(lines), 3, "There should be 3 running container, got %d", len(lines))
  399. for _, line := range lines {
  400. f := strings.Fields(line)
  401. switch f[0] {
  402. case id1:
  403. assert.Equal(c, f[1], "busybox", check.Commentf("Expected %s tag for id %s, got %s", "busybox", id1, f[1]))
  404. case id2:
  405. assert.Equal(c, f[1], tag, check.Commentf("Expected %s tag for id %s, got %s", tag, id2, f[1]))
  406. case id3:
  407. assert.Equal(c, f[1], imageID, check.Commentf("Expected %s imageID for id %s, got %s", tag, id3, f[1]))
  408. default:
  409. c.Fatalf("Unexpected id %s, expected %s and %s and %s", f[0], id1, id2, id3)
  410. }
  411. }
  412. }
  413. func (s *DockerSuite) TestPsListContainersFilterCreated(c *testing.T) {
  414. // create a container
  415. out, _ := dockerCmd(c, "create", "busybox")
  416. cID := strings.TrimSpace(out)
  417. shortCID := cID[:12]
  418. // Make sure it DOESN'T show up w/o a '-a' for normal 'ps'
  419. out, _ = dockerCmd(c, "ps", "-q")
  420. assert.Assert(c, !strings.Contains(out, shortCID), check.Commentf("Should have not seen '%s' in ps output:\n%s", shortCID, out))
  421. // Make sure it DOES show up as 'Created' for 'ps -a'
  422. out, _ = dockerCmd(c, "ps", "-a")
  423. hits := 0
  424. for _, line := range strings.Split(out, "\n") {
  425. if !strings.Contains(line, shortCID) {
  426. continue
  427. }
  428. hits++
  429. assert.Assert(c, line, checker.Contains, "Created", check.Commentf("Missing 'Created' on '%s'", line))
  430. }
  431. assert.Equal(c, hits, 1, check.Commentf("Should have seen '%s' in ps -a output once:%d\n%s", shortCID, hits, out))
  432. // filter containers by 'create' - note, no -a needed
  433. out, _ = dockerCmd(c, "ps", "-q", "-f", "status=created")
  434. containerOut := strings.TrimSpace(out)
  435. assert.Assert(c, strings.HasPrefix(cID, containerOut))
  436. }
  437. // Test for GitHub issue #12595
  438. func (s *DockerSuite) TestPsImageIDAfterUpdate(c *testing.T) {
  439. // TODO: Investigate why this fails on Windows to Windows CI further.
  440. testRequires(c, DaemonIsLinux)
  441. originalImageName := "busybox:TestPsImageIDAfterUpdate-original"
  442. updatedImageName := "busybox:TestPsImageIDAfterUpdate-updated"
  443. existingContainers := ExistingContainerIDs(c)
  444. icmd.RunCommand(dockerBinary, "tag", "busybox:latest", originalImageName).Assert(c, icmd.Success)
  445. originalImageID := getIDByName(c, originalImageName)
  446. result := icmd.RunCommand(dockerBinary, append([]string{"run", "-d", originalImageName}, sleepCommandForDaemonPlatform()...)...)
  447. result.Assert(c, icmd.Success)
  448. containerID := strings.TrimSpace(result.Combined())
  449. result = icmd.RunCommand(dockerBinary, "ps", "--no-trunc")
  450. result.Assert(c, icmd.Success)
  451. lines := strings.Split(strings.TrimSpace(string(result.Combined())), "\n")
  452. lines = RemoveLinesForExistingElements(lines, existingContainers)
  453. // skip header
  454. lines = lines[1:]
  455. assert.Equal(c, len(lines), 1)
  456. for _, line := range lines {
  457. f := strings.Fields(line)
  458. assert.Equal(c, f[1], originalImageName)
  459. }
  460. icmd.RunCommand(dockerBinary, "commit", containerID, updatedImageName).Assert(c, icmd.Success)
  461. icmd.RunCommand(dockerBinary, "tag", updatedImageName, originalImageName).Assert(c, icmd.Success)
  462. result = icmd.RunCommand(dockerBinary, "ps", "--no-trunc")
  463. result.Assert(c, icmd.Success)
  464. lines = strings.Split(strings.TrimSpace(string(result.Combined())), "\n")
  465. lines = RemoveLinesForExistingElements(lines, existingContainers)
  466. // skip header
  467. lines = lines[1:]
  468. assert.Equal(c, len(lines), 1)
  469. for _, line := range lines {
  470. f := strings.Fields(line)
  471. assert.Equal(c, f[1], originalImageID)
  472. }
  473. }
  474. func (s *DockerSuite) TestPsNotShowPortsOfStoppedContainer(c *testing.T) {
  475. testRequires(c, DaemonIsLinux)
  476. dockerCmd(c, "run", "--name=foo", "-d", "-p", "5000:5000", "busybox", "top")
  477. assert.Assert(c, waitRun("foo") == nil)
  478. out, _ := dockerCmd(c, "ps")
  479. lines := strings.Split(strings.TrimSpace(string(out)), "\n")
  480. expected := "0.0.0.0:5000->5000/tcp"
  481. fields := strings.Fields(lines[1])
  482. assert.Equal(c, fields[len(fields)-2], expected, check.Commentf("Expected: %v, got: %v", expected, fields[len(fields)-2]))
  483. dockerCmd(c, "kill", "foo")
  484. dockerCmd(c, "wait", "foo")
  485. out, _ = dockerCmd(c, "ps", "-l")
  486. lines = strings.Split(strings.TrimSpace(string(out)), "\n")
  487. fields = strings.Fields(lines[1])
  488. assert.Assert(c, fields[len(fields)-2] != expected, check.Commentf("Should not got %v", expected))
  489. }
  490. func (s *DockerSuite) TestPsShowMounts(c *testing.T) {
  491. existingContainers := ExistingContainerNames(c)
  492. prefix, slash := getPrefixAndSlashFromDaemonPlatform()
  493. mp := prefix + slash + "test"
  494. dockerCmd(c, "volume", "create", "ps-volume-test")
  495. // volume mount containers
  496. runSleepingContainer(c, "--name=volume-test-1", "--volume", "ps-volume-test:"+mp)
  497. assert.Assert(c, waitRun("volume-test-1") == nil)
  498. runSleepingContainer(c, "--name=volume-test-2", "--volume", mp)
  499. assert.Assert(c, waitRun("volume-test-2") == nil)
  500. // bind mount container
  501. var bindMountSource string
  502. var bindMountDestination string
  503. if DaemonIsWindows() {
  504. bindMountSource = "c:\\"
  505. bindMountDestination = "c:\\t"
  506. } else {
  507. bindMountSource = "/tmp"
  508. bindMountDestination = "/t"
  509. }
  510. runSleepingContainer(c, "--name=bind-mount-test", "-v", bindMountSource+":"+bindMountDestination)
  511. assert.Assert(c, waitRun("bind-mount-test") == nil)
  512. out, _ := dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}")
  513. lines := strings.Split(strings.TrimSpace(string(out)), "\n")
  514. lines = RemoveLinesForExistingElements(lines, existingContainers)
  515. assert.Equal(c, len(lines), 3)
  516. fields := strings.Fields(lines[0])
  517. assert.Equal(c, len(fields), 2)
  518. assert.Equal(c, fields[0], "bind-mount-test")
  519. assert.Equal(c, fields[1], bindMountSource)
  520. fields = strings.Fields(lines[1])
  521. assert.Equal(c, len(fields), 2)
  522. anonymousVolumeID := fields[1]
  523. fields = strings.Fields(lines[2])
  524. assert.Equal(c, fields[1], "ps-volume-test")
  525. // filter by volume name
  526. out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=ps-volume-test")
  527. lines = strings.Split(strings.TrimSpace(string(out)), "\n")
  528. lines = RemoveLinesForExistingElements(lines, existingContainers)
  529. assert.Equal(c, len(lines), 1)
  530. fields = strings.Fields(lines[0])
  531. assert.Equal(c, fields[1], "ps-volume-test")
  532. // empty results filtering by unknown volume
  533. out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=this-volume-should-not-exist")
  534. assert.Equal(c, len(strings.TrimSpace(string(out))), 0)
  535. // filter by mount destination
  536. out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+mp)
  537. lines = strings.Split(strings.TrimSpace(string(out)), "\n")
  538. lines = RemoveLinesForExistingElements(lines, existingContainers)
  539. assert.Equal(c, len(lines), 2)
  540. fields = strings.Fields(lines[0])
  541. assert.Equal(c, fields[1], anonymousVolumeID)
  542. fields = strings.Fields(lines[1])
  543. assert.Equal(c, fields[1], "ps-volume-test")
  544. // filter by bind mount source
  545. out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountSource)
  546. lines = strings.Split(strings.TrimSpace(string(out)), "\n")
  547. lines = RemoveLinesForExistingElements(lines, existingContainers)
  548. assert.Equal(c, len(lines), 1)
  549. fields = strings.Fields(lines[0])
  550. assert.Equal(c, len(fields), 2)
  551. assert.Equal(c, fields[0], "bind-mount-test")
  552. assert.Equal(c, fields[1], bindMountSource)
  553. // filter by bind mount destination
  554. out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountDestination)
  555. lines = strings.Split(strings.TrimSpace(string(out)), "\n")
  556. lines = RemoveLinesForExistingElements(lines, existingContainers)
  557. assert.Equal(c, len(lines), 1)
  558. fields = strings.Fields(lines[0])
  559. assert.Equal(c, len(fields), 2)
  560. assert.Equal(c, fields[0], "bind-mount-test")
  561. assert.Equal(c, fields[1], bindMountSource)
  562. // empty results filtering by unknown mount point
  563. out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+prefix+slash+"this-path-was-never-mounted")
  564. assert.Equal(c, len(strings.TrimSpace(string(out))), 0)
  565. }
  566. func (s *DockerSuite) TestPsListContainersFilterNetwork(c *testing.T) {
  567. existing := ExistingContainerIDs(c)
  568. // TODO default network on Windows is not called "bridge", and creating a
  569. // custom network fails on Windows fails with "Error response from daemon: plugin not found")
  570. testRequires(c, DaemonIsLinux)
  571. // create some containers
  572. runSleepingContainer(c, "--net=bridge", "--name=onbridgenetwork")
  573. runSleepingContainer(c, "--net=none", "--name=onnonenetwork")
  574. // Filter docker ps on non existing network
  575. out, _ := dockerCmd(c, "ps", "--filter", "network=doesnotexist")
  576. containerOut := strings.TrimSpace(string(out))
  577. lines := strings.Split(containerOut, "\n")
  578. // skip header
  579. lines = lines[1:]
  580. // ps output should have no containers
  581. assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 0)
  582. // Filter docker ps on network bridge
  583. out, _ = dockerCmd(c, "ps", "--filter", "network=bridge")
  584. containerOut = strings.TrimSpace(string(out))
  585. lines = strings.Split(containerOut, "\n")
  586. // skip header
  587. lines = lines[1:]
  588. // ps output should have only one container
  589. assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 1)
  590. // Making sure onbridgenetwork is on the output
  591. assert.Assert(c, containerOut, checker.Contains, "onbridgenetwork", check.Commentf("Missing the container on network\n"))
  592. // Filter docker ps on networks bridge and none
  593. out, _ = dockerCmd(c, "ps", "--filter", "network=bridge", "--filter", "network=none")
  594. containerOut = strings.TrimSpace(string(out))
  595. lines = strings.Split(containerOut, "\n")
  596. // skip header
  597. lines = lines[1:]
  598. //ps output should have both the containers
  599. assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 2)
  600. // Making sure onbridgenetwork and onnonenetwork is on the output
  601. assert.Assert(c, containerOut, checker.Contains, "onnonenetwork", check.Commentf("Missing the container on none network\n"))
  602. assert.Assert(c, containerOut, checker.Contains, "onbridgenetwork", check.Commentf("Missing the container on bridge network\n"))
  603. nwID, _ := dockerCmd(c, "network", "inspect", "--format", "{{.ID}}", "bridge")
  604. // Filter by network ID
  605. out, _ = dockerCmd(c, "ps", "--filter", "network="+nwID)
  606. containerOut = strings.TrimSpace(string(out))
  607. assert.Assert(c, is.Contains(containerOut, "onbridgenetwork"))
  608. // Filter by partial network ID
  609. partialnwID := string(nwID[0:4])
  610. out, _ = dockerCmd(c, "ps", "--filter", "network="+partialnwID)
  611. containerOut = strings.TrimSpace(string(out))
  612. lines = strings.Split(containerOut, "\n")
  613. // skip header
  614. lines = lines[1:]
  615. // ps output should have only one container
  616. assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 1)
  617. // Making sure onbridgenetwork is on the output
  618. assert.Assert(c, containerOut, checker.Contains, "onbridgenetwork", check.Commentf("Missing the container on network\n"))
  619. }
  620. func (s *DockerSuite) TestPsByOrder(c *testing.T) {
  621. out := runSleepingContainer(c, "--name", "xyz-abc")
  622. container1 := strings.TrimSpace(out)
  623. out = runSleepingContainer(c, "--name", "xyz-123")
  624. container2 := strings.TrimSpace(out)
  625. runSleepingContainer(c, "--name", "789-abc")
  626. runSleepingContainer(c, "--name", "789-123")
  627. // Run multiple time should have the same result
  628. out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz").Combined()
  629. assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%s\n%s", container2, container1))
  630. // Run multiple time should have the same result
  631. out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz").Combined()
  632. assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%s\n%s", container2, container1))
  633. }
  634. func (s *DockerSuite) TestPsListContainersFilterPorts(c *testing.T) {
  635. testRequires(c, DaemonIsLinux)
  636. existingContainers := ExistingContainerIDs(c)
  637. out, _ := dockerCmd(c, "run", "-d", "--publish=80", "busybox", "top")
  638. id1 := strings.TrimSpace(out)
  639. out, _ = dockerCmd(c, "run", "-d", "--expose=8080", "busybox", "top")
  640. id2 := strings.TrimSpace(out)
  641. out, _ = dockerCmd(c, "ps", "--no-trunc", "-q")
  642. assert.Assert(c, strings.TrimSpace(out), checker.Contains, id1)
  643. assert.Assert(c, strings.TrimSpace(out), checker.Contains, id2)
  644. out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-8080/udp")
  645. assert.Assert(c, strings.TrimSpace(out) != id1)
  646. assert.Assert(c, strings.TrimSpace(out) != id2)
  647. out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8081")
  648. assert.Assert(c, strings.TrimSpace(out) != id1)
  649. assert.Assert(c, strings.TrimSpace(out) != id2)
  650. out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-81")
  651. assert.Equal(c, strings.TrimSpace(out), id1)
  652. assert.Assert(c, strings.TrimSpace(out) != id2)
  653. out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=80/tcp")
  654. assert.Equal(c, strings.TrimSpace(out), id1)
  655. assert.Assert(c, strings.TrimSpace(out) != id2)
  656. out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8080/tcp")
  657. out = RemoveOutputForExistingElements(out, existingContainers)
  658. assert.Assert(c, strings.TrimSpace(out) != id1)
  659. assert.Equal(c, strings.TrimSpace(out), id2)
  660. }
  661. func (s *DockerSuite) TestPsNotShowLinknamesOfDeletedContainer(c *testing.T) {
  662. testRequires(c, DaemonIsLinux, MinimumAPIVersion("1.31"))
  663. existingContainers := ExistingContainerNames(c)
  664. dockerCmd(c, "create", "--name=aaa", "busybox", "top")
  665. dockerCmd(c, "create", "--name=bbb", "--link=aaa", "busybox", "top")
  666. out, _ := dockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}")
  667. lines := strings.Split(strings.TrimSpace(string(out)), "\n")
  668. lines = RemoveLinesForExistingElements(lines, existingContainers)
  669. expected := []string{"bbb", "aaa,bbb/aaa"}
  670. var names []string
  671. names = append(names, lines...)
  672. assert.Assert(c, is.DeepEqual(names, expected), "Expected array with non-truncated names: %v, got: %v", expected, names)
  673. dockerCmd(c, "rm", "bbb")
  674. out, _ = dockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}")
  675. out = RemoveOutputForExistingElements(out, existingContainers)
  676. assert.Equal(c, strings.TrimSpace(out), "aaa")
  677. }