pulpcore 3.83.1__py3-none-any.whl → 3.84.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/0134_task_insert_trigger.py +81 -0
- pulpcore/app/migrations/0135_task_pulp_task_resources_index.py +25 -0
- pulpcore/app/models/repository.py +39 -37
- pulpcore/app/models/task.py +7 -0
- pulpcore/app/settings.py +10 -2
- pulpcore/app/tasks/purge.py +8 -5
- pulpcore/constants.py +4 -0
- pulpcore/tasking/entrypoint.py +12 -2
- pulpcore/tasking/tasks.py +5 -30
- pulpcore/tasking/worker.py +77 -39
- pulpcore/tests/functional/api/test_login.py +62 -32
- {pulpcore-3.83.1.dist-info → pulpcore-3.84.0.dist-info}/METADATA +6 -5
- {pulpcore-3.83.1.dist-info → pulpcore-3.84.0.dist-info}/RECORD +20 -18
- {pulpcore-3.83.1.dist-info → pulpcore-3.84.0.dist-info}/WHEEL +0 -0
- {pulpcore-3.83.1.dist-info → pulpcore-3.84.0.dist-info}/entry_points.txt +0 -0
- {pulpcore-3.83.1.dist-info → pulpcore-3.84.0.dist-info}/licenses/LICENSE +0 -0
- {pulpcore-3.83.1.dist-info → pulpcore-3.84.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,81 @@
|
|
|
1
|
+
# Generated by Django 4.2.22 on 2025-06-06 14:32
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
from pulpcore.migrations import RequireVersion
|
|
5
|
+
|
|
6
|
+
# This migration is supposed to be zero downtime upgrade safe.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
TASK_INSERT_TRIGGER_UP = """
|
|
10
|
+
CREATE FUNCTION on_insert_timestamp_task()
|
|
11
|
+
RETURNS TRIGGER
|
|
12
|
+
LANGUAGE plpgsql
|
|
13
|
+
AS $$
|
|
14
|
+
DECLARE
|
|
15
|
+
res_list text[];
|
|
16
|
+
res_list_shared text[];
|
|
17
|
+
BEGIN
|
|
18
|
+
res_list := array_agg(q.res) FROM (SELECT regexp_replace(unnest(NEW.reserved_resources_record), '^shared:', '') res) AS q;
|
|
19
|
+
res_list_shared := array_agg(q.res) FROM (SELECT 'shared:' || unnest(res_list) AS res) AS q;
|
|
20
|
+
PERFORM pg_advisory_xact_lock(4711, q.id) FROM (SELECT hashtext(res) AS id FROM unnest(res_list) AS res ORDER BY id) AS q;
|
|
21
|
+
NEW.pulp_created = clock_timestamp();
|
|
22
|
+
IF NEW.pulp_created <= (
|
|
23
|
+
SELECT max(pulp_created) FROM core_task
|
|
24
|
+
WHERE
|
|
25
|
+
state NOT IN ('completed', 'failed', 'canceled', 'skipped')
|
|
26
|
+
AND
|
|
27
|
+
reserved_resources_record && (res_list || res_list_shared)
|
|
28
|
+
)
|
|
29
|
+
THEN
|
|
30
|
+
RAISE EXCEPTION 'Clock screw detected.';
|
|
31
|
+
END IF;
|
|
32
|
+
RETURN NEW;
|
|
33
|
+
END;
|
|
34
|
+
$$
|
|
35
|
+
;
|
|
36
|
+
|
|
37
|
+
CREATE FUNCTION on_update_timestamp_task()
|
|
38
|
+
RETURNS TRIGGER
|
|
39
|
+
LANGUAGE plpgsql
|
|
40
|
+
AS $$
|
|
41
|
+
BEGIN
|
|
42
|
+
-- This is mainly a safeguard to prevent old code from messing with the timestamp, now that the database is in charge.
|
|
43
|
+
RAISE EXCEPTION 'Updating pulp_created is not allowed.';
|
|
44
|
+
END;
|
|
45
|
+
$$
|
|
46
|
+
;
|
|
47
|
+
|
|
48
|
+
CREATE TRIGGER on_insert_timestamp_task_trigger
|
|
49
|
+
BEFORE INSERT
|
|
50
|
+
ON core_task
|
|
51
|
+
FOR EACH ROW
|
|
52
|
+
EXECUTE FUNCTION on_insert_timestamp_task()
|
|
53
|
+
;
|
|
54
|
+
|
|
55
|
+
CREATE TRIGGER on_update_timestamp_task_trigger
|
|
56
|
+
BEFORE UPDATE
|
|
57
|
+
ON core_task
|
|
58
|
+
FOR EACH ROW
|
|
59
|
+
WHEN (OLD.pulp_created <> NEW.pulp_created)
|
|
60
|
+
EXECUTE FUNCTION on_update_timestamp_task()
|
|
61
|
+
;
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
TASK_INSERT_TRIGGER_DOWN = """
|
|
65
|
+
DROP TRIGGER on_update_timestamp_task_trigger on core_task;
|
|
66
|
+
DROP TRIGGER on_insert_timestamp_task_trigger on core_task;
|
|
67
|
+
DROP FUNCTION on_update_timestamp_task;
|
|
68
|
+
DROP FUNCTION on_insert_timestamp_task;
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class Migration(migrations.Migration):
|
|
73
|
+
|
|
74
|
+
dependencies = [
|
|
75
|
+
("core", "0133_repositoryversion_content_ids"),
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
operations = [
|
|
79
|
+
RequireVersion("core", "3.82.1"),
|
|
80
|
+
migrations.RunSQL(sql=TASK_INSERT_TRIGGER_UP, reverse_sql=TASK_INSERT_TRIGGER_DOWN),
|
|
81
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Generated by Django 4.2.22 on 2025-07-07 11:07
|
|
2
|
+
|
|
3
|
+
import django.contrib.postgres.indexes
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
("core", "0134_task_insert_trigger"),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AddIndex(
|
|
15
|
+
model_name="task",
|
|
16
|
+
index=django.contrib.postgres.indexes.GinIndex(
|
|
17
|
+
condition=models.Q(
|
|
18
|
+
("state__in", ["completed", "failed", "canceled", "skipped"]), _negated=True
|
|
19
|
+
),
|
|
20
|
+
fields=["reserved_resources_record"],
|
|
21
|
+
name="pulp_task_resources_index",
|
|
22
|
+
opclasses=["array_ops"],
|
|
23
|
+
),
|
|
24
|
+
),
|
|
25
|
+
]
|
|
@@ -1064,28 +1064,29 @@ class RepositoryVersion(BaseModel):
|
|
|
1064
1064
|
)
|
|
1065
1065
|
repo_content = []
|
|
1066
1066
|
to_add = set(content.values_list("pk", flat=True)) - set(self._get_content_ids())
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1067
|
+
with transaction.atomic():
|
|
1068
|
+
if to_add:
|
|
1069
|
+
self.content_ids += list(to_add)
|
|
1070
|
+
self.save()
|
|
1071
|
+
|
|
1072
|
+
# Normalize representation if content has already been removed in this version and
|
|
1073
|
+
# is re-added: Undo removal by setting version_removed to None.
|
|
1074
|
+
for removed in batch_qs(self.removed().order_by("pk").values_list("pk", flat=True)):
|
|
1075
|
+
to_readd = to_add.intersection(set(removed))
|
|
1076
|
+
if to_readd:
|
|
1077
|
+
RepositoryContent.objects.filter(
|
|
1078
|
+
content__in=to_readd, repository=self.repository, version_removed=self
|
|
1079
|
+
).update(version_removed=None)
|
|
1080
|
+
to_add = to_add - to_readd
|
|
1081
|
+
|
|
1082
|
+
for content_pk in to_add:
|
|
1083
|
+
repo_content.append(
|
|
1084
|
+
RepositoryContent(
|
|
1085
|
+
repository=self.repository, content_id=content_pk, version_added=self
|
|
1086
|
+
)
|
|
1085
1087
|
)
|
|
1086
|
-
)
|
|
1087
1088
|
|
|
1088
|
-
|
|
1089
|
+
RepositoryContent.objects.bulk_create(repo_content)
|
|
1089
1090
|
|
|
1090
1091
|
def remove_content(self, content):
|
|
1091
1092
|
"""
|
|
@@ -1111,23 +1112,24 @@ class RepositoryVersion(BaseModel):
|
|
|
1111
1112
|
)
|
|
1112
1113
|
content_ids = set(self._get_content_ids())
|
|
1113
1114
|
to_remove = set(content.values_list("pk", flat=True))
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1115
|
+
with transaction.atomic():
|
|
1116
|
+
if to_remove:
|
|
1117
|
+
self.content_ids = list(content_ids - to_remove)
|
|
1118
|
+
self.save()
|
|
1119
|
+
|
|
1120
|
+
# Normalize representation if content has already been added in this version.
|
|
1121
|
+
# Undo addition by deleting the RepositoryContent.
|
|
1122
|
+
RepositoryContent.objects.filter(
|
|
1123
|
+
repository=self.repository,
|
|
1124
|
+
content_id__in=content,
|
|
1125
|
+
version_added=self,
|
|
1126
|
+
version_removed=None,
|
|
1127
|
+
).delete()
|
|
1128
|
+
|
|
1129
|
+
q_set = RepositoryContent.objects.filter(
|
|
1130
|
+
repository=self.repository, content_id__in=content, version_removed=None
|
|
1131
|
+
)
|
|
1132
|
+
q_set.update(version_removed=self)
|
|
1131
1133
|
|
|
1132
1134
|
def set_content(self, content):
|
|
1133
1135
|
"""
|
pulpcore/app/models/task.py
CHANGED
|
@@ -9,6 +9,7 @@ from gettext import gettext as _
|
|
|
9
9
|
|
|
10
10
|
from django.conf import settings
|
|
11
11
|
from django.contrib.postgres.fields import ArrayField, HStoreField
|
|
12
|
+
from django.contrib.postgres.indexes import GinIndex
|
|
12
13
|
from django.core.serializers.json import DjangoJSONEncoder
|
|
13
14
|
from django.db import connection, models
|
|
14
15
|
from django.utils import timezone
|
|
@@ -348,6 +349,12 @@ class Task(BaseModel, AutoAddObjPermsMixin):
|
|
|
348
349
|
models.Index(fields=["unblocked_at"]),
|
|
349
350
|
models.Index(fields=["state"]),
|
|
350
351
|
models.Index(fields=["state", "pulp_created"]),
|
|
352
|
+
GinIndex(
|
|
353
|
+
name="pulp_task_resources_index",
|
|
354
|
+
fields=["reserved_resources_record"],
|
|
355
|
+
condition=~models.Q(state__in=["completed", "failed", "canceled", "skipped"]),
|
|
356
|
+
opclasses=["array_ops"],
|
|
357
|
+
),
|
|
351
358
|
]
|
|
352
359
|
permissions = [
|
|
353
360
|
("manage_roles_task", "Can manage role assignments on task"),
|
pulpcore/app/settings.py
CHANGED
|
@@ -20,7 +20,8 @@ from django.core.files.storage import storages
|
|
|
20
20
|
from django.conf import global_settings
|
|
21
21
|
from django.core.exceptions import ImproperlyConfigured
|
|
22
22
|
from django.db import connection
|
|
23
|
-
from
|
|
23
|
+
from pulpcore.app.loggers import deprecation_logger
|
|
24
|
+
from dynaconf import DjangoDynaconf, Dynaconf, Validator, get_history
|
|
24
25
|
|
|
25
26
|
from pulpcore import constants
|
|
26
27
|
|
|
@@ -553,7 +554,14 @@ settings = DjangoDynaconf(
|
|
|
553
554
|
|
|
554
555
|
# begin compatibility layer for DEFAULT_FILE_STORAGE
|
|
555
556
|
# Remove on pulpcore=3.85 or pulpcore=4.0
|
|
556
|
-
|
|
557
|
+
using_deprecated_storage_settings = len(get_history(settings, key="DEFAULT_FILE_STORAGE")) > 1
|
|
558
|
+
if using_deprecated_storage_settings:
|
|
559
|
+
deprecation_logger.warning(
|
|
560
|
+
"[deprecation] DEFAULT_FILE_STORAGE will be removed in pulpcore 3.85. "
|
|
561
|
+
"Learn how to upgrade to STORAGES:\n"
|
|
562
|
+
"https://discourse.pulpproject.org/t/"
|
|
563
|
+
"action-required-upgrade-your-storage-settings-before-pulpcore-3-85/2072/2"
|
|
564
|
+
)
|
|
557
565
|
# Ensures the cached property storage.backends uses the the right value
|
|
558
566
|
storages._backends = settings.STORAGES.copy()
|
|
559
567
|
storages.backends
|
pulpcore/app/tasks/purge.py
CHANGED
|
@@ -82,17 +82,20 @@ def purge(finished_before=None, states=None, **kwargs):
|
|
|
82
82
|
states (Optional[List[str]]): List of task-states we want to purge.
|
|
83
83
|
|
|
84
84
|
"""
|
|
85
|
+
scheduled = current_task.get().taskschedule_set.exists()
|
|
86
|
+
|
|
85
87
|
if finished_before is None:
|
|
86
88
|
assert settings.TASK_PROTECTION_TIME > 0
|
|
87
89
|
finished_before = timezone.now() - timezone.timedelta(minutes=settings.TASK_PROTECTION_TIME)
|
|
88
90
|
if states is None:
|
|
89
91
|
states = TASK_FINAL_STATES
|
|
90
|
-
|
|
92
|
+
|
|
91
93
|
# Tasks, prior to the specified date, in the specified state, owned by the current-user, in the
|
|
92
94
|
# current domain
|
|
93
|
-
candidate_qs = Task.objects.filter(
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
candidate_qs = Task.objects.filter(finished_at__lt=finished_before, state__in=states)
|
|
96
|
+
|
|
97
|
+
if not scheduled:
|
|
98
|
+
candidate_qs = candidate_qs.filter(pulp_domain=get_domain())
|
|
96
99
|
if "user_pk" in kwargs:
|
|
97
100
|
if (user_pk := kwargs["user_pk"]) is not None:
|
|
98
101
|
current_user = User.objects.get(pk=user_pk)
|
|
@@ -101,7 +104,7 @@ def purge(finished_before=None, states=None, **kwargs):
|
|
|
101
104
|
# This is the old task signature (<= 3.74) without "user_pk".
|
|
102
105
|
# Has this task not been dispatched from a task schedule? Then we assume there was a user
|
|
103
106
|
# doing that.
|
|
104
|
-
if not
|
|
107
|
+
if not scheduled:
|
|
105
108
|
current_user = get_current_authenticated_user()
|
|
106
109
|
if current_user is None:
|
|
107
110
|
raise RuntimeError(
|
pulpcore/constants.py
CHANGED
|
@@ -12,6 +12,10 @@ TASK_UNBLOCKING_LOCK = 84
|
|
|
12
12
|
TASK_METRICS_HEARTBEAT_LOCK = 74
|
|
13
13
|
STORAGE_METRICS_LOCK = 72
|
|
14
14
|
|
|
15
|
+
# Reasons to send along a task worker wakeup call.
|
|
16
|
+
TASK_WAKEUP_UNBLOCK = "unblock"
|
|
17
|
+
TASK_WAKEUP_HANDLE = "handle"
|
|
18
|
+
|
|
15
19
|
#: All valid task states.
|
|
16
20
|
TASK_STATES = SimpleNamespace(
|
|
17
21
|
WAITING="waiting",
|
pulpcore/tasking/entrypoint.py
CHANGED
|
@@ -21,8 +21,18 @@ _logger = logging.getLogger(__name__)
|
|
|
21
21
|
@click.option(
|
|
22
22
|
"--reload/--no-reload", help="Reload worker on code changes. [requires hupper to be installed.]"
|
|
23
23
|
)
|
|
24
|
+
@click.option(
|
|
25
|
+
"--auxiliary/--no-auxiliary",
|
|
26
|
+
default=False,
|
|
27
|
+
help="Auxiliary workers do not perform housekeeping duties.",
|
|
28
|
+
)
|
|
24
29
|
@click.command()
|
|
25
|
-
def worker(
|
|
30
|
+
def worker(
|
|
31
|
+
pid,
|
|
32
|
+
burst,
|
|
33
|
+
reload,
|
|
34
|
+
auxiliary,
|
|
35
|
+
):
|
|
26
36
|
"""A Pulp worker."""
|
|
27
37
|
|
|
28
38
|
if reload:
|
|
@@ -40,4 +50,4 @@ def worker(pid, burst, reload):
|
|
|
40
50
|
|
|
41
51
|
_logger.info("Starting distributed type worker")
|
|
42
52
|
|
|
43
|
-
PulpcoreWorker().run(burst=burst)
|
|
53
|
+
PulpcoreWorker(auxiliary=auxiliary).run(burst=burst)
|
pulpcore/tasking/tasks.py
CHANGED
|
@@ -9,12 +9,11 @@ import traceback
|
|
|
9
9
|
import tempfile
|
|
10
10
|
import threading
|
|
11
11
|
from asgiref.sync import sync_to_async
|
|
12
|
-
from datetime import timedelta
|
|
13
12
|
from gettext import gettext as _
|
|
14
13
|
|
|
15
14
|
from django.conf import settings
|
|
16
15
|
from django.db import connection, transaction
|
|
17
|
-
from django.db.models import Model
|
|
16
|
+
from django.db.models import Model
|
|
18
17
|
from django_guid import get_guid
|
|
19
18
|
from pulpcore.app.apps import MODULE_PLUGIN_VERSIONS
|
|
20
19
|
from pulpcore.app.models import Task, TaskGroup
|
|
@@ -23,8 +22,8 @@ from pulpcore.constants import (
|
|
|
23
22
|
TASK_FINAL_STATES,
|
|
24
23
|
TASK_INCOMPLETE_STATES,
|
|
25
24
|
TASK_STATES,
|
|
26
|
-
TASK_DISPATCH_LOCK,
|
|
27
25
|
IMMEDIATE_TIMEOUT,
|
|
26
|
+
TASK_WAKEUP_UNBLOCK,
|
|
28
27
|
)
|
|
29
28
|
from pulpcore.middleware import x_task_diagnostics_var
|
|
30
29
|
from pulpcore.tasking.kafka import send_task_notification
|
|
@@ -47,10 +46,10 @@ def _validate_and_get_resources(resources):
|
|
|
47
46
|
return list(resource_set)
|
|
48
47
|
|
|
49
48
|
|
|
50
|
-
def wakeup_worker():
|
|
49
|
+
def wakeup_worker(reason="unknown"):
|
|
51
50
|
# Notify workers
|
|
52
51
|
with connection.connection.cursor() as cursor:
|
|
53
|
-
cursor.execute("
|
|
52
|
+
cursor.execute("SELECT pg_notify('pulp_worker_wakeup', %s)", (reason,))
|
|
54
53
|
|
|
55
54
|
|
|
56
55
|
def execute_task(task):
|
|
@@ -228,13 +227,6 @@ def dispatch(
|
|
|
228
227
|
notify_workers = False
|
|
229
228
|
with contextlib.ExitStack() as stack:
|
|
230
229
|
with transaction.atomic():
|
|
231
|
-
# Task creation need to be serialized so that pulp_created will provide a stable order
|
|
232
|
-
# at every time. We specifically need to ensure that each task, when committed to the
|
|
233
|
-
# task table will be the newest with respect to `pulp_created`.
|
|
234
|
-
with connection.cursor() as cursor:
|
|
235
|
-
# Wait for exclusive access and release automatically after transaction.
|
|
236
|
-
cursor.execute("SELECT pg_advisory_xact_lock(%s, %s)", [0, TASK_DISPATCH_LOCK])
|
|
237
|
-
newest_created = Task.objects.aggregate(Max("pulp_created"))["pulp_created__max"]
|
|
238
230
|
task = Task.objects.create(
|
|
239
231
|
state=TASK_STATES.WAITING,
|
|
240
232
|
logging_cid=(get_guid()),
|
|
@@ -250,23 +242,6 @@ def dispatch(
|
|
|
250
242
|
profile_options=x_task_diagnostics_var.get(None),
|
|
251
243
|
)
|
|
252
244
|
task.refresh_from_db() # The database may have assigned a timestamp for us.
|
|
253
|
-
if newest_created and task.pulp_created <= newest_created:
|
|
254
|
-
# Let this workaround not row forever into the future.
|
|
255
|
-
if newest_created - task.pulp_created > timedelta(seconds=1):
|
|
256
|
-
# Do not commit the transaction if this condition is not met.
|
|
257
|
-
# If we ever hit this, think about delegating the timestamping to PostgresQL.
|
|
258
|
-
raise RuntimeError("Clockscrew detected. Task dispatching would be dangerous.")
|
|
259
|
-
# Try to work around the smaller glitch
|
|
260
|
-
task.pulp_created = newest_created + timedelta(milliseconds=1)
|
|
261
|
-
task.save()
|
|
262
|
-
if task_group:
|
|
263
|
-
task_group.refresh_from_db()
|
|
264
|
-
if task_group.all_tasks_dispatched:
|
|
265
|
-
task.set_canceling()
|
|
266
|
-
task.set_canceled(
|
|
267
|
-
TASK_STATES.CANCELED, "All tasks in group have been dispatched/canceled."
|
|
268
|
-
)
|
|
269
|
-
return task
|
|
270
245
|
if immediate:
|
|
271
246
|
# Grab the advisory lock before the task hits the db.
|
|
272
247
|
stack.enter_context(task)
|
|
@@ -308,7 +283,7 @@ def dispatch(
|
|
|
308
283
|
task.set_canceling()
|
|
309
284
|
task.set_canceled(TASK_STATES.CANCELED, "Resources temporarily unavailable.")
|
|
310
285
|
if notify_workers:
|
|
311
|
-
wakeup_worker()
|
|
286
|
+
wakeup_worker(TASK_WAKEUP_UNBLOCK)
|
|
312
287
|
return task
|
|
313
288
|
|
|
314
289
|
|
pulpcore/tasking/worker.py
CHANGED
|
@@ -15,6 +15,7 @@ from packaging.version import parse as parse_version
|
|
|
15
15
|
from django.conf import settings
|
|
16
16
|
from django.db import connection
|
|
17
17
|
from django.db.models import Case, Count, F, Max, Value, When
|
|
18
|
+
from django.db.models.functions import Random
|
|
18
19
|
from django.utils import timezone
|
|
19
20
|
|
|
20
21
|
from pulpcore.constants import (
|
|
@@ -23,6 +24,8 @@ from pulpcore.constants import (
|
|
|
23
24
|
TASK_SCHEDULING_LOCK,
|
|
24
25
|
TASK_UNBLOCKING_LOCK,
|
|
25
26
|
TASK_METRICS_HEARTBEAT_LOCK,
|
|
27
|
+
TASK_WAKEUP_UNBLOCK,
|
|
28
|
+
TASK_WAKEUP_HANDLE,
|
|
26
29
|
)
|
|
27
30
|
from pulpcore.metrics import init_otel_meter
|
|
28
31
|
from pulpcore.app.apps import pulp_plugin_configs
|
|
@@ -56,12 +59,14 @@ THRESHOLD_UNBLOCKED_WAITING_TIME = 5
|
|
|
56
59
|
|
|
57
60
|
|
|
58
61
|
class PulpcoreWorker:
|
|
59
|
-
def __init__(self):
|
|
62
|
+
def __init__(self, auxiliary=False):
|
|
60
63
|
# Notification states from several signal handlers
|
|
61
64
|
self.shutdown_requested = False
|
|
62
|
-
self.
|
|
65
|
+
self.wakeup_unblock = False
|
|
66
|
+
self.wakeup_handle = False
|
|
63
67
|
self.cancel_task = False
|
|
64
68
|
|
|
69
|
+
self.auxiliary = auxiliary
|
|
65
70
|
self.task = None
|
|
66
71
|
self.name = f"{os.getpid()}@{socket.getfqdn()}"
|
|
67
72
|
self.heartbeat_period = timedelta(seconds=settings.WORKER_TTL / 3)
|
|
@@ -124,7 +129,17 @@ class PulpcoreWorker:
|
|
|
124
129
|
|
|
125
130
|
def _pg_notify_handler(self, notification):
|
|
126
131
|
if notification.channel == "pulp_worker_wakeup":
|
|
127
|
-
|
|
132
|
+
if notification.payload == TASK_WAKEUP_UNBLOCK:
|
|
133
|
+
# Auxiliary workers don't do this.
|
|
134
|
+
self.wakeup_unblock = not self.auxiliary
|
|
135
|
+
elif notification.payload == TASK_WAKEUP_HANDLE:
|
|
136
|
+
self.wakeup_handle = True
|
|
137
|
+
else:
|
|
138
|
+
_logger.warn("Unknown wakeup call recieved. Reason: '%s'", notification.payload)
|
|
139
|
+
# We cannot be sure so assume everything happened.
|
|
140
|
+
self.wakeup_unblock = not self.auxiliary
|
|
141
|
+
self.wakeup_handle = True
|
|
142
|
+
|
|
128
143
|
elif notification.channel == "pulp_worker_metrics_heartbeat":
|
|
129
144
|
self.last_metric_heartbeat = datetime.fromisoformat(notification.payload)
|
|
130
145
|
elif self.task and notification.channel == "pulp_worker_cancel":
|
|
@@ -179,18 +194,19 @@ class PulpcoreWorker:
|
|
|
179
194
|
def beat(self):
|
|
180
195
|
if self.worker.last_heartbeat < timezone.now() - self.heartbeat_period:
|
|
181
196
|
self.worker = self.handle_worker_heartbeat()
|
|
182
|
-
self.
|
|
183
|
-
|
|
184
|
-
self.worker_cleanup_countdown
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
197
|
+
if not self.auxiliary:
|
|
198
|
+
self.worker_cleanup_countdown -= 1
|
|
199
|
+
if self.worker_cleanup_countdown <= 0:
|
|
200
|
+
self.worker_cleanup_countdown = WORKER_CLEANUP_INTERVAL
|
|
201
|
+
self.worker_cleanup()
|
|
202
|
+
with contextlib.suppress(AdvisoryLockError), PGAdvisoryLock(TASK_SCHEDULING_LOCK):
|
|
203
|
+
dispatch_scheduled_tasks()
|
|
204
|
+
# This "reporting code" must not me moved inside a task, because it is supposed
|
|
205
|
+
# to be able to report on a congested tasking system to produce reliable results.
|
|
206
|
+
self.record_unblocked_waiting_tasks_metric()
|
|
207
|
+
|
|
208
|
+
def notify_workers(self, reason="unknown"):
|
|
209
|
+
self.cursor.execute("SELECT pg_notify('pulp_worker_wakeup', %s)", (reason,))
|
|
194
210
|
|
|
195
211
|
def cancel_abandoned_task(self, task, final_state, reason=None):
|
|
196
212
|
"""Cancel and clean up an abandoned task.
|
|
@@ -224,7 +240,7 @@ class PulpcoreWorker:
|
|
|
224
240
|
delete_incomplete_resources(task)
|
|
225
241
|
task.set_canceled(final_state=final_state, reason=reason)
|
|
226
242
|
if task.reserved_resources_record:
|
|
227
|
-
self.notify_workers()
|
|
243
|
+
self.notify_workers(TASK_WAKEUP_UNBLOCK)
|
|
228
244
|
return True
|
|
229
245
|
|
|
230
246
|
def is_compatible(self, task):
|
|
@@ -249,10 +265,31 @@ class PulpcoreWorker:
|
|
|
249
265
|
def unblock_tasks(self):
|
|
250
266
|
"""Iterate over waiting tasks and mark them unblocked accordingly.
|
|
251
267
|
|
|
252
|
-
|
|
268
|
+
This function also handles the communication around it.
|
|
269
|
+
In order to prevent multiple workers to attempt unblocking tasks at the same time it tries
|
|
270
|
+
to acquire a lock and just returns on failure to do so.
|
|
271
|
+
Also it clears the notification about tasks to be unblocked and sends the notification that
|
|
272
|
+
new unblocked tasks are made available.
|
|
273
|
+
|
|
274
|
+
Returns the number of new unblocked tasks.
|
|
253
275
|
"""
|
|
254
276
|
|
|
255
|
-
|
|
277
|
+
assert not self.auxiliary
|
|
278
|
+
|
|
279
|
+
count = 0
|
|
280
|
+
self.wakeup_unblock_tasks = False
|
|
281
|
+
with contextlib.suppress(AdvisoryLockError), PGAdvisoryLock(TASK_UNBLOCKING_LOCK):
|
|
282
|
+
if count := self._unblock_tasks():
|
|
283
|
+
self.notify_workers(TASK_WAKEUP_HANDLE)
|
|
284
|
+
return count
|
|
285
|
+
|
|
286
|
+
def _unblock_tasks(self):
|
|
287
|
+
"""Iterate over waiting tasks and mark them unblocked accordingly.
|
|
288
|
+
|
|
289
|
+
Returns the number of new unblocked tasks.
|
|
290
|
+
"""
|
|
291
|
+
|
|
292
|
+
count = 0
|
|
256
293
|
taken_exclusive_resources = set()
|
|
257
294
|
taken_shared_resources = set()
|
|
258
295
|
# When batching this query, be sure to use "pulp_created" as a cursor
|
|
@@ -280,7 +317,7 @@ class PulpcoreWorker:
|
|
|
280
317
|
task.pulp_domain.name,
|
|
281
318
|
)
|
|
282
319
|
task.unblock()
|
|
283
|
-
|
|
320
|
+
count += 1
|
|
284
321
|
# Don't consider this task's resources as held.
|
|
285
322
|
continue
|
|
286
323
|
|
|
@@ -301,7 +338,7 @@ class PulpcoreWorker:
|
|
|
301
338
|
task.pulp_domain.name,
|
|
302
339
|
)
|
|
303
340
|
task.unblock()
|
|
304
|
-
|
|
341
|
+
count += 1
|
|
305
342
|
elif task.state == TASK_STATES.RUNNING and task.unblocked_at is None:
|
|
306
343
|
# This should not happen in normal operation.
|
|
307
344
|
# And it is only an issue if the worker running that task died, because it will
|
|
@@ -318,7 +355,7 @@ class PulpcoreWorker:
|
|
|
318
355
|
taken_exclusive_resources.update(exclusive_resources)
|
|
319
356
|
taken_shared_resources.update(shared_resources)
|
|
320
357
|
|
|
321
|
-
return
|
|
358
|
+
return count
|
|
322
359
|
|
|
323
360
|
def iter_tasks(self):
|
|
324
361
|
"""Iterate over ready tasks and yield each task while holding the lock."""
|
|
@@ -327,7 +364,7 @@ class PulpcoreWorker:
|
|
|
327
364
|
for task in Task.objects.filter(
|
|
328
365
|
state__in=TASK_INCOMPLETE_STATES,
|
|
329
366
|
unblocked_at__isnull=False,
|
|
330
|
-
).order_by("-immediate", "pulp_created"):
|
|
367
|
+
).order_by("-immediate", F("pulp_created") + Value(timedelta(seconds=8)) * Random()):
|
|
331
368
|
# This code will only be called if we acquired the lock successfully
|
|
332
369
|
# The lock will be automatically be released at the end of the block
|
|
333
370
|
with contextlib.suppress(AdvisoryLockError), task:
|
|
@@ -366,16 +403,18 @@ class PulpcoreWorker:
|
|
|
366
403
|
"""Wait for signals on the wakeup channel while heart beating."""
|
|
367
404
|
|
|
368
405
|
_logger.debug(_("Worker %s entering sleep state."), self.name)
|
|
369
|
-
while not self.shutdown_requested and not self.
|
|
406
|
+
while not self.shutdown_requested and not self.wakeup_handle:
|
|
370
407
|
r, w, x = select.select(
|
|
371
408
|
[self.sentinel, connection.connection], [], [], self.heartbeat_period.seconds
|
|
372
409
|
)
|
|
373
410
|
self.beat()
|
|
374
411
|
if connection.connection in r:
|
|
375
412
|
connection.connection.execute("SELECT 1")
|
|
413
|
+
if self.wakeup_unblock:
|
|
414
|
+
self.unblock_tasks()
|
|
376
415
|
if self.sentinel in r:
|
|
377
416
|
os.read(self.sentinel, 256)
|
|
378
|
-
|
|
417
|
+
_logger.debug(_("Worker %s leaving sleep state."), self.name)
|
|
379
418
|
|
|
380
419
|
def supervise_task(self, task):
|
|
381
420
|
"""Call and supervise the task process while heart beating.
|
|
@@ -424,12 +463,8 @@ class PulpcoreWorker:
|
|
|
424
463
|
)
|
|
425
464
|
cancel_state = TASK_STATES.CANCELED
|
|
426
465
|
self.cancel_task = False
|
|
427
|
-
if self.
|
|
428
|
-
|
|
429
|
-
TASK_UNBLOCKING_LOCK
|
|
430
|
-
):
|
|
431
|
-
self.unblock_tasks()
|
|
432
|
-
self.wakeup = False
|
|
466
|
+
if self.wakeup_unblock:
|
|
467
|
+
self.unblock_tasks()
|
|
433
468
|
if task_process.sentinel in r:
|
|
434
469
|
if not task_process.is_alive():
|
|
435
470
|
break
|
|
@@ -471,10 +506,10 @@ class PulpcoreWorker:
|
|
|
471
506
|
if cancel_state:
|
|
472
507
|
self.cancel_abandoned_task(task, cancel_state, cancel_reason)
|
|
473
508
|
if task.reserved_resources_record:
|
|
474
|
-
self.notify_workers()
|
|
509
|
+
self.notify_workers(TASK_WAKEUP_UNBLOCK)
|
|
475
510
|
self.task = None
|
|
476
511
|
|
|
477
|
-
def
|
|
512
|
+
def handle_unblocked_tasks(self):
|
|
478
513
|
"""Pick and supervise tasks until there are no more available tasks.
|
|
479
514
|
|
|
480
515
|
Failing to detect new available tasks can lead to a stuck state, as the workers
|
|
@@ -483,11 +518,9 @@ class PulpcoreWorker:
|
|
|
483
518
|
"""
|
|
484
519
|
keep_looping = True
|
|
485
520
|
while keep_looping and not self.shutdown_requested:
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
except AdvisoryLockError:
|
|
490
|
-
keep_looping = True
|
|
521
|
+
# Clear pending wakeups. We are about to handle them anyway.
|
|
522
|
+
self.wakeup_handle = False
|
|
523
|
+
keep_looping = False
|
|
491
524
|
for task in self.iter_tasks():
|
|
492
525
|
keep_looping = True
|
|
493
526
|
self.supervise_task(task)
|
|
@@ -538,14 +571,19 @@ class PulpcoreWorker:
|
|
|
538
571
|
self.cursor.execute("LISTEN pulp_worker_cancel")
|
|
539
572
|
self.cursor.execute("LISTEN pulp_worker_metrics_heartbeat")
|
|
540
573
|
if burst:
|
|
541
|
-
self.
|
|
574
|
+
if not self.auxiliary:
|
|
575
|
+
# Attempt to flush the task queue completely.
|
|
576
|
+
# Stop iteration if no new tasks were found to unblock.
|
|
577
|
+
while self.unblock_tasks():
|
|
578
|
+
self.handle_unblocked_tasks()
|
|
579
|
+
self.handle_unblocked_tasks()
|
|
542
580
|
else:
|
|
543
581
|
self.cursor.execute("LISTEN pulp_worker_wakeup")
|
|
544
582
|
while not self.shutdown_requested:
|
|
545
583
|
# do work
|
|
546
584
|
if self.shutdown_requested:
|
|
547
585
|
break
|
|
548
|
-
self.
|
|
586
|
+
self.handle_unblocked_tasks()
|
|
549
587
|
if self.shutdown_requested:
|
|
550
588
|
break
|
|
551
589
|
# rest until notified to wakeup
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import http
|
|
2
2
|
import pytest
|
|
3
|
+
import uuid
|
|
4
|
+
|
|
5
|
+
from urllib.parse import urlparse
|
|
3
6
|
|
|
4
7
|
pytestmark = [pytest.mark.parallel]
|
|
5
8
|
|
|
@@ -20,27 +23,43 @@ def _fix_response_headers(monkeypatch, pulpcore_bindings):
|
|
|
20
23
|
|
|
21
24
|
|
|
22
25
|
@pytest.fixture
|
|
23
|
-
def session_user(pulpcore_bindings, gen_user,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
headers
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
26
|
+
def session_user(pulpcore_bindings, gen_user, bindings_cfg):
|
|
27
|
+
class SessionUser(gen_user):
|
|
28
|
+
def __enter__(self):
|
|
29
|
+
"""
|
|
30
|
+
Mimic the behavior of a session user (aka what browsers do).
|
|
31
|
+
|
|
32
|
+
- Set auth to None so client will use the session cookie
|
|
33
|
+
- Set X-CSRFToken header since we are posting JSON instead of form data
|
|
34
|
+
(Django creates a hidden input field for the CSRF token when using forms)
|
|
35
|
+
- Set Origin and Host headers so Django CSRF middleware will allow the request
|
|
36
|
+
(Browsers send these headers and it is needed when using HTTPS)
|
|
37
|
+
"""
|
|
38
|
+
self.old_cookie = pulpcore_bindings.client.cookie
|
|
39
|
+
super().__enter__()
|
|
40
|
+
response = pulpcore_bindings.LoginApi.login_with_http_info()
|
|
41
|
+
if isinstance(response, tuple):
|
|
42
|
+
# old bindings
|
|
43
|
+
_, _, headers = response
|
|
44
|
+
else:
|
|
45
|
+
# new bindings
|
|
46
|
+
headers = response.headers
|
|
47
|
+
cookie_jar = http.cookies.SimpleCookie(headers["Set-Cookie"])
|
|
48
|
+
self.cookie = "; ".join((f"{k}={v.value}" for k, v in cookie_jar.items()))
|
|
49
|
+
self.csrf_token = cookie_jar["csrftoken"].value
|
|
50
|
+
self.session_id = cookie_jar["sessionid"].value
|
|
51
|
+
bindings_cfg.username, bindings_cfg.password = None, None
|
|
52
|
+
pulpcore_bindings.client.cookie = self.cookie
|
|
53
|
+
pulpcore_bindings.client.set_default_header("X-CSRFToken", self.csrf_token)
|
|
54
|
+
pulpcore_bindings.client.set_default_header("Origin", bindings_cfg.host)
|
|
55
|
+
pulpcore_bindings.client.set_default_header("Host", urlparse(bindings_cfg.host).netloc)
|
|
56
|
+
return self
|
|
57
|
+
|
|
58
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
59
|
+
super().__exit__(exc_type, exc_value, traceback)
|
|
60
|
+
pulpcore_bindings.client.cookie = self.old_cookie
|
|
61
|
+
|
|
62
|
+
return SessionUser
|
|
44
63
|
|
|
45
64
|
|
|
46
65
|
def test_login_read_denies_anonymous(pulpcore_bindings, anonymous_user):
|
|
@@ -83,20 +102,31 @@ def test_login_sets_session_cookie(pulpcore_bindings, gen_user):
|
|
|
83
102
|
assert cookie_jar["csrftoken"].value != ""
|
|
84
103
|
|
|
85
104
|
|
|
86
|
-
def test_session_cookie_is_authorization(pulpcore_bindings,
|
|
87
|
-
|
|
88
|
-
|
|
105
|
+
def test_session_cookie_is_authorization(pulpcore_bindings, session_user):
|
|
106
|
+
with session_user() as user:
|
|
107
|
+
result = pulpcore_bindings.LoginApi.login_read()
|
|
108
|
+
assert result.username == user.username
|
|
109
|
+
assert pulpcore_bindings.client.configuration.username is None
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_session_cookie_object_create(pulpcore_bindings, session_user, gen_object_with_cleanup):
|
|
113
|
+
with session_user(model_roles=["core.rbaccontentguard_creator"]):
|
|
114
|
+
assert pulpcore_bindings.client.configuration.username is None
|
|
115
|
+
gen_object_with_cleanup(pulpcore_bindings.ContentguardsRbacApi, {"name": str(uuid.uuid4())})
|
|
89
116
|
|
|
90
117
|
|
|
91
118
|
def test_logout_removes_sessionid(pulpcore_bindings, session_user):
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
119
|
+
with session_user() as user:
|
|
120
|
+
assert user.session_id != ""
|
|
121
|
+
assert user.session_id in pulpcore_bindings.client.cookie
|
|
122
|
+
response = pulpcore_bindings.LoginApi.logout_with_http_info()
|
|
123
|
+
if isinstance(response, tuple):
|
|
124
|
+
# old bindings
|
|
125
|
+
_, status_code, headers = response
|
|
126
|
+
else:
|
|
127
|
+
# new bindings
|
|
128
|
+
status_code = response.status_code
|
|
129
|
+
headers = response.headers
|
|
100
130
|
assert status_code == 204
|
|
101
131
|
cookie_jar = http.cookies.SimpleCookie(headers["Set-Cookie"])
|
|
102
132
|
assert cookie_jar["sessionid"].value == ""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pulpcore
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.84.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
|
|
@@ -44,11 +44,11 @@ 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.
|
|
47
|
+
Requires-Dist: jq<1.11.0,>=1.6.0
|
|
48
48
|
Requires-Dist: PyOpenSSL<26.0
|
|
49
|
-
Requires-Dist: opentelemetry-api<1.
|
|
50
|
-
Requires-Dist: opentelemetry-sdk<1.
|
|
51
|
-
Requires-Dist: opentelemetry-exporter-otlp-proto-http<1.
|
|
49
|
+
Requires-Dist: opentelemetry-api<1.36,>=1.27.0
|
|
50
|
+
Requires-Dist: opentelemetry-sdk<1.36,>=1.27.0
|
|
51
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http<1.36,>=1.27.0
|
|
52
52
|
Requires-Dist: protobuf<6.0,>=4.21.1
|
|
53
53
|
Requires-Dist: pulp-glue<0.35,>=0.28.0
|
|
54
54
|
Requires-Dist: pygtrie<=2.5.0,>=2.5
|
|
@@ -70,6 +70,7 @@ Provides-Extra: google
|
|
|
70
70
|
Requires-Dist: django-storages[google]==1.14.6; extra == "google"
|
|
71
71
|
Provides-Extra: azure
|
|
72
72
|
Requires-Dist: django-storages[azure]==1.14.6; extra == "azure"
|
|
73
|
+
Requires-Dist: azure-storage-blob<12.26.0; extra == "azure"
|
|
73
74
|
Provides-Extra: prometheus
|
|
74
75
|
Requires-Dist: django-prometheus; extra == "prometheus"
|
|
75
76
|
Provides-Extra: kafka
|
|
@@ -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=-L1AHE-ls64OS0X-lq7xg4yPqwTZzBhEx4OcM3bWpeE,297
|
|
4
4
|
pulp_certguard/app/models.py,sha256=xy5IWxf0LQxayIDmQw25Y2YhB_NrlTGvuvdY-YW7QBU,8119
|
|
5
5
|
pulp_certguard/app/serializers.py,sha256=3jxWu82vU3xA578Qbyz-G4Q9Zlh3MFLGRHzX62M0RF8,1826
|
|
6
6
|
pulp_certguard/app/utils.py,sha256=O6T1Npdb8fu3XqIkDJd8PQdEFJWPUeQ-i_aHXBl7MEc,816
|
|
@@ -49,7 +49,7 @@ pulp_certguard/tests/unit/test_models.py,sha256=TBI0yKsrdbnJSPeBFfxSqhXK7zaNvR6q
|
|
|
49
49
|
pulp_file/__init__.py,sha256=0vOCXofR6Eyxkg4y66esnOGPeESCe23C1cNBHj56w44,61
|
|
50
50
|
pulp_file/manifest.py,sha256=1WwIOJrPSkFcmkRm7CkWifVOCoZvo_nnANgce6uuG7U,3796
|
|
51
51
|
pulp_file/pytest_plugin.py,sha256=l1PvTxUi5D3uJy4SnHWNhr-otWEYNcm-kc5nSqVJg0Y,10646
|
|
52
|
-
pulp_file/app/__init__.py,sha256=
|
|
52
|
+
pulp_file/app/__init__.py,sha256=jMD7UQn6iP02kt5RN9nH8EdERwruutYZzNZKh4ptVq0,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
|
|
@@ -101,7 +101,7 @@ pulp_file/tests/unit/test_safe_paths.py,sha256=CRJX3-MdIZF_4-hVK-7brH9LSK2i97GdI
|
|
|
101
101
|
pulp_file/tests/unit/test_serializers.py,sha256=reDGIZrAaPHITwiv-LSCJ85JK-aCcNh5cavmAaba8vw,2143
|
|
102
102
|
pulpcore/__init__.py,sha256=9L859gHcVX5TxrTP0Ef7GWv8oa7tsvIs_8XDkyZIu2g,107
|
|
103
103
|
pulpcore/backends.py,sha256=Ax_MJpbvtNDg_rhkHaiQRm39DBSS2dH8UpMRJN2T0oE,4482
|
|
104
|
-
pulpcore/constants.py,sha256=
|
|
104
|
+
pulpcore/constants.py,sha256=R97fEBxQ0jkf9RPNUh_B3f8yHKjydUZoDgiMEFn8Nd4,4787
|
|
105
105
|
pulpcore/filters.py,sha256=dD5oRRkWg65s3LoObr-ipRvRsxZK_3Zr0lKMNr9Sg5o,16682
|
|
106
106
|
pulpcore/metrics.py,sha256=Mfq-nnRjRf3vBHFO-ux-4d1I3yE7TgeptwgiSgGz4rA,2230
|
|
107
107
|
pulpcore/middleware.py,sha256=10Jxc4Iq03gZD3n39t63OmBCpdftcke8bxEd-LioJlA,5973
|
|
@@ -110,7 +110,7 @@ pulpcore/pytest_plugin.py,sha256=skubiEUIevVURr4LnmmVMt_ZeH5vT9mI0yiPUYerMnQ,380
|
|
|
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=
|
|
113
|
+
pulpcore/app/apps.py,sha256=r_P_PtQ94J3JkWzPyb-qpEy9_gzxZC5dYuJ6TqPkGnE,17860
|
|
114
114
|
pulpcore/app/authentication.py,sha256=1LIJW6HIQQlZrliHy__jdzkDEh6Oj7xKgd0V-vRcDus,2855
|
|
115
115
|
pulpcore/app/checks.py,sha256=jbfTF7nmftBbky4AQXHigpyCaGydKasvRUXsd72JZVg,1946
|
|
116
116
|
pulpcore/app/entrypoint.py,sha256=YIfQpM5UxybBTasiEY5ptq--UmqPqjdIGnwmqVsDC7E,4972
|
|
@@ -129,7 +129,7 @@ pulpcore/app/redis_connection.py,sha256=VTdG0ulXuyESjYV6SJdG_jLzkLZH-MlLcD6pielw
|
|
|
129
129
|
pulpcore/app/replica.py,sha256=rGE14OBaR_FKxmHL7NMxf_OizMyS-90IPsMRo_j9YRI,11474
|
|
130
130
|
pulpcore/app/response.py,sha256=hYH_jSBrxmRsBr2bknmXE1qfs2g8JjDTXYcQ5ZWlF_c,1950
|
|
131
131
|
pulpcore/app/role_util.py,sha256=84HSt8_9fxB--dtfSyg_TumVgOdyBbyP6rBaiAfTpOU,22393
|
|
132
|
-
pulpcore/app/settings.py,sha256=
|
|
132
|
+
pulpcore/app/settings.py,sha256=hSe_93KK3k70SbjkJ8JXdC-HE6K9gOwczisAxkrLbtQ,23040
|
|
133
133
|
pulpcore/app/urls.py,sha256=0gdI74CAdycJStXSw1gknviDGe3J3k0UhS4J8RYa5dg,8120
|
|
134
134
|
pulpcore/app/util.py,sha256=nYF6nZXgqVk4U1QeZEpWYX-wqitGSGAJip6W78IfXUk,24432
|
|
135
135
|
pulpcore/app/wsgi.py,sha256=7rpZ_1NHEN_UfeNZCj8206bas1WeqRkHnGdxpd7rdDI,492
|
|
@@ -286,6 +286,8 @@ pulpcore/app/migrations/0131_distribution_checkpoint_publication_checkpoint.py,s
|
|
|
286
286
|
pulpcore/app/migrations/0132_alter_content_options.py,sha256=hrhUTsRqQJgwC6wU9Ys5AvyVz2YCzklj2OuVf6hyBfs,477
|
|
287
287
|
pulpcore/app/migrations/0132_task_profile_options.py,sha256=ljdIm5-NXl_8s87HzkthvUxr7eHhLaETrr5qNtAVKDE,518
|
|
288
288
|
pulpcore/app/migrations/0133_repositoryversion_content_ids.py,sha256=P8H16p6-EWtnyoenomC4R8CvAivfPqUkkRAsoizgm2M,545
|
|
289
|
+
pulpcore/app/migrations/0134_task_insert_trigger.py,sha256=6kBoMWSwljS5RERsRu42xXXUOJS0_Z2w-Lv9FixPHf4,2310
|
|
290
|
+
pulpcore/app/migrations/0135_task_pulp_task_resources_index.py,sha256=X2cJRbuuKxv31psqDaLx8bQxb2Kcv5_zMuGHwwloSCg,714
|
|
289
291
|
pulpcore/app/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
290
292
|
pulpcore/app/models/__init__.py,sha256=9JKMGKbEV6nJPep_K36rnWnS1QWMKBFSty-Hkr65JVk,3459
|
|
291
293
|
pulpcore/app/models/access_policy.py,sha256=o4L41RGoZ5UMmh5UeeenmadD5MJgShguphgd4eAVxQA,6071
|
|
@@ -302,11 +304,11 @@ pulpcore/app/models/openpgp.py,sha256=3R5p8ZBPq63NzaE2_EwCXEMYPUQu7QUWanMcKCOoWk
|
|
|
302
304
|
pulpcore/app/models/progress.py,sha256=osD0cqPWC5oaebKgjpaOLY6tgv1bpjA66ty7nr8TaLU,13499
|
|
303
305
|
pulpcore/app/models/publication.py,sha256=Ltiwylew7OOrobQRjdy1p6NbppBMXD2uX_IC2Ybgl7E,28869
|
|
304
306
|
pulpcore/app/models/replica.py,sha256=i_wPxyPaVWpEVTJNVjJsBarxFauqeagtuwLadsmVz-g,2067
|
|
305
|
-
pulpcore/app/models/repository.py,sha256=
|
|
307
|
+
pulpcore/app/models/repository.py,sha256=SIc21Gex6okxI7OCfHEGIpXpGlypG3z9IgMt5-mkNy0,58056
|
|
306
308
|
pulpcore/app/models/role.py,sha256=dZklNd2VeAw4cT6dyJ7SyTBt9sZvdqakY86wXGAY3vU,3287
|
|
307
309
|
pulpcore/app/models/status.py,sha256=72oUOJ7BnCAw3uDbc-XuI72oAyP2llCoBic4zb2JP78,3683
|
|
308
310
|
pulpcore/app/models/storage.py,sha256=2b-DQWaO31NqjV6FiISALegND-sQZAU7BVAsduUvm3o,6780
|
|
309
|
-
pulpcore/app/models/task.py,sha256=
|
|
311
|
+
pulpcore/app/models/task.py,sha256=TpQfZDzH7NzeD4kIR3S0XX64p13jzAeJQjZ1M9sg8rk,15280
|
|
310
312
|
pulpcore/app/models/upload.py,sha256=3njXT2rrVJwBjEDegvqcLD9_7cPnnl974lhbAhikEp8,3004
|
|
311
313
|
pulpcore/app/protobuf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
312
314
|
pulpcore/app/protobuf/analytics_pb2.py,sha256=-4CkbSW8JUAEIjZJBTPAJ5QezFJOdCPiDhx8_KA1bMU,2168
|
|
@@ -339,7 +341,7 @@ pulpcore/app/tasks/export.py,sha256=dRg-KcnM7HumXUx8mjgJ-EVMcz2RbzSOPmMkzVtJEnI,
|
|
|
339
341
|
pulpcore/app/tasks/importer.py,sha256=5T14JynWJjBijAE-d_YstTRYOtY0WTHMqkF7GFJaj5o,23222
|
|
340
342
|
pulpcore/app/tasks/migrate.py,sha256=wCjGskoF-XWzbINEyC_crgcigFZlC8EHqZTbjkLQykg,2452
|
|
341
343
|
pulpcore/app/tasks/orphan.py,sha256=4rTZLZ549niJ7mGMh_7suy-czIcj06oCTxPYnsPN8mU,4685
|
|
342
|
-
pulpcore/app/tasks/purge.py,sha256=
|
|
344
|
+
pulpcore/app/tasks/purge.py,sha256=IpdKTj9AvlNNuMNbkxa63xuaf3eK6dUvHZeMMWr_MjQ,7532
|
|
343
345
|
pulpcore/app/tasks/reclaim_space.py,sha256=FZ7KFasbScPAU7A6lzK98pdylmqgThssgnNMecG5bEw,3803
|
|
344
346
|
pulpcore/app/tasks/replica.py,sha256=T0Mky1FjrJH0j6ag61fE-vQmdQ0Otoe8_nOREXYHVXg,4485
|
|
345
347
|
pulpcore/app/tasks/repository.py,sha256=v-CDXp03YV6S6Lf-rKklPw7PwpfeoQe_Gw3ZyMH6SFQ,9640
|
|
@@ -427,11 +429,11 @@ pulpcore/plugin/viewsets/__init__.py,sha256=G2zE-NRWz6PFYp8OMZrv01RYBQELFWfW702b
|
|
|
427
429
|
pulpcore/plugin/viewsets/content.py,sha256=MHvmLOxsKSQfk6y5t1s9CVxkce9YNeU-dYb1Ldyf83I,6432
|
|
428
430
|
pulpcore/tasking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
429
431
|
pulpcore/tasking/_util.py,sha256=fPW4k1nUa_NZ0ywy_A15Fuiejo5stY58abPbZTXw5t8,9904
|
|
430
|
-
pulpcore/tasking/entrypoint.py,sha256=
|
|
432
|
+
pulpcore/tasking/entrypoint.py,sha256=eAypZD4ORoNOrmBeMdbwO9p6GSQ59bMvZ3TrbnE0czw,1305
|
|
431
433
|
pulpcore/tasking/kafka.py,sha256=76z4DzeXM1WL5uu1HlKnduWeLO3-b-czvGBXdWR6054,3845
|
|
432
434
|
pulpcore/tasking/storage.py,sha256=zQkwlpC_FDQtmZGZ8vKwHqxvD6CLO_gAS4Q7wijZE-k,3106
|
|
433
|
-
pulpcore/tasking/tasks.py,sha256=
|
|
434
|
-
pulpcore/tasking/worker.py,sha256=
|
|
435
|
+
pulpcore/tasking/tasks.py,sha256=bYYAFwJGGyl3mgS7Iw3JZ-vDl1nXbHiAbt3LBSq-nqQ,12946
|
|
436
|
+
pulpcore/tasking/worker.py,sha256=zEdrEmdcnVqNzjkN09O3mui8xKBX04j_QDUHlX1Ugco,25698
|
|
435
437
|
pulpcore/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
436
438
|
pulpcore/tests/functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
437
439
|
pulpcore/tests/functional/content_with_coverage.py,sha256=gQK8himy32s9O9vpXdgoM6-_z2KySaXm5rTga9z0jGI,260
|
|
@@ -446,7 +448,7 @@ pulpcore/tests/functional/api/test_correlation_id.py,sha256=4iCKrI8exUPuwOr6tO1n
|
|
|
446
448
|
pulpcore/tests/functional/api/test_crd_artifacts.py,sha256=NNr7Bd9Uy7gSaeqQS8vs03znSv8KunM-EVWn9ab_Ycg,7873
|
|
447
449
|
pulpcore/tests/functional/api/test_crud_domains.py,sha256=vgPuj-J4-KxBegH5rFYWU6mWjU9OXq1OdN4FtRb0Aa0,13063
|
|
448
450
|
pulpcore/tests/functional/api/test_filter.py,sha256=2tPd85CJRxMNPDZYPkHnrcVyRq9pa1R06uWiYBbpGeA,9296
|
|
449
|
-
pulpcore/tests/functional/api/test_login.py,sha256=
|
|
451
|
+
pulpcore/tests/functional/api/test_login.py,sha256=BcOgch17WZ7jD7LGNN5s0i0KOdJt_uF25APbNYdYltI,5548
|
|
450
452
|
pulpcore/tests/functional/api/test_openapi_schema.py,sha256=pDm4xSp40sr69WgUM8MzHDaE8ouCgPRMKGC6cKTVkEs,3825
|
|
451
453
|
pulpcore/tests/functional/api/test_openpgp.py,sha256=6iKUhAs4mSeIDg1xVA6sP1SF0RgqwRzS9ioGfU6Ahlk,6272
|
|
452
454
|
pulpcore/tests/functional/api/test_replication.py,sha256=46DHyvbR1QevT_IzMtmR8wNsmUNp6U-vm3OI_oUQRRc,28730
|
|
@@ -532,9 +534,9 @@ pulpcore/tests/unit/stages/test_artifactdownloader.py,sha256=qB1ANdFmNtUnljg8fCd
|
|
|
532
534
|
pulpcore/tests/unit/stages/test_stages.py,sha256=H1a2BQLjdZlZvcb_qULp62huZ1xy6ItTcthktVyGU0w,4735
|
|
533
535
|
pulpcore/tests/unit/viewsets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
534
536
|
pulpcore/tests/unit/viewsets/test_viewset_base.py,sha256=W9o3V6758bZctR6krMPPQytb0xJuF-jb4uBWTNDoD_U,4837
|
|
535
|
-
pulpcore-3.
|
|
536
|
-
pulpcore-3.
|
|
537
|
-
pulpcore-3.
|
|
538
|
-
pulpcore-3.
|
|
539
|
-
pulpcore-3.
|
|
540
|
-
pulpcore-3.
|
|
537
|
+
pulpcore-3.84.0.dist-info/licenses/LICENSE,sha256=dhnHU8rJXUdAIgIjveSKAyYG_KzN5eVG-bxETIGrNW0,17988
|
|
538
|
+
pulpcore-3.84.0.dist-info/METADATA,sha256=XqnHGTwnBlSySFuK5Icohu-J5viTdz-LyV2f_SnBG_4,4380
|
|
539
|
+
pulpcore-3.84.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
540
|
+
pulpcore-3.84.0.dist-info/entry_points.txt,sha256=OZven4wzXzQA5b5q9MpP4HUpIPPQCSvIOvkKtNInrK0,452
|
|
541
|
+
pulpcore-3.84.0.dist-info/top_level.txt,sha256=6h-Lm3FKQSaT_nL1KSxu_hBnzKE15bcvf_BoU-ea4CI,34
|
|
542
|
+
pulpcore-3.84.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|