automation-tests/common/libnetwork/network/interface.go

150 lines
4.9 KiB
Go

//go:build linux || freebsd
package network
import (
"errors"
"fmt"
"os"
"path/filepath"
"github.com/containers/common/libnetwork/netavark"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/config"
"github.com/containers/storage"
"github.com/containers/storage/pkg/ioutils"
"github.com/containers/storage/pkg/unshare"
"github.com/sirupsen/logrus"
)
const (
// defaultNetworkBackendFileName is the file name for sentinel file to store the backend
defaultNetworkBackendFileName = "defaultNetworkBackend"
// netavarkBinary is the name of the netavark binary
netavarkBinary = "netavark"
// aardvarkBinary is the name of the aardvark binary
aardvarkBinary = "aardvark-dns"
)
// NetworkBackend returns the network backend name and interface
// It returns either the CNI or netavark backend depending on what is set in the config.
// If the backend is set to "" we will automatically assign the backend on the following conditions:
// 1. read ${graphroot}/defaultNetworkBackend
// 2. find netavark binary (if not installed use CNI)
// 3. check containers, images and CNI networks and if there are some we have an existing install and should continue to use CNI
//
// revive does not like the name because the package is already called network
//
//nolint:revive
func NetworkBackend(store storage.Store, conf *config.Config, syslog bool) (types.NetworkBackend, types.ContainerNetwork, error) {
backend := types.NetworkBackend(conf.Network.NetworkBackend)
if backend == "" {
var err error
backend, err = defaultNetworkBackend(store, conf)
if err != nil {
return "", nil, fmt.Errorf("failed to get default network backend: %w", err)
}
}
return backendFromType(backend, store, conf, syslog)
}
func netavarkBackendFromConf(store storage.Store, conf *config.Config, syslog bool) (types.ContainerNetwork, error) {
netavarkBin, err := conf.FindHelperBinary(netavarkBinary, false)
if err != nil {
return nil, err
}
aardvarkBin, _ := conf.FindHelperBinary(aardvarkBinary, false)
confDir := conf.Network.NetworkConfigDir
if confDir == "" {
confDir = getDefaultNetavarkConfigDir(store)
}
// We cannot use the runroot for rootful since the network namespace is shared for all
// libpod instances they also have to share the same ipam db.
// For rootless we have our own network namespace per libpod instances,
// so this is not a problem there.
runDir := netavarkRunDir
if unshare.IsRootless() {
runDir = filepath.Join(store.RunRoot(), "networks")
}
netInt, err := netavark.NewNetworkInterface(&netavark.InitConfig{
Config: conf,
NetworkConfigDir: confDir,
NetworkRunDir: runDir,
NetavarkBinary: netavarkBin,
AardvarkBinary: aardvarkBin,
Syslog: syslog,
})
return netInt, err
}
func defaultNetworkBackend(store storage.Store, conf *config.Config) (backend types.NetworkBackend, err error) {
err = nil
file := filepath.Join(store.GraphRoot(), defaultNetworkBackendFileName)
writeBackendToFile := func(backendT types.NetworkBackend) {
// only write when there is no error
if err == nil {
if err := ioutils.AtomicWriteFile(file, []byte(backendT), 0o644); err != nil {
logrus.Errorf("could not write network backend to file: %v", err)
}
}
}
// read defaultNetworkBackend file
b, err := os.ReadFile(file)
if err == nil {
val := string(b)
// if the network backend has been already set previously,
// handle the values depending on whether CNI is supported and
// whether the network backend is explicitly configured
if val == string(types.Netavark) {
// netavark is always good
return types.Netavark, nil
} else if val == string(types.CNI) {
if cniSupported {
return types.CNI, nil
}
// the user has *not* configured a network
// backend explicitly but used CNI in the past
// => we upgrade them in this case to netavark only
writeBackendToFile(types.Netavark)
logrus.Info("Migrating network backend to netavark as no backend has been configured previously")
return types.Netavark, nil
}
return "", fmt.Errorf("unknown network backend value %q in %q", val, file)
}
// fail for all errors except ENOENT
if !errors.Is(err, os.ErrNotExist) {
return "", fmt.Errorf("could not read network backend value: %w", err)
}
backend, err = networkBackendFromStore(store, conf)
if err != nil {
return "", err
}
// cache the network backend to make sure always the same one will be used
writeBackendToFile(backend)
return backend, nil
}
// getDefaultNetavarkConfigDir return the netavark config dir. For rootful it will
// use "/etc/containers/networks" and for rootless "$graphroot/networks". We cannot
// use the graphroot for rootful since the network namespace is shared for all
// libpod instances.
func getDefaultNetavarkConfigDir(store storage.Store) string {
if !unshare.IsRootless() {
return netavarkConfigDir
}
return filepath.Join(store.GraphRoot(), "networks")
}