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()),
],
],