mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
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>
This commit is contained in:
parent
6748ecb005
commit
8e9305ef94
5 changed files with 113 additions and 23 deletions
|
@ -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{
|
||||||
|
@ -473,7 +475,6 @@ func (daemon *Daemon) transformContainer(container *container.Container, ctx *li
|
||||||
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
|
volumesOut []*types.Volume
|
||||||
danglingOnly = false
|
|
||||||
)
|
)
|
||||||
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") {
|
for _, v := range filterVolumes {
|
||||||
volumes = daemon.volumes.FilterByUsed(volumes, !danglingOnly)
|
|
||||||
}
|
|
||||||
for _, v := range volumes {
|
|
||||||
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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -14,25 +14,68 @@ 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"`)
|
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.
|
||||||
|
|
||||||
There is a single supported filter `dangling=value` which takes a boolean of `true` or `false`.
|
|
||||||
|
|
||||||
Example output:
|
Example output:
|
||||||
|
|
||||||
$ docker volume create --name rose
|
$ docker volume create --name rosemary
|
||||||
rose
|
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
|
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
|
## Related information
|
||||||
|
|
||||||
* [volume create](volume_create.md)
|
* [volume create](volume_create.md)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue