Network: add support for 'dangling' filter

Like its counterpart in images and volumes, introduce the dangling
filter while listing networks. When the filter value is set to true,
only networks which aren't attached to containers and aren't builtin
networks are shown. When set to false, all builtin networks and
networks which are attached to containers are shown.

Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
This commit is contained in:
karthik nayak 2019-01-06 10:37:09 -05:00
parent 8d7889e510
commit 131cbaf5b7
3 changed files with 90 additions and 8 deletions

View file

@ -112,12 +112,13 @@ type ConfigReference struct {
}
var acceptedFilters = map[string]bool{
"driver": true,
"type": true,
"name": true,
"id": true,
"label": true,
"scope": true,
"driver": true,
"type": true,
"name": true,
"id": true,
"label": true,
"scope": true,
"dangling": true,
}
// ValidateFilters validates the list of filter args with the available filters.

View file

@ -3,6 +3,7 @@ package network // import "github.com/docker/docker/daemon/network"
import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/runconfig"
"github.com/pkg/errors"
)
@ -51,6 +52,24 @@ func FilterNetworks(nws []types.NetworkResource, filter filters.Args) ([]types.N
displayNet = append(displayNet, nw)
}
if values := filter.Get("dangling"); len(values) > 0 {
if len(values) > 1 {
return nil, errdefs.InvalidParameter(errors.New(`got more than one value for filter key "dangling"`))
}
var danglingOnly bool
switch values[0] {
case "0", "false":
// dangling is false already
case "1", "true":
danglingOnly = true
default:
return nil, errdefs.InvalidParameter(errors.New(`invalid value for filter 'dangling', must be "true" (or "1"), or "false" (or "0")`))
}
displayNet = filterNetworkByUse(displayNet, danglingOnly)
}
if filter.Contains("type") {
typeNet := []types.NetworkResource{}
errFilter := filter.WalkValues("type", func(fval string) error {
@ -70,6 +89,25 @@ func FilterNetworks(nws []types.NetworkResource, filter filters.Args) ([]types.N
return displayNet, nil
}
func filterNetworkByUse(nws []types.NetworkResource, danglingOnly bool) []types.NetworkResource {
retNws := []types.NetworkResource{}
filterFunc := func(nw types.NetworkResource) bool {
if danglingOnly {
return !runconfig.IsPreDefinedNetwork(nw.Name) && len(nw.Containers) == 0 && len(nw.Services) == 0
}
return runconfig.IsPreDefinedNetwork(nw.Name) || len(nw.Containers) > 0 || len(nw.Services) > 0
}
for _, nw := range nws {
if filterFunc(nw) {
retNws = append(retNws, nw)
}
}
return retNws
}
func filterNetworkByType(nws []types.NetworkResource, netType string) ([]types.NetworkResource, error) {
retNws := []types.NetworkResource{}
switch netType {

View file

@ -42,6 +42,16 @@ func TestFilterNetworks(t *testing.T) {
Driver: "mykvdriver",
Scope: "global",
},
{
Name: "networkwithcontainer",
Driver: "nwc",
Scope: "local",
Containers: map[string]types.EndpointResource{
"customcontainer": {
Name: "customendpoint",
},
},
},
}
bridgeDriverFilters := filters.NewArgs()
@ -71,11 +81,18 @@ func TestFilterNetworks(t *testing.T) {
globalScopeFilters := filters.NewArgs()
globalScopeFilters.Add("scope", "global")
trueDanglingFilters := filters.NewArgs()
trueDanglingFilters.Add("dangling", "true")
falseDanglingFilters := filters.NewArgs()
falseDanglingFilters.Add("dangling", "false")
testCases := []struct {
filter filters.Args
resultCount int
err string
name string
results []string
}{
{
filter: bridgeDriverFilters,
@ -97,7 +114,7 @@ func TestFilterNetworks(t *testing.T) {
},
{
filter: customDriverFilters,
resultCount: 3,
resultCount: 4,
err: "",
name: "custom driver filters",
},
@ -115,7 +132,7 @@ func TestFilterNetworks(t *testing.T) {
},
{
filter: localScopeFilters,
resultCount: 4,
resultCount: 5,
err: "",
name: "local scope filters",
},
@ -131,6 +148,20 @@ func TestFilterNetworks(t *testing.T) {
err: "",
name: "global scope filters",
},
{
filter: trueDanglingFilters,
resultCount: 3,
err: "",
name: "dangling filter is 'True'",
results: []string{"myoverlay", "mydrivernet", "mykvnet"},
},
{
filter: falseDanglingFilters,
resultCount: 4,
err: "",
name: "dangling filter is 'False'",
results: []string{"host", "bridge", "none", "networkwithcontainer"},
},
}
for _, testCase := range testCases {
@ -157,6 +188,18 @@ func TestFilterNetworks(t *testing.T) {
if len(result) != testCase.resultCount {
t.Fatalf("expect '%d' networks, got '%d' networks", testCase.resultCount, len(result))
}
if len(testCase.results) > 0 {
resultMap := make(map[string]bool)
for _, r := range result {
resultMap[r.Name] = true
}
for _, r := range testCase.results {
if _, ok := resultMap[r]; !ok {
t.Fatalf("expected result: '%s' not found", r)
}
}
}
}
})
}