Browse code

Add filter for `network ls` to hide predefined net

Add filter support for `network ls` to hide predefined network,
then user can use "docker network rm `docker network ls -f type=custom`"
to delete a bundle of userdefined networks.

Signed-off-by: Zhang Wei <zhangwei555@huawei.com>

Zhang Wei authored on 2015/11/10 17:57:06
Showing 13 changed files
... ...
@@ -65,7 +65,7 @@ type apiClient interface {
65 65
 	NetworkCreate(options types.NetworkCreate) (types.NetworkCreateResponse, error)
66 66
 	NetworkDisconnect(networkID, containerID string) error
67 67
 	NetworkInspect(networkID string) (types.NetworkResource, error)
68
-	NetworkList() ([]types.NetworkResource, error)
68
+	NetworkList(options types.NetworkListOptions) ([]types.NetworkResource, error)
69 69
 	NetworkRemove(networkID string) error
70 70
 	RegistryLogin(auth types.AuthConfig) (types.AuthResponse, error)
71 71
 	ServerVersion() (types.Version, error)
... ...
@@ -3,8 +3,10 @@ package lib
3 3
 import (
4 4
 	"encoding/json"
5 5
 	"net/http"
6
+	"net/url"
6 7
 
7 8
 	"github.com/docker/docker/api/types"
9
+	"github.com/docker/docker/api/types/filters"
8 10
 )
9 11
 
10 12
 // NetworkCreate creates a new network in the docker host.
... ...
@@ -44,9 +46,18 @@ func (cli *Client) NetworkDisconnect(networkID, containerID string) error {
44 44
 }
45 45
 
46 46
 // NetworkList returns the list of networks configured in the docker host.
47
-func (cli *Client) NetworkList() ([]types.NetworkResource, error) {
47
+func (cli *Client) NetworkList(options types.NetworkListOptions) ([]types.NetworkResource, error) {
48
+	query := url.Values{}
49
+	if options.Filters.Len() > 0 {
50
+		filterJSON, err := filters.ToParam(options.Filters)
51
+		if err != nil {
52
+			return nil, err
53
+		}
54
+
55
+		query.Set("filters", filterJSON)
56
+	}
48 57
 	var networkResources []types.NetworkResource
49
-	resp, err := cli.get("/networks", nil, nil)
58
+	resp, err := cli.get("/networks", query, nil)
50 59
 	if err != nil {
51 60
 		return networkResources, err
52 61
 	}
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"text/tabwriter"
8 8
 
9 9
 	"github.com/docker/docker/api/types"
10
+	"github.com/docker/docker/api/types/filters"
10 11
 	"github.com/docker/docker/api/types/network"
11 12
 	Cli "github.com/docker/docker/cli"
12 13
 	"github.com/docker/docker/opts"
... ...
@@ -138,12 +139,29 @@ func (cli *DockerCli) CmdNetworkLs(args ...string) error {
138 138
 	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
139 139
 	noTrunc := cmd.Bool([]string{"-no-trunc"}, false, "Do not truncate the output")
140 140
 
141
+	flFilter := opts.NewListOpts(nil)
142
+	cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
143
+
141 144
 	cmd.Require(flag.Exact, 0)
142
-	if err := cmd.ParseFlags(args, true); err != nil {
145
+	err := cmd.ParseFlags(args, true)
146
+	if err != nil {
143 147
 		return err
144 148
 	}
145 149
 
146
-	networkResources, err := cli.client.NetworkList()
150
+	// Consolidate all filter flags, and sanity check them early.
151
+	// They'll get process after get response from server.
152
+	netFilterArgs := filters.NewArgs()
153
+	for _, f := range flFilter.GetAll() {
154
+		if netFilterArgs, err = filters.ParseFlag(f, netFilterArgs); err != nil {
155
+			return err
156
+		}
157
+	}
158
+
159
+	options := types.NetworkListOptions{
160
+		Filters: netFilterArgs,
161
+	}
162
+
163
+	networkResources, err := cli.client.NetworkList(options)
147 164
 	if err != nil {
148 165
 		return err
149 166
 	}
... ...
@@ -12,6 +12,7 @@ type Backend interface {
12 12
 	FindNetwork(idName string) (libnetwork.Network, error)
13 13
 	GetNetwork(idName string, by int) (libnetwork.Network, error)
14 14
 	GetNetworksByID(partialID string) []libnetwork.Network
15
+	GetAllNetworks() []libnetwork.Network
15 16
 	CreateNetwork(name, driver string, ipam network.IPAM,
16 17
 		options map[string]string) (libnetwork.Network, error)
17 18
 	ConnectContainerToNetwork(containerName, networkName string) error
18 19
new file mode 100644
... ...
@@ -0,0 +1,110 @@
0
+package network
1
+
2
+import (
3
+	"fmt"
4
+	"regexp"
5
+	"strings"
6
+
7
+	"github.com/docker/docker/api/types/filters"
8
+	"github.com/docker/docker/runconfig"
9
+	"github.com/docker/libnetwork"
10
+)
11
+
12
+type filterHandler func([]libnetwork.Network, string) ([]libnetwork.Network, error)
13
+
14
+var (
15
+	// supportedFilters predefined some supported filter handler function
16
+	supportedFilters = map[string]filterHandler{
17
+		"type": filterNetworkByType,
18
+		"name": filterNetworkByName,
19
+		"id":   filterNetworkByID,
20
+	}
21
+
22
+	// acceptFilters is an acceptable filter flag list
23
+	// generated for validation. e.g.
24
+	// acceptedFilters = map[string]bool{
25
+	//     "type": true,
26
+	//     "name": true,
27
+	//     "id":   true,
28
+	// }
29
+	acceptedFilters = func() map[string]bool {
30
+		ret := make(map[string]bool)
31
+		for k := range supportedFilters {
32
+			ret[k] = true
33
+		}
34
+		return ret
35
+	}()
36
+)
37
+
38
+func filterNetworkByType(nws []libnetwork.Network, netType string) (retNws []libnetwork.Network, err error) {
39
+	switch netType {
40
+	case "builtin":
41
+		for _, nw := range nws {
42
+			if runconfig.IsPreDefinedNetwork(nw.Name()) {
43
+				retNws = append(retNws, nw)
44
+			}
45
+		}
46
+	case "custom":
47
+		for _, nw := range nws {
48
+			if !runconfig.IsPreDefinedNetwork(nw.Name()) {
49
+				retNws = append(retNws, nw)
50
+			}
51
+		}
52
+	default:
53
+		return nil, fmt.Errorf("Invalid filter: 'type'='%s'", netType)
54
+	}
55
+	return retNws, nil
56
+}
57
+
58
+func filterNetworkByName(nws []libnetwork.Network, name string) (retNws []libnetwork.Network, err error) {
59
+	for _, nw := range nws {
60
+		// exact match (fast path)
61
+		if nw.Name() == name {
62
+			retNws = append(retNws, nw)
63
+			continue
64
+		}
65
+
66
+		// regexp match (slow path)
67
+		match, err := regexp.MatchString(name, nw.Name())
68
+		if err != nil || !match {
69
+			continue
70
+		} else {
71
+			retNws = append(retNws, nw)
72
+		}
73
+	}
74
+	return retNws, nil
75
+}
76
+
77
+func filterNetworkByID(nws []libnetwork.Network, id string) (retNws []libnetwork.Network, err error) {
78
+	for _, nw := range nws {
79
+		if strings.HasPrefix(nw.ID(), id) {
80
+			retNws = append(retNws, nw)
81
+		}
82
+	}
83
+	return retNws, nil
84
+}
85
+
86
+// filterAllNetworks filter network list according to user specified filter
87
+// and return user chosen networks
88
+func filterNetworks(nws []libnetwork.Network, filter filters.Args) ([]libnetwork.Network, error) {
89
+	// if filter is empty, return original network list
90
+	if filter.Len() == 0 {
91
+		return nws, nil
92
+	}
93
+
94
+	var displayNet []libnetwork.Network
95
+	for fkey, fhandler := range supportedFilters {
96
+		errFilter := filter.WalkValues(fkey, func(fval string) error {
97
+			passList, err := fhandler(nws, fval)
98
+			if err != nil {
99
+				return err
100
+			}
101
+			displayNet = append(displayNet, passList...)
102
+			return nil
103
+		})
104
+		if errFilter != nil {
105
+			return nil, errFilter
106
+		}
107
+	}
108
+	return displayNet, nil
109
+}
... ...
@@ -7,7 +7,6 @@ import (
7 7
 
8 8
 	"golang.org/x/net/context"
9 9
 
10
-	"github.com/Sirupsen/logrus"
11 10
 	"github.com/docker/docker/api/server/httputils"
12 11
 	"github.com/docker/docker/api/types"
13 12
 	"github.com/docker/docker/api/types/filters"
... ...
@@ -28,29 +27,24 @@ func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWrit
28 28
 		return err
29 29
 	}
30 30
 
31
-	list := []*types.NetworkResource{}
32
-	netFilters.WalkValues("name", func(name string) error {
33
-		if nw, err := n.backend.GetNetwork(name, daemon.NetworkByName); err == nil {
34
-			list = append(list, buildNetworkResource(nw))
35
-		} else {
36
-			logrus.Errorf("failed to get network for filter=%s : %v", name, err)
31
+	if netFilters.Len() != 0 {
32
+		if err := netFilters.Validate(acceptedFilters); err != nil {
33
+			return err
37 34
 		}
38
-		return nil
39
-	})
35
+	}
40 36
 
41
-	netFilters.WalkValues("id", func(id string) error {
42
-		for _, nw := range n.backend.GetNetworksByID(id) {
43
-			list = append(list, buildNetworkResource(nw))
44
-		}
45
-		return nil
46
-	})
37
+	list := []*types.NetworkResource{}
47 38
 
48
-	if !netFilters.Include("name") && !netFilters.Include("id") {
49
-		nwList := n.backend.GetNetworksByID("")
50
-		for _, nw := range nwList {
51
-			list = append(list, buildNetworkResource(nw))
52
-		}
39
+	nwList := n.backend.GetAllNetworks()
40
+	displayable, err := filterNetworks(nwList, netFilters)
41
+	if err != nil {
42
+		return err
53 43
 	}
44
+
45
+	for _, nw := range displayable {
46
+		list = append(list, buildNetworkResource(nw))
47
+	}
48
+
54 49
 	return httputils.WriteJSON(w, http.StatusOK, list)
55 50
 }
56 51
 
... ...
@@ -86,6 +86,11 @@ type EventsOptions struct {
86 86
 	Filters filters.Args
87 87
 }
88 88
 
89
+// NetworkListOptions holds parameters to filter the list of networks with.
90
+type NetworkListOptions struct {
91
+	Filters filters.Args
92
+}
93
+
89 94
 // HijackedResponse holds connection information for a hijacked request.
90 95
 type HijackedResponse struct {
91 96
 	Conn   net.Conn
... ...
@@ -85,6 +85,19 @@ func (daemon *Daemon) GetNetworksByID(partialID string) []libnetwork.Network {
85 85
 	return list
86 86
 }
87 87
 
88
+// GetAllNetworks returns a list containing all networks
89
+func (daemon *Daemon) GetAllNetworks() []libnetwork.Network {
90
+	c := daemon.netController
91
+	list := []libnetwork.Network{}
92
+	l := func(nw libnetwork.Network) bool {
93
+		list = append(list, nw)
94
+		return false
95
+	}
96
+	c.WalkNetworks(l)
97
+
98
+	return list
99
+}
100
+
88 101
 // CreateNetwork creates a network with the given name, driver and other optional parameters
89 102
 func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, options map[string]string) (libnetwork.Network, error) {
90 103
 	c := daemon.netController
... ...
@@ -109,6 +109,7 @@ This section lists each version from latest to oldest.  Each listing includes a
109 109
   the push or pull completes.
110 110
 * `POST /containers/create` now allows you to set a read/write rate limit for a 
111 111
   device (in bytes per second or IO per second).
112
+* `GET /networks` now supports filtering by `name`, `id` and `type`.
112 113
 
113 114
 ### v1.21 API changes
114 115
 
... ...
@@ -2728,7 +2728,7 @@ Status Codes
2728 2728
 
2729 2729
 **Example request**:
2730 2730
 
2731
-    GET /networks HTTP/1.1
2731
+    GET /networks?filters={"type":{"custom":true}} HTTP/1.1
2732 2732
 
2733 2733
 **Example response**:
2734 2734
 
... ...
@@ -2794,11 +2794,12 @@ Content-Type: application/json
2794 2794
 ]
2795 2795
 ```
2796 2796
 
2797
-
2798
-
2799 2797
 Query Parameters:
2800 2798
 
2801
-- **filters** - JSON encoded value of the filters (a `map[string][]string`) to process on the networks list. Available filters: `name=[network-names]` , `id=[network-ids]`
2799
+- **filters** - JSON encoded network list filter. The filter value is one of: 
2800
+  -   `name=<network-name>` Matches all or part of a network name.
2801
+  -   `id=<network-id>` Matches all or part of a network id.
2802
+  -   `type=["custom"|"builtin"]` Filters networks by type. The `custom` keyword returns all user-defined networks.
2802 2803
 
2803 2804
 Status Codes:
2804 2805
 
... ...
@@ -13,6 +13,7 @@ parent = "smn_cli"
13 13
     Usage:  docker network ls [OPTIONS]
14 14
 
15 15
     Lists all the networks created by the user
16
+      -f, --filter=[]       Filter output based on conditions provided
16 17
       --help=false          Print usage
17 18
       --no-trunc=false      Do not truncate the output
18 19
       -q, --quiet=false     Only display numeric IDs
... ...
@@ -38,8 +39,91 @@ NETWORK ID                                                         NAME
38 38
 c288470c46f6c8949c5f7e5099b5b7947b07eabe8d9a27d79a9cbf111adcbf47   host                host                
39 39
 7b369448dccbf865d397c8d2be0cda7cf7edc6b0945f77d2529912ae917a0185   bridge              bridge              
40 40
 95e74588f40db048e86320c6526440c504650a1ff3e9f7d60a497c4d2163e5bd   foo                 bridge    
41
+63d1ff1f77b07ca51070a8c227e962238358bd310bde1529cf62e6c307ade161   dev                 bridge
41 42
 ```
42 43
 
44
+## Filtering
45
+
46
+The filtering flag (`-f` or `--filter`) format is a `key=value` pair. If there
47
+is more than one filter, then pass multiple flags (e.g. `--filter "foo=bar" --filter "bif=baz"`).
48
+Multiple filter flags are combined as an `OR` filter. For example, 
49
+`-f type=custom -f type=builtin` returns both `custom` and `builtin` networks.
50
+
51
+The currently supported filters are:
52
+
53
+* id (network's id)
54
+* name (network's name)
55
+* type (custom|builtin)
56
+
57
+#### Type
58
+
59
+The `type` filter supports two values; `builtin` displays predefined networks
60
+(`bridge`, `none`, `host`), whereas `custom` displays user defined networks.
61
+
62
+The following filter matches all user defined networks:
63
+
64
+```bash
65
+$ docker network ls --filter type=custom
66
+NETWORK ID          NAME                DRIVER
67
+95e74588f40d        foo                 bridge
68
+63d1ff1f77b0        dev                 bridge
69
+```
70
+
71
+By having this flag it allows for batch cleanup. For example, use this filter
72
+to delete all user defined networks:
73
+
74
+```bash
75
+$ docker network rm `docker network ls --filter type=custom -q`
76
+```
77
+
78
+A warning will be issued when trying to remove a network that has containers
79
+attached.
80
+
81
+#### Name
82
+
83
+The `name` filter matches on all or part of a network's name.
84
+
85
+The following filter matches all networks with a name containing the `foobar` string.
86
+
87
+```bash
88
+$ docker network ls --filter name=foobar
89
+NETWORK ID          NAME                DRIVER
90
+06e7eef0a170        foobar              bridge
91
+```
92
+
93
+You can also filter for a substring in a name as this shows:
94
+
95
+```bash
96
+$ docker ps --filter name=foo
97
+NETWORK ID          NAME                DRIVER
98
+95e74588f40d        foo                 bridge
99
+06e7eef0a170        foobar              bridge
100
+```
101
+
102
+#### ID
103
+
104
+The `id` filter matches on all or part of a network's ID.
105
+
106
+The following filter matches all networks with a name containing the
107
+`06e7eef01700` string.
108
+
109
+```bash
110
+$ docker network ls --filter id=63d1ff1f77b07ca51070a8c227e962238358bd310bde1529cf62e6c307ade161
111
+NETWORK ID          NAME                DRIVER
112
+63d1ff1f77b0        dev                 bridge
113
+```
114
+
115
+You can also filter for a substring in a ID as this shows:
116
+
117
+```bash
118
+$ docker ps --filter id=95e74588f40d
119
+NETWORK ID          NAME                DRIVER
120
+95e74588f40d        foo                 bridge
121
+
122
+$ docker ps --filter id=95e
123
+NETWORK ID          NAME                DRIVER
124
+95e74588f40d        foo                 bridge
125
+```
43 126
 
44 127
 ## Related information
45 128
 
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"net/http"
11 11
 	"net/http/httptest"
12 12
 	"os"
13
+	"sort"
13 14
 	"strings"
14 15
 
15 16
 	"github.com/docker/docker/api/types"
... ...
@@ -242,6 +243,25 @@ func isNwPresent(c *check.C, name string) bool {
242 242
 	return false
243 243
 }
244 244
 
245
+// assertNwList checks network list retrived with ls command
246
+// equals to expected network list
247
+// note: out should be `network ls [option]` result
248
+func assertNwList(c *check.C, out string, expectNws []string) {
249
+	lines := strings.Split(out, "\n")
250
+	var nwList []string
251
+	for _, line := range lines[1 : len(lines)-1] {
252
+		netFields := strings.Fields(line)
253
+		// wrap all network name in nwList
254
+		nwList = append(nwList, netFields[1])
255
+	}
256
+	// first need to sort out and expected
257
+	sort.StringSlice(nwList).Sort()
258
+	sort.StringSlice(expectNws).Sort()
259
+
260
+	// network ls should contains all expected networks
261
+	c.Assert(nwList, checker.DeepEquals, expectNws)
262
+}
263
+
245 264
 func getNwResource(c *check.C, name string) *types.NetworkResource {
246 265
 	out, _ := dockerCmd(c, "network", "inspect", name)
247 266
 	nr := []types.NetworkResource{}
... ...
@@ -257,6 +277,32 @@ func (s *DockerNetworkSuite) TestDockerNetworkLsDefault(c *check.C) {
257 257
 	}
258 258
 }
259 259
 
260
+func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *check.C) {
261
+	out, _ := dockerCmd(c, "network", "create", "dev")
262
+	defer func() {
263
+		dockerCmd(c, "network", "rm", "dev")
264
+	}()
265
+	containerID := strings.TrimSpace(out)
266
+
267
+	// filter with partial ID and partial name
268
+	// only show 'bridge' and 'dev' network
269
+	out, _ = dockerCmd(c, "network", "ls", "-f", "id="+containerID[0:5], "-f", "name=dge")
270
+	assertNwList(c, out, []string{"dev", "bridge"})
271
+
272
+	// only show built-in network (bridge, none, host)
273
+	out, _ = dockerCmd(c, "network", "ls", "-f", "type=builtin")
274
+	assertNwList(c, out, []string{"bridge", "none", "host"})
275
+
276
+	// only show custom networks (dev)
277
+	out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom")
278
+	assertNwList(c, out, []string{"dev"})
279
+
280
+	// show all networks with filter
281
+	// it should be equivalent of ls without option
282
+	out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom", "-f", "type=builtin")
283
+	assertNwList(c, out, []string{"dev", "bridge", "host", "none"})
284
+}
285
+
260 286
 func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *check.C) {
261 287
 	dockerCmd(c, "network", "create", "test")
262 288
 	assertNwIsAvailable(c, "test")
... ...
@@ -6,6 +6,7 @@ docker-network-ls - list networks
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker network ls**
9
+[**-f**|**--filter**[=*[]*]]
9 10
 [**--no-trunc**[=*true*|*false*]]
10 11
 [**-q**|**--quiet**[=*true*|*false*]]
11 12
 [**--help**]
... ...
@@ -16,7 +17,7 @@ Lists all the networks the Engine `daemon` knows about. This includes the
16 16
 networks that span across multiple hosts in a cluster, for example:
17 17
 
18 18
 ```bash
19
-    $ sudo docker network ls
19
+    $ docker network ls
20 20
     NETWORK ID          NAME                DRIVER
21 21
     7fca4eb8c647        bridge              bridge
22 22
     9f904ee27bf5        none                null
... ...
@@ -27,16 +28,103 @@ networks that span across multiple hosts in a cluster, for example:
27 27
 Use the `--no-trunc` option to display the full network id:
28 28
 
29 29
 ```bash
30
-docker network ls --no-trunc
30
+$ docker network ls --no-trunc
31 31
 NETWORK ID                                                         NAME                DRIVER
32 32
 18a2866682b85619a026c81b98a5e375bd33e1b0936a26cc497c283d27bae9b3   none                null                
33 33
 c288470c46f6c8949c5f7e5099b5b7947b07eabe8d9a27d79a9cbf111adcbf47   host                host                
34 34
 7b369448dccbf865d397c8d2be0cda7cf7edc6b0945f77d2529912ae917a0185   bridge              bridge              
35 35
 95e74588f40db048e86320c6526440c504650a1ff3e9f7d60a497c4d2163e5bd   foo                 bridge    
36
+63d1ff1f77b07ca51070a8c227e962238358bd310bde1529cf62e6c307ade161   dev                 bridge
37
+```
38
+
39
+## Filtering
40
+
41
+The filtering flag (`-f` or `--filter`) format is a `key=value` pair. If there
42
+is more than one filter, then pass multiple flags (e.g. `--filter "foo=bar" --filter "bif=baz"`).
43
+Multiple filter flags are combined as an `OR` filter. For example, 
44
+`-f type=custom -f type=builtin` returns both `custom` and `builtin` networks.
45
+
46
+The currently supported filters are:
47
+
48
+* id (network's id)
49
+* name (network's name)
50
+* type (custom|builtin)
51
+
52
+#### Type
53
+
54
+The `type` filter supports two values; `builtin` displays predefined networks
55
+(`bridge`, `none`, `host`), whereas `custom` displays user defined networks.
56
+
57
+The following filter matches all user defined networks:
58
+
59
+```bash
60
+$ docker network ls --filter type=custom
61
+NETWORK ID          NAME                DRIVER
62
+95e74588f40d        foo                 bridge
63
+63d1ff1f77b0        dev                 bridge
64
+```
65
+
66
+By having this flag it allows for batch cleanup. For example, use this filter
67
+to delete all user defined networks:
68
+
69
+```bash
70
+$ docker network rm `docker network ls --filter type=custom -q`
71
+```
72
+
73
+A warning will be issued when trying to remove a network that has containers
74
+attached.
75
+
76
+#### Name
77
+
78
+The `name` filter matches on all or part of a network's name.
79
+
80
+The following filter matches all networks with a name containing the `foobar` string.
81
+
82
+```bash
83
+$ docker network ls --filter name=foobar
84
+NETWORK ID          NAME                DRIVER
85
+06e7eef0a170        foobar              bridge
86
+```
87
+
88
+You can also filter for a substring in a name as this shows:
89
+
90
+```bash
91
+$ docker ps --filter name=foo
92
+NETWORK ID          NAME                DRIVER
93
+95e74588f40d        foo                 bridge
94
+06e7eef0a170        foobar              bridge
95
+```
96
+
97
+#### ID
98
+
99
+The `id` filter matches on all or part of a network's ID.
100
+
101
+The following filter matches all networks with a name containing the
102
+`06e7eef01700` string.
103
+
104
+```bash
105
+$ docker network ls --filter id=63d1ff1f77b07ca51070a8c227e962238358bd310bde1529cf62e6c307ade161
106
+NETWORK ID          NAME                DRIVER
107
+63d1ff1f77b0        dev                 bridge
108
+```
109
+
110
+You can also filter for a substring in a ID as this shows:
111
+
112
+```bash
113
+$ docker ps --filter id=95e74588f40d
114
+NETWORK ID          NAME                DRIVER
115
+95e74588f40d        foo                 bridge
116
+
117
+$ docker ps --filter id=95e
118
+NETWORK ID          NAME                DRIVER
119
+95e74588f40d        foo                 bridge
36 120
 ```
37 121
 
38 122
 # OPTIONS
39 123
 
124
+**-f**, **--filter**=*[]*
125
+  filter output based on conditions provided. 
126
+
40 127
 **--no-trunc**=*true*|*false*
41 128
   Do not truncate the output
42 129