Browse code

Add name/driver filter support for volume

This change include filter `name` and `driver`,
and also update related docs to reflect that filters usage.

Closes: #21243

Signed-off-by: Kai Qiang Wu(Kennan) <wkqwu@cn.ibm.com>

Kai Qiang Wu(Kennan) authored on 2016/03/21 16:39:48
Showing 5 changed files
... ...
@@ -18,6 +18,8 @@ import (
18 18
 
19 19
 var acceptedVolumeFilterTags = map[string]bool{
20 20
 	"dangling": true,
21
+	"name":     true,
22
+	"driver":   true,
21 23
 }
22 24
 
23 25
 var acceptedPsFilterTags = map[string]bool{
... ...
@@ -472,8 +474,7 @@ func (daemon *Daemon) transformContainer(container *container.Container, ctx *li
472 472
 // of volumes returned.
473 473
 func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error) {
474 474
 	var (
475
-		volumesOut   []*types.Volume
476
-		danglingOnly = false
475
+		volumesOut []*types.Volume
477 476
 	)
478 477
 	volFilters, err := filters.FromParam(filter)
479 478
 	if err != nil {
... ...
@@ -484,27 +485,51 @@ func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error)
484 484
 		return nil, nil, err
485 485
 	}
486 486
 
487
-	if volFilters.Include("dangling") {
488
-		if volFilters.ExactMatch("dangling", "true") || volFilters.ExactMatch("dangling", "1") {
489
-			danglingOnly = true
490
-		} else if !volFilters.ExactMatch("dangling", "false") && !volFilters.ExactMatch("dangling", "0") {
491
-			return nil, nil, fmt.Errorf("Invalid filter 'dangling=%s'", volFilters.Get("dangling"))
492
-		}
493
-	}
494
-
495 487
 	volumes, warnings, err := daemon.volumes.List()
488
+	filterVolumes, err := daemon.filterVolumes(volumes, volFilters)
496 489
 	if err != nil {
497 490
 		return nil, nil, err
498 491
 	}
499
-	if volFilters.Include("dangling") {
500
-		volumes = daemon.volumes.FilterByUsed(volumes, !danglingOnly)
501
-	}
502
-	for _, v := range volumes {
492
+	for _, v := range filterVolumes {
503 493
 		volumesOut = append(volumesOut, volumeToAPIType(v))
504 494
 	}
505 495
 	return volumesOut, warnings, nil
506 496
 }
507 497
 
498
+// filterVolumes filters volume list according to user specified filter
499
+// and returns user chosen volumes
500
+func (daemon *Daemon) filterVolumes(vols []volume.Volume, filter filters.Args) ([]volume.Volume, error) {
501
+	// if filter is empty, return original volume list
502
+	if filter.Len() == 0 {
503
+		return vols, nil
504
+	}
505
+
506
+	var retVols []volume.Volume
507
+	for _, vol := range vols {
508
+		if filter.Include("name") {
509
+			if !filter.Match("name", vol.Name()) {
510
+				continue
511
+			}
512
+		}
513
+		if filter.Include("driver") {
514
+			if !filter.Match("driver", vol.DriverName()) {
515
+				continue
516
+			}
517
+		}
518
+		retVols = append(retVols, vol)
519
+	}
520
+	danglingOnly := false
521
+	if filter.Include("dangling") {
522
+		if filter.ExactMatch("dangling", "true") || filter.ExactMatch("dangling", "1") {
523
+			danglingOnly = true
524
+		} else if !filter.ExactMatch("dangling", "false") && !filter.ExactMatch("dangling", "0") {
525
+			return nil, fmt.Errorf("Invalid filter 'dangling=%s'", filter.Get("dangling"))
526
+		}
527
+		retVols = daemon.volumes.FilterByUsed(retVols, !danglingOnly)
528
+	}
529
+	return retVols, nil
530
+}
531
+
508 532
 func populateImageFilterByParents(ancestorMap map[image.ID]bool, imageID image.ID, getChildren func(image.ID) []image.ID) {
509 533
 	if !ancestorMap[imageID] {
510 534
 		for _, id := range getChildren(imageID) {
... ...
@@ -134,6 +134,7 @@ This section lists each version from latest to oldest.  Each listing includes a
134 134
 * `POST /containers/create` now allows specifying `nocopy` for named volumes, which disables automatic copying from the container path to the volume.
135 135
 * `POST /auth` now returns an `IdentityToken` when supported by a registry.
136 136
 * `POST /containers/create` with both `Hostname` and `Domainname` fields specified will result in the container's hostname being set to `Hostname`, rather than `Hostname.Domainname`.
137
+* `GET /volumes` now supports more filters, new added filters are `name` and `driver`.
137 138
 
138 139
 ### v1.22 API changes
139 140
 
... ...
@@ -2837,7 +2837,10 @@ Status Codes:
2837 2837
 
2838 2838
 Query Parameters:
2839 2839
 
2840
-- **filters** - JSON encoded value of the filters (a `map[string][]string`) to process on the volumes list. There is one available filter: `dangling=true`
2840
+- **filters** - JSON encoded value of the filters (a `map[string][]string`) to process on the volumes list. Available filters:
2841
+  -   `name=<volume-name>` Matches all or part of a volume name.
2842
+  -   `dangling=<boolean>` When set to `true` (or `1`), returns all volumes that are "dangling" (not in use by a container). When set to `false` (or `0`), only volumes that are in use by one or more containers are returned.
2843
+  -   `driver=<volume-driver-name>` Matches all or part of a volume driver name.
2841 2844
 
2842 2845
 Status Codes:
2843 2846
 
... ...
@@ -14,28 +14,71 @@ parent = "smn_cli"
14 14
 
15 15
     List volumes
16 16
 
17
-      -f, --filter=[]      Provide filter values (i.e. 'dangling=true')
17
+      -f, --filter=[]      Filter output based on these conditions:
18
+                           - dangling=<boolean> a volume if referenced or not
19
+                           - driver=<string> a volume's driver name
20
+                           - name=<string> a volume's name
18 21
       --help               Print usage
19 22
       -q, --quiet          Only display volume names
20 23
 
21
-Lists all the volumes Docker knows about. You can filter using the `-f` or `--filter` flag. The filtering format is a `key=value` pair. To specify more than one filter,  pass multiple flags (for example,  `--filter "foo=bar" --filter "bif=baz"`)
22
-
23
-There is a single supported filter `dangling=value` which takes a boolean of `true` or `false`.
24
+Lists all the volumes Docker knows about. You can filter using the `-f` or `--filter` flag. Refer to the [filtering](#filtering) section for more information about available filter options.
24 25
 
25 26
 Example output:
26 27
 
27
-    $ docker volume create --name rose
28
-    rose
28
+    $ docker volume create --name rosemary
29
+    rosemary
29 30
     $docker volume create --name tyler
30 31
     tyler
31 32
     $ docker volume ls
32 33
     DRIVER              VOLUME NAME
33
-    local               rose
34
+    local               rosemary
35
+    local               tyler
36
+
37
+## Filtering
38
+
39
+The filtering flag (`-f` or `--filter`) format is of "key=value". If there is more
40
+than one filter, then pass multiple flags (e.g., `--filter "foo=bar" --filter "bif=baz"`)
41
+
42
+The currently supported filters are:
43
+
44
+* dangling (boolean - true or false, 0 or 1)
45
+* driver (a volume driver's name)
46
+* name (a volume's name)
47
+
48
+### dangling
49
+
50
+The `dangling` filter matches on all volumes not referenced by any containers
51
+
52
+    $ docker run -d  -v tyler:/tmpwork  busybox
53
+    f86a7dd02898067079c99ceacd810149060a70528eff3754d0b0f1a93bd0af18
54
+    $ docker volume ls -f dangling=true
55
+    DRIVER              VOLUME NAME
56
+    local               rosemary
57
+
58
+### driver
59
+
60
+The `driver` filter matches on all or part of a volume's driver name.
61
+
62
+The following filter matches all volumes with a driver name containing the `local` string.
63
+
64
+    $ docker volume ls -f driver=local
65
+    DRIVER              VOLUME NAME
66
+    local               rosemary
34 67
     local               tyler
35 68
 
69
+### name
70
+
71
+The `name` filter matches on all or part of a volume's name.
72
+
73
+The following filter matches all volumes with a name containing the `rose` string.
74
+
75
+    $ docker volume ls -f name=rose
76
+    DRIVER              VOLUME NAME
77
+    local               rosemary
78
+
36 79
 ## Related information
37 80
 
38 81
 * [volume create](volume_create.md)
39 82
 * [volume inspect](volume_inspect.md)
40 83
 * [volume rm](volume_rm.md)
41
-* [Understand Data Volumes](../../userguide/containers/dockervolumes.md)
42 84
\ No newline at end of file
85
+* [Understand Data Volumes](../../userguide/containers/dockervolumes.md)
... ...
@@ -138,6 +138,24 @@ func (s *DockerSuite) TestVolumeCliLsFilterDangling(c *check.C) {
138 138
 	c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
139 139
 	c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
140 140
 	c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
141
+
142
+	out, _ = dockerCmd(c, "volume", "ls", "--filter", "name=testisin")
143
+	c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output"))
144
+	c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("execpeted volume 'testisinuse1' in output"))
145
+	c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output"))
146
+
147
+	out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=invalidDriver")
148
+	outArr := strings.Split(strings.TrimSpace(out), "\n")
149
+	c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
150
+
151
+	out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=local")
152
+	outArr = strings.Split(strings.TrimSpace(out), "\n")
153
+	c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out))
154
+
155
+	out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=loc")
156
+	outArr = strings.Split(strings.TrimSpace(out), "\n")
157
+	c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out))
158
+
141 159
 }
142 160
 
143 161
 func (s *DockerSuite) TestVolumeCliLsErrorWithInvalidFilterName(c *check.C) {