docker_cli_ps_test.go 36 KB

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