docker_cli_ps_test.go 36 KB

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