summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorJohn Estabrook <jestabro@vyos.io>2025-10-06 09:25:11 -0500
committerJohn Estabrook <jestabro@vyos.io>2025-11-05 09:47:55 -0600
commitc414a7d555799e1ba8adb56ca23246cf3823100d (patch)
treeb2856c8b92bdb229f0cae528b8e88cb78372fc27 /python
parentcc60275ab0db2c45f2ad7387d6a91a96fa9d6337 (diff)
downloadvyos-1x-c414a7d555799e1ba8adb56ca23246cf3823100d.tar.gz
vyos-1x-c414a7d555799e1ba8adb56ca23246cf3823100d.zip
T7910: use weakref.finalize for reliable session teardown
Diffstat (limited to 'python')
-rw-r--r--python/vyos/configsession.py22
-rw-r--r--python/vyos/configsource.py7
-rw-r--r--python/vyos/vyconf_session.py24
3 files changed, 32 insertions, 21 deletions
diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py
index f0a22d930..62ce34b22 100644
--- a/python/vyos/configsession.py
+++ b/python/vyos/configsession.py
@@ -16,6 +16,7 @@
import os
import re
import sys
+import weakref
import subprocess
from tempfile import NamedTemporaryFile
from typing import TypeAlias
@@ -199,10 +200,15 @@ class ConfigSession(object):
self.shared = shared
+ if not self.shared and self._vyconf_session:
+ self._finalizer = weakref.finalize(
+ self, self.finalize_vyconf, self._vyconf_session
+ )
+
def __del__(self):
if self.shared:
return
- if self._vyconf_session is None:
+ if not vyconf_backend():
try:
output = (
subprocess.check_output(
@@ -223,12 +229,14 @@ class ConfigSession(object):
'Could not tear down session {0}: {1}'.format(self.__session_id, e),
file=sys.stderr,
)
- else:
- if self._vyconf_session.session_changed():
- Warn('Exiting with uncommitted changes')
- self._vyconf_session.discard()
- self._vyconf_session.exit_config_mode()
- self._vyconf_session.teardown()
+
+ @classmethod
+ def finalize_vyconf(cls, session: VyconfSession):
+ if session.session_changed():
+ Warn('Exiting with uncommitted changes')
+ session.discard()
+ session.exit_config_mode()
+ session.teardown()
def __run_command(self, cmd_list):
p = subprocess.Popen(
diff --git a/python/vyos/configsource.py b/python/vyos/configsource.py
index 6bf794d9e..33852a182 100644
--- a/python/vyos/configsource.py
+++ b/python/vyos/configsource.py
@@ -355,13 +355,6 @@ class ConfigSourceVyconfSession(ConfigSource):
# cf. T7374
self._level = []
- def __del__(self):
- try:
- if not self._vyconf_session.in_session():
- self._vyconf_session.teardown()
- except AttributeError:
- pass
-
def get_level(self):
return self._level
diff --git a/python/vyos/vyconf_session.py b/python/vyos/vyconf_session.py
index 379de4e24..bf1c344b4 100644
--- a/python/vyos/vyconf_session.py
+++ b/python/vyos/vyconf_session.py
@@ -16,6 +16,7 @@
#
import os
+import weakref
import tempfile
from functools import wraps
from typing import Type
@@ -64,6 +65,12 @@ class VyconfSession:
self.__token = token
self.in_config_session = in_config_session()
+
+ if not self.in_config_session:
+ # op-mode sessions are ephemeral
+ # config-mode sessions are persistent, and managed by caller (CLI or ConfigSession)
+ self._finalizer = weakref.finalize(self, self._teardown, self.__token)
+
if self.in_config_session:
out = vyconf_client.send_request(
'enter_configuration_mode', token=self.__token
@@ -73,8 +80,12 @@ class VyconfSession:
self.on_error = on_error
+ @classmethod
+ def _teardown(cls, token):
+ vyconf_client.send_request('teardown', token)
+
def teardown(self):
- vyconf_client.send_request('teardown', token=self.__token)
+ self._teardown(self.__token)
def exit_config_mode(self):
if self.session_changed():
@@ -129,6 +140,11 @@ class VyconfSession:
out = out + res
return out
+ @config_mode
+ def discard(self) -> tuple[str, int]:
+ out = vyconf_client.send_request('discard', token=self.__token)
+ return self.output(out), out.status
+
@raise_exception
@config_mode
def set(self, path: list[str]) -> tuple[str, int]:
@@ -189,12 +205,6 @@ class VyconfSession:
@raise_exception
@config_mode
- def discard(self) -> tuple[str, int]:
- out = vyconf_client.send_request('discard', token=self.__token)
- return self.output(out), out.status
-
- @raise_exception
- @config_mode
def load_config(
self, file_name: str, migrate: bool = False, cached: bool = False
) -> tuple[str, int]: