diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py index f0a22d930c..55ccc0d584 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 @@ def __init__(self, session_id, app=APP, shared=False): 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,13 @@ def __del__(self): '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() + + def finalize_vyconf(self, 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 6bf794d9e1..33852a182e 100644 --- a/python/vyos/configsource.py +++ b/python/vyos/configsource.py @@ -355,13 +355,6 @@ def __init__(self, session_env=None): # 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/proto/vyconf_pb2.py b/python/vyos/proto/vyconf_pb2.py index 164dbc1d7f..61047a0684 100644 --- a/python/vyos/proto/vyconf_pb2.py +++ b/python/vyos/proto/vyconf_pb2.py @@ -13,85 +13,87 @@ -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 a7fb24337f..080d103f9a 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 diff --git a/python/vyos/vyconf_session.py b/python/vyos/vyconf_session.py index 379de4e244..0adc41490b 100644 --- a/python/vyos/vyconf_session.py +++ b/python/vyos/vyconf_session.py @@ -16,7 +16,9 @@ # import os +import weakref import tempfile +import json from functools import wraps from typing import Type @@ -36,45 +38,75 @@ 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: int = None, + token: str = None, + extant=False, + 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() - if self.in_config_session: - out = vyconf_client.send_request( - 'enter_configuration_mode', token=self.__token - ) - if out.status: - raise VyconfSessionError(self.output(out)) + + match token: + case None: + # config-mode sessions are persistent, and managed by caller (CLI or ConfigSession) + # + # 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 + ) + 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: + 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 and not extant: + self._finalizer = weakref.finalize(self, self._teardown, self.__token) self.on_error = on_error + def _teardown(self, 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(): @@ -95,6 +127,21 @@ def get_config(self): 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) @@ -129,6 +176,11 @@ def output(o): 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 +239,6 @@ def commit(self) -> tuple[str, int]: 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( diff --git a/src/helpers/teardown-config-session.py b/src/helpers/teardown-config-session.py index c30303c99d..49a3f5bc55 100755 --- a/src/helpers/teardown-config-session.py +++ b/src/helpers/teardown-config-session.py @@ -23,5 +23,10 @@ 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()