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>
| ... | ... |
@@ -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) {
|