diff options
| author | Bartosz Bezak <bartosz@stackhpc.com> | 2025-08-04 11:31:26 +0200 |
|---|---|---|
| committer | Bartosz Bezak <bartosz@stackhpc.com> | 2025-08-06 11:50:39 +0200 |
| commit | ddac7ca1ed393609b7bda8753db3598f1ae02648 (patch) | |
| tree | 7bf0adec2a75b26ebe79acb2d6a3170f42b65472 /kolla/image | |
| parent | 9f24ce63d0ce245cc732a9c47a7dd4c39ee42066 (diff) | |
| download | kolla-ddac7ca1ed393609b7bda8753db3598f1ae02648.tar.gz kolla-ddac7ca1ed393609b7bda8753db3598f1ae02648.zip | |
send empty X-Registry-Auth for anonymous pushes
Since Docker 28.3.3 the daemon rejects a push that carries no
`X-Registry-Auth` header [1]. The SDK already sets this header when it
finds credentials, so the breakage happens only on anonymous pushes.
During `PushTask.push_image()` we now check whether the SDK can resolve
credentials for the target registry; if it cannot, we inject
`auth_config={}`, causing the SDK to send the minimal "{}" header that
satisfies the daemon while leaving authenticated pushes unchanged.
Drop this addition when [2] is fixed.
[1] https://github.com/moby/moby/pull/50371
[2] https://github.com/docker/docker-py/issues/3348
Closes-Bug: #2119619
Change-Id: I7a2f3fce223afd74741b40bf62836b325fca5b19
Signed-off-by: Bartosz Bezak <bartosz@stackhpc.com>
Diffstat (limited to 'kolla/image')
| -rw-r--r-- | kolla/image/tasks.py | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/kolla/image/tasks.py b/kolla/image/tasks.py index 28af3d52d..39d759390 100644 --- a/kolla/image/tasks.py +++ b/kolla/image/tasks.py @@ -119,6 +119,16 @@ class PushTask(EngineTask): def push_image(self, image): kwargs = dict(stream=True, decode=True) + # NOTE(bbezak): Docker ≥ 28.3.3 rejects a push with no + # X-Registry-Auth header (moby/moby#50371, docker-py#3348). + # If the SDK cannot find creds for this registry, we inject + # an empty {} so the daemon still accepts the request. + # TODO(bbezak): Remove fallback once docker-py handles empty auth + if self.conf.engine == engine.Engine.DOCKER.value: + from docker.auth import resolve_authconfig + if not resolve_authconfig(self.engine_client.api._auth_configs, + registry=self.conf.registry): + kwargs.setdefault("auth_config", {}) for response in self.engine_client.images.push(image.canonical_name, **kwargs): |
