Add a new "is-task" ps filter
| ... | ... |
@@ -2181,6 +2181,10 @@ _docker_ps() {
|
| 2181 | 2181 |
__docker_complete_container_ids |
| 2182 | 2182 |
return |
| 2183 | 2183 |
;; |
| 2184 |
+ is-task) |
|
| 2185 |
+ COMPREPLY=( $( compgen -W "true false" -- "${cur##*=}" ) )
|
|
| 2186 |
+ return |
|
| 2187 |
+ ;; |
|
| 2184 | 2188 |
name) |
| 2185 | 2189 |
cur="${cur##*=}"
|
| 2186 | 2190 |
__docker_complete_container_names |
| ... | ... |
@@ -36,6 +36,7 @@ var acceptedPsFilterTags = map[string]bool{
|
| 36 | 36 |
"since": true, |
| 37 | 37 |
"volume": true, |
| 38 | 38 |
"network": true, |
| 39 |
+ "is-task": true, |
|
| 39 | 40 |
} |
| 40 | 41 |
|
| 41 | 42 |
// iterationAction represents possible outcomes happening during the container iteration. |
| ... | ... |
@@ -79,11 +80,14 @@ type listContext struct {
|
| 79 | 79 |
exitAllowed []int |
| 80 | 80 |
|
| 81 | 81 |
// beforeFilter is a filter to ignore containers that appear before the one given |
| 82 |
- // this is used for --filter=before= and --before=, the latter is deprecated. |
|
| 83 | 82 |
beforeFilter *container.Container |
| 84 | 83 |
// sinceFilter is a filter to stop the filtering when the iterator arrive to the given container |
| 85 |
- // this is used for --filter=since= and --since=, the latter is deprecated. |
|
| 86 | 84 |
sinceFilter *container.Container |
| 85 |
+ |
|
| 86 |
+ // taskFilter tells if we should filter based on wether a container is part of a task |
|
| 87 |
+ taskFilter bool |
|
| 88 |
+ // isTask tells us if the we should filter container that are a task (true) or not (false) |
|
| 89 |
+ isTask bool |
|
| 87 | 90 |
// ContainerListOptions is the filters set by the user |
| 88 | 91 |
*types.ContainerListOptions |
| 89 | 92 |
} |
| ... | ... |
@@ -241,6 +245,19 @@ func (daemon *Daemon) foldFilter(config *types.ContainerListOptions) (*listConte |
| 241 | 241 |
return nil, err |
| 242 | 242 |
} |
| 243 | 243 |
|
| 244 |
+ var taskFilter, isTask bool |
|
| 245 |
+ if psFilters.Include("is-task") {
|
|
| 246 |
+ if psFilters.ExactMatch("is-task", "true") {
|
|
| 247 |
+ taskFilter = true |
|
| 248 |
+ isTask = true |
|
| 249 |
+ } else if psFilters.ExactMatch("is-task", "false") {
|
|
| 250 |
+ taskFilter = true |
|
| 251 |
+ isTask = false |
|
| 252 |
+ } else {
|
|
| 253 |
+ return nil, fmt.Errorf("Invalid filter 'is-task=%s'", psFilters.Get("is-task"))
|
|
| 254 |
+ } |
|
| 255 |
+ } |
|
| 256 |
+ |
|
| 244 | 257 |
var beforeContFilter, sinceContFilter *container.Container |
| 245 | 258 |
|
| 246 | 259 |
err = psFilters.WalkValues("before", func(value string) error {
|
| ... | ... |
@@ -286,6 +303,8 @@ func (daemon *Daemon) foldFilter(config *types.ContainerListOptions) (*listConte |
| 286 | 286 |
exitAllowed: filtExited, |
| 287 | 287 |
beforeFilter: beforeContFilter, |
| 288 | 288 |
sinceFilter: sinceContFilter, |
| 289 |
+ taskFilter: taskFilter, |
|
| 290 |
+ isTask: isTask, |
|
| 289 | 291 |
ContainerListOptions: config, |
| 290 | 292 |
names: daemon.nameIndex.GetAll(), |
| 291 | 293 |
}, nil |
| ... | ... |
@@ -325,6 +344,12 @@ func includeContainerInList(container *container.Container, ctx *listContext) it |
| 325 | 325 |
return excludeContainer |
| 326 | 326 |
} |
| 327 | 327 |
|
| 328 |
+ if ctx.taskFilter {
|
|
| 329 |
+ if ctx.isTask != container.Managed {
|
|
| 330 |
+ return excludeContainer |
|
| 331 |
+ } |
|
| 332 |
+ } |
|
| 333 |
+ |
|
| 328 | 334 |
// Do not include container if any of the labels don't match |
| 329 | 335 |
if !ctx.filters.MatchKVList("label", container.Config.Labels) {
|
| 330 | 336 |
return excludeContainer |
| ... | ... |
@@ -130,6 +130,8 @@ This section lists each version from latest to oldest. Each listing includes a |
| 130 | 130 |
instead of the default network if a trailing slash is provided, but no `name` |
| 131 | 131 |
or `id`. |
| 132 | 132 |
* `DELETE /containers/(name)` endpoint now returns an error of `removal of container name is already in progress` with status code of 400, when container name is in a state of removal in progress. |
| 133 |
+* `GET /containers/json` now supports a `is-task` filter to filter |
|
| 134 |
+ containers that are tasks (part of a service in swarm mode). |
|
| 133 | 135 |
|
| 134 | 136 |
### v1.24 API changes |
| 135 | 137 |
|
| ... | ... |
@@ -229,6 +229,9 @@ List containers |
| 229 | 229 |
- `status=`(`created`|`restarting`|`running`|`removing`|`paused`|`exited`|`dead`) |
| 230 | 230 |
- `label=key` or `label="key=value"` of a container label |
| 231 | 231 |
- `isolation=`(`default`|`process`|`hyperv`) (Windows daemon only) |
| 232 |
+ `id=<ID>` a container's ID |
|
| 233 |
+ `name=<name>` a container's name |
|
| 234 |
+ `is-task=`(`true`|`false`) |
|
| 232 | 235 |
- `ancestor`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) |
| 233 | 236 |
- `before`=(`<container id>` or `<container name>`) |
| 234 | 237 |
- `since`=(`<container id>` or `<container name>`) |
| ... | ... |
@@ -27,6 +27,7 @@ Options: |
| 27 | 27 |
- since=(<container-name>|<container-id>) |
| 28 | 28 |
- ancestor=(<image-name>[:tag]|<image-id>|<image@digest>) |
| 29 | 29 |
containers created from an image or a descendant. |
| 30 |
+ - is-task=(true|false) |
|
| 30 | 31 |
--format string Pretty-print containers using a Go template |
| 31 | 32 |
--help Print usage |
| 32 | 33 |
-n, --last int Show n last created containers (includes all states) (default -1) |
| ... | ... |
@@ -136,6 +136,7 @@ func assertContainerList(out string, expected []string) bool {
|
| 136 | 136 |
return true |
| 137 | 137 |
} |
| 138 | 138 |
|
| 139 |
+// FIXME(vdemeester) Move this into a unit test in daemon package |
|
| 139 | 140 |
func (s *DockerSuite) TestPsListContainersInvalidFilterName(c *check.C) {
|
| 140 | 141 |
out, _, err := dockerCmdWithError("ps", "-f", "invalidFilter=test")
|
| 141 | 142 |
c.Assert(err, checker.NotNil) |
| ... | ... |
@@ -323,3 +323,33 @@ func (s *DockerSwarmSuite) TestSwarmTaskListFilter(c *check.C) {
|
| 323 | 323 |
c.Assert(err, checker.IsNil) |
| 324 | 324 |
c.Assert(out, checker.Not(checker.Contains), name) |
| 325 | 325 |
} |
| 326 |
+ |
|
| 327 |
+func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *check.C) {
|
|
| 328 |
+ d := s.AddDaemon(c, true, true) |
|
| 329 |
+ |
|
| 330 |
+ // Create a bare container |
|
| 331 |
+ out, err := d.Cmd("run", "-d", "--name=bare-container", "busybox", "top")
|
|
| 332 |
+ c.Assert(err, checker.IsNil) |
|
| 333 |
+ bareID := strings.TrimSpace(out)[:12] |
|
| 334 |
+ // Create a service |
|
| 335 |
+ name := "busybox-top" |
|
| 336 |
+ out, err = d.Cmd("service", "create", "--name", name, "busybox", "top")
|
|
| 337 |
+ c.Assert(err, checker.IsNil) |
|
| 338 |
+ c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") |
|
| 339 |
+ |
|
| 340 |
+ // make sure task has been deployed. |
|
| 341 |
+ waitAndAssert(c, defaultReconciliationTimeout, d.checkServiceRunningTasks(c, name), checker.Equals, 1) |
|
| 342 |
+ |
|
| 343 |
+ // Filter non-tasks |
|
| 344 |
+ out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=false")
|
|
| 345 |
+ c.Assert(err, checker.IsNil) |
|
| 346 |
+ psOut := strings.TrimSpace(out) |
|
| 347 |
+ c.Assert(psOut, checker.Equals, bareID, check.Commentf("Expected id %s, got %s for is-task label, output %q", bareID, psOut, out))
|
|
| 348 |
+ |
|
| 349 |
+ // Filter tasks |
|
| 350 |
+ out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=true")
|
|
| 351 |
+ c.Assert(err, checker.IsNil) |
|
| 352 |
+ lines := strings.Split(strings.Trim(out, "\n "), "\n") |
|
| 353 |
+ c.Assert(lines, checker.HasLen, 1) |
|
| 354 |
+ c.Assert(lines[0], checker.Not(checker.Equals), bareID, check.Commentf("Expected not %s, but got it for is-task label, output %q", bareID, out))
|
|
| 355 |
+} |
| ... | ... |
@@ -32,6 +32,7 @@ the running containers. |
| 32 | 32 |
- status=(created|restarting|running|paused|exited|dead) |
| 33 | 33 |
- name=<string> a container's name |
| 34 | 34 |
- id=<ID> a container's ID |
| 35 |
+ - is-task=(true|false) - containers that are a task (part of a service managed by swarm) |
|
| 35 | 36 |
- before=(<container-name>|<container-id>) |
| 36 | 37 |
- since=(<container-name>|<container-id>) |
| 37 | 38 |
- ancestor=(<image-name>[:tag]|<image-id>|<image@digest>) - containers created from an image or a descendant. |