github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/integration-cli/docker_cli_ps_test.go (about)

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