mirror of
https://github.com/containers/podman.git
synced 2025-06-28 22:53:21 +08:00
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>
This commit is contained in:
@ -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'
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 \
|
||||
"[]"
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user