A continuation of #7616.
Adds `docker ps --filter=status=(restarting|running|paused|stopped)` option.
Docker-DCO-1.1-Signed-off-by: Jessica Frazelle <jess@docker.com> (github: jfrazelle)
| ... | ... |
@@ -1485,7 +1485,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
| 1485 | 1485 |
last := cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
|
| 1486 | 1486 |
|
| 1487 | 1487 |
flFilter := opts.NewListOpts(nil) |
| 1488 |
- cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited=<int> - containers with exit code of <int>")
|
|
| 1488 |
+ cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited=<int> - containers with exit code of <int>\nstatus=(restarting|running|paused|exited)")
|
|
| 1489 | 1489 |
|
| 1490 | 1490 |
if err := cmd.Parse(args); err != nil {
|
| 1491 | 1491 |
return nil |
| ... | ... |
@@ -28,6 +28,7 @@ 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 |
|
| 31 | 32 |
) |
| 32 | 33 |
outs := engine.NewTable("Created", 0)
|
| 33 | 34 |
|
| ... | ... |
@@ -45,6 +46,8 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
|
| 45 | 45 |
} |
| 46 | 46 |
} |
| 47 | 47 |
|
| 48 |
+ filt_status, _ = psFilters["status"] |
|
| 49 |
+ |
|
| 48 | 50 |
names := map[string][]string{}
|
| 49 | 51 |
daemon.ContainerGraph().Walk("/", func(p string, e *graphdb.Entity) error {
|
| 50 | 52 |
names[e.ID()] = append(names[e.ID()], p) |
| ... | ... |
@@ -99,6 +102,11 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
|
| 99 | 99 |
return nil |
| 100 | 100 |
} |
| 101 | 101 |
} |
| 102 |
+ for _, status := range filt_status {
|
|
| 103 |
+ if container.State.StateString() != strings.ToLower(status) {
|
|
| 104 |
+ return nil |
|
| 105 |
+ } |
|
| 106 |
+ } |
|
| 102 | 107 |
displayed++ |
| 103 | 108 |
out := &engine.Env{}
|
| 104 | 109 |
out.Set("Id", container.ID)
|
| ... | ... |
@@ -46,6 +46,20 @@ func (s *State) String() string {
|
| 46 | 46 |
return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
|
| 47 | 47 |
} |
| 48 | 48 |
|
| 49 |
+// StateString returns a single string to describe state |
|
| 50 |
+func (s *State) StateString() string {
|
|
| 51 |
+ if s.Running {
|
|
| 52 |
+ if s.Paused {
|
|
| 53 |
+ return "paused" |
|
| 54 |
+ } |
|
| 55 |
+ if s.Restarting {
|
|
| 56 |
+ return "restarting" |
|
| 57 |
+ } |
|
| 58 |
+ return "running" |
|
| 59 |
+ } |
|
| 60 |
+ return "exited" |
|
| 61 |
+} |
|
| 62 |
+ |
|
| 49 | 63 |
func wait(waitChan <-chan struct{}, timeout time.Duration) error {
|
| 50 | 64 |
if timeout < 0 {
|
| 51 | 65 |
<-waitChan |
| ... | ... |
@@ -241,14 +241,15 @@ as the root. Wildcards are allowed but the search is not recursive. |
| 241 | 241 |
temp? |
| 242 | 242 |
|
| 243 | 243 |
The first line above `*/temp*`, would ignore all files with names starting with |
| 244 |
-`temp` from any subdirectory below the root directory, for example file named |
|
| 245 |
-`/somedir/temporary.txt` will be ignored. The second line `*/*/temp*`, will |
|
| 244 |
+`temp` from any subdirectory below the root directory. For example, a file named |
|
| 245 |
+`/somedir/temporary.txt` would be ignored. The second line `*/*/temp*`, will |
|
| 246 | 246 |
ignore files starting with name `temp` from any subdirectory that is two levels |
| 247 |
-below the root directory, for example a file `/somedir/subdir/temporary.txt` is |
|
| 248 |
-ignored in this case. The last line in the above example `temp?`, will ignore |
|
| 249 |
-the files that match the pattern from the root directory, for example files |
|
| 250 |
-`tempa`, `tempb` are ignored from the root directory. Currently there is no |
|
| 251 |
-support for regular expressions, formats like `[^temp*]` are ignored. |
|
| 247 |
+below the root directory. For example, the file `/somedir/subdir/temporary.txt` |
|
| 248 |
+would get ignored in this case. The last line in the above example `temp?` |
|
| 249 |
+will ignore the files that match the pattern from the root directory. |
|
| 250 |
+For example, the files `tempa`, `tempb` are ignored from the root directory. |
|
| 251 |
+Currently there is no support for regular expressions. Formats |
|
| 252 |
+like `[^temp*]` are ignored. |
|
| 252 | 253 |
|
| 253 | 254 |
|
| 254 | 255 |
See also: |
| ... | ... |
@@ -943,6 +944,7 @@ further details. |
| 943 | 943 |
--before="" Show only container created before Id or Name, include non-running ones. |
| 944 | 944 |
-f, --filter=[] Provide filter values. Valid filters: |
| 945 | 945 |
exited=<int> - containers with exit code of <int> |
| 946 |
+ status=(restarting|running|paused|exited) |
|
| 946 | 947 |
-l, --latest=false Show only the latest created container, include non-running ones. |
| 947 | 948 |
-n=-1 Show n last created containers, include non-running ones. |
| 948 | 949 |
--no-trunc=false Don't truncate output |
| ... | ... |
@@ -235,4 +235,50 @@ func TestPsListContainersSize(t *testing.T) {
|
| 235 | 235 |
if foundSize != expectedSize {
|
| 236 | 236 |
t.Fatalf("Expected size %q, got %q", expectedSize, foundSize)
|
| 237 | 237 |
} |
| 238 |
+ |
|
| 239 |
+ deleteAllContainers() |
|
| 240 |
+ logDone("ps - test ps size")
|
|
| 241 |
+} |
|
| 242 |
+ |
|
| 243 |
+func TestPsListContainersFilterStatus(t *testing.T) {
|
|
| 244 |
+ // FIXME: this should test paused, but it makes things hang and its wonky |
|
| 245 |
+ // this is because paused containers can't be controlled by signals |
|
| 246 |
+ |
|
| 247 |
+ // start exited container |
|
| 248 |
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox") |
|
| 249 |
+ out, _, err := runCommandWithOutput(runCmd) |
|
| 250 |
+ errorOut(err, t, out) |
|
| 251 |
+ firstID := stripTrailingCharacters(out) |
|
| 252 |
+ |
|
| 253 |
+ // make sure the exited cintainer is not running |
|
| 254 |
+ runCmd = exec.Command(dockerBinary, "wait", firstID) |
|
| 255 |
+ out, _, err = runCommandWithOutput(runCmd) |
|
| 256 |
+ errorOut(err, t, out) |
|
| 257 |
+ |
|
| 258 |
+ // start running container |
|
| 259 |
+ runCmd = exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", "sleep 360") |
|
| 260 |
+ out, _, err = runCommandWithOutput(runCmd) |
|
| 261 |
+ errorOut(err, t, out) |
|
| 262 |
+ secondID := stripTrailingCharacters(out) |
|
| 263 |
+ |
|
| 264 |
+ // filter containers by exited |
|
| 265 |
+ runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--filter=status=exited") |
|
| 266 |
+ out, _, err = runCommandWithOutput(runCmd) |
|
| 267 |
+ errorOut(err, t, out) |
|
| 268 |
+ containerOut := strings.TrimSpace(out) |
|
| 269 |
+ if containerOut != firstID[:12] {
|
|
| 270 |
+ t.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out)
|
|
| 271 |
+ } |
|
| 272 |
+ |
|
| 273 |
+ runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--filter=status=running") |
|
| 274 |
+ out, _, err = runCommandWithOutput(runCmd) |
|
| 275 |
+ errorOut(err, t, out) |
|
| 276 |
+ containerOut = strings.TrimSpace(out) |
|
| 277 |
+ if containerOut != secondID[:12] {
|
|
| 278 |
+ t.Fatalf("Expected id %s, got %s for running filter, output: %q", secondID[:12], containerOut, out)
|
|
| 279 |
+ } |
|
| 280 |
+ |
|
| 281 |
+ deleteAllContainers() |
|
| 282 |
+ |
|
| 283 |
+ logDone("ps - test ps filter status")
|
|
| 238 | 284 |
} |