libnetwork/netavark: add plugin support
Users can now suplly custom network drivers which will execute the netavark plugin to create the network. Netavark will execute the pluign to setup/teardown the netns. see https://github.com/containers/netavark/pull/509 Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
parent
f43dd7eafa
commit
7052cdf26a
|
@ -209,7 +209,11 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported driver %s: %w", newNetwork.Driver, types.ErrInvalidArg)
|
net, err := n.createPlugin(newNetwork)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newNetwork = net
|
||||||
}
|
}
|
||||||
|
|
||||||
// when we do not have ipam we must disable dns
|
// when we do not have ipam we must disable dns
|
||||||
|
@ -403,3 +407,55 @@ func validateIPAMDriver(n *types.Network) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errInvalidPluginResult = errors.New("invalid plugin result")
|
||||||
|
|
||||||
|
func (n *netavarkNetwork) createPlugin(net *types.Network) (*types.Network, error) {
|
||||||
|
path, err := getPlugin(net.Driver, n.pluginDirs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := new(types.Network)
|
||||||
|
err = n.execPlugin(path, []string{"create"}, net, result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("plugin %s failed: %w", path, err)
|
||||||
|
}
|
||||||
|
// now make sure that neither the name, ID, driver were changed by the plugin
|
||||||
|
if net.Name != result.Name {
|
||||||
|
return nil, fmt.Errorf("%w: changed network name", errInvalidPluginResult)
|
||||||
|
}
|
||||||
|
if net.ID != result.ID {
|
||||||
|
return nil, fmt.Errorf("%w: changed network ID", errInvalidPluginResult)
|
||||||
|
}
|
||||||
|
if net.Driver != result.Driver {
|
||||||
|
return nil, fmt.Errorf("%w: changed network driver", errInvalidPluginResult)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAllPlugins(dirs []string) []string {
|
||||||
|
var plugins []string
|
||||||
|
for _, dir := range dirs {
|
||||||
|
entries, err := os.ReadDir(dir)
|
||||||
|
if err == nil {
|
||||||
|
for _, entry := range entries {
|
||||||
|
name := entry.Name()
|
||||||
|
if !util.StringInSlice(name, plugins) {
|
||||||
|
plugins = append(plugins, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return plugins
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPlugin(name string, dirs []string) (string, error) {
|
||||||
|
for _, dir := range dirs {
|
||||||
|
fullpath := filepath.Join(dir, name)
|
||||||
|
st, err := os.Stat(fullpath)
|
||||||
|
if err == nil && st.Mode().IsRegular() {
|
||||||
|
return fullpath, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("failed to find driver or plugin %q", name)
|
||||||
|
}
|
||||||
|
|
|
@ -925,7 +925,7 @@ var _ = Describe("Config", func() {
|
||||||
}
|
}
|
||||||
_, err := libpodNet.NetworkCreate(network, nil)
|
_, err := libpodNet.NetworkCreate(network, nil)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("unsupported driver someDriver"))
|
Expect(err.Error()).To(ContainSubstring(`failed to find driver or plugin "someDriver"`))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("network create internal and dns", func() {
|
It("network create internal and dns", func() {
|
||||||
|
|
|
@ -77,6 +77,23 @@ func getRustLogEnv() string {
|
||||||
// All errors return by this function should be of the type netavarkError
|
// All errors return by this function should be of the type netavarkError
|
||||||
// to provide a helpful error message.
|
// to provide a helpful error message.
|
||||||
func (n *netavarkNetwork) execNetavark(args []string, stdin, result interface{}) error {
|
func (n *netavarkNetwork) execNetavark(args []string, stdin, result interface{}) error {
|
||||||
|
// set the netavark log level to the same as the podman
|
||||||
|
env := append(os.Environ(), getRustLogEnv())
|
||||||
|
// if we run with debug log level lets also set RUST_BACKTRACE=1 so we can get the full stack trace in case of panics
|
||||||
|
if logrus.IsLevelEnabled(logrus.DebugLevel) {
|
||||||
|
env = append(env, "RUST_BACKTRACE=1")
|
||||||
|
}
|
||||||
|
if n.dnsBindPort != 0 {
|
||||||
|
env = append(env, "NETAVARK_DNS_PORT="+strconv.Itoa(int(n.dnsBindPort)))
|
||||||
|
}
|
||||||
|
return n.execBinary(n.netavarkBinary, append(n.getCommonNetavarkOptions(), args...), stdin, result, env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *netavarkNetwork) execPlugin(path string, args []string, stdin, result interface{}) error {
|
||||||
|
return n.execBinary(path, args, stdin, result, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *netavarkNetwork) execBinary(path string, args []string, stdin, result interface{}, env []string) error {
|
||||||
stdinR, stdinW, err := os.Pipe()
|
stdinR, stdinW, err := os.Pipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return newNetavarkError("failed to create stdin pipe", err)
|
return newNetavarkError("failed to create stdin pipe", err)
|
||||||
|
@ -108,20 +125,12 @@ func (n *netavarkNetwork) execNetavark(args []string, stdin, result interface{})
|
||||||
logWriter = io.MultiWriter(logWriter, &logrusNetavarkWriter{})
|
logWriter = io.MultiWriter(logWriter, &logrusNetavarkWriter{})
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command(n.netavarkBinary, append(n.getCommonNetavarkOptions(), args...)...)
|
cmd := exec.Command(path, args...)
|
||||||
// connect the pipes to stdin and stdout
|
// connect the pipes to stdin and stdout
|
||||||
cmd.Stdin = stdinR
|
cmd.Stdin = stdinR
|
||||||
cmd.Stdout = stdoutW
|
cmd.Stdout = stdoutW
|
||||||
cmd.Stderr = logWriter
|
cmd.Stderr = logWriter
|
||||||
// set the netavark log level to the same as the podman
|
cmd.Env = env
|
||||||
cmd.Env = append(os.Environ(), getRustLogEnv())
|
|
||||||
// if we run with debug log level lets also set RUST_BACKTRACE=1 so we can get the full stack trace in case of panics
|
|
||||||
if logrus.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
cmd.Env = append(cmd.Env, "RUST_BACKTRACE=1")
|
|
||||||
}
|
|
||||||
if n.dnsBindPort != 0 {
|
|
||||||
cmd.Env = append(cmd.Env, "NETAVARK_DNS_PORT="+strconv.Itoa(int(n.dnsBindPort)))
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Start()
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -46,6 +46,9 @@ type netavarkNetwork struct {
|
||||||
// dnsBindPort is set the the port to pass to netavark for aardvark
|
// dnsBindPort is set the the port to pass to netavark for aardvark
|
||||||
dnsBindPort uint16
|
dnsBindPort uint16
|
||||||
|
|
||||||
|
// pluginDirs list of directories were netavark plugins are located
|
||||||
|
pluginDirs []string
|
||||||
|
|
||||||
// ipamDBPath is the path to the ip allocation bolt db
|
// ipamDBPath is the path to the ip allocation bolt db
|
||||||
ipamDBPath string
|
ipamDBPath string
|
||||||
|
|
||||||
|
@ -86,6 +89,9 @@ type InitConfig struct {
|
||||||
// DNSBindPort is set the the port to pass to netavark for aardvark
|
// DNSBindPort is set the the port to pass to netavark for aardvark
|
||||||
DNSBindPort uint16
|
DNSBindPort uint16
|
||||||
|
|
||||||
|
// PluginDirs list of directories were netavark plugins are located
|
||||||
|
PluginDirs []string
|
||||||
|
|
||||||
// Syslog describes whenever the netavark debbug output should be log to the syslog as well.
|
// Syslog describes whenever the netavark debbug output should be log to the syslog as well.
|
||||||
// This will use logrus to do so, make sure logrus is set up to log to the syslog.
|
// This will use logrus to do so, make sure logrus is set up to log to the syslog.
|
||||||
Syslog bool
|
Syslog bool
|
||||||
|
@ -143,6 +149,7 @@ func NewNetworkInterface(conf *InitConfig) (types.ContainerNetwork, error) {
|
||||||
defaultSubnet: defaultNet,
|
defaultSubnet: defaultNet,
|
||||||
defaultsubnetPools: defaultSubnetPools,
|
defaultsubnetPools: defaultSubnetPools,
|
||||||
dnsBindPort: conf.DNSBindPort,
|
dnsBindPort: conf.DNSBindPort,
|
||||||
|
pluginDirs: conf.PluginDirs,
|
||||||
lock: lock,
|
lock: lock,
|
||||||
syslog: conf.Syslog,
|
syslog: conf.Syslog,
|
||||||
}
|
}
|
||||||
|
@ -153,7 +160,8 @@ func NewNetworkInterface(conf *InitConfig) (types.ContainerNetwork, error) {
|
||||||
// Drivers will return the list of supported network drivers
|
// Drivers will return the list of supported network drivers
|
||||||
// for this interface.
|
// for this interface.
|
||||||
func (n *netavarkNetwork) Drivers() []string {
|
func (n *netavarkNetwork) Drivers() []string {
|
||||||
return []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver}
|
paths := getAllPlugins(n.pluginDirs)
|
||||||
|
return append([]string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver}, paths...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultNetworkName will return the default netavark network name.
|
// DefaultNetworkName will return the default netavark network name.
|
||||||
|
|
Loading…
Reference in New Issue