github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/network/files.go (about)

     1  package network
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/containernetworking/cni/libcni"
    11  	"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
    12  	"github.com/containers/common/pkg/config"
    13  	"github.com/containers/podman/v2/libpod/define"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  // ErrNoSuchNetworkInterface indicates that no network interface exists
    18  var ErrNoSuchNetworkInterface = errors.New("unable to find interface name for network")
    19  
    20  // GetCNIConfDir get CNI configuration directory
    21  func GetCNIConfDir(configArg *config.Config) string {
    22  	if len(configArg.Network.NetworkConfigDir) < 1 {
    23  		dc, err := config.DefaultConfig()
    24  		if err != nil {
    25  			// Fallback to hard-coded dir
    26  			return CNIConfigDir
    27  		}
    28  		return dc.Network.NetworkConfigDir
    29  	}
    30  	return configArg.Network.NetworkConfigDir
    31  }
    32  
    33  // LoadCNIConfsFromDir loads all the CNI configurations from a dir
    34  func LoadCNIConfsFromDir(dir string) ([]*libcni.NetworkConfigList, error) {
    35  	files, err := libcni.ConfFiles(dir, []string{".conflist"})
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	sort.Strings(files)
    40  
    41  	configs := make([]*libcni.NetworkConfigList, 0, len(files))
    42  	for _, confFile := range files {
    43  		conf, err := libcni.ConfListFromFile(confFile)
    44  		if err != nil {
    45  			return nil, errors.Wrapf(err, "in %s", confFile)
    46  		}
    47  		configs = append(configs, conf)
    48  	}
    49  	return configs, nil
    50  }
    51  
    52  // GetCNIConfigPathByName finds a CNI network by name and
    53  // returns its configuration file path
    54  func GetCNIConfigPathByName(config *config.Config, name string) (string, error) {
    55  	files, err := libcni.ConfFiles(GetCNIConfDir(config), []string{".conflist"})
    56  	if err != nil {
    57  		return "", err
    58  	}
    59  	for _, confFile := range files {
    60  		conf, err := libcni.ConfListFromFile(confFile)
    61  		if err != nil {
    62  			return "", errors.Wrapf(err, "in %s", confFile)
    63  		}
    64  		if conf.Name == name {
    65  			return confFile, nil
    66  		}
    67  	}
    68  	return "", errors.Wrap(define.ErrNoSuchNetwork, fmt.Sprintf("unable to find network configuration for %s", name))
    69  }
    70  
    71  // ReadRawCNIConfByName reads the raw CNI configuration for a CNI
    72  // network by name
    73  func ReadRawCNIConfByName(config *config.Config, name string) ([]byte, error) {
    74  	confFile, err := GetCNIConfigPathByName(config, name)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	b, err := ioutil.ReadFile(confFile)
    79  	return b, err
    80  }
    81  
    82  // GetCNIPlugins returns a list of plugins that a given network
    83  // has in the form of a string
    84  func GetCNIPlugins(list *libcni.NetworkConfigList) string {
    85  	plugins := make([]string, 0, len(list.Plugins))
    86  	for _, plug := range list.Plugins {
    87  		plugins = append(plugins, plug.Network.Type)
    88  	}
    89  	return strings.Join(plugins, ",")
    90  }
    91  
    92  // GetNetworksFromFilesystem gets all the networks from the cni configuration
    93  // files
    94  func GetNetworksFromFilesystem(config *config.Config) ([]*allocator.Net, error) {
    95  	var cniNetworks []*allocator.Net
    96  
    97  	networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config))
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	for _, n := range networks {
   102  		for _, cniplugin := range n.Plugins {
   103  			if cniplugin.Network.Type == "bridge" {
   104  				ipamConf := allocator.Net{}
   105  				if err := json.Unmarshal(cniplugin.Bytes, &ipamConf); err != nil {
   106  					return nil, err
   107  				}
   108  				cniNetworks = append(cniNetworks, &ipamConf)
   109  				break
   110  			}
   111  		}
   112  	}
   113  	return cniNetworks, nil
   114  }
   115  
   116  // GetNetworkNamesFromFileSystem gets all the names from the cni network
   117  // configuration files
   118  func GetNetworkNamesFromFileSystem(config *config.Config) ([]string, error) {
   119  	networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config))
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	networkNames := []string{}
   124  	for _, n := range networks {
   125  		networkNames = append(networkNames, n.Name)
   126  	}
   127  	return networkNames, nil
   128  }
   129  
   130  // GetInterfaceNameFromConfig returns the interface name for the bridge plugin
   131  func GetInterfaceNameFromConfig(path string) (string, error) {
   132  	var name string
   133  	conf, err := libcni.ConfListFromFile(path)
   134  	if err != nil {
   135  		return "", err
   136  	}
   137  	for _, cniplugin := range conf.Plugins {
   138  		if cniplugin.Network.Type == "bridge" {
   139  			plugin := make(map[string]interface{})
   140  			if err := json.Unmarshal(cniplugin.Bytes, &plugin); err != nil {
   141  				return "", err
   142  			}
   143  			name = plugin["bridge"].(string)
   144  			break
   145  		}
   146  	}
   147  	if len(name) == 0 {
   148  		return "", ErrNoSuchNetworkInterface
   149  	}
   150  	return name, nil
   151  }
   152  
   153  // GetBridgeNamesFromFileSystem is a convenience function to get all the bridge
   154  // names from the configured networks
   155  func GetBridgeNamesFromFileSystem(config *config.Config) ([]string, error) {
   156  	networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config))
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	bridgeNames := []string{}
   162  	for _, n := range networks {
   163  		var name string
   164  		// iterate network conflists
   165  		for _, cniplugin := range n.Plugins {
   166  			// iterate plugins
   167  			if cniplugin.Network.Type == "bridge" {
   168  				plugin := make(map[string]interface{})
   169  				if err := json.Unmarshal(cniplugin.Bytes, &plugin); err != nil {
   170  					continue
   171  				}
   172  				name = plugin["bridge"].(string)
   173  			}
   174  		}
   175  		bridgeNames = append(bridgeNames, name)
   176  	}
   177  	return bridgeNames, nil
   178  }