pulpcore 3.80.2__py3-none-any.whl → 3.82.0__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.

Files changed (33) hide show
  1. pulp_certguard/app/__init__.py +1 -1
  2. pulp_file/app/__init__.py +1 -1
  3. pulp_file/pytest_plugin.py +22 -104
  4. pulp_file/tests/functional/api/test_bad_sync.py +62 -2
  5. pulpcore/app/apps.py +1 -1
  6. pulpcore/app/entrypoint.py +4 -1
  7. pulpcore/app/files.py +15 -5
  8. pulpcore/app/migrations/0132_task_profile_options.py +19 -0
  9. pulpcore/app/models/fields.py +2 -2
  10. pulpcore/app/models/task.py +1 -0
  11. pulpcore/app/netutil.py +20 -0
  12. pulpcore/app/replica.py +3 -9
  13. pulpcore/app/serializers/content.py +1 -1
  14. pulpcore/app/serializers/domain.py +1 -0
  15. pulpcore/app/serializers/fields.py +10 -0
  16. pulpcore/app/serializers/publication.py +4 -0
  17. pulpcore/app/settings.py +2 -0
  18. pulpcore/content/__init__.py +2 -1
  19. pulpcore/content/entrypoint.py +4 -1
  20. pulpcore/content/handler.py +14 -13
  21. pulpcore/download/base.py +9 -2
  22. pulpcore/middleware.py +25 -0
  23. pulpcore/openapi/__init__.py +13 -0
  24. pulpcore/tasking/_util.py +11 -6
  25. pulpcore/tasking/tasks.py +2 -0
  26. pulpcore/tests/functional/api/test_tasking.py +19 -0
  27. pulpcore/tests/functional/api/using_plugin/test_content_delivery.py +34 -0
  28. {pulpcore-3.80.2.dist-info → pulpcore-3.82.0.dist-info}/METADATA +22 -22
  29. {pulpcore-3.80.2.dist-info → pulpcore-3.82.0.dist-info}/RECORD +33 -31
  30. {pulpcore-3.80.2.dist-info → pulpcore-3.82.0.dist-info}/WHEEL +0 -0
  31. {pulpcore-3.80.2.dist-info → pulpcore-3.82.0.dist-info}/entry_points.txt +0 -0
  32. {pulpcore-3.80.2.dist-info → pulpcore-3.82.0.dist-info}/licenses/LICENSE +0 -0
  33. {pulpcore-3.80.2.dist-info → pulpcore-3.82.0.dist-info}/top_level.txt +0 -0
@@ -6,6 +6,6 @@ class PulpCertGuardPluginAppConfig(PulpPluginAppConfig):
6
6
 
7
7
  name = "pulp_certguard.app"
8
8
  label = "certguard"
9
- version = "3.80.2"
9
+ version = "3.82.0"
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.80.2"
11
+ version = "3.82.0"
12
12
  python_package_name = "pulpcore"
13
13
  domain_compatible = True
@@ -1,12 +1,7 @@
1
1
  import os
2
2
  import uuid
3
- import subprocess
4
- from collections import defaultdict
5
- from pathlib import Path
6
3
 
7
- import aiofiles
8
4
  import pytest
9
- from aiohttp import web
10
5
 
11
6
  from pulpcore.tests.functional.utils import BindingsNamespace, generate_iso, generate_manifest
12
7
 
@@ -37,9 +32,9 @@ def file_random_content_unit(file_content_unit_with_name_factory):
37
32
 
38
33
 
39
34
  @pytest.fixture
40
- def file_content_unit_with_name_factory(file_bindings, random_artifact, monitor_task):
35
+ def file_content_unit_with_name_factory(file_bindings, random_artifact_factory, monitor_task):
41
36
  def _file_content_unit_with_name_factory(name):
42
- artifact_attrs = {"artifact": random_artifact.pulp_href, "relative_path": name}
37
+ artifact_attrs = {"artifact": random_artifact_factory().pulp_href, "relative_path": name}
43
38
  return file_bindings.ContentFilesApi.read(
44
39
  monitor_task(
45
40
  file_bindings.ContentFilesApi.create(**artifact_attrs).task
@@ -74,14 +69,13 @@ def file_distribution_factory(file_bindings, gen_object_with_cleanup):
74
69
  return _file_distribution_factory
75
70
 
76
71
 
77
- @pytest.fixture
78
- def file_fixtures_root(tmp_path):
79
- fixture_dir = tmp_path / "fixtures"
80
- fixture_dir.mkdir()
72
+ @pytest.fixture(scope="class")
73
+ def file_fixtures_root(tmp_path_factory):
74
+ fixture_dir = tmp_path_factory.mktemp("fixtures")
81
75
  return fixture_dir
82
76
 
83
77
 
84
- @pytest.fixture
78
+ @pytest.fixture(scope="class")
85
79
  def write_3_iso_file_fixture_data_factory(file_fixtures_root):
86
80
  def _write_3_iso_file_fixture_data_factory(name, overwrite=False, seed=None):
87
81
  file_fixtures_root.joinpath(name).mkdir(exist_ok=overwrite)
@@ -96,12 +90,12 @@ def write_3_iso_file_fixture_data_factory(file_fixtures_root):
96
90
  return _write_3_iso_file_fixture_data_factory
97
91
 
98
92
 
99
- @pytest.fixture
93
+ @pytest.fixture(scope="class")
100
94
  def basic_manifest_path(write_3_iso_file_fixture_data_factory):
101
95
  return write_3_iso_file_fixture_data_factory("basic")
102
96
 
103
97
 
104
- @pytest.fixture
98
+ @pytest.fixture(scope="class")
105
99
  def copy_manifest_only_factory(file_fixtures_root):
106
100
  def _copy_manifest_only(name):
107
101
  file_fixtures_root.joinpath(f"{name}-manifest").mkdir()
@@ -114,12 +108,12 @@ def copy_manifest_only_factory(file_fixtures_root):
114
108
  return _copy_manifest_only
115
109
 
116
110
 
117
- @pytest.fixture
111
+ @pytest.fixture(scope="class")
118
112
  def basic_manifest_only_path(copy_manifest_only_factory):
119
113
  return copy_manifest_only_factory("basic")
120
114
 
121
115
 
122
- @pytest.fixture
116
+ @pytest.fixture(scope="class")
123
117
  def large_manifest_path(file_fixtures_root):
124
118
  one_megabyte = 1048576
125
119
  file_fixtures_root.joinpath("large").mkdir()
@@ -128,7 +122,7 @@ def large_manifest_path(file_fixtures_root):
128
122
  return "/large/PULP_MANIFEST"
129
123
 
130
124
 
131
- @pytest.fixture
125
+ @pytest.fixture(scope="class")
132
126
  def range_header_manifest_path(file_fixtures_root):
133
127
  """A path to a File repository manifest that contains 8 unique files each 4mb in size."""
134
128
  one_megabyte = 1048576
@@ -147,7 +141,7 @@ def range_header_manifest_path(file_fixtures_root):
147
141
  return "/range/PULP_MANIFEST"
148
142
 
149
143
 
150
- @pytest.fixture
144
+ @pytest.fixture(scope="class")
151
145
  def manifest_path_with_commas(file_fixtures_root):
152
146
  file_fixtures_root.joinpath("comma_test").mkdir()
153
147
  file_fixtures_root.joinpath("comma_test/comma,folder").mkdir()
@@ -161,15 +155,15 @@ def manifest_path_with_commas(file_fixtures_root):
161
155
  return "/comma_test/PULP_MANIFEST"
162
156
 
163
157
 
164
- @pytest.fixture
158
+ @pytest.fixture(scope="class")
165
159
  def invalid_manifest_path(file_fixtures_root, basic_manifest_path):
166
- file_path_to_corrupt = file_fixtures_root / Path("basic/1.iso")
160
+ file_path_to_corrupt = file_fixtures_root / "basic/1.iso"
167
161
  with open(file_path_to_corrupt, "w") as f:
168
162
  f.write("this is not the right data")
169
163
  return basic_manifest_path
170
164
 
171
165
 
172
- @pytest.fixture
166
+ @pytest.fixture(scope="class")
173
167
  def duplicate_filename_paths(write_3_iso_file_fixture_data_factory):
174
168
  return (
175
169
  write_3_iso_file_fixture_data_factory("file"),
@@ -177,24 +171,24 @@ def duplicate_filename_paths(write_3_iso_file_fixture_data_factory):
177
171
  )
178
172
 
179
173
 
180
- @pytest.fixture
174
+ @pytest.fixture(scope="class")
181
175
  def file_fixture_server_ssl_client_cert_req(
182
176
  ssl_ctx_req_client_auth, file_fixtures_root, gen_fixture_server
183
177
  ):
184
178
  return gen_fixture_server(file_fixtures_root, ssl_ctx_req_client_auth)
185
179
 
186
180
 
187
- @pytest.fixture
181
+ @pytest.fixture(scope="class")
188
182
  def file_fixture_server_ssl(ssl_ctx, file_fixtures_root, gen_fixture_server):
189
183
  return gen_fixture_server(file_fixtures_root, ssl_ctx)
190
184
 
191
185
 
192
- @pytest.fixture
186
+ @pytest.fixture(scope="class")
193
187
  def file_fixture_server(file_fixtures_root, gen_fixture_server):
194
188
  return gen_fixture_server(file_fixtures_root, None)
195
189
 
196
190
 
197
- @pytest.fixture
191
+ @pytest.fixture(scope="class")
198
192
  def file_remote_factory(file_fixture_server, file_bindings, gen_object_with_cleanup):
199
193
  def _file_remote_factory(
200
194
  manifest_path=None, url=None, policy="immediate", pulp_domain=None, **body
@@ -213,7 +207,7 @@ def file_remote_factory(file_fixture_server, file_bindings, gen_object_with_clea
213
207
  return _file_remote_factory
214
208
 
215
209
 
216
- @pytest.fixture
210
+ @pytest.fixture(scope="class")
217
211
  def file_remote_ssl_factory(
218
212
  file_fixture_server_ssl,
219
213
  file_bindings,
@@ -235,7 +229,7 @@ def file_remote_ssl_factory(
235
229
  return _file_remote_ssl_factory
236
230
 
237
231
 
238
- @pytest.fixture
232
+ @pytest.fixture(scope="class")
239
233
  def file_remote_client_cert_req_factory(
240
234
  file_fixture_server_ssl_client_cert_req,
241
235
  file_bindings,
@@ -290,83 +284,7 @@ def file_publication_factory(file_bindings, gen_object_with_cleanup):
290
284
  return _file_publication_factory
291
285
 
292
286
 
293
- @pytest.fixture
294
- def gen_bad_response_fixture_server(gen_threaded_aiohttp_server):
295
- """
296
- This server will perform 3 bad responses for each file requested.
297
-
298
- 1st response will be incomplete, sending only half of the data.
299
- 2nd response will have corrupted data, with one byte changed.
300
- 3rd response will return error 429.
301
- 4th response will be correct.
302
- """
303
-
304
- def _gen_fixture_server(fixtures_root, ssl_ctx):
305
- record = []
306
- num_requests = defaultdict(int)
307
-
308
- async def handler(request):
309
- nonlocal num_requests
310
- record.append(request)
311
- relative_path = request.raw_path[1:] # Strip off leading "/"
312
- file_path = Path(fixtures_root) / Path(relative_path)
313
- # Max retries is 3. So on fourth request, send full data
314
- num_requests[relative_path] += 1
315
- if "PULP_MANIFEST" in relative_path or num_requests[relative_path] % 4 == 0:
316
- return web.FileResponse(file_path)
317
-
318
- # On third request send 429 error, TooManyRequests
319
- if num_requests[relative_path] % 4 == 3:
320
- raise web.HTTPTooManyRequests
321
-
322
- size = file_path.stat().st_size
323
- response = web.StreamResponse(headers={"content-length": f"{size}"})
324
- await response.prepare(request)
325
- async with aiofiles.open(file_path, "rb") as f:
326
- # Send only partial content causing aiohttp.ClientPayloadError if request num == 1
327
- chunk = await f.read(size // 2)
328
- await response.write(chunk)
329
- # Send last chunk with modified last byte if request num == 2
330
- if num_requests[relative_path] % 4 == 2:
331
- chunk2 = await f.read()
332
- await response.write(chunk2[:-1])
333
- await response.write(bytes([chunk2[-1] ^ 1]))
334
- else:
335
- request.transport.close()
336
-
337
- return response
338
-
339
- app = web.Application()
340
- app.add_routes([web.get("/{tail:.*}", handler)])
341
- return gen_threaded_aiohttp_server(app, ssl_ctx, record)
342
-
343
- return _gen_fixture_server
344
-
345
-
346
- @pytest.fixture
347
- def bad_response_fixture_server(file_fixtures_root, gen_bad_response_fixture_server):
348
- return gen_bad_response_fixture_server(file_fixtures_root, None)
349
-
350
-
351
- @pytest.fixture
352
- def wget_recursive_download_on_host():
353
- def _wget_recursive_download_on_host(url, destination):
354
- subprocess.check_output(
355
- [
356
- "wget",
357
- "--recursive",
358
- "--no-parent",
359
- "--no-host-directories",
360
- "--directory-prefix",
361
- destination,
362
- url,
363
- ]
364
- )
365
-
366
- return _wget_recursive_download_on_host
367
-
368
-
369
- @pytest.fixture
287
+ @pytest.fixture(scope="class")
370
288
  def generate_server_and_remote(
371
289
  file_bindings, gen_fixture_server, file_fixtures_root, gen_object_with_cleanup
372
290
  ):
@@ -1,7 +1,9 @@
1
+ from collections import defaultdict
2
+
1
3
  import pytest
2
4
  import uuid
3
-
4
- from collections import defaultdict
5
+ import aiofiles
6
+ from aiohttp import web
5
7
 
6
8
  from pulpcore.client.pulp_file import RepositorySyncURL
7
9
 
@@ -28,6 +30,64 @@ def perform_sync(
28
30
  yield _perform_sync
29
31
 
30
32
 
33
+ @pytest.fixture(scope="class")
34
+ def gen_bad_response_fixture_server(gen_threaded_aiohttp_server):
35
+ """
36
+ This server will perform 3 bad responses for each file requested.
37
+
38
+ 1st response will be incomplete, sending only half of the data.
39
+ 2nd response will have corrupted data, with one byte changed.
40
+ 3rd response will return error 429.
41
+ 4th response will be correct.
42
+ """
43
+
44
+ def _gen_fixture_server(fixtures_root, ssl_ctx):
45
+ record = []
46
+ num_requests = defaultdict(int)
47
+
48
+ async def handler(request):
49
+ nonlocal num_requests
50
+ record.append(request)
51
+ relative_path = request.raw_path[1:] # Strip off leading "/"
52
+ file_path = fixtures_root / relative_path
53
+ # Max retries is 3. So on fourth request, send full data
54
+ num_requests[relative_path] += 1
55
+ if "PULP_MANIFEST" in relative_path or num_requests[relative_path] % 4 == 0:
56
+ return web.FileResponse(file_path)
57
+
58
+ # On third request send 429 error, TooManyRequests
59
+ if num_requests[relative_path] % 4 == 3:
60
+ raise web.HTTPTooManyRequests
61
+
62
+ size = file_path.stat().st_size
63
+ response = web.StreamResponse(headers={"content-length": f"{size}"})
64
+ await response.prepare(request)
65
+ async with aiofiles.open(file_path, "rb") as f:
66
+ # Send only partial content causing aiohttp.ClientPayloadError if request num == 1
67
+ chunk = await f.read(size // 2)
68
+ await response.write(chunk)
69
+ # Send last chunk with modified last byte if request num == 2
70
+ if num_requests[relative_path] % 4 == 2:
71
+ chunk2 = await f.read()
72
+ await response.write(chunk2[:-1])
73
+ await response.write(bytes([chunk2[-1] ^ 1]))
74
+ else:
75
+ request.transport.close()
76
+
77
+ return response
78
+
79
+ app = web.Application()
80
+ app.add_routes([web.get("/{tail:.*}", handler)])
81
+ return gen_threaded_aiohttp_server(app, ssl_ctx, record)
82
+
83
+ return _gen_fixture_server
84
+
85
+
86
+ @pytest.fixture(scope="class")
87
+ def bad_response_fixture_server(file_fixtures_root, gen_bad_response_fixture_server):
88
+ return gen_bad_response_fixture_server(file_fixtures_root, None)
89
+
90
+
31
91
  @pytest.mark.parallel
32
92
  def test_bad_response_retry(bad_response_fixture_server, large_manifest_path, perform_sync):
33
93
  """
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.80.2"
250
+ version = "3.82.0"
251
251
 
252
252
  # The python package name providing this app
253
253
  python_package_name = "pulpcore"
@@ -11,6 +11,7 @@ from django.db.utils import InterfaceError, DatabaseError
11
11
  from gunicorn.workers.sync import SyncWorker
12
12
 
13
13
  from pulpcore.app.apps import pulp_plugin_configs
14
+ from pulpcore.app.netutil import has_ipv6
14
15
  from pulpcore.app.pulpcore_gunicorn_application import PulpcoreGunicornApplication
15
16
 
16
17
  logger = getLogger(__name__)
@@ -102,7 +103,9 @@ class PulpcoreApiApplication(PulpcoreGunicornApplication):
102
103
  # https://github.com/benoitc/gunicorn/blob/master/gunicorn/config.py
103
104
 
104
105
 
105
- @click.option("--bind", "-b", default=["[::]:24817"], multiple=True)
106
+ @click.option(
107
+ "--bind", "-b", default=[f"{ '[::]' if has_ipv6() else '0.0.0.0' }:24817"], multiple=True
108
+ )
106
109
  @click.option("--workers", "-w", type=int)
107
110
  # @click.option("--threads", "-w", type=int) # We don't use a threaded worker...
108
111
  @click.option("--name", "-n", "proc_name")
pulpcore/app/files.py CHANGED
@@ -1,4 +1,6 @@
1
1
  import os
2
+ import concurrent.futures
3
+ from concurrent.futures import ThreadPoolExecutor, ALL_COMPLETED
2
4
  from gettext import gettext as _
3
5
 
4
6
  from django.core.files.uploadedfile import TemporaryUploadedFile
@@ -39,9 +41,13 @@ class PulpTemporaryUploadedFile(TemporaryUploadedFile):
39
41
  instance = cls(name, "", size, "", "")
40
42
  instance.file = file
41
43
  # Default 1MB
42
- while data := file.read(1048576):
43
- for hasher in models.Artifact.DIGEST_FIELDS:
44
- instance.hashers[hasher].update(data)
44
+ with ThreadPoolExecutor(max_workers=6) as executor:
45
+ while data := file.read(1048576):
46
+ futures = [
47
+ executor.submit(instance.hashers[hasher].update, data)
48
+ for hasher in models.Artifact.DIGEST_FIELDS
49
+ ]
50
+ concurrent.futures.wait(futures, timeout=None, return_when=ALL_COMPLETED)
45
51
 
46
52
  # calling the method read() moves the file's pointer to the end of the file object,
47
53
  # thus, it is necessary to reset the file's pointer position back to 0 in case of
@@ -82,11 +88,15 @@ class HashingFileUploadHandler(TemporaryFileUploadHandler):
82
88
  self.file = PulpTemporaryUploadedFile(
83
89
  file_name, content_type, 0, charset, content_type_extra
84
90
  )
91
+ self.threadpool = ThreadPoolExecutor(max_workers=6)
85
92
 
86
93
  def receive_data_chunk(self, raw_data, start):
94
+ futures = [
95
+ self.threadpool.submit(self.file.hashers[hasher].update, raw_data)
96
+ for hasher in models.Artifact.DIGEST_FIELDS
97
+ ]
87
98
  self.file.write(raw_data)
88
- for hasher in models.Artifact.DIGEST_FIELDS:
89
- self.file.hashers[hasher].update(raw_data)
99
+ concurrent.futures.wait(futures, timeout=None, return_when=ALL_COMPLETED)
90
100
 
91
101
 
92
102
  class TemporaryDownloadedFile(TemporaryUploadedFile):
@@ -0,0 +1,19 @@
1
+ # Generated by Django 4.2.10 on 2025-06-26 19:44
2
+
3
+ import django.contrib.postgres.fields
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('core', '0131_distribution_checkpoint_publication_checkpoint'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AddField(
15
+ model_name='task',
16
+ name='profile_options',
17
+ field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), null=True, size=None),
18
+ ),
19
+ ]
@@ -90,7 +90,7 @@ class ArtifactFileField(FileField):
90
90
 
91
91
 
92
92
  class EncryptedTextField(TextField):
93
- """A field mixin that encrypts text using settings.DB_ENCRYPTION_KEY."""
93
+ """A field that encrypts text using settings.DB_ENCRYPTION_KEY."""
94
94
 
95
95
  def __init__(self, *args, **kwargs):
96
96
  if kwargs.get("primary_key"):
@@ -114,7 +114,7 @@ class EncryptedTextField(TextField):
114
114
 
115
115
 
116
116
  class EncryptedJSONField(JSONField):
117
- """A Field mixin that encrypts the JSON text using settings.DP_ENCRYPTION_KEY."""
117
+ """A Field that encrypts the JSON text using settings.DP_ENCRYPTION_KEY."""
118
118
 
119
119
  def __init__(self, *args, **kwargs):
120
120
  if kwargs.get("primary_key"):
@@ -147,6 +147,7 @@ class Task(BaseModel, AutoAddObjPermsMixin):
147
147
  pulp_domain = models.ForeignKey("Domain", default=get_domain_pk, on_delete=models.CASCADE)
148
148
  versions = HStoreField(default=dict)
149
149
 
150
+ profile_options = ArrayField(models.TextField(), null=True)
150
151
  profile_artifacts = models.ManyToManyField("Artifact", through=ProfileArtifact)
151
152
 
152
153
  immediate = models.BooleanField(default=False, null=True)
@@ -0,0 +1,20 @@
1
+ """
2
+ network utility functions
3
+ """
4
+
5
+ import socket
6
+
7
+
8
+ def has_ipv6():
9
+ """
10
+ check if host can use IPv6
11
+ """
12
+ # if python has IPv6 support we need to check if we can bind an IPv6 socket
13
+ if socket.has_ipv6:
14
+ try:
15
+ with socket.socket(socket.AF_INET6) as sock:
16
+ sock.bind(("::1", 0))
17
+ return True
18
+ except OSError:
19
+ pass
20
+ return False
pulpcore/app/replica.py CHANGED
@@ -90,15 +90,9 @@ class Replicator:
90
90
  params = {"q": q}
91
91
  else:
92
92
  params = {}
93
- offset = 0
94
- list_size = 100
95
- while True:
96
- distributions = self.distribution_ctx_cls(self.pulp_ctx).list(list_size, offset, params)
97
- for distro in distributions:
98
- yield distro
99
- if len(distributions) < list_size:
100
- break
101
- offset += list_size
93
+ yield from self.distribution_ctx_cls(self.pulp_ctx).list_iterator(
94
+ parameters=params, batch_size=100
95
+ )
102
96
 
103
97
  def labels(self, upstream_object):
104
98
  upstream_labels = getattr(upstream_object, "pulp_labels", {})
@@ -11,7 +11,7 @@ from pulpcore.app.util import get_domain
11
11
 
12
12
  class NoArtifactContentSerializer(base.ModelSerializer):
13
13
  pulp_href = base.DetailIdentityField(view_name_pattern=r"contents(-.*/.*)-detail")
14
- pulp_labels = serializers.HStoreField(
14
+ pulp_labels = fields.PulpLabelsField(
15
15
  help_text=_(
16
16
  "A dictionary of arbitrary key/value pairs used to describe a specific "
17
17
  "Content instance."
@@ -342,6 +342,7 @@ class StorageSettingsSerializer(serializers.Serializer):
342
342
  STORAGE_MAPPING = {
343
343
  "pulpcore.app.models.storage.FileSystem": FileSystemSettingsSerializer,
344
344
  "pulpcore.app.models.storage.PulpSFTPStorage": SFTPSettingsSerializer,
345
+ "storages.backends.s3.S3Storage": AmazonS3SettingsSerializer,
345
346
  "storages.backends.s3boto3.S3Boto3Storage": AmazonS3SettingsSerializer,
346
347
  "storages.backends.azure_storage.AzureStorage": AzureSettingsSerializer,
347
348
  "storages.backends.gcloud.GoogleCloudStorage": GoogleSettingsSerializer,
@@ -435,3 +435,13 @@ def pulp_labels_validator(value):
435
435
  )
436
436
 
437
437
  return value
438
+
439
+
440
+ class PulpLabelsField(serializers.HStoreField):
441
+ """
442
+ Custom field for handling pulp labels that ensures proper dictionary format.
443
+ Converts JSON strings to dictionaries during validation.
444
+ """
445
+
446
+ def get_value(self, dictionary):
447
+ return dictionary.get(self.field_name, empty)
@@ -78,6 +78,10 @@ class PublicationSerializer(ModelSerializer):
78
78
 
79
79
 
80
80
  class ContentGuardSerializer(ModelSerializer):
81
+ """
82
+ Base class for content guard serializers.
83
+ """
84
+
81
85
  pulp_href = DetailIdentityField(view_name_pattern=r"contentguards(-.*/.*)-detail")
82
86
 
83
87
  name = serializers.CharField(
pulpcore/app/settings.py CHANGED
@@ -173,6 +173,7 @@ MIDDLEWARE = [
173
173
  "django.middleware.clickjacking.XFrameOptionsMiddleware",
174
174
  "pulpcore.middleware.DomainMiddleware",
175
175
  "pulpcore.middleware.APIRootRewriteMiddleware",
176
+ "pulpcore.middleware.TaskProfilerMiddleware",
176
177
  ]
177
178
 
178
179
  AUTHENTICATION_BACKENDS = [
@@ -436,6 +437,7 @@ storage_validator = (
436
437
  Validator("REDIRECT_TO_OBJECT_STORAGE", eq=False)
437
438
  | Validator(*storage_keys, eq="pulpcore.app.models.storage.FileSystem")
438
439
  | Validator(*storage_keys, eq="storages.backends.azure_storage.AzureStorage")
440
+ | Validator(*storage_keys, eq="storages.backends.s3.S3Storage")
439
441
  | Validator(*storage_keys, eq="storages.backends.s3boto3.S3Boto3Storage")
440
442
  | Validator(*storage_keys, eq="storages.backends.gcloud.GoogleCloudStorage")
441
443
  )
@@ -25,13 +25,14 @@ from pulpcore.app.models import ContentAppStatus # noqa: E402: module level not
25
25
  from pulpcore.app.util import get_worker_name # noqa: E402: module level not at top of file
26
26
 
27
27
  from .handler import Handler # noqa: E402: module level not at top of file
28
- from .instrumentation import instrumentation # noqa: E402: module level not at top of file
29
28
  from .authentication import authenticate, guid # noqa: E402: module level not at top of file
30
29
 
31
30
 
32
31
  log = logging.getLogger(__name__)
33
32
 
34
33
  if settings.OTEL_ENABLED:
34
+ from .instrumentation import instrumentation # noqa: E402: module level not at top of file
35
+
35
36
  app = web.Application(middlewares=[guid, authenticate, instrumentation()])
36
37
  else:
37
38
  app = web.Application(middlewares=[guid, authenticate])
@@ -1,4 +1,5 @@
1
1
  import click
2
+ from pulpcore.app.netutil import has_ipv6
2
3
  from pulpcore.app.pulpcore_gunicorn_application import PulpcoreGunicornApplication
3
4
  from django.conf import settings
4
5
 
@@ -19,7 +20,9 @@ class PulpcoreContentApplication(PulpcoreGunicornApplication):
19
20
  return pulpcore.content.server
20
21
 
21
22
 
22
- @click.option("--bind", "-b", default=["[::]:24816"], multiple=True)
23
+ @click.option(
24
+ "--bind", "-b", default=[f"{ '[::]' if has_ipv6() else '0.0.0.0' }:24816"], multiple=True
25
+ )
23
26
  @click.option("--workers", "-w", type=int)
24
27
  # @click.option("--threads", "-w", type=int) # We don't use a threaded worker...
25
28
  @click.option("--name", "-n", "proc_name")
@@ -1279,19 +1279,20 @@ class Handler:
1279
1279
  # "backstop" the prepare() call here, so the write() will be allowed.
1280
1280
  if not response.prepared:
1281
1281
  await response.prepare(request)
1282
- if range_start or range_stop:
1283
- start_byte_pos = 0
1284
- end_byte_pos = len(data)
1285
- if range_start:
1286
- start_byte_pos = max(0, range_start - data_size_handled)
1287
- if range_stop:
1288
- end_byte_pos = min(len(data), range_stop - data_size_handled)
1289
-
1290
- data_for_client = data[start_byte_pos:end_byte_pos]
1291
- await response.write(data_for_client)
1292
- data_size_handled = data_size_handled + len(data)
1293
- else:
1294
- await response.write(data)
1282
+ if request.method == "GET":
1283
+ if range_start or range_stop:
1284
+ start_byte_pos = 0
1285
+ end_byte_pos = len(data)
1286
+ if range_start:
1287
+ start_byte_pos = max(0, range_start - data_size_handled)
1288
+ if range_stop:
1289
+ end_byte_pos = min(len(data), range_stop - data_size_handled)
1290
+
1291
+ data_for_client = data[start_byte_pos:end_byte_pos]
1292
+ await response.write(data_for_client)
1293
+ data_size_handled = data_size_handled + len(data)
1294
+ else:
1295
+ await response.write(data)
1295
1296
  if remote.policy != Remote.STREAMED:
1296
1297
  await original_handle_data(data)
1297
1298
 
pulpcore/download/base.py CHANGED
@@ -2,6 +2,8 @@ from gettext import gettext as _
2
2
 
3
3
  import asyncio
4
4
  from collections import namedtuple
5
+ import concurrent.futures
6
+ from concurrent.futures import ThreadPoolExecutor, ALL_COMPLETED
5
7
  import logging
6
8
  import os
7
9
  import tempfile
@@ -34,6 +36,8 @@ Args:
34
36
  values are header content. None when not using the HttpDownloader or sublclass.
35
37
  """
36
38
 
39
+ THREADPOOL = ThreadPoolExecutor()
40
+
37
41
 
38
42
  class BaseDownloader:
39
43
  """
@@ -200,8 +204,11 @@ class BaseDownloader:
200
204
  Args:
201
205
  data (bytes): The data to have its size and digest values recorded.
202
206
  """
203
- for algorithm in self._digests.values():
204
- algorithm.update(data)
207
+ global THREADPOOL
208
+ futures = [
209
+ THREADPOOL.submit(algorithm.update, data) for algorithm in self._digests.values()
210
+ ]
211
+ concurrent.futures.wait(futures, timeout=None, return_when=ALL_COMPLETED)
205
212
  self._size += len(data)
206
213
 
207
214
  @property
pulpcore/middleware.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import time
2
+ from contextvars import ContextVar
2
3
 
3
4
  from django.http.response import Http404
4
5
  from django.conf import settings
@@ -13,6 +14,8 @@ from pulpcore.app.util import (
13
14
  set_domain,
14
15
  )
15
16
 
17
+ x_task_diagnostics_var = ContextVar("x_profile_task")
18
+
16
19
 
17
20
  class DomainMiddleware:
18
21
  """
@@ -143,3 +146,25 @@ class DjangoMetricsMiddleware:
143
146
  match = getattr(request, "resolver_match", "")
144
147
  route = getattr(match, "route", "")
145
148
  return route
149
+
150
+
151
+ class TaskProfilerMiddleware:
152
+ """
153
+ Middleware that looks for the presence of X-TASK-DIAGNOSTICS header and provides its value
154
+ as a ContextVar to the dispatch() method in the tasking system. It enables generating
155
+ profiling data of tasks dispatched via API.
156
+ """
157
+
158
+ def __init__(self, get_response):
159
+ self.get_response = get_response
160
+
161
+ def __call__(self, request):
162
+ if "HTTP_X_TASK_DIAGNOSTICS" in request.META:
163
+ task_diagnostics = request.META["HTTP_X_TASK_DIAGNOSTICS"]
164
+ ctx_token = x_task_diagnostics_var.set(task_diagnostics.split(","))
165
+ try:
166
+ return self.get_response(request)
167
+ finally:
168
+ x_task_diagnostics_var.reset(ctx_token)
169
+ else:
170
+ return self.get_response(request)
@@ -201,6 +201,19 @@ class PulpAutoSchema(AutoSchema):
201
201
  name = name + "Response"
202
202
  return name
203
203
 
204
+ def get_override_parameters(self):
205
+ parameters = super().get_override_parameters()
206
+ parameters.append(
207
+ OpenApiParameter(
208
+ name="X-Task-Diagnostics",
209
+ location=OpenApiParameter.HEADER,
210
+ required=False,
211
+ type={"type": "array", "items": {"type": "string"}},
212
+ description="List of profilers to use on tasks.",
213
+ )
214
+ )
215
+ return parameters
216
+
204
217
  def map_parsers(self):
205
218
  """
206
219
  Get request parsers.
pulpcore/tasking/_util.py CHANGED
@@ -127,21 +127,26 @@ def perform_task(task_pk, task_working_dir_rel_path):
127
127
  set_domain(task.pulp_domain)
128
128
  os.chdir(task_working_dir_rel_path)
129
129
 
130
- if settings.TASK_DIAGNOSTICS:
131
- _execute_task_and_profile(task)
130
+ if task.profile_options:
131
+ profilers = set(task.profile_options) & set(settings.TASK_DIAGNOSTICS)
132
+ if unavailable_profilers := set(task.profile_options) - set(settings.TASK_DIAGNOSTICS):
133
+ _logger.warning(
134
+ "Requested task diagnostic profilers are not available: %s", unavailable_profilers
135
+ )
136
+ _execute_task_and_profile(task, profilers)
132
137
  else:
133
138
  execute_task(task)
134
139
 
135
140
 
136
- def _execute_task_and_profile(task):
141
+ def _execute_task_and_profile(task, profile_options):
137
142
  with tempfile.TemporaryDirectory(dir=settings.WORKING_DIRECTORY) as temp_dir:
138
143
  _execute_task = execute_task
139
144
 
140
- if settings.TASK_DIAGNOSTICS is True or "memory" in settings.TASK_DIAGNOSTICS:
145
+ if "memory" in profile_options:
141
146
  _execute_task = _memory_diagnostic_decorator(temp_dir, _execute_task)
142
- if settings.TASK_DIAGNOSTICS is True or "pyinstrument" in settings.TASK_DIAGNOSTICS:
147
+ if "pyinstrument" in profile_options:
143
148
  _execute_task = _pyinstrument_diagnostic_decorator(temp_dir, _execute_task)
144
- if settings.TASK_DIAGNOSTICS is True or "memray" in settings.TASK_DIAGNOSTICS:
149
+ if "memray" in profile_options:
145
150
  _execute_task = _memray_diagnostic_decorator(temp_dir, _execute_task)
146
151
 
147
152
  _execute_task(task)
pulpcore/tasking/tasks.py CHANGED
@@ -26,6 +26,7 @@ from pulpcore.constants import (
26
26
  TASK_DISPATCH_LOCK,
27
27
  IMMEDIATE_TIMEOUT,
28
28
  )
29
+ from pulpcore.middleware import x_task_diagnostics_var
29
30
  from pulpcore.tasking.kafka import send_task_notification
30
31
 
31
32
  _logger = logging.getLogger(__name__)
@@ -246,6 +247,7 @@ def dispatch(
246
247
  versions=versions,
247
248
  immediate=immediate,
248
249
  deferred=deferred,
250
+ profile_options=x_task_diagnostics_var.get(None),
249
251
  )
250
252
  if newest_created and task.pulp_created <= newest_created:
251
253
  # Let this workaround not row forever into the future.
@@ -33,6 +33,25 @@ def test_retrieving_task_profile_artifacts(gen_user, pulpcore_bindings, task):
33
33
  assert pulpcore_bindings.TasksApi.profile_artifacts(task.pulp_href).urls is not None
34
34
 
35
35
 
36
+ @pytest.mark.parallel
37
+ def test_profiling_task_using_header(gen_user, pulpcore_bindings, monitor_task, pulp_settings):
38
+ # Check that no profile artifacts are created by default
39
+ task_href = pulpcore_bindings.OrphansCleanupApi.cleanup({"orphan_protection_time": 10000}).task
40
+ task = monitor_task(task_href)
41
+ assert pulpcore_bindings.TasksApi.profile_artifacts(task.pulp_href).urls == {}
42
+
43
+ # Check that profile artifacts are created when X-TASK-DIAGNOSTICS headers is passed
44
+ task_href = pulpcore_bindings.OrphansCleanupApi.cleanup(
45
+ {"orphan_protection_time": 10000}, x_task_diagnostics=["memory"]
46
+ ).task
47
+ task = monitor_task(task_href)
48
+ profile_artifacts_urls = pulpcore_bindings.TasksApi.profile_artifacts(task.pulp_href).urls
49
+ if "memory" in pulp_settings.TASK_DIAGNOSTICS:
50
+ assert "memory_profile" in profile_artifacts_urls
51
+ else:
52
+ assert "memory_profile" not in profile_artifacts_urls
53
+
54
+
36
55
  @pytest.mark.parallel
37
56
  def test_multi_resource_locking(dispatch_task, monitor_task):
38
57
  task_href1 = dispatch_task(
@@ -1,8 +1,10 @@
1
1
  """Tests related to content delivery."""
2
2
 
3
3
  import hashlib
4
+ import requests
4
5
  import subprocess
5
6
  import uuid
7
+ from random import sample
6
8
  from urllib.parse import urljoin
7
9
 
8
10
  import pytest
@@ -244,3 +246,35 @@ def test_handling_remote_artifact_on_demand_streaming_failure(
244
246
  # WHEN/THEN (second request)
245
247
  actual_checksum = download_from_distribution(content_name, distribution)
246
248
  assert actual_checksum == expected_checksum
249
+
250
+
251
+ @pytest.mark.parallel
252
+ def test_head_request_large_on_demand_file(
253
+ file_repo_with_auto_publish,
254
+ file_remote_factory,
255
+ file_bindings,
256
+ range_header_manifest_path,
257
+ distribution_base_url,
258
+ file_distribution_factory,
259
+ monitor_task,
260
+ ):
261
+ """Test that a HEAD request to a large on-demand file properly saves the file."""
262
+ # range_header_manifest_path has 8 files, each 4MB
263
+ remote = file_remote_factory(manifest_path=range_header_manifest_path, policy="on_demand")
264
+ body = RepositorySyncURL(remote=remote.pulp_href)
265
+ monitor_task(
266
+ file_bindings.RepositoriesFileApi.sync(file_repo_with_auto_publish.pulp_href, body).task
267
+ )
268
+ repo = file_bindings.RepositoriesFileApi.read(file_repo_with_auto_publish.pulp_href)
269
+ content = file_bindings.ContentFilesApi.list(repository_version=repo.latest_version_href)
270
+ content_href_filenames = sample([(c.pulp_href, c.relative_path) for c in content.results], k=3)
271
+
272
+ distro = file_distribution_factory(repository=repo.pulp_href)
273
+ for _, content_filename in content_href_filenames:
274
+ url = urljoin(distribution_base_url(distro.base_url), content_filename)
275
+ response = requests.head(url)
276
+ assert response.status_code == 200
277
+ # Give some time for the file to be saved
278
+ for content_href, _ in content_href_filenames:
279
+ content = file_bindings.ContentFilesApi.read(content_href)
280
+ assert content.artifact is not None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulpcore
3
- Version: 3.80.2
3
+ Version: 3.82.0
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
@@ -21,17 +21,17 @@ Classifier: Programming Language :: Python :: 3.12
21
21
  Requires-Python: >=3.9
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
- Requires-Dist: aiodns<=3.4.0,>=3.3
25
- Requires-Dist: aiofiles<24.2.0,>=22.1
26
- Requires-Dist: aiohttp<3.12,>=3.8.1
24
+ Requires-Dist: aiodns<3.6,>=3.3.0
25
+ Requires-Dist: aiofiles<=24.1.0,>=22.1
26
+ Requires-Dist: aiohttp<3.13,>=3.8.3
27
27
  Requires-Dist: asyncio-throttle<=1.0.2,>=1.0
28
28
  Requires-Dist: async-timeout<4.0.4,>=4.0.3; python_version < "3.11"
29
- Requires-Dist: backoff<2.2.2,>=2.1.2
30
- Requires-Dist: click<=8.1.8,>=8.1.0
31
- Requires-Dist: cryptography<45.0.5,>=38.0.1
29
+ Requires-Dist: backoff<2.3,>=2.1.2
30
+ Requires-Dist: click<8.2,>=8.1.0
31
+ Requires-Dist: cryptography<46.0,>=38.0.1
32
32
  Requires-Dist: Django~=4.2.0
33
33
  Requires-Dist: django-filter<=25.1,>=23.1
34
- Requires-Dist: django-guid<=3.5.1,>=3.3
34
+ Requires-Dist: django-guid<3.6,>=3.3.0
35
35
  Requires-Dist: django-import-export<3.4.0,>=2.9
36
36
  Requires-Dist: django-lifecycle<=1.2.4,>=1.0
37
37
  Requires-Dist: djangorestframework<=3.16.0,>=3.14.0
@@ -40,28 +40,28 @@ Requires-Dist: drf-access-policy<1.5.1,>=1.1.2
40
40
  Requires-Dist: drf-nested-routers<=0.94.2,>=0.93.4
41
41
  Requires-Dist: drf-spectacular==0.27.2
42
42
  Requires-Dist: dynaconf<3.3.0,>=3.2.5
43
- Requires-Dist: gunicorn<23.1.0,>=20.1
43
+ Requires-Dist: gunicorn<23.1.0,>=22.0
44
44
  Requires-Dist: importlib-metadata<=6.0.1,>=6.0.1
45
45
  Requires-Dist: jinja2<=3.1.6,>=3.1
46
46
  Requires-Dist: json_stream<2.4,>=2.3.2
47
- Requires-Dist: jq<1.9.0,>=1.6.0
47
+ Requires-Dist: jq<1.10.0,>=1.6.0
48
48
  Requires-Dist: PyOpenSSL<26.0
49
- Requires-Dist: opentelemetry-api<1.34,>=1.27.0
50
- Requires-Dist: opentelemetry-sdk<1.34,>=1.27.0
51
- Requires-Dist: opentelemetry-exporter-otlp-proto-http<1.34,>=1.27.0
49
+ Requires-Dist: opentelemetry-api<1.35,>=1.27.0
50
+ Requires-Dist: opentelemetry-sdk<1.35,>=1.27.0
51
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http<1.35,>=1.27.0
52
52
  Requires-Dist: protobuf<6.0,>=4.21.1
53
- Requires-Dist: pulp-glue<0.33,>=0.18.0
53
+ Requires-Dist: pulp-glue<0.34,>=0.28.0
54
54
  Requires-Dist: pygtrie<=2.5.0,>=2.5
55
55
  Requires-Dist: psycopg[binary]<3.3,>=3.1.8
56
- Requires-Dist: pyparsing<=3.2.3,>=3.1.0
56
+ Requires-Dist: pyparsing<3.3,>=3.1.0
57
57
  Requires-Dist: python-gnupg<=0.5.4,>=0.5
58
- Requires-Dist: PyYAML<=6.0.2,>=5.1.1
59
- Requires-Dist: redis<5.2.2,>=4.3
60
- Requires-Dist: tablib<3.6.0
61
- Requires-Dist: url-normalize<=2.2.1,>=1.4.3
62
- Requires-Dist: uuid6<=2024.7.10,>=2023.5.2
58
+ Requires-Dist: PyYAML<6.1,>=5.1.1
59
+ Requires-Dist: redis<5.3,>=4.3.0
60
+ Requires-Dist: tablib<3.6,>=3.5.0
61
+ Requires-Dist: url-normalize<2.3,>=1.4.3
62
+ Requires-Dist: uuid6<=2025.0.0,>=2023.5.2
63
63
  Requires-Dist: whitenoise<6.10.0,>=5.0
64
- Requires-Dist: yarl<1.20.1,>=1.8
64
+ Requires-Dist: yarl<1.21,>=1.8
65
65
  Provides-Extra: sftp
66
66
  Requires-Dist: django-storages[sftp]==1.14.6; extra == "sftp"
67
67
  Provides-Extra: s3
@@ -74,7 +74,7 @@ Provides-Extra: prometheus
74
74
  Requires-Dist: django-prometheus; extra == "prometheus"
75
75
  Provides-Extra: kafka
76
76
  Requires-Dist: cloudevents==1.11.0; extra == "kafka"
77
- Requires-Dist: confluent-kafka<2.10.0,>=2.4.0; extra == "kafka"
77
+ Requires-Dist: confluent-kafka<2.11.0,>=2.4.0; extra == "kafka"
78
78
  Provides-Extra: diagnostics
79
79
  Requires-Dist: pyinstrument~=5.0; extra == "diagnostics"
80
80
  Requires-Dist: memray~=1.17; extra == "diagnostics"
@@ -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=eYIaNGdyJN3i8Hyg4xdmWYHCH92mz7dc8qNvl9hlkEM,297
3
+ pulp_certguard/app/__init__.py,sha256=asgxMyJ-_usTvtv9VipyiO0urYAshXR_2kfO8CtupGw,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
@@ -48,8 +48,8 @@ pulp_certguard/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
48
48
  pulp_certguard/tests/unit/test_models.py,sha256=TBI0yKsrdbnJSPeBFfxSqhXK7zaNvR6qg5JehGH3Pds,229
49
49
  pulp_file/__init__.py,sha256=0vOCXofR6Eyxkg4y66esnOGPeESCe23C1cNBHj56w44,61
50
50
  pulp_file/manifest.py,sha256=1WwIOJrPSkFcmkRm7CkWifVOCoZvo_nnANgce6uuG7U,3796
51
- pulp_file/pytest_plugin.py,sha256=Fi_p-Vle_I-VYUSe4Zlg7esb_Ul5fpB8Rx9UGLK5UNQ,13281
52
- pulp_file/app/__init__.py,sha256=LS53kL09EDYbyCrSTAdukSjcbFbPIeOBExG0gOVDQhk,292
51
+ pulp_file/pytest_plugin.py,sha256=l1PvTxUi5D3uJy4SnHWNhr-otWEYNcm-kc5nSqVJg0Y,10646
52
+ pulp_file/app/__init__.py,sha256=H2wrrNOzI22OucPfAe9Od3DtsHVRpfwIA0kcylz6Efc,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
@@ -82,7 +82,7 @@ pulp_file/tests/functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
82
82
  pulp_file/tests/functional/api/__init__.py,sha256=IxizGLz9A_3Sh2ZGHpRlqMyZ1gIVAepBpJB474OJefE,62
83
83
  pulp_file/tests/functional/api/test_acs.py,sha256=L9MuroKKGSuxe2SzmHWCTeUUe3WSClKSn5UBiedViPg,9277
84
84
  pulp_file/tests/functional/api/test_auto_publish.py,sha256=GGcXqIZhANsMd5R2MYNtjCsqp1vHT6q13AoEv-3dBE0,4514
85
- pulp_file/tests/functional/api/test_bad_sync.py,sha256=QrYYbZA7noLor5PMoJuXj6KQ6aci_qnlxCmr3xP4oak,2057
85
+ pulp_file/tests/functional/api/test_bad_sync.py,sha256=IKdMNDL3jRDA2SiaVsJHFU7PWCIBa-kpKM-ILNTKPaw,4448
86
86
  pulp_file/tests/functional/api/test_content_labels.py,sha256=9jvG3SPQ_40OrdgEu7xHQYmNNmqWseGoTHITe6OsWLw,6798
87
87
  pulp_file/tests/functional/api/test_crud_content_unit.py,sha256=YUug-4ZCADnxYUj3aB8e8lyJ7_rrXPPfRcXW3IlBKI8,14772
88
88
  pulp_file/tests/functional/api/test_crud_remotes.py,sha256=ukQOUGssEiwYNm7A8ti5b_cv91eec8FsbGghCNgNXhs,3459
@@ -104,31 +104,32 @@ pulpcore/backends.py,sha256=Ax_MJpbvtNDg_rhkHaiQRm39DBSS2dH8UpMRJN2T0oE,4482
104
104
  pulpcore/constants.py,sha256=06lih8sVRzHCrBXGmoT3Q-9ZkKZUEEYZ8EoeFfxEq04,4673
105
105
  pulpcore/filters.py,sha256=dD5oRRkWg65s3LoObr-ipRvRsxZK_3Zr0lKMNr9Sg5o,16682
106
106
  pulpcore/metrics.py,sha256=Mfq-nnRjRf3vBHFO-ux-4d1I3yE7TgeptwgiSgGz4rA,2230
107
- pulpcore/middleware.py,sha256=tJB2rGnulvNBN1fZ6lyN4zd60ja5QUNYD4l5dLHHaoY,5079
107
+ pulpcore/middleware.py,sha256=10Jxc4Iq03gZD3n39t63OmBCpdftcke8bxEd-LioJlA,5973
108
108
  pulpcore/migrations.py,sha256=gzUTxcXnbYkM0_vN8Rfr_XWuwsGWedVZAwNy9JqJ8sQ,2476
109
109
  pulpcore/pytest_plugin.py,sha256=skubiEUIevVURr4LnmmVMt_ZeH5vT9mI0yiPUYerMnQ,38090
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=rUgJ2SXznPOA50XaX9hwIhc2qCyBqdcsWlVowyn6r8A,17860
113
+ pulpcore/app/apps.py,sha256=0CaBE8E7gFLpu-mv5pv13EjHBBNa7Tj3r9oNT5Tiw8Y,17860
114
114
  pulpcore/app/authentication.py,sha256=1LIJW6HIQQlZrliHy__jdzkDEh6Oj7xKgd0V-vRcDus,2855
115
115
  pulpcore/app/checks.py,sha256=jbfTF7nmftBbky4AQXHigpyCaGydKasvRUXsd72JZVg,1946
116
- pulpcore/app/entrypoint.py,sha256=m9kwANkh9OkhyAcWqPbrZg21IMQibLlB8_k1tkVgedg,4888
117
- pulpcore/app/files.py,sha256=uPodXYTVh7Ud-lQn8F58viSdom7TMh2X1SpoDt6XRKw,5797
116
+ pulpcore/app/entrypoint.py,sha256=YIfQpM5UxybBTasiEY5ptq--UmqPqjdIGnwmqVsDC7E,4972
117
+ pulpcore/app/files.py,sha256=BHq2T6cizPXfepQuEw_RfPXBqzcDRRVK3sedGDrgSJ4,6315
118
118
  pulpcore/app/global_access_conditions.py,sha256=Jezc1Hf0bQFaZvZFEDPpBrJmK0EvIa6zHRHHZYkez2Y,30398
119
119
  pulpcore/app/importexport.py,sha256=x1gGrHgirfMLsv92GEwBIQe12aItJJW9JH8TPij-rms,8795
120
120
  pulpcore/app/loggers.py,sha256=7tteVBBIf4W7jk4tB7QNpFGjCZueDDrPAavHj46LdJI,79
121
121
  pulpcore/app/manage.py,sha256=5YGD5ly3dJcLjX4jKIo3BBPFi_aqEPqi-CCoogV8lm8,286
122
122
  pulpcore/app/mime_types.py,sha256=xQh9gd5jHKxS0RrYqUjg98pST-Cyfcrk_Et1l2eby_w,6706
123
123
  pulpcore/app/modelresource.py,sha256=SlnKD_K-ZFtR5Gt8hpoF5odEX2y-1v2bb6UkJcOqnd8,4847
124
+ pulpcore/app/netutil.py,sha256=qO99WtWPLjAKPh_APw92Y3mUtxPH91NfeRuWLii1MLA,412
124
125
  pulpcore/app/openpgp.py,sha256=MYwCTGz7J9-Zr5aSBrz7KGWWWNC1EI-aItGb5dr7XPE,17246
125
126
  pulpcore/app/pulp_hashlib.py,sha256=NoVCO8duLz9rggPcilg0smi6fTDnsn-zS9dXgO831Pg,1327
126
127
  pulpcore/app/pulpcore_gunicorn_application.py,sha256=caqbDg9dhzECbx9Ss76biuEARhquj9gQaSL6v3XLy2w,2612
127
128
  pulpcore/app/redis_connection.py,sha256=VTdG0ulXuyESjYV6SJdG_jLzkLZH-MlLcD6pielwRSk,952
128
- pulpcore/app/replica.py,sha256=6WU-K8olrOoO4q8gwJ2bKc_qmvw8wCOzRZdNZrr895g,11678
129
+ pulpcore/app/replica.py,sha256=rGE14OBaR_FKxmHL7NMxf_OizMyS-90IPsMRo_j9YRI,11474
129
130
  pulpcore/app/response.py,sha256=hYH_jSBrxmRsBr2bknmXE1qfs2g8JjDTXYcQ5ZWlF_c,1950
130
131
  pulpcore/app/role_util.py,sha256=84HSt8_9fxB--dtfSyg_TumVgOdyBbyP6rBaiAfTpOU,22393
131
- pulpcore/app/settings.py,sha256=f2LXOVLd58iG2z1Whm_XlLop129uKT5-GYxWiBq-ja8,22430
132
+ pulpcore/app/settings.py,sha256=HxZj3R15UG_AhwhNIs1VFXZqPuBHW3shjHkPwqvZMqo,22548
132
133
  pulpcore/app/urls.py,sha256=0gdI74CAdycJStXSw1gknviDGe3J3k0UhS4J8RYa5dg,8120
133
134
  pulpcore/app/util.py,sha256=nYF6nZXgqVk4U1QeZEpWYX-wqitGSGAJip6W78IfXUk,24432
134
135
  pulpcore/app/wsgi.py,sha256=7rpZ_1NHEN_UfeNZCj8206bas1WeqRkHnGdxpd7rdDI,492
@@ -283,6 +284,7 @@ pulpcore/app/migrations/0129_content_pulp_labels.py,sha256=3Ee8lpGfo02t-1tnOH1CJ
283
284
  pulpcore/app/migrations/0130_upstreampulp_policy.py,sha256=PLpgBU6iXTl7gruCe12aA5Zk4eG6heyrC6Rh1jeaxps,709
284
285
  pulpcore/app/migrations/0131_distribution_checkpoint_publication_checkpoint.py,sha256=MXZXQapnSXVfV9FFiIaoMb6M7qAnAJwtEmN6hSlJ8RQ,561
285
286
  pulpcore/app/migrations/0132_alter_content_options.py,sha256=hrhUTsRqQJgwC6wU9Ys5AvyVz2YCzklj2OuVf6hyBfs,477
287
+ pulpcore/app/migrations/0132_task_profile_options.py,sha256=ljdIm5-NXl_8s87HzkthvUxr7eHhLaETrr5qNtAVKDE,518
286
288
  pulpcore/app/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
287
289
  pulpcore/app/models/__init__.py,sha256=9JKMGKbEV6nJPep_K36rnWnS1QWMKBFSty-Hkr65JVk,3459
288
290
  pulpcore/app/models/access_policy.py,sha256=o4L41RGoZ5UMmh5UeeenmadD5MJgShguphgd4eAVxQA,6071
@@ -292,7 +294,7 @@ pulpcore/app/models/base.py,sha256=YbbH4LEEKIlFOWX_73bsYFlum8eOPmxHkESuKQTIapY,9
292
294
  pulpcore/app/models/content.py,sha256=8NE__k2suNvI1L9eNeWvIqB6i_fmpBHRJEt_B50S1zc,35713
293
295
  pulpcore/app/models/domain.py,sha256=c9EUAKPEKKpeNxwDGhdw6UyD5cyZGrIA3qzjsN-RIc0,3685
294
296
  pulpcore/app/models/exporter.py,sha256=rAa-abuyJqV-o1BNaoSxrYlxoUGBMqZQ0laMCVou84w,4325
295
- pulpcore/app/models/fields.py,sha256=hAjATkRtrgukLwGj1WIuYudGARvLZ_YjzE6WhYbp3rU,6463
297
+ pulpcore/app/models/fields.py,sha256=NJMASz5iQc95GSqzWFiWqsJhdaLM75udfci3IptvTlY,6451
296
298
  pulpcore/app/models/generic.py,sha256=PWeVttDRysgy9aReSkJ0TUORwyTf1-lE68fp8wMGhik,962
297
299
  pulpcore/app/models/importer.py,sha256=HECnV3oAPSAgFugYE72RNvh5l1wUs_S69NL80BMp0uc,3082
298
300
  pulpcore/app/models/openpgp.py,sha256=3R5p8ZBPq63NzaE2_EwCXEMYPUQu7QUWanMcKCOoWkM,7874
@@ -303,7 +305,7 @@ pulpcore/app/models/repository.py,sha256=xBMKsryirkpZyrQHnFbwolNbvyX1jHljcqC1ofv
303
305
  pulpcore/app/models/role.py,sha256=dZklNd2VeAw4cT6dyJ7SyTBt9sZvdqakY86wXGAY3vU,3287
304
306
  pulpcore/app/models/status.py,sha256=72oUOJ7BnCAw3uDbc-XuI72oAyP2llCoBic4zb2JP78,3683
305
307
  pulpcore/app/models/storage.py,sha256=2b-DQWaO31NqjV6FiISALegND-sQZAU7BVAsduUvm3o,6780
306
- pulpcore/app/models/task.py,sha256=PTVOAmjqU-8nIsPJAXt7VcZywCIl-Dm-ZEmg9bCssjs,14886
308
+ pulpcore/app/models/task.py,sha256=2w0fXHeErSrVssCfP8LeUuYjKgupAbhfR_IkWG8wmus,14950
307
309
  pulpcore/app/models/upload.py,sha256=3njXT2rrVJwBjEDegvqcLD9_7cPnnl974lhbAhikEp8,3004
308
310
  pulpcore/app/protobuf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
309
311
  pulpcore/app/protobuf/analytics_pb2.py,sha256=-4CkbSW8JUAEIjZJBTPAJ5QezFJOdCPiDhx8_KA1bMU,2168
@@ -311,15 +313,15 @@ pulpcore/app/serializers/__init__.py,sha256=M1g5Si6hRi1flhQ-F1n6G-uFEzIZ7BUqHZ8i
311
313
  pulpcore/app/serializers/access_policy.py,sha256=NNtuzDW5H4RGfy5LbRFEHWDTDzXdL-Kihe9uquXnxBU,2818
312
314
  pulpcore/app/serializers/acs.py,sha256=wBbGE5YHR7dJWuicbDtiPQUJ7xEgz1zKHGkJEaMfpDU,5834
313
315
  pulpcore/app/serializers/base.py,sha256=ojWmsr2U2Mx8qpSFxqHLNQyfU2Z9q7hY1NUwVs9s3HE,21418
314
- pulpcore/app/serializers/content.py,sha256=lqfSah9Kg2i6dV-x2MGwQ-1q87GB9VOtjkQdjQKC5tQ,11967
315
- pulpcore/app/serializers/domain.py,sha256=-xRJS_Olb1s2bqFzKamV0d_QnYO-e2iIyBJw-39uqMI,22688
316
+ pulpcore/app/serializers/content.py,sha256=TKEh774Q-0l1AfUeMmVxPM5lk5UiYZxgkt9NU1RjZ9M,11966
317
+ pulpcore/app/serializers/domain.py,sha256=y2qXdf2gSvWH5UtYULhX390u6wWmegg-GD9g5QwqZJA,22758
316
318
  pulpcore/app/serializers/exporter.py,sha256=TxAgHDt34YUGPusawn7B8HL3bBymp46__6CnfhXSgGs,11179
317
- pulpcore/app/serializers/fields.py,sha256=NlxrK9__GVt1untO4USkd5ARltEgp_NqwG0M3St3SuQ,16181
319
+ pulpcore/app/serializers/fields.py,sha256=kWA6wYNA8dYmDJfFE_3eVUQRj4vCceqjzYPEEP53rxA,16481
318
320
  pulpcore/app/serializers/importer.py,sha256=PVSNs5U0dfAm-XlRKpMqOXK0VmUErxJauNJCNro6ONA,8200
319
321
  pulpcore/app/serializers/openpgp.py,sha256=3Svxskj_-HmOVbjay7QI82zXnKTsbtaSlZZ03CoT-MQ,8966
320
322
  pulpcore/app/serializers/orphans.py,sha256=Vhyaj0fqYT4pkiYoNjgmsy1u5BiR_aHwZm2y7rk9cbk,1967
321
323
  pulpcore/app/serializers/progress.py,sha256=j4IQDLb_XOrLzTud4Fq8T-8kkOqLewReMVkbS5uCEIg,2575
322
- pulpcore/app/serializers/publication.py,sha256=9Lzvn5e04TQ8EVMR_aR5NWK-P3X_4PYSUaWAfD2rHQg,16439
324
+ pulpcore/app/serializers/publication.py,sha256=Qg9ZbvyyS4VoYqLSVXdJ3ceTUP2IAJQgY-K9sJJcXNc,16502
323
325
  pulpcore/app/serializers/purge.py,sha256=CnjKWUvkuI207QMbqwmNs7FqMdOMUh1cujagby3vVM0,779
324
326
  pulpcore/app/serializers/reclaim.py,sha256=-ewdNqu-Ck1B_IUWJHG0pvN5zCMMEK9RiWI45g7D0ro,1710
325
327
  pulpcore/app/serializers/repair.py,sha256=uKrxTnhoarxyyGCixPRn9pmG19gRRVUTM7nPwCVp6_8,554
@@ -371,13 +373,13 @@ pulpcore/app/viewsets/upload.py,sha256=Mfy9Vcm5KcqARooH4iExzoXVkL6boDddEqAnGWDWz
371
373
  pulpcore/app/viewsets/user.py,sha256=86eMawpaVrvp6ilQmb1C4j7SKpesPB5HgMovYL9rY3Q,13813
372
374
  pulpcore/cache/__init__.py,sha256=GkYD4PgIMaVL83ywfAsLBC9JNNDUpmTtbitW9zZSslk,131
373
375
  pulpcore/cache/cache.py,sha256=d8GMlvjeGG9MOMdi5_9029WpGCKH8Y5q9b2lt3wSREo,17371
374
- pulpcore/content/__init__.py,sha256=CVrhM5Ep2NFZBWOPxuyXXz7xL0bdZsmpBaOLPeA14SI,4010
376
+ pulpcore/content/__init__.py,sha256=lJDgxeIHXI__7LOQciRQSTItebgsxpoEGbd19Q7jNdI,4015
375
377
  pulpcore/content/authentication.py,sha256=lEZBkXBBBkIdtFMCSpHDD7583M0bO-zsZNYXTmpr4k8,3235
376
- pulpcore/content/entrypoint.py,sha256=svs6pEYa5bEGhWAAHpZt-uqlTuVXQ2UdW4U_LRlRHhY,2048
377
- pulpcore/content/handler.py,sha256=-EsaNoTUZu2k3zCOMLA-IiD8vyYwUAJOJxstH0CuaZo,56693
378
+ pulpcore/content/entrypoint.py,sha256=DiQTQzfcUiuyl37uvy6Wpa_7kr8t79ekpMHr31MDL2s,2132
379
+ pulpcore/content/handler.py,sha256=B0G2MwOtCedMfwFA5qcHsvg884GhsG_xw4ybYAmLthY,56781
378
380
  pulpcore/content/instrumentation.py,sha256=H0N0GWzvOPGGjFi6eIbGW3mcvagfnAfazccTh-BZVmE,1426
379
381
  pulpcore/download/__init__.py,sha256=s3Wh2GKdsmbUooVIR6wSvhYVIhpaTbtfR3Ar1OJhC7s,154
380
- pulpcore/download/base.py,sha256=G8jgyowvVEFCGA_KTr0CtHn0qHWXKsnv4Xpi0KSMglM,12821
382
+ pulpcore/download/base.py,sha256=4KCAYnV8jSOX078ETwlfwNZGY3xCBF9yy866tyGKAzE,13095
381
383
  pulpcore/download/factory.py,sha256=NQ1c7lqf8cCTZvhBeDaDjCE2qBAvPRzSDbtP2yN8SFk,9679
382
384
  pulpcore/download/file.py,sha256=nrPqcqB1k7MOaIhTKB2KS_Vc6O10--c-t1Tgf-Ct8fg,2235
383
385
  pulpcore/download/http.py,sha256=EVNlO10sZYzx8GmIg8ulHY-jw1V1sNXgvwS7RrU-VPE,12333
@@ -385,7 +387,7 @@ pulpcore/exceptions/__init__.py,sha256=ZgqOLvuNEAEPkC8lUVEJIFyUJZJOy94whdzXYoMP2
385
387
  pulpcore/exceptions/base.py,sha256=3iNTD8BsAfe7vpUaOzXl2f_WJPd4wfqEuf2GkFheBhs,2863
386
388
  pulpcore/exceptions/plugin.py,sha256=CrfzjCP1YZk_W6p1yRFrUfqTv0Iptzu2aBxzlebXeLU,613
387
389
  pulpcore/exceptions/validation.py,sha256=4iyDMxKzejHIzEuebDRXkvA_GNCdaommW9Ycsaa1v3Y,2481
388
- pulpcore/openapi/__init__.py,sha256=lGb5ncwR1eotpOwfxPeAioanGfqajOkO1gncXww9pdk,17981
390
+ pulpcore/openapi/__init__.py,sha256=8R96t7rvAFgIU_-Bv79X_cW0NV10Au9vHzUmp5jaFpw,18443
389
391
  pulpcore/openapi/hooks.py,sha256=uRFFW6khHNrntK6R99SUEDfP4LzmYJfsX7i8XGO4iaI,1426
390
392
  pulpcore/plugin/__init__.py,sha256=q0qu_15BTEY_EqPB9DSDk8rdnZMvld3cZsFXEnOVjuo,131
391
393
  pulpcore/plugin/access_policy.py,sha256=KHbWBXEOP59V8J_R52Pw2Q_Amodg-1bJYh6tyt5vDgk,4968
@@ -423,11 +425,11 @@ pulpcore/plugin/stages/models.py,sha256=0b7xs9d64WTG2yHog1Zo_Z_-pomFAe-gC4u9wksY
423
425
  pulpcore/plugin/viewsets/__init__.py,sha256=G2zE-NRWz6PFYp8OMZrv01RYBQELFWfW702bRvxXs3k,2281
424
426
  pulpcore/plugin/viewsets/content.py,sha256=MHvmLOxsKSQfk6y5t1s9CVxkce9YNeU-dYb1Ldyf83I,6432
425
427
  pulpcore/tasking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
426
- pulpcore/tasking/_util.py,sha256=giR8f8fNvsjsTiuJOU9X21Dyb14fFntSYU7xXGwQZzo,9705
428
+ pulpcore/tasking/_util.py,sha256=fPW4k1nUa_NZ0ywy_A15Fuiejo5stY58abPbZTXw5t8,9904
427
429
  pulpcore/tasking/entrypoint.py,sha256=Npnn41e39soGvJ7CTaZXT5MjIhOO7UtQmpmNaZtfKYg,1120
428
430
  pulpcore/tasking/kafka.py,sha256=76z4DzeXM1WL5uu1HlKnduWeLO3-b-czvGBXdWR6054,3845
429
431
  pulpcore/tasking/storage.py,sha256=zQkwlpC_FDQtmZGZ8vKwHqxvD6CLO_gAS4Q7wijZE-k,3106
430
- pulpcore/tasking/tasks.py,sha256=Y1tvG2hHREtpzVnQtu-_QYXD6mKtuvyCethOopWUJAI,14327
432
+ pulpcore/tasking/tasks.py,sha256=OhiKVl_WKc7m-7V-bWTh9hM3GgQlcnPCIeLw97FXAYM,14448
431
433
  pulpcore/tasking/worker.py,sha256=c9RgSYg4J_Jn_q70MVF_2egDeASFgXlLrP00lqWKtnQ,23822
432
434
  pulpcore/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
433
435
  pulpcore/tests/functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -454,7 +456,7 @@ pulpcore/tests/functional/api/test_scoping.py,sha256=uiLOsx5_7puRMcvrpPKEYQziqlu
454
456
  pulpcore/tests/functional/api/test_signing_service.py,sha256=yr1HXBrNoliBHJNAGAN4PAN0eBKPIvAQP-uMoMSrO_I,222
455
457
  pulpcore/tests/functional/api/test_status.py,sha256=Vmmj-ueGxJw1JFSQtr5feTM8vjgyyROvxsRm-OgzLUQ,5370
456
458
  pulpcore/tests/functional/api/test_task_purge.py,sha256=Av4DrUdCqf-JegfoP1pkY4B-teoUzYd1LBZKAhDa-08,7273
457
- pulpcore/tests/functional/api/test_tasking.py,sha256=LPJtsRK9Ggh7CUsVuATcLYUnhdclbbS2zPUwAJGo2fg,21566
459
+ pulpcore/tests/functional/api/test_tasking.py,sha256=jozm0Bpv1AavPDSu0QOZMCzre9Zgpw7_M9HCiaoTRmA,22511
458
460
  pulpcore/tests/functional/api/test_upload.py,sha256=oLP1ZmQgPzgK5jAQwGeXS8uLFHgAzVeLW0GfANMWexI,6794
459
461
  pulpcore/tests/functional/api/test_users_groups.py,sha256=YFG0xtyJuIRraczR7ERl_UNS7dlJfKd2eUmXgD1lLBU,2926
460
462
  pulpcore/tests/functional/api/test_workers.py,sha256=u3oQnErjf6qPCg08XMRZzecGetLLDWmvHvoZIk-AUAA,4659
@@ -462,7 +464,7 @@ pulpcore/tests/functional/api/using_plugin/__init__.py,sha256=QyyfzgjLOi4n32G3o9
462
464
  pulpcore/tests/functional/api/using_plugin/test_checkpoint.py,sha256=gx1oiHOVUH5QZfF33k_DXSw-AVbYQp39uKii1D96BoI,7965
463
465
  pulpcore/tests/functional/api/using_plugin/test_content_access.py,sha256=Ym800bU-M48RCDfQMkVa1UQt_sfgy5ciU0FxorCk9Ds,2551
464
466
  pulpcore/tests/functional/api/using_plugin/test_content_cache.py,sha256=OB3gDbPDptQBjyYnr_jHyU9bcI_-ANAoUp9EDiskwug,7312
465
- pulpcore/tests/functional/api/using_plugin/test_content_delivery.py,sha256=88ZtwViR3KueR6PUQX72Kx1IKpRcMuJMeJu43ylRxqc,9901
467
+ pulpcore/tests/functional/api/using_plugin/test_content_delivery.py,sha256=oatcqaiOv7o_BqsgQ3uXCWnY1RWa5cmzUvPBHzJuI8o,11384
466
468
  pulpcore/tests/functional/api/using_plugin/test_content_directory.py,sha256=w4uY258etnP8-LbrbZ_EZTolciYTt7cY1HJK9Ll7mS0,1931
467
469
  pulpcore/tests/functional/api/using_plugin/test_content_path.py,sha256=fvqeptqo-mrUAiKIjlypuvHG1XsFeKKP81ocTmo4hv0,3334
468
470
  pulpcore/tests/functional/api/using_plugin/test_content_promotion.py,sha256=Co4ytrfpzklwgDdEthv45dsmrceRpqIQfLJlZWM6EBY,2388
@@ -529,9 +531,9 @@ pulpcore/tests/unit/stages/test_artifactdownloader.py,sha256=qB1ANdFmNtUnljg8fCd
529
531
  pulpcore/tests/unit/stages/test_stages.py,sha256=H1a2BQLjdZlZvcb_qULp62huZ1xy6ItTcthktVyGU0w,4735
530
532
  pulpcore/tests/unit/viewsets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
531
533
  pulpcore/tests/unit/viewsets/test_viewset_base.py,sha256=W9o3V6758bZctR6krMPPQytb0xJuF-jb4uBWTNDoD_U,4837
532
- pulpcore-3.80.2.dist-info/licenses/LICENSE,sha256=dhnHU8rJXUdAIgIjveSKAyYG_KzN5eVG-bxETIGrNW0,17988
533
- pulpcore-3.80.2.dist-info/METADATA,sha256=nEk9DQ9c12BFdDsxXq3P45UZ4ji955j6m9I64m2Ptm4,4333
534
- pulpcore-3.80.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
535
- pulpcore-3.80.2.dist-info/entry_points.txt,sha256=OZven4wzXzQA5b5q9MpP4HUpIPPQCSvIOvkKtNInrK0,452
536
- pulpcore-3.80.2.dist-info/top_level.txt,sha256=6h-Lm3FKQSaT_nL1KSxu_hBnzKE15bcvf_BoU-ea4CI,34
537
- pulpcore-3.80.2.dist-info/RECORD,,
534
+ pulpcore-3.82.0.dist-info/licenses/LICENSE,sha256=dhnHU8rJXUdAIgIjveSKAyYG_KzN5eVG-bxETIGrNW0,17988
535
+ pulpcore-3.82.0.dist-info/METADATA,sha256=WRDG4YKlKA1AR0LuMwR56Gsp7DRzkbqsXMUcurqx6jI,4320
536
+ pulpcore-3.82.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
537
+ pulpcore-3.82.0.dist-info/entry_points.txt,sha256=OZven4wzXzQA5b5q9MpP4HUpIPPQCSvIOvkKtNInrK0,452
538
+ pulpcore-3.82.0.dist-info/top_level.txt,sha256=6h-Lm3FKQSaT_nL1KSxu_hBnzKE15bcvf_BoU-ea4CI,34
539
+ pulpcore-3.82.0.dist-info/RECORD,,