pulpcore 3.88.0__py3-none-any.whl → 3.89.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.
- pulp_certguard/app/__init__.py +1 -1
- pulp_file/app/__init__.py +1 -1
- pulpcore/app/apps.py +1 -1
- pulpcore/app/migrations/0143_require_app_lock_zdu.py +15 -0
- pulpcore/app/models/task.py +24 -24
- pulpcore/app/settings.py +0 -2
- pulpcore/content/handler.py +7 -6
- pulpcore/tasking/tasks.py +64 -68
- pulpcore/tasking/worker.py +91 -89
- pulpcore/tests/functional/api/test_status.py +1 -1
- pulpcore/tests/functional/api/test_upload.py +3 -1
- pulpcore/tests/functional/api/using_plugin/test_distributions.py +6 -2
- pulpcore/tests/functional/utils.py +1 -1
- pulpcore/tests/unit/metrics/test_aiohttp_instrumentation.py +4 -1
- pulpcore/tests/unit/models/test_task.py +5 -3
- pulpcore/tests/unit/stages/test_artifactdownloader.py +2 -2
- pulpcore/tests/unit/viewsets/test_viewset_base.py +3 -3
- {pulpcore-3.88.0.dist-info → pulpcore-3.89.0.dist-info}/METADATA +2 -2
- {pulpcore-3.88.0.dist-info → pulpcore-3.89.0.dist-info}/RECORD +23 -22
- {pulpcore-3.88.0.dist-info → pulpcore-3.89.0.dist-info}/WHEEL +0 -0
- {pulpcore-3.88.0.dist-info → pulpcore-3.89.0.dist-info}/entry_points.txt +0 -0
- {pulpcore-3.88.0.dist-info → pulpcore-3.89.0.dist-info}/licenses/LICENSE +0 -0
- {pulpcore-3.88.0.dist-info → pulpcore-3.89.0.dist-info}/top_level.txt +0 -0
pulp_certguard/app/__init__.py
CHANGED
pulp_file/app/__init__.py
CHANGED
pulpcore/app/apps.py
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Generated by Django 4.2.23 on 2025-09-04 08:58
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
from pulpcore.migrations import RequireVersion
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
("core", "0142_task_result"),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
RequireVersion("core", "3.87"),
|
|
15
|
+
]
|
pulpcore/app/models/task.py
CHANGED
|
@@ -12,7 +12,7 @@ from django.conf import settings
|
|
|
12
12
|
from django.contrib.postgres.fields import ArrayField, HStoreField
|
|
13
13
|
from django.contrib.postgres.indexes import GinIndex
|
|
14
14
|
from django.core.serializers.json import DjangoJSONEncoder
|
|
15
|
-
from django.db import
|
|
15
|
+
from django.db import models
|
|
16
16
|
from django.utils import timezone
|
|
17
17
|
from django_lifecycle import hook, AFTER_CREATE
|
|
18
18
|
|
|
@@ -21,10 +21,10 @@ from pulpcore.app.models import (
|
|
|
21
21
|
BaseModel,
|
|
22
22
|
GenericRelationModel,
|
|
23
23
|
)
|
|
24
|
-
from pulpcore.app.models.status import BaseAppStatus
|
|
24
|
+
from pulpcore.app.models.status import AppStatus, BaseAppStatus
|
|
25
25
|
from pulpcore.app.models.fields import EncryptedJSONField
|
|
26
26
|
from pulpcore.constants import TASK_CHOICES, TASK_INCOMPLETE_STATES, TASK_STATES
|
|
27
|
-
from pulpcore.exceptions import
|
|
27
|
+
from pulpcore.exceptions import exception_to_dict
|
|
28
28
|
from pulpcore.app.util import get_domain_pk, current_task
|
|
29
29
|
from pulpcore.app.loggers import deprecation_logger
|
|
30
30
|
|
|
@@ -141,7 +141,7 @@ class Task(BaseModel, AutoAddObjPermsMixin):
|
|
|
141
141
|
enc_kwargs = EncryptedJSONField(null=True, encoder=DjangoJSONEncoder)
|
|
142
142
|
|
|
143
143
|
worker = models.ForeignKey("Worker", null=True, related_name="tasks", on_delete=models.SET_NULL)
|
|
144
|
-
# This field is
|
|
144
|
+
# This field is the lock to protect tasks.
|
|
145
145
|
app_lock = models.ForeignKey(
|
|
146
146
|
"AppStatus", null=True, related_name="tasks", on_delete=models.SET_NULL
|
|
147
147
|
)
|
|
@@ -167,22 +167,6 @@ class Task(BaseModel, AutoAddObjPermsMixin):
|
|
|
167
167
|
def __str__(self):
|
|
168
168
|
return "Task: {name} [{state}]".format(name=self.name, state=self.state)
|
|
169
169
|
|
|
170
|
-
def __enter__(self):
|
|
171
|
-
self.lock = _uuid_to_advisory_lock(self.pk.int)
|
|
172
|
-
with connection.cursor() as cursor:
|
|
173
|
-
cursor.execute("SELECT pg_try_advisory_lock(%s)", [self.lock])
|
|
174
|
-
acquired = cursor.fetchone()[0]
|
|
175
|
-
if not acquired:
|
|
176
|
-
raise AdvisoryLockError("Could not acquire lock.")
|
|
177
|
-
return self
|
|
178
|
-
|
|
179
|
-
def __exit__(self, exc_type, exc_value, traceback):
|
|
180
|
-
with connection.cursor() as cursor:
|
|
181
|
-
cursor.execute("SELECT pg_advisory_unlock(%s)", [self.lock])
|
|
182
|
-
released = cursor.fetchone()[0]
|
|
183
|
-
if not released:
|
|
184
|
-
raise RuntimeError("Lock not held.")
|
|
185
|
-
|
|
186
170
|
@staticmethod
|
|
187
171
|
def current_id():
|
|
188
172
|
"""
|
|
@@ -218,7 +202,11 @@ class Task(BaseModel, AutoAddObjPermsMixin):
|
|
|
218
202
|
This updates the :attr:`started_at` and sets the :attr:`state` to :attr:`RUNNING`.
|
|
219
203
|
"""
|
|
220
204
|
started_at = timezone.now()
|
|
221
|
-
rows = Task.objects.filter(
|
|
205
|
+
rows = Task.objects.filter(
|
|
206
|
+
pk=self.pk,
|
|
207
|
+
state=TASK_STATES.WAITING,
|
|
208
|
+
app_lock=AppStatus.objects.current(),
|
|
209
|
+
).update(
|
|
222
210
|
state=TASK_STATES.RUNNING,
|
|
223
211
|
started_at=started_at,
|
|
224
212
|
)
|
|
@@ -254,7 +242,11 @@ class Task(BaseModel, AutoAddObjPermsMixin):
|
|
|
254
242
|
# Only set the state to finished if it's running. This is important for when the task has
|
|
255
243
|
# been canceled, so we don't move the task from canceled to finished.
|
|
256
244
|
finished_at = timezone.now()
|
|
257
|
-
rows = Task.objects.filter(
|
|
245
|
+
rows = Task.objects.filter(
|
|
246
|
+
pk=self.pk,
|
|
247
|
+
state=TASK_STATES.RUNNING,
|
|
248
|
+
app_lock=AppStatus.objects.current(),
|
|
249
|
+
).update(
|
|
258
250
|
state=TASK_STATES.COMPLETED,
|
|
259
251
|
finished_at=finished_at,
|
|
260
252
|
result=result,
|
|
@@ -289,7 +281,11 @@ class Task(BaseModel, AutoAddObjPermsMixin):
|
|
|
289
281
|
finished_at = timezone.now()
|
|
290
282
|
tb_str = "".join(traceback.format_tb(tb))
|
|
291
283
|
error = exception_to_dict(exc, tb_str)
|
|
292
|
-
rows = Task.objects.filter(
|
|
284
|
+
rows = Task.objects.filter(
|
|
285
|
+
pk=self.pk,
|
|
286
|
+
state=TASK_STATES.RUNNING,
|
|
287
|
+
app_lock=AppStatus.objects.current(),
|
|
288
|
+
).update(
|
|
293
289
|
state=TASK_STATES.FAILED,
|
|
294
290
|
finished_at=finished_at,
|
|
295
291
|
error=error,
|
|
@@ -336,7 +332,11 @@ class Task(BaseModel, AutoAddObjPermsMixin):
|
|
|
336
332
|
task_data = {}
|
|
337
333
|
if reason:
|
|
338
334
|
task_data["error"] = {"reason": reason}
|
|
339
|
-
rows = Task.objects.filter(
|
|
335
|
+
rows = Task.objects.filter(
|
|
336
|
+
pk=self.pk,
|
|
337
|
+
state=TASK_STATES.CANCELING,
|
|
338
|
+
app_lock=AppStatus.objects.current(),
|
|
339
|
+
).update(
|
|
340
340
|
state=final_state,
|
|
341
341
|
finished_at=finished_at,
|
|
342
342
|
**task_data,
|
pulpcore/app/settings.py
CHANGED
pulpcore/content/handler.py
CHANGED
|
@@ -7,6 +7,7 @@ import socket
|
|
|
7
7
|
import struct
|
|
8
8
|
from gettext import gettext as _
|
|
9
9
|
from datetime import datetime, timedelta
|
|
10
|
+
from datetime import timezone as dt_timezone
|
|
10
11
|
|
|
11
12
|
from aiohttp.client_exceptions import ClientResponseError, ClientConnectionError
|
|
12
13
|
from aiohttp.web import FileResponse, StreamResponse, HTTPOk
|
|
@@ -115,7 +116,7 @@ class DistroListings(HTTPOk):
|
|
|
115
116
|
if path == "":
|
|
116
117
|
path = settings.CONTENT_PATH_PREFIX
|
|
117
118
|
html = Handler.render_html(directory_list, path=path)
|
|
118
|
-
super().__init__(
|
|
119
|
+
super().__init__(text=html, headers={"Content-Type": "text/html"})
|
|
119
120
|
|
|
120
121
|
|
|
121
122
|
class CheckpointListings(HTTPOk):
|
|
@@ -137,7 +138,7 @@ class CheckpointListings(HTTPOk):
|
|
|
137
138
|
dates = {f"{Handler._format_checkpoint_timestamp(s)}/": s for s in checkpoints}
|
|
138
139
|
directory_list = dates.keys()
|
|
139
140
|
html = Handler.render_html(directory_list, dates=dates, path=path)
|
|
140
|
-
super().__init__(
|
|
141
|
+
super().__init__(text=html, headers={"Content-Type": "text/html"})
|
|
141
142
|
|
|
142
143
|
|
|
143
144
|
class ArtifactNotFound(Exception):
|
|
@@ -439,9 +440,9 @@ class Handler:
|
|
|
439
440
|
else:
|
|
440
441
|
raise PathNotResolved(path)
|
|
441
442
|
|
|
442
|
-
request_timestamp = request_timestamp.replace(tzinfo=
|
|
443
|
+
request_timestamp = request_timestamp.replace(tzinfo=dt_timezone.utc)
|
|
443
444
|
# Future timestamps are not allowed for checkpoints
|
|
444
|
-
if request_timestamp > datetime.now(tz=
|
|
445
|
+
if request_timestamp > datetime.now(tz=dt_timezone.utc):
|
|
445
446
|
raise PathNotResolved(path)
|
|
446
447
|
# The timestamp is truncated to seconds, so we need to cover the whole second
|
|
447
448
|
request_timestamp = request_timestamp.replace(microsecond=999999)
|
|
@@ -787,7 +788,7 @@ class Handler:
|
|
|
787
788
|
elif dir_list:
|
|
788
789
|
return HTTPOk(
|
|
789
790
|
headers={"Content-Type": "text/html"},
|
|
790
|
-
|
|
791
|
+
text=self.render_html(
|
|
791
792
|
dir_list, path=request.path, dates=dates, sizes=sizes
|
|
792
793
|
),
|
|
793
794
|
)
|
|
@@ -862,7 +863,7 @@ class Handler:
|
|
|
862
863
|
elif dir_list:
|
|
863
864
|
return HTTPOk(
|
|
864
865
|
headers={"Content-Type": "text/html"},
|
|
865
|
-
|
|
866
|
+
text=self.render_html(
|
|
866
867
|
dir_list, path=request.path, dates=dates, sizes=sizes
|
|
867
868
|
),
|
|
868
869
|
)
|
pulpcore/tasking/tasks.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import contextlib
|
|
3
2
|
import contextvars
|
|
4
3
|
import importlib
|
|
5
4
|
import logging
|
|
@@ -11,7 +10,7 @@ import threading
|
|
|
11
10
|
from gettext import gettext as _
|
|
12
11
|
|
|
13
12
|
from django.conf import settings
|
|
14
|
-
from django.db import connection
|
|
13
|
+
from django.db import connection
|
|
15
14
|
from django.db.models import Model
|
|
16
15
|
from django_guid import get_guid
|
|
17
16
|
from pulpcore.app.apps import MODULE_PLUGIN_VERSIONS
|
|
@@ -26,6 +25,7 @@ from pulpcore.constants import (
|
|
|
26
25
|
TASK_INCOMPLETE_STATES,
|
|
27
26
|
TASK_STATES,
|
|
28
27
|
IMMEDIATE_TIMEOUT,
|
|
28
|
+
TASK_WAKEUP_HANDLE,
|
|
29
29
|
TASK_WAKEUP_UNBLOCK,
|
|
30
30
|
)
|
|
31
31
|
from pulpcore.middleware import x_task_diagnostics_var
|
|
@@ -49,7 +49,7 @@ def _validate_and_get_resources(resources):
|
|
|
49
49
|
return list(resource_set)
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
def wakeup_worker(reason
|
|
52
|
+
def wakeup_worker(reason):
|
|
53
53
|
# Notify workers
|
|
54
54
|
with connection.connection.cursor() as cursor:
|
|
55
55
|
cursor.execute("SELECT pg_notify('pulp_worker_wakeup', %s)", (reason,))
|
|
@@ -222,67 +222,61 @@ def dispatch(
|
|
|
222
222
|
resources = exclusive_resources + [f"shared:{resource}" for resource in shared_resources]
|
|
223
223
|
|
|
224
224
|
notify_workers = False
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
colliding_resources
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
try:
|
|
271
|
-
execute_task(task)
|
|
272
|
-
finally:
|
|
273
|
-
# Whether the task fails or not, we should always restore the workdir.
|
|
274
|
-
os.chdir(cur_dir)
|
|
275
|
-
|
|
276
|
-
if resources:
|
|
277
|
-
notify_workers = True
|
|
278
|
-
elif deferred:
|
|
279
|
-
# Resources are blocked. Let the others handle it.
|
|
225
|
+
task = Task.objects.create(
|
|
226
|
+
state=TASK_STATES.WAITING,
|
|
227
|
+
logging_cid=(get_guid()),
|
|
228
|
+
task_group=task_group,
|
|
229
|
+
name=function_name,
|
|
230
|
+
enc_args=args,
|
|
231
|
+
enc_kwargs=kwargs,
|
|
232
|
+
parent_task=Task.current(),
|
|
233
|
+
reserved_resources_record=resources,
|
|
234
|
+
versions=versions,
|
|
235
|
+
immediate=immediate,
|
|
236
|
+
deferred=deferred,
|
|
237
|
+
profile_options=x_task_diagnostics_var.get(None),
|
|
238
|
+
app_lock=None if not immediate else AppStatus.objects.current(), # Lazy evaluation...
|
|
239
|
+
)
|
|
240
|
+
task.refresh_from_db() # The database will have assigned a timestamp for us.
|
|
241
|
+
if immediate:
|
|
242
|
+
prior_tasks = Task.objects.filter(
|
|
243
|
+
state__in=TASK_INCOMPLETE_STATES, pulp_created__lt=task.pulp_created
|
|
244
|
+
)
|
|
245
|
+
# Compile a list of resources that must not be taken by other tasks.
|
|
246
|
+
colliding_resources = (
|
|
247
|
+
shared_resources
|
|
248
|
+
+ exclusive_resources
|
|
249
|
+
+ [f"shared:{resource}" for resource in exclusive_resources]
|
|
250
|
+
)
|
|
251
|
+
# Can we execute this task immediately?
|
|
252
|
+
if (
|
|
253
|
+
not colliding_resources
|
|
254
|
+
or not prior_tasks.filter(
|
|
255
|
+
reserved_resources_record__overlap=colliding_resources
|
|
256
|
+
).exists()
|
|
257
|
+
):
|
|
258
|
+
task.unblock()
|
|
259
|
+
|
|
260
|
+
cur_dir = os.getcwd()
|
|
261
|
+
with tempfile.TemporaryDirectory(dir=settings.WORKING_DIRECTORY) as working_dir:
|
|
262
|
+
os.chdir(working_dir)
|
|
263
|
+
try:
|
|
264
|
+
execute_task(task)
|
|
265
|
+
finally:
|
|
266
|
+
# Whether the task fails or not, we should always restore the workdir.
|
|
267
|
+
os.chdir(cur_dir)
|
|
268
|
+
|
|
269
|
+
if resources:
|
|
280
270
|
notify_workers = True
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
271
|
+
elif deferred:
|
|
272
|
+
# Resources are blocked. Let the others handle it.
|
|
273
|
+
task.app_lock = None
|
|
274
|
+
task.save()
|
|
275
|
+
else:
|
|
276
|
+
task.set_canceling()
|
|
277
|
+
task.set_canceled(TASK_STATES.CANCELED, "Resources temporarily unavailable.")
|
|
278
|
+
else:
|
|
279
|
+
notify_workers = True
|
|
286
280
|
if notify_workers:
|
|
287
281
|
wakeup_worker(TASK_WAKEUP_UNBLOCK)
|
|
288
282
|
return task
|
|
@@ -304,7 +298,7 @@ def cancel_task(task_id):
|
|
|
304
298
|
task = Task.objects.select_related("pulp_domain").get(pk=task_id)
|
|
305
299
|
|
|
306
300
|
if task.state in TASK_FINAL_STATES:
|
|
307
|
-
# If the task is already done, just stop
|
|
301
|
+
# If the task is already done, just stop.
|
|
308
302
|
_logger.debug(
|
|
309
303
|
"Task [{task_id}] in domain: {name} already in a final state: {state}".format(
|
|
310
304
|
task_id=task_id, name=task.pulp_domain.name, state=task.state
|
|
@@ -315,12 +309,14 @@ def cancel_task(task_id):
|
|
|
315
309
|
"Canceling task: {id} in domain: {name}".format(id=task_id, name=task.pulp_domain.name)
|
|
316
310
|
)
|
|
317
311
|
|
|
318
|
-
# This is the only valid transition without holding the task lock
|
|
312
|
+
# This is the only valid transition without holding the task lock.
|
|
319
313
|
task.set_canceling()
|
|
320
|
-
# Notify the worker that might be running that task
|
|
314
|
+
# Notify the worker that might be running that task.
|
|
321
315
|
with connection.cursor() as cursor:
|
|
322
|
-
|
|
323
|
-
|
|
316
|
+
if task.app_lock is None:
|
|
317
|
+
wakeup_worker(TASK_WAKEUP_HANDLE)
|
|
318
|
+
else:
|
|
319
|
+
cursor.execute("SELECT pg_notify('pulp_worker_cancel', %s)", (str(task.pk),))
|
|
324
320
|
return task
|
|
325
321
|
|
|
326
322
|
|
pulpcore/tasking/worker.py
CHANGED
|
@@ -15,7 +15,6 @@ from packaging.version import parse as parse_version
|
|
|
15
15
|
from django.conf import settings
|
|
16
16
|
from django.db import connection, DatabaseError, IntegrityError
|
|
17
17
|
from django.db.models import Case, Count, F, Max, Value, When
|
|
18
|
-
from django.db.models.functions import Random
|
|
19
18
|
from django.utils import timezone
|
|
20
19
|
|
|
21
20
|
from pulpcore.constants import (
|
|
@@ -54,6 +53,8 @@ TASK_GRACE_INTERVAL = settings.TASK_GRACE_INTERVAL
|
|
|
54
53
|
TASK_KILL_INTERVAL = 1
|
|
55
54
|
# Number of heartbeats between cleaning up worker processes (approx)
|
|
56
55
|
WORKER_CLEANUP_INTERVAL = 100
|
|
56
|
+
# Number of hearbeats between rechecking ignored tasks.
|
|
57
|
+
IGNORED_TASKS_CLEANUP_INTERVAL = 100
|
|
57
58
|
# Threshold time in seconds of an unblocked task before we consider a queue stalled
|
|
58
59
|
THRESHOLD_UNBLOCKED_WAITING_TIME = 5
|
|
59
60
|
|
|
@@ -66,6 +67,9 @@ class PulpcoreWorker:
|
|
|
66
67
|
self.wakeup_handle = False
|
|
67
68
|
self.cancel_task = False
|
|
68
69
|
|
|
70
|
+
self.ignored_task_ids = []
|
|
71
|
+
self.ignored_task_countdown = IGNORED_TASKS_CLEANUP_INTERVAL
|
|
72
|
+
|
|
69
73
|
self.auxiliary = auxiliary
|
|
70
74
|
self.task = None
|
|
71
75
|
self.name = f"{os.getpid()}@{socket.getfqdn()}"
|
|
@@ -73,13 +77,10 @@ class PulpcoreWorker:
|
|
|
73
77
|
self.last_metric_heartbeat = timezone.now()
|
|
74
78
|
self.versions = {app.label: app.version for app in pulp_plugin_configs()}
|
|
75
79
|
self.cursor = connection.cursor()
|
|
76
|
-
|
|
77
|
-
self.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
except IntegrityError:
|
|
81
|
-
_logger.error(f"A worker with name {self.name} already exists in the database.")
|
|
82
|
-
exit(1)
|
|
80
|
+
self.app_status = AppStatus.objects.create(
|
|
81
|
+
name=self.name, app_type="worker", versions=self.versions
|
|
82
|
+
)
|
|
83
|
+
|
|
83
84
|
# This defaults to immediate task cancellation.
|
|
84
85
|
# It will be set into the future on moderately graceful worker shutdown,
|
|
85
86
|
# and set to None for fully graceful shutdown.
|
|
@@ -152,6 +153,10 @@ class PulpcoreWorker:
|
|
|
152
153
|
if notification.payload == str(self.task.pk):
|
|
153
154
|
self.cancel_task = True
|
|
154
155
|
|
|
156
|
+
def shutdown(self):
|
|
157
|
+
self.app_status.delete()
|
|
158
|
+
_logger.info(_("Worker %s was shut down."), self.name)
|
|
159
|
+
|
|
155
160
|
def handle_worker_heartbeat(self):
|
|
156
161
|
"""
|
|
157
162
|
Update worker heartbeat records.
|
|
@@ -174,9 +179,13 @@ class PulpcoreWorker:
|
|
|
174
179
|
self.shutdown_requested = True
|
|
175
180
|
self.cancel_task = True
|
|
176
181
|
|
|
177
|
-
def
|
|
178
|
-
|
|
179
|
-
|
|
182
|
+
def cleanup_ignored_tasks(self):
|
|
183
|
+
for pk in (
|
|
184
|
+
Task.objects.filter(pk__in=self.ignored_task_ids)
|
|
185
|
+
.exclude(state__in=TASK_INCOMPLETE_STATES)
|
|
186
|
+
.values_list("pk", flat=True)
|
|
187
|
+
):
|
|
188
|
+
self.ignored_task_ids.remove(pk)
|
|
180
189
|
|
|
181
190
|
def worker_cleanup(self):
|
|
182
191
|
qs = AppStatus.objects.older_than(age=timedelta(days=7))
|
|
@@ -198,6 +207,11 @@ class PulpcoreWorker:
|
|
|
198
207
|
def beat(self):
|
|
199
208
|
if self.app_status.last_heartbeat < timezone.now() - self.heartbeat_period:
|
|
200
209
|
self.handle_worker_heartbeat()
|
|
210
|
+
if self.ignored_task_ids:
|
|
211
|
+
self.ignored_task_countdown -= 1
|
|
212
|
+
if self.ignored_task_countdown <= 0:
|
|
213
|
+
self.ignored_task_countdown = IGNORED_TASKS_CLEANUP_INTERVAL
|
|
214
|
+
self.cleanup_ignored_tasks()
|
|
201
215
|
if not self.auxiliary:
|
|
202
216
|
self.worker_cleanup_countdown -= 1
|
|
203
217
|
if self.worker_cleanup_countdown <= 0:
|
|
@@ -217,15 +231,10 @@ class PulpcoreWorker:
|
|
|
217
231
|
|
|
218
232
|
This function must only be called while holding the lock for that task. It is a no-op if
|
|
219
233
|
the task is neither in "running" nor "canceling" state.
|
|
220
|
-
|
|
221
|
-
Return ``True`` if the task was actually canceled, ``False`` otherwise.
|
|
222
234
|
"""
|
|
223
235
|
# A task is considered abandoned when in running state, but no worker holds its lock
|
|
224
236
|
domain = task.pulp_domain
|
|
225
|
-
|
|
226
|
-
task.set_canceling()
|
|
227
|
-
except RuntimeError:
|
|
228
|
-
return False
|
|
237
|
+
task.set_canceling()
|
|
229
238
|
if reason:
|
|
230
239
|
_logger.info(
|
|
231
240
|
"Cleaning up task %s in domain: %s and marking as %s. Reason: %s",
|
|
@@ -245,10 +254,8 @@ class PulpcoreWorker:
|
|
|
245
254
|
task.set_canceled(final_state=final_state, reason=reason)
|
|
246
255
|
if task.reserved_resources_record:
|
|
247
256
|
self.notify_workers(TASK_WAKEUP_UNBLOCK)
|
|
248
|
-
return True
|
|
249
257
|
|
|
250
258
|
def is_compatible(self, task):
|
|
251
|
-
domain = task.pulp_domain
|
|
252
259
|
unmatched_versions = [
|
|
253
260
|
f"task: {label}>={version} worker: {self.versions.get(label)}"
|
|
254
261
|
for label, version in task.versions.items()
|
|
@@ -256,6 +263,7 @@ class PulpcoreWorker:
|
|
|
256
263
|
or parse_version(self.versions[label]) < parse_version(version)
|
|
257
264
|
]
|
|
258
265
|
if unmatched_versions:
|
|
266
|
+
domain = task.pulp_domain # Hidden db roundtrip
|
|
259
267
|
_logger.info(
|
|
260
268
|
_("Incompatible versions to execute task %s in domain: %s by worker %s: %s"),
|
|
261
269
|
task.pk,
|
|
@@ -361,70 +369,6 @@ class PulpcoreWorker:
|
|
|
361
369
|
|
|
362
370
|
return count
|
|
363
371
|
|
|
364
|
-
def iter_tasks(self):
|
|
365
|
-
"""Iterate over ready tasks and yield each task while holding the lock."""
|
|
366
|
-
while not self.shutdown_requested:
|
|
367
|
-
# When batching this query, be sure to use "pulp_created" as a cursor.
|
|
368
|
-
for task in Task.objects.filter(
|
|
369
|
-
state__in=TASK_INCOMPLETE_STATES,
|
|
370
|
-
unblocked_at__isnull=False,
|
|
371
|
-
app_lock__isnull=True,
|
|
372
|
-
).order_by("-immediate", F("pulp_created") + Value(timedelta(seconds=8)) * Random()):
|
|
373
|
-
# This code will only be called if we acquired the lock successfully.
|
|
374
|
-
# The lock will be automatically be released at the end of the block.
|
|
375
|
-
with contextlib.suppress(AdvisoryLockError), task:
|
|
376
|
-
# Check if someone else changed the task before we got the lock.
|
|
377
|
-
task.refresh_from_db()
|
|
378
|
-
if task.state not in TASK_INCOMPLETE_STATES:
|
|
379
|
-
continue
|
|
380
|
-
# We got the advisory lock (OLD) now try to get the app_lock (NEW).
|
|
381
|
-
rows = Task.objects.filter(pk=task.pk, app_lock=None).update(
|
|
382
|
-
app_lock=AppStatus.objects.current()
|
|
383
|
-
)
|
|
384
|
-
if rows == 0:
|
|
385
|
-
_logger.error(
|
|
386
|
-
"Acquired advisory lock but missed the app_lock for the task. "
|
|
387
|
-
"This should only happen during the upgrade phase to the new app_lock."
|
|
388
|
-
f"Task: {task.pk=}, {task.state=}, {task.app_lock=}."
|
|
389
|
-
)
|
|
390
|
-
continue
|
|
391
|
-
try:
|
|
392
|
-
if task.state == TASK_STATES.CANCELING:
|
|
393
|
-
# No worker picked this task up before being canceled.
|
|
394
|
-
if self.cancel_abandoned_task(task, TASK_STATES.CANCELED):
|
|
395
|
-
# Continue looking for the next task without considering this
|
|
396
|
-
# tasks resources, as we just released them.
|
|
397
|
-
continue
|
|
398
|
-
if task.state == TASK_STATES.RUNNING:
|
|
399
|
-
# A running task without a lock must be abandoned.
|
|
400
|
-
if self.cancel_abandoned_task(
|
|
401
|
-
task, TASK_STATES.FAILED, "Worker has gone missing."
|
|
402
|
-
):
|
|
403
|
-
# Continue looking for the next task without considering this
|
|
404
|
-
# tasks resources, as we just released them.
|
|
405
|
-
continue
|
|
406
|
-
|
|
407
|
-
# This statement is using lazy evaluation.
|
|
408
|
-
if (
|
|
409
|
-
task.state == TASK_STATES.WAITING
|
|
410
|
-
and task.unblocked_at is not None
|
|
411
|
-
and self.is_compatible(task)
|
|
412
|
-
):
|
|
413
|
-
yield task
|
|
414
|
-
# Start from the top of the Task list.
|
|
415
|
-
break
|
|
416
|
-
finally:
|
|
417
|
-
rows = Task.objects.filter(
|
|
418
|
-
pk=task.pk, app_lock=AppStatus.objects.current()
|
|
419
|
-
).update(app_lock=None)
|
|
420
|
-
if rows != 1:
|
|
421
|
-
raise RuntimeError(
|
|
422
|
-
"Something other than us is messing around with locks."
|
|
423
|
-
)
|
|
424
|
-
else:
|
|
425
|
-
# No task found in the for-loop
|
|
426
|
-
break
|
|
427
|
-
|
|
428
372
|
def sleep(self):
|
|
429
373
|
"""Wait for signals on the wakeup channel while heart beating."""
|
|
430
374
|
|
|
@@ -533,6 +477,44 @@ class PulpcoreWorker:
|
|
|
533
477
|
self.notify_workers(TASK_WAKEUP_UNBLOCK)
|
|
534
478
|
self.task = None
|
|
535
479
|
|
|
480
|
+
def fetch_task(self):
|
|
481
|
+
"""
|
|
482
|
+
Fetch an available unblocked task and set the app_lock to this process.
|
|
483
|
+
"""
|
|
484
|
+
# The PostgreSQL returning logic cannot be represented in Django ORM.
|
|
485
|
+
# Also I doubt that rewriting this in ORM makes it any more readable.
|
|
486
|
+
query = """
|
|
487
|
+
UPDATE core_task
|
|
488
|
+
SET app_lock_id = %s
|
|
489
|
+
WHERE pulp_id IN (
|
|
490
|
+
SELECT pulp_id FROM core_task
|
|
491
|
+
WHERE
|
|
492
|
+
state = ANY(%s)
|
|
493
|
+
AND unblocked_at IS NOT NULL
|
|
494
|
+
AND app_lock_id IS NULL
|
|
495
|
+
AND NOT pulp_id = ANY(%s)
|
|
496
|
+
ORDER BY immediate DESC, pulp_created + '8 s'::interval * random()
|
|
497
|
+
LIMIT 1
|
|
498
|
+
FOR UPDATE SKIP LOCKED
|
|
499
|
+
)
|
|
500
|
+
RETURNING
|
|
501
|
+
pulp_id,
|
|
502
|
+
state,
|
|
503
|
+
unblocked_at,
|
|
504
|
+
versions,
|
|
505
|
+
pulp_domain_id,
|
|
506
|
+
reserved_resources_record
|
|
507
|
+
"""
|
|
508
|
+
qs = Task.objects.raw(
|
|
509
|
+
query,
|
|
510
|
+
[
|
|
511
|
+
self.app_status.pulp_id,
|
|
512
|
+
list(TASK_INCOMPLETE_STATES),
|
|
513
|
+
self.ignored_task_ids,
|
|
514
|
+
],
|
|
515
|
+
)
|
|
516
|
+
return next(iter(qs), None)
|
|
517
|
+
|
|
536
518
|
def handle_unblocked_tasks(self):
|
|
537
519
|
"""Pick and supervise tasks until there are no more available tasks.
|
|
538
520
|
|
|
@@ -540,14 +522,34 @@ class PulpcoreWorker:
|
|
|
540
522
|
would go to sleep and wouldn't be able to know about the unhandled task until
|
|
541
523
|
an external wakeup event occurs (e.g., new worker startup or new task gets in).
|
|
542
524
|
"""
|
|
543
|
-
|
|
544
|
-
while keep_looping and not self.shutdown_requested:
|
|
525
|
+
while not self.shutdown_requested:
|
|
545
526
|
# Clear pending wakeups. We are about to handle them anyway.
|
|
546
527
|
self.wakeup_handle = False
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
528
|
+
|
|
529
|
+
task = self.fetch_task()
|
|
530
|
+
if task is None:
|
|
531
|
+
# No task found
|
|
532
|
+
break
|
|
533
|
+
try:
|
|
534
|
+
if task.state == TASK_STATES.CANCELING:
|
|
535
|
+
# No worker picked this task up before being canceled.
|
|
536
|
+
# Or the worker disappeared before handling the canceling.
|
|
537
|
+
self.cancel_abandoned_task(task, TASK_STATES.CANCELED)
|
|
538
|
+
elif task.state == TASK_STATES.RUNNING:
|
|
539
|
+
# A running task without a lock must be abandoned.
|
|
540
|
+
self.cancel_abandoned_task(task, TASK_STATES.FAILED, "Worker has gone missing.")
|
|
541
|
+
elif task.state == TASK_STATES.WAITING and self.is_compatible(task):
|
|
542
|
+
self.supervise_task(task)
|
|
543
|
+
else:
|
|
544
|
+
# Probably incompatible, but for whatever reason we didn't pick it up this time,
|
|
545
|
+
# we don't need to look at it ever again.
|
|
546
|
+
self.ignored_task_ids.append(task.pk)
|
|
547
|
+
finally:
|
|
548
|
+
rows = Task.objects.filter(pk=task.pk, app_lock=AppStatus.objects.current()).update(
|
|
549
|
+
app_lock=None
|
|
550
|
+
)
|
|
551
|
+
if rows != 1:
|
|
552
|
+
raise RuntimeError("Something other than us is messing around with locks.")
|
|
551
553
|
|
|
552
554
|
def _record_unblocked_waiting_tasks_metric(self):
|
|
553
555
|
now = timezone.now()
|
|
@@ -6,7 +6,7 @@ from jsonschema import validate
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
STATUS = {
|
|
9
|
-
"$schema": "
|
|
9
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
10
10
|
"title": "Pulp 3 status API schema",
|
|
11
11
|
"description": ("Derived from Pulp's actual behaviour and various Pulp issues."),
|
|
12
12
|
"type": "object",
|
|
@@ -158,7 +158,9 @@ def test_upload_response(
|
|
|
158
158
|
{"offset": 0, "size": 6291456},
|
|
159
159
|
{"offset": 6291456, "size": 4194304},
|
|
160
160
|
]
|
|
161
|
-
sorted_chunks_response = sorted(
|
|
161
|
+
sorted_chunks_response = sorted(
|
|
162
|
+
[c.model_dump() for c in upload.chunks], key=lambda i: i["offset"]
|
|
163
|
+
)
|
|
162
164
|
assert sorted_chunks_response == expected_chunks
|
|
163
165
|
|
|
164
166
|
|
|
@@ -85,7 +85,9 @@ def test_crud_publication_distribution(
|
|
|
85
85
|
new_name = str(uuid4())
|
|
86
86
|
distribution.name = new_name
|
|
87
87
|
monitor_task(
|
|
88
|
-
file_bindings.DistributionsFileApi.update(
|
|
88
|
+
file_bindings.DistributionsFileApi.update(
|
|
89
|
+
distribution.pulp_href, distribution.model_dump()
|
|
90
|
+
).task
|
|
89
91
|
)
|
|
90
92
|
distribution = file_bindings.DistributionsFileApi.read(distribution.pulp_href)
|
|
91
93
|
assert distribution.name == new_name
|
|
@@ -94,7 +96,9 @@ def test_crud_publication_distribution(
|
|
|
94
96
|
new_base_path = str(uuid4())
|
|
95
97
|
distribution.base_path = new_base_path
|
|
96
98
|
monitor_task(
|
|
97
|
-
file_bindings.DistributionsFileApi.update(
|
|
99
|
+
file_bindings.DistributionsFileApi.update(
|
|
100
|
+
distribution.pulp_href, distribution.model_dump()
|
|
101
|
+
).task
|
|
98
102
|
)
|
|
99
103
|
distribution = file_bindings.DistributionsFileApi.read(distribution.pulp_href)
|
|
100
104
|
assert distribution.base_path == new_base_path
|
|
@@ -154,5 +154,5 @@ def get_from_url(url, auth=None, headers=None):
|
|
|
154
154
|
|
|
155
155
|
async def _get_from_url(url, auth=None, headers=None):
|
|
156
156
|
async with aiohttp.ClientSession(auth=auth) as session:
|
|
157
|
-
async with session.get(url,
|
|
157
|
+
async with session.get(url, ssl=False, headers=headers) as response:
|
|
158
158
|
return response
|
|
@@ -10,7 +10,10 @@ def run_middleware(aiohttp_client):
|
|
|
10
10
|
async def _run_middleware(provider):
|
|
11
11
|
app = web.Application(middlewares=[instrumentation(provider=provider)])
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
async def handler(req):
|
|
14
|
+
return web.Response()
|
|
15
|
+
|
|
16
|
+
app.router.add_get("/", handler)
|
|
14
17
|
|
|
15
18
|
client = await aiohttp_client(app)
|
|
16
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
import sys
|
|
3
|
-
from pulpcore.app.models import Task, ProgressReport
|
|
3
|
+
from pulpcore.app.models import AppStatus, Task, ProgressReport
|
|
4
4
|
from pulpcore.constants import TASK_STATES
|
|
5
5
|
|
|
6
6
|
|
|
@@ -13,8 +13,10 @@ from pulpcore.constants import TASK_STATES
|
|
|
13
13
|
],
|
|
14
14
|
)
|
|
15
15
|
@pytest.mark.django_db
|
|
16
|
-
def test_report_state_changes(to_state, use_canceled):
|
|
17
|
-
|
|
16
|
+
def test_report_state_changes(monkeypatch, to_state, use_canceled):
|
|
17
|
+
monkeypatch.setattr(AppStatus.objects, "_current_app_status", None)
|
|
18
|
+
app_status = AppStatus.objects.create(app_type="worker", name="test_runner")
|
|
19
|
+
task = Task.objects.create(name="test", state=TASK_STATES.RUNNING, app_lock=app_status)
|
|
18
20
|
reports = {}
|
|
19
21
|
for state in vars(TASK_STATES):
|
|
20
22
|
report = ProgressReport(message="test", code="test", state=state, task=task)
|
|
@@ -118,7 +118,7 @@ def queue_dc(in_q, downloader_mock):
|
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
@pytest_asyncio.fixture
|
|
121
|
-
async def download_task(
|
|
121
|
+
async def download_task(in_q, out_q):
|
|
122
122
|
async def _download_task():
|
|
123
123
|
"""
|
|
124
124
|
A coroutine running the downloader stage with a mocked ProgressReport.
|
|
@@ -133,7 +133,7 @@ async def download_task(event_loop, in_q, out_q):
|
|
|
133
133
|
await ad()
|
|
134
134
|
return pb.return_value.__aenter__.return_value.done
|
|
135
135
|
|
|
136
|
-
task =
|
|
136
|
+
task = asyncio.get_event_loop().create_task(_download_task())
|
|
137
137
|
yield task
|
|
138
138
|
if not task.done():
|
|
139
139
|
task.cancel()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import pytest
|
|
2
|
-
from pytest_django.asserts import
|
|
2
|
+
from pytest_django.asserts import assertQuerySetEqual
|
|
3
3
|
import unittest
|
|
4
4
|
|
|
5
5
|
from django.http import Http404, QueryDict
|
|
@@ -23,7 +23,7 @@ def test_adds_filters():
|
|
|
23
23
|
queryset = viewset.get_queryset()
|
|
24
24
|
expected = models.RepositoryVersion.objects.filter(repository__pk=repo.pk)
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
assertQuerySetEqual(queryset, expected)
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
@pytest.mark.django_db
|
|
@@ -38,7 +38,7 @@ def test_does_not_add_filters():
|
|
|
38
38
|
queryset = viewset.get_queryset()
|
|
39
39
|
expected = models.Repository.objects.all()
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
assertQuerySetEqual(queryset, expected)
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
def test_must_define_serializer_class():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pulpcore
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.89.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
|
|
@@ -46,7 +46,7 @@ Requires-Dist: opentelemetry-api<1.37,>=1.27.0
|
|
|
46
46
|
Requires-Dist: opentelemetry-sdk<1.37,>=1.27.0
|
|
47
47
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http<1.37,>=1.27.0
|
|
48
48
|
Requires-Dist: protobuf<7.0,>=4.21.1
|
|
49
|
-
Requires-Dist: pulp-glue<0.
|
|
49
|
+
Requires-Dist: pulp-glue<0.37,>=0.28.0
|
|
50
50
|
Requires-Dist: pygtrie<=2.5.0,>=2.5
|
|
51
51
|
Requires-Dist: psycopg[binary]<3.3,>=3.1.8
|
|
52
52
|
Requires-Dist: pyparsing<3.3,>=3.1.0
|
|
@@ -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=
|
|
3
|
+
pulp_certguard/app/__init__.py,sha256=v_a1q8VcjywdotIrzqCkXvyBTyZe-ktKVmAKWLZuysk,297
|
|
4
4
|
pulp_certguard/app/models.py,sha256=YLEhBtZM4hetekVZ_GTnbLlWD6CkIQw2B3ILwXRcq-s,7483
|
|
5
5
|
pulp_certguard/app/serializers.py,sha256=9IxlQiy783RdKF9oI1mrYS4haG5Boy2DOjfP_eJtMLY,1726
|
|
6
6
|
pulp_certguard/app/viewsets.py,sha256=1_gNmsWyOT8kcOiGVkn4-wrtAjZO4wC8q0-aoEsCpjI,697
|
|
@@ -51,7 +51,7 @@ pulp_certguard/tests/unit/test_rhsm_check_path.py,sha256=Q1CsXnUgD7ELvtolPeumyNr
|
|
|
51
51
|
pulp_file/__init__.py,sha256=0vOCXofR6Eyxkg4y66esnOGPeESCe23C1cNBHj56w44,61
|
|
52
52
|
pulp_file/manifest.py,sha256=1WwIOJrPSkFcmkRm7CkWifVOCoZvo_nnANgce6uuG7U,3796
|
|
53
53
|
pulp_file/pytest_plugin.py,sha256=l1PvTxUi5D3uJy4SnHWNhr-otWEYNcm-kc5nSqVJg0Y,10646
|
|
54
|
-
pulp_file/app/__init__.py,sha256=
|
|
54
|
+
pulp_file/app/__init__.py,sha256=4YvCEsDnvVl-nX3X-bdvrlFLtBNQp-I1dTIhrtMMByY,292
|
|
55
55
|
pulp_file/app/modelresource.py,sha256=v-m-_bBEsfr8wG0TI5ffx1TuKUy2-PsirhuQz4XXF-0,1063
|
|
56
56
|
pulp_file/app/models.py,sha256=QsrVg_2uKqnR89sLN2Y7Zy260_nLIcUfa94uZowlmFw,4571
|
|
57
57
|
pulp_file/app/replica.py,sha256=OtNWVmdFUgNTYhPttftVNQnSrnvx2_hnrJgtW_G0Vrg,1894
|
|
@@ -96,7 +96,7 @@ pulpcore/pytest_plugin.py,sha256=fy9vz5-bw30T7f4jxDtNIgF7L_0MJ_q7KIAzpvizvnY,382
|
|
|
96
96
|
pulpcore/responses.py,sha256=mIGKmdCfTSoZxbFu4yIH1xbdLx1u5gqt3D99LTamcJg,6125
|
|
97
97
|
pulpcore/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
98
98
|
pulpcore/app/access_policy.py,sha256=5vCKy6WoHtIt1_-eS5vMaZ7CmR4G-CIpsrB8yT-d88Q,6079
|
|
99
|
-
pulpcore/app/apps.py,sha256=
|
|
99
|
+
pulpcore/app/apps.py,sha256=zJJxHhtTfq3Q6HhPGyl4Sp_Y3hMGKiedm8Dkl6VTPos,17412
|
|
100
100
|
pulpcore/app/authentication.py,sha256=1LIJW6HIQQlZrliHy__jdzkDEh6Oj7xKgd0V-vRcDus,2855
|
|
101
101
|
pulpcore/app/checks.py,sha256=jbfTF7nmftBbky4AQXHigpyCaGydKasvRUXsd72JZVg,1946
|
|
102
102
|
pulpcore/app/entrypoint.py,sha256=GYEq4GjglQZhFlU3865AT_H0nPypDKJAsf8qdyR4tPY,4985
|
|
@@ -115,7 +115,7 @@ pulpcore/app/redis_connection.py,sha256=VTdG0ulXuyESjYV6SJdG_jLzkLZH-MlLcD6pielw
|
|
|
115
115
|
pulpcore/app/replica.py,sha256=rGE14OBaR_FKxmHL7NMxf_OizMyS-90IPsMRo_j9YRI,11474
|
|
116
116
|
pulpcore/app/response.py,sha256=hYH_jSBrxmRsBr2bknmXE1qfs2g8JjDTXYcQ5ZWlF_c,1950
|
|
117
117
|
pulpcore/app/role_util.py,sha256=84HSt8_9fxB--dtfSyg_TumVgOdyBbyP6rBaiAfTpOU,22393
|
|
118
|
-
pulpcore/app/settings.py,sha256=
|
|
118
|
+
pulpcore/app/settings.py,sha256=tjq6rQW5_uDgiIJVwMTTuJDfXR32QK0gl9UqPDYPhJQ,21876
|
|
119
119
|
pulpcore/app/urls.py,sha256=0gdI74CAdycJStXSw1gknviDGe3J3k0UhS4J8RYa5dg,8120
|
|
120
120
|
pulpcore/app/util.py,sha256=nYF6nZXgqVk4U1QeZEpWYX-wqitGSGAJip6W78IfXUk,24432
|
|
121
121
|
pulpcore/app/wsgi.py,sha256=7rpZ_1NHEN_UfeNZCj8206bas1WeqRkHnGdxpd7rdDI,492
|
|
@@ -191,6 +191,7 @@ pulpcore/app/migrations/0139_task_app_lock.py,sha256=Dtu_om_zFplrPr8DageoiXOWUiO
|
|
|
191
191
|
pulpcore/app/migrations/0140_require_appstatus_zdu.py,sha256=KrSyuQDg6Wd_M4RetDfGS9FDSMkHJxjh6BijR3Hro78,305
|
|
192
192
|
pulpcore/app/migrations/0141_alter_appstatus_name.py,sha256=bkNO_1RrCFn5VQWTNRpz5LhZyWXluLdVekPfDGEHFB8,375
|
|
193
193
|
pulpcore/app/migrations/0142_task_result.py,sha256=aoq81R1-mPylVQr7pQy5Bf2Yfz5ssjDqmSXUjv2rPHg,514
|
|
194
|
+
pulpcore/app/migrations/0143_require_app_lock_zdu.py,sha256=RX6bk1VULScY9K5fyCejPBVbWojCVdRSB39WuLwgdIc,303
|
|
194
195
|
pulpcore/app/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
195
196
|
pulpcore/app/models/__init__.py,sha256=P_2UnLmtQYbASWrm8elO2Zm_od-LXVqQKnjCwYFlZW0,3552
|
|
196
197
|
pulpcore/app/models/access_policy.py,sha256=o4L41RGoZ5UMmh5UeeenmadD5MJgShguphgd4eAVxQA,6071
|
|
@@ -211,7 +212,7 @@ pulpcore/app/models/repository.py,sha256=SIc21Gex6okxI7OCfHEGIpXpGlypG3z9IgMt5-m
|
|
|
211
212
|
pulpcore/app/models/role.py,sha256=dZklNd2VeAw4cT6dyJ7SyTBt9sZvdqakY86wXGAY3vU,3287
|
|
212
213
|
pulpcore/app/models/status.py,sha256=WniovQQFdlR0TN-XWd_0FnBRiwzKxDyODyD-5VUgXjo,8290
|
|
213
214
|
pulpcore/app/models/storage.py,sha256=2b-DQWaO31NqjV6FiISALegND-sQZAU7BVAsduUvm3o,6780
|
|
214
|
-
pulpcore/app/models/task.py,sha256=
|
|
215
|
+
pulpcore/app/models/task.py,sha256=0SLfpkyIvyJ1WAWKHl_eanjjincU0UUGyws1k0YTiys,16031
|
|
215
216
|
pulpcore/app/models/upload.py,sha256=3njXT2rrVJwBjEDegvqcLD9_7cPnnl974lhbAhikEp8,3004
|
|
216
217
|
pulpcore/app/models/vulnerability_report.py,sha256=DDAUjDaW3Kn9KPBkBl94u4EuQy8UIu5wKbmE5kMkhWE,1238
|
|
217
218
|
pulpcore/app/protobuf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -286,7 +287,7 @@ pulpcore/cache/cache.py,sha256=d8GMlvjeGG9MOMdi5_9029WpGCKH8Y5q9b2lt3wSREo,17371
|
|
|
286
287
|
pulpcore/content/__init__.py,sha256=mHYi85Hy-IhG50AR-jICk9pIiMUatHJx5wO1dFJkn9k,4000
|
|
287
288
|
pulpcore/content/authentication.py,sha256=lEZBkXBBBkIdtFMCSpHDD7583M0bO-zsZNYXTmpr4k8,3235
|
|
288
289
|
pulpcore/content/entrypoint.py,sha256=DiQTQzfcUiuyl37uvy6Wpa_7kr8t79ekpMHr31MDL2s,2132
|
|
289
|
-
pulpcore/content/handler.py,sha256=
|
|
290
|
+
pulpcore/content/handler.py,sha256=EubizF5HP5QK_N5eMe8sHIyUZT3ipVhaQJ-NYb1dr5g,56959
|
|
290
291
|
pulpcore/content/instrumentation.py,sha256=H0N0GWzvOPGGjFi6eIbGW3mcvagfnAfazccTh-BZVmE,1426
|
|
291
292
|
pulpcore/download/__init__.py,sha256=s3Wh2GKdsmbUooVIR6wSvhYVIhpaTbtfR3Ar1OJhC7s,154
|
|
292
293
|
pulpcore/download/base.py,sha256=4KCAYnV8jSOX078ETwlfwNZGY3xCBF9yy866tyGKAzE,13095
|
|
@@ -339,12 +340,12 @@ pulpcore/tasking/_util.py,sha256=fPW4k1nUa_NZ0ywy_A15Fuiejo5stY58abPbZTXw5t8,990
|
|
|
339
340
|
pulpcore/tasking/entrypoint.py,sha256=eAypZD4ORoNOrmBeMdbwO9p6GSQ59bMvZ3TrbnE0czw,1305
|
|
340
341
|
pulpcore/tasking/kafka.py,sha256=76z4DzeXM1WL5uu1HlKnduWeLO3-b-czvGBXdWR6054,3845
|
|
341
342
|
pulpcore/tasking/storage.py,sha256=zQkwlpC_FDQtmZGZ8vKwHqxvD6CLO_gAS4Q7wijZE-k,3106
|
|
342
|
-
pulpcore/tasking/tasks.py,sha256=
|
|
343
|
-
pulpcore/tasking/worker.py,sha256=
|
|
343
|
+
pulpcore/tasking/tasks.py,sha256=MyqqjkFbl3GSkfLu1MKEe7bJiGRn924_uAa4l18QSSk,12459
|
|
344
|
+
pulpcore/tasking/worker.py,sha256=vuQDKmxWxkeWCqNrye5MUlx2qSFn3W8sMJumEu_kSPE,26596
|
|
344
345
|
pulpcore/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
345
346
|
pulpcore/tests/functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
346
347
|
pulpcore/tests/functional/content_with_coverage.py,sha256=gQK8himy32s9O9vpXdgoM6-_z2KySaXm5rTga9z0jGI,260
|
|
347
|
-
pulpcore/tests/functional/utils.py,sha256=
|
|
348
|
+
pulpcore/tests/functional/utils.py,sha256=FgqQwcciV8gFEfYB-RFO4bwAYp8FHDRAwRJGIl4TL-E,4692
|
|
348
349
|
pulpcore/tests/functional/api/__init__.py,sha256=ougP6XAtutbcm8kwvJN5i51KEeQZT2-A7u-Y3so2mi4,57
|
|
349
350
|
pulpcore/tests/functional/api/test_access_policy.py,sha256=R2vPadltPVpOL61LiarfOOl7W7m3EB8LXlmwRQJcVxg,3984
|
|
350
351
|
pulpcore/tests/functional/api/test_api_docs.py,sha256=72CB6jRB1Inubj0ZdkV9FsFBbu4YQDqn1ITNvemnAxg,1133
|
|
@@ -364,10 +365,10 @@ pulpcore/tests/functional/api/test_role.py,sha256=JnhVMs22IP3ngdwu4P0vVgJuGGkqjK
|
|
|
364
365
|
pulpcore/tests/functional/api/test_root_endpoint.py,sha256=CSp68Z6APY9pCvu-JtX820TnF9t2MllAxRGT3ekw5Fs,244
|
|
365
366
|
pulpcore/tests/functional/api/test_scoping.py,sha256=uiLOsx5_7puRMcvrpPKEYQziqluPNv9vstySfoD7Edc,2671
|
|
366
367
|
pulpcore/tests/functional/api/test_signing_service.py,sha256=yr1HXBrNoliBHJNAGAN4PAN0eBKPIvAQP-uMoMSrO_I,222
|
|
367
|
-
pulpcore/tests/functional/api/test_status.py,sha256=
|
|
368
|
+
pulpcore/tests/functional/api/test_status.py,sha256=S4lWuemCLwM4rC3fCCZEehGMGypirPo5fnT7bkJuYxI,5384
|
|
368
369
|
pulpcore/tests/functional/api/test_task_purge.py,sha256=Av4DrUdCqf-JegfoP1pkY4B-teoUzYd1LBZKAhDa-08,7273
|
|
369
370
|
pulpcore/tests/functional/api/test_tasking.py,sha256=4QPkdPVt1L01GzXyCWDmKwQbCPATSj-UznjDUFt609U,21204
|
|
370
|
-
pulpcore/tests/functional/api/test_upload.py,sha256=
|
|
371
|
+
pulpcore/tests/functional/api/test_upload.py,sha256=dG9G6jLl-qGqC87LWJfkDJ1s3ppDdeanTmbbIVQnYQQ,6814
|
|
371
372
|
pulpcore/tests/functional/api/test_users_groups.py,sha256=YFG0xtyJuIRraczR7ERl_UNS7dlJfKd2eUmXgD1lLBU,2926
|
|
372
373
|
pulpcore/tests/functional/api/test_workers.py,sha256=XJrQdxt0BpMeMVOdTyzcTEMk5bB8XC4rA8U580HnzBc,4691
|
|
373
374
|
pulpcore/tests/functional/api/using_plugin/__init__.py,sha256=QyyfzgjLOi4n32G3o9aGH5eQDNjjD_qUpHLOZpPPZa4,80
|
|
@@ -380,7 +381,7 @@ pulpcore/tests/functional/api/using_plugin/test_content_path.py,sha256=fvqeptqo-
|
|
|
380
381
|
pulpcore/tests/functional/api/using_plugin/test_content_promotion.py,sha256=Co4ytrfpzklwgDdEthv45dsmrceRpqIQfLJlZWM6EBY,2388
|
|
381
382
|
pulpcore/tests/functional/api/using_plugin/test_contentguard.py,sha256=aMZf4g1uNHhWM7cAJa7bC49A-9uNLIphlr6sBkCOzi8,12894
|
|
382
383
|
pulpcore/tests/functional/api/using_plugin/test_crud_repos.py,sha256=4XJ7e_BnzOIBpdTFt2kpiZC_YEu2bBimFpxURKvQwfU,14334
|
|
383
|
-
pulpcore/tests/functional/api/using_plugin/test_distributions.py,sha256=
|
|
384
|
+
pulpcore/tests/functional/api/using_plugin/test_distributions.py,sha256=CeOMN4iTzATp_NJC0Bu2n8RFyQKiIk3y8hcfERQJcfk,11992
|
|
384
385
|
pulpcore/tests/functional/api/using_plugin/test_filesystemexport.py,sha256=s5C9lW5Q4gaY56d3Rsa-uadcn_3D7rWQ2CosowTe8_Y,6059
|
|
385
386
|
pulpcore/tests/functional/api/using_plugin/test_labels.py,sha256=LO45iAFel4SKB6R5InUouiifGu_eHMZnoMFmwI4cSyE,2463
|
|
386
387
|
pulpcore/tests/functional/api/using_plugin/test_migrate.py,sha256=DiCAessLO4B9jnTNkngczIdsHswNr73H4is_6H1Ue2I,4457
|
|
@@ -417,7 +418,7 @@ pulpcore/tests/unit/download/test_downloader_base.py,sha256=TYG_OPuyj-_N5L-zLTW1
|
|
|
417
418
|
pulpcore/tests/unit/download/test_downloader_factory.py,sha256=mumtIAtRg_dS2uQvOH3J5NXb9XuvQ53iWlBP5koZ_nM,1177
|
|
418
419
|
pulpcore/tests/unit/metrics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
419
420
|
pulpcore/tests/unit/metrics/conftest.py,sha256=pyA8wwLO-TsyERvYnwnF2_Ura0rvZbAmjSUzivcMrE4,620
|
|
420
|
-
pulpcore/tests/unit/metrics/test_aiohttp_instrumentation.py,sha256=
|
|
421
|
+
pulpcore/tests/unit/metrics/test_aiohttp_instrumentation.py,sha256=qQrO2LEutBrY182EHcsQVDsUSkpQrpV11rduR2XXR4w,616
|
|
421
422
|
pulpcore/tests/unit/metrics/test_django_instrumentation.py,sha256=vkUGm_Q0WCph6x-fWOX8bkpY7XFaNjqVKnJ2zWqu08Q,676
|
|
422
423
|
pulpcore/tests/unit/migration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
423
424
|
pulpcore/tests/unit/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -425,7 +426,7 @@ pulpcore/tests/unit/models/test_base.py,sha256=77hnxOFBJYMNbI1YGEaR5yj8VCapNGmEg
|
|
|
425
426
|
pulpcore/tests/unit/models/test_content.py,sha256=heU0vJKucPIp6py2Ww-eXLvhFopvmK8QjFgzt1jGnYQ,5599
|
|
426
427
|
pulpcore/tests/unit/models/test_remote.py,sha256=KxXwHdA-wj7D-ZpuVi33cLX43wkEeIzeqF9uMsJGt-k,2354
|
|
427
428
|
pulpcore/tests/unit/models/test_repository.py,sha256=ciwyo7dMl-dxlzHb55eQ-ohEEBPF3-GjbO23mMSccqQ,13791
|
|
428
|
-
pulpcore/tests/unit/models/test_task.py,sha256=
|
|
429
|
+
pulpcore/tests/unit/models/test_task.py,sha256=zkHNs2DYpJbl-nMNFXs21Pyvw9eSpmSIJFFFXK2dT90,1655
|
|
429
430
|
pulpcore/tests/unit/roles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
430
431
|
pulpcore/tests/unit/roles/test_roles.py,sha256=TkPPCLEHMaxfafsRf_3pc4Z3w8BPTyteY7rFkVo65GM,4973
|
|
431
432
|
pulpcore/tests/unit/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -437,13 +438,13 @@ pulpcore/tests/unit/serializers/test_pulpexport.py,sha256=gXn7E13X-SP0rFM0bUv8Pw
|
|
|
437
438
|
pulpcore/tests/unit/serializers/test_repository.py,sha256=eknsHlbHz1K0nqntDntltFLU2EunrSlXCgg3HrV9PTI,9288
|
|
438
439
|
pulpcore/tests/unit/serializers/test_user.py,sha256=lemDxBIDWKrfFmazl9DMW7-k3lQyWtD8uQCxNktHI3Q,3094
|
|
439
440
|
pulpcore/tests/unit/stages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
440
|
-
pulpcore/tests/unit/stages/test_artifactdownloader.py,sha256=
|
|
441
|
+
pulpcore/tests/unit/stages/test_artifactdownloader.py,sha256=DX6jHctGYbDhsnzQpXfEnAbcr-Q6_QWs6ETIZDJmSK4,12482
|
|
441
442
|
pulpcore/tests/unit/stages/test_stages.py,sha256=H1a2BQLjdZlZvcb_qULp62huZ1xy6ItTcthktVyGU0w,4735
|
|
442
443
|
pulpcore/tests/unit/viewsets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
443
|
-
pulpcore/tests/unit/viewsets/test_viewset_base.py,sha256=
|
|
444
|
-
pulpcore-3.
|
|
445
|
-
pulpcore-3.
|
|
446
|
-
pulpcore-3.
|
|
447
|
-
pulpcore-3.
|
|
448
|
-
pulpcore-3.
|
|
449
|
-
pulpcore-3.
|
|
444
|
+
pulpcore/tests/unit/viewsets/test_viewset_base.py,sha256=gmVIgE9o0tAdiF92HCNiJkb1joc8oEaG5rnzh5V1loc,4837
|
|
445
|
+
pulpcore-3.89.0.dist-info/licenses/LICENSE,sha256=dhnHU8rJXUdAIgIjveSKAyYG_KzN5eVG-bxETIGrNW0,17988
|
|
446
|
+
pulpcore-3.89.0.dist-info/METADATA,sha256=mS1LG2PZjuNRjuezug7aAhP2g2g32swvlibYJmpLYLE,4104
|
|
447
|
+
pulpcore-3.89.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
448
|
+
pulpcore-3.89.0.dist-info/entry_points.txt,sha256=OZven4wzXzQA5b5q9MpP4HUpIPPQCSvIOvkKtNInrK0,452
|
|
449
|
+
pulpcore-3.89.0.dist-info/top_level.txt,sha256=6h-Lm3FKQSaT_nL1KSxu_hBnzKE15bcvf_BoU-ea4CI,34
|
|
450
|
+
pulpcore-3.89.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|