1package network // import "github.com/docker/docker/daemon/network"
2
3import (
4	"github.com/docker/docker/api/types"
5	"github.com/docker/docker/api/types/filters"
6	"github.com/docker/docker/errdefs"
7	"github.com/docker/docker/runconfig"
8	"github.com/pkg/errors"
9)
10
11// FilterNetworks filters network list according to user specified filter
12// and returns user chosen networks
13func FilterNetworks(nws []types.NetworkResource, filter filters.Args) ([]types.NetworkResource, error) {
14	// if filter is empty, return original network list
15	if filter.Len() == 0 {
16		return nws, nil
17	}
18
19	displayNet := nws[:0]
20	for _, nw := range nws {
21		if filter.Contains("driver") {
22			if !filter.ExactMatch("driver", nw.Driver) {
23				continue
24			}
25		}
26		if filter.Contains("name") {
27			if !filter.Match("name", nw.Name) {
28				continue
29			}
30		}
31		if filter.Contains("id") {
32			if !filter.Match("id", nw.ID) {
33				continue
34			}
35		}
36		if filter.Contains("label") {
37			if !filter.MatchKVList("label", nw.Labels) {
38				continue
39			}
40		}
41		if filter.Contains("scope") {
42			if !filter.ExactMatch("scope", nw.Scope) {
43				continue
44			}
45		}
46
47		if filter.Contains("idOrName") {
48			if !filter.Match("name", nw.Name) && !filter.Match("id", nw.Name) {
49				continue
50			}
51		}
52		displayNet = append(displayNet, nw)
53	}
54
55	if values := filter.Get("dangling"); len(values) > 0 {
56		if len(values) > 1 {
57			return nil, errdefs.InvalidParameter(errors.New(`got more than one value for filter key "dangling"`))
58		}
59
60		var danglingOnly bool
61		switch values[0] {
62		case "0", "false":
63			// dangling is false already
64		case "1", "true":
65			danglingOnly = true
66		default:
67			return nil, errdefs.InvalidParameter(errors.New(`invalid value for filter 'dangling', must be "true" (or "1"), or "false" (or "0")`))
68		}
69
70		displayNet = filterNetworkByUse(displayNet, danglingOnly)
71	}
72
73	if filter.Contains("type") {
74		typeNet := []types.NetworkResource{}
75		errFilter := filter.WalkValues("type", func(fval string) error {
76			passList, err := filterNetworkByType(displayNet, fval)
77			if err != nil {
78				return err
79			}
80			typeNet = append(typeNet, passList...)
81			return nil
82		})
83		if errFilter != nil {
84			return nil, errFilter
85		}
86		displayNet = typeNet
87	}
88
89	return displayNet, nil
90}
91
92func filterNetworkByUse(nws []types.NetworkResource, danglingOnly bool) []types.NetworkResource {
93	retNws := []types.NetworkResource{}
94
95	filterFunc := func(nw types.NetworkResource) bool {
96		if danglingOnly {
97			return !runconfig.IsPreDefinedNetwork(nw.Name) && len(nw.Containers) == 0 && len(nw.Services) == 0
98		}
99		return runconfig.IsPreDefinedNetwork(nw.Name) || len(nw.Containers) > 0 || len(nw.Services) > 0
100	}
101
102	for _, nw := range nws {
103		if filterFunc(nw) {
104			retNws = append(retNws, nw)
105		}
106	}
107
108	return retNws
109}
110
111func filterNetworkByType(nws []types.NetworkResource, netType string) ([]types.NetworkResource, error) {
112	retNws := []types.NetworkResource{}
113	switch netType {
114	case "builtin":
115		for _, nw := range nws {
116			if runconfig.IsPreDefinedNetwork(nw.Name) {
117				retNws = append(retNws, nw)
118			}
119		}
120	case "custom":
121		for _, nw := range nws {
122			if !runconfig.IsPreDefinedNetwork(nw.Name) {
123				retNws = append(retNws, nw)
124			}
125		}
126	default:
127		return nil, errors.Errorf("invalid filter: 'type'='%s'", netType)
128	}
129	return retNws, nil
130}
131