Browse code

Merge pull request #21495 from HackToday/addnetworkfilter

Add network label filter support

Vincent Demeester authored on 2016/04/20 02:15:14
Showing 6 changed files
... ...
@@ -2,8 +2,6 @@ package network
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"regexp"
6
-	"strings"
7 5
 
8 6
 	"github.com/docker/docker/runconfig"
9 7
 	"github.com/docker/engine-api/types/filters"
... ...
@@ -13,27 +11,13 @@ import (
13 13
 type filterHandler func([]libnetwork.Network, string) ([]libnetwork.Network, error)
14 14
 
15 15
 var (
16
-	// supportedFilters predefined some supported filter handler function
17
-	supportedFilters = map[string]filterHandler{
18
-		"type": filterNetworkByType,
19
-		"name": filterNetworkByName,
20
-		"id":   filterNetworkByID,
16
+	// AcceptedFilters is an acceptable filters for validation
17
+	AcceptedFilters = map[string]bool{
18
+		"type":  true,
19
+		"name":  true,
20
+		"id":    true,
21
+		"label": true,
21 22
 	}
22
-
23
-	// AcceptedFilters is an acceptable filter flag list
24
-	// generated for validation. e.g.
25
-	// acceptedFilters = map[string]bool{
26
-	//     "type": true,
27
-	//     "name": true,
28
-	//     "id":   true,
29
-	// }
30
-	AcceptedFilters = func() map[string]bool {
31
-		ret := make(map[string]bool)
32
-		for k := range supportedFilters {
33
-			ret[k] = true
34
-		}
35
-		return ret
36
-	}()
37 23
 )
38 24
 
39 25
 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
56 56
 	return retNws, nil
57 57
 }
58 58
 
59
-func filterNetworkByName(nws []libnetwork.Network, name string) (retNws []libnetwork.Network, err error) {
60
-	for _, nw := range nws {
61
-		// exact match (fast path)
62
-		if nw.Name() == name {
63
-			retNws = append(retNws, nw)
64
-			continue
65
-		}
66
-
67
-		// regexp match (slow path)
68
-		match, err := regexp.MatchString(name, nw.Name())
69
-		if err != nil || !match {
70
-			continue
71
-		} else {
72
-			retNws = append(retNws, nw)
73
-		}
74
-	}
75
-	return retNws, nil
76
-}
77
-
78
-func filterNetworkByID(nws []libnetwork.Network, id string) (retNws []libnetwork.Network, err error) {
79
-	for _, nw := range nws {
80
-		if strings.HasPrefix(nw.ID(), id) {
81
-			retNws = append(retNws, nw)
82
-		}
83
-	}
84
-	return retNws, nil
85
-}
86
-
87 59
 // FilterNetworks filters network list according to user specified filter
88 60
 // and returns user chosen networks
89 61
 func FilterNetworks(nws []libnetwork.Network, filter filters.Args) ([]libnetwork.Network, error) {
... ...
@@ -93,18 +49,40 @@ func FilterNetworks(nws []libnetwork.Network, filter filters.Args) ([]libnetwork
93 93
 	}
94 94
 
95 95
 	var displayNet []libnetwork.Network
96
-	for fkey, fhandler := range supportedFilters {
97
-		errFilter := filter.WalkValues(fkey, func(fval string) error {
98
-			passList, err := fhandler(nws, fval)
96
+	for _, nw := range nws {
97
+		if filter.Include("name") {
98
+			if !filter.Match("name", nw.Name()) {
99
+				continue
100
+			}
101
+		}
102
+		if filter.Include("id") {
103
+			if !filter.Match("id", nw.ID()) {
104
+				continue
105
+			}
106
+		}
107
+		if filter.Include("label") {
108
+			if !filter.MatchKVList("label", nw.Info().Labels()) {
109
+				continue
110
+			}
111
+		}
112
+		displayNet = append(displayNet, nw)
113
+	}
114
+
115
+	if filter.Include("type") {
116
+		var typeNet []libnetwork.Network
117
+		errFilter := filter.WalkValues("type", func(fval string) error {
118
+			passList, err := filterNetworkByType(displayNet, fval)
99 119
 			if err != nil {
100 120
 				return err
101 121
 			}
102
-			displayNet = append(displayNet, passList...)
122
+			typeNet = append(typeNet, passList...)
103 123
 			return nil
104 124
 		})
105 125
 		if errFilter != nil {
106 126
 			return nil, errFilter
107 127
 		}
128
+		displayNet = typeNet
108 129
 	}
130
+
109 131
 	return displayNet, nil
110 132
 }
... ...
@@ -118,6 +118,7 @@ This section lists each version from latest to oldest.  Each listing includes a
118 118
 
119 119
 * `POST /containers/create` now takes `StorageOpt` field.
120 120
 * `GET /info` now returns `SecurityOptions` field, showing if `apparmor`, `seccomp`, or `selinux` is supported.
121
+* `GET /networks` now supports filtering by `label`.
121 122
 
122 123
 ### v1.23 API changes
123 124
 
... ...
@@ -2961,8 +2961,9 @@ Content-Type: application/json
2961 2961
 Query Parameters:
2962 2962
 
2963 2963
 - **filters** - JSON encoded network list filter. The filter value is one of:
2964
-  -   `name=<network-name>` Matches all or part of a network name.
2965 2964
   -   `id=<network-id>` Matches all or part of a network id.
2965
+  -   `label=<key>` or `label=<key>=<value>` of a network label.
2966
+  -   `name=<network-name>` Matches all or part of a network name.
2966 2967
   -   `type=["custom"|"builtin"]` Filters networks by type. The `custom` keyword returns all user-defined networks.
2967 2968
 
2968 2969
 Status Codes:
... ...
@@ -52,32 +52,56 @@ Multiple filter flags are combined as an `OR` filter. For example,
52 52
 The currently supported filters are:
53 53
 
54 54
 * id (network's id)
55
+* label (`label=<key>` or `label=<key>=<value>`)
55 56
 * name (network's name)
56 57
 * type (custom|builtin)
57 58
 
58
-#### Type
59
+#### ID
59 60
 
60
-The `type` filter supports two values; `builtin` displays predefined networks
61
-(`bridge`, `none`, `host`), whereas `custom` displays user defined networks.
61
+The `id` filter matches on all or part of a network's ID.
62 62
 
63
-The following filter matches all user defined networks:
63
+The following filter matches all networks with an ID containing the
64
+`63d1ff1f77b0...` string.
64 65
 
65 66
 ```bash
66
-$ docker network ls --filter type=custom
67
+$ docker network ls --filter id=63d1ff1f77b07ca51070a8c227e962238358bd310bde1529cf62e6c307ade161
67 68
 NETWORK ID          NAME                DRIVER
68
-95e74588f40d        foo                 bridge
69 69
 63d1ff1f77b0        dev                 bridge
70 70
 ```
71 71
 
72
-By having this flag it allows for batch cleanup. For example, use this filter
73
-to delete all user defined networks:
72
+You can also filter for a substring in an ID as this shows:
74 73
 
75 74
 ```bash
76
-$ docker network rm `docker network ls --filter type=custom -q`
75
+$ docker network ls --filter id=95e74588f40d
76
+NETWORK ID          NAME                DRIVER
77
+95e74588f40d        foo                 bridge
78
+
79
+$ docker network ls --filter id=95e
80
+NETWORK ID          NAME                DRIVER
81
+95e74588f40d        foo                 bridge
77 82
 ```
78 83
 
79
-A warning will be issued when trying to remove a network that has containers
80
-attached.
84
+#### Label
85
+
86
+The `label` filter matches containers based on the presence of a `label` alone or a `label` and a
87
+value.
88
+
89
+The following filter matches networks with the `usage` label regardless of its value.
90
+
91
+```bash
92
+$ docker network ls -f "label=usage"
93
+NETWORK ID          NAME                DRIVER
94
+db9db329f835        test1               bridge              
95
+f6e212da9dfd        test2               bridge
96
+```
97
+
98
+The following filter matches containers with the `usage` label with the `prod` value.
99
+
100
+```bash
101
+$ docker network ls -f "label=usage=prod"
102
+NETWORK ID          NAME                DRIVER
103
+f6e212da9dfd        test2               bridge
104
+```
81 105
 
82 106
 #### Name
83 107
 
... ...
@@ -100,31 +124,30 @@ NETWORK ID          NAME                DRIVER
100 100
 06e7eef0a170        foobar              bridge
101 101
 ```
102 102
 
103
-#### ID
103
+#### Type
104 104
 
105
-The `id` filter matches on all or part of a network's ID.
105
+The `type` filter supports two values; `builtin` displays predefined networks
106
+(`bridge`, `none`, `host`), whereas `custom` displays user defined networks.
106 107
 
107
-The following filter matches all networks with an ID containing the
108
-`63d1ff1f77b0...` string.
108
+The following filter matches all user defined networks:
109 109
 
110 110
 ```bash
111
-$ docker network ls --filter id=63d1ff1f77b07ca51070a8c227e962238358bd310bde1529cf62e6c307ade161
111
+$ docker network ls --filter type=custom
112 112
 NETWORK ID          NAME                DRIVER
113
+95e74588f40d        foo                 bridge
113 114
 63d1ff1f77b0        dev                 bridge
114 115
 ```
115 116
 
116
-You can also filter for a substring in an ID as this shows:
117
+By having this flag it allows for batch cleanup. For example, use this filter
118
+to delete all user defined networks:
117 119
 
118 120
 ```bash
119
-$ docker network ls --filter id=95e74588f40d
120
-NETWORK ID          NAME                DRIVER
121
-95e74588f40d        foo                 bridge
122
-
123
-$ docker network ls --filter id=95e
124
-NETWORK ID          NAME                DRIVER
125
-95e74588f40d        foo                 bridge
121
+$ docker network rm `docker network ls --filter type=custom -q`
126 122
 ```
127 123
 
124
+A warning will be issued when trying to remove a network that has containers
125
+attached.
126
+
128 127
 ## Related information
129 128
 
130 129
 * [network disconnect ](network_disconnect.md)
... ...
@@ -309,16 +309,23 @@ func (s *DockerNetworkSuite) TestDockerNetworkRmPredefined(c *check.C) {
309 309
 }
310 310
 
311 311
 func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *check.C) {
312
+	testNet := "testnet1"
313
+	testLabel := "foo"
314
+	testValue := "bar"
312 315
 	out, _ := dockerCmd(c, "network", "create", "dev")
313 316
 	defer func() {
314 317
 		dockerCmd(c, "network", "rm", "dev")
318
+		dockerCmd(c, "network", "rm", testNet)
315 319
 	}()
316 320
 	networkID := strings.TrimSpace(out)
317 321
 
318
-	// filter with partial ID and partial name
319
-	// only show 'bridge' and 'dev' network
320
-	out, _ = dockerCmd(c, "network", "ls", "-f", "id="+networkID[0:5], "-f", "name=dge")
321
-	assertNwList(c, out, []string{"bridge", "dev"})
322
+	// filter with partial ID
323
+	// only show 'dev' network
324
+	out, _ = dockerCmd(c, "network", "ls", "-f", "id="+networkID[0:5])
325
+	assertNwList(c, out, []string{"dev"})
326
+
327
+	out, _ = dockerCmd(c, "network", "ls", "-f", "name=dge")
328
+	assertNwList(c, out, []string{"bridge"})
322 329
 
323 330
 	// only show built-in network (bridge, none, host)
324 331
 	out, _ = dockerCmd(c, "network", "ls", "-f", "type=builtin")
... ...
@@ -332,6 +339,19 @@ func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *check.C) {
332 332
 	// it should be equivalent of ls without option
333 333
 	out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom", "-f", "type=builtin")
334 334
 	assertNwList(c, out, []string{"bridge", "dev", "host", "none"})
335
+
336
+	out, _ = dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet)
337
+	assertNwIsAvailable(c, testNet)
338
+
339
+	out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel)
340
+	assertNwList(c, out, []string{testNet})
341
+
342
+	out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel+"="+testValue)
343
+	assertNwList(c, out, []string{testNet})
344
+
345
+	out, _ = dockerCmd(c, "network", "ls", "-f", "label=nonexistent")
346
+	outArr := strings.Split(strings.TrimSpace(out), "\n")
347
+	c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
335 348
 }
336 349
 
337 350
 func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *check.C) {
... ...
@@ -47,32 +47,56 @@ Multiple filter flags are combined as an `OR` filter. For example,
47 47
 The currently supported filters are:
48 48
 
49 49
 * id (network's id)
50
+* label (`label=<key>` or `label=<key>=<value>`)
50 51
 * name (network's name)
51 52
 * type (custom|builtin)
52 53
 
53
-#### Type
54
+#### ID
54 55
 
55
-The `type` filter supports two values; `builtin` displays predefined networks
56
-(`bridge`, `none`, `host`), whereas `custom` displays user defined networks.
56
+The `id` filter matches on all or part of a network's ID.
57 57
 
58
-The following filter matches all user defined networks:
58
+The following filter matches all networks with an ID containing the
59
+`63d1ff1f77b0...` string.
59 60
 
60 61
 ```bash
61
-$ docker network ls --filter type=custom
62
+$ docker network ls --filter id=63d1ff1f77b07ca51070a8c227e962238358bd310bde1529cf62e6c307ade161
62 63
 NETWORK ID          NAME                DRIVER
63
-95e74588f40d        foo                 bridge
64 64
 63d1ff1f77b0        dev                 bridge
65 65
 ```
66 66
 
67
-By having this flag it allows for batch cleanup. For example, use this filter
68
-to delete all user defined networks:
67
+You can also filter for a substring in an ID as this shows:
69 68
 
70 69
 ```bash
71
-$ docker network rm `docker network ls --filter type=custom -q`
70
+$ docker network ls --filter id=95e74588f40d
71
+NETWORK ID          NAME                DRIVER
72
+95e74588f40d        foo                 bridge
73
+
74
+$ docker network ls --filter id=95e
75
+NETWORK ID          NAME                DRIVER
76
+95e74588f40d        foo                 bridge
72 77
 ```
73 78
 
74
-A warning will be issued when trying to remove a network that has containers
75
-attached.
79
+#### Label
80
+
81
+The `label` filter matches containers based on the presence of a `label` alone or a `label` and a
82
+value.
83
+
84
+The following filter matches networks with the `usage` label regardless of its value.
85
+
86
+```bash
87
+$ docker network ls -f "label=usage"
88
+NETWORK ID          NAME                DRIVER
89
+db9db329f835        test1               bridge              
90
+f6e212da9dfd        test2               bridge
91
+```
92
+
93
+The following filter matches containers with the `usage` label with the `prod` value.
94
+
95
+```bash
96
+$ docker network ls -f "label=usage=prod"
97
+NETWORK ID          NAME                DRIVER
98
+f6e212da9dfd        test2               bridge
99
+```
76 100
 
77 101
 #### Name
78 102
 
... ...
@@ -95,31 +119,30 @@ NETWORK ID          NAME                DRIVER
95 95
 06e7eef0a170        foobar              bridge
96 96
 ```
97 97
 
98
-#### ID
98
+#### Type
99 99
 
100
-The `id` filter matches on all or part of a network's ID.
100
+The `type` filter supports two values; `builtin` displays predefined networks
101
+(`bridge`, `none`, `host`), whereas `custom` displays user defined networks.
101 102
 
102
-The following filter matches all networks with an ID containing the
103
-`63d1ff1f77b0...` string.
103
+The following filter matches all user defined networks:
104 104
 
105 105
 ```bash
106
-$ docker network ls --filter id=63d1ff1f77b07ca51070a8c227e962238358bd310bde1529cf62e6c307ade161
106
+$ docker network ls --filter type=custom
107 107
 NETWORK ID          NAME                DRIVER
108
+95e74588f40d        foo                 bridge
108 109
 63d1ff1f77b0        dev                 bridge
109 110
 ```
110 111
 
111
-You can also filter for a substring in an ID as this shows:
112
+By having this flag it allows for batch cleanup. For example, use this filter
113
+to delete all user defined networks:
112 114
 
113 115
 ```bash
114
-$ docker network ls --filter id=95e74588f40d
115
-NETWORK ID          NAME                DRIVER
116
-95e74588f40d        foo                 bridge
117
-
118
-$ docker network ls --filter id=95e
119
-NETWORK ID          NAME                DRIVER
120
-95e74588f40d        foo                 bridge
116
+$ docker network rm `docker network ls --filter type=custom -q`
121 117
 ```
122 118
 
119
+A warning will be issued when trying to remove a network that has containers
120
+attached.
121
+
123 122
 # OPTIONS
124 123
 
125 124
 **-f**, **--filter**=*[]*