docker_cli_ps_test.go 36 KB

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