Add network label filter support

This patch did following:

1) Make filter check logic same as `docker ps ` filters

Right now docker container logic work as following:
when same filter used like below:
 -f name=jack -f name=tom
it would get all containers name is jack or tom(it is or logic)

when different filter used like below:

 -f name=jack -f id=7d1
it would get all containers name is jack and id contains 7d1(it is and logic)

It would make sense in many user cases, but it did lack of compliate filter cases,
like "I want to get containers name is jack or id=7d1", it could work around use
(get id=7d1 containers' name and get name=jack containers, and then construct the
final containers, they could be done in user side use shell or rest API)

2) Fix one network filter bug which could include duplicate result
when use -f name=  -f id=, it would get duplicate results

3) Make id filter same as container id filter, which means match any string.
not use prefix match.

It is for consistent match logic

Closes: #21417

Signed-off-by: Kai Qiang Wu(Kennan) <wkqwu@cn.ibm.com>
This commit is contained in:
Kai Qiang Wu(Kennan) 2016-03-24 14:31:19 +00:00
parent 2a95488f78
commit f812b55692
6 changed files with 195 additions and 149 deletions

View File

@ -2,8 +2,6 @@ package network
import (
"fmt"
"regexp"
"strings"
"github.com/docker/docker/runconfig"
"github.com/docker/engine-api/types/filters"
@ -13,27 +11,13 @@ import (
type filterHandler func([]libnetwork.Network, string) ([]libnetwork.Network, error)
var (
// supportedFilters predefined some supported filter handler function
supportedFilters = map[string]filterHandler{
"type": filterNetworkByType,
"name": filterNetworkByName,
"id": filterNetworkByID,
// AcceptedFilters is an acceptable filters for validation
AcceptedFilters = map[string]bool{
"type": true,
"name": true,
"id": true,
"label": true,
}
// AcceptedFilters is an acceptable filter flag list
// generated for validation. e.g.
// acceptedFilters = map[string]bool{
// "type": true,
// "name": true,
// "id": true,
// }
AcceptedFilters = func() map[string]bool {
ret := make(map[string]bool)
for k := range supportedFilters {
ret[k] = true
}
return ret
}()
)
func filterNetworkByType(nws []libnetwork.Network, netType string) (retNws []libnetwork.Network, err error) {
@ -56,34 +40,6 @@ func filterNetworkByType(nws []libnetwork.Network, netType string) (retNws []lib
return retNws, nil
}
func filterNetworkByName(nws []libnetwork.Network, name string) (retNws []libnetwork.Network, err error) {
for _, nw := range nws {
// exact match (fast path)
if nw.Name() == name {
retNws = append(retNws, nw)
continue
}
// regexp match (slow path)
match, err := regexp.MatchString(name, nw.Name())
if err != nil || !match {
continue
} else {
retNws = append(retNws, nw)
}
}
return retNws, nil
}
func filterNetworkByID(nws []libnetwork.Network, id string) (retNws []libnetwork.Network, err error) {
for _, nw := range nws {
if strings.HasPrefix(nw.ID(), id) {
retNws = append(retNws, nw)
}
}
return retNws, nil
}
// FilterNetworks filters network list according to user specified filter
// and returns user chosen networks
func FilterNetworks(nws []libnetwork.Network, filter filters.Args) ([]libnetwork.Network, error) {
@ -93,18 +49,40 @@ func FilterNetworks(nws []libnetwork.Network, filter filters.Args) ([]libnetwork
}
var displayNet []libnetwork.Network
for fkey, fhandler := range supportedFilters {
errFilter := filter.WalkValues(fkey, func(fval string) error {
passList, err := fhandler(nws, fval)
for _, nw := range nws {
if filter.Include("name") {
if !filter.Match("name", nw.Name()) {
continue
}
}
if filter.Include("id") {
if !filter.Match("id", nw.ID()) {
continue
}
}
if filter.Include("label") {
if !filter.MatchKVList("label", nw.Info().Labels()) {
continue
}
}
displayNet = append(displayNet, nw)
}
if filter.Include("type") {
var typeNet []libnetwork.Network
errFilter := filter.WalkValues("type", func(fval string) error {
passList, err := filterNetworkByType(displayNet, fval)
if err != nil {
return err
}
displayNet = append(displayNet, passList...)
typeNet = append(typeNet, passList...)
return nil
})
if errFilter != nil {
return nil, errFilter
}
displayNet = typeNet
}
return displayNet, nil
}

View File

@ -118,6 +118,7 @@ This section lists each version from latest to oldest. Each listing includes a
* `POST /containers/create` now takes `StorageOpt` field.
* `GET /info` now returns `SecurityOptions` field, showing if `apparmor`, `seccomp`, or `selinux` is supported.
* `GET /networks` now supports filtering by `label`.
### v1.23 API changes

View File

@ -2947,8 +2947,9 @@ Content-Type: application/json
Query Parameters:
- **filters** - JSON encoded network list filter. The filter value is one of:
- `name=<network-name>` Matches all or part of a network name.
- `id=<network-id>` Matches all or part of a network id.
- `label=<key>` or `label=<key>=<value>` of a network label.
- `name=<network-name>` Matches all or part of a network name.
- `type=["custom"|"builtin"]` Filters networks by type. The `custom` keyword returns all user-defined networks.
Status Codes:

View File

@ -52,54 +52,10 @@ Multiple filter flags are combined as an `OR` filter. For example,
The currently supported filters are:
* id (network's id)
* label (`label=<key>` or `label=<key>=<value>`)
* name (network's name)
* type (custom|builtin)
#### Type
The `type` filter supports two values; `builtin` displays predefined networks
(`bridge`, `none`, `host`), whereas `custom` displays user defined networks.
The following filter matches all user defined networks:
```bash
$ docker network ls --filter type=custom
NETWORK ID NAME DRIVER
95e74588f40d foo bridge
63d1ff1f77b0 dev bridge
```
By having this flag it allows for batch cleanup. For example, use this filter
to delete all user defined networks:
```bash
$ docker network rm `docker network ls --filter type=custom -q`
```
A warning will be issued when trying to remove a network that has containers
attached.
#### Name
The `name` filter matches on all or part of a network's name.
The following filter matches all networks with a name containing the `foobar` string.
```bash
$ docker network ls --filter name=foobar
NETWORK ID NAME DRIVER
06e7eef0a170 foobar bridge
```
You can also filter for a substring in a name as this shows:
```bash
$ docker network ls --filter name=foo
NETWORK ID NAME DRIVER
95e74588f40d foo bridge
06e7eef0a170 foobar bridge
```
#### ID
The `id` filter matches on all or part of a network's ID.
@ -125,6 +81,73 @@ NETWORK ID NAME DRIVER
95e74588f40d foo bridge
```
#### Label
The `label` filter matches containers based on the presence of a `label` alone or a `label` and a
value.
The following filter matches networks with the `usage` label regardless of its value.
```bash
$ docker network ls -f "label=usage"
NETWORK ID NAME DRIVER
db9db329f835 test1 bridge
f6e212da9dfd test2 bridge
```
The following filter matches containers with the `usage` label with the `prod` value.
```bash
$ docker network ls -f "label=usage=prod"
NETWORK ID NAME DRIVER
f6e212da9dfd test2 bridge
```
#### Name
The `name` filter matches on all or part of a network's name.
The following filter matches all networks with a name containing the `foobar` string.
```bash
$ docker network ls --filter name=foobar
NETWORK ID NAME DRIVER
06e7eef0a170 foobar bridge
```
You can also filter for a substring in a name as this shows:
```bash
$ docker network ls --filter name=foo
NETWORK ID NAME DRIVER
95e74588f40d foo bridge
06e7eef0a170 foobar bridge
```
#### Type
The `type` filter supports two values; `builtin` displays predefined networks
(`bridge`, `none`, `host`), whereas `custom` displays user defined networks.
The following filter matches all user defined networks:
```bash
$ docker network ls --filter type=custom
NETWORK ID NAME DRIVER
95e74588f40d foo bridge
63d1ff1f77b0 dev bridge
```
By having this flag it allows for batch cleanup. For example, use this filter
to delete all user defined networks:
```bash
$ docker network rm `docker network ls --filter type=custom -q`
```
A warning will be issued when trying to remove a network that has containers
attached.
## Related information
* [network disconnect ](network_disconnect.md)

View File

@ -308,16 +308,23 @@ func (s *DockerNetworkSuite) TestDockerNetworkRmPredefined(c *check.C) {
}
func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *check.C) {
testNet := "testnet1"
testLabel := "foo"
testValue := "bar"
out, _ := dockerCmd(c, "network", "create", "dev")
defer func() {
dockerCmd(c, "network", "rm", "dev")
dockerCmd(c, "network", "rm", testNet)
}()
networkID := strings.TrimSpace(out)
// filter with partial ID and partial name
// only show 'bridge' and 'dev' network
out, _ = dockerCmd(c, "network", "ls", "-f", "id="+networkID[0:5], "-f", "name=dge")
assertNwList(c, out, []string{"bridge", "dev"})
// filter with partial ID
// only show 'dev' network
out, _ = dockerCmd(c, "network", "ls", "-f", "id="+networkID[0:5])
assertNwList(c, out, []string{"dev"})
out, _ = dockerCmd(c, "network", "ls", "-f", "name=dge")
assertNwList(c, out, []string{"bridge"})
// only show built-in network (bridge, none, host)
out, _ = dockerCmd(c, "network", "ls", "-f", "type=builtin")
@ -331,6 +338,19 @@ func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *check.C) {
// it should be equivalent of ls without option
out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom", "-f", "type=builtin")
assertNwList(c, out, []string{"bridge", "dev", "host", "none"})
out, _ = dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet)
assertNwIsAvailable(c, testNet)
out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel)
assertNwList(c, out, []string{testNet})
out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel+"="+testValue)
assertNwList(c, out, []string{testNet})
out, _ = dockerCmd(c, "network", "ls", "-f", "label=nonexistent")
outArr := strings.Split(strings.TrimSpace(out), "\n")
c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
}
func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *check.C) {

View File

@ -47,54 +47,10 @@ Multiple filter flags are combined as an `OR` filter. For example,
The currently supported filters are:
* id (network's id)
* label (`label=<key>` or `label=<key>=<value>`)
* name (network's name)
* type (custom|builtin)
#### Type
The `type` filter supports two values; `builtin` displays predefined networks
(`bridge`, `none`, `host`), whereas `custom` displays user defined networks.
The following filter matches all user defined networks:
```bash
$ docker network ls --filter type=custom
NETWORK ID NAME DRIVER
95e74588f40d foo bridge
63d1ff1f77b0 dev bridge
```
By having this flag it allows for batch cleanup. For example, use this filter
to delete all user defined networks:
```bash
$ docker network rm `docker network ls --filter type=custom -q`
```
A warning will be issued when trying to remove a network that has containers
attached.
#### Name
The `name` filter matches on all or part of a network's name.
The following filter matches all networks with a name containing the `foobar` string.
```bash
$ docker network ls --filter name=foobar
NETWORK ID NAME DRIVER
06e7eef0a170 foobar bridge
```
You can also filter for a substring in a name as this shows:
```bash
$ docker network ls --filter name=foo
NETWORK ID NAME DRIVER
95e74588f40d foo bridge
06e7eef0a170 foobar bridge
```
#### ID
The `id` filter matches on all or part of a network's ID.
@ -120,6 +76,73 @@ NETWORK ID NAME DRIVER
95e74588f40d foo bridge
```
#### Label
The `label` filter matches containers based on the presence of a `label` alone or a `label` and a
value.
The following filter matches networks with the `usage` label regardless of its value.
```bash
$ docker network ls -f "label=usage"
NETWORK ID NAME DRIVER
db9db329f835 test1 bridge
f6e212da9dfd test2 bridge
```
The following filter matches containers with the `usage` label with the `prod` value.
```bash
$ docker network ls -f "label=usage=prod"
NETWORK ID NAME DRIVER
f6e212da9dfd test2 bridge
```
#### Name
The `name` filter matches on all or part of a network's name.
The following filter matches all networks with a name containing the `foobar` string.
```bash
$ docker network ls --filter name=foobar
NETWORK ID NAME DRIVER
06e7eef0a170 foobar bridge
```
You can also filter for a substring in a name as this shows:
```bash
$ docker network ls --filter name=foo
NETWORK ID NAME DRIVER
95e74588f40d foo bridge
06e7eef0a170 foobar bridge
```
#### Type
The `type` filter supports two values; `builtin` displays predefined networks
(`bridge`, `none`, `host`), whereas `custom` displays user defined networks.
The following filter matches all user defined networks:
```bash
$ docker network ls --filter type=custom
NETWORK ID NAME DRIVER
95e74588f40d foo bridge
63d1ff1f77b0 dev bridge
```
By having this flag it allows for batch cleanup. For example, use this filter
to delete all user defined networks:
```bash
$ docker network rm `docker network ls --filter type=custom -q`
```
A warning will be issued when trying to remove a network that has containers
attached.
# OPTIONS
**-f**, **--filter**=*[]*