Skip to content

Commit

Permalink
Consider monotonic timer for future timeout detection (Python 3 only). (
Browse files Browse the repository at this point in the history
#14)

* Consider monotonic timer for future timeout detection (Python 3 only).

* version bumped, pylama satisfied
  • Loading branch information
skolbel authored Aug 3, 2021
1 parent 1fe9b71 commit 9c9f5fa
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 21 deletions.
2 changes: 1 addition & 1 deletion netconf_client/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.7.2
1.7.3
3 changes: 2 additions & 1 deletion netconf_client/connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -178,6 +178,7 @@ def _try_load_pkey(path):
return cls.from_private_key_file(path)
except Exception:
pass
return None


class SshSessionSock:
Expand Down
35 changes: 27 additions & 8 deletions netconf_client/ncclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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")
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down
22 changes: 11 additions & 11 deletions test/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def test_manager_lifecycle_with_id(session):
"</edit-config>",
],
[
r"NC Failure \(\d\.\d+ sec\)\n",
r"NC Failure \(\d+\.\d+ sec\)\n",
"Cause: RPC returned without result",
],
],
Expand All @@ -147,7 +147,7 @@ def test_manager_lifecycle_with_id(session):
"</edit-config>",
],
[
r"NC Failure <= Raspi-2 \(\d\.\d+ sec\)\n",
r"NC Failure <= Raspi-2 \(\d+\.\d+ sec\)\n",
"Cause: RPC returned without result",
],
],
Expand Down Expand Up @@ -195,7 +195,7 @@ def test_edit_config(session, fake_id, log_enabled, log_id, log_funcname, log_co
[
["NC Request:\n", "<get xmlns:nc", "<filter>foo</filter>", "</get>"],
[
r"NC Response \(\d\.\d+ sec\):\n",
r"NC Response \(\d+\.\d+ sec\):\n",
"<rpc-reply ",
"<data>bar</data>",
"</rpc-reply>",
Expand All @@ -215,7 +215,7 @@ def test_edit_config(session, fake_id, log_enabled, log_id, log_funcname, log_co
"</get>",
],
[
r"NC Response <= Raspi-4 \(\d\.\d+ sec\):\n",
r"NC Response <= Raspi-4 \(\d+\.\d+ sec\):\n",
"<rpc-reply ",
"<data>bar</data>",
"</rpc-reply>",
Expand All @@ -235,7 +235,7 @@ def test_edit_config(session, fake_id, log_enabled, log_id, log_funcname, log_co
"</get>",
],
[
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",
"<rpc-reply ",
"<data>bar</data>",
"</rpc-reply>",
Expand All @@ -255,7 +255,7 @@ def test_edit_config(session, fake_id, log_enabled, log_id, log_funcname, log_co
"</get>",
],
[
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",
"<rpc-reply ",
"<data>bar</data>",
"</rpc-reply>",
Expand Down Expand Up @@ -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",
"<rpc-reply ",
"<data>bar</data>",
"</rpc-reply>",
Expand Down Expand Up @@ -575,7 +575,7 @@ def test_dispatch(session, fake_id):
[
["NC Request:\n", "<rpc xmlns", "<data>pie test</data>", "</rpc>"],
[
r"NC Response \(\d\.\d+ sec\):\n",
r"NC Response \(\d+\.\d+ sec\):\n",
"<rpc-reply",
"<data>bar</data>",
"</rpc-reply>",
Expand Down Expand Up @@ -625,7 +625,7 @@ def test_take_notification_empty(session):
"</get>",
],
[
r"NC Failure <= bad device \(\d\.\d+ sec\)\n",
r"NC Failure <= bad device \(\d+\.\d+ sec\)\n",
"Cause: RPC cancelled",
],
],
Expand All @@ -641,7 +641,7 @@ def test_take_notification_empty(session):
"</get>",
],
[
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\)",
],
],
Expand All @@ -657,7 +657,7 @@ def test_take_notification_empty(session):
"</get>",
],
[
r"NC Failure <= bad device \(\d\.\d+ sec\)\n",
r"NC Failure <= bad device \(\d+\.\d+ sec\)\n",
"Cause: RPC exception: " + str(ValueError()),
],
],
Expand Down

0 comments on commit 9c9f5fa

Please sign in to comment.