From 8e9305ef946843ce2f8ef47909d6a866eab5dfa8 Mon Sep 17 00:00:00 2001 From: "Kai Qiang Wu(Kennan)" Date: Mon, 21 Mar 2016 07:39:48 +0000 Subject: [PATCH] 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) --- daemon/list.go | 53 ++++++++++++----- docs/reference/api/docker_remote_api.md | 1 + docs/reference/api/docker_remote_api_v1.23.md | 5 +- docs/reference/commandline/volume_ls.md | 59 ++++++++++++++++--- integration-cli/docker_cli_volume_test.go | 18 ++++++ 5 files changed, 113 insertions(+), 23 deletions(-) diff --git a/daemon/list.go b/daemon/list.go index 44ab3cbc9c..c29eaadb42 100644 --- a/daemon/list.go +++ b/daemon/list.go @@ -18,6 +18,8 @@ import ( var acceptedVolumeFilterTags = map[string]bool{ "dangling": true, + "name": true, + "driver": true, } var acceptedPsFilterTags = map[string]bool{ @@ -472,8 +474,7 @@ func (daemon *Daemon) transformContainer(container *container.Container, ctx *li // of volumes returned. func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error) { var ( - volumesOut []*types.Volume - danglingOnly = false + volumesOut []*types.Volume ) volFilters, err := filters.FromParam(filter) if err != nil { @@ -484,27 +485,51 @@ func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error) return nil, nil, err } - if volFilters.Include("dangling") { - if volFilters.ExactMatch("dangling", "true") || volFilters.ExactMatch("dangling", "1") { - danglingOnly = true - } else if !volFilters.ExactMatch("dangling", "false") && !volFilters.ExactMatch("dangling", "0") { - return nil, nil, fmt.Errorf("Invalid filter 'dangling=%s'", volFilters.Get("dangling")) - } - } - volumes, warnings, err := daemon.volumes.List() + filterVolumes, err := daemon.filterVolumes(volumes, volFilters) if err != nil { return nil, nil, err } - if volFilters.Include("dangling") { - volumes = daemon.volumes.FilterByUsed(volumes, !danglingOnly) - } - for _, v := range volumes { + for _, v := range filterVolumes { volumesOut = append(volumesOut, volumeToAPIType(v)) } return volumesOut, warnings, nil } +// filterVolumes filters volume list according to user specified filter +// and returns user chosen volumes +func (daemon *Daemon) filterVolumes(vols []volume.Volume, filter filters.Args) ([]volume.Volume, error) { + // if filter is empty, return original volume list + if filter.Len() == 0 { + return vols, nil + } + + var retVols []volume.Volume + for _, vol := range vols { + if filter.Include("name") { + if !filter.Match("name", vol.Name()) { + continue + } + } + if filter.Include("driver") { + if !filter.Match("driver", vol.DriverName()) { + continue + } + } + retVols = append(retVols, vol) + } + danglingOnly := false + if filter.Include("dangling") { + if filter.ExactMatch("dangling", "true") || filter.ExactMatch("dangling", "1") { + danglingOnly = true + } else if !filter.ExactMatch("dangling", "false") && !filter.ExactMatch("dangling", "0") { + return nil, fmt.Errorf("Invalid filter 'dangling=%s'", filter.Get("dangling")) + } + retVols = daemon.volumes.FilterByUsed(retVols, !danglingOnly) + } + return retVols, nil +} + func populateImageFilterByParents(ancestorMap map[image.ID]bool, imageID image.ID, getChildren func(image.ID) []image.ID) { if !ancestorMap[imageID] { for _, id := range getChildren(imageID) { diff --git a/docs/reference/api/docker_remote_api.md b/docs/reference/api/docker_remote_api.md index d49c085d6a..033aea63d0 100644 --- a/docs/reference/api/docker_remote_api.md +++ b/docs/reference/api/docker_remote_api.md @@ -134,6 +134,7 @@ This section lists each version from latest to oldest. Each listing includes a * `POST /containers/create` now allows specifying `nocopy` for named volumes, which disables automatic copying from the container path to the volume. * `POST /auth` now returns an `IdentityToken` when supported by a registry. * `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`. +* `GET /volumes` now supports more filters, new added filters are `name` and `driver`. ### v1.22 API changes diff --git a/docs/reference/api/docker_remote_api_v1.23.md b/docs/reference/api/docker_remote_api_v1.23.md index 2d799bd340..9b522acb6b 100644 --- a/docs/reference/api/docker_remote_api_v1.23.md +++ b/docs/reference/api/docker_remote_api_v1.23.md @@ -2837,7 +2837,10 @@ Status Codes: Query Parameters: -- **filters** - JSON encoded value of the filters (a `map[string][]string`) to process on the volumes list. There is one available filter: `dangling=true` +- **filters** - JSON encoded value of the filters (a `map[string][]string`) to process on the volumes list. Available filters: + - `name=` Matches all or part of a volume name. + - `dangling=` 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. + - `driver=` Matches all or part of a volume driver name. Status Codes: diff --git a/docs/reference/commandline/volume_ls.md b/docs/reference/commandline/volume_ls.md index 0388e8ae2d..9774c7b834 100644 --- a/docs/reference/commandline/volume_ls.md +++ b/docs/reference/commandline/volume_ls.md @@ -14,28 +14,71 @@ parent = "smn_cli" List volumes - -f, --filter=[] Provide filter values (i.e. 'dangling=true') + -f, --filter=[] Filter output based on these conditions: + - dangling= a volume if referenced or not + - driver= a volume's driver name + - name= a volume's name --help Print usage -q, --quiet Only display volume names -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"`) - -There is a single supported filter `dangling=value` which takes a boolean of `true` or `false`. +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. Example output: - $ docker volume create --name rose - rose + $ docker volume create --name rosemary + rosemary $docker volume create --name tyler tyler $ docker volume ls DRIVER VOLUME NAME - local rose + local rosemary local tyler +## Filtering + +The filtering flag (`-f` or `--filter`) format is of "key=value". If there is more +than one filter, then pass multiple flags (e.g., `--filter "foo=bar" --filter "bif=baz"`) + +The currently supported filters are: + +* dangling (boolean - true or false, 0 or 1) +* driver (a volume driver's name) +* name (a volume's name) + +### dangling + +The `dangling` filter matches on all volumes not referenced by any containers + + $ docker run -d -v tyler:/tmpwork busybox + f86a7dd02898067079c99ceacd810149060a70528eff3754d0b0f1a93bd0af18 + $ docker volume ls -f dangling=true + DRIVER VOLUME NAME + local rosemary + +### driver + +The `driver` filter matches on all or part of a volume's driver name. + +The following filter matches all volumes with a driver name containing the `local` string. + + $ docker volume ls -f driver=local + DRIVER VOLUME NAME + local rosemary + local tyler + +### name + +The `name` filter matches on all or part of a volume's name. + +The following filter matches all volumes with a name containing the `rose` string. + + $ docker volume ls -f name=rose + DRIVER VOLUME NAME + local rosemary + ## Related information * [volume create](volume_create.md) * [volume inspect](volume_inspect.md) * [volume rm](volume_rm.md) -* [Understand Data Volumes](../../userguide/containers/dockervolumes.md) \ No newline at end of file +* [Understand Data Volumes](../../userguide/containers/dockervolumes.md) diff --git a/integration-cli/docker_cli_volume_test.go b/integration-cli/docker_cli_volume_test.go index a10316f616..6756fafe77 100644 --- a/integration-cli/docker_cli_volume_test.go +++ b/integration-cli/docker_cli_volume_test.go @@ -138,6 +138,24 @@ func (s *DockerSuite) TestVolumeCliLsFilterDangling(c *check.C) { c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output")) c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output")) c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output")) + + out, _ = dockerCmd(c, "volume", "ls", "--filter", "name=testisin") + c.Assert(out, check.Not(checker.Contains), "testnotinuse1\n", check.Commentf("expected volume 'testnotinuse1' in output")) + c.Assert(out, checker.Contains, "testisinuse1\n", check.Commentf("execpeted volume 'testisinuse1' in output")) + c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' in output")) + + out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=invalidDriver") + outArr := strings.Split(strings.TrimSpace(out), "\n") + c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out)) + + out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=local") + outArr = strings.Split(strings.TrimSpace(out), "\n") + c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out)) + + out, _ = dockerCmd(c, "volume", "ls", "--filter", "driver=loc") + outArr = strings.Split(strings.TrimSpace(out), "\n") + c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out)) + } func (s *DockerSuite) TestVolumeCliLsErrorWithInvalidFilterName(c *check.C) {