Sort output of `docker ps --filter` with order by creation time

This fix tries to address the issue raised in 25374 where the
output of `docker ps --filter` is in random order and
not deterministic.

This fix sorts the list of containers by creation time so that the
output is deterministic.

An integration test has been added.

This fix fixes 25374.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
Yong Tang 2016-08-03 19:02:39 -07:00
parent 9513aa3a48
commit 3f97133546
2 changed files with 49 additions and 0 deletions

View File

@ -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
}

View File

@ -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))
}