Repository: buildbot/buildbot

Issue:
Add support for docker-py 6.0.0
See https://github.com/docker/docker-py/releases/tag/6.0.0

Foolishly, I did not pin my docker-py version. So since august, our build server was broken and it turned out to be coming from a new version of docker-py. The following shows what happens with current Buildbot master and docker-py 6.0.0:

```
buildbot_master  | 2022-10-17 13:41:09+0000 [-] while worker_prepare
buildbot_master  |       Traceback (most recent call last):
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/twisted/internet/defer.py", line 891, in _runCallbacks
buildbot_master  |           current.result = callback(  # type: ignore[misc]
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/twisted/internet/defer.py", line 1791, in gotResult
buildbot_master  |           _inlineCallbacks(r, gen, status, context)
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/twisted/internet/defer.py", line 1692, in _inlineCallbacks
buildbot_master  |           result = context.run(
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/twisted/python/failure.py", line 518, in throwExceptionIntoGenerator
buildbot_master  |           return g.throw(self.type, self.value, self.tb)
buildbot_master  |       --- <exception caught here> ---
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/buildbot/process/build.py", line 360, in startBuild
buildbot_master  |           ready_or_failure = yield workerforbuilder.substantiate_if_needed(self)
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/buildbot/worker/latent.py", line 289, in _substantiate
buildbot_master  |           start_success = yield self.start_instance(build)
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/twisted/internet/defer.py", line 1692, in _inlineCallbacks
buildbot_master  |           result = context.run(
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/twisted/python/failure.py", line 518, in throwExceptionIntoGenerator
buildbot_master  |           return g.throw(self.type, self.value, self.tb)
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/buildbot/worker/docker.py", line 233, in start_instance
buildbot_master  |           res = yield threads.deferToThread(self._thd_start_instance, docker_host, image,
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/twisted/python/threadpool.py", line 244, in inContext
buildbot_master  |           result = inContext.theWork()  # type: ignore[attr-defined]
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/twisted/python/threadpool.py", line 260, in <lambda>
buildbot_master  |           inContext.theWork = lambda: context.call(  # type: ignore[attr-defined]
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/twisted/python/context.py", line 117, in callWithContext
buildbot_master  |           return self.currentContext().callWithContext(ctx, func, *args, **kw)
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/twisted/python/context.py", line 82, in callWithContext
buildbot_master  |           return func(*args, **kw)
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/buildbot/worker/docker.py", line 253, in _thd_start_instance
buildbot_master  |           docker_client = self._getDockerClient(curr_client_args)
buildbot_master  |         File "/buildbot_venv/lib/python3.9/site-packages/buildbot/worker/docker.py", line 213, in _getDockerClient
buildbot_master  |           if docker.version[0] == '1':
buildbot_master  |       builtins.TypeError: 'module' object is not subscriptable
```

(This stack trace is from Buildbot v3.5.0)

Quoting from the GitHub releases page:
```
Version metadata is now exposed as __version__
```

So this was the failure in the stack trace.


Discussion:

Resolving patch:
diff --git a/master/buildbot/worker/docker.py b/master/buildbot/worker/docker.py
--- a/master/buildbot/worker/docker.py
+++ b/master/buildbot/worker/docker.py
@@ -210,7 +210,7 @@ def _thd_parse_volumes(self, volumes):
         return volume_list, volumes
 
     def _getDockerClient(self, client_args):
-        if docker.version[0] == '1':
+        if 1.0 <= docker_py_version < 2.0:
             docker_client = client.Client(**client_args)
         else:
             docker_client = client.APIClient(**client_args)


Test patch:
diff --git a/master/buildbot/test/fake/docker.py b/master/buildbot/test/fake/docker.py
--- a/master/buildbot/test/fake/docker.py
+++ b/master/buildbot/test/fake/docker.py
@@ -14,7 +14,7 @@
 # Copyright Buildbot Team Members
 
 
-version = "1.10.6"
+__version__ = "1.10.6"
 
 
 class Client:
diff --git a/master/buildbot/test/unit/worker/test_docker.py b/master/buildbot/test/unit/worker/test_docker.py
--- a/master/buildbot/test/unit/worker/test_docker.py
+++ b/master/buildbot/test/unit/worker/test_docker.py
@@ -96,7 +96,7 @@ def test_builds_may_be_incompatible(self):
 
     @defer.inlineCallbacks
     def test_contruction_minimal_docker_py(self):
-        docker.version = "1.10.6"
+        self.patch(dockerworker, 'docker_py_version', 1.10)
         bs = yield self.setupWorker('bot', 'pass', 'tcp://1234:2375', 'worker')
         yield bs.start_instance(self.build)
         client = docker.APIClient.latest
@@ -106,7 +106,7 @@ def test_contruction_minimal_docker_py(self):
 
     @defer.inlineCallbacks
     def test_contruction_minimal_docker(self):
-        docker.version = "2.0.0"
+        self.patch(dockerworker, 'docker_py_version', 2.0)
         bs = yield self.setupWorker('bot', 'pass', 'tcp://1234:2375', 'worker')
         yield bs.start_instance(self.build)
         client = docker.Client.latest