From c414a7d555799e1ba8adb56ca23246cf3823100d Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Mon, 6 Oct 2025 09:25:11 -0500 Subject: T7910: use weakref.finalize for reliable session teardown --- python/vyos/configsession.py | 22 +++++++++++++++------- python/vyos/configsource.py | 7 ------- python/vyos/vyconf_session.py | 24 +++++++++++++++++------- 3 files changed, 32 insertions(+), 21 deletions(-) (limited to 'python') 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]: @@ -187,12 +203,6 @@ class VyconfSession: return pre_out + self.output(out) + post_out, out.status - @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( -- cgit v1.2.3 From cbbfd427896db481437364522e0a1c4a6d25be1c Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Fri, 17 Oct 2025 20:33:31 -0500 Subject: T7910: op-mode init should always start a new session --- python/vyos/vyconf_session.py | 53 +++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 22 deletions(-) (limited to 'python') diff --git a/python/vyos/vyconf_session.py b/python/vyos/vyconf_session.py index bf1c344b4..c89f33e97 100644 --- a/python/vyos/vyconf_session.py +++ b/python/vyos/vyconf_session.py @@ -37,38 +37,47 @@ class VyconfSessionError(Exception): pass +def new_session(pid: int, sudo_user: str, user: str): + out = vyconf_client.send_request( + 'setup_session', + client_pid=pid, + client_sudo_user=sudo_user, + client_user=user, + ) + return out.output + + class VyconfSession: def __init__( self, token: str = None, pid: int = None, on_error: Type[Exception] = None ): - self.pid = os.getpid() if pid is None else pid + self.pid = pid if pid else os.getpid() self.sudo_user = os.environ.get('SUDO_USER', None) self.user = os.environ.get('USER', None) - if token is None: - # CLI applications with arg pid=getppid() allow coordination - # with the ambient session; other uses (such as ConfigSession) - # may default to self pid - out = vyconf_client.send_request('session_of_pid', client_pid=self.pid) - if out.output is None: - out = vyconf_client.send_request( - 'setup_session', - client_pid=self.pid, - client_sudo_user=self.sudo_user, - client_user=self.user, - ) - self.__token = out.output - else: - out = vyconf_client.send_request('session_exists', token=token) - if out.status: - raise ValueError(f'No existing session for token: {token}') - self.__token = token - self.in_config_session = in_config_session() + match token: + case None: + # config-mode sessions are persistent, and managed by caller (CLI or ConfigSession) + # op-mode sessions are ephemeral: a new session on init; teardown in finalizer + if self.in_config_session: + out = vyconf_client.send_request( + 'session_of_pid', client_pid=self.pid + ) + if out.output is None: + self.__token = new_session(self.pid, self.sudo_user, self.user) + else: + self.__token = out.output + else: + self.__token = new_session(self.pid, self.sudo_user, self.user) + case _: + out = vyconf_client.send_request('session_exists', token=token) + if out.status: + raise ValueError(f'No existing session for token: {token}') + self.__token = token + 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: -- cgit v1.2.3 From 2a574f7e146a82beb04661d85d7fd83553b2c160 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Sun, 19 Oct 2025 19:29:14 -0500 Subject: T7910: call enter_config_mode only on new session --- python/vyos/vyconf_session.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'python') diff --git a/python/vyos/vyconf_session.py b/python/vyos/vyconf_session.py index c89f33e97..1e113c2ad 100644 --- a/python/vyos/vyconf_session.py +++ b/python/vyos/vyconf_session.py @@ -67,6 +67,11 @@ class VyconfSession: ) if out.output is None: self.__token = new_session(self.pid, self.sudo_user, self.user) + out = vyconf_client.send_request( + 'enter_configuration_mode', token=self.__token + ) + if out.status: + raise VyconfSessionError(self.output(out)) else: self.__token = out.output else: @@ -80,13 +85,6 @@ class VyconfSession: if not self.in_config_session: 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 - ) - if out.status: - raise VyconfSessionError(self.output(out)) - self.on_error = on_error @classmethod -- cgit v1.2.3 From 4c391ed39c51172cbb8f2de6732d6fe4e3a8b125 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Tue, 21 Oct 2025 19:14:12 -0500 Subject: T7910: add keyword extant, for use by teardown script The standalone script teardown-config-session.py is called on CLI config-mode exit, to close the persistent vyconf config session. Instead of injecting the config-mode env var into the external script to indicate a non-ephemeral session, add keyword 'extant' to find existing session. --- python/vyos/vyconf_session.py | 22 ++++++++++++++++++---- src/helpers/teardown-config-session.py | 9 +++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'python') diff --git a/python/vyos/vyconf_session.py b/python/vyos/vyconf_session.py index 1e113c2ad..225765f0b 100644 --- a/python/vyos/vyconf_session.py +++ b/python/vyos/vyconf_session.py @@ -49,7 +49,11 @@ def new_session(pid: int, sudo_user: str, user: str): class VyconfSession: def __init__( - self, token: str = None, pid: int = None, on_error: Type[Exception] = None + self, + token: str = None, + pid: int = None, + extant=False, + on_error: Type[Exception] = None, ): self.pid = pid if pid else os.getpid() self.sudo_user = os.environ.get('SUDO_USER', None) @@ -60,7 +64,9 @@ class VyconfSession: match token: case None: # config-mode sessions are persistent, and managed by caller (CLI or ConfigSession) - # op-mode sessions are ephemeral: a new session on init; teardown in finalizer + # + # op-mode sessions are ephemeral, unless forced with extant=True: + # --- open a new session on init; teardown in finalizer if self.in_config_session: out = vyconf_client.send_request( 'session_of_pid', client_pid=self.pid @@ -75,14 +81,22 @@ class VyconfSession: else: self.__token = out.output else: - self.__token = new_session(self.pid, self.sudo_user, self.user) + if not extant: + self.__token = new_session(self.pid, self.sudo_user, self.user) + else: + out = vyconf_client.send_request( + 'session_of_pid', client_pid=self.pid + ) + if out.output is None: + raise ValueError(f'No existing session for pid {self.pid}') + self.__token = out.output case _: out = vyconf_client.send_request('session_exists', token=token) if out.status: raise ValueError(f'No existing session for token: {token}') self.__token = token - if not self.in_config_session: + if not self.in_config_session and not extant: self._finalizer = weakref.finalize(self, self._teardown, self.__token) self.on_error = on_error diff --git a/src/helpers/teardown-config-session.py b/src/helpers/teardown-config-session.py index c30303c99..49a3f5bc5 100755 --- a/src/helpers/teardown-config-session.py +++ b/src/helpers/teardown-config-session.py @@ -23,5 +23,10 @@ if len(sys.argv) < 2: pid = sys.argv[1] -vc = VyconfSession(pid=pid) -vc.teardown() +try: + vc = VyconfSession(pid=int(pid), extant=True) +except ValueError: + # as this script is called on any config session exit, ignore non-existent + pass +else: + vc.teardown() -- cgit v1.2.3 From 47b36a3af0bd8c2958354d961d4ae4c3ae991d6f Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Wed, 22 Oct 2025 13:45:10 -0500 Subject: T7910: switch keyword order pid/token for consistency and intuition pid is the more commonly passed argument, and this maintains consistency with configsession arg use. --- python/vyos/vyconf_session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python') diff --git a/python/vyos/vyconf_session.py b/python/vyos/vyconf_session.py index 225765f0b..461b225a8 100644 --- a/python/vyos/vyconf_session.py +++ b/python/vyos/vyconf_session.py @@ -50,8 +50,8 @@ def new_session(pid: int, sudo_user: str, user: str): class VyconfSession: def __init__( self, - token: str = None, pid: int = None, + token: str = None, extant=False, on_error: Type[Exception] = None, ): -- cgit v1.2.3 From cad2c08ee6f273ff4b9a0917825ca52ce25bfefa Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Fri, 17 Oct 2025 11:08:26 -0500 Subject: T7910: update auto-generated protobuf files for show_sessions --- python/vyos/proto/vyconf_pb2.py | 150 +++++++++++++++++++------------------- python/vyos/proto/vyconf_proto.py | 12 +++ 2 files changed, 88 insertions(+), 74 deletions(-) (limited to 'python') diff --git a/python/vyos/proto/vyconf_pb2.py b/python/vyos/proto/vyconf_pb2.py index 164dbc1d7..61047a068 100644 --- a/python/vyos/proto/vyconf_pb2.py +++ b/python/vyos/proto/vyconf_pb2.py @@ -13,85 +13,87 @@ _sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cvyconf.proto\"\xc5\x17\n\x07Request\x12!\n\x06prompt\x18\x01 \x01(\x0b\x32\x0f.Request.PromptH\x00\x12.\n\rsetup_session\x18\x02 \x01(\x0b\x32\x15.Request.SetupSessionH\x00\x12\x1b\n\x03set\x18\x03 \x01(\x0b\x32\x0c.Request.SetH\x00\x12!\n\x06\x64\x65lete\x18\x04 \x01(\x0b\x32\x0f.Request.DeleteH\x00\x12!\n\x06rename\x18\x05 \x01(\x0b\x32\x0f.Request.RenameH\x00\x12\x1d\n\x04\x63opy\x18\x06 \x01(\x0b\x32\r.Request.CopyH\x00\x12#\n\x07\x63omment\x18\x07 \x01(\x0b\x32\x10.Request.CommentH\x00\x12!\n\x06\x63ommit\x18\x08 \x01(\x0b\x32\x0f.Request.CommitH\x00\x12%\n\x08rollback\x18\t \x01(\x0b\x32\x11.Request.RollbackH\x00\x12\x1f\n\x05merge\x18\n \x01(\x0b\x32\x0e.Request.MergeH\x00\x12\x1d\n\x04save\x18\x0b \x01(\x0b\x32\r.Request.SaveH\x00\x12*\n\x0bshow_config\x18\x0c \x01(\x0b\x32\x13.Request.ShowConfigH\x00\x12!\n\x06\x65xists\x18\r \x01(\x0b\x32\x0f.Request.ExistsH\x00\x12&\n\tget_value\x18\x0e \x01(\x0b\x32\x11.Request.GetValueH\x00\x12(\n\nget_values\x18\x0f \x01(\x0b\x32\x12.Request.GetValuesH\x00\x12.\n\rlist_children\x18\x10 \x01(\x0b\x32\x15.Request.ListChildrenH\x00\x12)\n\x0brun_op_mode\x18\x11 \x01(\x0b\x32\x12.Request.RunOpModeH\x00\x12#\n\x07\x63onfirm\x18\x12 \x01(\x0b\x32\x10.Request.ConfirmH\x00\x12\x43\n\x18\x65nter_configuration_mode\x18\x13 \x01(\x0b\x32\x1f.Request.EnterConfigurationModeH\x00\x12\x41\n\x17\x65xit_configuration_mode\x18\x14 \x01(\x0b\x32\x1e.Request.ExitConfigurationModeH\x00\x12%\n\x08validate\x18\x15 \x01(\x0b\x32\x11.Request.ValidateH\x00\x12%\n\x08teardown\x18\x16 \x01(\x0b\x32\x11.Request.TeardownH\x00\x12\x30\n\x0ereload_reftree\x18\x17 \x01(\x0b\x32\x16.Request.ReloadReftreeH\x00\x12\x1d\n\x04load\x18\x18 \x01(\x0b\x32\r.Request.LoadH\x00\x12#\n\x07\x64iscard\x18\x19 \x01(\x0b\x32\x10.Request.DiscardH\x00\x12\x32\n\x0fsession_changed\x18\x1a \x01(\x0b\x32\x17.Request.SessionChangedH\x00\x12/\n\x0esession_of_pid\x18\x1b \x01(\x0b\x32\x15.Request.SessionOfPidH\x00\x12\x30\n\x0esession_exists\x18\x1c \x01(\x0b\x32\x16.Request.SessionExistsH\x00\x12(\n\nget_config\x18\x1d \x01(\x0b\x32\x12.Request.GetConfigH\x00\x12\"\n\x07\x61ux_set\x18\x1e \x01(\x0b\x32\x0f.Request.AuxSetH\x00\x12(\n\naux_delete\x18\x1f \x01(\x0b\x32\x12.Request.AuxDeleteH\x00\x1a\x08\n\x06Prompt\x1a\x83\x01\n\x0cSetupSession\x12\x12\n\nclient_pid\x18\x01 \x02(\x05\x12\x1a\n\x12\x63lient_application\x18\x02 \x01(\t\x12\x14\n\x0con_behalf_of\x18\x03 \x01(\x05\x12\x13\n\x0b\x63lient_user\x18\x04 \x01(\t\x12\x18\n\x10\x63lient_sudo_user\x18\x05 \x01(\t\x1a\"\n\x0cSessionOfPid\x12\x12\n\nclient_pid\x18\x01 \x02(\x05\x1a\x1e\n\rSessionExists\x12\r\n\x05\x64ummy\x18\x01 \x01(\x05\x1a\x1a\n\tGetConfig\x12\r\n\x05\x64ummy\x18\x01 \x01(\x05\x1a \n\x08Teardown\x12\x14\n\x0con_behalf_of\x18\x01 \x01(\x05\x1a\x46\n\x08Validate\x12\x0c\n\x04Path\x18\x01 \x03(\t\x12,\n\routput_format\x18\x02 \x01(\x0e\x32\x15.Request.OutputFormat\x1a\x13\n\x03Set\x12\x0c\n\x04path\x18\x01 \x03(\t\x1a\x16\n\x06\x44\x65lete\x12\x0c\n\x04path\x18\x01 \x03(\t\x1a>\n\x06\x41uxSet\x12\x0c\n\x04path\x18\x01 \x03(\t\x12\x13\n\x0bscript_name\x18\x02 \x02(\t\x12\x11\n\ttag_value\x18\x03 \x01(\t\x1a\x41\n\tAuxDelete\x12\x0c\n\x04path\x18\x01 \x03(\t\x12\x13\n\x0bscript_name\x18\x02 \x02(\t\x12\x11\n\ttag_value\x18\x03 \x01(\t\x1a\x18\n\x07\x44iscard\x12\r\n\x05\x64ummy\x18\x01 \x01(\x05\x1a\x1f\n\x0eSessionChanged\x12\r\n\x05\x64ummy\x18\x01 \x01(\x05\x1a\x41\n\x06Rename\x12\x12\n\nedit_level\x18\x01 \x03(\t\x12\x0e\n\x06source\x18\x02 \x02(\t\x12\x13\n\x0b\x64\x65stination\x18\x03 \x02(\t\x1a?\n\x04\x43opy\x12\x12\n\nedit_level\x18\x01 \x03(\t\x12\x0e\n\x06source\x18\x02 \x02(\t\x12\x13\n\x0b\x64\x65stination\x18\x03 \x02(\t\x1a(\n\x07\x43omment\x12\x0c\n\x04path\x18\x01 \x03(\t\x12\x0f\n\x07\x63omment\x18\x02 \x02(\t\x1aT\n\x06\x43ommit\x12\x0f\n\x07\x63onfirm\x18\x01 \x01(\x08\x12\x17\n\x0f\x63onfirm_timeout\x18\x02 \x01(\x05\x12\x0f\n\x07\x63omment\x18\x03 \x01(\t\x12\x0f\n\x07\x64ry_run\x18\x04 \x01(\x08\x1a\x1c\n\x08Rollback\x12\x10\n\x08revision\x18\x01 \x02(\x05\x1aO\n\x04Load\x12\x10\n\x08location\x18\x01 \x02(\t\x12\x0e\n\x06\x63\x61\x63hed\x18\x02 \x02(\x08\x12%\n\x06\x66ormat\x18\x03 \x01(\x0e\x32\x15.Request.ConfigFormat\x1aU\n\x05Merge\x12\x10\n\x08location\x18\x01 \x02(\t\x12\x13\n\x0b\x64\x65structive\x18\x02 \x02(\x08\x12%\n\x06\x66ormat\x18\x03 \x01(\x0e\x32\x15.Request.ConfigFormat\x1a?\n\x04Save\x12\x10\n\x08location\x18\x01 \x02(\t\x12%\n\x06\x66ormat\x18\x02 \x01(\x0e\x32\x15.Request.ConfigFormat\x1a\x41\n\nShowConfig\x12\x0c\n\x04path\x18\x01 \x03(\t\x12%\n\x06\x66ormat\x18\x02 \x01(\x0e\x32\x15.Request.ConfigFormat\x1a\x16\n\x06\x45xists\x12\x0c\n\x04path\x18\x01 \x03(\t\x1a\x46\n\x08GetValue\x12\x0c\n\x04path\x18\x01 \x03(\t\x12,\n\routput_format\x18\x02 \x01(\x0e\x32\x15.Request.OutputFormat\x1aG\n\tGetValues\x12\x0c\n\x04path\x18\x01 \x03(\t\x12,\n\routput_format\x18\x02 \x01(\x0e\x32\x15.Request.OutputFormat\x1aJ\n\x0cListChildren\x12\x0c\n\x04path\x18\x01 \x03(\t\x12,\n\routput_format\x18\x02 \x01(\x0e\x32\x15.Request.OutputFormat\x1aG\n\tRunOpMode\x12\x0c\n\x04path\x18\x01 \x03(\t\x12,\n\routput_format\x18\x02 \x01(\x0e\x32\x15.Request.OutputFormat\x1a\t\n\x07\x43onfirm\x1aG\n\x16\x45nterConfigurationMode\x12\x11\n\texclusive\x18\x01 \x02(\x08\x12\x1a\n\x12override_exclusive\x18\x02 \x02(\x08\x1a\x17\n\x15\x45xitConfigurationMode\x1a%\n\rReloadReftree\x12\x14\n\x0con_behalf_of\x18\x01 \x01(\x05\"#\n\x0c\x43onfigFormat\x12\t\n\x05\x43URLY\x10\x00\x12\x08\n\x04JSON\x10\x01\")\n\x0cOutputFormat\x12\x0c\n\x08OutPlain\x10\x00\x12\x0b\n\x07OutJSON\x10\x01\x42\x05\n\x03msg\";\n\x0fRequestEnvelope\x12\r\n\x05token\x18\x01 \x01(\t\x12\x19\n\x07request\x18\x02 \x02(\x0b\x32\x08.Request\"S\n\x08Response\x12\x17\n\x06status\x18\x01 \x02(\x0e\x32\x07.Errnum\x12\x0e\n\x06output\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12\x0f\n\x07warning\x18\x04 \x01(\t*\xd2\x01\n\x06\x45rrnum\x12\x0b\n\x07SUCCESS\x10\x00\x12\x08\n\x04\x46\x41IL\x10\x01\x12\x10\n\x0cINVALID_PATH\x10\x02\x12\x11\n\rINVALID_VALUE\x10\x03\x12\x16\n\x12\x43OMMIT_IN_PROGRESS\x10\x04\x12\x18\n\x14\x43ONFIGURATION_LOCKED\x10\x05\x12\x12\n\x0eINTERNAL_ERROR\x10\x06\x12\x15\n\x11PERMISSION_DENIED\x10\x07\x12\x17\n\x13PATH_ALREADY_EXISTS\x10\x08\x12\x16\n\x12UNCOMMITED_CHANGES\x10\t') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cvyconf.proto\"\xb2\x18\n\x07Request\x12!\n\x06prompt\x18\x01 \x01(\x0b\x32\x0f.Request.PromptH\x00\x12.\n\rsetup_session\x18\x02 \x01(\x0b\x32\x15.Request.SetupSessionH\x00\x12\x1b\n\x03set\x18\x03 \x01(\x0b\x32\x0c.Request.SetH\x00\x12!\n\x06\x64\x65lete\x18\x04 \x01(\x0b\x32\x0f.Request.DeleteH\x00\x12!\n\x06rename\x18\x05 \x01(\x0b\x32\x0f.Request.RenameH\x00\x12\x1d\n\x04\x63opy\x18\x06 \x01(\x0b\x32\r.Request.CopyH\x00\x12#\n\x07\x63omment\x18\x07 \x01(\x0b\x32\x10.Request.CommentH\x00\x12!\n\x06\x63ommit\x18\x08 \x01(\x0b\x32\x0f.Request.CommitH\x00\x12%\n\x08rollback\x18\t \x01(\x0b\x32\x11.Request.RollbackH\x00\x12\x1f\n\x05merge\x18\n \x01(\x0b\x32\x0e.Request.MergeH\x00\x12\x1d\n\x04save\x18\x0b \x01(\x0b\x32\r.Request.SaveH\x00\x12*\n\x0bshow_config\x18\x0c \x01(\x0b\x32\x13.Request.ShowConfigH\x00\x12!\n\x06\x65xists\x18\r \x01(\x0b\x32\x0f.Request.ExistsH\x00\x12&\n\tget_value\x18\x0e \x01(\x0b\x32\x11.Request.GetValueH\x00\x12(\n\nget_values\x18\x0f \x01(\x0b\x32\x12.Request.GetValuesH\x00\x12.\n\rlist_children\x18\x10 \x01(\x0b\x32\x15.Request.ListChildrenH\x00\x12)\n\x0brun_op_mode\x18\x11 \x01(\x0b\x32\x12.Request.RunOpModeH\x00\x12#\n\x07\x63onfirm\x18\x12 \x01(\x0b\x32\x10.Request.ConfirmH\x00\x12\x43\n\x18\x65nter_configuration_mode\x18\x13 \x01(\x0b\x32\x1f.Request.EnterConfigurationModeH\x00\x12\x41\n\x17\x65xit_configuration_mode\x18\x14 \x01(\x0b\x32\x1e.Request.ExitConfigurationModeH\x00\x12%\n\x08validate\x18\x15 \x01(\x0b\x32\x11.Request.ValidateH\x00\x12%\n\x08teardown\x18\x16 \x01(\x0b\x32\x11.Request.TeardownH\x00\x12\x30\n\x0ereload_reftree\x18\x17 \x01(\x0b\x32\x16.Request.ReloadReftreeH\x00\x12\x1d\n\x04load\x18\x18 \x01(\x0b\x32\r.Request.LoadH\x00\x12#\n\x07\x64iscard\x18\x19 \x01(\x0b\x32\x10.Request.DiscardH\x00\x12\x32\n\x0fsession_changed\x18\x1a \x01(\x0b\x32\x17.Request.SessionChangedH\x00\x12/\n\x0esession_of_pid\x18\x1b \x01(\x0b\x32\x15.Request.SessionOfPidH\x00\x12\x30\n\x0esession_exists\x18\x1c \x01(\x0b\x32\x16.Request.SessionExistsH\x00\x12(\n\nget_config\x18\x1d \x01(\x0b\x32\x12.Request.GetConfigH\x00\x12\"\n\x07\x61ux_set\x18\x1e \x01(\x0b\x32\x0f.Request.AuxSetH\x00\x12(\n\naux_delete\x18\x1f \x01(\x0b\x32\x12.Request.AuxDeleteH\x00\x12.\n\rshow_sessions\x18 \x01(\x0b\x32\x15.Request.ShowSessionsH\x00\x1a\x08\n\x06Prompt\x1a\x83\x01\n\x0cSetupSession\x12\x12\n\nclient_pid\x18\x01 \x02(\x05\x12\x1a\n\x12\x63lient_application\x18\x02 \x01(\t\x12\x14\n\x0con_behalf_of\x18\x03 \x01(\x05\x12\x13\n\x0b\x63lient_user\x18\x04 \x01(\t\x12\x18\n\x10\x63lient_sudo_user\x18\x05 \x01(\t\x1a\"\n\x0cSessionOfPid\x12\x12\n\nclient_pid\x18\x01 \x02(\x05\x1a\x1e\n\rSessionExists\x12\r\n\x05\x64ummy\x18\x01 \x01(\x05\x1a\x1a\n\tGetConfig\x12\r\n\x05\x64ummy\x18\x01 \x01(\x05\x1a \n\x08Teardown\x12\x14\n\x0con_behalf_of\x18\x01 \x01(\x05\x1a\x46\n\x08Validate\x12\x0c\n\x04Path\x18\x01 \x03(\t\x12,\n\routput_format\x18\x02 \x01(\x0e\x32\x15.Request.OutputFormat\x1a\x13\n\x03Set\x12\x0c\n\x04path\x18\x01 \x03(\t\x1a\x16\n\x06\x44\x65lete\x12\x0c\n\x04path\x18\x01 \x03(\t\x1a>\n\x06\x41uxSet\x12\x0c\n\x04path\x18\x01 \x03(\t\x12\x13\n\x0bscript_name\x18\x02 \x02(\t\x12\x11\n\ttag_value\x18\x03 \x01(\t\x1a\x41\n\tAuxDelete\x12\x0c\n\x04path\x18\x01 \x03(\t\x12\x13\n\x0bscript_name\x18\x02 \x02(\t\x12\x11\n\ttag_value\x18\x03 \x01(\t\x1a\x18\n\x07\x44iscard\x12\r\n\x05\x64ummy\x18\x01 \x01(\x05\x1a\x1f\n\x0eSessionChanged\x12\r\n\x05\x64ummy\x18\x01 \x01(\x05\x1a\x41\n\x06Rename\x12\x12\n\nedit_level\x18\x01 \x03(\t\x12\x0e\n\x06source\x18\x02 \x02(\t\x12\x13\n\x0b\x64\x65stination\x18\x03 \x02(\t\x1a?\n\x04\x43opy\x12\x12\n\nedit_level\x18\x01 \x03(\t\x12\x0e\n\x06source\x18\x02 \x02(\t\x12\x13\n\x0b\x64\x65stination\x18\x03 \x02(\t\x1a(\n\x07\x43omment\x12\x0c\n\x04path\x18\x01 \x03(\t\x12\x0f\n\x07\x63omment\x18\x02 \x02(\t\x1aT\n\x06\x43ommit\x12\x0f\n\x07\x63onfirm\x18\x01 \x01(\x08\x12\x17\n\x0f\x63onfirm_timeout\x18\x02 \x01(\x05\x12\x0f\n\x07\x63omment\x18\x03 \x01(\t\x12\x0f\n\x07\x64ry_run\x18\x04 \x01(\x08\x1a\x1c\n\x08Rollback\x12\x10\n\x08revision\x18\x01 \x02(\x05\x1aO\n\x04Load\x12\x10\n\x08location\x18\x01 \x02(\t\x12\x0e\n\x06\x63\x61\x63hed\x18\x02 \x02(\x08\x12%\n\x06\x66ormat\x18\x03 \x01(\x0e\x32\x15.Request.ConfigFormat\x1aU\n\x05Merge\x12\x10\n\x08location\x18\x01 \x02(\t\x12\x13\n\x0b\x64\x65structive\x18\x02 \x02(\x08\x12%\n\x06\x66ormat\x18\x03 \x01(\x0e\x32\x15.Request.ConfigFormat\x1a?\n\x04Save\x12\x10\n\x08location\x18\x01 \x02(\t\x12%\n\x06\x66ormat\x18\x02 \x01(\x0e\x32\x15.Request.ConfigFormat\x1a\x41\n\nShowConfig\x12\x0c\n\x04path\x18\x01 \x03(\t\x12%\n\x06\x66ormat\x18\x02 \x01(\x0e\x32\x15.Request.ConfigFormat\x1a\x16\n\x06\x45xists\x12\x0c\n\x04path\x18\x01 \x03(\t\x1a\x46\n\x08GetValue\x12\x0c\n\x04path\x18\x01 \x03(\t\x12,\n\routput_format\x18\x02 \x01(\x0e\x32\x15.Request.OutputFormat\x1aG\n\tGetValues\x12\x0c\n\x04path\x18\x01 \x03(\t\x12,\n\routput_format\x18\x02 \x01(\x0e\x32\x15.Request.OutputFormat\x1aJ\n\x0cListChildren\x12\x0c\n\x04path\x18\x01 \x03(\t\x12,\n\routput_format\x18\x02 \x01(\x0e\x32\x15.Request.OutputFormat\x1aG\n\tRunOpMode\x12\x0c\n\x04path\x18\x01 \x03(\t\x12,\n\routput_format\x18\x02 \x01(\x0e\x32\x15.Request.OutputFormat\x1a\t\n\x07\x43onfirm\x1aG\n\x16\x45nterConfigurationMode\x12\x11\n\texclusive\x18\x01 \x02(\x08\x12\x1a\n\x12override_exclusive\x18\x02 \x02(\x08\x1a\x17\n\x15\x45xitConfigurationMode\x1a%\n\rReloadReftree\x12\x14\n\x0con_behalf_of\x18\x01 \x01(\x05\x1a;\n\x0cShowSessions\x12\x14\n\x0c\x65xclude_self\x18\x01 \x02(\x08\x12\x15\n\rexclude_other\x18\x02 \x02(\x08\"#\n\x0c\x43onfigFormat\x12\t\n\x05\x43URLY\x10\x00\x12\x08\n\x04JSON\x10\x01\")\n\x0cOutputFormat\x12\x0c\n\x08OutPlain\x10\x00\x12\x0b\n\x07OutJSON\x10\x01\x42\x05\n\x03msg\";\n\x0fRequestEnvelope\x12\r\n\x05token\x18\x01 \x01(\t\x12\x19\n\x07request\x18\x02 \x02(\x0b\x32\x08.Request\"S\n\x08Response\x12\x17\n\x06status\x18\x01 \x02(\x0e\x32\x07.Errnum\x12\x0e\n\x06output\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12\x0f\n\x07warning\x18\x04 \x01(\t*\xd2\x01\n\x06\x45rrnum\x12\x0b\n\x07SUCCESS\x10\x00\x12\x08\n\x04\x46\x41IL\x10\x01\x12\x10\n\x0cINVALID_PATH\x10\x02\x12\x11\n\rINVALID_VALUE\x10\x03\x12\x16\n\x12\x43OMMIT_IN_PROGRESS\x10\x04\x12\x18\n\x14\x43ONFIGURATION_LOCKED\x10\x05\x12\x12\n\x0eINTERNAL_ERROR\x10\x06\x12\x15\n\x11PERMISSION_DENIED\x10\x07\x12\x17\n\x13PATH_ALREADY_EXISTS\x10\x08\x12\x16\n\x12UNCOMMITED_CHANGES\x10\t') _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'vyconf_pb2', globals()) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None - _ERRNUM._serialized_start=3179 - _ERRNUM._serialized_end=3389 + _ERRNUM._serialized_start=3288 + _ERRNUM._serialized_end=3498 _REQUEST._serialized_start=17 - _REQUEST._serialized_end=3030 - _REQUEST_PROMPT._serialized_start=1308 - _REQUEST_PROMPT._serialized_end=1316 - _REQUEST_SETUPSESSION._serialized_start=1319 - _REQUEST_SETUPSESSION._serialized_end=1450 - _REQUEST_SESSIONOFPID._serialized_start=1452 - _REQUEST_SESSIONOFPID._serialized_end=1486 - _REQUEST_SESSIONEXISTS._serialized_start=1488 - _REQUEST_SESSIONEXISTS._serialized_end=1518 - _REQUEST_GETCONFIG._serialized_start=1520 - _REQUEST_GETCONFIG._serialized_end=1546 - _REQUEST_TEARDOWN._serialized_start=1548 - _REQUEST_TEARDOWN._serialized_end=1580 - _REQUEST_VALIDATE._serialized_start=1582 - _REQUEST_VALIDATE._serialized_end=1652 - _REQUEST_SET._serialized_start=1654 - _REQUEST_SET._serialized_end=1673 - _REQUEST_DELETE._serialized_start=1675 - _REQUEST_DELETE._serialized_end=1697 - _REQUEST_AUXSET._serialized_start=1699 - _REQUEST_AUXSET._serialized_end=1761 - _REQUEST_AUXDELETE._serialized_start=1763 - _REQUEST_AUXDELETE._serialized_end=1828 - _REQUEST_DISCARD._serialized_start=1830 - _REQUEST_DISCARD._serialized_end=1854 - _REQUEST_SESSIONCHANGED._serialized_start=1856 - _REQUEST_SESSIONCHANGED._serialized_end=1887 - _REQUEST_RENAME._serialized_start=1889 - _REQUEST_RENAME._serialized_end=1954 - _REQUEST_COPY._serialized_start=1956 - _REQUEST_COPY._serialized_end=2019 - _REQUEST_COMMENT._serialized_start=2021 - _REQUEST_COMMENT._serialized_end=2061 - _REQUEST_COMMIT._serialized_start=2063 - _REQUEST_COMMIT._serialized_end=2147 - _REQUEST_ROLLBACK._serialized_start=2149 - _REQUEST_ROLLBACK._serialized_end=2177 - _REQUEST_LOAD._serialized_start=2179 - _REQUEST_LOAD._serialized_end=2258 - _REQUEST_MERGE._serialized_start=2260 - _REQUEST_MERGE._serialized_end=2345 - _REQUEST_SAVE._serialized_start=2347 - _REQUEST_SAVE._serialized_end=2410 - _REQUEST_SHOWCONFIG._serialized_start=2412 - _REQUEST_SHOWCONFIG._serialized_end=2477 - _REQUEST_EXISTS._serialized_start=2479 - _REQUEST_EXISTS._serialized_end=2501 - _REQUEST_GETVALUE._serialized_start=2503 - _REQUEST_GETVALUE._serialized_end=2573 - _REQUEST_GETVALUES._serialized_start=2575 - _REQUEST_GETVALUES._serialized_end=2646 - _REQUEST_LISTCHILDREN._serialized_start=2648 - _REQUEST_LISTCHILDREN._serialized_end=2722 - _REQUEST_RUNOPMODE._serialized_start=2724 - _REQUEST_RUNOPMODE._serialized_end=2795 - _REQUEST_CONFIRM._serialized_start=2797 - _REQUEST_CONFIRM._serialized_end=2806 - _REQUEST_ENTERCONFIGURATIONMODE._serialized_start=2808 - _REQUEST_ENTERCONFIGURATIONMODE._serialized_end=2879 - _REQUEST_EXITCONFIGURATIONMODE._serialized_start=2881 - _REQUEST_EXITCONFIGURATIONMODE._serialized_end=2904 - _REQUEST_RELOADREFTREE._serialized_start=2906 - _REQUEST_RELOADREFTREE._serialized_end=2943 - _REQUEST_CONFIGFORMAT._serialized_start=2945 - _REQUEST_CONFIGFORMAT._serialized_end=2980 - _REQUEST_OUTPUTFORMAT._serialized_start=2982 - _REQUEST_OUTPUTFORMAT._serialized_end=3023 - _REQUESTENVELOPE._serialized_start=3032 - _REQUESTENVELOPE._serialized_end=3091 - _RESPONSE._serialized_start=3093 - _RESPONSE._serialized_end=3176 + _REQUEST._serialized_end=3139 + _REQUEST_PROMPT._serialized_start=1356 + _REQUEST_PROMPT._serialized_end=1364 + _REQUEST_SETUPSESSION._serialized_start=1367 + _REQUEST_SETUPSESSION._serialized_end=1498 + _REQUEST_SESSIONOFPID._serialized_start=1500 + _REQUEST_SESSIONOFPID._serialized_end=1534 + _REQUEST_SESSIONEXISTS._serialized_start=1536 + _REQUEST_SESSIONEXISTS._serialized_end=1566 + _REQUEST_GETCONFIG._serialized_start=1568 + _REQUEST_GETCONFIG._serialized_end=1594 + _REQUEST_TEARDOWN._serialized_start=1596 + _REQUEST_TEARDOWN._serialized_end=1628 + _REQUEST_VALIDATE._serialized_start=1630 + _REQUEST_VALIDATE._serialized_end=1700 + _REQUEST_SET._serialized_start=1702 + _REQUEST_SET._serialized_end=1721 + _REQUEST_DELETE._serialized_start=1723 + _REQUEST_DELETE._serialized_end=1745 + _REQUEST_AUXSET._serialized_start=1747 + _REQUEST_AUXSET._serialized_end=1809 + _REQUEST_AUXDELETE._serialized_start=1811 + _REQUEST_AUXDELETE._serialized_end=1876 + _REQUEST_DISCARD._serialized_start=1878 + _REQUEST_DISCARD._serialized_end=1902 + _REQUEST_SESSIONCHANGED._serialized_start=1904 + _REQUEST_SESSIONCHANGED._serialized_end=1935 + _REQUEST_RENAME._serialized_start=1937 + _REQUEST_RENAME._serialized_end=2002 + _REQUEST_COPY._serialized_start=2004 + _REQUEST_COPY._serialized_end=2067 + _REQUEST_COMMENT._serialized_start=2069 + _REQUEST_COMMENT._serialized_end=2109 + _REQUEST_COMMIT._serialized_start=2111 + _REQUEST_COMMIT._serialized_end=2195 + _REQUEST_ROLLBACK._serialized_start=2197 + _REQUEST_ROLLBACK._serialized_end=2225 + _REQUEST_LOAD._serialized_start=2227 + _REQUEST_LOAD._serialized_end=2306 + _REQUEST_MERGE._serialized_start=2308 + _REQUEST_MERGE._serialized_end=2393 + _REQUEST_SAVE._serialized_start=2395 + _REQUEST_SAVE._serialized_end=2458 + _REQUEST_SHOWCONFIG._serialized_start=2460 + _REQUEST_SHOWCONFIG._serialized_end=2525 + _REQUEST_EXISTS._serialized_start=2527 + _REQUEST_EXISTS._serialized_end=2549 + _REQUEST_GETVALUE._serialized_start=2551 + _REQUEST_GETVALUE._serialized_end=2621 + _REQUEST_GETVALUES._serialized_start=2623 + _REQUEST_GETVALUES._serialized_end=2694 + _REQUEST_LISTCHILDREN._serialized_start=2696 + _REQUEST_LISTCHILDREN._serialized_end=2770 + _REQUEST_RUNOPMODE._serialized_start=2772 + _REQUEST_RUNOPMODE._serialized_end=2843 + _REQUEST_CONFIRM._serialized_start=2845 + _REQUEST_CONFIRM._serialized_end=2854 + _REQUEST_ENTERCONFIGURATIONMODE._serialized_start=2856 + _REQUEST_ENTERCONFIGURATIONMODE._serialized_end=2927 + _REQUEST_EXITCONFIGURATIONMODE._serialized_start=2929 + _REQUEST_EXITCONFIGURATIONMODE._serialized_end=2952 + _REQUEST_RELOADREFTREE._serialized_start=2954 + _REQUEST_RELOADREFTREE._serialized_end=2991 + _REQUEST_SHOWSESSIONS._serialized_start=2993 + _REQUEST_SHOWSESSIONS._serialized_end=3052 + _REQUEST_CONFIGFORMAT._serialized_start=3054 + _REQUEST_CONFIGFORMAT._serialized_end=3089 + _REQUEST_OUTPUTFORMAT._serialized_start=3091 + _REQUEST_OUTPUTFORMAT._serialized_end=3132 + _REQUESTENVELOPE._serialized_start=3141 + _REQUESTENVELOPE._serialized_end=3200 + _RESPONSE._serialized_start=3202 + _RESPONSE._serialized_end=3285 # @@protoc_insertion_point(module_scope) diff --git a/python/vyos/proto/vyconf_proto.py b/python/vyos/proto/vyconf_proto.py index a7fb24337..080d103f9 100644 --- a/python/vyos/proto/vyconf_proto.py +++ b/python/vyos/proto/vyconf_proto.py @@ -174,6 +174,11 @@ class ExitConfigurationMode: class ReloadReftree: on_behalf_of: int = None +@dataclass +class ShowSessions: + exclude_self: bool = False + exclude_other: bool = False + @dataclass class Request: prompt: Prompt = None @@ -207,6 +212,7 @@ class Request: get_config: GetConfig = None aux_set: AuxSet = None aux_delete: AuxDelete = None + show_sessions: ShowSessions = None @dataclass class RequestEnvelope: @@ -405,3 +411,9 @@ def set_request_reload_reftree(token: str = None, on_behalf_of: int = None): req = Request(reload_reftree=reqi) req_env = RequestEnvelope(token, req) return req_env + +def set_request_show_sessions(token: str = None, exclude_self: bool = False, exclude_other: bool = False): + reqi = ShowSessions (exclude_self, exclude_other) + req = Request(show_sessions=reqi) + req_env = RequestEnvelope(token, req) + return req_env -- cgit v1.2.3 From a02b7d54c561368d8a9a22a0643a1b4fb1e90345 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Fri, 17 Oct 2025 14:53:10 -0500 Subject: T7910: add call show_sessions show_sessions returns a list of dicts of the internal session record structure for each live session. As this call is itself mediated by a session one can specify exclude_self=True, resp., exclude_other=True. --- python/vyos/vyconf_session.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'python') diff --git a/python/vyos/vyconf_session.py b/python/vyos/vyconf_session.py index 461b225a8..5748ab2dd 100644 --- a/python/vyos/vyconf_session.py +++ b/python/vyos/vyconf_session.py @@ -18,6 +18,7 @@ import os import weakref import tempfile +import json from functools import wraps from typing import Type @@ -127,6 +128,21 @@ class VyconfSession: raise VyconfSessionError(self.output(out)) return out.output + def show_sessions( + self, exclude_self: bool = False, exclude_other: bool = False + ) -> list | dict: + out = vyconf_client.send_request( + 'show_sessions', + token=self.__token, + exclude_self=exclude_self, + exclude_other=exclude_other, + ) + + lst = json.loads(out.output) + if len(lst) == 1: + return lst[0] + return lst + @staticmethod def config_mode(f): @wraps(f) -- cgit v1.2.3