Browse code

Adding capability to filter by name, id or status to list containers api Closes #7599

Signed-off-by: Srini Brahmaroutu <srbrahma@us.ibm.com>

Srini Brahmaroutu authored on 2014/10/13 15:12:44
Showing 3 changed files
... ...
@@ -28,7 +28,6 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
28 28
 		size        = job.GetenvBool("size")
29 29
 		psFilters   filters.Args
30 30
 		filt_exited []int
31
-		filt_status []string
32 31
 	)
33 32
 	outs := engine.NewTable("Created", 0)
34 33
 
... ...
@@ -46,8 +45,6 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
46 46
 		}
47 47
 	}
48 48
 
49
-	filt_status, _ = psFilters["status"]
50
-
51 49
 	names := map[string][]string{}
52 50
 	daemon.ContainerGraph().Walk("/", func(p string, e *graphdb.Entity) error {
53 51
 		names[e.ID()] = append(names[e.ID()], p)
... ...
@@ -76,6 +73,15 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
76 76
 		if !container.Running && !all && n <= 0 && since == "" && before == "" {
77 77
 			return nil
78 78
 		}
79
+
80
+		if !psFilters.Match("name", container.Name) {
81
+			return nil
82
+		}
83
+
84
+		if !psFilters.Match("id", container.ID) {
85
+			return nil
86
+		}
87
+
79 88
 		if before != "" && !foundBefore {
80 89
 			if container.ID == beforeCont.ID {
81 90
 				foundBefore = true
... ...
@@ -102,10 +108,9 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
102 102
 				return nil
103 103
 			}
104 104
 		}
105
-		for _, status := range filt_status {
106
-			if container.State.StateString() != strings.ToLower(status) {
107
-				return nil
108
-			}
105
+
106
+		if !psFilters.Match("status", container.State.StateString()) {
107
+			return nil
109 108
 		}
110 109
 		displayed++
111 110
 		out := &engine.Env{}
... ...
@@ -336,3 +336,63 @@ func TestPsListContainersFilterStatus(t *testing.T) {
336 336
 
337 337
 	logDone("ps - test ps filter status")
338 338
 }
339
+
340
+func TestPsListContainersFilterID(t *testing.T) {
341
+	// start container
342
+	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox")
343
+	out, _, err := runCommandWithOutput(runCmd)
344
+	if err != nil {
345
+		t.Fatal(out, err)
346
+	}
347
+	firstID := stripTrailingCharacters(out)
348
+
349
+	// start another container
350
+	runCmd = exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", "sleep 360")
351
+	if out, _, err = runCommandWithOutput(runCmd); err != nil {
352
+		t.Fatal(out, err)
353
+	}
354
+
355
+	// filter containers by id
356
+	runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--filter=id="+firstID)
357
+	if out, _, err = runCommandWithOutput(runCmd); err != nil {
358
+		t.Fatal(out, err)
359
+	}
360
+	containerOut := strings.TrimSpace(out)
361
+	if containerOut != firstID[:12] {
362
+		t.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out)
363
+	}
364
+
365
+	deleteAllContainers()
366
+
367
+	logDone("ps - test ps filter id")
368
+}
369
+
370
+func TestPsListContainersFilterName(t *testing.T) {
371
+	// start container
372
+	runCmd := exec.Command(dockerBinary, "run", "-d", "--name=a_name_to_match", "busybox")
373
+	out, _, err := runCommandWithOutput(runCmd)
374
+	if err != nil {
375
+		t.Fatal(out, err)
376
+	}
377
+	firstID := stripTrailingCharacters(out)
378
+
379
+	// start another container
380
+	runCmd = exec.Command(dockerBinary, "run", "-d", "--name=b_name_to_match", "busybox", "sh", "-c", "sleep 360")
381
+	if out, _, err = runCommandWithOutput(runCmd); err != nil {
382
+		t.Fatal(out, err)
383
+	}
384
+
385
+	// filter containers by name
386
+	runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--filter=name=a_name_to_match")
387
+	if out, _, err = runCommandWithOutput(runCmd); err != nil {
388
+		t.Fatal(out, err)
389
+	}
390
+	containerOut := strings.TrimSpace(out)
391
+	if containerOut != firstID[:12] {
392
+		t.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out)
393
+	}
394
+
395
+	deleteAllContainers()
396
+
397
+	logDone("ps - test ps filter name")
398
+}
... ...
@@ -3,6 +3,7 @@ package filters
3 3
 import (
4 4
 	"encoding/json"
5 5
 	"errors"
6
+	"regexp"
6 7
 	"strings"
7 8
 )
8 9
 
... ...
@@ -61,3 +62,22 @@ func FromParam(p string) (Args, error) {
61 61
 	}
62 62
 	return args, nil
63 63
 }
64
+
65
+func (filters Args) Match(field, source string) bool {
66
+	fieldValues := filters[field]
67
+
68
+	//do not filter if there is no filter set or cannot determine filter
69
+	if len(fieldValues) == 0 {
70
+		return true
71
+	}
72
+	for _, name2match := range fieldValues {
73
+		match, err := regexp.MatchString(name2match, source)
74
+		if err != nil {
75
+			continue
76
+		}
77
+		if match {
78
+			return true
79
+		}
80
+	}
81
+	return false
82
+}