Browse code

docker ps: introducing filters

* starting with filtering for exit codes. `docker ps -a --filter 'exited=1'`
* API doc for filter parameter
* formatting filters for help usage
* tweaks for review

This requires https://github.com/dotcloud/docker/pull/4430

Docker-DCO-1.1-Signed-off-by: Vincent Batts <vbatts@redhat.com> (github: vbatts)

Vincent Batts authored on 2014/06/03 04:08:39
Showing 5 changed files
... ...
@@ -1487,6 +1487,9 @@ func (cli *DockerCli) CmdPs(args ...string) error {
1487 1487
 	before := cmd.String([]string{"#beforeId", "#-before-id", "-before"}, "", "Show only container created before Id or Name, include non-running ones.")
1488 1488
 	last := cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
1489 1489
 
1490
+	var flFilter opts.ListOpts
1491
+	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited=<int> - containers with exit code of <int>")
1492
+
1490 1493
 	if err := cmd.Parse(args); err != nil {
1491 1494
 		return nil
1492 1495
 	}
... ...
@@ -1510,6 +1513,24 @@ func (cli *DockerCli) CmdPs(args ...string) error {
1510 1510
 		v.Set("size", "1")
1511 1511
 	}
1512 1512
 
1513
+	// Consolidate all filter flags, and sanity check them.
1514
+	// They'll get processed in the daemon/server.
1515
+	psFilterArgs := filters.Args{}
1516
+	for _, f := range flFilter.GetAll() {
1517
+		var err error
1518
+		psFilterArgs, err = filters.ParseFlag(f, psFilterArgs)
1519
+		if err != nil {
1520
+			return err
1521
+		}
1522
+	}
1523
+	if len(psFilterArgs) > 0 {
1524
+		filterJson, err := filters.ToParam(psFilterArgs)
1525
+		if err != nil {
1526
+			return err
1527
+		}
1528
+		v.Set("filters", filterJson)
1529
+	}
1530
+
1513 1531
 	body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, false))
1514 1532
 	if err != nil {
1515 1533
 		return err
... ...
@@ -339,6 +339,7 @@ func getContainersJSON(eng *engine.Engine, version version.Version, w http.Respo
339 339
 	job.Setenv("since", r.Form.Get("since"))
340 340
 	job.Setenv("before", r.Form.Get("before"))
341 341
 	job.Setenv("limit", r.Form.Get("limit"))
342
+	job.Setenv("filters", r.Form.Get("filters"))
342 343
 
343 344
 	if version.GreaterThanOrEqualTo("1.5") {
344 345
 		streamJSON(job, w, false)
... ...
@@ -3,11 +3,13 @@ package daemon
3 3
 import (
4 4
 	"errors"
5 5
 	"fmt"
6
+	"strconv"
6 7
 	"strings"
7 8
 
8 9
 	"github.com/docker/docker/pkg/graphdb"
9 10
 
10 11
 	"github.com/docker/docker/engine"
12
+	"github.com/docker/docker/pkg/parsers/filters"
11 13
 )
12 14
 
13 15
 // List returns an array of all containers registered in the daemon.
... ...
@@ -24,9 +26,25 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
24 24
 		before      = job.Getenv("before")
25 25
 		n           = job.GetenvInt("limit")
26 26
 		size        = job.GetenvBool("size")
27
+		psFilters   filters.Args
28
+		filt_exited []int
27 29
 	)
28 30
 	outs := engine.NewTable("Created", 0)
29 31
 
32
+	psFilters, err := filters.FromParam(job.Getenv("filters"))
33
+	if err != nil {
34
+		return job.Error(err)
35
+	}
36
+	if i, ok := psFilters["exited"]; ok {
37
+		for _, value := range i {
38
+			code, err := strconv.Atoi(value)
39
+			if err != nil {
40
+				return job.Error(err)
41
+			}
42
+			filt_exited = append(filt_exited, code)
43
+		}
44
+	}
45
+
30 46
 	names := map[string][]string{}
31 47
 	daemon.ContainerGraph().Walk("/", func(p string, e *graphdb.Entity) error {
32 48
 		names[e.ID()] = append(names[e.ID()], p)
... ...
@@ -69,6 +87,18 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
69 69
 				return errLast
70 70
 			}
71 71
 		}
72
+		if len(filt_exited) > 0 && !container.State.IsRunning() {
73
+			should_skip := true
74
+			for _, code := range filt_exited {
75
+				if code == container.State.GetExitCode() {
76
+					should_skip = false
77
+					break
78
+				}
79
+			}
80
+			if should_skip {
81
+				return nil
82
+			}
83
+		}
72 84
 		displayed++
73 85
 		out := &engine.Env{}
74 86
 		out.Set("Id", container.ID)
... ...
@@ -90,6 +90,8 @@ List containers
90 90
         non-running ones.
91 91
     -   **size** – 1/True/true or 0/False/false, Show the containers
92 92
         sizes
93
+    -   **filters** – a JSON encoded value of the filters (a map[string][]string)
94
+        to process on the images list.
93 95
 
94 96
     Status Codes:
95 97
 
... ...
@@ -759,7 +761,7 @@ Copy files or folders of container `id`
759 759
      
760 760
 
761 761
     -   **all** – 1/True/true or 0/False/false, default false
762
-    -   **filters** – a json encoded value of the filters (a map[string][]string) to process on the images list.
762
+    -   **filters** – a JSON encoded value of the filters (a map[string][]string) to process on the images list.
763 763
 
764 764
 
765 765
 
... ...
@@ -794,6 +794,7 @@ further details.
794 794
 
795 795
       -a, --all=false       Show all containers. Only running containers are shown by default.
796 796
       --before=""           Show only container created before Id or Name, include non-running ones.
797
+      -f, --filter=[]       Provide filter values (i.e. 'exited=0')
797 798
       -l, --latest=false    Show only the latest created container, include non-running ones.
798 799
       -n=-1                 Show n last created containers, include non-running ones.
799 800
       --no-trunc=false      Don't truncate output
... ...
@@ -811,6 +812,25 @@ Running `docker ps` showing 2 linked containers.
811 811
 `docker ps` will show only running containers by default. To see all containers:
812 812
 `docker ps -a`
813 813
 
814
+### Filtering
815
+
816
+The filtering flag (-f or --filter) format is a "key=value" pair. If there is more
817
+than one filter, then pass multiple flags (e.g. `--filter "foo=bar" --filter "bif=baz"`)
818
+
819
+Current filters:
820
+ * exited (int - the code of exited containers. Only useful with '--all')
821
+
822
+
823
+#### Successfully exited containers
824
+
825
+    $ sudo docker ps -a --filter 'exited=0'
826
+    CONTAINER ID        IMAGE             COMMAND                CREATED             STATUS                   PORTS                      NAMES
827
+    ea09c3c82f6e        registry:latest   /srv/run.sh            2 weeks ago         Exited (0) 2 weeks ago   127.0.0.1:5000->5000/tcp   desperate_leakey       
828
+    106ea823fe4e        fedora:latest     /bin/sh -c 'bash -l'   2 weeks ago         Exited (0) 2 weeks ago                              determined_albattani   
829
+    48ee228c9464        fedora:20         bash                   2 weeks ago         Exited (0) 2 weeks ago                              tender_torvalds
830
+
831
+This shows all the containers that have exited with status of '0'
832
+
814 833
 ## pull
815 834
 
816 835
     Usage: docker pull NAME[:TAG]