summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorViacheslav Hletenko <v.gletenko@vyos.io>2025-11-04 17:53:11 +0200
committerGitHub <noreply@github.com>2025-11-04 17:53:11 +0200
commitcc60275ab0db2c45f2ad7387d6a91a96fa9d6337 (patch)
treea59baa904529193481c12fb112a2de29b9d08608
parent6d0324506a5b0419eb0ae001d8d006a414030405 (diff)
parentae6d3437dc3247c396444b7f65eb49a98b0dd800 (diff)
downloadvyos-1x-cc60275ab0db2c45f2ad7387d6a91a96fa9d6337.tar.gz
vyos-1x-cc60275ab0db2c45f2ad7387d6a91a96fa9d6337.zip
Merge pull request #4828 from c-po/restart-container-vrf
container: T7305: fix VRF loss when restarting pods
-rw-r--r--python/vyos/container.py41
-rw-r--r--python/vyos/ifconfig/interface.py2
-rwxr-xr-xsmoketest/scripts/cli/test_container.py27
-rwxr-xr-xsrc/conf_mode/container.py25
-rwxr-xr-xsrc/op_mode/container.py9
5 files changed, 82 insertions, 22 deletions
diff --git a/python/vyos/container.py b/python/vyos/container.py
new file mode 100644
index 000000000..475d796f2
--- /dev/null
+++ b/python/vyos/container.py
@@ -0,0 +1,41 @@
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from vyos.config import Config
+from vyos.ifconfig import Interface
+from vyos.utils.dict import dict_search
+from vyos.utils.network import interface_exists
+
+def restart_network(config: Config) -> None:
+ """
+ Start network and assign it to given VRF if requested.
+
+ This can only be done after the containers got started as the podman network
+ interface will only be enabled by the first container and yet I do not know
+ how to enable the network interface in advance.
+ """
+ if 'network' in config:
+ for network, network_config in config['network'].items():
+ type_config = dict_search('type', network_config)
+ if not dict_search('macvlan', type_config):
+ network_name = f'pod-{network}'
+ # T5147: Networks are started only as soon as there is a consumer.
+ # If only a network is created in the first place, no need to assign
+ # it to a VRF as there's no consumer, yet.
+ if interface_exists(network_name):
+ tmp = Interface(network_name)
+ tmp.set_vrf(network_config.get('vrf', ''))
+ tmp.add_ipv6_eui64_address('fe80::/64')
+
+ return None
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index 761ba1799..ad634c4d7 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -619,7 +619,7 @@ class Interface(Control):
if 'netns' in self.config:
return False
- tmp = self.get_interface('vrf')
+ tmp = self.get_vrf()
if tmp == vrf:
return False
diff --git a/smoketest/scripts/cli/test_container.py b/smoketest/scripts/cli/test_container.py
index b41a7dd53..ae85273e8 100755
--- a/smoketest/scripts/cli/test_container.py
+++ b/smoketest/scripts/cli/test_container.py
@@ -23,6 +23,7 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from ipaddress import ip_interface
from vyos.configsession import ConfigSessionError
+from vyos.utils.network import get_interface_vrf
from vyos.utils.process import cmd
from vyos.utils.process import process_named_running
@@ -51,6 +52,7 @@ class TestContainer(VyOSUnitTestSHIM.TestCase):
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
+ cls.cli_delete(cls, ['vrf'])
@classmethod
def tearDownClass(cls):
@@ -133,7 +135,6 @@ class TestContainer(VyOSUnitTestSHIM.TestCase):
self.assertEqual(l['Config']['Healthcheck']['Timeout'], 1000000000)
self.assertEqual(l['Config']['Healthcheck']['Retries'], 2)
-
def test_name_server(self):
cont_name = 'dns-test'
net_name = 'net-test'
@@ -517,6 +518,30 @@ class TestContainer(VyOSUnitTestSHIM.TestCase):
# We expect the same amount of containers from the API that we started above
self.assertEqual(len(container_list), len(tmp))
+ def test_network_vrf(self):
+ cont_name = 'vrf-test50'
+ net_name = 'vrf-test50'
+ vrf_name = 'red-15'
+
+ # create temporary VRF for testing
+ self.cli_set(['vrf', 'name', vrf_name, 'table', '100'])
+
+ self.cli_set(base_path + ['name', cont_name, 'image', busybox_image])
+ self.cli_set(base_path + ['name', cont_name, 'network', net_name])
+ self.cli_set(base_path + ['network', net_name, 'prefix', '192.168.0.0/24'])
+ self.cli_set(base_path + ['network', net_name, 'vrf', vrf_name])
+
+ self.cli_commit()
+
+ tmp = get_interface_vrf(f'pod-{net_name}')
+ self.assertEqual(tmp, vrf_name)
+
+ # Restart container and validate VRF assignment
+ self.op_mode(['restart', 'container', cont_name])
+ tmp = get_interface_vrf(f'pod-{net_name}')
+ self.assertEqual(tmp, vrf_name)
+
+ self.cli_delete(['vrf', 'name', vrf_name])
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py
index a57a9d054..af09ac52a 100755
--- a/src/conf_mode/container.py
+++ b/src/conf_mode/container.py
@@ -29,7 +29,7 @@ from vyos.configdict import dict_merge
from vyos.configdict import node_changed
from vyos.configdict import is_node_changed
from vyos.configverify import verify_vrf
-from vyos.ifconfig import Interface
+from vyos.container import restart_network
from vyos.utils.configfs import delete_cli_node
from vyos.utils.configfs import add_cli_node
from vyos.utils.cpu import get_core_count
@@ -161,7 +161,7 @@ def verify(container):
if 'name_server' in container_config and 'no_name_server' not in container['network'][network_name]:
raise ConfigError(f'Setting name server has no effect when attached container network has DNS enabled!')
- mac = dict_search(f'network.{network_name}.mac', container_config)
+ mac = dict_search(f'network.{network_name}.mac', container_config)
if mac:
if mac in net_dict['mac'].keys():
raise ConfigError(f'MAC address "{mac}" is already used by container "{net_dict["mac"][mac]}"!')
@@ -194,7 +194,7 @@ def verify(container):
if ip_address(address) == ip_network(network)[1]:
raise ConfigError(f'IP address "{address}" can not be used for a container, ' \
'reserved for the container engine!')
-
+
if address in net_dict['address'].keys():
raise ConfigError(f'IP address "{address}" is already used by container "{net_dict["address"][address]}"!')
net_dict['address'][address] = name
@@ -673,23 +673,8 @@ def apply(container):
if disabled_new:
call('systemctl daemon-reload')
- # Start network and assign it to given VRF if requested. this can only be done
- # after the containers got started as the podman network interface will
- # only be enabled by the first container and yet I do not know how to enable
- # the network interface in advance
- if 'network' in container:
- for network, network_config in container['network'].items():
- type_config = dict_search('type', network_config)
- if not dict_search('macvlan', type_config):
- network_name = f'pod-{network}'
- # T5147: Networks are started only as soon as there is a consumer.
- # If only a network is created in the first place, no need to assign
- # it to a VRF as there's no consumer, yet.
- if interface_exists(network_name):
- tmp = Interface(network_name)
- tmp.set_vrf(network_config.get('vrf', ''))
- tmp.add_ipv6_eui64_address('fe80::/64')
-
+ # Re-Start network and assign it to given VRF if requested.
+ restart_network(container)
return None
diff --git a/src/op_mode/container.py b/src/op_mode/container.py
index a34901cb4..281c95e2c 100755
--- a/src/op_mode/container.py
+++ b/src/op_mode/container.py
@@ -166,6 +166,8 @@ def show_network(raw: bool):
def restart(name: str):
from vyos.utils.process import rc_cmd
+ from vyos.config import Config
+ from vyos.container import restart_network
rc, output = rc_cmd(f'systemctl restart vyos-container-{name}.service')
if rc != 0:
@@ -173,6 +175,13 @@ def restart(name: str):
if rc2 != 0:
print(output)
return None
+ if rc == 0:
+ conf = Config()
+ container = conf.get_config_dict(['container'], key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
+ get_first_key=True,
+ with_recursive_defaults=True)
+ restart_network(container)
print(f'Container "{name}" restarted!')
return output