From 40858f367856697f9b5a793e9f1aef78f8e276a4 Mon Sep 17 00:00:00 2001 From: Arun S A G Date: Wed, 9 Sep 2020 17:22:29 -0700 Subject: [PATCH] Add support for TCP keep alive in gerritlib Clients using gerritlib behind NAT/firewall can be stuck when the NAT/firewall discard packets belong to the TCP connection after extended silent periods thinking the connection is dead. This change allows clients using gerritlib to set keep alive interval to a non zero value. This will enable TCP keep alive packets to be sent in configured intervals keeping the TCP connections alive. Change-Id: I588706bb51ce41810cd2243f4969763d193d1d55 --- doc/source/usage.rst | 4 ++-- gerritlib/gerrit.py | 15 +++++++++++---- test-requirements.txt | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/doc/source/usage.rst b/doc/source/usage.rst index 8dff103..085a0b5 100644 --- a/doc/source/usage.rst +++ b/doc/source/usage.rst @@ -5,7 +5,7 @@ Usage Example usage:: import gerritlib.gerrit as gerrit - g = gerrit.Gerrit('gerrit_host', 'username', keyfile='/home/username/.ssh/id_rsa.pub') + g = gerrit.Gerrit('gerrit_host', 'username', keyfile='/home/username/.ssh/id_rsa.pub', keep_alive_interval=60) # manage projects g.createProject('test', description='a test project') @@ -18,4 +18,4 @@ Example usage:: print(groups) -Look at the :doc:`api` for more details. \ No newline at end of file +Look at the :doc:`api` for more details. diff --git a/gerritlib/gerrit.py b/gerritlib/gerrit.py index 6172488..a518bfb 100644 --- a/gerritlib/gerrit.py +++ b/gerritlib/gerrit.py @@ -40,7 +40,8 @@ class GerritConnection(object): log = logging.getLogger("gerrit.GerritConnection") def __init__(self, username=None, hostname=None, port=29418, - keyfile=None, connection_attempts=-1, retry_delay=5): + keyfile=None, keep_alive=0, connection_attempts=-1, + retry_delay=5): assert retry_delay >= 0, "Retry delay must be >= 0" self.username = username @@ -49,6 +50,7 @@ class GerritConnection(object): self.keyfile = keyfile self.connection_attempts = int(connection_attempts) self.retry_delay = float(retry_delay) + self.keep_alive = keep_alive def connect(self): """Attempts to connect and returns the connected client.""" @@ -85,6 +87,8 @@ class GerritConnection(object): username=self.username, port=self.port, key_filename=self.keyfile) + if self.keep_alive: + client.get_transport().set_keepalive(self.keep_alive) return client except (IOError, paramiko.SSHException) as e: self.log.exception("Exception connecting to %s:%s", @@ -108,7 +112,7 @@ class GerritWatcher(threading.Thread): def __init__( self, gerrit, username=None, hostname=None, port=None, - keyfile=None, connection_attempts=-1, retry_delay=5): + keyfile=None, keep_alive=0, connection_attempts=-1, retry_delay=5): """Create a GerritWatcher. :param gerrit: A GerritConnection instance to pass events to. @@ -122,6 +126,7 @@ class GerritWatcher(threading.Thread): hostname or gerrit.connection.hostname, port or gerrit.connection.port, keyfile or gerrit.connection.keyfile, + keep_alive or gerrit.connection.keep_alive, connection_attempts, retry_delay ) @@ -194,8 +199,10 @@ class GerritWatcher(threading.Thread): class Gerrit(object): log = logging.getLogger("gerrit.Gerrit") - def __init__(self, hostname, username, port=29418, keyfile=None): - self.connection = GerritConnection(username, hostname, port, keyfile) + def __init__(self, hostname, username, port=29418, keyfile=None, + keep_alive_interval=0): + self.connection = GerritConnection(username, hostname, port, keyfile, + keep_alive=keep_alive_interval) self.client = None self.watcher_thread = None self.event_queue = None diff --git a/test-requirements.txt b/test-requirements.txt index 905b329..6aab4a2 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,4 +1,4 @@ -hacking>=0.5.6,<0.11 +hacking sphinx>=1.1.2,<1.2 python-subunit stestr<3.0.0;python_version<'3.5'