mirror of
https://github.com/containers/podman.git
synced 2025-06-21 09:28:09 +08:00
Merge pull request #3978 from baude/networkremove
enhance podman network rm
This commit is contained in:
@ -280,6 +280,7 @@ type NetworkListValues struct {
|
|||||||
|
|
||||||
type NetworkRmValues struct {
|
type NetworkRmValues struct {
|
||||||
PodmanCommand
|
PodmanCommand
|
||||||
|
Force bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type NetworkInspectValues struct {
|
type NetworkInspectValues struct {
|
||||||
|
@ -3,10 +3,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||||
"github.com/containers/libpod/pkg/adapter"
|
"github.com/containers/libpod/pkg/adapter"
|
||||||
"github.com/containers/libpod/pkg/rootless"
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,6 +34,8 @@ func init() {
|
|||||||
networkrmCommand.Command = _networkrmCommand
|
networkrmCommand.Command = _networkrmCommand
|
||||||
networkrmCommand.SetHelpTemplate(HelpTemplate())
|
networkrmCommand.SetHelpTemplate(HelpTemplate())
|
||||||
networkrmCommand.SetUsageTemplate(UsageTemplate())
|
networkrmCommand.SetUsageTemplate(UsageTemplate())
|
||||||
|
flags := networkrmCommand.Flags()
|
||||||
|
flags.BoolVarP(&networkrmCommand.Force, "force", "f", false, "remove any containers using network")
|
||||||
}
|
}
|
||||||
|
|
||||||
func networkrmCmd(c *cliconfig.NetworkRmValues) error {
|
func networkrmCmd(c *cliconfig.NetworkRmValues) error {
|
||||||
@ -40,9 +45,18 @@ func networkrmCmd(c *cliconfig.NetworkRmValues) error {
|
|||||||
if len(c.InputArgs) < 1 {
|
if len(c.InputArgs) < 1 {
|
||||||
return errors.Errorf("at least one network name is required")
|
return errors.Errorf("at least one network name is required")
|
||||||
}
|
}
|
||||||
runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
|
runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return runtime.NetworkRemove(c)
|
deletes, rmErrors, lastErr := runtime.NetworkRemove(getContext(), c)
|
||||||
|
for _, d := range deletes {
|
||||||
|
fmt.Println(d)
|
||||||
|
}
|
||||||
|
// we only want to print errors if there is more
|
||||||
|
// than one
|
||||||
|
for network, removalErr := range rmErrors {
|
||||||
|
logrus.Errorf("unable to remove %q: %q", network, removalErr)
|
||||||
|
}
|
||||||
|
return lastErr
|
||||||
}
|
}
|
||||||
|
@ -1032,6 +1032,8 @@ _podman_network_rm() {
|
|||||||
local options_with_args="
|
local options_with_args="
|
||||||
"
|
"
|
||||||
local boolean_options="
|
local boolean_options="
|
||||||
|
--force
|
||||||
|
-f
|
||||||
--help
|
--help
|
||||||
-h
|
-h
|
||||||
"
|
"
|
||||||
|
@ -9,13 +9,26 @@ podman\-network\-rm - Remove one or more CNI networks
|
|||||||
## DESCRIPTION
|
## DESCRIPTION
|
||||||
Delete one or more Podman networks.
|
Delete one or more Podman networks.
|
||||||
|
|
||||||
|
## OPTIONS
|
||||||
|
**--force**, **-f**
|
||||||
|
|
||||||
|
The `force` option will remove all containers that use the named network. If the container is
|
||||||
|
running, the container will be stopped and removed.
|
||||||
|
|
||||||
## EXAMPLE
|
## EXAMPLE
|
||||||
|
|
||||||
Delete the `podman9` network
|
Delete the `cni-podman9` network
|
||||||
|
|
||||||
```
|
```
|
||||||
# podman network rm podman
|
# podman network rm cni-podman9
|
||||||
Deleted: podman9
|
Deleted: cni-podman9
|
||||||
|
```
|
||||||
|
|
||||||
|
Delete the `fred` network and all containers associated with the network.
|
||||||
|
|
||||||
|
```
|
||||||
|
# podman network rm -f fred
|
||||||
|
Deleted: fred
|
||||||
```
|
```
|
||||||
|
|
||||||
## SEE ALSO
|
## SEE ALSO
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
package adapter
|
package adapter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/containers/libpod/pkg/util"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -14,6 +14,7 @@ import (
|
|||||||
cniversion "github.com/containernetworking/cni/pkg/version"
|
cniversion "github.com/containernetworking/cni/pkg/version"
|
||||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||||
"github.com/containers/libpod/pkg/network"
|
"github.com/containers/libpod/pkg/network"
|
||||||
|
"github.com/containers/libpod/pkg/util"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -85,16 +86,69 @@ func (r *LocalRuntime) NetworkInspect(cli *cliconfig.NetworkInspectValues) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NetworkRemove deletes one or more CNI networks
|
// NetworkRemove deletes one or more CNI networks
|
||||||
func (r *LocalRuntime) NetworkRemove(cli *cliconfig.NetworkRmValues) error {
|
func (r *LocalRuntime) NetworkRemove(ctx context.Context, cli *cliconfig.NetworkRmValues) ([]string, map[string]error, error) {
|
||||||
|
var (
|
||||||
|
networkRmSuccesses []string
|
||||||
|
lastError error
|
||||||
|
)
|
||||||
|
networkRmErrors := make(map[string]error)
|
||||||
|
|
||||||
for _, name := range cli.InputArgs {
|
for _, name := range cli.InputArgs {
|
||||||
|
containers, err := r.GetAllContainers()
|
||||||
|
if err != nil {
|
||||||
|
return networkRmSuccesses, networkRmErrors, err
|
||||||
|
}
|
||||||
|
if err := r.removeNetwork(ctx, name, containers, cli.Force); err != nil {
|
||||||
|
if lastError != nil {
|
||||||
|
networkRmErrors[name] = lastError
|
||||||
|
}
|
||||||
|
lastError = err
|
||||||
|
} else {
|
||||||
|
networkRmSuccesses = append(networkRmSuccesses, fmt.Sprintf("Deleted: %s\n", name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return networkRmSuccesses, networkRmErrors, lastError
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeNetwork removes a single network and its containers given a force bool
|
||||||
|
func (r *LocalRuntime) removeNetwork(ctx context.Context, name string, containers []*Container, force bool) error {
|
||||||
cniPath, err := network.GetCNIConfigPathByName(name)
|
cniPath, err := network.GetCNIConfigPathByName(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := os.Remove(cniPath); err != nil {
|
// We need to iterate containers looking to see if they belong to the given network
|
||||||
|
for _, c := range containers {
|
||||||
|
if util.StringInSlice(name, c.Config().Networks) {
|
||||||
|
// if user passes force, we nuke containers
|
||||||
|
if force {
|
||||||
|
if err := r.RemoveContainer(ctx, c.Container, true, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Deleted: %s\n", name)
|
} else {
|
||||||
|
// Without the the force option, we return an error
|
||||||
|
return errors.Errorf("%q has associated containers with it. use -f to forcibly delete containers", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Before we delete the configuration file, we need to make sure we can read and parse
|
||||||
|
// it to get the network interface name so we can remove that too
|
||||||
|
interfaceName, err := network.GetInterfaceNameFromConfig(cniPath)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to find network interface name in %q", cniPath)
|
||||||
|
}
|
||||||
|
liveNetworkNames, err := network.GetLiveNetworkNames()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to get live network names")
|
||||||
|
}
|
||||||
|
if util.StringInSlice(interfaceName, liveNetworkNames) {
|
||||||
|
if err := network.RemoveInterface(interfaceName); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to delete the network interface %q", interfaceName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remove the configuration file
|
||||||
|
if err := os.Remove(cniPath); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to remove network configuration file %q", cniPath)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@ package network
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/containers/libpod/pkg/util"
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/containers/libpod/pkg/util"
|
||||||
|
"github.com/containers/libpod/utils"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,3 +41,15 @@ func GetFreeDeviceName() (string, error) {
|
|||||||
}
|
}
|
||||||
return deviceName, nil
|
return deviceName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveInterface removes an interface by the given name
|
||||||
|
func RemoveInterface(interfaceName string) error {
|
||||||
|
// Make sure we have the ip command on the system
|
||||||
|
ipPath, err := exec.LookPath("ip")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Delete the network interface
|
||||||
|
_, err = utils.ExecCmd(ipPath, []string{"link", "del", interfaceName}...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
@ -86,6 +86,7 @@ func GetNetworksFromFilesystem() ([]*allocator.Net, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cniNetworks = append(cniNetworks, &ipamConf)
|
cniNetworks = append(cniNetworks, &ipamConf)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,3 +106,26 @@ func GetNetworkNamesFromFileSystem() ([]string, error) {
|
|||||||
}
|
}
|
||||||
return networkNames, nil
|
return networkNames, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetInterfaceNameFromConfig returns the interface name for the bridge plugin
|
||||||
|
func GetInterfaceNameFromConfig(path string) (string, error) {
|
||||||
|
var name string
|
||||||
|
conf, err := libcni.ConfListFromFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for _, cniplugin := range conf.Plugins {
|
||||||
|
if cniplugin.Network.Type == "bridge" {
|
||||||
|
plugin := make(map[string]interface{})
|
||||||
|
if err := json.Unmarshal(cniplugin.Bytes, &plugin); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
name = plugin["bridge"].(string)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(name) == 0 {
|
||||||
|
return "", errors.New("unable to find interface name for network")
|
||||||
|
}
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user