github.com/lacework-dev/go-moby@v20.10.12+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", "6000:5000", "busybox", "top")
   598  	assert.Assert(c, waitRun("foo") == nil)
   599  	ports, _ := dockerCmd(c, "ps", "--format", "{{ .Ports }}", "--filter", "name=foo")
   600  	expected := ":6000->5000/tcp"
   601  	assert.Assert(c, is.Contains(ports, expected), "Expected: %v, got: %v", expected, ports)
   602  
   603  	dockerCmd(c, "kill", "foo")
   604  	dockerCmd(c, "wait", "foo")
   605  	ports, _ = dockerCmd(c, "ps", "--format", "{{ .Ports }}", "--filter", "name=foo")
   606  	assert.Equal(c, ports, "", "Should not got %v", expected)
   607  }
   608  
   609  func (s *DockerSuite) TestPsShowMounts(c *testing.T) {
   610  	existingContainers := ExistingContainerNames(c)
   611  
   612  	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
   613  
   614  	mp := prefix + slash + "test"
   615  
   616  	dockerCmd(c, "volume", "create", "ps-volume-test")
   617  	// volume mount containers
   618  	runSleepingContainer(c, "--name=volume-test-1", "--volume", "ps-volume-test:"+mp)
   619  	assert.Assert(c, waitRun("volume-test-1") == nil)
   620  	runSleepingContainer(c, "--name=volume-test-2", "--volume", mp)
   621  	assert.Assert(c, waitRun("volume-test-2") == nil)
   622  	// bind mount container
   623  	var bindMountSource string
   624  	var bindMountDestination string
   625  	if DaemonIsWindows() {
   626  		bindMountSource = "c:\\"
   627  		bindMountDestination = "c:\\t"
   628  	} else {
   629  		bindMountSource = "/tmp"
   630  		bindMountDestination = "/t"
   631  	}
   632  	runSleepingContainer(c, "--name=bind-mount-test", "-v", bindMountSource+":"+bindMountDestination)
   633  	assert.Assert(c, waitRun("bind-mount-test") == nil)
   634  
   635  	out, _ := dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}")
   636  
   637  	lines := strings.Split(strings.TrimSpace(out), "\n")
   638  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   639  	assert.Equal(c, len(lines), 3)
   640  
   641  	fields := strings.Fields(lines[0])
   642  	assert.Equal(c, len(fields), 2)
   643  	assert.Equal(c, fields[0], "bind-mount-test")
   644  	assert.Equal(c, fields[1], bindMountSource)
   645  
   646  	fields = strings.Fields(lines[1])
   647  	assert.Equal(c, len(fields), 2)
   648  
   649  	anonymousVolumeID := fields[1]
   650  
   651  	fields = strings.Fields(lines[2])
   652  	assert.Equal(c, fields[1], "ps-volume-test")
   653  
   654  	// filter by volume name
   655  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=ps-volume-test")
   656  
   657  	lines = strings.Split(strings.TrimSpace(out), "\n")
   658  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   659  	assert.Equal(c, len(lines), 1)
   660  
   661  	fields = strings.Fields(lines[0])
   662  	assert.Equal(c, fields[1], "ps-volume-test")
   663  
   664  	// empty results filtering by unknown volume
   665  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=this-volume-should-not-exist")
   666  	assert.Equal(c, len(strings.TrimSpace(out)), 0)
   667  
   668  	// filter by mount destination
   669  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+mp)
   670  
   671  	lines = strings.Split(strings.TrimSpace(out), "\n")
   672  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   673  	assert.Equal(c, len(lines), 2)
   674  
   675  	fields = strings.Fields(lines[0])
   676  	assert.Equal(c, fields[1], anonymousVolumeID)
   677  	fields = strings.Fields(lines[1])
   678  	assert.Equal(c, fields[1], "ps-volume-test")
   679  
   680  	// filter by bind mount source
   681  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountSource)
   682  
   683  	lines = strings.Split(strings.TrimSpace(out), "\n")
   684  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   685  	assert.Equal(c, len(lines), 1)
   686  
   687  	fields = strings.Fields(lines[0])
   688  	assert.Equal(c, len(fields), 2)
   689  	assert.Equal(c, fields[0], "bind-mount-test")
   690  	assert.Equal(c, fields[1], bindMountSource)
   691  
   692  	// filter by bind mount destination
   693  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountDestination)
   694  
   695  	lines = strings.Split(strings.TrimSpace(out), "\n")
   696  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   697  	assert.Equal(c, len(lines), 1)
   698  
   699  	fields = strings.Fields(lines[0])
   700  	assert.Equal(c, len(fields), 2)
   701  	assert.Equal(c, fields[0], "bind-mount-test")
   702  	assert.Equal(c, fields[1], bindMountSource)
   703  
   704  	// empty results filtering by unknown mount point
   705  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+prefix+slash+"this-path-was-never-mounted")
   706  	assert.Equal(c, len(strings.TrimSpace(out)), 0)
   707  }
   708  
   709  func (s *DockerSuite) TestPsListContainersFilterNetwork(c *testing.T) {
   710  	existing := ExistingContainerIDs(c)
   711  
   712  	// TODO default network on Windows is not called "bridge", and creating a
   713  	// custom network fails on Windows fails with "Error response from daemon: plugin not found")
   714  	testRequires(c, DaemonIsLinux)
   715  
   716  	// create some containers
   717  	runSleepingContainer(c, "--net=bridge", "--name=onbridgenetwork")
   718  	runSleepingContainer(c, "--net=none", "--name=onnonenetwork")
   719  
   720  	// Filter docker ps on non existing network
   721  	out, _ := dockerCmd(c, "ps", "--filter", "network=doesnotexist")
   722  	containerOut := strings.TrimSpace(out)
   723  	lines := strings.Split(containerOut, "\n")
   724  
   725  	// skip header
   726  	lines = lines[1:]
   727  
   728  	// ps output should have no containers
   729  	assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 0)
   730  
   731  	// Filter docker ps on network bridge
   732  	out, _ = dockerCmd(c, "ps", "--filter", "network=bridge")
   733  	containerOut = strings.TrimSpace(out)
   734  
   735  	lines = strings.Split(containerOut, "\n")
   736  
   737  	// skip header
   738  	lines = lines[1:]
   739  
   740  	// ps output should have only one container
   741  	assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 1)
   742  
   743  	// Making sure onbridgenetwork is on the output
   744  	assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on network\n")
   745  	// Filter docker ps on networks bridge and none
   746  	out, _ = dockerCmd(c, "ps", "--filter", "network=bridge", "--filter", "network=none")
   747  	containerOut = strings.TrimSpace(out)
   748  
   749  	lines = strings.Split(containerOut, "\n")
   750  
   751  	// skip header
   752  	lines = lines[1:]
   753  
   754  	// ps output should have both the containers
   755  	assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 2)
   756  
   757  	// Making sure onbridgenetwork and onnonenetwork is on the output
   758  	assert.Assert(c, strings.Contains(containerOut, "onnonenetwork"), "Missing the container on none network\n")
   759  	assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on bridge network\n")
   760  	nwID, _ := dockerCmd(c, "network", "inspect", "--format", "{{.ID}}", "bridge")
   761  
   762  	// Filter by network ID
   763  	out, _ = dockerCmd(c, "ps", "--filter", "network="+nwID)
   764  	containerOut = strings.TrimSpace(out)
   765  
   766  	assert.Assert(c, is.Contains(containerOut, "onbridgenetwork"))
   767  
   768  	// Filter by partial network ID
   769  	partialnwID := nwID[0:4]
   770  
   771  	out, _ = dockerCmd(c, "ps", "--filter", "network="+partialnwID)
   772  	containerOut = strings.TrimSpace(out)
   773  
   774  	lines = strings.Split(containerOut, "\n")
   775  
   776  	// skip header
   777  	lines = lines[1:]
   778  
   779  	// ps output should have only one container
   780  	assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 1)
   781  
   782  	// Making sure onbridgenetwork is on the output
   783  	assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on network\n")
   784  }
   785  
   786  func (s *DockerSuite) TestPsByOrder(c *testing.T) {
   787  	out := runSleepingContainer(c, "--name", "xyz-abc")
   788  	container1 := strings.TrimSpace(out)
   789  
   790  	out = runSleepingContainer(c, "--name", "xyz-123")
   791  	container2 := strings.TrimSpace(out)
   792  
   793  	runSleepingContainer(c, "--name", "789-abc")
   794  	runSleepingContainer(c, "--name", "789-123")
   795  
   796  	// Run multiple time should have the same result
   797  	out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz").Combined()
   798  	assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%s\n%s", container2, container1))
   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  
   805  func (s *DockerSuite) TestPsListContainersFilterPorts(c *testing.T) {
   806  	testRequires(c, DaemonIsLinux)
   807  	existingContainers := ExistingContainerIDs(c)
   808  
   809  	out, _ := dockerCmd(c, "run", "-d", "--publish=80", "busybox", "top")
   810  	id1 := strings.TrimSpace(out)
   811  
   812  	out, _ = dockerCmd(c, "run", "-d", "--expose=8080", "busybox", "top")
   813  	id2 := strings.TrimSpace(out)
   814  
   815  	out, _ = dockerCmd(c, "run", "-d", "-p", "1090:90", "busybox", "top")
   816  	id3 := strings.TrimSpace(out)
   817  
   818  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q")
   819  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), id1))
   820  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), id2))
   821  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), id3))
   822  
   823  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-8080/udp")
   824  	assert.Assert(c, strings.TrimSpace(out) != id1)
   825  	assert.Assert(c, strings.TrimSpace(out) != id2)
   826  	assert.Assert(c, strings.TrimSpace(out) != id3)
   827  
   828  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8081")
   829  	assert.Assert(c, strings.TrimSpace(out) != id1)
   830  	assert.Assert(c, strings.TrimSpace(out) != id2)
   831  	assert.Assert(c, strings.TrimSpace(out) != id3)
   832  
   833  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-81")
   834  	assert.Assert(c, strings.TrimSpace(out) != id1)
   835  	assert.Assert(c, strings.TrimSpace(out) != id2)
   836  	assert.Assert(c, strings.TrimSpace(out) != id3)
   837  
   838  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=80/tcp")
   839  	assert.Equal(c, strings.TrimSpace(out), id1)
   840  	assert.Assert(c, strings.TrimSpace(out) != id2)
   841  	assert.Assert(c, strings.TrimSpace(out) != id3)
   842  
   843  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=1090")
   844  	assert.Assert(c, strings.TrimSpace(out) != id1)
   845  	assert.Assert(c, strings.TrimSpace(out) != id2)
   846  	assert.Equal(c, strings.TrimSpace(out), id3)
   847  
   848  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8080/tcp")
   849  	out = RemoveOutputForExistingElements(out, existingContainers)
   850  	assert.Assert(c, strings.TrimSpace(out) != id1)
   851  	assert.Equal(c, strings.TrimSpace(out), id2)
   852  	assert.Assert(c, strings.TrimSpace(out) != id3)
   853  }
   854  
   855  func (s *DockerSuite) TestPsNotShowLinknamesOfDeletedContainer(c *testing.T) {
   856  	testRequires(c, DaemonIsLinux, MinimumAPIVersion("1.31"))
   857  	existingContainers := ExistingContainerNames(c)
   858  
   859  	dockerCmd(c, "create", "--name=aaa", "busybox", "top")
   860  	dockerCmd(c, "create", "--name=bbb", "--link=aaa", "busybox", "top")
   861  
   862  	out, _ := dockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}")
   863  	lines := strings.Split(strings.TrimSpace(out), "\n")
   864  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   865  	expected := []string{"bbb", "aaa,bbb/aaa"}
   866  	var names []string
   867  	names = append(names, lines...)
   868  	assert.Assert(c, is.DeepEqual(names, expected), "Expected array with non-truncated names: %v, got: %v", expected, names)
   869  
   870  	dockerCmd(c, "rm", "bbb")
   871  
   872  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}")
   873  	out = RemoveOutputForExistingElements(out, existingContainers)
   874  	assert.Equal(c, strings.TrimSpace(out), "aaa")
   875  }