mirror of
https://github.com/containers/podman.git
synced 2025-06-24 19:42:56 +08:00
82
cmd/podman/networks/prune.go
Normal file
82
cmd/podman/networks/prune.go
Normal file
@ -0,0 +1,82 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/podman/v2/cmd/podman/common"
|
||||
"github.com/containers/podman/v2/cmd/podman/registry"
|
||||
"github.com/containers/podman/v2/cmd/podman/utils"
|
||||
"github.com/containers/podman/v2/cmd/podman/validate"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var (
|
||||
networkPruneDescription = `Prune unused networks`
|
||||
networkPruneCommand = &cobra.Command{
|
||||
Use: "prune [options]",
|
||||
Short: "network prune",
|
||||
Long: networkPruneDescription,
|
||||
RunE: networkPrune,
|
||||
Example: `podman network prune`,
|
||||
Args: validate.NoArgs,
|
||||
ValidArgsFunction: common.AutocompleteNetworks,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
networkPruneOptions entities.NetworkPruneOptions
|
||||
force bool
|
||||
)
|
||||
|
||||
func networkPruneFlags(flags *pflag.FlagSet) {
|
||||
//TODO: Not implemented but for future reference
|
||||
//flags.StringSliceVar(&networkPruneOptions.Filters,"filters", []string{}, "provide filter values (e.g. 'until=<timestamp>')")
|
||||
flags.BoolVarP(&force, "force", "f", false, "do not prompt for confirmation")
|
||||
}
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: networkPruneCommand,
|
||||
Parent: networkCmd,
|
||||
})
|
||||
flags := networkPruneCommand.Flags()
|
||||
networkPruneFlags(flags)
|
||||
}
|
||||
|
||||
func networkPrune(cmd *cobra.Command, _ []string) error {
|
||||
var (
|
||||
errs utils.OutputErrors
|
||||
)
|
||||
if !force {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Println("WARNING! This will remove all networks not used by at least one container.")
|
||||
fmt.Print("Are you sure you want to continue? [y/N] ")
|
||||
answer, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.ToLower(answer)[0] != 'y' {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
responses, err := registry.ContainerEngine().NetworkPrune(registry.Context(), networkPruneOptions)
|
||||
if err != nil {
|
||||
setExitCode(err)
|
||||
return err
|
||||
}
|
||||
for _, r := range responses {
|
||||
if r.Error == nil {
|
||||
fmt.Println(r.Name)
|
||||
} else {
|
||||
setExitCode(r.Error)
|
||||
errs = append(errs, r.Error)
|
||||
}
|
||||
}
|
||||
return errs.PrintErrors()
|
||||
}
|
31
docs/source/markdown/podman-network-prune.1.md
Normal file
31
docs/source/markdown/podman-network-prune.1.md
Normal file
@ -0,0 +1,31 @@
|
||||
% podman-network-prune(1)
|
||||
|
||||
## NAME
|
||||
podman\-network\-prune - Remove all unused networks
|
||||
|
||||
## SYNOPSIS
|
||||
**podman network prune** [*options*]
|
||||
|
||||
## DESCRIPTION
|
||||
Remove all unused networks. An unused network is defined by a network which
|
||||
has no containers connected or configured to connect to it. It will not remove
|
||||
the so-called default network which goes by the name of *podman*.
|
||||
|
||||
## OPTIONS
|
||||
#### **--force**, **-f**
|
||||
|
||||
Do not prompt for confirmation
|
||||
|
||||
## EXAMPLE
|
||||
Prune networks
|
||||
|
||||
```
|
||||
podman network prune
|
||||
```
|
||||
|
||||
|
||||
## SEE ALSO
|
||||
podman(1), podman-network(1), podman-network-remove(1)
|
||||
|
||||
## HISTORY
|
||||
February 2021, Originally compiled by Brent Baude <bbaude@redhat.com>
|
@ -19,6 +19,7 @@ The network command manages CNI networks for Podman.
|
||||
| exists | [podman-network-exists(1)](podman-network-exists.1.md) | Check if the given network exists |
|
||||
| inspect | [podman-network-inspect(1)](podman-network-inspect.1.md) | Displays the raw CNI network configuration for one or more networks |
|
||||
| ls | [podman-network-ls(1)](podman-network-ls.1.md) | Display a summary of CNI networks |
|
||||
| prune | [podman-network-prune(1)](podman-network-prune.1.md) | Remove all unused networks |
|
||||
| reload | [podman-network-reload(1)](podman-network-reload.1.md) | Reload network configuration for containers |
|
||||
| rm | [podman-network-rm(1)](podman-network-rm.1.md) | Remove one or more CNI networks |
|
||||
|
||||
|
@ -13,6 +13,8 @@ Network
|
||||
|
||||
:doc:`ls <markdown/podman-network-ls.1>` network list
|
||||
|
||||
:doc:`prune <markdown/podman-network-prune.1>` network prune
|
||||
|
||||
:doc:`reload <markdown/podman-network-reload.1>` network reload
|
||||
|
||||
:doc:`rm <markdown/podman-network-rm.1>` network rm
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/containers/podman/v2/pkg/rootless"
|
||||
"github.com/containers/podman/v2/pkg/util"
|
||||
"github.com/pkg/errors"
|
||||
@ -174,14 +175,9 @@ func ValidateUserNetworkIsAvailable(config *config.Config, userNet *net.IPNet) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveNetwork removes a given network by name. If the network has container associated with it, that
|
||||
// must be handled outside the context of this.
|
||||
func RemoveNetwork(config *config.Config, name string) error {
|
||||
l, err := acquireCNILock(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer l.releaseCNILock()
|
||||
// removeNetwork is removes a cni network without a lock and should only be called
|
||||
// when a lock was otherwise acquired.
|
||||
func removeNetwork(config *config.Config, name string) error {
|
||||
cniPath, err := GetCNIConfigPathByNameOrID(config, name)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -213,6 +209,17 @@ func RemoveNetwork(config *config.Config, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveNetwork removes a given network by name. If the network has container associated with it, that
|
||||
// must be handled outside the context of this.
|
||||
func RemoveNetwork(config *config.Config, name string) error {
|
||||
l, err := acquireCNILock(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer l.releaseCNILock()
|
||||
return removeNetwork(config, name)
|
||||
}
|
||||
|
||||
// InspectNetwork reads a CNI config and returns its configuration
|
||||
func InspectNetwork(config *config.Config, name string) (map[string]interface{}, error) {
|
||||
b, err := ReadRawCNIConfByName(config, name)
|
||||
@ -243,3 +250,30 @@ func GetNetworkID(name string) string {
|
||||
hash := sha256.Sum256([]byte(name))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
// PruneNetworks removes networks that are not being used and that is not the default
|
||||
// network. To keep proper fencing for imports, you must provide the used networks
|
||||
// to this function as a map. the key is meaningful in the map, the book is a no-op
|
||||
func PruneNetworks(rtc *config.Config, usedNetworks map[string]bool) ([]*entities.NetworkPruneReport, error) {
|
||||
var reports []*entities.NetworkPruneReport
|
||||
lock, err := acquireCNILock(rtc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer lock.releaseCNILock()
|
||||
nets, err := GetNetworkNamesFromFileSystem(rtc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range nets {
|
||||
_, found := usedNetworks[n]
|
||||
// Remove is not default network and not found in the used list
|
||||
if n != rtc.Network.DefaultNetwork && !found {
|
||||
reports = append(reports, &entities.NetworkPruneReport{
|
||||
Name: n,
|
||||
Error: removeNetwork(rtc, n),
|
||||
})
|
||||
}
|
||||
}
|
||||
return reports, nil
|
||||
}
|
||||
|
@ -388,3 +388,25 @@ func Disconnect(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
utils.WriteResponse(w, http.StatusOK, "OK")
|
||||
}
|
||||
|
||||
// Prune removes unused networks
|
||||
func Prune(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO Filters are not implemented
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
ic := abi.ContainerEngine{Libpod: runtime}
|
||||
pruneOptions := entities.NetworkPruneOptions{}
|
||||
pruneReports, err := ic.NetworkPrune(r.Context(), pruneOptions)
|
||||
if err != nil {
|
||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
var prunedNetworks []string //nolint
|
||||
for _, pr := range pruneReports {
|
||||
if pr.Error != nil {
|
||||
logrus.Error(pr.Error)
|
||||
continue
|
||||
}
|
||||
prunedNetworks = append(prunedNetworks, pr.Name)
|
||||
}
|
||||
utils.WriteResponse(w, http.StatusOK, prunedNetworks)
|
||||
}
|
||||
|
@ -77,3 +77,10 @@ type swagCompatNetworkDisconnectRequest struct {
|
||||
// in:body
|
||||
Body struct{ types.NetworkDisconnect }
|
||||
}
|
||||
|
||||
// Network prune
|
||||
// swagger:response NetworkPruneResponse
|
||||
type swagCompatNetworkPruneResponse struct {
|
||||
// in:body
|
||||
Body []string
|
||||
}
|
||||
|
@ -175,3 +175,17 @@ func ExistsNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
utils.WriteResponse(w, http.StatusNoContent, "")
|
||||
}
|
||||
|
||||
// Prune removes unused networks
|
||||
func Prune(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO Filters are not implemented
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
ic := abi.ContainerEngine{Libpod: runtime}
|
||||
pruneOptions := entities.NetworkPruneOptions{}
|
||||
pruneReports, err := ic.NetworkPrune(r.Context(), pruneOptions)
|
||||
if err != nil {
|
||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
utils.WriteResponse(w, http.StatusOK, pruneReports)
|
||||
}
|
||||
|
@ -9,19 +9,6 @@ import (
|
||||
)
|
||||
|
||||
func (s *APIServer) registerNetworkHandlers(r *mux.Router) error {
|
||||
// swagger:operation POST /networks/prune compat compatPruneNetwork
|
||||
// ---
|
||||
// tags:
|
||||
// - networks (compat)
|
||||
// Summary: Delete unused networks
|
||||
// description: Not supported
|
||||
// produces:
|
||||
// - application/json
|
||||
// responses:
|
||||
// 404:
|
||||
// $ref: "#/responses/NoSuchNetwork"
|
||||
r.HandleFunc(VersionedPath("/networks/prune"), compat.UnsupportedHandler).Methods(http.MethodPost)
|
||||
r.HandleFunc("/networks/prune", compat.UnsupportedHandler).Methods(http.MethodPost)
|
||||
// swagger:operation DELETE /networks/{name} compat compatRemoveNetwork
|
||||
// ---
|
||||
// tags:
|
||||
@ -172,6 +159,35 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error {
|
||||
// $ref: "#/responses/InternalError"
|
||||
r.HandleFunc(VersionedPath("/networks/{name}/disconnect"), s.APIHandler(compat.Disconnect)).Methods(http.MethodPost)
|
||||
r.HandleFunc("/networks/{name}/disconnect", s.APIHandler(compat.Disconnect)).Methods(http.MethodPost)
|
||||
// swagger:operation POST /networks/prune compat compatPruneNetwork
|
||||
// ---
|
||||
// tags:
|
||||
// - networks (compat)
|
||||
// summary: Delete unused networks
|
||||
// description: Remove CNI networks that do not have containers
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - in: query
|
||||
// name: filters
|
||||
// type: string
|
||||
// description: |
|
||||
// NOT IMPLEMENTED
|
||||
// Filters to process on the prune list, encoded as JSON (a map[string][]string).
|
||||
// Available filters:
|
||||
// - until=<timestamp> Prune networks created before this timestamp. The <timestamp> can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the daemon machine’s time.
|
||||
// - label (label=<key>, label=<key>=<value>, label!=<key>, or label!=<key>=<value>) Prune networks with (or without, in case label!=... is used) the specified labels.
|
||||
// responses:
|
||||
// 200:
|
||||
// description: OK
|
||||
// schema:
|
||||
// type: array
|
||||
// items:
|
||||
// type: string
|
||||
// 500:
|
||||
// $ref: "#/responses/InternalError"
|
||||
r.HandleFunc(VersionedPath("/networks/prune"), s.APIHandler(compat.Prune)).Methods(http.MethodPost)
|
||||
r.HandleFunc("/networks/prune", s.APIHandler(compat.Prune)).Methods(http.MethodPost)
|
||||
|
||||
// swagger:operation DELETE /libpod/networks/{name} libpod libpodRemoveNetwork
|
||||
// ---
|
||||
@ -353,5 +369,29 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error {
|
||||
// 500:
|
||||
// $ref: "#/responses/InternalError"
|
||||
r.HandleFunc(VersionedPath("/libpod/networks/{name}/disconnect"), s.APIHandler(compat.Disconnect)).Methods(http.MethodPost)
|
||||
// swagger:operation POST /libpod/networks/prune libpod libpodPruneNetwork
|
||||
// ---
|
||||
// tags:
|
||||
// - networks
|
||||
// summary: Delete unused networks
|
||||
// description: Remove CNI networks that do not have containers
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - in: query
|
||||
// name: filters
|
||||
// type: string
|
||||
// description: |
|
||||
// NOT IMPLEMENTED
|
||||
// Filters to process on the prune list, encoded as JSON (a map[string][]string).
|
||||
// Available filters:
|
||||
// - until=<timestamp> Prune networks created before this timestamp. The <timestamp> can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the daemon machine’s time.
|
||||
// - label (label=<key>, label=<key>=<value>, label!=<key>, or label!=<key>=<value>) Prune networks with (or without, in case label!=... is used) the specified labels.
|
||||
// responses:
|
||||
// 200:
|
||||
// $ref: "#/responses/NetworkPruneResponse"
|
||||
// 500:
|
||||
// $ref: "#/responses/InternalError"
|
||||
r.HandleFunc(VersionedPath("/libpod/networks/prune"), s.APIHandler(libpod.Prune)).Methods(http.MethodPost)
|
||||
return nil
|
||||
}
|
||||
|
@ -180,3 +180,21 @@ func Exists(ctx context.Context, nameOrID string, options *ExistsOptions) (bool,
|
||||
}
|
||||
return response.IsSuccess(), nil
|
||||
}
|
||||
|
||||
// Prune removes unused CNI networks
|
||||
func Prune(ctx context.Context, options *PruneOptions) ([]*entities.NetworkPruneReport, error) {
|
||||
// TODO Filters is not implemented
|
||||
var (
|
||||
prunedNetworks []*entities.NetworkPruneReport
|
||||
)
|
||||
conn, err := bindings.GetClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := conn.DoRequest(nil, http.MethodPost, "/networks/prune", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return prunedNetworks, response.Process(&prunedNetworks)
|
||||
}
|
||||
|
@ -74,3 +74,9 @@ type ConnectOptions struct {
|
||||
// if a network exists
|
||||
type ExistsOptions struct {
|
||||
}
|
||||
|
||||
//go:generate go run ../generator/generator.go PruneOptions
|
||||
// PruneOptions are optional options for removing unused
|
||||
// CNI networks
|
||||
type PruneOptions struct {
|
||||
}
|
||||
|
75
pkg/bindings/network/types_prune_options.go
Normal file
75
pkg/bindings/network/types_prune_options.go
Normal file
@ -0,0 +1,75 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/podman/v2/pkg/bindings/util"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
/*
|
||||
This file is generated automatically by go generate. Do not edit.
|
||||
*/
|
||||
|
||||
// Changed
|
||||
func (o *PruneOptions) Changed(fieldName string) bool {
|
||||
r := reflect.ValueOf(o)
|
||||
value := reflect.Indirect(r).FieldByName(fieldName)
|
||||
return !value.IsNil()
|
||||
}
|
||||
|
||||
// ToParams
|
||||
func (o *PruneOptions) ToParams() (url.Values, error) {
|
||||
params := url.Values{}
|
||||
if o == nil {
|
||||
return params, nil
|
||||
}
|
||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
s := reflect.ValueOf(o)
|
||||
if reflect.Ptr == s.Kind() {
|
||||
s = s.Elem()
|
||||
}
|
||||
sType := s.Type()
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
fieldName := sType.Field(i).Name
|
||||
if !o.Changed(fieldName) {
|
||||
continue
|
||||
}
|
||||
fieldName = strings.ToLower(fieldName)
|
||||
f := s.Field(i)
|
||||
if reflect.Ptr == f.Kind() {
|
||||
f = f.Elem()
|
||||
}
|
||||
switch {
|
||||
case util.IsSimpleType(f):
|
||||
params.Set(fieldName, util.SimpleTypeToParam(f))
|
||||
case f.Kind() == reflect.Slice:
|
||||
for i := 0; i < f.Len(); i++ {
|
||||
elem := f.Index(i)
|
||||
if util.IsSimpleType(elem) {
|
||||
params.Add(fieldName, util.SimpleTypeToParam(elem))
|
||||
} else {
|
||||
return nil, errors.New("slices must contain only simple types")
|
||||
}
|
||||
}
|
||||
case f.Kind() == reflect.Map:
|
||||
lowerCaseKeys := make(map[string][]string)
|
||||
iter := f.MapRange()
|
||||
for iter.Next() {
|
||||
lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
|
||||
|
||||
}
|
||||
s, err := json.MarshalToString(lowerCaseKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params.Set(fieldName, s)
|
||||
}
|
||||
|
||||
}
|
||||
return params, nil
|
||||
}
|
@ -63,6 +63,7 @@ type ContainerEngine interface {
|
||||
NetworkExists(ctx context.Context, networkname string) (*BoolReport, error)
|
||||
NetworkInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]NetworkInspectReport, []error, error)
|
||||
NetworkList(ctx context.Context, options NetworkListOptions) ([]*NetworkListReport, error)
|
||||
NetworkPrune(ctx context.Context, options NetworkPruneOptions) ([]*NetworkPruneReport, error)
|
||||
NetworkReload(ctx context.Context, names []string, options NetworkReloadOptions) ([]*NetworkReloadReport, error)
|
||||
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
|
||||
PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error)
|
||||
|
@ -80,3 +80,15 @@ type NetworkConnectOptions struct {
|
||||
Aliases []string
|
||||
Container string
|
||||
}
|
||||
|
||||
// NetworkPruneReport containers the name of network and an error
|
||||
// associated in its pruning (removal)
|
||||
// swagger:model NetworkPruneReport
|
||||
type NetworkPruneReport struct {
|
||||
Name string
|
||||
Error error
|
||||
}
|
||||
|
||||
// NetworkPruneOptions describes options for pruning
|
||||
// unused cni networks
|
||||
type NetworkPruneOptions struct{}
|
||||
|
@ -155,3 +155,28 @@ func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string
|
||||
Value: exists,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Network prune removes unused cni networks
|
||||
func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.NetworkPruneOptions) ([]*entities.NetworkPruneReport, error) {
|
||||
runtimeConfig, err := ic.Libpod.GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cons, err := ic.Libpod.GetAllContainers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Gather up all the non-default networks that the
|
||||
// containers want
|
||||
usedNetworks := make(map[string]bool)
|
||||
for _, c := range cons {
|
||||
nets, _, err := c.Networks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, n := range nets {
|
||||
usedNetworks[n] = true
|
||||
}
|
||||
}
|
||||
return network.PruneNetworks(runtimeConfig, usedNetworks)
|
||||
}
|
||||
|
@ -89,3 +89,8 @@ func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string
|
||||
Value: exists,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Network prune removes unused cni networks
|
||||
func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.NetworkPruneOptions) ([]*entities.NetworkPruneReport, error) {
|
||||
return network.Prune(ic.ClientCtx, nil)
|
||||
}
|
||||
|
@ -484,7 +484,7 @@ class TestApi(unittest.TestCase):
|
||||
self.assertEqual(inspect.status_code, 404, inspect.content)
|
||||
|
||||
prune = requests.post(PODMAN_URL + "/v1.40/networks/prune")
|
||||
self.assertEqual(prune.status_code, 404, prune.content)
|
||||
self.assertEqual(prune.status_code, 200, prune.content)
|
||||
|
||||
def test_volumes_compat(self):
|
||||
name = "Volume_" + "".join(random.choice(string.ascii_letters) for i in range(10))
|
||||
|
@ -540,4 +540,54 @@ var _ = Describe("Podman network", func() {
|
||||
nc.WaitWithDefaultTimeout()
|
||||
Expect(nc.ExitCode()).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman network prune", func() {
|
||||
// Create two networks
|
||||
// Check they are there
|
||||
// Run a container on one of them
|
||||
// Network Prune
|
||||
// Check that one has been pruned, other remains
|
||||
net := "macvlan" + stringid.GenerateNonCryptoID()
|
||||
net1 := net + "1"
|
||||
net2 := net + "2"
|
||||
nc := podmanTest.Podman([]string{"network", "create", net1})
|
||||
nc.WaitWithDefaultTimeout()
|
||||
defer podmanTest.removeCNINetwork(net1)
|
||||
Expect(nc.ExitCode()).To(Equal(0))
|
||||
|
||||
nc2 := podmanTest.Podman([]string{"network", "create", net2})
|
||||
nc2.WaitWithDefaultTimeout()
|
||||
defer podmanTest.removeCNINetwork(net2)
|
||||
Expect(nc2.ExitCode()).To(Equal(0))
|
||||
|
||||
list := podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}}"})
|
||||
list.WaitWithDefaultTimeout()
|
||||
Expect(list.ExitCode()).To(BeZero())
|
||||
|
||||
Expect(StringInSlice(net1, list.OutputToStringArray())).To(BeTrue())
|
||||
Expect(StringInSlice(net2, list.OutputToStringArray())).To(BeTrue())
|
||||
if !isRootless() {
|
||||
Expect(StringInSlice("podman", list.OutputToStringArray())).To(BeTrue())
|
||||
}
|
||||
|
||||
session := podmanTest.Podman([]string{"run", "-dt", "--net", net2, ALPINE, "top"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
|
||||
prune := podmanTest.Podman([]string{"network", "prune", "-f"})
|
||||
prune.WaitWithDefaultTimeout()
|
||||
Expect(prune.ExitCode()).To(BeZero())
|
||||
|
||||
listAgain := podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}}"})
|
||||
listAgain.WaitWithDefaultTimeout()
|
||||
Expect(listAgain.ExitCode()).To(BeZero())
|
||||
|
||||
Expect(StringInSlice(net1, listAgain.OutputToStringArray())).To(BeFalse())
|
||||
Expect(StringInSlice(net2, listAgain.OutputToStringArray())).To(BeTrue())
|
||||
// Make sure default network 'podman' still exists
|
||||
if !isRootless() {
|
||||
Expect(StringInSlice("podman", list.OutputToStringArray())).To(BeTrue())
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
|
Reference in New Issue
Block a user