This stuff doesn't belong here and is causing imports of libnetwork into
the router, which is not what we want.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
| ... | ... |
@@ -13,7 +13,7 @@ import ( |
| 13 | 13 |
// to provide network specific functionality. |
| 14 | 14 |
type Backend interface {
|
| 15 | 15 |
FindNetwork(idName string) (libnetwork.Network, error) |
| 16 |
- GetNetworks() []libnetwork.Network |
|
| 16 |
+ GetNetworks(filters.Args, types.NetworkListConfig) ([]types.NetworkResource, error) |
|
| 17 | 17 |
CreateNetwork(nc types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) |
| 18 | 18 |
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error |
| 19 | 19 |
DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error |
| ... | ... |
@@ -24,7 +24,7 @@ type Backend interface {
|
| 24 | 24 |
// ClusterBackend is all the methods that need to be implemented |
| 25 | 25 |
// to provide cluster network specific functionality. |
| 26 | 26 |
type ClusterBackend interface {
|
| 27 |
- GetNetworks() ([]types.NetworkResource, error) |
|
| 27 |
+ GetNetworks(filters.Args) ([]types.NetworkResource, error) |
|
| 28 | 28 |
GetNetwork(name string) (types.NetworkResource, error) |
| 29 | 29 |
GetNetworksByName(name string) ([]types.NetworkResource, error) |
| 30 | 30 |
CreateNetwork(nc types.NetworkCreateRequest) (string, error) |
| ... | ... |
@@ -1,93 +1 @@ |
| 1 | 1 |
package network // import "github.com/docker/docker/api/server/router/network" |
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "github.com/docker/docker/api/types" |
|
| 5 |
- "github.com/docker/docker/api/types/filters" |
|
| 6 |
- "github.com/docker/docker/runconfig" |
|
| 7 |
-) |
|
| 8 |
- |
|
| 9 |
-func filterNetworkByType(nws []types.NetworkResource, netType string) ([]types.NetworkResource, error) {
|
|
| 10 |
- retNws := []types.NetworkResource{}
|
|
| 11 |
- switch netType {
|
|
| 12 |
- case "builtin": |
|
| 13 |
- for _, nw := range nws {
|
|
| 14 |
- if runconfig.IsPreDefinedNetwork(nw.Name) {
|
|
| 15 |
- retNws = append(retNws, nw) |
|
| 16 |
- } |
|
| 17 |
- } |
|
| 18 |
- case "custom": |
|
| 19 |
- for _, nw := range nws {
|
|
| 20 |
- if !runconfig.IsPreDefinedNetwork(nw.Name) {
|
|
| 21 |
- retNws = append(retNws, nw) |
|
| 22 |
- } |
|
| 23 |
- } |
|
| 24 |
- default: |
|
| 25 |
- return nil, invalidFilter(netType) |
|
| 26 |
- } |
|
| 27 |
- return retNws, nil |
|
| 28 |
-} |
|
| 29 |
- |
|
| 30 |
-type invalidFilter string |
|
| 31 |
- |
|
| 32 |
-func (e invalidFilter) Error() string {
|
|
| 33 |
- return "Invalid filter: 'type'='" + string(e) + "'" |
|
| 34 |
-} |
|
| 35 |
- |
|
| 36 |
-func (e invalidFilter) InvalidParameter() {}
|
|
| 37 |
- |
|
| 38 |
-// filterNetworks filters network list according to user specified filter |
|
| 39 |
-// and returns user chosen networks |
|
| 40 |
-func filterNetworks(nws []types.NetworkResource, filter filters.Args) ([]types.NetworkResource, error) {
|
|
| 41 |
- // if filter is empty, return original network list |
|
| 42 |
- if filter.Len() == 0 {
|
|
| 43 |
- return nws, nil |
|
| 44 |
- } |
|
| 45 |
- |
|
| 46 |
- displayNet := []types.NetworkResource{}
|
|
| 47 |
- for _, nw := range nws {
|
|
| 48 |
- if filter.Contains("driver") {
|
|
| 49 |
- if !filter.ExactMatch("driver", nw.Driver) {
|
|
| 50 |
- continue |
|
| 51 |
- } |
|
| 52 |
- } |
|
| 53 |
- if filter.Contains("name") {
|
|
| 54 |
- if !filter.Match("name", nw.Name) {
|
|
| 55 |
- continue |
|
| 56 |
- } |
|
| 57 |
- } |
|
| 58 |
- if filter.Contains("id") {
|
|
| 59 |
- if !filter.Match("id", nw.ID) {
|
|
| 60 |
- continue |
|
| 61 |
- } |
|
| 62 |
- } |
|
| 63 |
- if filter.Contains("label") {
|
|
| 64 |
- if !filter.MatchKVList("label", nw.Labels) {
|
|
| 65 |
- continue |
|
| 66 |
- } |
|
| 67 |
- } |
|
| 68 |
- if filter.Contains("scope") {
|
|
| 69 |
- if !filter.ExactMatch("scope", nw.Scope) {
|
|
| 70 |
- continue |
|
| 71 |
- } |
|
| 72 |
- } |
|
| 73 |
- displayNet = append(displayNet, nw) |
|
| 74 |
- } |
|
| 75 |
- |
|
| 76 |
- if filter.Contains("type") {
|
|
| 77 |
- typeNet := []types.NetworkResource{}
|
|
| 78 |
- errFilter := filter.WalkValues("type", func(fval string) error {
|
|
| 79 |
- passList, err := filterNetworkByType(displayNet, fval) |
|
| 80 |
- if err != nil {
|
|
| 81 |
- return err |
|
| 82 |
- } |
|
| 83 |
- typeNet = append(typeNet, passList...) |
|
| 84 |
- return nil |
|
| 85 |
- }) |
|
| 86 |
- if errFilter != nil {
|
|
| 87 |
- return nil, errFilter |
|
| 88 |
- } |
|
| 89 |
- displayNet = typeNet |
|
| 90 |
- } |
|
| 91 |
- |
|
| 92 |
- return displayNet, nil |
|
| 93 |
-} |
| 94 | 2 |
deleted file mode 100644 |
| ... | ... |
@@ -1,149 +0,0 @@ |
| 1 |
-// +build !windows |
|
| 2 |
- |
|
| 3 |
-package network // import "github.com/docker/docker/api/server/router/network" |
|
| 4 |
- |
|
| 5 |
-import ( |
|
| 6 |
- "strings" |
|
| 7 |
- "testing" |
|
| 8 |
- |
|
| 9 |
- "github.com/docker/docker/api/types" |
|
| 10 |
- "github.com/docker/docker/api/types/filters" |
|
| 11 |
-) |
|
| 12 |
- |
|
| 13 |
-func TestFilterNetworks(t *testing.T) {
|
|
| 14 |
- networks := []types.NetworkResource{
|
|
| 15 |
- {
|
|
| 16 |
- Name: "host", |
|
| 17 |
- Driver: "host", |
|
| 18 |
- Scope: "local", |
|
| 19 |
- }, |
|
| 20 |
- {
|
|
| 21 |
- Name: "bridge", |
|
| 22 |
- Driver: "bridge", |
|
| 23 |
- Scope: "local", |
|
| 24 |
- }, |
|
| 25 |
- {
|
|
| 26 |
- Name: "none", |
|
| 27 |
- Driver: "null", |
|
| 28 |
- Scope: "local", |
|
| 29 |
- }, |
|
| 30 |
- {
|
|
| 31 |
- Name: "myoverlay", |
|
| 32 |
- Driver: "overlay", |
|
| 33 |
- Scope: "swarm", |
|
| 34 |
- }, |
|
| 35 |
- {
|
|
| 36 |
- Name: "mydrivernet", |
|
| 37 |
- Driver: "mydriver", |
|
| 38 |
- Scope: "local", |
|
| 39 |
- }, |
|
| 40 |
- {
|
|
| 41 |
- Name: "mykvnet", |
|
| 42 |
- Driver: "mykvdriver", |
|
| 43 |
- Scope: "global", |
|
| 44 |
- }, |
|
| 45 |
- } |
|
| 46 |
- |
|
| 47 |
- bridgeDriverFilters := filters.NewArgs() |
|
| 48 |
- bridgeDriverFilters.Add("driver", "bridge")
|
|
| 49 |
- |
|
| 50 |
- overlayDriverFilters := filters.NewArgs() |
|
| 51 |
- overlayDriverFilters.Add("driver", "overlay")
|
|
| 52 |
- |
|
| 53 |
- nonameDriverFilters := filters.NewArgs() |
|
| 54 |
- nonameDriverFilters.Add("driver", "noname")
|
|
| 55 |
- |
|
| 56 |
- customDriverFilters := filters.NewArgs() |
|
| 57 |
- customDriverFilters.Add("type", "custom")
|
|
| 58 |
- |
|
| 59 |
- builtinDriverFilters := filters.NewArgs() |
|
| 60 |
- builtinDriverFilters.Add("type", "builtin")
|
|
| 61 |
- |
|
| 62 |
- invalidDriverFilters := filters.NewArgs() |
|
| 63 |
- invalidDriverFilters.Add("type", "invalid")
|
|
| 64 |
- |
|
| 65 |
- localScopeFilters := filters.NewArgs() |
|
| 66 |
- localScopeFilters.Add("scope", "local")
|
|
| 67 |
- |
|
| 68 |
- swarmScopeFilters := filters.NewArgs() |
|
| 69 |
- swarmScopeFilters.Add("scope", "swarm")
|
|
| 70 |
- |
|
| 71 |
- globalScopeFilters := filters.NewArgs() |
|
| 72 |
- globalScopeFilters.Add("scope", "global")
|
|
| 73 |
- |
|
| 74 |
- testCases := []struct {
|
|
| 75 |
- filter filters.Args |
|
| 76 |
- resultCount int |
|
| 77 |
- err string |
|
| 78 |
- }{
|
|
| 79 |
- {
|
|
| 80 |
- filter: bridgeDriverFilters, |
|
| 81 |
- resultCount: 1, |
|
| 82 |
- err: "", |
|
| 83 |
- }, |
|
| 84 |
- {
|
|
| 85 |
- filter: overlayDriverFilters, |
|
| 86 |
- resultCount: 1, |
|
| 87 |
- err: "", |
|
| 88 |
- }, |
|
| 89 |
- {
|
|
| 90 |
- filter: nonameDriverFilters, |
|
| 91 |
- resultCount: 0, |
|
| 92 |
- err: "", |
|
| 93 |
- }, |
|
| 94 |
- {
|
|
| 95 |
- filter: customDriverFilters, |
|
| 96 |
- resultCount: 3, |
|
| 97 |
- err: "", |
|
| 98 |
- }, |
|
| 99 |
- {
|
|
| 100 |
- filter: builtinDriverFilters, |
|
| 101 |
- resultCount: 3, |
|
| 102 |
- err: "", |
|
| 103 |
- }, |
|
| 104 |
- {
|
|
| 105 |
- filter: invalidDriverFilters, |
|
| 106 |
- resultCount: 0, |
|
| 107 |
- err: "Invalid filter: 'type'='invalid'", |
|
| 108 |
- }, |
|
| 109 |
- {
|
|
| 110 |
- filter: localScopeFilters, |
|
| 111 |
- resultCount: 4, |
|
| 112 |
- err: "", |
|
| 113 |
- }, |
|
| 114 |
- {
|
|
| 115 |
- filter: swarmScopeFilters, |
|
| 116 |
- resultCount: 1, |
|
| 117 |
- err: "", |
|
| 118 |
- }, |
|
| 119 |
- {
|
|
| 120 |
- filter: globalScopeFilters, |
|
| 121 |
- resultCount: 1, |
|
| 122 |
- err: "", |
|
| 123 |
- }, |
|
| 124 |
- } |
|
| 125 |
- |
|
| 126 |
- for _, testCase := range testCases {
|
|
| 127 |
- result, err := filterNetworks(networks, testCase.filter) |
|
| 128 |
- if testCase.err != "" {
|
|
| 129 |
- if err == nil {
|
|
| 130 |
- t.Fatalf("expect error '%s', got no error", testCase.err)
|
|
| 131 |
- |
|
| 132 |
- } else if !strings.Contains(err.Error(), testCase.err) {
|
|
| 133 |
- t.Fatalf("expect error '%s', got '%s'", testCase.err, err)
|
|
| 134 |
- } |
|
| 135 |
- } else {
|
|
| 136 |
- if err != nil {
|
|
| 137 |
- t.Fatalf("expect no error, got error '%s'", err)
|
|
| 138 |
- } |
|
| 139 |
- // Make sure result is not nil |
|
| 140 |
- if result == nil {
|
|
| 141 |
- t.Fatal("filterNetworks should not return nil")
|
|
| 142 |
- } |
|
| 143 |
- |
|
| 144 |
- if len(result) != testCase.resultCount {
|
|
| 145 |
- t.Fatalf("expect '%d' networks, got '%d' networks", testCase.resultCount, len(result))
|
|
| 146 |
- } |
|
| 147 |
- } |
|
| 148 |
- } |
|
| 149 |
-} |
| ... | ... |
@@ -15,70 +15,54 @@ import ( |
| 15 | 15 |
"github.com/docker/docker/errdefs" |
| 16 | 16 |
"github.com/docker/libnetwork" |
| 17 | 17 |
netconst "github.com/docker/libnetwork/datastore" |
| 18 |
- "github.com/docker/libnetwork/networkdb" |
|
| 19 | 18 |
"github.com/pkg/errors" |
| 20 | 19 |
) |
| 21 | 20 |
|
| 22 |
-var ( |
|
| 23 |
- // acceptedNetworkFilters is a list of acceptable filters |
|
| 24 |
- acceptedNetworkFilters = map[string]bool{
|
|
| 25 |
- "driver": true, |
|
| 26 |
- "type": true, |
|
| 27 |
- "name": true, |
|
| 28 |
- "id": true, |
|
| 29 |
- "label": true, |
|
| 30 |
- "scope": true, |
|
| 31 |
- } |
|
| 32 |
-) |
|
| 33 |
- |
|
| 34 | 21 |
func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
| 35 | 22 |
if err := httputils.ParseForm(r); err != nil {
|
| 36 | 23 |
return err |
| 37 | 24 |
} |
| 38 | 25 |
|
| 39 |
- filter := r.Form.Get("filters")
|
|
| 40 |
- netFilters, err := filters.FromJSON(filter) |
|
| 26 |
+ filter, err := filters.FromJSON(r.Form.Get("filters"))
|
|
| 41 | 27 |
if err != nil {
|
| 42 | 28 |
return err |
| 43 | 29 |
} |
| 44 | 30 |
|
| 45 |
- if err := netFilters.Validate(acceptedNetworkFilters); err != nil {
|
|
| 31 |
+ if err := network.ValidateFilters(filter); err != nil {
|
|
| 46 | 32 |
return err |
| 47 | 33 |
} |
| 48 | 34 |
|
| 49 |
- list := []types.NetworkResource{}
|
|
| 50 |
- |
|
| 51 |
- if nr, err := n.cluster.GetNetworks(); err == nil {
|
|
| 52 |
- list = append(list, nr...) |
|
| 35 |
+ var list []types.NetworkResource |
|
| 36 |
+ nr, err := n.cluster.GetNetworks(filter) |
|
| 37 |
+ if err == nil {
|
|
| 38 |
+ list = nr |
|
| 53 | 39 |
} |
| 54 | 40 |
|
| 55 | 41 |
// Combine the network list returned by Docker daemon if it is not already |
| 56 | 42 |
// returned by the cluster manager |
| 57 |
-SKIP: |
|
| 58 |
- for _, nw := range n.backend.GetNetworks() {
|
|
| 59 |
- for _, nl := range list {
|
|
| 60 |
- if nl.ID == nw.ID() {
|
|
| 61 |
- continue SKIP |
|
| 62 |
- } |
|
| 63 |
- } |
|
| 43 |
+ localNetworks, err := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: versions.LessThan(httputils.VersionFromContext(ctx), "1.28")})
|
|
| 44 |
+ if err != nil {
|
|
| 45 |
+ return err |
|
| 46 |
+ } |
|
| 64 | 47 |
|
| 65 |
- var nr *types.NetworkResource |
|
| 66 |
- // Versions < 1.28 fetches all the containers attached to a network |
|
| 67 |
- // in a network list api call. It is a heavy weight operation when |
|
| 68 |
- // run across all the networks. Starting API version 1.28, this detailed |
|
| 69 |
- // info is available for network specific GET API (equivalent to inspect) |
|
| 70 |
- if versions.LessThan(httputils.VersionFromContext(ctx), "1.28") {
|
|
| 71 |
- nr = n.buildDetailedNetworkResources(nw, false) |
|
| 72 |
- } else {
|
|
| 73 |
- nr = n.buildNetworkResource(nw) |
|
| 48 |
+ var idx map[string]bool |
|
| 49 |
+ if len(list) > 0 {
|
|
| 50 |
+ idx = make(map[string]bool, len(list)) |
|
| 51 |
+ for _, n := range list {
|
|
| 52 |
+ idx[n.ID] = true |
|
| 74 | 53 |
} |
| 75 |
- list = append(list, *nr) |
|
| 54 |
+ } |
|
| 55 |
+ for _, n := range localNetworks {
|
|
| 56 |
+ if idx[n.ID] {
|
|
| 57 |
+ continue |
|
| 58 |
+ } |
|
| 59 |
+ list = append(list, n) |
|
| 76 | 60 |
} |
| 77 | 61 |
|
| 78 |
- list, err = filterNetworks(list, netFilters) |
|
| 79 |
- if err != nil {
|
|
| 80 |
- return err |
|
| 62 |
+ if list == nil {
|
|
| 63 |
+ list = []types.NetworkResource{}
|
|
| 81 | 64 |
} |
| 65 |
+ |
|
| 82 | 66 |
return httputils.WriteJSON(w, http.StatusOK, list) |
| 83 | 67 |
} |
| 84 | 68 |
|
| ... | ... |
@@ -121,13 +105,6 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r |
| 121 | 121 |
} |
| 122 | 122 |
scope := r.URL.Query().Get("scope")
|
| 123 | 123 |
|
| 124 |
- isMatchingScope := func(scope, term string) bool {
|
|
| 125 |
- if term != "" {
|
|
| 126 |
- return scope == term |
|
| 127 |
- } |
|
| 128 |
- return true |
|
| 129 |
- } |
|
| 130 |
- |
|
| 131 | 124 |
// In case multiple networks have duplicate names, return error. |
| 132 | 125 |
// TODO (yongtang): should we wrap with version here for backward compatibility? |
| 133 | 126 |
|
| ... | ... |
@@ -139,20 +116,26 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r |
| 139 | 139 |
listByFullName := map[string]types.NetworkResource{}
|
| 140 | 140 |
listByPartialID := map[string]types.NetworkResource{}
|
| 141 | 141 |
|
| 142 |
- nw := n.backend.GetNetworks() |
|
| 142 |
+ // TODO(@cpuguy83): All this logic for figuring out which network to return does not belong here |
|
| 143 |
+ // Instead there should be a backend function to just get one network. |
|
| 144 |
+ filter := filters.NewArgs(filters.Arg("idOrName", term))
|
|
| 145 |
+ if scope != "" {
|
|
| 146 |
+ filter.Add("scope", scope)
|
|
| 147 |
+ } |
|
| 148 |
+ nw, _ := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: true, Verbose: verbose})
|
|
| 143 | 149 |
for _, network := range nw {
|
| 144 |
- if network.ID() == term && isMatchingScope(network.Info().Scope(), scope) {
|
|
| 145 |
- return httputils.WriteJSON(w, http.StatusOK, *n.buildDetailedNetworkResources(network, verbose)) |
|
| 150 |
+ if network.ID == term {
|
|
| 151 |
+ return httputils.WriteJSON(w, http.StatusOK, network) |
|
| 146 | 152 |
} |
| 147 |
- if network.Name() == term && isMatchingScope(network.Info().Scope(), scope) {
|
|
| 153 |
+ if network.Name == term {
|
|
| 148 | 154 |
// No need to check the ID collision here as we are still in |
| 149 | 155 |
// local scope and the network ID is unique in this scope. |
| 150 |
- listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network, verbose) |
|
| 156 |
+ listByFullName[network.ID] = network |
|
| 151 | 157 |
} |
| 152 |
- if strings.HasPrefix(network.ID(), term) && isMatchingScope(network.Info().Scope(), scope) {
|
|
| 158 |
+ if strings.HasPrefix(network.ID, term) {
|
|
| 153 | 159 |
// No need to check the ID collision here as we are still in |
| 154 | 160 |
// local scope and the network ID is unique in this scope. |
| 155 |
- listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network, verbose) |
|
| 161 |
+ listByPartialID[network.ID] = network |
|
| 156 | 162 |
} |
| 157 | 163 |
} |
| 158 | 164 |
|
| ... | ... |
@@ -174,12 +157,12 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r |
| 174 | 174 |
} |
| 175 | 175 |
} |
| 176 | 176 |
|
| 177 |
- nr, _ := n.cluster.GetNetworks() |
|
| 177 |
+ nr, _ := n.cluster.GetNetworks(filter) |
|
| 178 | 178 |
for _, network := range nr {
|
| 179 |
- if network.ID == term && isMatchingScope(network.Scope, scope) {
|
|
| 179 |
+ if network.ID == term {
|
|
| 180 | 180 |
return httputils.WriteJSON(w, http.StatusOK, network) |
| 181 | 181 |
} |
| 182 |
- if network.Name == term && isMatchingScope(network.Scope, scope) {
|
|
| 182 |
+ if network.Name == term {
|
|
| 183 | 183 |
// Check the ID collision as we are in swarm scope here, and |
| 184 | 184 |
// the map (of the listByFullName) may have already had a |
| 185 | 185 |
// network with the same ID (from local scope previously) |
| ... | ... |
@@ -187,7 +170,7 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r |
| 187 | 187 |
listByFullName[network.ID] = network |
| 188 | 188 |
} |
| 189 | 189 |
} |
| 190 |
- if strings.HasPrefix(network.ID, term) && isMatchingScope(network.Scope, scope) {
|
|
| 190 |
+ if strings.HasPrefix(network.ID, term) {
|
|
| 191 | 191 |
// Check the ID collision as we are in swarm scope here, and |
| 192 | 192 |
// the map (of the listByPartialID) may have already had a |
| 193 | 193 |
// network with the same ID (from local scope previously) |
| ... | ... |
@@ -327,182 +310,6 @@ func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter |
| 327 | 327 |
return nil |
| 328 | 328 |
} |
| 329 | 329 |
|
| 330 |
-func (n *networkRouter) buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
|
|
| 331 |
- r := &types.NetworkResource{}
|
|
| 332 |
- if nw == nil {
|
|
| 333 |
- return r |
|
| 334 |
- } |
|
| 335 |
- |
|
| 336 |
- info := nw.Info() |
|
| 337 |
- r.Name = nw.Name() |
|
| 338 |
- r.ID = nw.ID() |
|
| 339 |
- r.Created = info.Created() |
|
| 340 |
- r.Scope = info.Scope() |
|
| 341 |
- r.Driver = nw.Type() |
|
| 342 |
- r.EnableIPv6 = info.IPv6Enabled() |
|
| 343 |
- r.Internal = info.Internal() |
|
| 344 |
- r.Attachable = info.Attachable() |
|
| 345 |
- r.Ingress = info.Ingress() |
|
| 346 |
- r.Options = info.DriverOptions() |
|
| 347 |
- r.Containers = make(map[string]types.EndpointResource) |
|
| 348 |
- buildIpamResources(r, info) |
|
| 349 |
- r.Labels = info.Labels() |
|
| 350 |
- r.ConfigOnly = info.ConfigOnly() |
|
| 351 |
- |
|
| 352 |
- if cn := info.ConfigFrom(); cn != "" {
|
|
| 353 |
- r.ConfigFrom = network.ConfigReference{Network: cn}
|
|
| 354 |
- } |
|
| 355 |
- |
|
| 356 |
- peers := info.Peers() |
|
| 357 |
- if len(peers) != 0 {
|
|
| 358 |
- r.Peers = buildPeerInfoResources(peers) |
|
| 359 |
- } |
|
| 360 |
- |
|
| 361 |
- return r |
|
| 362 |
-} |
|
| 363 |
- |
|
| 364 |
-func (n *networkRouter) buildDetailedNetworkResources(nw libnetwork.Network, verbose bool) *types.NetworkResource {
|
|
| 365 |
- if nw == nil {
|
|
| 366 |
- return &types.NetworkResource{}
|
|
| 367 |
- } |
|
| 368 |
- |
|
| 369 |
- r := n.buildNetworkResource(nw) |
|
| 370 |
- epl := nw.Endpoints() |
|
| 371 |
- for _, e := range epl {
|
|
| 372 |
- ei := e.Info() |
|
| 373 |
- if ei == nil {
|
|
| 374 |
- continue |
|
| 375 |
- } |
|
| 376 |
- sb := ei.Sandbox() |
|
| 377 |
- tmpID := e.ID() |
|
| 378 |
- key := "ep-" + tmpID |
|
| 379 |
- if sb != nil {
|
|
| 380 |
- key = sb.ContainerID() |
|
| 381 |
- } |
|
| 382 |
- |
|
| 383 |
- r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei) |
|
| 384 |
- } |
|
| 385 |
- if !verbose {
|
|
| 386 |
- return r |
|
| 387 |
- } |
|
| 388 |
- services := nw.Info().Services() |
|
| 389 |
- r.Services = make(map[string]network.ServiceInfo) |
|
| 390 |
- for name, service := range services {
|
|
| 391 |
- tasks := []network.Task{}
|
|
| 392 |
- for _, t := range service.Tasks {
|
|
| 393 |
- tasks = append(tasks, network.Task{
|
|
| 394 |
- Name: t.Name, |
|
| 395 |
- EndpointID: t.EndpointID, |
|
| 396 |
- EndpointIP: t.EndpointIP, |
|
| 397 |
- Info: t.Info, |
|
| 398 |
- }) |
|
| 399 |
- } |
|
| 400 |
- r.Services[name] = network.ServiceInfo{
|
|
| 401 |
- VIP: service.VIP, |
|
| 402 |
- Ports: service.Ports, |
|
| 403 |
- Tasks: tasks, |
|
| 404 |
- LocalLBIndex: service.LocalLBIndex, |
|
| 405 |
- } |
|
| 406 |
- } |
|
| 407 |
- return r |
|
| 408 |
-} |
|
| 409 |
- |
|
| 410 |
-func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo {
|
|
| 411 |
- peerInfo := make([]network.PeerInfo, 0, len(peers)) |
|
| 412 |
- for _, peer := range peers {
|
|
| 413 |
- peerInfo = append(peerInfo, network.PeerInfo{
|
|
| 414 |
- Name: peer.Name, |
|
| 415 |
- IP: peer.IP, |
|
| 416 |
- }) |
|
| 417 |
- } |
|
| 418 |
- return peerInfo |
|
| 419 |
-} |
|
| 420 |
- |
|
| 421 |
-func buildIpamResources(r *types.NetworkResource, nwInfo libnetwork.NetworkInfo) {
|
|
| 422 |
- id, opts, ipv4conf, ipv6conf := nwInfo.IpamConfig() |
|
| 423 |
- |
|
| 424 |
- ipv4Info, ipv6Info := nwInfo.IpamInfo() |
|
| 425 |
- |
|
| 426 |
- r.IPAM.Driver = id |
|
| 427 |
- |
|
| 428 |
- r.IPAM.Options = opts |
|
| 429 |
- |
|
| 430 |
- r.IPAM.Config = []network.IPAMConfig{}
|
|
| 431 |
- for _, ip4 := range ipv4conf {
|
|
| 432 |
- if ip4.PreferredPool == "" {
|
|
| 433 |
- continue |
|
| 434 |
- } |
|
| 435 |
- iData := network.IPAMConfig{}
|
|
| 436 |
- iData.Subnet = ip4.PreferredPool |
|
| 437 |
- iData.IPRange = ip4.SubPool |
|
| 438 |
- iData.Gateway = ip4.Gateway |
|
| 439 |
- iData.AuxAddress = ip4.AuxAddresses |
|
| 440 |
- r.IPAM.Config = append(r.IPAM.Config, iData) |
|
| 441 |
- } |
|
| 442 |
- |
|
| 443 |
- if len(r.IPAM.Config) == 0 {
|
|
| 444 |
- for _, ip4Info := range ipv4Info {
|
|
| 445 |
- iData := network.IPAMConfig{}
|
|
| 446 |
- iData.Subnet = ip4Info.IPAMData.Pool.String() |
|
| 447 |
- if ip4Info.IPAMData.Gateway != nil {
|
|
| 448 |
- iData.Gateway = ip4Info.IPAMData.Gateway.IP.String() |
|
| 449 |
- } |
|
| 450 |
- r.IPAM.Config = append(r.IPAM.Config, iData) |
|
| 451 |
- } |
|
| 452 |
- } |
|
| 453 |
- |
|
| 454 |
- hasIpv6Conf := false |
|
| 455 |
- for _, ip6 := range ipv6conf {
|
|
| 456 |
- if ip6.PreferredPool == "" {
|
|
| 457 |
- continue |
|
| 458 |
- } |
|
| 459 |
- hasIpv6Conf = true |
|
| 460 |
- iData := network.IPAMConfig{}
|
|
| 461 |
- iData.Subnet = ip6.PreferredPool |
|
| 462 |
- iData.IPRange = ip6.SubPool |
|
| 463 |
- iData.Gateway = ip6.Gateway |
|
| 464 |
- iData.AuxAddress = ip6.AuxAddresses |
|
| 465 |
- r.IPAM.Config = append(r.IPAM.Config, iData) |
|
| 466 |
- } |
|
| 467 |
- |
|
| 468 |
- if !hasIpv6Conf {
|
|
| 469 |
- for _, ip6Info := range ipv6Info {
|
|
| 470 |
- if ip6Info.IPAMData.Pool == nil {
|
|
| 471 |
- continue |
|
| 472 |
- } |
|
| 473 |
- iData := network.IPAMConfig{}
|
|
| 474 |
- iData.Subnet = ip6Info.IPAMData.Pool.String() |
|
| 475 |
- iData.Gateway = ip6Info.IPAMData.Gateway.String() |
|
| 476 |
- r.IPAM.Config = append(r.IPAM.Config, iData) |
|
| 477 |
- } |
|
| 478 |
- } |
|
| 479 |
-} |
|
| 480 |
- |
|
| 481 |
-func buildEndpointResource(id string, name string, info libnetwork.EndpointInfo) types.EndpointResource {
|
|
| 482 |
- er := types.EndpointResource{}
|
|
| 483 |
- |
|
| 484 |
- er.EndpointID = id |
|
| 485 |
- er.Name = name |
|
| 486 |
- ei := info |
|
| 487 |
- if ei == nil {
|
|
| 488 |
- return er |
|
| 489 |
- } |
|
| 490 |
- |
|
| 491 |
- if iface := ei.Iface(); iface != nil {
|
|
| 492 |
- if mac := iface.MacAddress(); mac != nil {
|
|
| 493 |
- er.MacAddress = mac.String() |
|
| 494 |
- } |
|
| 495 |
- if ip := iface.Address(); ip != nil && len(ip.IP) > 0 {
|
|
| 496 |
- er.IPv4Address = ip.String() |
|
| 497 |
- } |
|
| 498 |
- |
|
| 499 |
- if ipv6 := iface.AddressIPv6(); ipv6 != nil && len(ipv6.IP) > 0 {
|
|
| 500 |
- er.IPv6Address = ipv6.String() |
|
| 501 |
- } |
|
| 502 |
- } |
|
| 503 |
- return er |
|
| 504 |
-} |
|
| 505 |
- |
|
| 506 | 330 |
func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
| 507 | 331 |
if err := httputils.ParseForm(r); err != nil {
|
| 508 | 332 |
return err |
| ... | ... |
@@ -532,25 +339,25 @@ func (n *networkRouter) findUniqueNetwork(term string) (types.NetworkResource, e |
| 532 | 532 |
listByFullName := map[string]types.NetworkResource{}
|
| 533 | 533 |
listByPartialID := map[string]types.NetworkResource{}
|
| 534 | 534 |
|
| 535 |
- nw := n.backend.GetNetworks() |
|
| 535 |
+ filter := filters.NewArgs(filters.Arg("idOrName", term))
|
|
| 536 |
+ nw, _ := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: true})
|
|
| 536 | 537 |
for _, network := range nw {
|
| 537 |
- if network.ID() == term {
|
|
| 538 |
- return *n.buildDetailedNetworkResources(network, false), nil |
|
| 539 |
- |
|
| 538 |
+ if network.ID == term {
|
|
| 539 |
+ return network, nil |
|
| 540 | 540 |
} |
| 541 |
- if network.Name() == term && !network.Info().Ingress() {
|
|
| 541 |
+ if network.Name == term && !network.Ingress {
|
|
| 542 | 542 |
// No need to check the ID collision here as we are still in |
| 543 | 543 |
// local scope and the network ID is unique in this scope. |
| 544 |
- listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network, false) |
|
| 544 |
+ listByFullName[network.ID] = network |
|
| 545 | 545 |
} |
| 546 |
- if strings.HasPrefix(network.ID(), term) {
|
|
| 546 |
+ if strings.HasPrefix(network.ID, term) {
|
|
| 547 | 547 |
// No need to check the ID collision here as we are still in |
| 548 | 548 |
// local scope and the network ID is unique in this scope. |
| 549 |
- listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network, false) |
|
| 549 |
+ listByPartialID[network.ID] = network |
|
| 550 | 550 |
} |
| 551 | 551 |
} |
| 552 | 552 |
|
| 553 |
- nr, _ := n.cluster.GetNetworks() |
|
| 553 |
+ nr, _ := n.cluster.GetNetworks(filter) |
|
| 554 | 554 |
for _, network := range nr {
|
| 555 | 555 |
if network.ID == term {
|
| 556 | 556 |
return network, nil |
| ... | ... |
@@ -55,3 +55,10 @@ type PluginEnableConfig struct {
|
| 55 | 55 |
type PluginDisableConfig struct {
|
| 56 | 56 |
ForceDisable bool |
| 57 | 57 |
} |
| 58 |
+ |
|
| 59 |
+// NetworkListConfig stores the options available for listing networks |
|
| 60 |
+type NetworkListConfig struct {
|
|
| 61 |
+ // TODO(@cpuguy83): naming is hard, this is pulled from what was being used in the router before moving here |
|
| 62 |
+ Detailed bool |
|
| 63 |
+ Verbose bool |
|
| 64 |
+} |
| ... | ... |
@@ -1,4 +1,8 @@ |
| 1 | 1 |
package network // import "github.com/docker/docker/api/types/network" |
| 2 |
+import ( |
|
| 3 |
+ "github.com/docker/docker/api/types/filters" |
|
| 4 |
+ "github.com/docker/docker/errdefs" |
|
| 5 |
+) |
|
| 2 | 6 |
|
| 3 | 7 |
// Address represents an IP address |
| 4 | 8 |
type Address struct {
|
| ... | ... |
@@ -106,3 +110,17 @@ type NetworkingConfig struct {
|
| 106 | 106 |
type ConfigReference struct {
|
| 107 | 107 |
Network string |
| 108 | 108 |
} |
| 109 |
+ |
|
| 110 |
+var acceptedFilters = map[string]bool{
|
|
| 111 |
+ "driver": true, |
|
| 112 |
+ "type": true, |
|
| 113 |
+ "name": true, |
|
| 114 |
+ "id": true, |
|
| 115 |
+ "label": true, |
|
| 116 |
+ "scope": true, |
|
| 117 |
+} |
|
| 118 |
+ |
|
| 119 |
+// ValidateFilters validates the list of filter args with the available filters. |
|
| 120 |
+func ValidateFilters(filter filters.Args) error {
|
|
| 121 |
+ return errdefs.InvalidParameter(filter.Validate(acceptedFilters)) |
|
| 122 |
+} |
| ... | ... |
@@ -2,6 +2,7 @@ package daemon // import "github.com/docker/docker/daemon" |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
apitypes "github.com/docker/docker/api/types" |
| 5 |
+ "github.com/docker/docker/api/types/filters" |
|
| 5 | 6 |
lncluster "github.com/docker/libnetwork/cluster" |
| 6 | 7 |
) |
| 7 | 8 |
|
| ... | ... |
@@ -21,6 +22,6 @@ type ClusterStatus interface {
|
| 21 | 21 |
// NetworkManager provides methods to manage networks |
| 22 | 22 |
type NetworkManager interface {
|
| 23 | 23 |
GetNetwork(input string) (apitypes.NetworkResource, error) |
| 24 |
- GetNetworks() ([]apitypes.NetworkResource, error) |
|
| 24 |
+ GetNetworks(filters.Args) ([]apitypes.NetworkResource, error) |
|
| 25 | 25 |
RemoveNetwork(input string) error |
| 26 | 26 |
} |
| ... | ... |
@@ -5,9 +5,11 @@ import ( |
| 5 | 5 |
"fmt" |
| 6 | 6 |
|
| 7 | 7 |
apitypes "github.com/docker/docker/api/types" |
| 8 |
+ "github.com/docker/docker/api/types/filters" |
|
| 8 | 9 |
"github.com/docker/docker/api/types/network" |
| 9 | 10 |
types "github.com/docker/docker/api/types/swarm" |
| 10 | 11 |
"github.com/docker/docker/daemon/cluster/convert" |
| 12 |
+ internalnetwork "github.com/docker/docker/daemon/network" |
|
| 11 | 13 |
"github.com/docker/docker/errdefs" |
| 12 | 14 |
"github.com/docker/docker/runconfig" |
| 13 | 15 |
swarmapi "github.com/docker/swarmkit/api" |
| ... | ... |
@@ -16,16 +18,32 @@ import ( |
| 16 | 16 |
) |
| 17 | 17 |
|
| 18 | 18 |
// GetNetworks returns all current cluster managed networks. |
| 19 |
-func (c *Cluster) GetNetworks() ([]apitypes.NetworkResource, error) {
|
|
| 20 |
- list, err := c.getNetworks(nil) |
|
| 19 |
+func (c *Cluster) GetNetworks(filter filters.Args) ([]apitypes.NetworkResource, error) {
|
|
| 20 |
+ var f *swarmapi.ListNetworksRequest_Filters |
|
| 21 |
+ |
|
| 22 |
+ if filter.Len() > 0 {
|
|
| 23 |
+ f = &swarmapi.ListNetworksRequest_Filters{}
|
|
| 24 |
+ |
|
| 25 |
+ if filter.Contains("name") {
|
|
| 26 |
+ f.Names = filter.Get("name")
|
|
| 27 |
+ f.NamePrefixes = filter.Get("name")
|
|
| 28 |
+ } |
|
| 29 |
+ |
|
| 30 |
+ if filter.Contains("id") {
|
|
| 31 |
+ f.IDPrefixes = filter.Get("id")
|
|
| 32 |
+ } |
|
| 33 |
+ } |
|
| 34 |
+ |
|
| 35 |
+ list, err := c.getNetworks(f) |
|
| 21 | 36 |
if err != nil {
|
| 22 | 37 |
return nil, err |
| 23 | 38 |
} |
| 24 |
- removePredefinedNetworks(&list) |
|
| 25 |
- return list, nil |
|
| 39 |
+ filterPredefinedNetworks(&list) |
|
| 40 |
+ |
|
| 41 |
+ return internalnetwork.FilterNetworks(list, filter) |
|
| 26 | 42 |
} |
| 27 | 43 |
|
| 28 |
-func removePredefinedNetworks(networks *[]apitypes.NetworkResource) {
|
|
| 44 |
+func filterPredefinedNetworks(networks *[]apitypes.NetworkResource) {
|
|
| 29 | 45 |
if networks == nil {
|
| 30 | 46 |
return |
| 31 | 47 |
} |
| ... | ... |
@@ -12,6 +12,7 @@ import ( |
| 12 | 12 |
|
| 13 | 13 |
"github.com/docker/docker/api/types" |
| 14 | 14 |
containertypes "github.com/docker/docker/api/types/container" |
| 15 |
+ "github.com/docker/docker/api/types/filters" |
|
| 15 | 16 |
"github.com/docker/docker/api/types/network" |
| 16 | 17 |
"github.com/docker/docker/container" |
| 17 | 18 |
clustertypes "github.com/docker/docker/daemon/cluster/provider" |
| ... | ... |
@@ -26,6 +27,7 @@ import ( |
| 26 | 26 |
"github.com/docker/libnetwork/driverapi" |
| 27 | 27 |
"github.com/docker/libnetwork/ipamapi" |
| 28 | 28 |
"github.com/docker/libnetwork/netlabel" |
| 29 |
+ "github.com/docker/libnetwork/networkdb" |
|
| 29 | 30 |
"github.com/docker/libnetwork/options" |
| 30 | 31 |
networktypes "github.com/docker/libnetwork/types" |
| 31 | 32 |
"github.com/pkg/errors" |
| ... | ... |
@@ -89,7 +91,7 @@ func (daemon *Daemon) FindNetwork(term string) (libnetwork.Network, error) {
|
| 89 | 89 |
func (daemon *Daemon) GetNetworkByID(id string) (libnetwork.Network, error) {
|
| 90 | 90 |
c := daemon.netController |
| 91 | 91 |
if c == nil {
|
| 92 |
- return nil, libnetwork.ErrNoSuchNetwork(id) |
|
| 92 |
+ return nil, errors.Wrap(libnetwork.ErrNoSuchNetwork(id), "netcontroller is nil") |
|
| 93 | 93 |
} |
| 94 | 94 |
return c.NetworkByID(id) |
| 95 | 95 |
} |
| ... | ... |
@@ -507,7 +509,7 @@ func (daemon *Daemon) DeleteManagedNetwork(networkID string) error {
|
| 507 | 507 |
func (daemon *Daemon) DeleteNetwork(networkID string) error {
|
| 508 | 508 |
n, err := daemon.GetNetworkByID(networkID) |
| 509 | 509 |
if err != nil {
|
| 510 |
- return err |
|
| 510 |
+ return errors.Wrap(err, "could not find network by ID") |
|
| 511 | 511 |
} |
| 512 | 512 |
return daemon.deleteNetwork(n, false) |
| 513 | 513 |
} |
| ... | ... |
@@ -560,7 +562,7 @@ func (daemon *Daemon) deleteNetwork(nw libnetwork.Network, dynamic bool) error {
|
| 560 | 560 |
} |
| 561 | 561 |
|
| 562 | 562 |
if err := nw.Delete(); err != nil {
|
| 563 |
- return err |
|
| 563 |
+ return errors.Wrap(err, "error while removing network") |
|
| 564 | 564 |
} |
| 565 | 565 |
|
| 566 | 566 |
// If this is not a configuration only network, we need to |
| ... | ... |
@@ -576,8 +578,212 @@ func (daemon *Daemon) deleteNetwork(nw libnetwork.Network, dynamic bool) error {
|
| 576 | 576 |
} |
| 577 | 577 |
|
| 578 | 578 |
// GetNetworks returns a list of all networks |
| 579 |
-func (daemon *Daemon) GetNetworks() []libnetwork.Network {
|
|
| 580 |
- return daemon.getAllNetworks() |
|
| 579 |
+func (daemon *Daemon) GetNetworks(filter filters.Args, config types.NetworkListConfig) ([]types.NetworkResource, error) {
|
|
| 580 |
+ networks := daemon.getAllNetworks() |
|
| 581 |
+ |
|
| 582 |
+ list := make([]types.NetworkResource, 0, len(networks)) |
|
| 583 |
+ var idx map[string]libnetwork.Network |
|
| 584 |
+ if config.Detailed {
|
|
| 585 |
+ idx = make(map[string]libnetwork.Network) |
|
| 586 |
+ } |
|
| 587 |
+ |
|
| 588 |
+ for _, n := range networks {
|
|
| 589 |
+ nr := buildNetworkResource(n) |
|
| 590 |
+ list = append(list, nr) |
|
| 591 |
+ if config.Detailed {
|
|
| 592 |
+ idx[nr.ID] = n |
|
| 593 |
+ } |
|
| 594 |
+ } |
|
| 595 |
+ |
|
| 596 |
+ var err error |
|
| 597 |
+ list, err = internalnetwork.FilterNetworks(list, filter) |
|
| 598 |
+ if err != nil {
|
|
| 599 |
+ return nil, err |
|
| 600 |
+ } |
|
| 601 |
+ |
|
| 602 |
+ if config.Detailed {
|
|
| 603 |
+ for i, n := range list {
|
|
| 604 |
+ np := &n |
|
| 605 |
+ buildDetailedNetworkResources(np, idx[n.ID], config.Verbose) |
|
| 606 |
+ list[i] = *np |
|
| 607 |
+ } |
|
| 608 |
+ } |
|
| 609 |
+ |
|
| 610 |
+ return list, nil |
|
| 611 |
+} |
|
| 612 |
+ |
|
| 613 |
+func buildNetworkResource(nw libnetwork.Network) types.NetworkResource {
|
|
| 614 |
+ r := types.NetworkResource{}
|
|
| 615 |
+ if nw == nil {
|
|
| 616 |
+ return r |
|
| 617 |
+ } |
|
| 618 |
+ |
|
| 619 |
+ info := nw.Info() |
|
| 620 |
+ r.Name = nw.Name() |
|
| 621 |
+ r.ID = nw.ID() |
|
| 622 |
+ r.Created = info.Created() |
|
| 623 |
+ r.Scope = info.Scope() |
|
| 624 |
+ r.Driver = nw.Type() |
|
| 625 |
+ r.EnableIPv6 = info.IPv6Enabled() |
|
| 626 |
+ r.Internal = info.Internal() |
|
| 627 |
+ r.Attachable = info.Attachable() |
|
| 628 |
+ r.Ingress = info.Ingress() |
|
| 629 |
+ r.Options = info.DriverOptions() |
|
| 630 |
+ r.Containers = make(map[string]types.EndpointResource) |
|
| 631 |
+ buildIpamResources(&r, info) |
|
| 632 |
+ r.Labels = info.Labels() |
|
| 633 |
+ r.ConfigOnly = info.ConfigOnly() |
|
| 634 |
+ |
|
| 635 |
+ if cn := info.ConfigFrom(); cn != "" {
|
|
| 636 |
+ r.ConfigFrom = network.ConfigReference{Network: cn}
|
|
| 637 |
+ } |
|
| 638 |
+ |
|
| 639 |
+ peers := info.Peers() |
|
| 640 |
+ if len(peers) != 0 {
|
|
| 641 |
+ r.Peers = buildPeerInfoResources(peers) |
|
| 642 |
+ } |
|
| 643 |
+ |
|
| 644 |
+ return r |
|
| 645 |
+} |
|
| 646 |
+ |
|
| 647 |
+func buildDetailedNetworkResources(r *types.NetworkResource, nw libnetwork.Network, verbose bool) {
|
|
| 648 |
+ if nw == nil {
|
|
| 649 |
+ return |
|
| 650 |
+ } |
|
| 651 |
+ |
|
| 652 |
+ epl := nw.Endpoints() |
|
| 653 |
+ for _, e := range epl {
|
|
| 654 |
+ ei := e.Info() |
|
| 655 |
+ if ei == nil {
|
|
| 656 |
+ continue |
|
| 657 |
+ } |
|
| 658 |
+ sb := ei.Sandbox() |
|
| 659 |
+ tmpID := e.ID() |
|
| 660 |
+ key := "ep-" + tmpID |
|
| 661 |
+ if sb != nil {
|
|
| 662 |
+ key = sb.ContainerID() |
|
| 663 |
+ } |
|
| 664 |
+ |
|
| 665 |
+ r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei) |
|
| 666 |
+ } |
|
| 667 |
+ if !verbose {
|
|
| 668 |
+ return |
|
| 669 |
+ } |
|
| 670 |
+ services := nw.Info().Services() |
|
| 671 |
+ r.Services = make(map[string]network.ServiceInfo) |
|
| 672 |
+ for name, service := range services {
|
|
| 673 |
+ tasks := []network.Task{}
|
|
| 674 |
+ for _, t := range service.Tasks {
|
|
| 675 |
+ tasks = append(tasks, network.Task{
|
|
| 676 |
+ Name: t.Name, |
|
| 677 |
+ EndpointID: t.EndpointID, |
|
| 678 |
+ EndpointIP: t.EndpointIP, |
|
| 679 |
+ Info: t.Info, |
|
| 680 |
+ }) |
|
| 681 |
+ } |
|
| 682 |
+ r.Services[name] = network.ServiceInfo{
|
|
| 683 |
+ VIP: service.VIP, |
|
| 684 |
+ Ports: service.Ports, |
|
| 685 |
+ Tasks: tasks, |
|
| 686 |
+ LocalLBIndex: service.LocalLBIndex, |
|
| 687 |
+ } |
|
| 688 |
+ } |
|
| 689 |
+} |
|
| 690 |
+ |
|
| 691 |
+func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo {
|
|
| 692 |
+ peerInfo := make([]network.PeerInfo, 0, len(peers)) |
|
| 693 |
+ for _, peer := range peers {
|
|
| 694 |
+ peerInfo = append(peerInfo, network.PeerInfo{
|
|
| 695 |
+ Name: peer.Name, |
|
| 696 |
+ IP: peer.IP, |
|
| 697 |
+ }) |
|
| 698 |
+ } |
|
| 699 |
+ return peerInfo |
|
| 700 |
+} |
|
| 701 |
+ |
|
| 702 |
+func buildIpamResources(r *types.NetworkResource, nwInfo libnetwork.NetworkInfo) {
|
|
| 703 |
+ id, opts, ipv4conf, ipv6conf := nwInfo.IpamConfig() |
|
| 704 |
+ |
|
| 705 |
+ ipv4Info, ipv6Info := nwInfo.IpamInfo() |
|
| 706 |
+ |
|
| 707 |
+ r.IPAM.Driver = id |
|
| 708 |
+ |
|
| 709 |
+ r.IPAM.Options = opts |
|
| 710 |
+ |
|
| 711 |
+ r.IPAM.Config = []network.IPAMConfig{}
|
|
| 712 |
+ for _, ip4 := range ipv4conf {
|
|
| 713 |
+ if ip4.PreferredPool == "" {
|
|
| 714 |
+ continue |
|
| 715 |
+ } |
|
| 716 |
+ iData := network.IPAMConfig{}
|
|
| 717 |
+ iData.Subnet = ip4.PreferredPool |
|
| 718 |
+ iData.IPRange = ip4.SubPool |
|
| 719 |
+ iData.Gateway = ip4.Gateway |
|
| 720 |
+ iData.AuxAddress = ip4.AuxAddresses |
|
| 721 |
+ r.IPAM.Config = append(r.IPAM.Config, iData) |
|
| 722 |
+ } |
|
| 723 |
+ |
|
| 724 |
+ if len(r.IPAM.Config) == 0 {
|
|
| 725 |
+ for _, ip4Info := range ipv4Info {
|
|
| 726 |
+ iData := network.IPAMConfig{}
|
|
| 727 |
+ iData.Subnet = ip4Info.IPAMData.Pool.String() |
|
| 728 |
+ if ip4Info.IPAMData.Gateway != nil {
|
|
| 729 |
+ iData.Gateway = ip4Info.IPAMData.Gateway.IP.String() |
|
| 730 |
+ } |
|
| 731 |
+ r.IPAM.Config = append(r.IPAM.Config, iData) |
|
| 732 |
+ } |
|
| 733 |
+ } |
|
| 734 |
+ |
|
| 735 |
+ hasIpv6Conf := false |
|
| 736 |
+ for _, ip6 := range ipv6conf {
|
|
| 737 |
+ if ip6.PreferredPool == "" {
|
|
| 738 |
+ continue |
|
| 739 |
+ } |
|
| 740 |
+ hasIpv6Conf = true |
|
| 741 |
+ iData := network.IPAMConfig{}
|
|
| 742 |
+ iData.Subnet = ip6.PreferredPool |
|
| 743 |
+ iData.IPRange = ip6.SubPool |
|
| 744 |
+ iData.Gateway = ip6.Gateway |
|
| 745 |
+ iData.AuxAddress = ip6.AuxAddresses |
|
| 746 |
+ r.IPAM.Config = append(r.IPAM.Config, iData) |
|
| 747 |
+ } |
|
| 748 |
+ |
|
| 749 |
+ if !hasIpv6Conf {
|
|
| 750 |
+ for _, ip6Info := range ipv6Info {
|
|
| 751 |
+ if ip6Info.IPAMData.Pool == nil {
|
|
| 752 |
+ continue |
|
| 753 |
+ } |
|
| 754 |
+ iData := network.IPAMConfig{}
|
|
| 755 |
+ iData.Subnet = ip6Info.IPAMData.Pool.String() |
|
| 756 |
+ iData.Gateway = ip6Info.IPAMData.Gateway.String() |
|
| 757 |
+ r.IPAM.Config = append(r.IPAM.Config, iData) |
|
| 758 |
+ } |
|
| 759 |
+ } |
|
| 760 |
+} |
|
| 761 |
+ |
|
| 762 |
+func buildEndpointResource(id string, name string, info libnetwork.EndpointInfo) types.EndpointResource {
|
|
| 763 |
+ er := types.EndpointResource{}
|
|
| 764 |
+ |
|
| 765 |
+ er.EndpointID = id |
|
| 766 |
+ er.Name = name |
|
| 767 |
+ ei := info |
|
| 768 |
+ if ei == nil {
|
|
| 769 |
+ return er |
|
| 770 |
+ } |
|
| 771 |
+ |
|
| 772 |
+ if iface := ei.Iface(); iface != nil {
|
|
| 773 |
+ if mac := iface.MacAddress(); mac != nil {
|
|
| 774 |
+ er.MacAddress = mac.String() |
|
| 775 |
+ } |
|
| 776 |
+ if ip := iface.Address(); ip != nil && len(ip.IP) > 0 {
|
|
| 777 |
+ er.IPv4Address = ip.String() |
|
| 778 |
+ } |
|
| 779 |
+ |
|
| 780 |
+ if ipv6 := iface.AddressIPv6(); ipv6 != nil && len(ipv6.IP) > 0 {
|
|
| 781 |
+ er.IPv6Address = ipv6.String() |
|
| 782 |
+ } |
|
| 783 |
+ } |
|
| 784 |
+ return er |
|
| 581 | 785 |
} |
| 582 | 786 |
|
| 583 | 787 |
// clearAttachableNetworks removes the attachable networks |
| 584 | 788 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,92 @@ |
| 0 |
+package network // import "github.com/docker/docker/daemon/network" |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/docker/docker/api/types" |
|
| 4 |
+ "github.com/docker/docker/api/types/filters" |
|
| 5 |
+ "github.com/docker/docker/runconfig" |
|
| 6 |
+ "github.com/pkg/errors" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+// FilterNetworks filters network list according to user specified filter |
|
| 10 |
+// and returns user chosen networks |
|
| 11 |
+func FilterNetworks(nws []types.NetworkResource, filter filters.Args) ([]types.NetworkResource, error) {
|
|
| 12 |
+ // if filter is empty, return original network list |
|
| 13 |
+ if filter.Len() == 0 {
|
|
| 14 |
+ return nws, nil |
|
| 15 |
+ } |
|
| 16 |
+ |
|
| 17 |
+ displayNet := nws[:0] |
|
| 18 |
+ for _, nw := range nws {
|
|
| 19 |
+ if filter.Contains("driver") {
|
|
| 20 |
+ if !filter.ExactMatch("driver", nw.Driver) {
|
|
| 21 |
+ continue |
|
| 22 |
+ } |
|
| 23 |
+ } |
|
| 24 |
+ if filter.Contains("name") {
|
|
| 25 |
+ if !filter.Match("name", nw.Name) {
|
|
| 26 |
+ continue |
|
| 27 |
+ } |
|
| 28 |
+ } |
|
| 29 |
+ if filter.Contains("id") {
|
|
| 30 |
+ if !filter.Match("id", nw.ID) {
|
|
| 31 |
+ continue |
|
| 32 |
+ } |
|
| 33 |
+ } |
|
| 34 |
+ if filter.Contains("label") {
|
|
| 35 |
+ if !filter.MatchKVList("label", nw.Labels) {
|
|
| 36 |
+ continue |
|
| 37 |
+ } |
|
| 38 |
+ } |
|
| 39 |
+ if filter.Contains("scope") {
|
|
| 40 |
+ if !filter.ExactMatch("scope", nw.Scope) {
|
|
| 41 |
+ continue |
|
| 42 |
+ } |
|
| 43 |
+ } |
|
| 44 |
+ |
|
| 45 |
+ if filter.Contains("idOrName") {
|
|
| 46 |
+ if !filter.Match("name", nw.Name) && !filter.Match("id", nw.Name) {
|
|
| 47 |
+ continue |
|
| 48 |
+ } |
|
| 49 |
+ } |
|
| 50 |
+ displayNet = append(displayNet, nw) |
|
| 51 |
+ } |
|
| 52 |
+ |
|
| 53 |
+ if filter.Contains("type") {
|
|
| 54 |
+ typeNet := []types.NetworkResource{}
|
|
| 55 |
+ errFilter := filter.WalkValues("type", func(fval string) error {
|
|
| 56 |
+ passList, err := filterNetworkByType(displayNet, fval) |
|
| 57 |
+ if err != nil {
|
|
| 58 |
+ return err |
|
| 59 |
+ } |
|
| 60 |
+ typeNet = append(typeNet, passList...) |
|
| 61 |
+ return nil |
|
| 62 |
+ }) |
|
| 63 |
+ if errFilter != nil {
|
|
| 64 |
+ return nil, errFilter |
|
| 65 |
+ } |
|
| 66 |
+ displayNet = typeNet |
|
| 67 |
+ } |
|
| 68 |
+ |
|
| 69 |
+ return displayNet, nil |
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+func filterNetworkByType(nws []types.NetworkResource, netType string) ([]types.NetworkResource, error) {
|
|
| 73 |
+ retNws := []types.NetworkResource{}
|
|
| 74 |
+ switch netType {
|
|
| 75 |
+ case "builtin": |
|
| 76 |
+ for _, nw := range nws {
|
|
| 77 |
+ if runconfig.IsPreDefinedNetwork(nw.Name) {
|
|
| 78 |
+ retNws = append(retNws, nw) |
|
| 79 |
+ } |
|
| 80 |
+ } |
|
| 81 |
+ case "custom": |
|
| 82 |
+ for _, nw := range nws {
|
|
| 83 |
+ if !runconfig.IsPreDefinedNetwork(nw.Name) {
|
|
| 84 |
+ retNws = append(retNws, nw) |
|
| 85 |
+ } |
|
| 86 |
+ } |
|
| 87 |
+ default: |
|
| 88 |
+ return nil, errors.Errorf("invalid filter: 'type'='%s'", netType)
|
|
| 89 |
+ } |
|
| 90 |
+ return retNws, nil |
|
| 91 |
+} |
| 0 | 92 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,163 @@ |
| 0 |
+// +build !windows |
|
| 1 |
+ |
|
| 2 |
+package network // import "github.com/docker/docker/daemon/network" |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "strings" |
|
| 6 |
+ "testing" |
|
| 7 |
+ |
|
| 8 |
+ "github.com/docker/docker/api/types" |
|
| 9 |
+ "github.com/docker/docker/api/types/filters" |
|
| 10 |
+) |
|
| 11 |
+ |
|
| 12 |
+func TestFilterNetworks(t *testing.T) {
|
|
| 13 |
+ networks := []types.NetworkResource{
|
|
| 14 |
+ {
|
|
| 15 |
+ Name: "host", |
|
| 16 |
+ Driver: "host", |
|
| 17 |
+ Scope: "local", |
|
| 18 |
+ }, |
|
| 19 |
+ {
|
|
| 20 |
+ Name: "bridge", |
|
| 21 |
+ Driver: "bridge", |
|
| 22 |
+ Scope: "local", |
|
| 23 |
+ }, |
|
| 24 |
+ {
|
|
| 25 |
+ Name: "none", |
|
| 26 |
+ Driver: "null", |
|
| 27 |
+ Scope: "local", |
|
| 28 |
+ }, |
|
| 29 |
+ {
|
|
| 30 |
+ Name: "myoverlay", |
|
| 31 |
+ Driver: "overlay", |
|
| 32 |
+ Scope: "swarm", |
|
| 33 |
+ }, |
|
| 34 |
+ {
|
|
| 35 |
+ Name: "mydrivernet", |
|
| 36 |
+ Driver: "mydriver", |
|
| 37 |
+ Scope: "local", |
|
| 38 |
+ }, |
|
| 39 |
+ {
|
|
| 40 |
+ Name: "mykvnet", |
|
| 41 |
+ Driver: "mykvdriver", |
|
| 42 |
+ Scope: "global", |
|
| 43 |
+ }, |
|
| 44 |
+ } |
|
| 45 |
+ |
|
| 46 |
+ bridgeDriverFilters := filters.NewArgs() |
|
| 47 |
+ bridgeDriverFilters.Add("driver", "bridge")
|
|
| 48 |
+ |
|
| 49 |
+ overlayDriverFilters := filters.NewArgs() |
|
| 50 |
+ overlayDriverFilters.Add("driver", "overlay")
|
|
| 51 |
+ |
|
| 52 |
+ nonameDriverFilters := filters.NewArgs() |
|
| 53 |
+ nonameDriverFilters.Add("driver", "noname")
|
|
| 54 |
+ |
|
| 55 |
+ customDriverFilters := filters.NewArgs() |
|
| 56 |
+ customDriverFilters.Add("type", "custom")
|
|
| 57 |
+ |
|
| 58 |
+ builtinDriverFilters := filters.NewArgs() |
|
| 59 |
+ builtinDriverFilters.Add("type", "builtin")
|
|
| 60 |
+ |
|
| 61 |
+ invalidDriverFilters := filters.NewArgs() |
|
| 62 |
+ invalidDriverFilters.Add("type", "invalid")
|
|
| 63 |
+ |
|
| 64 |
+ localScopeFilters := filters.NewArgs() |
|
| 65 |
+ localScopeFilters.Add("scope", "local")
|
|
| 66 |
+ |
|
| 67 |
+ swarmScopeFilters := filters.NewArgs() |
|
| 68 |
+ swarmScopeFilters.Add("scope", "swarm")
|
|
| 69 |
+ |
|
| 70 |
+ globalScopeFilters := filters.NewArgs() |
|
| 71 |
+ globalScopeFilters.Add("scope", "global")
|
|
| 72 |
+ |
|
| 73 |
+ testCases := []struct {
|
|
| 74 |
+ filter filters.Args |
|
| 75 |
+ resultCount int |
|
| 76 |
+ err string |
|
| 77 |
+ name string |
|
| 78 |
+ }{
|
|
| 79 |
+ {
|
|
| 80 |
+ filter: bridgeDriverFilters, |
|
| 81 |
+ resultCount: 1, |
|
| 82 |
+ err: "", |
|
| 83 |
+ name: "bridge driver filters", |
|
| 84 |
+ }, |
|
| 85 |
+ {
|
|
| 86 |
+ filter: overlayDriverFilters, |
|
| 87 |
+ resultCount: 1, |
|
| 88 |
+ err: "", |
|
| 89 |
+ name: "overlay driver filters", |
|
| 90 |
+ }, |
|
| 91 |
+ {
|
|
| 92 |
+ filter: nonameDriverFilters, |
|
| 93 |
+ resultCount: 0, |
|
| 94 |
+ err: "", |
|
| 95 |
+ name: "no name driver filters", |
|
| 96 |
+ }, |
|
| 97 |
+ {
|
|
| 98 |
+ filter: customDriverFilters, |
|
| 99 |
+ resultCount: 3, |
|
| 100 |
+ err: "", |
|
| 101 |
+ name: "custom driver filters", |
|
| 102 |
+ }, |
|
| 103 |
+ {
|
|
| 104 |
+ filter: builtinDriverFilters, |
|
| 105 |
+ resultCount: 3, |
|
| 106 |
+ err: "", |
|
| 107 |
+ name: "builtin driver filters", |
|
| 108 |
+ }, |
|
| 109 |
+ {
|
|
| 110 |
+ filter: invalidDriverFilters, |
|
| 111 |
+ resultCount: 0, |
|
| 112 |
+ err: "invalid filter: 'type'='invalid'", |
|
| 113 |
+ name: "invalid driver filters", |
|
| 114 |
+ }, |
|
| 115 |
+ {
|
|
| 116 |
+ filter: localScopeFilters, |
|
| 117 |
+ resultCount: 4, |
|
| 118 |
+ err: "", |
|
| 119 |
+ name: "local scope filters", |
|
| 120 |
+ }, |
|
| 121 |
+ {
|
|
| 122 |
+ filter: swarmScopeFilters, |
|
| 123 |
+ resultCount: 1, |
|
| 124 |
+ err: "", |
|
| 125 |
+ name: "swarm scope filters", |
|
| 126 |
+ }, |
|
| 127 |
+ {
|
|
| 128 |
+ filter: globalScopeFilters, |
|
| 129 |
+ resultCount: 1, |
|
| 130 |
+ err: "", |
|
| 131 |
+ name: "global scope filters", |
|
| 132 |
+ }, |
|
| 133 |
+ } |
|
| 134 |
+ |
|
| 135 |
+ for _, testCase := range testCases {
|
|
| 136 |
+ t.Run(testCase.name, func(t *testing.T) {
|
|
| 137 |
+ ls := make([]types.NetworkResource, 0, len(networks)) |
|
| 138 |
+ ls = append(ls, networks...) |
|
| 139 |
+ result, err := FilterNetworks(ls, testCase.filter) |
|
| 140 |
+ if testCase.err != "" {
|
|
| 141 |
+ if err == nil {
|
|
| 142 |
+ t.Fatalf("expect error '%s', got no error", testCase.err)
|
|
| 143 |
+ |
|
| 144 |
+ } else if !strings.Contains(err.Error(), testCase.err) {
|
|
| 145 |
+ t.Fatalf("expect error '%s', got '%s'", testCase.err, err)
|
|
| 146 |
+ } |
|
| 147 |
+ } else {
|
|
| 148 |
+ if err != nil {
|
|
| 149 |
+ t.Fatalf("expect no error, got error '%s'", err)
|
|
| 150 |
+ } |
|
| 151 |
+ // Make sure result is not nil |
|
| 152 |
+ if result == nil {
|
|
| 153 |
+ t.Fatal("filterNetworks should not return nil")
|
|
| 154 |
+ } |
|
| 155 |
+ |
|
| 156 |
+ if len(result) != testCase.resultCount {
|
|
| 157 |
+ t.Fatalf("expect '%d' networks, got '%d' networks", testCase.resultCount, len(result))
|
|
| 158 |
+ } |
|
| 159 |
+ } |
|
| 160 |
+ }) |
|
| 161 |
+ } |
|
| 162 |
+} |
| ... | ... |
@@ -141,7 +141,7 @@ func (daemon *Daemon) clusterNetworksPrune(ctx context.Context, pruneFilters fil |
| 141 | 141 |
return rep, nil |
| 142 | 142 |
} |
| 143 | 143 |
|
| 144 |
- networks, err := cluster.GetNetworks() |
|
| 144 |
+ networks, err := cluster.GetNetworks(pruneFilters) |
|
| 145 | 145 |
if err != nil {
|
| 146 | 146 |
return rep, err |
| 147 | 147 |
} |