Browse Source

Merge pull request #31551 from KarthikNayak/dry_run

Network: add support for 'dangling' filter
Vincent Demeester 6 years ago
parent
commit
ba641fef28
3 changed files with 90 additions and 8 deletions
  1. 7 6
      api/types/network/network.go
  2. 38 0
      daemon/network/filter.go
  3. 45 2
      daemon/network/filter_test.go

+ 7 - 6
api/types/network/network.go

@@ -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.

+ 38 - 0
daemon/network/filter.go

@@ -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 {

+ 45 - 2
daemon/network/filter_test.go

@@ -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)
+						}
+					}
+				}
 			}
 		})
 	}