From 9c9f5fa023960218c120d7bb704d37a3fe987d4a Mon Sep 17 00:00:00 2001 From: Steffen Koelbel <50140366+skolbel@users.noreply.github.com> Date: Tue, 3 Aug 2021 15:07:09 +0200 Subject: [PATCH] Consider monotonic timer for future timeout detection (Python 3 only). (#14) * Consider monotonic timer for future timeout detection (Python 3 only). * version bumped, pylama satisfied --- netconf_client/VERSION | 2 +- netconf_client/connect.py | 3 ++- netconf_client/ncclient.py | 35 +++++++++++++++++++++++++++-------- test/test_manager.py | 22 +++++++++++----------- 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/netconf_client/VERSION b/netconf_client/VERSION index f8a696c..661e7ae 100644 --- a/netconf_client/VERSION +++ b/netconf_client/VERSION @@ -1 +1 @@ -1.7.2 +1.7.3 diff --git a/netconf_client/connect.py b/netconf_client/connect.py index 4c112d3..08773b1 100644 --- a/netconf_client/connect.py +++ b/netconf_client/connect.py @@ -92,7 +92,7 @@ def connect_tls( sock.connect((host, port)) sock.settimeout(None) cert_reqs = ssl.CERT_REQUIRED if ca_certs else ssl.CERT_NONE - ssl_sock = ssl.wrap_socket( + ssl_sock = ssl.wrap_socket( # pylint: disable=W1505 sock, keyfile=keyfile, certfile=certfile, cert_reqs=cert_reqs, ca_certs=ca_certs ) return Session(ssl_sock) @@ -178,6 +178,7 @@ def _try_load_pkey(path): return cls.from_private_key_file(path) except Exception: pass + return None class SshSessionSock: diff --git a/netconf_client/ncclient.py b/netconf_client/ncclient.py index d693617..214a036 100644 --- a/netconf_client/ncclient.py +++ b/netconf_client/ncclient.py @@ -6,6 +6,8 @@ from six.moves.queue import Empty from lxml import etree +import six + from netconf_client.error import RpcError from netconf_client.rpc import ( edit_config, @@ -24,6 +26,15 @@ delete_config, ) +if six.PY3: + from time import monotonic + + _get_current_timestamp = monotonic +else: + from time import time + + _get_current_timestamp = time + # Defines the scope for netconf traces _logger = logging.getLogger("netconf_client.manager") @@ -210,14 +221,24 @@ def _send_rpc(self, rpc_xml): (raw, ele) = (None, None) self._log_rpc_request(rpc_xml) + current_timestamp = _get_current_timestamp() + end_timestamp = current_timestamp + self.timeout try: f = self.session.send_rpc(rpc_xml) - r = f.result(timeout=self.timeout) - if not r: - self._log_rpc_failure("RPC returned without result") - else: - (raw, ele) = f.result(timeout=self.timeout) - self._log_rpc_response(raw) + while current_timestamp < end_timestamp: + timeout = end_timestamp - current_timestamp + try: + r = f.result(timeout=timeout) + if not r: + self._log_rpc_failure("RPC returned without result") + else: + (raw, ele) = f.result(timeout=timeout) + self._log_rpc_response(raw) + return (raw, ele) + except TimeoutError: + current_timestamp = _get_current_timestamp() + if current_timestamp >= end_timestamp: + raise except CancelledError: self._log_rpc_failure("RPC cancelled") raise @@ -229,8 +250,6 @@ def _send_rpc(self, rpc_xml): self._log_rpc_failure("RPC exception: {}".format(message)) raise - return (raw, ele) - def edit_config( self, config, diff --git a/test/test_manager.py b/test/test_manager.py index 9550a9e..8ccfe97 100644 --- a/test/test_manager.py +++ b/test/test_manager.py @@ -130,7 +130,7 @@ def test_manager_lifecycle_with_id(session): "", ], [ - r"NC Failure \(\d\.\d+ sec\)\n", + r"NC Failure \(\d+\.\d+ sec\)\n", "Cause: RPC returned without result", ], ], @@ -147,7 +147,7 @@ def test_manager_lifecycle_with_id(session): "", ], [ - r"NC Failure <= Raspi-2 \(\d\.\d+ sec\)\n", + r"NC Failure <= Raspi-2 \(\d+\.\d+ sec\)\n", "Cause: RPC returned without result", ], ], @@ -195,7 +195,7 @@ def test_edit_config(session, fake_id, log_enabled, log_id, log_funcname, log_co [ ["NC Request:\n", "foo", ""], [ - r"NC Response \(\d\.\d+ sec\):\n", + r"NC Response \(\d+\.\d+ sec\):\n", "bar", "", @@ -215,7 +215,7 @@ def test_edit_config(session, fake_id, log_enabled, log_id, log_funcname, log_co "", ], [ - r"NC Response <= Raspi-4 \(\d\.\d+ sec\):\n", + r"NC Response <= Raspi-4 \(\d+\.\d+ sec\):\n", "bar", "", @@ -235,7 +235,7 @@ def test_edit_config(session, fake_id, log_enabled, log_id, log_funcname, log_co "", ], [ - r"NC Response 1\.2\.3\.4 <= 5\.6\.7\.8 \(\d\.\d+ sec\):\n", + r"NC Response 1\.2\.3\.4 <= 5\.6\.7\.8 \(\d+\.\d+ sec\):\n", "bar", "", @@ -255,7 +255,7 @@ def test_edit_config(session, fake_id, log_enabled, log_id, log_funcname, log_co "", ], [ - r"NC Response \(1\.2\.3\.4\) <= Raspi-4 \(5\.6\.7\.8\) \(\d\.\d+ sec\):\n", + r"NC Response \(1\.2\.3\.4\) <= Raspi-4 \(5\.6\.7\.8\) \(\d+\.\d+ sec\):\n", "bar", "", @@ -328,7 +328,7 @@ def test_xml_error(fake_id): bad_filter, ], [ - r"NC Response \(\d\.\d+ sec\):\n", + r"NC Response \(\d+\.\d+ sec\):\n", "bar", "", @@ -575,7 +575,7 @@ def test_dispatch(session, fake_id): [ ["NC Request:\n", "pie test", ""], [ - r"NC Response \(\d\.\d+ sec\):\n", + r"NC Response \(\d+\.\d+ sec\):\n", "bar", "", @@ -625,7 +625,7 @@ def test_take_notification_empty(session): "", ], [ - r"NC Failure <= bad device \(\d\.\d+ sec\)\n", + r"NC Failure <= bad device \(\d+\.\d+ sec\)\n", "Cause: RPC cancelled", ], ], @@ -641,7 +641,7 @@ def test_take_notification_empty(session): "", ], [ - r"NC Failure <= bad device \(\d\.\d+ sec\)\n", + r"NC Failure <= bad device \(\d+\.\d+ sec\)\n", r"Cause: RPC timeout \(max\. 10 seconds\)", ], ], @@ -657,7 +657,7 @@ def test_take_notification_empty(session): "", ], [ - r"NC Failure <= bad device \(\d\.\d+ sec\)\n", + r"NC Failure <= bad device \(\d+\.\d+ sec\)\n", "Cause: RPC exception: " + str(ValueError()), ], ],