278 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			278 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Go
		
	
	
	
// +build !remoteclient
 | 
						|
 | 
						|
package adapter
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"io/ioutil"
 | 
						|
	"os"
 | 
						|
	"path/filepath"
 | 
						|
	"text/tabwriter"
 | 
						|
 | 
						|
	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"
 | 
						|
)
 | 
						|
 | 
						|
func getCNIConfDir(r *LocalRuntime) (string, error) {
 | 
						|
	config, err := r.GetConfig()
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	configPath := config.CNIConfigDir
 | 
						|
 | 
						|
	if len(config.CNIConfigDir) < 1 {
 | 
						|
		configPath = network.CNIConfigDir
 | 
						|
	}
 | 
						|
	return configPath, nil
 | 
						|
}
 | 
						|
 | 
						|
// NetworkList displays summary information about CNI networks
 | 
						|
func (r *LocalRuntime) NetworkList(cli *cliconfig.NetworkListValues) error {
 | 
						|
	cniConfigPath, err := getCNIConfDir(r)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	networks, err := network.LoadCNIConfsFromDir(cniConfigPath)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	// quiet means we only print the network names
 | 
						|
	if cli.Quiet {
 | 
						|
		for _, cniNetwork := range networks {
 | 
						|
			fmt.Println(cniNetwork.Name)
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
 | 
						|
	if _, err := fmt.Fprintln(w, "NAME\tVERSION\tPLUGINS"); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	for _, cniNetwork := range networks {
 | 
						|
		if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n", cniNetwork.Name, cniNetwork.CNIVersion, network.GetCNIPlugins(cniNetwork)); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return w.Flush()
 | 
						|
}
 | 
						|
 | 
						|
// NetworkInspect displays the raw CNI configuration for one
 | 
						|
// or more CNI networks
 | 
						|
func (r *LocalRuntime) NetworkInspect(cli *cliconfig.NetworkInspectValues) error {
 | 
						|
	var (
 | 
						|
		rawCNINetworks []map[string]interface{}
 | 
						|
	)
 | 
						|
	for _, name := range cli.InputArgs {
 | 
						|
		rawList, err := network.InspectNetwork(name)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		rawCNINetworks = append(rawCNINetworks, rawList)
 | 
						|
	}
 | 
						|
	out, err := json.MarshalIndent(rawCNINetworks, "", "\t")
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	fmt.Printf("%s\n", out)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// NetworkRemove deletes one or more CNI networks
 | 
						|
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 {
 | 
						|
		containers, err := r.GetAllContainers()
 | 
						|
		if err != nil {
 | 
						|
			return networkRmSuccesses, networkRmErrors, 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 !cli.Force {
 | 
						|
					// Without the force option, we return an error
 | 
						|
					return nil, nil, errors.Errorf("%q has associated containers with it. Use -f to forcibly delete containers", name)
 | 
						|
				}
 | 
						|
				if err := r.RemoveContainer(ctx, c.Container, true, true); err != nil {
 | 
						|
					return nil, nil, err
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if err := network.RemoveNetwork(name); err != nil {
 | 
						|
			if lastError != nil {
 | 
						|
				networkRmErrors[name] = lastError
 | 
						|
			}
 | 
						|
			lastError = err
 | 
						|
		} else {
 | 
						|
			networkRmSuccesses = append(networkRmSuccesses, fmt.Sprintf("Deleted: %s\n", name))
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return networkRmSuccesses, networkRmErrors, lastError
 | 
						|
}
 | 
						|
 | 
						|
// NetworkCreateBridge creates a CNI network
 | 
						|
func (r *LocalRuntime) NetworkCreateBridge(cli *cliconfig.NetworkCreateValues) (string, error) {
 | 
						|
	isGateway := true
 | 
						|
	ipMasq := true
 | 
						|
	subnet := &cli.Network
 | 
						|
	ipRange := cli.IPRange
 | 
						|
	runtimeConfig, err := r.GetConfig()
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	// if range is provided, make sure it is "in" network
 | 
						|
	if cli.IsSet("subnet") {
 | 
						|
		// if network is provided, does it conflict with existing CNI or live networks
 | 
						|
		err = network.ValidateUserNetworkIsAvailable(subnet)
 | 
						|
	} else {
 | 
						|
		// if no network is provided, figure out network
 | 
						|
		subnet, err = network.GetFreeNetwork()
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	gateway := cli.Gateway
 | 
						|
	if gateway == nil {
 | 
						|
		// if no gateway is provided, provide it as first ip of network
 | 
						|
		gateway = network.CalcGatewayIP(subnet)
 | 
						|
	}
 | 
						|
	// if network is provided and if gateway is provided, make sure it is "in" network
 | 
						|
	if cli.IsSet("subnet") && cli.IsSet("gateway") {
 | 
						|
		if !subnet.Contains(gateway) {
 | 
						|
			return "", errors.Errorf("gateway %s is not in valid for subnet %s", gateway.String(), subnet.String())
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if cli.Internal {
 | 
						|
		isGateway = false
 | 
						|
		ipMasq = false
 | 
						|
	}
 | 
						|
 | 
						|
	// if a range is given, we need to ensure it is "in" the network range.
 | 
						|
	if cli.IsSet("ip-range") {
 | 
						|
		if !cli.IsSet("subnet") {
 | 
						|
			return "", errors.New("you must define a subnet range to define an ip-range")
 | 
						|
		}
 | 
						|
		firstIP, err := network.FirstIPInSubnet(&cli.IPRange)
 | 
						|
		if err != nil {
 | 
						|
			return "", err
 | 
						|
		}
 | 
						|
		lastIP, err := network.LastIPInSubnet(&cli.IPRange)
 | 
						|
		if err != nil {
 | 
						|
			return "", err
 | 
						|
		}
 | 
						|
		if !subnet.Contains(firstIP) || !subnet.Contains(lastIP) {
 | 
						|
			return "", errors.Errorf("the ip range %s does not fall within the subnet range %s", cli.IPRange.String(), subnet.String())
 | 
						|
		}
 | 
						|
	}
 | 
						|
	bridgeDeviceName, err := network.GetFreeDeviceName()
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	// If no name is given, we give the name of the bridge device
 | 
						|
	name := bridgeDeviceName
 | 
						|
	if len(cli.InputArgs) > 0 {
 | 
						|
		name = cli.InputArgs[0]
 | 
						|
		netNames, err := network.GetNetworkNamesFromFileSystem()
 | 
						|
		if err != nil {
 | 
						|
			return "", err
 | 
						|
		}
 | 
						|
		if util.StringInSlice(name, netNames) {
 | 
						|
			return "", errors.Errorf("the network name %s is already used", name)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	ncList := network.NewNcList(name, cniversion.Current())
 | 
						|
	var plugins []network.CNIPlugins
 | 
						|
	var routes []network.IPAMRoute
 | 
						|
 | 
						|
	defaultRoute, err := network.NewIPAMDefaultRoute()
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	routes = append(routes, defaultRoute)
 | 
						|
	ipamConfig, err := network.NewIPAMHostLocalConf(subnet, routes, ipRange, gateway)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	// TODO need to iron out the role of isDefaultGW and IPMasq
 | 
						|
	bridge := network.NewHostLocalBridge(bridgeDeviceName, isGateway, false, ipMasq, ipamConfig)
 | 
						|
	plugins = append(plugins, bridge)
 | 
						|
	plugins = append(plugins, network.NewPortMapPlugin())
 | 
						|
	plugins = append(plugins, network.NewFirewallPlugin())
 | 
						|
	// if we find the dnsname plugin, we add configuration for it
 | 
						|
	if network.HasDNSNamePlugin(runtimeConfig.CNIPluginDir) && !cli.DisableDNS {
 | 
						|
		// Note: in the future we might like to allow for dynamic domain names
 | 
						|
		plugins = append(plugins, network.NewDNSNamePlugin(network.DefaultPodmanDomainName))
 | 
						|
	}
 | 
						|
	ncList["plugins"] = plugins
 | 
						|
	b, err := json.MarshalIndent(ncList, "", "   ")
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	cniConfigPath, err := getCNIConfDir(r)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	cniPathName := filepath.Join(cniConfigPath, fmt.Sprintf("%s.conflist", name))
 | 
						|
	err = ioutil.WriteFile(cniPathName, b, 0644)
 | 
						|
	return cniPathName, err
 | 
						|
}
 | 
						|
 | 
						|
// NetworkCreateMacVLAN creates a CNI network
 | 
						|
func (r *LocalRuntime) NetworkCreateMacVLAN(cli *cliconfig.NetworkCreateValues) (string, error) {
 | 
						|
	var (
 | 
						|
		name    string
 | 
						|
		plugins []network.CNIPlugins
 | 
						|
	)
 | 
						|
	liveNetNames, err := network.GetLiveNetworkNames()
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	// Make sure the host-device exists
 | 
						|
	if !util.StringInSlice(cli.MacVLAN, liveNetNames) {
 | 
						|
		return "", errors.Errorf("failed to find network interface %q", cli.MacVLAN)
 | 
						|
	}
 | 
						|
	if len(cli.InputArgs) > 0 {
 | 
						|
		name = cli.InputArgs[0]
 | 
						|
		netNames, err := network.GetNetworkNamesFromFileSystem()
 | 
						|
		if err != nil {
 | 
						|
			return "", err
 | 
						|
		}
 | 
						|
		if util.StringInSlice(name, netNames) {
 | 
						|
			return "", errors.Errorf("the network name %s is already used", name)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if len(name) < 1 {
 | 
						|
		name, err = network.GetFreeDeviceName()
 | 
						|
		if err != nil {
 | 
						|
			return "", err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	ncList := network.NewNcList(name, cniversion.Current())
 | 
						|
	macvlan := network.NewMacVLANPlugin(cli.MacVLAN)
 | 
						|
	plugins = append(plugins, macvlan)
 | 
						|
	ncList["plugins"] = plugins
 | 
						|
	b, err := json.MarshalIndent(ncList, "", "   ")
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	cniConfigPath, err := getCNIConfDir(r)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	cniPathName := filepath.Join(cniConfigPath, fmt.Sprintf("%s.conflist", name))
 | 
						|
	err = ioutil.WriteFile(cniPathName, b, 0644)
 | 
						|
	return cniPathName, err
 | 
						|
}
 |