Repository: fail2ban/fail2ban

Issue:
python 3.9 threading changes
Copied from https://bugzilla.redhat.com/show_bug.cgi?id=1808347

            Bug ID: 1808347
           Summary: fail2ban fails to build with Python 3.9: uses removed
                    threading.Thread.isAlive()
           Product: Fedora
           Version: rawhide
            Status: NEW
         Component: fail2ban
          Assignee: orion@nwra.com
          Reporter: mhroncok@redhat.com
        QA Contact: extras-qa@fedoraproject.org
                CC: anon.amish@gmail.com, axel.thimm@atrpms.net,
                    cstratak@redhat.com, mhroncok@redhat.com,
                    mplch@redhat.com, orion@nwra.com, vonsch@gmail.com
            Blocks: 1785415 (PYTHON39)
  Target Milestone: ---
    Classification: Fedora

fail2ban fails to build with Python 3.9.0a4.
```
ERROR: test_del_file
(fail2ban.tests.filtertestcase.MonitorFailures<FilterPoll>(/tmp/monitorfailures_FilterPoll__nshi9c2fail2ban))
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./fail2ban/tests/filtertestcase.py", line 987, in setUp
    self._sleep_4_poll()
  File "./fail2ban/tests/filtertestcase.py", line 1008, in _sleep_4_poll
    Utils.wait_for(self.filter.isAlive, _maxWaitTime(5))
AttributeError: 'FilterPoll' object has no attribute 'isAlive'
```

And more. This looks like:

See https://docs.python.org/3.9/whatsnew/3.9.html#removed

"The isAlive() method of threading.Thread has been removed. It was deprecated
since Python 3.8. Use is_alive() instead."

For the build logs, see:
https://copr-be.cloud.fedoraproject.org/results/@python/python3.9/fedora-rawhide-x86_64/01255081-fail2ban/

For all our attempts to build fail2ban with Python 3.9, see:
https://copr.fedorainfracloud.org/coprs/g/python/python3.9/package/fail2ban/

Testing and mass rebuild of packages is happening in copr. You can follow these
instructions to test locally in mock if your package builds with Python 3.9:
https://copr.fedorainfracloud.org/coprs/g/python/python3.9/

Let us know here if you have any questions.

Python 3.9 will be included in Fedora 33. To make that update smoother, we're
building Fedora packages with early pre-releases of Python 3.9.
A build failure prevents us from testing all dependent packages (transitive
[Build]Requires), so if this package is required a lot, it's important for us
to get it fixed soon.
We'd appreciate help from the people who know this package best, but if you
don't want to work on this now, let us know so we can try to work around it on
our side.


Referenced Bugs:

https://bugzilla.redhat.com/show_bug.cgi?id=1785415
[Bug 1785415] Python 3.9


Discussion:

Resolving patch:
diff --git a/fail2ban/server/jailthread.py b/fail2ban/server/jailthread.py
--- a/fail2ban/server/jailthread.py
+++ b/fail2ban/server/jailthread.py
@@ -120,3 +120,6 @@ def join(self):
 ## python 2.x replace binding of private __bootstrap method:
 if sys.version_info < (3,): # pragma: 3.x no cover
 	JailThread._Thread__bootstrap = JailThread._JailThread__bootstrap
+## python 3.9, restore isAlive method:
+elif not hasattr(JailThread, 'isAlive'): # pragma: 2.x no cover
+	 JailThread.isAlive = JailThread.is_alive


Test patch:
diff --git a/fail2ban/tests/sockettestcase.py b/fail2ban/tests/sockettestcase.py
--- a/fail2ban/tests/sockettestcase.py
+++ b/fail2ban/tests/sockettestcase.py
@@ -86,7 +86,7 @@ def _createServerThread(self, force=False):
 	def _stopServerThread(self):
 		serverThread = self.serverThread
 		# wait for end of thread :
-		Utils.wait_for(lambda: not serverThread.isAlive() 
+		Utils.wait_for(lambda: not serverThread.is_alive() 
 			or serverThread.join(Utils.DEFAULT_SLEEP_TIME), unittest.F2B.maxWaitTime(10))
 		self.serverThread = None
 
@@ -97,7 +97,7 @@ def testStopPerCloseUnexpected(self):
 		self.server.close()
 		# wait for end of thread :
 		self._stopServerThread()
-		self.assertFalse(serverThread.isAlive())
+		self.assertFalse(serverThread.is_alive())
 		# clean :
 		self.server.stop()
 		self.assertFalse(self.server.isActive())
@@ -138,7 +138,7 @@ def testSocket(self):
 		self.server.stop()
 		# wait for end of thread :
 		self._stopServerThread()
-		self.assertFalse(serverThread.isAlive())
+		self.assertFalse(serverThread.is_alive())
 		self.assertFalse(self.server.isActive())
 		self.assertFalse(os.path.exists(self.sock_name))
 
@@ -179,7 +179,7 @@ def testStopByCommunicate(self):
 		self.server.stop()
 		# wait for end of thread :
 		self._stopServerThread()
-		self.assertFalse(serverThread.isAlive())
+		self.assertFalse(serverThread.is_alive())
 
 	def testLoopErrors(self):
 		# replace poll handler to produce error in loop-cycle:
@@ -215,7 +215,7 @@ def testSocketForce(self):
 		self.server.stop()
 		# wait for end of thread :
 		self._stopServerThread()
-		self.assertFalse(serverThread.isAlive())
+		self.assertFalse(serverThread.is_alive())
 		self.assertFalse(self.server.isActive())
 		self.assertFalse(os.path.exists(self.sock_name))