github.com/AbhinandanKurakure/podman/v3@v3.4.10/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/v3/libpod/define"
    14  	"github.com/containers/podman/v3/pkg/network"
    15  	"github.com/pkg/errors"
    16  	"github.com/sirupsen/logrus"
    17  )
    18  
    19  // ErrNoSuchNetworkInterface indicates that no network interface exists
    20  var ErrNoSuchNetworkInterface = errors.New("unable to find interface name for network")
    21  
    22  // GetCNIConfDir get CNI configuration directory
    23  func GetCNIConfDir(configArg *config.Config) string {
    24  	if len(configArg.Network.NetworkConfigDir) < 1 {
    25  		dc, err := config.DefaultConfig()
    26  		if err != nil {
    27  			// Fallback to hard-coded dir
    28  			return CNIConfigDir
    29  		}
    30  		return dc.Network.NetworkConfigDir
    31  	}
    32  	return configArg.Network.NetworkConfigDir
    33  }
    34  
    35  // LoadCNIConfsFromDir loads all the CNI configurations from a dir
    36  func LoadCNIConfsFromDir(dir string) ([]*libcni.NetworkConfigList, error) {
    37  	files, err := libcni.ConfFiles(dir, []string{".conflist"})
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	sort.Strings(files)
    42  
    43  	configs := make([]*libcni.NetworkConfigList, 0, len(files))
    44  	for _, confFile := range files {
    45  		conf, err := libcni.ConfListFromFile(confFile)
    46  		if err != nil {
    47  			return nil, errors.Wrapf(err, "in %s", confFile)
    48  		}
    49  		configs = append(configs, conf)
    50  	}
    51  	return configs, nil
    52  }
    53  
    54  // GetCNIConfigPathByNameOrID finds a CNI network by name and
    55  // returns its configuration file path
    56  func GetCNIConfigPathByNameOrID(config *config.Config, name string) (string, error) {
    57  	files, err := libcni.ConfFiles(GetCNIConfDir(config), []string{".conflist"})
    58  	if err != nil {
    59  		return "", err
    60  	}
    61  	idMatch := 0
    62  	file := ""
    63  	for _, confFile := range files {
    64  		conf, err := libcni.ConfListFromFile(confFile)
    65  		if err != nil {
    66  			return "", errors.Wrapf(err, "in %s", confFile)
    67  		}
    68  		if conf.Name == name {
    69  			return confFile, nil
    70  		}
    71  		if strings.HasPrefix(network.GetNetworkID(conf.Name), name) {
    72  			idMatch++
    73  			file = confFile
    74  		}
    75  	}
    76  	if idMatch == 1 {
    77  		return file, nil
    78  	}
    79  	if idMatch > 1 {
    80  		return "", errors.Errorf("more than one result for network ID %s", name)
    81  	}
    82  	return "", errors.Wrap(define.ErrNoSuchNetwork, fmt.Sprintf("unable to find network configuration for %s", name))
    83  }
    84  
    85  // ReadRawCNIConfByNameOrID reads the raw CNI configuration for a CNI
    86  // network by name
    87  func ReadRawCNIConfByNameOrID(config *config.Config, name string) ([]byte, error) {
    88  	confFile, err := GetCNIConfigPathByNameOrID(config, name)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	b, err := ioutil.ReadFile(confFile)
    93  	return b, err
    94  }
    95  
    96  // GetNetworkLabels returns a list of labels as a string
    97  func GetNetworkLabels(list *libcni.NetworkConfigList) NcLabels {
    98  	cniJSON := make(map[string]interface{})
    99  	err := json.Unmarshal(list.Bytes, &cniJSON)
   100  	if err != nil {
   101  		logrus.Errorf("failed to unmarshal network config %v %v", cniJSON["name"], err)
   102  		return nil
   103  	}
   104  	if args, ok := cniJSON["args"]; ok {
   105  		if key, ok := args.(map[string]interface{}); ok {
   106  			if labels, ok := key[PodmanLabelKey]; ok {
   107  				if labels, ok := labels.(map[string]interface{}); ok {
   108  					result := make(NcLabels, len(labels))
   109  					for k, v := range labels {
   110  						if v, ok := v.(string); ok {
   111  							result[k] = v
   112  						} else {
   113  							logrus.Errorf("network config %v invalid label value type %T should be string", cniJSON["name"], labels)
   114  						}
   115  					}
   116  					return result
   117  				}
   118  				logrus.Errorf("network config %v invalid label type %T should be map[string]string", cniJSON["name"], labels)
   119  			}
   120  		}
   121  	}
   122  	return nil
   123  }
   124  
   125  // GetNetworksFromFilesystem gets all the networks from the cni configuration
   126  // files
   127  func GetNetworksFromFilesystem(config *config.Config) ([]*allocator.Net, error) {
   128  	var cniNetworks []*allocator.Net
   129  
   130  	networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config))
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	for _, n := range networks {
   135  		for _, cniplugin := range n.Plugins {
   136  			if cniplugin.Network.Type == "bridge" {
   137  				ipamConf := allocator.Net{}
   138  				if err := json.Unmarshal(cniplugin.Bytes, &ipamConf); err != nil {
   139  					return nil, err
   140  				}
   141  				cniNetworks = append(cniNetworks, &ipamConf)
   142  				break
   143  			}
   144  		}
   145  	}
   146  	return cniNetworks, nil
   147  }
   148  
   149  // GetNetworkNamesFromFileSystem gets all the names from the cni network
   150  // configuration files
   151  func GetNetworkNamesFromFileSystem(config *config.Config) ([]string, error) {
   152  	networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config))
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	networkNames := []string{}
   157  	for _, n := range networks {
   158  		networkNames = append(networkNames, n.Name)
   159  	}
   160  	return networkNames, nil
   161  }
   162  
   163  // GetInterfaceNameFromConfig returns the interface name for the bridge plugin
   164  func GetInterfaceNameFromConfig(path string) (string, error) {
   165  	var name string
   166  	conf, err := libcni.ConfListFromFile(path)
   167  	if err != nil {
   168  		return "", err
   169  	}
   170  	for _, cniplugin := range conf.Plugins {
   171  		if cniplugin.Network.Type == "bridge" {
   172  			plugin := make(map[string]interface{})
   173  			if err := json.Unmarshal(cniplugin.Bytes, &plugin); err != nil {
   174  				return "", err
   175  			}
   176  			name = plugin["bridge"].(string)
   177  			break
   178  		}
   179  	}
   180  	if len(name) == 0 {
   181  		return "", ErrNoSuchNetworkInterface
   182  	}
   183  	return name, nil
   184  }
   185  
   186  // GetBridgeNamesFromFileSystem is a convenience function to get all the bridge
   187  // names from the configured networks
   188  func GetBridgeNamesFromFileSystem(config *config.Config) ([]string, error) {
   189  	networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config))
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  
   194  	bridgeNames := []string{}
   195  	for _, n := range networks {
   196  		var name string
   197  		// iterate network conflists
   198  		for _, cniplugin := range n.Plugins {
   199  			// iterate plugins
   200  			if cniplugin.Network.Type == "bridge" {
   201  				plugin := make(map[string]interface{})
   202  				if err := json.Unmarshal(cniplugin.Bytes, &plugin); err != nil {
   203  					continue
   204  				}
   205  				name = plugin["bridge"].(string)
   206  			}
   207  		}
   208  		bridgeNames = append(bridgeNames, name)
   209  	}
   210  	return bridgeNames, nil
   211  }