mirror of
https://github.com/containers/podman.git
synced 2025-06-29 06:57:13 +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. |
|
| label | Filter by network with (or without, in the case of label!=[...] is used) the specified labels. |
|
||||||
| name | Filter by network name (accepts `regex`). |
|
| name | Filter by network name (accepts `regex`). |
|
||||||
| until | Filter by networks created before given timestamp. |
|
| until | Filter by networks created before given timestamp. |
|
||||||
|
| dangling | Filter by networks with no containers attached. |
|
||||||
|
|
||||||
|
|
||||||
The `driver` filter accepts values: `bridge`, `macvlan`, `ipvlan`.
|
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 `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*
|
#### **--format**=*format*
|
||||||
|
|
||||||
Change the default output format. This can be of a supported type like 'json'
|
Change the default output format. This can be of a supported type like 'json'
|
||||||
|
@ -2,6 +2,7 @@ package abi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/containers/common/libnetwork/types"
|
"github.com/containers/common/libnetwork/types"
|
||||||
netutil "github.com/containers/common/libnetwork/util"
|
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) {
|
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)
|
filters, err := netutil.GenerateNetworkFilters(options.Filters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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...)
|
nets, err := ic.Libpod.Network().NetworkList(filters...)
|
||||||
return nets, err
|
return nets, err
|
||||||
}
|
}
|
||||||
@ -144,6 +174,33 @@ func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string
|
|||||||
|
|
||||||
// Network prune removes unused cni networks
|
// Network prune removes unused cni networks
|
||||||
func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.NetworkPruneOptions) ([]*entities.NetworkPruneReport, error) {
|
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()
|
cons, err := ic.Libpod.GetAllContainers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// ignore the default network, this one cannot be deleted
|
||||||
networksToKeep[ic.Libpod.GetDefaultNetworkName()] = true
|
networksToKeep[ic.Libpod.GetDefaultNetworkName()] = true
|
||||||
|
|
||||||
// get all filters
|
return func(net types.Network) bool {
|
||||||
filters, err := netutil.GenerateNetworkPruneFilters(options.Filters)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
danglingFilterFunc := func(net types.Network) bool {
|
|
||||||
for network := range networksToKeep {
|
for network := range networksToKeep {
|
||||||
if network == net.Name {
|
if network == net.Name {
|
||||||
return false
|
return !wantDangling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return wantDangling
|
||||||
}
|
}, nil
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
@ -78,8 +78,8 @@ t GET networks?filters="{\"id\":[\"$network1_id\"]}" 200 \
|
|||||||
.[0].Name=network1 \
|
.[0].Name=network1 \
|
||||||
.[0].Id=$network1_id
|
.[0].Id=$network1_id
|
||||||
# invalid filter
|
# invalid filter
|
||||||
t GET networks?filters='{"dangling":["1"]}' 500 \
|
t GET networks?filters='{"dangling":["true","0"]}' 500 \
|
||||||
.cause='invalid filter "dangling"'
|
.cause="got more than one value for filter key \"dangling\""
|
||||||
# (#9293 with no networks the endpoint should return empty array instead of null)
|
# (#9293 with no networks the endpoint should return empty array instead of null)
|
||||||
t GET networks?filters='{"name":["doesnotexists"]}' 200 \
|
t GET networks?filters='{"name":["doesnotexists"]}' 200 \
|
||||||
"[]"
|
"[]"
|
||||||
|
@ -163,6 +163,26 @@ var _ = Describe("Podman network", func() {
|
|||||||
Expect(session.OutputToString()).To(Not(ContainSubstring(name)))
|
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() {
|
It("podman network ID test", func() {
|
||||||
net := "networkIDTest"
|
net := "networkIDTest"
|
||||||
// the network id should be the sha256 hash of the network name
|
// the network id should be the sha256 hash of the network name
|
||||||
|
Reference in New Issue
Block a user