github.com/afbjorklund/moby@v20.10.5+incompatible/integration-cli/docker_cli_ps_test.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strconv"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/docker/docker/api/types/versions"
    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  	"gotest.tools/v3/assert"
    16  	is "gotest.tools/v3/assert/cmp"
    17  	"gotest.tools/v3/icmd"
    18  	"gotest.tools/v3/skip"
    19  )
    20  
    21  func (s *DockerSuite) TestPsListContainersBase(c *testing.T) {
    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  	assert.Assert(c, waitRun(secondID) == nil)
    39  
    40  	// make sure third one is not running
    41  	dockerCmd(c, "wait", thirdID)
    42  
    43  	// make sure the forth is running
    44  	assert.Assert(c, waitRun(fourthID) == nil)
    45  
    46  	// all
    47  	out, _ = dockerCmd(c, "ps", "-a")
    48  	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))
    49  
    50  	// running
    51  	out, _ = dockerCmd(c, "ps")
    52  	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))
    53  
    54  	// limit
    55  	out, _ = dockerCmd(c, "ps", "-n=2", "-a")
    56  	expected := []string{fourthID, thirdID}
    57  	assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("LIMIT & ALL: Container list is not in the correct order: \n%s", out))
    58  
    59  	out, _ = dockerCmd(c, "ps", "-n=2")
    60  	assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("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  	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))
    66  
    67  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID)
    68  	expected = []string{fourthID, secondID}
    69  	assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("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  	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  
    75  	// filter before
    76  	out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-a")
    77  	expected = []string{thirdID, secondID, firstID}
    78  	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))
    79  
    80  	out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID)
    81  	expected = []string{secondID, firstID}
    82  	assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("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  	assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("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  	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))
    92  
    93  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID)
    94  	expected = []string{secondID}
    95  	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))
    96  
    97  	// filter since & limit
    98  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2", "-a")
    99  	expected = []string{fourthID, thirdID}
   100  
   101  	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))
   102  
   103  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2")
   104  	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))
   105  
   106  	// filter before & limit
   107  	out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1", "-a")
   108  	expected = []string{thirdID}
   109  	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))
   110  
   111  	out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1")
   112  	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))
   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  	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))
   118  
   119  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1")
   120  	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))
   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 *testing.T) {
   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  	assert.Equal(c, foundID, id[:12], fmt.Sprintf("Expected id %s, got %s", id[:12], foundID))
   177  	expectedSize := fmt.Sprintf("%dB", 2+baseBytes)
   178  	foundSize := lines[1][sizeIndex:]
   179  	assert.Assert(c, strings.Contains(foundSize, expectedSize), "Expected size %q, got %q", expectedSize, foundSize)
   180  }
   181  
   182  func (s *DockerSuite) TestPsListContainersFilterStatus(c *testing.T) {
   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  	assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), firstID)
   200  
   201  	out = cli.DockerCmd(c, "ps", "-a", "--no-trunc", "-q", "--filter=status=running").Combined()
   202  	containerOut = strings.TrimSpace(out)
   203  	assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), 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  		assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), pausedID)
   226  	}
   227  }
   228  
   229  func (s *DockerSuite) TestPsListContainersFilterHealth(c *testing.T) {
   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  	assert.Equal(c, containerOut, containerID, fmt.Sprintf("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  	assert.Equal(c, containerOut, containerID, fmt.Sprintf("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  	assert.Equal(c, containerOut, containerID, fmt.Sprintf("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  	assert.Equal(c, containerOut, containerID, fmt.Sprintf("Expected containerID %s, got %s for healthy filter, output: %q", containerID, containerOut, out))
   270  }
   271  
   272  func (s *DockerSuite) TestPsListContainersFilterID(c *testing.T) {
   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  	assert.Equal(c, containerOut, firstID[:12], fmt.Sprintf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out))
   284  }
   285  
   286  func (s *DockerSuite) TestPsListContainersFilterName(c *testing.T) {
   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  	assert.Equal(c, containerOut, id[:12], fmt.Sprintf("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 *testing.T) {
   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 *testing.T, 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  	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))
   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  		assert.Equal(c, same, true, fmt.Sprintf("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 *testing.T) {
   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  	assert.Equal(c, containerOut, firstID, fmt.Sprintf("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  	assert.Equal(c, containerOut, firstID, fmt.Sprintf("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  	assert.Equal(c, containerOut, "", fmt.Sprintf("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  	assert.Assert(c, strings.Contains(containerOut, firstID))
   435  	assert.Assert(c, strings.Contains(containerOut, secondID))
   436  	assert.Assert(c, !strings.Contains(containerOut, thirdID))
   437  }
   438  
   439  func (s *DockerSuite) TestPsListContainersFilterExited(c *testing.T) {
   440  	// TODO Flaky on  Windows CI [both RS1 and RS5]
   441  	// On slower machines the container may not have exited
   442  	// yet when we filter below by exit status/exit value.
   443  	skip.If(c, DaemonIsWindows(), "FLAKY on Windows, see #20819")
   444  	runSleepingContainer(c, "--name=sleep")
   445  
   446  	firstZero, _ := dockerCmd(c, "run", "-d", "busybox", "true")
   447  	secondZero, _ := dockerCmd(c, "run", "-d", "busybox", "true")
   448  
   449  	out, _, err := dockerCmdWithError("run", "--name", "nonzero1", "busybox", "false")
   450  	assert.Assert(c, err != nil, "Should fail. out: %s", out)
   451  	firstNonZero := getIDByName(c, "nonzero1")
   452  
   453  	out, _, err = dockerCmdWithError("run", "--name", "nonzero2", "busybox", "false")
   454  	assert.Assert(c, err != nil, "Should fail. out: %s", out)
   455  	secondNonZero := getIDByName(c, "nonzero2")
   456  
   457  	// filter containers by exited=0
   458  	out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=exited=0")
   459  	assert.Assert(c, strings.Contains(out, strings.TrimSpace(firstZero)))
   460  	assert.Assert(c, strings.Contains(out, strings.TrimSpace(secondZero)))
   461  	assert.Assert(c, !strings.Contains(out, strings.TrimSpace(firstNonZero)))
   462  	assert.Assert(c, !strings.Contains(out, strings.TrimSpace(secondNonZero)))
   463  	out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=exited=1")
   464  	assert.Assert(c, strings.Contains(out, strings.TrimSpace(firstNonZero)))
   465  	assert.Assert(c, strings.Contains(out, strings.TrimSpace(secondNonZero)))
   466  	assert.Assert(c, !strings.Contains(out, strings.TrimSpace(firstZero)))
   467  	assert.Assert(c, !strings.Contains(out, strings.TrimSpace(secondZero)))
   468  }
   469  
   470  func (s *DockerSuite) TestPsRightTagName(c *testing.T) {
   471  	// TODO Investigate further why this fails on Windows to Windows CI
   472  	testRequires(c, DaemonIsLinux)
   473  
   474  	existingContainers := ExistingContainerNames(c)
   475  
   476  	tag := "asybox:shmatest"
   477  	dockerCmd(c, "tag", "busybox", tag)
   478  
   479  	var id1 string
   480  	out := runSleepingContainer(c)
   481  	id1 = strings.TrimSpace(out)
   482  
   483  	var id2 string
   484  	out = runSleepingContainerInImage(c, tag)
   485  	id2 = strings.TrimSpace(out)
   486  
   487  	var imageID string
   488  	out = inspectField(c, "busybox", "Id")
   489  	imageID = strings.TrimSpace(out)
   490  
   491  	var id3 string
   492  	out = runSleepingContainerInImage(c, imageID)
   493  	id3 = strings.TrimSpace(out)
   494  
   495  	out, _ = dockerCmd(c, "ps", "--no-trunc")
   496  	lines := strings.Split(strings.TrimSpace(out), "\n")
   497  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   498  	// skip header
   499  	lines = lines[1:]
   500  	assert.Equal(c, len(lines), 3, "There should be 3 running container, got %d", len(lines))
   501  	for _, line := range lines {
   502  		f := strings.Fields(line)
   503  		switch f[0] {
   504  		case id1:
   505  			assert.Equal(c, f[1], "busybox", fmt.Sprintf("Expected %s tag for id %s, got %s", "busybox", id1, f[1]))
   506  		case id2:
   507  			assert.Equal(c, f[1], tag, fmt.Sprintf("Expected %s tag for id %s, got %s", tag, id2, f[1]))
   508  		case id3:
   509  			assert.Equal(c, f[1], imageID, fmt.Sprintf("Expected %s imageID for id %s, got %s", tag, id3, f[1]))
   510  		default:
   511  			c.Fatalf("Unexpected id %s, expected %s and %s and %s", f[0], id1, id2, id3)
   512  		}
   513  	}
   514  }
   515  
   516  func (s *DockerSuite) TestPsListContainersFilterCreated(c *testing.T) {
   517  	// create a container
   518  	out, _ := dockerCmd(c, "create", "busybox")
   519  	cID := strings.TrimSpace(out)
   520  	shortCID := cID[:12]
   521  
   522  	// Make sure it DOESN'T show up w/o a '-a' for normal 'ps'
   523  	out, _ = dockerCmd(c, "ps", "-q")
   524  	assert.Assert(c, !strings.Contains(out, shortCID), "Should have not seen '%s' in ps output:\n%s", shortCID, out)
   525  	// Make sure it DOES show up as 'Created' for 'ps -a'
   526  	out, _ = dockerCmd(c, "ps", "-a")
   527  
   528  	hits := 0
   529  	for _, line := range strings.Split(out, "\n") {
   530  		if !strings.Contains(line, shortCID) {
   531  			continue
   532  		}
   533  		hits++
   534  		assert.Assert(c, strings.Contains(line, "Created"), "Missing 'Created' on '%s'", line)
   535  	}
   536  
   537  	assert.Equal(c, hits, 1, fmt.Sprintf("Should have seen '%s' in ps -a output once:%d\n%s", shortCID, hits, out))
   538  
   539  	// filter containers by 'create' - note, no -a needed
   540  	out, _ = dockerCmd(c, "ps", "-q", "-f", "status=created")
   541  	containerOut := strings.TrimSpace(out)
   542  	assert.Assert(c, strings.HasPrefix(cID, containerOut))
   543  }
   544  
   545  // Test for GitHub issue #12595
   546  func (s *DockerSuite) TestPsImageIDAfterUpdate(c *testing.T) {
   547  	// TODO: Investigate why this fails on Windows to Windows CI further.
   548  	testRequires(c, DaemonIsLinux)
   549  	originalImageName := "busybox:TestPsImageIDAfterUpdate-original"
   550  	updatedImageName := "busybox:TestPsImageIDAfterUpdate-updated"
   551  
   552  	existingContainers := ExistingContainerIDs(c)
   553  
   554  	icmd.RunCommand(dockerBinary, "tag", "busybox:latest", originalImageName).Assert(c, icmd.Success)
   555  
   556  	originalImageID := getIDByName(c, originalImageName)
   557  
   558  	result := icmd.RunCommand(dockerBinary, append([]string{"run", "-d", originalImageName}, sleepCommandForDaemonPlatform()...)...)
   559  	result.Assert(c, icmd.Success)
   560  	containerID := strings.TrimSpace(result.Combined())
   561  
   562  	result = icmd.RunCommand(dockerBinary, "ps", "--no-trunc")
   563  	result.Assert(c, icmd.Success)
   564  
   565  	lines := strings.Split(strings.TrimSpace(result.Combined()), "\n")
   566  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   567  	// skip header
   568  	lines = lines[1:]
   569  	assert.Equal(c, len(lines), 1)
   570  
   571  	for _, line := range lines {
   572  		f := strings.Fields(line)
   573  		assert.Equal(c, f[1], originalImageName)
   574  	}
   575  
   576  	icmd.RunCommand(dockerBinary, "commit", containerID, updatedImageName).Assert(c, icmd.Success)
   577  	icmd.RunCommand(dockerBinary, "tag", updatedImageName, originalImageName).Assert(c, icmd.Success)
   578  
   579  	result = icmd.RunCommand(dockerBinary, "ps", "--no-trunc")
   580  	result.Assert(c, icmd.Success)
   581  
   582  	lines = strings.Split(strings.TrimSpace(result.Combined()), "\n")
   583  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   584  	// skip header
   585  	lines = lines[1:]
   586  	assert.Equal(c, len(lines), 1)
   587  
   588  	for _, line := range lines {
   589  		f := strings.Fields(line)
   590  		assert.Equal(c, f[1], originalImageID)
   591  	}
   592  
   593  }
   594  
   595  func (s *DockerSuite) TestPsNotShowPortsOfStoppedContainer(c *testing.T) {
   596  	testRequires(c, DaemonIsLinux)
   597  	dockerCmd(c, "run", "--name=foo", "-d", "-p", "5000:5000", "busybox", "top")
   598  	assert.Assert(c, waitRun("foo") == nil)
   599  	out, _ := dockerCmd(c, "ps")
   600  	lines := strings.Split(strings.TrimSpace(out), "\n")
   601  	expected := "0.0.0.0:5000->5000/tcp"
   602  	fields := strings.Fields(lines[1])
   603  	assert.Equal(c, fields[len(fields)-2], expected, fmt.Sprintf("Expected: %v, got: %v", expected, fields[len(fields)-2]))
   604  
   605  	dockerCmd(c, "kill", "foo")
   606  	dockerCmd(c, "wait", "foo")
   607  	out, _ = dockerCmd(c, "ps", "-l")
   608  	lines = strings.Split(strings.TrimSpace(out), "\n")
   609  	fields = strings.Fields(lines[1])
   610  	assert.Assert(c, fields[len(fields)-2] != expected, "Should not got %v", expected)
   611  }
   612  
   613  func (s *DockerSuite) TestPsShowMounts(c *testing.T) {
   614  	existingContainers := ExistingContainerNames(c)
   615  
   616  	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
   617  
   618  	mp := prefix + slash + "test"
   619  
   620  	dockerCmd(c, "volume", "create", "ps-volume-test")
   621  	// volume mount containers
   622  	runSleepingContainer(c, "--name=volume-test-1", "--volume", "ps-volume-test:"+mp)
   623  	assert.Assert(c, waitRun("volume-test-1") == nil)
   624  	runSleepingContainer(c, "--name=volume-test-2", "--volume", mp)
   625  	assert.Assert(c, waitRun("volume-test-2") == nil)
   626  	// bind mount container
   627  	var bindMountSource string
   628  	var bindMountDestination string
   629  	if DaemonIsWindows() {
   630  		bindMountSource = "c:\\"
   631  		bindMountDestination = "c:\\t"
   632  	} else {
   633  		bindMountSource = "/tmp"
   634  		bindMountDestination = "/t"
   635  	}
   636  	runSleepingContainer(c, "--name=bind-mount-test", "-v", bindMountSource+":"+bindMountDestination)
   637  	assert.Assert(c, waitRun("bind-mount-test") == nil)
   638  
   639  	out, _ := dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}")
   640  
   641  	lines := strings.Split(strings.TrimSpace(out), "\n")
   642  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   643  	assert.Equal(c, len(lines), 3)
   644  
   645  	fields := strings.Fields(lines[0])
   646  	assert.Equal(c, len(fields), 2)
   647  	assert.Equal(c, fields[0], "bind-mount-test")
   648  	assert.Equal(c, fields[1], bindMountSource)
   649  
   650  	fields = strings.Fields(lines[1])
   651  	assert.Equal(c, len(fields), 2)
   652  
   653  	anonymousVolumeID := fields[1]
   654  
   655  	fields = strings.Fields(lines[2])
   656  	assert.Equal(c, fields[1], "ps-volume-test")
   657  
   658  	// filter by volume name
   659  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=ps-volume-test")
   660  
   661  	lines = strings.Split(strings.TrimSpace(out), "\n")
   662  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   663  	assert.Equal(c, len(lines), 1)
   664  
   665  	fields = strings.Fields(lines[0])
   666  	assert.Equal(c, fields[1], "ps-volume-test")
   667  
   668  	// empty results filtering by unknown volume
   669  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=this-volume-should-not-exist")
   670  	assert.Equal(c, len(strings.TrimSpace(out)), 0)
   671  
   672  	// filter by mount destination
   673  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+mp)
   674  
   675  	lines = strings.Split(strings.TrimSpace(out), "\n")
   676  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   677  	assert.Equal(c, len(lines), 2)
   678  
   679  	fields = strings.Fields(lines[0])
   680  	assert.Equal(c, fields[1], anonymousVolumeID)
   681  	fields = strings.Fields(lines[1])
   682  	assert.Equal(c, fields[1], "ps-volume-test")
   683  
   684  	// filter by bind mount source
   685  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountSource)
   686  
   687  	lines = strings.Split(strings.TrimSpace(out), "\n")
   688  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   689  	assert.Equal(c, len(lines), 1)
   690  
   691  	fields = strings.Fields(lines[0])
   692  	assert.Equal(c, len(fields), 2)
   693  	assert.Equal(c, fields[0], "bind-mount-test")
   694  	assert.Equal(c, fields[1], bindMountSource)
   695  
   696  	// filter by bind mount destination
   697  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountDestination)
   698  
   699  	lines = strings.Split(strings.TrimSpace(out), "\n")
   700  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   701  	assert.Equal(c, len(lines), 1)
   702  
   703  	fields = strings.Fields(lines[0])
   704  	assert.Equal(c, len(fields), 2)
   705  	assert.Equal(c, fields[0], "bind-mount-test")
   706  	assert.Equal(c, fields[1], bindMountSource)
   707  
   708  	// empty results filtering by unknown mount point
   709  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+prefix+slash+"this-path-was-never-mounted")
   710  	assert.Equal(c, len(strings.TrimSpace(out)), 0)
   711  }
   712  
   713  func (s *DockerSuite) TestPsListContainersFilterNetwork(c *testing.T) {
   714  	existing := ExistingContainerIDs(c)
   715  
   716  	// TODO default network on Windows is not called "bridge", and creating a
   717  	// custom network fails on Windows fails with "Error response from daemon: plugin not found")
   718  	testRequires(c, DaemonIsLinux)
   719  
   720  	// create some containers
   721  	runSleepingContainer(c, "--net=bridge", "--name=onbridgenetwork")
   722  	runSleepingContainer(c, "--net=none", "--name=onnonenetwork")
   723  
   724  	// Filter docker ps on non existing network
   725  	out, _ := dockerCmd(c, "ps", "--filter", "network=doesnotexist")
   726  	containerOut := strings.TrimSpace(out)
   727  	lines := strings.Split(containerOut, "\n")
   728  
   729  	// skip header
   730  	lines = lines[1:]
   731  
   732  	// ps output should have no containers
   733  	assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 0)
   734  
   735  	// Filter docker ps on network bridge
   736  	out, _ = dockerCmd(c, "ps", "--filter", "network=bridge")
   737  	containerOut = strings.TrimSpace(out)
   738  
   739  	lines = strings.Split(containerOut, "\n")
   740  
   741  	// skip header
   742  	lines = lines[1:]
   743  
   744  	// ps output should have only one container
   745  	assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 1)
   746  
   747  	// Making sure onbridgenetwork is on the output
   748  	assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on network\n")
   749  	// Filter docker ps on networks bridge and none
   750  	out, _ = dockerCmd(c, "ps", "--filter", "network=bridge", "--filter", "network=none")
   751  	containerOut = strings.TrimSpace(out)
   752  
   753  	lines = strings.Split(containerOut, "\n")
   754  
   755  	// skip header
   756  	lines = lines[1:]
   757  
   758  	// ps output should have both the containers
   759  	assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 2)
   760  
   761  	// Making sure onbridgenetwork and onnonenetwork is on the output
   762  	assert.Assert(c, strings.Contains(containerOut, "onnonenetwork"), "Missing the container on none network\n")
   763  	assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on bridge network\n")
   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(out)
   769  
   770  	assert.Assert(c, is.Contains(containerOut, "onbridgenetwork"))
   771  
   772  	// Filter by partial network ID
   773  	partialnwID := nwID[0:4]
   774  
   775  	out, _ = dockerCmd(c, "ps", "--filter", "network="+partialnwID)
   776  	containerOut = strings.TrimSpace(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  	assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on network\n")
   788  }
   789  
   790  func (s *DockerSuite) TestPsByOrder(c *testing.T) {
   791  	out := runSleepingContainer(c, "--name", "xyz-abc")
   792  	container1 := strings.TrimSpace(out)
   793  
   794  	out = runSleepingContainer(c, "--name", "xyz-123")
   795  	container2 := strings.TrimSpace(out)
   796  
   797  	runSleepingContainer(c, "--name", "789-abc")
   798  	runSleepingContainer(c, "--name", "789-123")
   799  
   800  	// Run multiple time should have the same result
   801  	out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz").Combined()
   802  	assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%s\n%s", container2, container1))
   803  
   804  	// Run multiple time should have the same result
   805  	out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz").Combined()
   806  	assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%s\n%s", container2, container1))
   807  }
   808  
   809  func (s *DockerSuite) TestPsListContainersFilterPorts(c *testing.T) {
   810  	testRequires(c, DaemonIsLinux)
   811  	existingContainers := ExistingContainerIDs(c)
   812  
   813  	out, _ := dockerCmd(c, "run", "-d", "--publish=80", "busybox", "top")
   814  	id1 := strings.TrimSpace(out)
   815  
   816  	out, _ = dockerCmd(c, "run", "-d", "--expose=8080", "busybox", "top")
   817  	id2 := strings.TrimSpace(out)
   818  
   819  	out, _ = dockerCmd(c, "run", "-d", "-p", "1090:90", "busybox", "top")
   820  	id3 := strings.TrimSpace(out)
   821  
   822  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q")
   823  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), id1))
   824  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), id2))
   825  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), id3))
   826  
   827  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-8080/udp")
   828  	assert.Assert(c, strings.TrimSpace(out) != id1)
   829  	assert.Assert(c, strings.TrimSpace(out) != id2)
   830  	assert.Assert(c, strings.TrimSpace(out) != id3)
   831  
   832  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8081")
   833  	assert.Assert(c, strings.TrimSpace(out) != id1)
   834  	assert.Assert(c, strings.TrimSpace(out) != id2)
   835  	assert.Assert(c, strings.TrimSpace(out) != id3)
   836  
   837  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-81")
   838  	assert.Assert(c, strings.TrimSpace(out) != id1)
   839  	assert.Assert(c, strings.TrimSpace(out) != id2)
   840  	assert.Assert(c, strings.TrimSpace(out) != id3)
   841  
   842  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=80/tcp")
   843  	assert.Equal(c, strings.TrimSpace(out), id1)
   844  	assert.Assert(c, strings.TrimSpace(out) != id2)
   845  	assert.Assert(c, strings.TrimSpace(out) != id3)
   846  
   847  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=1090")
   848  	assert.Assert(c, strings.TrimSpace(out) != id1)
   849  	assert.Assert(c, strings.TrimSpace(out) != id2)
   850  	assert.Equal(c, strings.TrimSpace(out), id3)
   851  
   852  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8080/tcp")
   853  	out = RemoveOutputForExistingElements(out, existingContainers)
   854  	assert.Assert(c, strings.TrimSpace(out) != id1)
   855  	assert.Equal(c, strings.TrimSpace(out), id2)
   856  	assert.Assert(c, strings.TrimSpace(out) != id3)
   857  }
   858  
   859  func (s *DockerSuite) TestPsNotShowLinknamesOfDeletedContainer(c *testing.T) {
   860  	testRequires(c, DaemonIsLinux, MinimumAPIVersion("1.31"))
   861  	existingContainers := ExistingContainerNames(c)
   862  
   863  	dockerCmd(c, "create", "--name=aaa", "busybox", "top")
   864  	dockerCmd(c, "create", "--name=bbb", "--link=aaa", "busybox", "top")
   865  
   866  	out, _ := dockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}")
   867  	lines := strings.Split(strings.TrimSpace(out), "\n")
   868  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   869  	expected := []string{"bbb", "aaa,bbb/aaa"}
   870  	var names []string
   871  	names = append(names, lines...)
   872  	assert.Assert(c, is.DeepEqual(names, expected), "Expected array with non-truncated names: %v, got: %v", expected, names)
   873  
   874  	dockerCmd(c, "rm", "bbb")
   875  
   876  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}")
   877  	out = RemoveOutputForExistingElements(out, existingContainers)
   878  	assert.Equal(c, strings.TrimSpace(out), "aaa")
   879  }