Skip to content

Commit 6573762

Browse files
authored
Merge pull request #1220 from jobselko/backport_1006
[PULP-1694] [3.19] Fix pull-through failing to check repository when package was not in remote
2 parents 5973730 + 3eb46f7 commit 6573762

3 files changed

Lines changed: 58 additions & 29 deletions

File tree

CHANGES/1004.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed pull-through caching not checking the repository if package was not present on remote.

pulp_python/app/pypi/views.py

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
HttpResponse,
1616
HttpResponseBadRequest,
1717
HttpResponseForbidden,
18+
HttpResponseNotFound,
1819
StreamingHttpResponse,
1920
)
2021
from django.shortcuts import redirect
@@ -255,52 +256,53 @@ def parse_package(release_package):
255256

256257
rfilter = get_remote_package_filter(remote)
257258
if not rfilter.filter_project(package):
258-
raise Http404(f"{package} does not exist.")
259+
return {}
259260

260261
url = remote.get_remote_artifact_url(f"simple/{package}/")
261262
remote.headers = remote.headers or []
262263
remote.headers.append({"Accept": ACCEPT_JSON_PREFERRED})
263264
downloader = remote.get_downloader(url=url, max_retries=1)
264265
try:
265266
d = downloader.fetch()
266-
except ClientError:
267-
return HttpResponse(f"Failed to fetch {package} from {remote.url}.", status=502)
268-
except TimeoutException:
269-
return HttpResponse(f"{remote.url} timed out while fetching {package}.", status=504)
267+
except (ClientError, TimeoutException):
268+
log.info(f"Failed to fetch {package} simple page from {remote.url}")
269+
return {}
270270

271271
if d.headers["content-type"] == "application/vnd.pypi.simple.v1+json":
272272
page = ProjectPage.from_json_data(json.load(open(d.path, "rb")), base_url=url)
273273
else:
274274
page = ProjectPage.from_html(package, open(d.path, "rb").read(), base_url=url)
275-
packages = [
276-
parse_package(p) for p in page.packages if rfilter.filter_release(package, p.version)
277-
]
278-
return HttpResponse(write_simple_detail(package, packages))
275+
return {
276+
p.filename: parse_package(p)
277+
for p in page.packages
278+
if rfilter.filter_release(package, p.version)
279+
}
279280

280281
@extend_schema(operation_id="pypi_simple_package_read", summary="Get package simple page")
281282
def retrieve(self, request, path, package):
282283
"""Retrieves the simple api html page for a package."""
283284
repo_ver, content = self.get_rvc()
284285
# Should I redirect if the normalized name is different?
285286
normalized = canonicalize_name(package)
287+
releases = {}
286288
if self.distribution.remote:
287-
return self.pull_through_package_simple(normalized, path, self.distribution.remote)
288-
if self.should_redirect(repo_version=repo_ver):
289+
releases = self.pull_through_package_simple(normalized, path, self.distribution.remote)
290+
elif self.should_redirect(repo_version=repo_ver):
289291
return redirect(urljoin(self.base_content_url, f"{path}/simple/{normalized}/"))
290-
packages = (
291-
content.filter(name__normalize=normalized)
292-
.values_list("filename", "sha256", "name")
293-
.iterator()
294-
)
295-
try:
296-
present = next(packages)
297-
except StopIteration:
298-
raise Http404(f"{normalized} does not exist.")
299-
else:
300-
packages = chain([present], packages)
301-
name = present[2]
302-
releases = ((f, urljoin(self.base_content_url, f"{path}/{f}"), d) for f, d, _ in packages)
303-
return StreamingHttpResponse(write_simple_detail(name, releases, streamed=True))
292+
if content:
293+
packages = content.filter(name__normalize=normalized).values("filename", "sha256")
294+
local_releases = {
295+
p["filename"]: (
296+
p["filename"],
297+
urljoin(self.base_content_url, f"{path}/{p['filename']}"),
298+
p["sha256"],
299+
)
300+
for p in packages
301+
}
302+
releases.update(local_releases)
303+
if not releases:
304+
return HttpResponseNotFound(f"{normalized} does not exist.")
305+
return HttpResponse(write_simple_detail(normalized, releases.values()))
304306

305307
@extend_schema(
306308
request=PackageUploadSerializer,

pulp_python/tests/functional/api/test_full_mirror.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def test_pull_through_filter(python_remote_factory, python_distribution_factory)
6666

6767
r = requests.get(f"{distro.base_url}simple/pulpcore/")
6868
assert r.status_code == 404
69-
assert r.json() == {"detail": "pulpcore does not exist."}
69+
assert r.text == "pulpcore does not exist."
7070

7171
r = requests.get(f"{distro.base_url}simple/shelf-reader/")
7272
assert r.status_code == 200
@@ -86,11 +86,11 @@ def test_pull_through_filter(python_remote_factory, python_distribution_factory)
8686

8787
r = requests.get(f"{distro.base_url}simple/django/")
8888
assert r.status_code == 404
89-
assert r.json() == {"detail": "django does not exist."}
89+
assert r.text == "django does not exist."
9090

9191
r = requests.get(f"{distro.base_url}simple/pulpcore/")
92-
assert r.status_code == 502
93-
assert r.text == f"Failed to fetch pulpcore from {remote.url}."
92+
assert r.status_code == 404
93+
assert r.text == "pulpcore does not exist."
9494

9595
r = requests.get(f"{distro.base_url}simple/shelf-reader/")
9696
assert r.status_code == 200
@@ -138,3 +138,29 @@ def test_pull_through_with_repo(
138138
assert r.status_code == 200
139139
tasks = pulpcore_bindings.TasksApi.list(reserved_resources=repo.prn)
140140
assert tasks.count == 3
141+
142+
143+
@pytest.mark.parallel
144+
def test_pull_through_local_only(
145+
python_remote_factory, python_distribution_factory, python_repo_with_sync
146+
):
147+
"""Tests that pull-through checks the repository if the package is not present on the remote."""
148+
remote = python_remote_factory(url=PYPI_URL, includes=["pulpcore"])
149+
repo = python_repo_with_sync(remote=remote)
150+
remote2 = python_remote_factory(includes=[]) # Fixtures does not have pulpcore
151+
distro = python_distribution_factory(repository=repo.pulp_href, remote=remote2.pulp_href)
152+
153+
url = f"{distro.base_url}simple/pulpcore/"
154+
r = requests.get(url)
155+
assert r.status_code == 200
156+
assert "?redirect=" not in r.text
157+
158+
url = f"{distro.base_url}simple/shelf-reader/"
159+
r = requests.get(url)
160+
assert r.status_code == 200
161+
assert "?redirect=" in r.text
162+
163+
url = f"{distro.base_url}simple/pulp_python/"
164+
r = requests.get(url)
165+
assert r.status_code == 404
166+
assert r.text == "pulp-python does not exist."

0 commit comments

Comments
 (0)