docker_cli_ps_test.go 35 KB

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