From 16346253537267b42bbf35e81c0139b4d0aee43c Mon Sep 17 00:00:00 2001 From: Srini Brahmaroutu Date: Mon, 13 Oct 2014 06:12:44 +0000 Subject: [PATCH] Adding capability to filter by name, id or status to list containers api Closes #7599 Signed-off-by: Srini Brahmaroutu --- daemon/list.go | 19 +++++---- integration-cli/docker_cli_ps_test.go | 60 +++++++++++++++++++++++++++ pkg/parsers/filters/parse.go | 20 +++++++++ 3 files changed, 92 insertions(+), 7 deletions(-) diff --git a/daemon/list.go b/daemon/list.go index 35effa4344..347d3c20d8 100644 --- a/daemon/list.go +++ b/daemon/list.go @@ -28,7 +28,6 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status { size = job.GetenvBool("size") psFilters filters.Args filt_exited []int - filt_status []string ) outs := engine.NewTable("Created", 0) @@ -46,8 +45,6 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status { } } - filt_status, _ = psFilters["status"] - names := map[string][]string{} daemon.ContainerGraph().Walk("/", func(p string, e *graphdb.Entity) error { names[e.ID()] = append(names[e.ID()], p) @@ -76,6 +73,15 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status { if !container.Running && !all && n <= 0 && since == "" && before == "" { return nil } + + if !psFilters.Match("name", container.Name) { + return nil + } + + if !psFilters.Match("id", container.ID) { + return nil + } + if before != "" && !foundBefore { if container.ID == beforeCont.ID { foundBefore = true @@ -102,10 +108,9 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status { return nil } } - for _, status := range filt_status { - if container.State.StateString() != strings.ToLower(status) { - return nil - } + + if !psFilters.Match("status", container.State.StateString()) { + return nil } displayed++ out := &engine.Env{} diff --git a/integration-cli/docker_cli_ps_test.go b/integration-cli/docker_cli_ps_test.go index 8be4dfb16f..3874fa70b5 100644 --- a/integration-cli/docker_cli_ps_test.go +++ b/integration-cli/docker_cli_ps_test.go @@ -336,3 +336,63 @@ func TestPsListContainersFilterStatus(t *testing.T) { logDone("ps - test ps filter status") } + +func TestPsListContainersFilterID(t *testing.T) { + // start container + runCmd := exec.Command(dockerBinary, "run", "-d", "busybox") + out, _, err := runCommandWithOutput(runCmd) + if err != nil { + t.Fatal(out, err) + } + firstID := stripTrailingCharacters(out) + + // start another container + runCmd = exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", "sleep 360") + if out, _, err = runCommandWithOutput(runCmd); err != nil { + t.Fatal(out, err) + } + + // filter containers by id + runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--filter=id="+firstID) + if out, _, err = runCommandWithOutput(runCmd); err != nil { + t.Fatal(out, err) + } + containerOut := strings.TrimSpace(out) + if containerOut != firstID[:12] { + t.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out) + } + + deleteAllContainers() + + logDone("ps - test ps filter id") +} + +func TestPsListContainersFilterName(t *testing.T) { + // start container + runCmd := exec.Command(dockerBinary, "run", "-d", "--name=a_name_to_match", "busybox") + out, _, err := runCommandWithOutput(runCmd) + if err != nil { + t.Fatal(out, err) + } + firstID := stripTrailingCharacters(out) + + // start another container + runCmd = exec.Command(dockerBinary, "run", "-d", "--name=b_name_to_match", "busybox", "sh", "-c", "sleep 360") + if out, _, err = runCommandWithOutput(runCmd); err != nil { + t.Fatal(out, err) + } + + // filter containers by name + runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--filter=name=a_name_to_match") + if out, _, err = runCommandWithOutput(runCmd); err != nil { + t.Fatal(out, err) + } + containerOut := strings.TrimSpace(out) + if containerOut != firstID[:12] { + t.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out) + } + + deleteAllContainers() + + logDone("ps - test ps filter name") +} diff --git a/pkg/parsers/filters/parse.go b/pkg/parsers/filters/parse.go index 27c7132e8e..403959223c 100644 --- a/pkg/parsers/filters/parse.go +++ b/pkg/parsers/filters/parse.go @@ -3,6 +3,7 @@ package filters import ( "encoding/json" "errors" + "regexp" "strings" ) @@ -61,3 +62,22 @@ func FromParam(p string) (Args, error) { } return args, nil } + +func (filters Args) Match(field, source string) bool { + fieldValues := filters[field] + + //do not filter if there is no filter set or cannot determine filter + if len(fieldValues) == 0 { + return true + } + for _, name2match := range fieldValues { + match, err := regexp.MatchString(name2match, source) + if err != nil { + continue + } + if match { + return true + } + } + return false +}