aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlo Lobrano <c.lobrano@gmail.com>2022-06-17 09:54:22 +0200
committerCarlo Lobrano <c.lobrano@gmail.com>2022-06-21 17:50:55 +0200
commit4a981c490be01547c17fb0b1fc4d1c3bfbf3551e (patch)
tree30f5c0a94a89d8a361272dd9243602e34890d927
parent78ecdad5f8f16dbb6146f2741a3d7ead1ce837bc (diff)
downloadpodman-4a981c490be01547c17fb0b1fc4d1c3bfbf3551e.tar.gz
podman-4a981c490be01547c17fb0b1fc4d1c3bfbf3551e.tar.bz2
podman-4a981c490be01547c17fb0b1fc4d1c3bfbf3551e.zip
allow filter networks by dangling status
add the ability to filter networks by their dangling status via: `network ls --filter dangling=true/false` Fixes: #14595 Signed-off-by: Carlo Lobrano <c.lobrano@gmail.com>
-rw-r--r--docs/source/markdown/podman-network-ls.1.md3
-rw-r--r--pkg/domain/infra/abi/network.go84
-rw-r--r--test/apiv2/35-networks.at4
-rw-r--r--test/e2e/network_test.go20
4 files changed, 86 insertions, 25 deletions
diff --git a/docs/source/markdown/podman-network-ls.1.md b/docs/source/markdown/podman-network-ls.1.md
index b341083f9..3c696d404 100644
--- a/docs/source/markdown/podman-network-ls.1.md
+++ b/docs/source/markdown/podman-network-ls.1.md
@@ -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`.
@@ -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'
diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go
index 47f7917f4..43047c936 100644
--- a/pkg/domain/infra/abi/network.go
+++ b/pkg/domain/infra/abi/network.go
@@ -2,6 +2,7 @@ package abi
import (
"context"
+ "strconv"
"github.com/containers/common/libnetwork/types"
netutil "github.com/containers/common/libnetwork/util"
@@ -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
}
@@ -144,6 +174,33 @@ func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string
// Network prune removes unused cni 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
@@ -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
}
diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at
index 4aad4563d..fcff26521 100644
--- a/test/apiv2/35-networks.at
+++ b/test/apiv2/35-networks.at
@@ -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 \
"[]"
diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go
index 715455521..2fdd62f7e 100644
--- a/test/e2e/network_test.go
+++ b/test/e2e/network_test.go
@@ -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