pulpcore 3.77.0__py3-none-any.whl → 3.77.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pulpcore might be problematic. Click here for more details.

@@ -6,6 +6,6 @@ class PulpCertGuardPluginAppConfig(PulpPluginAppConfig):
6
6
 
7
7
  name = "pulp_certguard.app"
8
8
  label = "certguard"
9
- version = "3.77.0"
9
+ version = "3.77.1"
10
10
  python_package_name = "pulpcore"
11
11
  domain_compatible = True
pulp_file/app/__init__.py CHANGED
@@ -8,6 +8,6 @@ class PulpFilePluginAppConfig(PulpPluginAppConfig):
8
8
 
9
9
  name = "pulp_file.app"
10
10
  label = "file"
11
- version = "3.77.0"
11
+ version = "3.77.1"
12
12
  python_package_name = "pulpcore"
13
13
  domain_compatible = True
pulpcore/app/apps.py CHANGED
@@ -247,7 +247,7 @@ class PulpAppConfig(PulpPluginAppConfig):
247
247
  label = "core"
248
248
 
249
249
  # The version of this app
250
- version = "3.77.0"
250
+ version = "3.77.1"
251
251
 
252
252
  # The python package name providing this app
253
253
  python_package_name = "pulpcore"
pulpcore/cache/cache.py CHANGED
@@ -8,7 +8,7 @@ from django.http import HttpResponseRedirect, HttpResponse, FileResponse as ApiF
8
8
 
9
9
  from rest_framework.request import Request as ApiRequest
10
10
 
11
- from aiohttp.web import FileResponse, Response, HTTPSuccessful, Request
11
+ from aiohttp.web import FileResponse, Response, HTTPSuccessful, Request, StreamResponse
12
12
  from aiohttp.web_exceptions import HTTPFound
13
13
 
14
14
  from redis import ConnectionError
@@ -401,6 +401,11 @@ class AsyncContentCache(AsyncCache):
401
401
  except (HTTPSuccessful, HTTPFound) as e:
402
402
  response = e
403
403
 
404
+ original_response = response
405
+ if isinstance(response, StreamResponse):
406
+ if hasattr(response, "future_response"):
407
+ response = response.future_response
408
+
404
409
  entry = {"headers": dict(response.headers), "status": response.status}
405
410
  if expires is not None:
406
411
  # Redis TTL is not sufficient: https://github.com/pulp/pulpcore/issues/4845
@@ -427,12 +432,12 @@ class AsyncContentCache(AsyncCache):
427
432
  entry["location"] = str(response.location)
428
433
  entry["type"] = "Redirect"
429
434
  else:
430
- # We don't cache StreamResponses or errors
435
+ # We don't cache errors
431
436
  return response
432
437
 
433
438
  # TODO look into smaller format, maybe some compression on the text
434
439
  await self.set(key, json.dumps(entry), expires, base_key=base_key)
435
- return response
440
+ return original_response
436
441
 
437
442
  def make_key(self, request):
438
443
  """Makes the key based off the request"""
@@ -1093,26 +1093,8 @@ class Handler:
1093
1093
  ret.update({ca.relative_path: ca for ca in cas})
1094
1094
  return ret
1095
1095
 
1096
- async def _serve_content_artifact(self, content_artifact, headers, request):
1097
- """
1098
- Handle response for a Content Artifact with the file present.
1099
-
1100
- Depending on where the file storage (e.g. filesystem, S3, etc) this could be responding with
1101
- the file (filesystem) or a redirect (S3).
1102
-
1103
- Args:
1104
- content_artifact (pulpcore.app.models.ContentArtifact) The Content Artifact to
1105
- respond with.
1106
- headers (dict): A dictionary of response headers.
1107
- request(aiohttp.web.Request) The request to prepare a response for.
1108
-
1109
- Raises:
1110
- [aiohttp.web_exceptions.HTTPFound][]: When we need to redirect to the file
1111
- NotImplementedError: If file is stored in a file storage we can't handle
1112
-
1113
- Returns:
1114
- The [aiohttp.web.FileResponse][] for the file.
1115
- """
1096
+ def _build_response_from_content_artifact(self, content_artifact, headers, request):
1097
+ """Helper method to build the correct response to serve a ContentArtifact."""
1116
1098
 
1117
1099
  def _set_params_from_headers(hdrs, storage_domain):
1118
1100
  # Map standard-response-headers to storage-object-specific keys
@@ -1137,7 +1119,47 @@ class Handler:
1137
1119
  artifact_name = artifact_file.name
1138
1120
  domain = get_domain()
1139
1121
  storage = domain.get_storage()
1122
+ headers["X-PULP-ARTIFACT-SIZE"] = str(artifact_file.size)
1123
+
1124
+ if domain.storage_class == "pulpcore.app.models.storage.FileSystem":
1125
+ path = storage.path(artifact_name)
1126
+ if not os.path.exists(path):
1127
+ raise Exception(_("Expected path '{}' is not found").format(path))
1128
+ return FileResponse(path, headers=headers)
1129
+ elif not domain.redirect_to_object_storage:
1130
+ return ArtifactResponse(content_artifact.artifact, headers=headers)
1131
+ elif domain.storage_class == "storages.backends.s3boto3.S3Boto3Storage":
1132
+ return HTTPFound(_build_url(http_method=request.method), headers=headers)
1133
+ elif domain.storage_class in (
1134
+ "storages.backends.azure_storage.AzureStorage",
1135
+ "storages.backends.gcloud.GoogleCloudStorage",
1136
+ ):
1137
+ return HTTPFound(_build_url(), headers=headers)
1138
+ else:
1139
+ raise NotImplementedError()
1140
1140
 
1141
+ async def _serve_content_artifact(self, content_artifact, headers, request):
1142
+ """
1143
+ Handle response for a Content Artifact with the file present.
1144
+
1145
+ Depending on where the file storage (e.g. filesystem, S3, etc) this could be responding with
1146
+ the file (filesystem) or a redirect (S3).
1147
+
1148
+ Args:
1149
+ content_artifact (pulpcore.app.models.ContentArtifact) The Content Artifact to
1150
+ respond with.
1151
+ headers (dict): A dictionary of response headers.
1152
+ request(aiohttp.web.Request) The request to prepare a response for.
1153
+
1154
+ Raises:
1155
+ [aiohttp.web_exceptions.HTTPFound][]: When we need to redirect to the file
1156
+ NotImplementedError: If file is stored in a file storage we can't handle
1157
+ HTTPRequestRangeNotSatisfiable: If the request is for a range that is not
1158
+ satisfiable.
1159
+ Returns:
1160
+ The [aiohttp.web.FileResponse][] for the file.
1161
+ """
1162
+ artifact_file = content_artifact.artifact.file
1141
1163
  content_length = artifact_file.size
1142
1164
 
1143
1165
  try:
@@ -1152,25 +1174,13 @@ class Handler:
1152
1174
  size = artifact_file.size or "*"
1153
1175
  raise HTTPRequestRangeNotSatisfiable(headers={"Content-Range": f"bytes */{size}"})
1154
1176
 
1155
- headers["X-PULP-ARTIFACT-SIZE"] = str(content_length)
1156
1177
  artifacts_size_counter.add(content_length)
1157
1178
 
1158
- if domain.storage_class == "pulpcore.app.models.storage.FileSystem":
1159
- path = storage.path(artifact_name)
1160
- if not os.path.exists(path):
1161
- raise Exception(_("Expected path '{}' is not found").format(path))
1162
- return FileResponse(path, headers=headers)
1163
- elif not domain.redirect_to_object_storage:
1164
- return ArtifactResponse(content_artifact.artifact, headers=headers)
1165
- elif domain.storage_class == "storages.backends.s3boto3.S3Boto3Storage":
1166
- raise HTTPFound(_build_url(http_method=request.method), headers=headers)
1167
- elif domain.storage_class in (
1168
- "storages.backends.azure_storage.AzureStorage",
1169
- "storages.backends.gcloud.GoogleCloudStorage",
1170
- ):
1171
- raise HTTPFound(_build_url(), headers=headers)
1179
+ response = self._build_response_from_content_artifact(content_artifact, headers, request)
1180
+ if isinstance(response, HTTPFound):
1181
+ raise response
1172
1182
  else:
1173
- raise NotImplementedError()
1183
+ return response
1174
1184
 
1175
1185
  async def _stream_remote_artifact(
1176
1186
  self, request, response, remote_artifact, save_artifact=True, repository=None
@@ -1214,6 +1224,7 @@ class Handler:
1214
1224
  size = remote_artifact.size or "*"
1215
1225
  raise HTTPRequestRangeNotSatisfiable(headers={"Content-Range": f"bytes */{size}"})
1216
1226
 
1227
+ original_headers = response.headers.copy()
1217
1228
  actual_content_length = None
1218
1229
 
1219
1230
  if range_start or range_stop:
@@ -1323,9 +1334,14 @@ class Handler:
1323
1334
  content_artifacts = await asyncio.shield(
1324
1335
  sync_to_async(self._save_artifact)(download_result, remote_artifact, request)
1325
1336
  )
1337
+ ca = content_artifacts[remote_artifact.content_artifact.relative_path]
1338
+ # If cache is enabled, add the future response to our stream response
1339
+ if settings.CACHE_ENABLED:
1340
+ response.future_response = self._build_response_from_content_artifact(
1341
+ ca, original_headers, request
1342
+ )
1326
1343
  # Try to add content to repository if present & supported
1327
1344
  if repository and repository.PULL_THROUGH_SUPPORTED:
1328
- ca = content_artifacts[remote_artifact.content_artifact.relative_path]
1329
1345
  await sync_to_async(repository.pull_through_add_content)(ca)
1330
1346
  await response.write_eof()
1331
1347
 
@@ -16,7 +16,7 @@ from pulpcore.tests.functional.utils import get_from_url
16
16
  @pytest.mark.parallel
17
17
  def test_full_workflow(
18
18
  file_repo_with_auto_publish,
19
- basic_manifest_path,
19
+ duplicate_filename_paths,
20
20
  file_remote_factory,
21
21
  file_bindings,
22
22
  distribution_base_url,
@@ -37,7 +37,8 @@ def test_full_workflow(
37
37
  return r.status, r.headers.get("X-PULP-CACHE")
38
38
 
39
39
  # Sync from the remote and assert that a new repository version is created
40
- remote = file_remote_factory(manifest_path=basic_manifest_path, policy="immediate")
40
+ manifest_1, manifest_2 = duplicate_filename_paths
41
+ remote = file_remote_factory(manifest_path=manifest_1, policy="immediate")
41
42
  body = RepositorySyncURL(remote=remote.pulp_href)
42
43
  monitor_task(
43
44
  file_bindings.RepositoriesFileApi.sync(file_repo_with_auto_publish.pulp_href, body).task
@@ -129,6 +130,21 @@ def test_full_workflow(
129
130
  url = urljoin(distro_base_url, file)
130
131
  assert (200, "HIT" if i % 2 == 1 else "MISS") == _check_cache(url), file
131
132
 
133
+ # Sync a new remote with same filenames but on-demand
134
+ remote = file_remote_factory(manifest_path=manifest_2, policy="on_demand")
135
+ body = RepositorySyncURL(remote=remote.pulp_href)
136
+ monitor_task(
137
+ file_bindings.RepositoriesFileApi.sync(file_repo_with_auto_publish.pulp_href, body).task
138
+ )
139
+ repo = file_bindings.RepositoriesFileApi.read(file_repo_with_auto_publish.pulp_href)
140
+ assert repo.latest_version_href.endswith("/versions/3/")
141
+
142
+ # Test that cache is invalidated from sync, but on-demand responses are immediately cached
143
+ files = ["1.iso", "1.iso", "2.iso", "2.iso", "3.iso", "3.iso"]
144
+ for i, file in enumerate(files):
145
+ url = urljoin(distro_base_url, file)
146
+ assert (200, "HIT" if i % 2 == 1 else None) == _check_cache(url), file
147
+
132
148
  # Tests that deleting a repository invalidates the cache"""
133
149
  monitor_task(file_bindings.RepositoriesFileApi.delete(repo.pulp_href).task)
134
150
  files = ["", "PULP_MANIFEST", "2.iso"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulpcore
3
- Version: 3.77.0
3
+ Version: 3.77.1
4
4
  Summary: Pulp Django Application and Related Modules
5
5
  Author-email: Pulp Team <pulp-list@redhat.com>
6
6
  Project-URL: Homepage, https://pulpproject.org
@@ -1,6 +1,6 @@
1
1
  pulp_certguard/__init__.py,sha256=llnEd00PrsAretsgAOHiNKFbmvIdXe3iDVPmSaKz7gU,71
2
2
  pulp_certguard/pytest_plugin.py,sha256=qhRbChzqN2PROtD-65KuoTfKr5k9T3GPsz9daFgpqpM,852
3
- pulp_certguard/app/__init__.py,sha256=Ri9QtsoSI0bmv_5qz0wCvWhDbrGkCr8nUXdTtLNS8QM,297
3
+ pulp_certguard/app/__init__.py,sha256=yrfk5jSZdckh14GlycVlp7yj-aqEz9RhG4NbxWcr-tg,297
4
4
  pulp_certguard/app/models.py,sha256=xy5IWxf0LQxayIDmQw25Y2YhB_NrlTGvuvdY-YW7QBU,8119
5
5
  pulp_certguard/app/serializers.py,sha256=3jxWu82vU3xA578Qbyz-G4Q9Zlh3MFLGRHzX62M0RF8,1826
6
6
  pulp_certguard/app/utils.py,sha256=O6T1Npdb8fu3XqIkDJd8PQdEFJWPUeQ-i_aHXBl7MEc,816
@@ -49,7 +49,7 @@ pulp_certguard/tests/unit/test_models.py,sha256=TBI0yKsrdbnJSPeBFfxSqhXK7zaNvR6q
49
49
  pulp_file/__init__.py,sha256=0vOCXofR6Eyxkg4y66esnOGPeESCe23C1cNBHj56w44,61
50
50
  pulp_file/manifest.py,sha256=1WwIOJrPSkFcmkRm7CkWifVOCoZvo_nnANgce6uuG7U,3796
51
51
  pulp_file/pytest_plugin.py,sha256=Fi_p-Vle_I-VYUSe4Zlg7esb_Ul5fpB8Rx9UGLK5UNQ,13281
52
- pulp_file/app/__init__.py,sha256=jbAB2BH6-V4jKXVeEoaxYLmvFY-CRmc2LSOL3mBWyEw,292
52
+ pulp_file/app/__init__.py,sha256=VYwb2aF8lkSmk9tLh7bZi3s7FK82uIttiD6z8Setxaw,292
53
53
  pulp_file/app/modelresource.py,sha256=v-m-_bBEsfr8wG0TI5ffx1TuKUy2-PsirhuQz4XXF-0,1063
54
54
  pulp_file/app/models.py,sha256=QsrVg_2uKqnR89sLN2Y7Zy260_nLIcUfa94uZowlmFw,4571
55
55
  pulp_file/app/replica.py,sha256=OtNWVmdFUgNTYhPttftVNQnSrnvx2_hnrJgtW_G0Vrg,1894
@@ -110,7 +110,7 @@ pulpcore/pytest_plugin.py,sha256=Tq_xlO8Z2iyjFtbnaKHbWQogq6jxcRpjji9XbKrs5_U,377
110
110
  pulpcore/responses.py,sha256=mIGKmdCfTSoZxbFu4yIH1xbdLx1u5gqt3D99LTamcJg,6125
111
111
  pulpcore/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
112
112
  pulpcore/app/access_policy.py,sha256=5vCKy6WoHtIt1_-eS5vMaZ7CmR4G-CIpsrB8yT-d88Q,6079
113
- pulpcore/app/apps.py,sha256=Dyk1l_Cch5VavYZp-bbWsJA1SP9RcqQN9dPjHEKmtRE,17860
113
+ pulpcore/app/apps.py,sha256=x8Vf5rLOz4SXECRMlgYd6X18xDdnymVmdFS7c701DHo,17860
114
114
  pulpcore/app/authentication.py,sha256=1LIJW6HIQQlZrliHy__jdzkDEh6Oj7xKgd0V-vRcDus,2855
115
115
  pulpcore/app/checks.py,sha256=jbfTF7nmftBbky4AQXHigpyCaGydKasvRUXsd72JZVg,1946
116
116
  pulpcore/app/entrypoint.py,sha256=HRfaHDkveSIfcTOtWEWYqg1poTmTo0J9hzzmj0yDcEM,4885
@@ -369,11 +369,11 @@ pulpcore/app/viewsets/task.py,sha256=pMoOQnhjA91dUgNNAnL3OaCHcVOrQcB-CD3D5Px96YE
369
369
  pulpcore/app/viewsets/upload.py,sha256=Mfy9Vcm5KcqARooH4iExzoXVkL6boDddEqAnGWDWzFg,5452
370
370
  pulpcore/app/viewsets/user.py,sha256=86eMawpaVrvp6ilQmb1C4j7SKpesPB5HgMovYL9rY3Q,13813
371
371
  pulpcore/cache/__init__.py,sha256=GkYD4PgIMaVL83ywfAsLBC9JNNDUpmTtbitW9zZSslk,131
372
- pulpcore/cache/cache.py,sha256=2fIr4chvKOQpDeIxw0Yl2-V2zMgcjOBWEZ6M2QOFrHA,17173
372
+ pulpcore/cache/cache.py,sha256=d8GMlvjeGG9MOMdi5_9029WpGCKH8Y5q9b2lt3wSREo,17371
373
373
  pulpcore/content/__init__.py,sha256=iDCr_SjoC8Y58sfSzx1-zU1l44fVrxOpekVALohezQM,3758
374
374
  pulpcore/content/authentication.py,sha256=lEZBkXBBBkIdtFMCSpHDD7583M0bO-zsZNYXTmpr4k8,3235
375
375
  pulpcore/content/entrypoint.py,sha256=fVqligooWVaW6ZZvNoj6TpCbb3AO5jtG9WXQL2kPXsU,1865
376
- pulpcore/content/handler.py,sha256=Od3BALbztHEzwUSSM8Bw-QLGprb79Wc1cXwUfk24MYo,55766
376
+ pulpcore/content/handler.py,sha256=_hPNpfbqMucXk3uGrb_PzzlWvZ6ptLhNj7XyOJxdxgY,56651
377
377
  pulpcore/content/instrumentation.py,sha256=H0N0GWzvOPGGjFi6eIbGW3mcvagfnAfazccTh-BZVmE,1426
378
378
  pulpcore/download/__init__.py,sha256=s3Wh2GKdsmbUooVIR6wSvhYVIhpaTbtfR3Ar1OJhC7s,154
379
379
  pulpcore/download/base.py,sha256=G8jgyowvVEFCGA_KTr0CtHn0qHWXKsnv4Xpi0KSMglM,12821
@@ -460,7 +460,7 @@ pulpcore/tests/functional/api/test_workers.py,sha256=u3oQnErjf6qPCg08XMRZzecGetL
460
460
  pulpcore/tests/functional/api/using_plugin/__init__.py,sha256=QyyfzgjLOi4n32G3o9aGH5eQDNjjD_qUpHLOZpPPZa4,80
461
461
  pulpcore/tests/functional/api/using_plugin/test_checkpoint.py,sha256=gx1oiHOVUH5QZfF33k_DXSw-AVbYQp39uKii1D96BoI,7965
462
462
  pulpcore/tests/functional/api/using_plugin/test_content_access.py,sha256=Ym800bU-M48RCDfQMkVa1UQt_sfgy5ciU0FxorCk9Ds,2551
463
- pulpcore/tests/functional/api/using_plugin/test_content_cache.py,sha256=J9uQgcAZ2gFRkHe0gpPfOLG4DoV1dr3tbgiaig3AILY,6475
463
+ pulpcore/tests/functional/api/using_plugin/test_content_cache.py,sha256=OB3gDbPDptQBjyYnr_jHyU9bcI_-ANAoUp9EDiskwug,7312
464
464
  pulpcore/tests/functional/api/using_plugin/test_content_delivery.py,sha256=sDYRqwZvOmDX6mc_UeVWI05CWm7nyNMPgeWf2r913i8,10549
465
465
  pulpcore/tests/functional/api/using_plugin/test_content_directory.py,sha256=w4uY258etnP8-LbrbZ_EZTolciYTt7cY1HJK9Ll7mS0,1931
466
466
  pulpcore/tests/functional/api/using_plugin/test_content_path.py,sha256=fvqeptqo-mrUAiKIjlypuvHG1XsFeKKP81ocTmo4hv0,3334
@@ -526,9 +526,9 @@ pulpcore/tests/unit/stages/test_artifactdownloader.py,sha256=qB1ANdFmNtUnljg8fCd
526
526
  pulpcore/tests/unit/stages/test_stages.py,sha256=H1a2BQLjdZlZvcb_qULp62huZ1xy6ItTcthktVyGU0w,4735
527
527
  pulpcore/tests/unit/viewsets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
528
528
  pulpcore/tests/unit/viewsets/test_viewset_base.py,sha256=W9o3V6758bZctR6krMPPQytb0xJuF-jb4uBWTNDoD_U,4837
529
- pulpcore-3.77.0.dist-info/licenses/LICENSE,sha256=dhnHU8rJXUdAIgIjveSKAyYG_KzN5eVG-bxETIGrNW0,17988
530
- pulpcore-3.77.0.dist-info/METADATA,sha256=KwDSPdPh-YRNIQvRh9sEpF7cyW7j3UiWEKTJaq5Fo_k,4260
531
- pulpcore-3.77.0.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
532
- pulpcore-3.77.0.dist-info/entry_points.txt,sha256=OZven4wzXzQA5b5q9MpP4HUpIPPQCSvIOvkKtNInrK0,452
533
- pulpcore-3.77.0.dist-info/top_level.txt,sha256=6h-Lm3FKQSaT_nL1KSxu_hBnzKE15bcvf_BoU-ea4CI,34
534
- pulpcore-3.77.0.dist-info/RECORD,,
529
+ pulpcore-3.77.1.dist-info/licenses/LICENSE,sha256=dhnHU8rJXUdAIgIjveSKAyYG_KzN5eVG-bxETIGrNW0,17988
530
+ pulpcore-3.77.1.dist-info/METADATA,sha256=5PbwCkEF0X97zbdXnPwJmL1f2cIxS-bfJCQ5WuG__k4,4260
531
+ pulpcore-3.77.1.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
532
+ pulpcore-3.77.1.dist-info/entry_points.txt,sha256=OZven4wzXzQA5b5q9MpP4HUpIPPQCSvIOvkKtNInrK0,452
533
+ pulpcore-3.77.1.dist-info/top_level.txt,sha256=6h-Lm3FKQSaT_nL1KSxu_hBnzKE15bcvf_BoU-ea4CI,34
534
+ pulpcore-3.77.1.dist-info/RECORD,,