Browse Source

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) 9 years ago
parent
commit
8e9305ef94

+ 39 - 14
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) {

+ 1 - 0
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
 

+ 4 - 1
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=<volume-name>` Matches all or part of a volume name.
+  -   `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.
+  -   `driver=<volume-driver-name>` Matches all or part of a volume driver name.
 
 Status Codes:
 

+ 51 - 8
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=<boolean> a volume if referenced or not
+                           - driver=<string> a volume's driver name
+                           - name=<string> 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)
+* [Understand Data Volumes](../../userguide/containers/dockervolumes.md)

+ 18 - 0
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) {