Przeglądaj źródła

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 lat temu
rodzic
commit
8e9305ef94

+ 39 - 14
daemon/list.go

@@ -18,6 +18,8 @@ import (
 
 
 var acceptedVolumeFilterTags = map[string]bool{
 var acceptedVolumeFilterTags = map[string]bool{
 	"dangling": true,
 	"dangling": true,
+	"name":     true,
+	"driver":   true,
 }
 }
 
 
 var acceptedPsFilterTags = map[string]bool{
 var acceptedPsFilterTags = map[string]bool{
@@ -472,8 +474,7 @@ func (daemon *Daemon) transformContainer(container *container.Container, ctx *li
 // of volumes returned.
 // of volumes returned.
 func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error) {
 func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error) {
 	var (
 	var (
-		volumesOut   []*types.Volume
-		danglingOnly = false
+		volumesOut []*types.Volume
 	)
 	)
 	volFilters, err := filters.FromParam(filter)
 	volFilters, err := filters.FromParam(filter)
 	if err != nil {
 	if err != nil {
@@ -484,27 +485,51 @@ func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error)
 		return nil, nil, err
 		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()
 	volumes, warnings, err := daemon.volumes.List()
+	filterVolumes, err := daemon.filterVolumes(volumes, volFilters)
 	if err != nil {
 	if err != nil {
 		return nil, nil, err
 		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))
 		volumesOut = append(volumesOut, volumeToAPIType(v))
 	}
 	}
 	return volumesOut, warnings, nil
 	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) {
 func populateImageFilterByParents(ancestorMap map[image.ID]bool, imageID image.ID, getChildren func(image.ID) []image.ID) {
 	if !ancestorMap[imageID] {
 	if !ancestorMap[imageID] {
 		for _, id := range getChildren(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 /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 /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`.
 * `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
 ### v1.22 API changes
 
 

+ 4 - 1
docs/reference/api/docker_remote_api_v1.23.md

@@ -2837,7 +2837,10 @@ Status Codes:
 
 
 Query Parameters:
 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:
 Status Codes:
 
 

+ 51 - 8
docs/reference/commandline/volume_ls.md

@@ -14,28 +14,71 @@ parent = "smn_cli"
 
 
     List volumes
     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
       --help               Print usage
       -q, --quiet          Only display volume names
       -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:
 Example output:
 
 
-    $ docker volume create --name rose
-    rose
+    $ docker volume create --name rosemary
+    rosemary
     $docker volume create --name tyler
     $docker volume create --name tyler
     tyler
     tyler
     $ docker volume ls
     $ docker volume ls
     DRIVER              VOLUME NAME
     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
     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
 ## Related information
 
 
 * [volume create](volume_create.md)
 * [volume create](volume_create.md)
 * [volume inspect](volume_inspect.md)
 * [volume inspect](volume_inspect.md)
 * [volume rm](volume_rm.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, 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, "testisinuse1\n", check.Commentf("expected volume 'testisinuse1' in output"))
 	c.Assert(out, checker.Contains, "testisinuse2\n", check.Commentf("expected volume 'testisinuse2' 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) {
 func (s *DockerSuite) TestVolumeCliLsErrorWithInvalidFilterName(c *check.C) {