diff --git a/daemon/list.go b/daemon/list.go index 128d9eda9c..6d86cd3b48 100644 --- a/daemon/list.go +++ b/daemon/list.go @@ -3,6 +3,7 @@ package daemon import ( "errors" "fmt" + "sort" "strconv" "strings" @@ -86,6 +87,15 @@ type listContext struct { *types.ContainerListOptions } +// byContainerCreated is a temporary type used to sort a list of containers by creation time. +type byContainerCreated []*container.Container + +func (r byContainerCreated) Len() int { return len(r) } +func (r byContainerCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] } +func (r byContainerCreated) Less(i, j int) bool { + return r[i].Created.UnixNano() < r[j].Created.UnixNano() +} + // Containers returns the list of containers to show given the user's filtering. func (daemon *Daemon) Containers(config *types.ContainerListOptions) ([]*types.Container, error) { return daemon.reduceContainers(config, daemon.transformContainer) @@ -149,6 +159,11 @@ func (daemon *Daemon) filterByNameIDMatches(ctx *listContext) []*container.Conta for id := range matches { cntrs = append(cntrs, daemon.containers.Get(id)) } + + // Restore sort-order after filtering + // Created gives us nanosec resolution for sorting + sort.Sort(sort.Reverse(byContainerCreated(cntrs))) + return cntrs } diff --git a/integration-cli/docker_cli_ps_test.go b/integration-cli/docker_cli_ps_test.go index a4ee9a9f65..6e1756f06f 100644 --- a/integration-cli/docker_cli_ps_test.go +++ b/integration-cli/docker_cli_ps_test.go @@ -864,3 +864,37 @@ func (s *DockerSuite) TestPsListContainersFilterNetwork(c *check.C) { c.Assert(containerOut, checker.Contains, "onbridgenetwork") } + +func (s *DockerSuite) TestPsByOrder(c *check.C) { + name1 := "xyz-abc" + out, err := runSleepingContainer(c, "--name", name1) + c.Assert(err, checker.NotNil) + c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") + container1 := strings.TrimSpace(out) + + name2 := "xyz-123" + out, err = runSleepingContainer(c, "--name", name2) + c.Assert(err, checker.NotNil) + c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") + container2 := strings.TrimSpace(out) + + name3 := "789-abc" + out, err = runSleepingContainer(c, "--name", name3) + c.Assert(err, checker.NotNil) + c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") + + name4 := "789-123" + out, err = runSleepingContainer(c, "--name", name4) + c.Assert(err, checker.NotNil) + c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") + + // Run multiple time should have the same result + out, err = dockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz") + c.Assert(err, checker.NotNil) + c.Assert(strings.TrimSpace(out), checker.Equals, fmt.Sprintf("%s\n%s", container2, container1)) + + // Run multiple time should have the same result + out, err = dockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz") + c.Assert(err, checker.NotNil) + c.Assert(strings.TrimSpace(out), checker.Equals, fmt.Sprintf("%s\n%s", container2, container1)) +}