Browse code

Merge pull request #24411 from vdemeester/24393-ps-filter-managed

Add a new "is-task" ps filter

Vincent Demeester authored on 2016/09/30 01:54:15
Showing 9 changed files
... ...
@@ -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
... ...
@@ -333,6 +333,9 @@ __docker_complete_ps_filters() {
333 333
             (id)
334 334
                 __docker_containers_ids && ret=0
335 335
                 ;;
336
+            (is-task)
337
+                _describe -t boolean-filter-opts "filter options" boolean_opts && ret=0
338
+                ;;
336 339
             (name)
337 340
                 __docker_containers_names && ret=0
338 341
                 ;;
... ...
@@ -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.