Skip to content

Commit

Permalink
Merge pull request #14643 from clobrano/feature/network/list/dangling…
Browse files Browse the repository at this point in the history
…/dev

allow filter networks by dangling status
  • Loading branch information
openshift-ci[bot] authored Jun 21, 2022
2 parents c9dce63 + 4a981c4 commit 8863e13
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 25 deletions.
3 changes: 3 additions & 0 deletions docs/source/markdown/podman-network-ls.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Supported filters:
| label | Filter by network with (or without, in the case of label!=[...] is used) the specified labels. |
| name | Filter by network name (accepts `regex`). |
| until | Filter by networks created before given timestamp. |
| dangling | Filter by networks with no containers attached. |


The `driver` filter accepts values: `bridge`, `macvlan`, `ipvlan`.
Expand All @@ -33,6 +34,8 @@ The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*k

The `until` *filter* can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.

The `dangling` *filter* accepts values `true` or `false`.

#### **--format**=*format*

Change the default output format. This can be of a supported type like 'json'
Expand Down
84 changes: 61 additions & 23 deletions pkg/domain/infra/abi/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package abi

import (
"context"
"strconv"

"github.com/containers/common/libnetwork/types"
netutil "github.com/containers/common/libnetwork/util"
Expand All @@ -12,10 +13,39 @@ import (
)

func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.NetworkListOptions) ([]types.Network, error) {
// dangling filter is not provided by netutil
var wantDangling bool

val, filterDangling := options.Filters["dangling"]
if filterDangling {
switch len(val) {
case 0:
return nil, errors.Errorf("got no values for filter key \"dangling\"")
case 1:
var err error
wantDangling, err = strconv.ParseBool(val[0])
if err != nil {
return nil, errors.Errorf("invalid dangling filter value \"%v\"", val[0])
}
delete(options.Filters, "dangling")
default:
return nil, errors.Errorf("got more than one value for filter key \"dangling\"")
}
}

filters, err := netutil.GenerateNetworkFilters(options.Filters)
if err != nil {
return nil, err
}

if filterDangling {
danglingFilterFunc, err := ic.createDanglingFilterFunc(wantDangling)
if err != nil {
return nil, err
}

filters = append(filters, danglingFilterFunc)
}
nets, err := ic.Libpod.Network().NetworkList(filters...)
return nets, err
}
Expand Down Expand Up @@ -144,6 +174,33 @@ func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string

// Network prune removes unused networks
func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.NetworkPruneOptions) ([]*entities.NetworkPruneReport, error) {
// get all filters
filters, err := netutil.GenerateNetworkPruneFilters(options.Filters)
if err != nil {
return nil, err
}
danglingFilterFunc, err := ic.createDanglingFilterFunc(true)
if err != nil {
return nil, err
}
filters = append(filters, danglingFilterFunc)
nets, err := ic.Libpod.Network().NetworkList(filters...)
if err != nil {
return nil, err
}

pruneReport := make([]*entities.NetworkPruneReport, 0, len(nets))
for _, net := range nets {
pruneReport = append(pruneReport, &entities.NetworkPruneReport{
Name: net.Name,
Error: ic.Libpod.Network().NetworkRemove(net.Name),
})
}
return pruneReport, nil
}

// danglingFilter function is special and not implemented in libnetwork filters
func (ic *ContainerEngine) createDanglingFilterFunc(wantDangling bool) (types.FilterFunc, error) {
cons, err := ic.Libpod.GetAllContainers()
if err != nil {
return nil, err
Expand All @@ -163,31 +220,12 @@ func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.Ne
// ignore the default network, this one cannot be deleted
networksToKeep[ic.Libpod.GetDefaultNetworkName()] = true

// get all filters
filters, err := netutil.GenerateNetworkPruneFilters(options.Filters)
if err != nil {
return nil, err
}
danglingFilterFunc := func(net types.Network) bool {
return func(net types.Network) bool {
for network := range networksToKeep {
if network == net.Name {
return false
return !wantDangling
}
}
return true
}
filters = append(filters, danglingFilterFunc)
nets, err := ic.Libpod.Network().NetworkList(filters...)
if err != nil {
return nil, err
}

pruneReport := make([]*entities.NetworkPruneReport, 0, len(nets))
for _, net := range nets {
pruneReport = append(pruneReport, &entities.NetworkPruneReport{
Name: net.Name,
Error: ic.Libpod.Network().NetworkRemove(net.Name),
})
}
return pruneReport, nil
return wantDangling
}, nil
}
4 changes: 2 additions & 2 deletions test/apiv2/35-networks.at
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ t GET networks?filters="{\"id\":[\"$network1_id\"]}" 200 \
.[0].Name=network1 \
.[0].Id=$network1_id
# invalid filter
t GET networks?filters='{"dangling":["1"]}' 500 \
.cause='invalid filter "dangling"'
t GET networks?filters='{"dangling":["true","0"]}' 500 \
.cause="got more than one value for filter key \"dangling\""
# (#9293 with no networks the endpoint should return empty array instead of null)
t GET networks?filters='{"name":["doesnotexists"]}' 200 \
"[]"
Expand Down
20 changes: 20 additions & 0 deletions test/e2e/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,26 @@ var _ = Describe("Podman network", func() {
Expect(session.OutputToString()).To(Not(ContainSubstring(name)))
})

It("podman network list --filter dangling", func() {
name, path := generateNetworkConfig(podmanTest)
defer removeConf(path)

session := podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=true"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring(name))

session = podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=false"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).NotTo(ContainSubstring(name))

session = podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=foo"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
Expect(session.ErrorToString()).To(ContainSubstring(`invalid dangling filter value "foo"`))
})

It("podman network ID test", func() {
net := "networkIDTest"
// the network id should be the sha256 hash of the network name
Expand Down

0 comments on commit 8863e13

Please sign in to comment.