Skip to content

Commit 72db4ce

Browse files
authored
fix: de pull fails for images with digest in URI (#1347)
DE image pulls will fail when there is a sha digest in the URI. This fix implements a change to the pull logic to split the image URI and pass the repo and tag to podman-py as separate params, as documented in the podman-py docs.
1 parent 7e2b6bf commit 72db4ce

File tree

4 files changed

+64
-4
lines changed

4 files changed

+64
-4
lines changed

src/aap_eda/services/activation/engine/podman.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from aap_eda.core.enums import ActivationStatus
2626
from aap_eda.settings import features
2727
from aap_eda.utils import str_to_bool
28+
from aap_eda.utils.podman import parse_repository
2829

2930
from . import exceptions, messages
3031
from .common import (
@@ -379,7 +380,12 @@ def _pull_image(
379380
"username": request.credential.username,
380381
"password": request.credential.secret,
381382
}
382-
image = self.client.images.pull(request.image_url, **kwargs)
383+
384+
image_repository, image_tag = parse_repository(request.image_url)
385+
386+
image = self.client.images.pull(
387+
repository=image_repository, tag=image_tag, **kwargs
388+
)
383389

384390
LOGGER.info("Downloaded image")
385391
return image

src/aap_eda/utils/podman.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Copyright 2025 Red Hat, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
from typing import Optional
15+
16+
17+
# temporary parser until bug is fixed in podman-py
18+
# https://github.com/containers/podman-py/pull/555
19+
def parse_repository(name: str) -> tuple[str, Optional[str]]:
20+
"""Parse repository image name from tag or digest.
21+
22+
Returns:
23+
item 1: repository name
24+
item 2: Either tag or None
25+
"""
26+
# split repository and image name from tag
27+
# tags need to be split from the right since
28+
# a port number might increase the split list len by 1
29+
elements = name.rsplit(":", 1)
30+
if len(elements) == 2 and "/" not in elements[1]:
31+
return elements[0], elements[1]
32+
33+
return name, None

tests/integration/services/activation/engine/test_podman.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
from aap_eda.settings.default import ( # noqa: N811
4949
DYNACONF as orig_dynaconf_settings,
5050
)
51+
from aap_eda.utils.podman import parse_repository
5152

5253
from .utils import InitData, get_ansible_rulebook_cmdline, get_request
5354

@@ -262,16 +263,33 @@ def test_engine_start_with_none_image_url(
262263
engine.start(request, log_handler)
263264

264265

266+
@pytest.mark.parametrize(
267+
"image_url",
268+
[
269+
"quay.io/ansible/ansible-rulebook",
270+
"quay.io:5004/ansible/ansible-rulebook",
271+
"quay.io:5004/ansible/ansible-rulebook:main",
272+
"quay.io/ansible/ansible-rulebook@sha256:756dd6a40b62975ea10d83a577ed6b1cddd545de17d9fb56b3d4e80e166826df", # noqa: E501
273+
"quay.io:5004/ansible/ansible-rulebook@sha256:756dd6a40b62975ea10d83a577ed6b1cddd545de17d9fb56b3d4e80e166826df", # noqa: E501
274+
"quay.io:443/ansible/ansible-rulebook@sha512:756dd6a40b62975ea10d83a577ed6b1cddd545de17d9fb56b3d4e80e166826df", # noqa: E501
275+
"quay.io/ansible/ansible-rulebook:42@sha256:756dd6a40b62975ea10d83a577ed6b1cddd545de17d9fb56b3d4e80e166826df", # noqa: E501
276+
],
277+
)
265278
@pytest.mark.django_db
266279
def test_engine_start_with_credential(
267280
init_podman_data,
268281
podman_engine,
269282
default_organization: models.Organization,
283+
image_url,
270284
):
271285
engine = podman_engine
272286
log_handler = DBLogger(init_podman_data.activation_instance.id)
273287
request = get_request(
274-
init_podman_data, "me", default_organization, mounts=[{"/dev": "/opt"}]
288+
init_podman_data,
289+
"me",
290+
default_organization,
291+
image_url,
292+
mounts=[{"/dev": "/opt"}],
275293
)
276294
credential = Credential(
277295
username="me",
@@ -283,8 +301,10 @@ def test_engine_start_with_credential(
283301

284302
engine.start(request, log_handler)
285303

304+
image_repo, image_tag = parse_repository(request.image_url)
286305
engine.client.images.pull.assert_called_once_with(
287-
request.image_url,
306+
repository=image_repo,
307+
tag=image_tag,
288308
tls_verify=bool(credential.ssl_verify),
289309
auth_config={
290310
"username": credential.username,

tests/integration/services/activation/engine/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,12 @@ def get_request(
4646
data: InitData,
4747
username: str,
4848
default_organization: models.Organization,
49+
image_url: str = "quay.io/ansible/ansible-rulebook:main",
4950
**kwargs,
5051
):
5152
return ContainerRequest(
5253
name="test-request",
53-
image_url="quay.io/ansible/ansible-rulebook:main",
54+
image_url=image_url,
5455
rulebook_process_id=data.activation_instance.id,
5556
process_parent_id=data.activation.id,
5657
cmdline=get_ansible_rulebook_cmdline(data),

0 commit comments

Comments
 (0)