mirror of https://github.com/containers/podman.git
				
				
				
			Merge pull request #3978 from baude/networkremove
enhance podman network rm
This commit is contained in:
		
						commit
						b43a36d7a3
					
				|  | @ -280,6 +280,7 @@ type NetworkListValues struct { | |||
| 
 | ||||
| type NetworkRmValues struct { | ||||
| 	PodmanCommand | ||||
| 	Force bool | ||||
| } | ||||
| 
 | ||||
| type NetworkInspectValues struct { | ||||
|  |  | |||
|  | @ -3,10 +3,13 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/cmd/podman/cliconfig" | ||||
| 	"github.com/containers/libpod/pkg/adapter" | ||||
| 	"github.com/containers/libpod/pkg/rootless" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
| 
 | ||||
|  | @ -31,6 +34,8 @@ func init() { | |||
| 	networkrmCommand.Command = _networkrmCommand | ||||
| 	networkrmCommand.SetHelpTemplate(HelpTemplate()) | ||||
| 	networkrmCommand.SetUsageTemplate(UsageTemplate()) | ||||
| 	flags := networkrmCommand.Flags() | ||||
| 	flags.BoolVarP(&networkrmCommand.Force, "force", "f", false, "remove any containers using network") | ||||
| } | ||||
| 
 | ||||
| func networkrmCmd(c *cliconfig.NetworkRmValues) error { | ||||
|  | @ -40,9 +45,18 @@ func networkrmCmd(c *cliconfig.NetworkRmValues) error { | |||
| 	if len(c.InputArgs) < 1 { | ||||
| 		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 { | ||||
| 		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 boolean_options=" | ||||
|     --force | ||||
|     -f | ||||
|     --help | ||||
|     -h | ||||
|     " | ||||
|  |  | |||
|  | @ -9,13 +9,26 @@ podman\-network\-rm - Remove one or more CNI networks | |||
| ## DESCRIPTION | ||||
| 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 | ||||
| 
 | ||||
| Delete the `podman9` network | ||||
| Delete the `cni-podman9` network | ||||
| 
 | ||||
| ``` | ||||
| # podman network rm podman | ||||
| Deleted: podman9 | ||||
| # podman network rm cni-podman9 | ||||
| Deleted: cni-podman9 | ||||
| ``` | ||||
| 
 | ||||
| Delete the `fred` network and all containers associated with the network. | ||||
| 
 | ||||
| ``` | ||||
| # podman network rm -f fred | ||||
| Deleted: fred | ||||
| ``` | ||||
| 
 | ||||
| ## SEE ALSO | ||||
|  |  | |||
|  | @ -3,9 +3,9 @@ | |||
| package adapter | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"github.com/containers/libpod/pkg/util" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | @ -14,6 +14,7 @@ import ( | |||
| 	cniversion "github.com/containernetworking/cni/pkg/version" | ||||
| 	"github.com/containers/libpod/cmd/podman/cliconfig" | ||||
| 	"github.com/containers/libpod/pkg/network" | ||||
| 	"github.com/containers/libpod/pkg/util" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
| 
 | ||||
|  | @ -85,16 +86,69 @@ func (r *LocalRuntime) NetworkInspect(cli *cliconfig.NetworkInspectValues) error | |||
| } | ||||
| 
 | ||||
| // 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 { | ||||
| 		cniPath, err := network.GetCNIConfigPathByName(name) | ||||
| 		containers, err := r.GetAllContainers() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 			return networkRmSuccesses, networkRmErrors, err | ||||
| 		} | ||||
| 		if err := os.Remove(cniPath); err != nil { | ||||
| 			return 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)) | ||||
| 		} | ||||
| 		fmt.Printf("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) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	// 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 | ||||
| 				} | ||||
| 			} 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 | ||||
| } | ||||
|  |  | |||
|  | @ -2,8 +2,10 @@ package network | |||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/containers/libpod/pkg/util" | ||||
| 	"os/exec" | ||||
| 
 | ||||
| 	"github.com/containers/libpod/pkg/util" | ||||
| 	"github.com/containers/libpod/utils" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
| 
 | ||||
|  | @ -39,3 +41,15 @@ func GetFreeDeviceName() (string, error) { | |||
| 	} | ||||
| 	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 | ||||
| 				} | ||||
| 				cniNetworks = append(cniNetworks, &ipamConf) | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -105,3 +106,26 @@ func GetNetworkNamesFromFileSystem() ([]string, error) { | |||
| 	} | ||||
| 	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 | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue