diff --git a/api/client/commands.go b/api/client/commands.go index ee52d98946..1d6ff1668e 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1487,6 +1487,9 @@ func (cli *DockerCli) CmdPs(args ...string) error { before := cmd.String([]string{"#beforeId", "#-before-id", "-before"}, "", "Show only container created before Id or Name, include non-running ones.") last := cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.") + var flFilter opts.ListOpts + cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited= - containers with exit code of ") + if err := cmd.Parse(args); err != nil { return nil } @@ -1510,6 +1513,24 @@ func (cli *DockerCli) CmdPs(args ...string) error { v.Set("size", "1") } + // Consolidate all filter flags, and sanity check them. + // They'll get processed in the daemon/server. + psFilterArgs := filters.Args{} + for _, f := range flFilter.GetAll() { + var err error + psFilterArgs, err = filters.ParseFlag(f, psFilterArgs) + if err != nil { + return err + } + } + if len(psFilterArgs) > 0 { + filterJson, err := filters.ToParam(psFilterArgs) + if err != nil { + return err + } + v.Set("filters", filterJson) + } + body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, false)) if err != nil { return err diff --git a/api/server/server.go b/api/server/server.go index ae73660b6b..10e5090ce0 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -339,6 +339,7 @@ func getContainersJSON(eng *engine.Engine, version version.Version, w http.Respo job.Setenv("since", r.Form.Get("since")) job.Setenv("before", r.Form.Get("before")) job.Setenv("limit", r.Form.Get("limit")) + job.Setenv("filters", r.Form.Get("filters")) if version.GreaterThanOrEqualTo("1.5") { streamJSON(job, w, false) diff --git a/daemon/list.go b/daemon/list.go index e3749346f4..2da5254866 100644 --- a/daemon/list.go +++ b/daemon/list.go @@ -3,11 +3,13 @@ package daemon import ( "errors" "fmt" + "strconv" "strings" "github.com/docker/docker/pkg/graphdb" "github.com/docker/docker/engine" + "github.com/docker/docker/pkg/parsers/filters" ) // List returns an array of all containers registered in the daemon. @@ -24,9 +26,25 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status { before = job.Getenv("before") n = job.GetenvInt("limit") size = job.GetenvBool("size") + psFilters filters.Args + filt_exited []int ) outs := engine.NewTable("Created", 0) + psFilters, err := filters.FromParam(job.Getenv("filters")) + if err != nil { + return job.Error(err) + } + if i, ok := psFilters["exited"]; ok { + for _, value := range i { + code, err := strconv.Atoi(value) + if err != nil { + return job.Error(err) + } + filt_exited = append(filt_exited, code) + } + } + names := map[string][]string{} daemon.ContainerGraph().Walk("/", func(p string, e *graphdb.Entity) error { names[e.ID()] = append(names[e.ID()], p) @@ -69,6 +87,18 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status { return errLast } } + if len(filt_exited) > 0 && !container.State.IsRunning() { + should_skip := true + for _, code := range filt_exited { + if code == container.State.GetExitCode() { + should_skip = false + break + } + } + if should_skip { + return nil + } + } displayed++ out := &engine.Env{} out.Set("Id", container.ID) diff --git a/docs/sources/reference/api/docker_remote_api_v1.12.md b/docs/sources/reference/api/docker_remote_api_v1.12.md index 54e57d2916..9ea83e2853 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.12.md +++ b/docs/sources/reference/api/docker_remote_api_v1.12.md @@ -90,6 +90,8 @@ List containers non-running ones. - **size** – 1/True/true or 0/False/false, Show the containers sizes + - **filters** – a JSON encoded value of the filters (a map[string][]string) + to process on the images list. Status Codes: @@ -759,7 +761,7 @@ Copy files or folders of container `id`   - **all** – 1/True/true or 0/False/false, default false - - **filters** – a json encoded value of the filters (a map[string][]string) to process on the images list. + - **filters** – a JSON encoded value of the filters (a map[string][]string) to process on the images list. diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 9d5a950220..311fc849e9 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -794,6 +794,7 @@ further details. -a, --all=false Show all containers. Only running containers are shown by default. --before="" Show only container created before Id or Name, include non-running ones. + -f, --filter=[] Provide filter values (i.e. 'exited=0') -l, --latest=false Show only the latest created container, include non-running ones. -n=-1 Show n last created containers, include non-running ones. --no-trunc=false Don't truncate output @@ -811,6 +812,25 @@ Running `docker ps` showing 2 linked containers. `docker ps` will show only running containers by default. To see all containers: `docker ps -a` +### Filtering + +The filtering flag (-f or --filter) format is a "key=value" pair. If there is more +than one filter, then pass multiple flags (e.g. `--filter "foo=bar" --filter "bif=baz"`) + +Current filters: + * exited (int - the code of exited containers. Only useful with '--all') + + +#### Successfully exited containers + + $ sudo docker ps -a --filter 'exited=0' + CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES + ea09c3c82f6e registry:latest /srv/run.sh 2 weeks ago Exited (0) 2 weeks ago 127.0.0.1:5000->5000/tcp desperate_leakey + 106ea823fe4e fedora:latest /bin/sh -c 'bash -l' 2 weeks ago Exited (0) 2 weeks ago determined_albattani + 48ee228c9464 fedora:20 bash 2 weeks ago Exited (0) 2 weeks ago tender_torvalds + +This shows all the containers that have exited with status of '0' + ## pull Usage: docker pull NAME[:TAG]