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 }