From 411c8683456a416d795e21a97f07d8f8e5e9c84f Mon Sep 17 00:00:00 2001 From: Jan Tluka Date: Mon, 16 Sep 2024 12:21:25 +0200 Subject: [PATCH] ContainerPoolManager: add netavark support Signed-off-by: Jan Tluka --- lnst/Controller/ContainerPoolManager.py | 49 +++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/lnst/Controller/ContainerPoolManager.py b/lnst/Controller/ContainerPoolManager.py index 2a32770a6..7dc4ca810 100644 --- a/lnst/Controller/ContainerPoolManager.py +++ b/lnst/Controller/ContainerPoolManager.py @@ -3,6 +3,7 @@ import socket from time import sleep from json import loads +from typing import Optional from lnst.Controller.AgentPoolManager import PoolManagerError from lnst.Controller.Machine import Machine from lnst.Common.DependencyError import DependencyError @@ -38,10 +39,15 @@ class ContainerPoolManager(object): :param image: Mandatory parameter :type image: str + + :param network_plugin: + Podman network plugin, 'cni' or 'netavark', if unset, the network backend is auto-detected + :type network_plugin: Optional[str] """ def __init__( - self, pools, msg_dispatcher, ctl_config, podman_uri, image, pool_checks=True + self, pools, msg_dispatcher, ctl_config, podman_uri, image, + network_plugin='netavark', pool_checks=True ): self._import_optionals() self._pool = {} @@ -54,6 +60,7 @@ def __init__( self._image = "" self._podman_connect(podman_uri) self.image = image + self.network_plugin = network_plugin self._networks = {} self._network_prefix = "lnst_container_net_" @@ -207,7 +214,21 @@ def _create_container(self, name: str, reqs: dict): return container, machine - def _create_network(self, network_name: str): + def _create_network(self, network_name: str, plugin: Optional[str]): + if not plugin: + podman_info = self._podman_client.info() + plugin = podman_info["host"]["networkBackend"] + + logging.debug(f"Using {plugin} network backend for containers") + + if plugin == "netavark": + return self._create_network_netavark(network_name) + elif plugin == "cni": + return self._create_network_cni(network_name) + else: + raise PoolManagerError(f"Unknown podman network plugin {plugin}") + + def _create_network_cni(self, network_name: str): """Networks are created "manually" because podman does not support creating L2 [1] networks. IPs in these networks are managed by controller. @@ -249,6 +270,28 @@ def _create_network(self, network_name: str): return network + def _create_network_netavark(self, network_name: str): + name = self.get_network_name(network_name) + if name in self._networks: + return self._networks[name] + + logging.info(f"Creating network {name}") + try: + self._podman_client.networks.create( + name, + internal=True, + enable_ipv6=True, + ) + network = self._podman_client.networks.get(name) + except APIError as e: + raise PoolManagerError(f"Could not create network {name}: {e}") + except IOError as e: + raise PoolManagerError(f"Could not create network configuration file: {e}") + + self._networks[name] = network + + return network + def _connect_to_network(self, container: "Container", network: "Network"): """There is no way to get MAC address of remote interface except executing "ip l" inside container. @@ -292,7 +335,7 @@ def _connect_to_networks(self, container: "Container", network_reqs: dict): name = params["network"] logging.debug(f"Connecting {container.name} to {name}") - network = self._create_network(name) + network = self._create_network(name, self.network_plugin) self._connect_to_network(container, network)