diff options
| author | Zuul <zuul@review.opendev.org> | 2025-08-06 15:13:35 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2025-08-06 15:13:35 +0000 |
| commit | 5563c32e652153e9e7856b2c01075c3cdf45403d (patch) | |
| tree | 22772ccc1d3716d200495f8b79adb4f1380cd9f5 | |
| parent | f25cf12455e3180dd422581c96e2a73df5d1d666 (diff) | |
| parent | ddac7ca1ed393609b7bda8753db3598f1ae02648 (diff) | |
| download | kolla-5563c32e652153e9e7856b2c01075c3cdf45403d.tar.gz kolla-5563c32e652153e9e7856b2c01075c3cdf45403d.zip | |
Merge "send empty X-Registry-Auth for anonymous pushes"
| -rw-r--r-- | kolla/image/tasks.py | 10 | ||||
| -rw-r--r-- | kolla/tests/test_build.py | 20 |
2 files changed, 25 insertions, 5 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): diff --git a/kolla/tests/test_build.py b/kolla/tests/test_build.py index ca2faa056..deb2dfa10 100644 --- a/kolla/tests/test_build.py +++ b/kolla/tests/test_build.py @@ -81,10 +81,12 @@ class TasksTest(base.TestCase): @mock.patch(engine_client) def test_push_image(self, mock_client): self.engine_client = mock_client + mock_client().api._auth_configs = {} pusher = tasks.PushTask(self.conf, self.image) pusher.run() mock_client().images.push.assert_called_once_with( - self.image.canonical_name, decode=True, stream=True) + self.image.canonical_name, + decode=True, stream=True, auth_config={}) self.assertTrue(pusher.success) @mock.patch.dict(os.environ, clear=True) @@ -92,11 +94,13 @@ class TasksTest(base.TestCase): def test_push_image_failure(self, mock_client): """failure on connecting Docker API""" self.engine_client = mock_client + mock_client().api._auth_configs = {} mock_client().images.push.side_effect = Exception pusher = tasks.PushTask(self.conf, self.image) pusher.run() mock_client().images.push.assert_called_once_with( - self.image.canonical_name, decode=True, stream=True) + self.image.canonical_name, + decode=True, stream=True, auth_config={}) self.assertFalse(pusher.success) self.assertEqual(utils.Status.PUSH_ERROR, self.image.status) @@ -105,11 +109,13 @@ class TasksTest(base.TestCase): def test_push_image_failure_retry(self, mock_client): """failure on connecting Docker API, success on retry""" self.engine_client = mock_client + mock_client().api._auth_configs = {} mock_client().images.push.side_effect = [Exception, []] pusher = tasks.PushTask(self.conf, self.image) pusher.run() mock_client().images.push.assert_called_once_with( - self.image.canonical_name, decode=True, stream=True) + self.image.canonical_name, + decode=True, stream=True, auth_config={}) self.assertFalse(pusher.success) self.assertEqual(utils.Status.PUSH_ERROR, self.image.status) @@ -125,12 +131,14 @@ class TasksTest(base.TestCase): def test_push_image_failure_error(self, mock_client): """Docker connected, failure to push""" self.engine_client = mock_client + mock_client().api._auth_configs = {} mock_client().images.push.return_value = [{'errorDetail': {'message': 'mock push fail'}}] pusher = tasks.PushTask(self.conf, self.image) pusher.run() mock_client().images.push.assert_called_once_with( - self.image.canonical_name, decode=True, stream=True) + self.image.canonical_name, + decode=True, stream=True, auth_config={}) self.assertFalse(pusher.success) self.assertEqual(utils.Status.PUSH_ERROR, self.image.status) @@ -139,12 +147,14 @@ class TasksTest(base.TestCase): def test_push_image_failure_error_retry(self, mock_client): """Docker connected, failure to push, success on retry""" self.engine_client = mock_client + mock_client().api._auth_configs = {} mock_client().images.push.return_value = [{'errorDetail': {'message': 'mock push fail'}}] pusher = tasks.PushTask(self.conf, self.image) pusher.run() mock_client().images.push.assert_called_once_with( - self.image.canonical_name, decode=True, stream=True) + self.image.canonical_name, + decode=True, stream=True, auth_config={}) self.assertFalse(pusher.success) self.assertEqual(utils.Status.PUSH_ERROR, self.image.status) |
