mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
Merge pull request #50860 from corhere/network-filter-iface
daemon: filter networks before converting to API types
This commit is contained in:
@@ -2,8 +2,6 @@ package network
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/moby/moby/api/types/filters"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -116,21 +114,6 @@ type ConfigReference struct {
|
||||
Network string
|
||||
}
|
||||
|
||||
var acceptedFilters = map[string]bool{
|
||||
"dangling": true,
|
||||
"driver": true,
|
||||
"id": true,
|
||||
"label": true,
|
||||
"name": true,
|
||||
"scope": true,
|
||||
"type": true,
|
||||
}
|
||||
|
||||
// ValidateFilters validates the list of filter args with the available filters.
|
||||
func ValidateFilters(filter filters.Args) error {
|
||||
return filter.Validate(acceptedFilters)
|
||||
}
|
||||
|
||||
// PruneReport contains the response for Engine API:
|
||||
// POST "/networks/prune"
|
||||
type PruneReport struct {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/moby/moby/api/types/filters"
|
||||
"github.com/moby/moby/api/types/network"
|
||||
lncluster "github.com/moby/moby/v2/daemon/libnetwork/cluster"
|
||||
dnetwork "github.com/moby/moby/v2/daemon/network"
|
||||
)
|
||||
|
||||
// Cluster is the interface for [github.com/moby/moby/v2/daemon/cluster.Cluster].
|
||||
@@ -22,6 +22,6 @@ type ClusterStatus interface {
|
||||
// NetworkManager provides methods to manage networks
|
||||
type NetworkManager interface {
|
||||
GetNetwork(input string) (network.Inspect, error)
|
||||
GetNetworks(filters.Args) ([]network.Inspect, error)
|
||||
GetNetworks(dnetwork.Filter) ([]network.Inspect, error)
|
||||
RemoveNetwork(input string) error
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package convert
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
gogotypes "github.com/gogo/protobuf/types"
|
||||
"github.com/moby/moby/api/types/network"
|
||||
@@ -240,3 +241,47 @@ func IsIngressNetwork(n *swarmapi.Network) bool {
|
||||
_, ok := n.Spec.Annotations.Labels["com.docker.swarm.internal"]
|
||||
return ok && n.Spec.Annotations.Name == "ingress"
|
||||
}
|
||||
|
||||
// FilterNetwork adapts [swarmapi.Network] to the
|
||||
// [github.com/moby/moby/v2/daemon/network.FilterNetwork] interface.
|
||||
type FilterNetwork struct {
|
||||
N *swarmapi.Network
|
||||
}
|
||||
|
||||
func (nw FilterNetwork) ID() string {
|
||||
return nw.N.ID
|
||||
}
|
||||
|
||||
func (nw FilterNetwork) Name() string {
|
||||
return nw.N.Spec.Annotations.Name
|
||||
}
|
||||
|
||||
func (nw FilterNetwork) Driver() string {
|
||||
if nw.N.DriverState != nil {
|
||||
return nw.N.DriverState.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (nw FilterNetwork) Labels() map[string]string {
|
||||
return nw.N.Spec.Annotations.Labels
|
||||
}
|
||||
|
||||
func (nw FilterNetwork) Scope() string {
|
||||
return scope.Swarm
|
||||
}
|
||||
|
||||
func (nw FilterNetwork) Created() time.Time {
|
||||
t, _ := gogotypes.TimestampFromProto(nw.N.Meta.CreatedAt)
|
||||
return t
|
||||
}
|
||||
|
||||
func (nw FilterNetwork) HasContainerAttachments() bool {
|
||||
// Not tracked in swarmkit
|
||||
return false
|
||||
}
|
||||
|
||||
func (nw FilterNetwork) HasServiceAttachments() bool {
|
||||
// Not tracked in swarmkit
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/moby/moby/api/types/filters"
|
||||
"github.com/moby/moby/api/types/network"
|
||||
types "github.com/moby/moby/api/types/swarm"
|
||||
"github.com/moby/moby/v2/daemon/cluster/convert"
|
||||
@@ -16,65 +15,45 @@ import (
|
||||
)
|
||||
|
||||
// GetNetworks returns all current cluster managed networks.
|
||||
func (c *Cluster) GetNetworks(filter filters.Args) ([]network.Inspect, error) {
|
||||
var f *swarmapi.ListNetworksRequest_Filters
|
||||
|
||||
if filter.Len() > 0 {
|
||||
f = &swarmapi.ListNetworksRequest_Filters{}
|
||||
|
||||
if filter.Contains("name") {
|
||||
f.Names = filter.Get("name")
|
||||
f.NamePrefixes = filter.Get("name")
|
||||
}
|
||||
|
||||
if filter.Contains("id") {
|
||||
f.IDPrefixes = filter.Get("id")
|
||||
}
|
||||
}
|
||||
|
||||
list, err := c.getNetworks(f)
|
||||
func (c *Cluster) GetNetworks(filter networkSettings.Filter) ([]network.Inspect, error) {
|
||||
// Swarmkit API's filters are too limited to express the Moby filter
|
||||
// semantics with much fidelity. It only supports filtering on one of:
|
||||
// - Names (exact match)
|
||||
// - NamePrefixes (prefix match)
|
||||
// - IDPrefixes (prefix match)
|
||||
// The first of the list that is set is used as the filter predicate.
|
||||
// The other fields are ignored. However, the Engine API filter
|
||||
// semantics are to match on any substring of the network name or ID. We
|
||||
// therefore need to request all networks from Swarmkit and filter them
|
||||
// ourselves.
|
||||
list, err := c.listNetworks(context.TODO(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filterPredefinedNetworks(&list)
|
||||
|
||||
return networkSettings.FilterNetworks(list, filter)
|
||||
}
|
||||
|
||||
func filterPredefinedNetworks(networks *[]network.Inspect) {
|
||||
if networks == nil {
|
||||
return
|
||||
}
|
||||
var idxs []int
|
||||
for i, nw := range *networks {
|
||||
if v, ok := nw.Labels["com.docker.swarm.predefined"]; ok && v == "true" {
|
||||
idxs = append(idxs, i)
|
||||
var filtered []network.Inspect
|
||||
for _, n := range list {
|
||||
if n.Spec.Annotations.Labels["com.docker.swarm.predefined"] == "true" {
|
||||
continue
|
||||
}
|
||||
if filter.Matches(convert.FilterNetwork{N: n}) {
|
||||
filtered = append(filtered, convert.BasicNetworkFromGRPC(*n))
|
||||
}
|
||||
}
|
||||
for i, idx := range idxs {
|
||||
idx -= i
|
||||
*networks = append((*networks)[:idx], (*networks)[idx+1:]...)
|
||||
}
|
||||
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
func (c *Cluster) getNetworks(filters *swarmapi.ListNetworksRequest_Filters) ([]network.Inspect, error) {
|
||||
var r *swarmapi.ListNetworksResponse
|
||||
err := c.lockedManagerAction(context.TODO(), func(ctx context.Context, state nodeState) error {
|
||||
var err error
|
||||
r, err = state.controlClient.ListNetworks(ctx, &swarmapi.ListNetworksRequest{Filters: filters})
|
||||
return err
|
||||
func (c *Cluster) listNetworks(ctx context.Context, filters *swarmapi.ListNetworksRequest_Filters) ([]*swarmapi.Network, error) {
|
||||
var list []*swarmapi.Network
|
||||
err := c.lockedManagerAction(ctx, func(ctx context.Context, state nodeState) error {
|
||||
l, err := state.controlClient.ListNetworks(ctx, &swarmapi.ListNetworksRequest{Filters: filters})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
list = l.Networks
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
networks := make([]network.Inspect, 0, len(r.Networks))
|
||||
|
||||
for _, nw := range r.Networks {
|
||||
networks = append(networks, convert.BasicNetworkFromGRPC(*nw))
|
||||
}
|
||||
|
||||
return networks, nil
|
||||
return list, err
|
||||
}
|
||||
|
||||
// GetNetwork returns a cluster network by an ID.
|
||||
@@ -99,9 +78,17 @@ func (c *Cluster) GetNetwork(input string) (network.Inspect, error) {
|
||||
func (c *Cluster) GetNetworksByName(name string) ([]network.Inspect, error) {
|
||||
// Note that swarmapi.GetNetworkRequest.Name is not functional.
|
||||
// So we cannot just use that with c.GetNetwork.
|
||||
return c.getNetworks(&swarmapi.ListNetworksRequest_Filters{
|
||||
list, err := c.listNetworks(context.TODO(), &swarmapi.ListNetworksRequest_Filters{
|
||||
Names: []string{name},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nr := make([]network.Inspect, len(list))
|
||||
for i, n := range list {
|
||||
nr[i] = convert.BasicNetworkFromGRPC(*n)
|
||||
}
|
||||
return nr, nil
|
||||
}
|
||||
|
||||
func attacherKey(target, containerID string) string {
|
||||
|
||||
@@ -539,6 +539,11 @@ func (n *Network) Services() map[string]ServiceInfo {
|
||||
return sinfo
|
||||
}
|
||||
|
||||
// HasServiceAttachments returns true when len(n.Services()) > 0.
|
||||
func (n *Network) HasServiceAttachments() bool {
|
||||
return len(n.Services()) > 0
|
||||
}
|
||||
|
||||
// clusterAgent returns the cluster agent if the network is a swarm-scoped,
|
||||
// multi-host network.
|
||||
func (n *Network) clusterAgent() (agent *nwAgent, ok bool) {
|
||||
|
||||
@@ -249,6 +249,11 @@ func (n *Network) Type() string {
|
||||
return n.networkType
|
||||
}
|
||||
|
||||
// Driver is an alias for [Network.Type].
|
||||
func (n *Network) Driver() string {
|
||||
return n.Type()
|
||||
}
|
||||
|
||||
func (n *Network) Resolvers() []*Resolver {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
@@ -1283,6 +1288,11 @@ func (n *Network) Endpoints() []*Endpoint {
|
||||
return endpoints
|
||||
}
|
||||
|
||||
// HasContainerAttachments returns true when len(n.Endpoints()) > 0.
|
||||
func (n *Network) HasContainerAttachments() bool {
|
||||
return len(n.Endpoints()) > 0
|
||||
}
|
||||
|
||||
// WalkEndpoints uses the provided function to walk the Endpoints.
|
||||
func (n *Network) WalkEndpoints(walker EndpointWalker) {
|
||||
for _, e := range n.Endpoints() {
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"github.com/docker/go-connections/nat"
|
||||
containertypes "github.com/moby/moby/api/types/container"
|
||||
"github.com/moby/moby/api/types/events"
|
||||
"github.com/moby/moby/api/types/filters"
|
||||
networktypes "github.com/moby/moby/api/types/network"
|
||||
clustertypes "github.com/moby/moby/v2/daemon/cluster/provider"
|
||||
"github.com/moby/moby/v2/daemon/config"
|
||||
@@ -591,34 +590,19 @@ func (daemon *Daemon) deleteNetwork(nw *libnetwork.Network, dynamic bool) error
|
||||
}
|
||||
|
||||
// GetNetworks returns a list of all networks
|
||||
func (daemon *Daemon) GetNetworks(filter filters.Args, config backend.NetworkListConfig) ([]networktypes.Inspect, error) {
|
||||
var idx map[string]*libnetwork.Network
|
||||
if config.Detailed {
|
||||
idx = make(map[string]*libnetwork.Network)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) GetNetworks(filter network.Filter, config backend.NetworkListConfig) ([]networktypes.Inspect, error) {
|
||||
allNetworks := daemon.getAllNetworks()
|
||||
networks := make([]networktypes.Inspect, 0, len(allNetworks))
|
||||
for _, n := range allNetworks {
|
||||
nr := buildNetworkResource(n)
|
||||
networks = append(networks, nr)
|
||||
if config.Detailed {
|
||||
idx[nr.ID] = n
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
networks, err = network.FilterNetworks(networks, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config.Detailed {
|
||||
for i, nw := range networks {
|
||||
networks[i].Containers = buildContainerAttachments(idx[nw.ID])
|
||||
if config.Verbose {
|
||||
networks[i].Services = buildServiceAttachments(idx[nw.ID])
|
||||
if filter.Matches(n) {
|
||||
nr := buildNetworkResource(n)
|
||||
if config.Detailed {
|
||||
nr.Containers = buildContainerAttachments(n)
|
||||
if config.Verbose {
|
||||
nr.Services = buildServiceAttachments(n)
|
||||
}
|
||||
}
|
||||
networks = append(networks, nr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,129 +1,194 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/moby/moby/api/types/filters"
|
||||
"github.com/moby/moby/api/types/network"
|
||||
"github.com/moby/moby/v2/daemon/internal/timestamp"
|
||||
"github.com/moby/moby/v2/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// FilterNetworks filters network list according to user specified filter
|
||||
// and returns user chosen networks
|
||||
func FilterNetworks(nws []network.Inspect, filter filters.Args) ([]network.Inspect, error) {
|
||||
// if filter is empty, return original network list
|
||||
if filter.Len() == 0 {
|
||||
return nws, nil
|
||||
var (
|
||||
acceptedFilters = map[string]bool{
|
||||
"dangling": true,
|
||||
"driver": true,
|
||||
"id": true,
|
||||
"label": true,
|
||||
"name": true,
|
||||
"scope": true,
|
||||
"type": true,
|
||||
}
|
||||
|
||||
displayNet := nws[:0]
|
||||
for _, nw := range nws {
|
||||
if filter.Contains("driver") {
|
||||
if !filter.ExactMatch("driver", nw.Driver) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Contains("name") {
|
||||
if !filter.Match("name", nw.Name) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Contains("id") {
|
||||
if !filter.Match("id", nw.ID) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Contains("label") {
|
||||
if !filter.MatchKVList("label", nw.Labels) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Contains("scope") {
|
||||
if !filter.ExactMatch("scope", nw.Scope) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if filter.Contains("idOrName") {
|
||||
if !filter.Match("name", nw.Name) && !filter.Match("id", nw.Name) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
displayNet = append(displayNet, nw)
|
||||
pruneFilters = map[string]bool{
|
||||
"label": true,
|
||||
"label!": true,
|
||||
"until": true,
|
||||
}
|
||||
)
|
||||
|
||||
if values := filter.Get("dangling"); len(values) > 0 {
|
||||
type Filter struct {
|
||||
args filters.Args
|
||||
|
||||
filterByUse, danglingOnly bool
|
||||
until time.Time
|
||||
|
||||
// IDAlsoMatchesName makes the "id" filter term also match against
|
||||
// network names.
|
||||
IDAlsoMatchesName bool
|
||||
}
|
||||
|
||||
type FilterNetwork interface {
|
||||
Driver() string
|
||||
Name() string
|
||||
ID() string
|
||||
Labels() map[string]string
|
||||
Scope() string
|
||||
Created() time.Time
|
||||
HasContainerAttachments() bool
|
||||
HasServiceAttachments() bool
|
||||
}
|
||||
|
||||
// NewFilter returns a network list filter that filters by the provided args.
|
||||
//
|
||||
// An [errdefs.InvalidParameter] error is returned if the filter args are not
|
||||
// well-formed.
|
||||
func NewFilter(args filters.Args) (Filter, error) {
|
||||
if err := args.Validate(acceptedFilters); err != nil {
|
||||
return Filter{}, err
|
||||
}
|
||||
return newFilter(args)
|
||||
}
|
||||
|
||||
// NewPruneFilter returns a network prune filter that filters by the provided args.
|
||||
//
|
||||
// The filter matches dangling networks which also match args.
|
||||
func NewPruneFilter(args filters.Args) (Filter, error) {
|
||||
if err := args.Validate(pruneFilters); err != nil {
|
||||
return Filter{}, err
|
||||
}
|
||||
f, err := newFilter(args)
|
||||
if err != nil {
|
||||
return Filter{}, err
|
||||
}
|
||||
f.filterByUse = true
|
||||
f.danglingOnly = true
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func newFilter(args filters.Args) (Filter, error) {
|
||||
var filterByUse, danglingOnly bool
|
||||
if values := args.Get("dangling"); len(values) > 0 {
|
||||
if len(values) > 1 {
|
||||
return nil, errdefs.InvalidParameter(errors.New(`got more than one value for filter key "dangling"`))
|
||||
return Filter{}, errdefs.InvalidParameter(errors.New(`got more than one value for filter key "dangling"`))
|
||||
}
|
||||
|
||||
var danglingOnly bool
|
||||
filterByUse = true
|
||||
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")`))
|
||||
return Filter{}, 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 := []network.Inspect{}
|
||||
errFilter := filter.WalkValues("type", func(fval string) error {
|
||||
passList, err := filterNetworkByType(displayNet, fval)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
typeNet = append(typeNet, passList...)
|
||||
return nil
|
||||
})
|
||||
if errFilter != nil {
|
||||
return nil, errFilter
|
||||
if err := args.WalkValues("type", validateNetworkTypeFilter); err != nil {
|
||||
return Filter{}, err
|
||||
}
|
||||
until := time.Time{}
|
||||
if untilFilters := args.Get("until"); len(untilFilters) > 0 {
|
||||
if len(untilFilters) > 1 {
|
||||
return Filter{}, errdefs.InvalidParameter(errors.New("more than one until filter specified"))
|
||||
}
|
||||
displayNet = typeNet
|
||||
ts, err := timestamp.GetTimestamp(untilFilters[0], time.Now())
|
||||
if err != nil {
|
||||
return Filter{}, errdefs.InvalidParameter(err)
|
||||
}
|
||||
seconds, nanoseconds, err := timestamp.ParseTimestamps(ts, 0)
|
||||
if err != nil {
|
||||
return Filter{}, errdefs.InvalidParameter(err)
|
||||
}
|
||||
until = time.Unix(seconds, nanoseconds)
|
||||
}
|
||||
|
||||
return displayNet, nil
|
||||
return Filter{
|
||||
args: args,
|
||||
filterByUse: filterByUse,
|
||||
danglingOnly: danglingOnly,
|
||||
until: until,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func filterNetworkByUse(nws []network.Inspect, danglingOnly bool) []network.Inspect {
|
||||
retNws := []network.Inspect{}
|
||||
|
||||
filterFunc := func(nw network.Inspect) bool {
|
||||
if danglingOnly {
|
||||
return !IsPredefined(nw.Name) && len(nw.Containers) == 0 && len(nw.Services) == 0
|
||||
}
|
||||
return IsPredefined(nw.Name) || len(nw.Containers) > 0 || len(nw.Services) > 0
|
||||
}
|
||||
|
||||
for _, nw := range nws {
|
||||
if filterFunc(nw) {
|
||||
retNws = append(retNws, nw)
|
||||
}
|
||||
}
|
||||
|
||||
return retNws
|
||||
func (f Filter) Get(key string) []string {
|
||||
return f.args.Get(key)
|
||||
}
|
||||
|
||||
func filterNetworkByType(nws []network.Inspect, netType string) ([]network.Inspect, error) {
|
||||
retNws := []network.Inspect{}
|
||||
// Matches returns true if nw satisfies the filter criteria.
|
||||
func (f Filter) Matches(nw FilterNetwork) bool {
|
||||
if f.args.Contains("driver") &&
|
||||
!f.args.ExactMatch("driver", nw.Driver()) {
|
||||
return false
|
||||
}
|
||||
if f.args.Contains("name") &&
|
||||
!f.args.Match("name", nw.Name()) {
|
||||
return false
|
||||
}
|
||||
if f.args.Contains("id") &&
|
||||
!f.args.Match("id", nw.ID()) &&
|
||||
(!f.IDAlsoMatchesName || !f.args.Match("id", nw.Name())) {
|
||||
return false
|
||||
}
|
||||
if f.args.Contains("label") &&
|
||||
!f.args.MatchKVList("label", nw.Labels()) {
|
||||
return false
|
||||
}
|
||||
if f.args.Contains("label!") &&
|
||||
f.args.MatchKVList("label!", nw.Labels()) {
|
||||
return false
|
||||
}
|
||||
if f.args.Contains("scope") &&
|
||||
!f.args.ExactMatch("scope", nw.Scope()) {
|
||||
return false
|
||||
}
|
||||
if f.filterByUse &&
|
||||
!matchesUse(f.danglingOnly, nw) {
|
||||
return false
|
||||
}
|
||||
if netTypes := f.args.Get("type"); len(netTypes) > 0 &&
|
||||
!matchesType(netTypes, nw) {
|
||||
return false
|
||||
}
|
||||
if !f.until.IsZero() &&
|
||||
nw.Created().After(f.until) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func matchesUse(danglingOnly bool, nw FilterNetwork) bool {
|
||||
if danglingOnly {
|
||||
return !IsPredefined(nw.Name()) && !nw.HasContainerAttachments() && !nw.HasServiceAttachments()
|
||||
}
|
||||
return IsPredefined(nw.Name()) || nw.HasContainerAttachments() || nw.HasServiceAttachments()
|
||||
}
|
||||
|
||||
func validateNetworkTypeFilter(netType string) error {
|
||||
switch netType {
|
||||
case "builtin":
|
||||
for _, nw := range nws {
|
||||
if IsPredefined(nw.Name) {
|
||||
retNws = append(retNws, nw)
|
||||
}
|
||||
}
|
||||
case "custom":
|
||||
for _, nw := range nws {
|
||||
if !IsPredefined(nw.Name) {
|
||||
retNws = append(retNws, nw)
|
||||
}
|
||||
}
|
||||
case "builtin", "custom":
|
||||
return nil
|
||||
default:
|
||||
return nil, errors.Errorf("invalid filter: 'type'='%s'", netType)
|
||||
return errors.Errorf("invalid filter: 'type'='%s'", netType)
|
||||
}
|
||||
return retNws, nil
|
||||
}
|
||||
|
||||
func matchesType(netTypes []string, nw FilterNetwork) bool {
|
||||
for _, netType := range netTypes {
|
||||
switch netType {
|
||||
case "builtin":
|
||||
return IsPredefined(nw.Name())
|
||||
case "custom":
|
||||
return !IsPredefined(nw.Name())
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -3,170 +3,372 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
|
||||
"github.com/moby/moby/api/types/filters"
|
||||
"github.com/moby/moby/api/types/network"
|
||||
)
|
||||
|
||||
func TestFilterNetworks(t *testing.T) {
|
||||
networks := []network.Inspect{
|
||||
var _ FilterNetwork = mockFilterNetwork{}
|
||||
|
||||
type mockFilterNetwork struct {
|
||||
driver string
|
||||
name string
|
||||
id string
|
||||
labels map[string]string
|
||||
scope string
|
||||
created time.Time
|
||||
containers bool
|
||||
services bool
|
||||
}
|
||||
|
||||
func (n mockFilterNetwork) Driver() string {
|
||||
return n.driver
|
||||
}
|
||||
|
||||
func (n mockFilterNetwork) Name() string {
|
||||
return n.name
|
||||
}
|
||||
|
||||
func (n mockFilterNetwork) ID() string {
|
||||
return n.id
|
||||
}
|
||||
|
||||
func (n mockFilterNetwork) Labels() map[string]string {
|
||||
return n.labels
|
||||
}
|
||||
|
||||
func (n mockFilterNetwork) Scope() string {
|
||||
return n.scope
|
||||
}
|
||||
|
||||
func (n mockFilterNetwork) Created() time.Time {
|
||||
return n.created
|
||||
}
|
||||
|
||||
func (n mockFilterNetwork) HasContainerAttachments() bool {
|
||||
return n.containers
|
||||
}
|
||||
|
||||
func (n mockFilterNetwork) HasServiceAttachments() bool {
|
||||
return n.services
|
||||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
networks := []mockFilterNetwork{
|
||||
{
|
||||
Name: "host",
|
||||
Driver: "host",
|
||||
Scope: "local",
|
||||
name: network.NetworkHost,
|
||||
id: "ubfg", // ROT13(name)
|
||||
driver: "host",
|
||||
scope: "local",
|
||||
created: time.Date(2025, time.June, 1, 0, 0, 0, 0, time.Local),
|
||||
},
|
||||
{
|
||||
Name: "bridge",
|
||||
Driver: "bridge",
|
||||
Scope: "local",
|
||||
name: network.NetworkBridge,
|
||||
id: "oevqtr",
|
||||
driver: "bridge",
|
||||
scope: "local",
|
||||
created: time.Date(2025, time.June, 1, 0, 0, 0, 0, time.Local),
|
||||
},
|
||||
{
|
||||
Name: "none",
|
||||
Driver: "null",
|
||||
Scope: "local",
|
||||
name: network.NetworkNone,
|
||||
id: "abar",
|
||||
driver: "null",
|
||||
scope: "local",
|
||||
created: time.Date(2025, time.June, 1, 0, 0, 0, 0, time.Local),
|
||||
},
|
||||
{
|
||||
Name: "myoverlay",
|
||||
Driver: "overlay",
|
||||
Scope: "swarm",
|
||||
name: "myoverlay",
|
||||
id: "zlbireynl",
|
||||
driver: "overlay",
|
||||
scope: "swarm",
|
||||
created: time.Date(2024, time.June, 1, 12, 0, 0, 0, time.Local),
|
||||
},
|
||||
{
|
||||
Name: "mydrivernet",
|
||||
Driver: "mydriver",
|
||||
Scope: "local",
|
||||
name: "mydrivernet",
|
||||
id: "zlqevirearg",
|
||||
driver: "mydriver",
|
||||
scope: "local",
|
||||
labels: map[string]string{"foo": "bar"},
|
||||
created: time.Date(2024, time.December, 1, 2, 0, 0, 0, time.Local),
|
||||
},
|
||||
{
|
||||
Name: "mykvnet",
|
||||
Driver: "mykvdriver",
|
||||
Scope: "global",
|
||||
name: "mykvnet",
|
||||
id: "zlxiarg",
|
||||
driver: "mykvdriver",
|
||||
scope: "global",
|
||||
created: time.Date(2025, time.January, 1, 0, 0, 0, 0, time.Local),
|
||||
},
|
||||
{
|
||||
Name: "networkwithcontainer",
|
||||
Driver: "nwc",
|
||||
Scope: "local",
|
||||
Containers: map[string]network.EndpointResource{
|
||||
"customcontainer": {
|
||||
Name: "customendpoint",
|
||||
},
|
||||
},
|
||||
name: "networkwithcontainer",
|
||||
id: "argjbexjvgupbagnvare",
|
||||
driver: "nwc",
|
||||
scope: "local",
|
||||
containers: true,
|
||||
created: time.Date(2025, time.June, 1, 0, 0, 0, 0, time.Local),
|
||||
},
|
||||
{
|
||||
name: "networkwithservice",
|
||||
id: "argjbexjvgufreivpr",
|
||||
driver: "nwc",
|
||||
scope: "local",
|
||||
services: true,
|
||||
created: time.Date(2025, time.June, 1, 0, 0, 0, 0, time.Local),
|
||||
},
|
||||
{
|
||||
name: "idoverlap",
|
||||
id: "aaaaa0my0bbbbbb",
|
||||
driver: "nwc",
|
||||
scope: "local",
|
||||
created: time.Date(2025, time.February, 1, 0, 0, 0, 0, time.Local),
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
filter filters.Args
|
||||
resultCount int
|
||||
err string
|
||||
name string
|
||||
results []string
|
||||
subtest string
|
||||
filter filters.Args
|
||||
pruneFilter bool
|
||||
idAlsoMatchesName bool
|
||||
|
||||
err string
|
||||
results []string
|
||||
}{
|
||||
{
|
||||
filter: filters.NewArgs(filters.Arg("driver", "bridge")),
|
||||
resultCount: 1,
|
||||
err: "",
|
||||
name: "bridge driver filters",
|
||||
subtest: "EmptyFilter",
|
||||
filter: filters.NewArgs(),
|
||||
results: (func() []string {
|
||||
var r []string
|
||||
for _, n := range networks {
|
||||
r = append(r, n.name)
|
||||
}
|
||||
return r
|
||||
})(),
|
||||
},
|
||||
{
|
||||
filter: filters.NewArgs(filters.Arg("driver", "overlay")),
|
||||
resultCount: 1,
|
||||
err: "",
|
||||
name: "overlay driver filters",
|
||||
subtest: "driver=bridge",
|
||||
filter: filters.NewArgs(filters.Arg("driver", "bridge")),
|
||||
results: []string{"bridge"},
|
||||
},
|
||||
{
|
||||
filter: filters.NewArgs(filters.Arg("driver", "noname")),
|
||||
resultCount: 0,
|
||||
err: "",
|
||||
name: "no name driver filters",
|
||||
subtest: "driver=overlay",
|
||||
filter: filters.NewArgs(filters.Arg("driver", "overlay")),
|
||||
results: []string{"myoverlay"},
|
||||
},
|
||||
{
|
||||
filter: filters.NewArgs(filters.Arg("type", "custom")),
|
||||
resultCount: 4,
|
||||
err: "",
|
||||
name: "custom driver filters",
|
||||
subtest: "driver=noname",
|
||||
filter: filters.NewArgs(filters.Arg("driver", "noname")),
|
||||
},
|
||||
{
|
||||
filter: filters.NewArgs(filters.Arg("type", "builtin")),
|
||||
resultCount: 3,
|
||||
err: "",
|
||||
name: "builtin driver filters",
|
||||
subtest: "type=custom",
|
||||
filter: filters.NewArgs(filters.Arg("type", "custom")),
|
||||
results: []string{"myoverlay", "mydrivernet", "mykvnet", "networkwithcontainer", "networkwithservice", "idoverlap"},
|
||||
},
|
||||
{
|
||||
filter: filters.NewArgs(filters.Arg("type", "invalid")),
|
||||
resultCount: 0,
|
||||
err: "invalid filter: 'type'='invalid'",
|
||||
name: "invalid driver filters",
|
||||
subtest: "type=builtin",
|
||||
filter: filters.NewArgs(filters.Arg("type", "builtin")),
|
||||
results: []string{network.NetworkHost, network.NetworkBridge, network.NetworkNone},
|
||||
},
|
||||
{
|
||||
filter: filters.NewArgs(filters.Arg("scope", "local")),
|
||||
resultCount: 5,
|
||||
err: "",
|
||||
name: "local scope filters",
|
||||
subtest: "type=invalid",
|
||||
filter: filters.NewArgs(filters.Arg("type", "invalid")),
|
||||
err: "invalid filter: 'type'='invalid'",
|
||||
},
|
||||
{
|
||||
filter: filters.NewArgs(filters.Arg("scope", "swarm")),
|
||||
resultCount: 1,
|
||||
err: "",
|
||||
name: "swarm scope filters",
|
||||
subtest: "scope=local",
|
||||
filter: filters.NewArgs(filters.Arg("scope", "local")),
|
||||
results: []string{network.NetworkHost, network.NetworkBridge, network.NetworkNone, "mydrivernet", "networkwithcontainer", "networkwithservice", "idoverlap"},
|
||||
},
|
||||
{
|
||||
filter: filters.NewArgs(filters.Arg("scope", "global")),
|
||||
resultCount: 1,
|
||||
err: "",
|
||||
name: "global scope filters",
|
||||
subtest: "scope=swarm",
|
||||
filter: filters.NewArgs(filters.Arg("scope", "swarm")),
|
||||
results: []string{"myoverlay"},
|
||||
},
|
||||
{
|
||||
filter: filters.NewArgs(filters.Arg("dangling", "true")),
|
||||
resultCount: 3,
|
||||
err: "",
|
||||
name: "dangling filter is 'True'",
|
||||
subtest: "scope=global",
|
||||
filter: filters.NewArgs(filters.Arg("scope", "global")),
|
||||
results: []string{"mykvnet"},
|
||||
},
|
||||
{
|
||||
subtest: "dangling=true",
|
||||
filter: filters.NewArgs(filters.Arg("dangling", "true")),
|
||||
results: []string{"myoverlay", "mydrivernet", "mykvnet", "idoverlap"},
|
||||
},
|
||||
{
|
||||
subtest: "dangling=1",
|
||||
filter: filters.NewArgs(filters.Arg("dangling", "1")),
|
||||
results: []string{"myoverlay", "mydrivernet", "mykvnet", "idoverlap"},
|
||||
},
|
||||
{
|
||||
subtest: "dangling=false",
|
||||
filter: filters.NewArgs(filters.Arg("dangling", "false")),
|
||||
results: []string{network.NetworkHost, network.NetworkBridge, network.NetworkNone, "networkwithcontainer", "networkwithservice"},
|
||||
},
|
||||
{
|
||||
subtest: "dangling=0",
|
||||
filter: filters.NewArgs(filters.Arg("dangling", "0")),
|
||||
results: []string{network.NetworkHost, network.NetworkBridge, network.NetworkNone, "networkwithcontainer", "networkwithservice"},
|
||||
},
|
||||
{
|
||||
subtest: "dangling=asdf",
|
||||
filter: filters.NewArgs(filters.Arg("dangling", "asdf")),
|
||||
err: "invalid value for filter 'dangling'",
|
||||
},
|
||||
{
|
||||
subtest: "MultipleTerms=dangling",
|
||||
filter: filters.NewArgs(filters.Arg("dangling", "1"), filters.Arg("dangling", "true")),
|
||||
err: `got more than one value for filter key "dangling"`,
|
||||
},
|
||||
{
|
||||
subtest: "label=foo",
|
||||
filter: filters.NewArgs(filters.Arg("label", "foo")),
|
||||
results: []string{"mydrivernet"},
|
||||
},
|
||||
{
|
||||
subtest: "label=foo=bar",
|
||||
filter: filters.NewArgs(filters.Arg("label", "foo=bar")),
|
||||
results: []string{"mydrivernet"},
|
||||
},
|
||||
{
|
||||
subtest: "label=foo=baz",
|
||||
filter: filters.NewArgs(filters.Arg("label", "foo=baz")),
|
||||
},
|
||||
{
|
||||
subtest: "label!=foo",
|
||||
filter: filters.NewArgs(filters.Arg("label!", "foo")),
|
||||
err: "invalid filter 'label!'",
|
||||
},
|
||||
{
|
||||
subtest: "until=1h",
|
||||
filter: filters.NewArgs(filters.Arg("until", "1h")),
|
||||
err: "invalid filter 'until'",
|
||||
},
|
||||
{
|
||||
subtest: "name=with",
|
||||
filter: filters.NewArgs(filters.Arg("name", "with")),
|
||||
results: []string{"networkwithcontainer", "networkwithservice"},
|
||||
},
|
||||
{
|
||||
subtest: "id=with/IDAlsoMatchesName=False",
|
||||
filter: filters.NewArgs(filters.Arg("id", "with")),
|
||||
},
|
||||
{
|
||||
subtest: "id=with/IDAlsoMatchesName=True",
|
||||
filter: filters.NewArgs(filters.Arg("id", "with")),
|
||||
idAlsoMatchesName: true,
|
||||
results: []string{"networkwithcontainer", "networkwithservice"},
|
||||
},
|
||||
{
|
||||
subtest: "id=jbexjvgu/IDAlsoMatchesName=False",
|
||||
filter: filters.NewArgs(filters.Arg("id", "argjbex")),
|
||||
results: []string{"networkwithcontainer", "networkwithservice"},
|
||||
},
|
||||
{
|
||||
subtest: "id=jbexjvgu/IDAlsoMatchesName=True",
|
||||
filter: filters.NewArgs(filters.Arg("id", "argjbex")),
|
||||
idAlsoMatchesName: true,
|
||||
results: []string{"networkwithcontainer", "networkwithservice"},
|
||||
},
|
||||
{
|
||||
subtest: "id=my/IDAlsoMatchesName=False",
|
||||
filter: filters.NewArgs(filters.Arg("id", "my")),
|
||||
results: []string{"idoverlap"},
|
||||
},
|
||||
{
|
||||
subtest: "id=my/IDAlsoMatchesName=True",
|
||||
filter: filters.NewArgs(filters.Arg("id", "my")),
|
||||
idAlsoMatchesName: true,
|
||||
results: []string{"myoverlay", "mydrivernet", "mykvnet", "idoverlap"},
|
||||
},
|
||||
{
|
||||
subtest: "Prune/empty",
|
||||
filter: filters.NewArgs(),
|
||||
pruneFilter: true,
|
||||
// Prune filters have an implicit dangling=true
|
||||
results: []string{"myoverlay", "mydrivernet", "mykvnet", "idoverlap"},
|
||||
},
|
||||
{
|
||||
subtest: "Prune/label=foo",
|
||||
filter: filters.NewArgs(filters.Arg("label", "foo")),
|
||||
pruneFilter: true,
|
||||
results: []string{"mydrivernet"},
|
||||
},
|
||||
{
|
||||
subtest: "Prune/label=foo=bar",
|
||||
filter: filters.NewArgs(filters.Arg("label", "foo=bar")),
|
||||
pruneFilter: true,
|
||||
results: []string{"mydrivernet"},
|
||||
},
|
||||
{
|
||||
subtest: "Prune/label=foo=baz",
|
||||
filter: filters.NewArgs(filters.Arg("label", "foo=baz")),
|
||||
pruneFilter: true,
|
||||
},
|
||||
{
|
||||
subtest: "Prune/label!=foo",
|
||||
filter: filters.NewArgs(filters.Arg("label!", "foo")),
|
||||
pruneFilter: true,
|
||||
results: []string{"myoverlay", "mykvnet", "idoverlap"},
|
||||
},
|
||||
{
|
||||
subtest: "Prune/until=2025-01-01",
|
||||
filter: filters.NewArgs(filters.Arg("until", "2025-01-01")),
|
||||
pruneFilter: true,
|
||||
results: []string{"myoverlay", "mydrivernet", "mykvnet"},
|
||||
},
|
||||
{
|
||||
filter: filters.NewArgs(filters.Arg("dangling", "false")),
|
||||
resultCount: 4,
|
||||
err: "",
|
||||
name: "dangling filter is 'False'",
|
||||
results: []string{"host", "bridge", "none", "networkwithcontainer"},
|
||||
subtest: "Prune/until=2024-12-01T01:00:00",
|
||||
filter: filters.NewArgs(filters.Arg("until", "2024-12-01T01:00:00")),
|
||||
pruneFilter: true,
|
||||
results: []string{"myoverlay"},
|
||||
},
|
||||
{
|
||||
subtest: "Prune/MultipleTerms=until",
|
||||
filter: filters.NewArgs(filters.Arg("until", "2024-12-01T01:00:00"), filters.Arg("until", "2h")),
|
||||
pruneFilter: true,
|
||||
err: "more than one until filter specified",
|
||||
},
|
||||
{
|
||||
subtest: "Prune/id=invalid",
|
||||
filter: filters.NewArgs(filters.Arg("id", "invalid")),
|
||||
pruneFilter: true,
|
||||
err: "invalid filter 'id'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
ls := make([]network.Inspect, 0, len(networks))
|
||||
ls = append(ls, networks...)
|
||||
result, err := FilterNetworks(ls, testCase.filter)
|
||||
if testCase.err != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("expect error '%s', got no error", testCase.err)
|
||||
} else if !strings.Contains(err.Error(), testCase.err) {
|
||||
t.Fatalf("expect error '%s', got '%s'", testCase.err, err)
|
||||
}
|
||||
t.Run(testCase.subtest, func(t *testing.T) {
|
||||
var (
|
||||
flt Filter
|
||||
err error
|
||||
)
|
||||
if testCase.pruneFilter {
|
||||
flt, err = NewPruneFilter(testCase.filter)
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("expect no error, got error '%s'", err)
|
||||
}
|
||||
// Make sure result is not nil
|
||||
if result == nil {
|
||||
t.Fatal("filterNetworks should not return nil")
|
||||
}
|
||||
flt, err = NewFilter(testCase.filter)
|
||||
}
|
||||
if testCase.err != "" {
|
||||
assert.ErrorContains(t, err, testCase.err)
|
||||
return
|
||||
}
|
||||
assert.NilError(t, err)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
flt.IDAlsoMatchesName = testCase.idAlsoMatchesName
|
||||
got := map[string]bool{}
|
||||
for _, nw := range networks {
|
||||
if flt.Matches(nw) {
|
||||
got[nw.Name()] = true
|
||||
}
|
||||
}
|
||||
|
||||
want := map[string]bool{}
|
||||
for _, r := range testCase.results {
|
||||
want[r] = true
|
||||
}
|
||||
assert.Check(t, is.DeepEqual(got, want))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/moby/moby/v2/daemon/internal/lazyregexp"
|
||||
"github.com/moby/moby/v2/daemon/internal/timestamp"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork"
|
||||
dnetwork "github.com/moby/moby/v2/daemon/network"
|
||||
"github.com/moby/moby/v2/daemon/server/backend"
|
||||
"github.com/moby/moby/v2/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
@@ -28,12 +29,6 @@ var (
|
||||
"label!": true,
|
||||
"until": true,
|
||||
}
|
||||
|
||||
networksAcceptedFilters = map[string]bool{
|
||||
"label": true,
|
||||
"label!": true,
|
||||
"until": true,
|
||||
}
|
||||
)
|
||||
|
||||
// ContainersPrune removes unused containers
|
||||
@@ -96,11 +91,9 @@ func (daemon *Daemon) ContainersPrune(ctx context.Context, pruneFilters filters.
|
||||
}
|
||||
|
||||
// localNetworksPrune removes unused local networks
|
||||
func (daemon *Daemon) localNetworksPrune(ctx context.Context, pruneFilters filters.Args) *network.PruneReport {
|
||||
func (daemon *Daemon) localNetworksPrune(ctx context.Context, pruneFilters dnetwork.Filter) *network.PruneReport {
|
||||
rep := &network.PruneReport{}
|
||||
|
||||
until, _ := getUntilFromPruneFilters(pruneFilters)
|
||||
|
||||
// When the function returns true, the walk will stop.
|
||||
daemon.netController.WalkNetworks(func(nw *libnetwork.Network) bool {
|
||||
select {
|
||||
@@ -112,10 +105,7 @@ func (daemon *Daemon) localNetworksPrune(ctx context.Context, pruneFilters filte
|
||||
if nw.ConfigOnly() {
|
||||
return false
|
||||
}
|
||||
if !until.IsZero() && nw.Created().After(until) {
|
||||
return false
|
||||
}
|
||||
if !matchLabels(pruneFilters, nw.Labels()) {
|
||||
if !pruneFilters.Matches(nw) {
|
||||
return false
|
||||
}
|
||||
if !nw.IsPruneable() {
|
||||
@@ -137,11 +127,9 @@ func (daemon *Daemon) localNetworksPrune(ctx context.Context, pruneFilters filte
|
||||
var networkIsInUse = lazyregexp.New(`network ([[:alnum:]]+) is in use`)
|
||||
|
||||
// clusterNetworksPrune removes unused cluster networks
|
||||
func (daemon *Daemon) clusterNetworksPrune(ctx context.Context, pruneFilters filters.Args) (*network.PruneReport, error) {
|
||||
func (daemon *Daemon) clusterNetworksPrune(ctx context.Context, pruneFilters dnetwork.Filter) (*network.PruneReport, error) {
|
||||
rep := &network.PruneReport{}
|
||||
|
||||
until, _ := getUntilFromPruneFilters(pruneFilters)
|
||||
|
||||
cluster := daemon.GetCluster()
|
||||
|
||||
if !cluster.IsManager() {
|
||||
@@ -162,12 +150,6 @@ func (daemon *Daemon) clusterNetworksPrune(ctx context.Context, pruneFilters fil
|
||||
// Routing-mesh network removal has to be explicitly invoked by user
|
||||
continue
|
||||
}
|
||||
if !until.IsZero() && nw.Created.After(until) {
|
||||
continue
|
||||
}
|
||||
if !matchLabels(pruneFilters, nw.Labels) {
|
||||
continue
|
||||
}
|
||||
// https://github.com/moby/moby/issues/24186
|
||||
// `docker network inspect` unfortunately displays ONLY those containers that are local to that node.
|
||||
// So we try to remove it anyway and check the error
|
||||
@@ -187,22 +169,17 @@ func (daemon *Daemon) clusterNetworksPrune(ctx context.Context, pruneFilters fil
|
||||
}
|
||||
|
||||
// NetworksPrune removes unused networks
|
||||
func (daemon *Daemon) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (*network.PruneReport, error) {
|
||||
func (daemon *Daemon) NetworksPrune(ctx context.Context, filterArgs filters.Args) (*network.PruneReport, error) {
|
||||
if !daemon.pruneRunning.CompareAndSwap(false, true) {
|
||||
return nil, errPruneRunning
|
||||
}
|
||||
defer daemon.pruneRunning.Store(false)
|
||||
|
||||
// make sure that only accepted filters have been received
|
||||
err := pruneFilters.Validate(networksAcceptedFilters)
|
||||
pruneFilters, err := dnetwork.NewPruneFilter(filterArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := getUntilFromPruneFilters(pruneFilters); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rep := &network.PruneReport{}
|
||||
if clusterRep, err := daemon.clusterNetworksPrune(ctx, pruneFilters); err == nil {
|
||||
rep.NetworksDeleted = append(rep.NetworksDeleted, clusterRep.NetworksDeleted...)
|
||||
|
||||
@@ -5,13 +5,14 @@ import (
|
||||
|
||||
"github.com/moby/moby/api/types/filters"
|
||||
"github.com/moby/moby/api/types/network"
|
||||
dnetwork "github.com/moby/moby/v2/daemon/network"
|
||||
"github.com/moby/moby/v2/daemon/server/backend"
|
||||
)
|
||||
|
||||
// Backend is all the methods that need to be implemented
|
||||
// to provide network specific functionality.
|
||||
type Backend interface {
|
||||
GetNetworks(filters.Args, backend.NetworkListConfig) ([]network.Inspect, error)
|
||||
GetNetworks(dnetwork.Filter, backend.NetworkListConfig) ([]network.Inspect, error)
|
||||
CreateNetwork(ctx context.Context, nc network.CreateRequest) (*network.CreateResponse, error)
|
||||
ConnectContainerToNetwork(ctx context.Context, containerName, networkName string, endpointConfig *network.EndpointSettings) error
|
||||
DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error
|
||||
@@ -22,7 +23,7 @@ type Backend interface {
|
||||
// ClusterBackend is all the methods that need to be implemented
|
||||
// to provide cluster network specific functionality.
|
||||
type ClusterBackend interface {
|
||||
GetNetworks(filters.Args) ([]network.Inspect, error)
|
||||
GetNetworks(dnetwork.Filter) ([]network.Inspect, error)
|
||||
GetNetwork(name string) (network.Inspect, error)
|
||||
GetNetworksByName(name string) ([]network.Inspect, error)
|
||||
CreateNetwork(nc network.CreateRequest) (string, error)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/moby/moby/api/types/versions"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork"
|
||||
"github.com/moby/moby/v2/daemon/libnetwork/scope"
|
||||
dnetwork "github.com/moby/moby/v2/daemon/network"
|
||||
"github.com/moby/moby/v2/daemon/server/backend"
|
||||
"github.com/moby/moby/v2/daemon/server/httputils"
|
||||
"github.com/moby/moby/v2/daemon/server/networkbackend"
|
||||
@@ -23,12 +24,13 @@ func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWrit
|
||||
return err
|
||||
}
|
||||
|
||||
filter, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
filterArgs, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := network.ValidateFilters(filter); err != nil {
|
||||
filter, err := dnetwork.NewFilter(filterArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -114,10 +116,16 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
||||
|
||||
// TODO(@cpuguy83): All this logic for figuring out which network to return does not belong here
|
||||
// Instead there should be a backend function to just get one network.
|
||||
filter := filters.NewArgs(filters.Arg("idOrName", term))
|
||||
filterArgs := filters.NewArgs(filters.Arg("id", term))
|
||||
if networkScope != "" {
|
||||
filter.Add("scope", networkScope)
|
||||
filterArgs.Add("scope", networkScope)
|
||||
}
|
||||
filter, err := dnetwork.NewFilter(filterArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filter.IDAlsoMatchesName = true
|
||||
|
||||
networks, _ := n.backend.GetNetworks(filter, backend.NetworkListConfig{Detailed: true, Verbose: verbose})
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
@@ -322,7 +330,12 @@ func (n *networkRouter) findUniqueNetwork(term string) (network.Inspect, error)
|
||||
listByFullName := map[string]network.Inspect{}
|
||||
listByPartialID := map[string]network.Inspect{}
|
||||
|
||||
filter := filters.NewArgs(filters.Arg("idOrName", term))
|
||||
filter, err := dnetwork.NewFilter(filters.NewArgs(filters.Arg("id", term)))
|
||||
if err != nil {
|
||||
return network.Inspect{}, err
|
||||
}
|
||||
filter.IDAlsoMatchesName = true
|
||||
|
||||
networks, _ := n.backend.GetNetworks(filter, backend.NetworkListConfig{Detailed: true})
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
|
||||
17
vendor/github.com/moby/moby/api/types/network/network.go
generated
vendored
17
vendor/github.com/moby/moby/api/types/network/network.go
generated
vendored
@@ -2,8 +2,6 @@ package network
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/moby/moby/api/types/filters"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -116,21 +114,6 @@ type ConfigReference struct {
|
||||
Network string
|
||||
}
|
||||
|
||||
var acceptedFilters = map[string]bool{
|
||||
"dangling": true,
|
||||
"driver": true,
|
||||
"id": true,
|
||||
"label": true,
|
||||
"name": true,
|
||||
"scope": true,
|
||||
"type": true,
|
||||
}
|
||||
|
||||
// ValidateFilters validates the list of filter args with the available filters.
|
||||
func ValidateFilters(filter filters.Args) error {
|
||||
return filter.Validate(acceptedFilters)
|
||||
}
|
||||
|
||||
// PruneReport contains the response for Engine API:
|
||||
// POST "/networks/prune"
|
||||
type PruneReport struct {
|
||||
|
||||
Reference in New Issue
Block a user