diff options
author | baude <bbaude@redhat.com> | 2020-10-06 12:24:21 -0500 |
---|---|---|
committer | baude <bbaude@redhat.com> | 2020-10-07 10:03:21 -0500 |
commit | fe3faa517e1bbc3b2e82afaae32d8712c844fdae (patch) | |
tree | 3b4a74edc98a2861d2e1b6bb1d9769e078b9ba3c /libpod/network/files.go | |
parent | defb754945b3f99c1d786dac95d9b17b24f55e59 (diff) | |
download | podman-fe3faa517e1bbc3b2e82afaae32d8712c844fdae.tar.gz podman-fe3faa517e1bbc3b2e82afaae32d8712c844fdae.tar.bz2 podman-fe3faa517e1bbc3b2e82afaae32d8712c844fdae.zip |
prevent unpredictable results with network create|remove
due to a lack of "locking" on cni operations, we could get ourselves in trouble when doing rapid creation or removal of networks. added a simple file lock to deal with the collision and because it is not considered a performent path, use of the file lock should be ok. if proven otherwise in the future, some generic shared memory lock should be implemented for libpod and also used here.
moved pkog/network to libpod/network because libpod is now being pulled into the package and it has therefore lost its generic nature. this will make it easier to absorb into libpod as we try to make the network closer to core operations.
Fixes: #7807
Signed-off-by: baude <bbaude@redhat.com>
Diffstat (limited to 'libpod/network/files.go')
-rw-r--r-- | libpod/network/files.go | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/libpod/network/files.go b/libpod/network/files.go new file mode 100644 index 000000000..a2090491f --- /dev/null +++ b/libpod/network/files.go @@ -0,0 +1,174 @@ +package network + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "sort" + "strings" + + "github.com/containernetworking/cni/libcni" + "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator" + "github.com/containers/common/pkg/config" + "github.com/containers/podman/v2/libpod/define" + "github.com/pkg/errors" +) + +func GetCNIConfDir(configArg *config.Config) string { + if len(configArg.Network.NetworkConfigDir) < 1 { + dc, err := config.DefaultConfig() + if err != nil { + // Fallback to hard-coded dir + return CNIConfigDir + } + return dc.Network.NetworkConfigDir + } + return configArg.Network.NetworkConfigDir +} + +// LoadCNIConfsFromDir loads all the CNI configurations from a dir +func LoadCNIConfsFromDir(dir string) ([]*libcni.NetworkConfigList, error) { + files, err := libcni.ConfFiles(dir, []string{".conflist"}) + if err != nil { + return nil, err + } + sort.Strings(files) + + configs := make([]*libcni.NetworkConfigList, 0, len(files)) + for _, confFile := range files { + conf, err := libcni.ConfListFromFile(confFile) + if err != nil { + return nil, errors.Wrapf(err, "in %s", confFile) + } + configs = append(configs, conf) + } + return configs, nil +} + +// GetCNIConfigPathByName finds a CNI network by name and +// returns its configuration file path +func GetCNIConfigPathByName(config *config.Config, name string) (string, error) { + files, err := libcni.ConfFiles(GetCNIConfDir(config), []string{".conflist"}) + if err != nil { + return "", err + } + for _, confFile := range files { + conf, err := libcni.ConfListFromFile(confFile) + if err != nil { + return "", errors.Wrapf(err, "in %s", confFile) + } + if conf.Name == name { + return confFile, nil + } + } + return "", errors.Wrap(define.ErrNoSuchNetwork, fmt.Sprintf("unable to find network configuration for %s", name)) +} + +// ReadRawCNIConfByName reads the raw CNI configuration for a CNI +// network by name +func ReadRawCNIConfByName(config *config.Config, name string) ([]byte, error) { + confFile, err := GetCNIConfigPathByName(config, name) + if err != nil { + return nil, err + } + b, err := ioutil.ReadFile(confFile) + return b, err +} + +// GetCNIPlugins returns a list of plugins that a given network +// has in the form of a string +func GetCNIPlugins(list *libcni.NetworkConfigList) string { + plugins := make([]string, 0, len(list.Plugins)) + for _, plug := range list.Plugins { + plugins = append(plugins, plug.Network.Type) + } + return strings.Join(plugins, ",") +} + +// GetNetworksFromFilesystem gets all the networks from the cni configuration +// files +func GetNetworksFromFilesystem(config *config.Config) ([]*allocator.Net, error) { + var cniNetworks []*allocator.Net + + networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config)) + if err != nil { + return nil, err + } + for _, n := range networks { + for _, cniplugin := range n.Plugins { + if cniplugin.Network.Type == "bridge" { + ipamConf := allocator.Net{} + if err := json.Unmarshal(cniplugin.Bytes, &ipamConf); err != nil { + return nil, err + } + cniNetworks = append(cniNetworks, &ipamConf) + break + } + } + } + return cniNetworks, nil +} + +// GetNetworkNamesFromFileSystem gets all the names from the cni network +// configuration files +func GetNetworkNamesFromFileSystem(config *config.Config) ([]string, error) { + networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config)) + if err != nil { + return nil, err + } + networkNames := []string{} + for _, n := range networks { + networkNames = append(networkNames, n.Name) + } + 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 +} + +// GetBridgeNamesFromFileSystem is a convenience function to get all the bridge +// names from the configured networks +func GetBridgeNamesFromFileSystem(config *config.Config) ([]string, error) { + networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config)) + if err != nil { + return nil, err + } + + bridgeNames := []string{} + for _, n := range networks { + var name string + // iterate network conflists + for _, cniplugin := range n.Plugins { + // iterate plugins + if cniplugin.Network.Type == "bridge" { + plugin := make(map[string]interface{}) + if err := json.Unmarshal(cniplugin.Bytes, &plugin); err != nil { + continue + } + name = plugin["bridge"].(string) + } + } + bridgeNames = append(bridgeNames, name) + } + return bridgeNames, nil +} |