Skip to content

Commit

Permalink
Merge pull request #9236 from baude/networkprune
Browse files Browse the repository at this point in the history
add network prune
  • Loading branch information
openshift-merge-robot authored Feb 8, 2021
2 parents 2aaf631 + 91ea3fa commit c32913d
Show file tree
Hide file tree
Showing 18 changed files with 447 additions and 22 deletions.
82 changes: 82 additions & 0 deletions cmd/podman/networks/prune.go
Original file line number Diff line number Diff line change
@@ -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 changes: 31 additions & 0 deletions docs/source/markdown/podman-network-prune.1.md
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
1 change: 1 addition & 0 deletions docs/source/markdown/podman-network.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |

Expand Down
2 changes: 2 additions & 0 deletions docs/source/network.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
50 changes: 42 additions & 8 deletions libpod/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
22 changes: 22 additions & 0 deletions pkg/api/handlers/compat/networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
7 changes: 7 additions & 0 deletions pkg/api/handlers/compat/swagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
14 changes: 14 additions & 0 deletions pkg/api/handlers/libpod/networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
66 changes: 53 additions & 13 deletions pkg/api/server/register_networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
// ---
Expand Down Expand Up @@ -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
}
18 changes: 18 additions & 0 deletions pkg/bindings/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
6 changes: 6 additions & 0 deletions pkg/bindings/network/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
}
Loading

0 comments on commit c32913d

Please sign in to comment.