pulpcore 3.76.0__py3-none-any.whl → 3.77.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
- pulp_file/tests/functional/api/test_remote_settings.py +68 -0
- pulpcore/app/apps.py +1 -1
- pulpcore/app/replica.py +4 -4
- pulpcore/app/serializers/publication.py +30 -10
- pulpcore/app/serializers/repository.py +27 -17
- pulpcore/app/settings.py +13 -1
- pulpcore/app/tasks/__init__.py +1 -1
- pulpcore/app/tasks/base.py +37 -0
- pulpcore/app/tasks/test.py +9 -6
- pulpcore/app/viewsets/base.py +2 -2
- pulpcore/constants.py +2 -0
- pulpcore/plugin/stages/artifact_stages.py +11 -5
- pulpcore/plugin/tasking.py +2 -2
- pulpcore/pytest_plugin.py +2 -0
- pulpcore/tasking/_util.py +46 -16
- pulpcore/tasking/tasks.py +44 -4
- pulpcore/tests/functional/api/test_tasking.py +151 -1
- {pulpcore-3.76.0.dist-info → pulpcore-3.77.0.dist-info}/METADATA +8 -5
- {pulpcore-3.76.0.dist-info → pulpcore-3.77.0.dist-info}/RECORD +25 -25
- {pulpcore-3.76.0.dist-info → pulpcore-3.77.0.dist-info}/WHEEL +1 -1
- {pulpcore-3.76.0.dist-info → pulpcore-3.77.0.dist-info}/entry_points.txt +0 -0
- {pulpcore-3.76.0.dist-info → pulpcore-3.77.0.dist-info}/licenses/LICENSE +0 -0
- {pulpcore-3.76.0.dist-info → pulpcore-3.77.0.dist-info}/top_level.txt +0 -0
pulp_certguard/app/__init__.py
CHANGED
pulp_file/app/__init__.py
CHANGED
|
@@ -45,9 +45,46 @@ IwtfRg==
|
|
|
45
45
|
-----END CERTIFICATE-----
|
|
46
46
|
"""
|
|
47
47
|
|
|
48
|
+
GOOD_CERT_TWO = """-----BEGIN CERTIFICATE-----
|
|
49
|
+
MIICqjCCAZICAgtCMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNVBAMMB2dvdmVnYW4w
|
|
50
|
+
HhcNMTkwMzEzMjEwMzMwWhcNMjkwMzEwMjEwMzMwWjAjMRAwDgYDVQQDDAdnb3Zl
|
|
51
|
+
Z2FuMQ8wDQYDVQQKDAZjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
|
52
|
+
AoIBAQCxJWx5t25jY4womWtKxGqv2LHg9YnU0b2VCECLhu5JjoAzFPja5VHB0Maz
|
|
53
|
+
G8m5c0+N2ubrPcBC+KdoGMd2MqrrGyzKOiwbVDW0YOgnFqh58p796iKtVboWx41y
|
|
54
|
+
Gzn289PzYccxH6mhhPmRVD25KyV1TenqvGIHJTepF7mgIemGDTv+j7+mYPT/3r6I
|
|
55
|
+
pnwTkEVPr+Q4iW0l3fNESlFFRt2b7yhz9f0E4SMhmIRnSIGOLO1zE02IJ1hTuGkx
|
|
56
|
+
/MZ1AqQdVSdm4jenTIMp91R1kYylI66yMcpU6w6x4j8qvJ8nBZ4r4DqOHcOobyHp
|
|
57
|
+
qlaJjv/K5SGJxV2k0EFk7b483lbrAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBALYh
|
|
58
|
+
SHLGJCxVL8ePFLs294fhTq4pTQsvHm8q3SyJD9DaB+HKTceCFErNv18Dsl/QwBis
|
|
59
|
+
WPHWKpDN0EUcuuE/8oUaGjjzByJ8bPafMicFCHSSefcJw+IOOqKBkWDT+4YGkvfs
|
|
60
|
+
RpwxSLqLOhEt7aSkiPcMvD20v8cvj0O36c5G3Vv0E8WmPWOEqjyPFoU9X1vACr+h
|
|
61
|
+
DdIKvxFbvRU9ObektFxOYHuvP010IBv2dGyw3G5W5fh9A5OSXHAShWSwkRU36oft
|
|
62
|
+
ugB47fIIlb7zLm4GBmxGG0yBwAf4otBlUXVNqNx15bbUuVgKbGMFfItQgEo9AQcz
|
|
63
|
+
gGsetwDOs/NgZ95oH40=
|
|
64
|
+
-----END CERTIFICATE-----
|
|
65
|
+
"""
|
|
66
|
+
|
|
48
67
|
BAD_CERT = """-----BEGIN CERTIFICATE-----\nBOGUS==\n-----END CERTIFICATE-----
|
|
49
68
|
"""
|
|
50
69
|
|
|
70
|
+
NO_CERT = """
|
|
71
|
+
MIICoDCCAYgCCQC2c2uY34HNlzANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDDAdn
|
|
72
|
+
b3ZlZ2FuMB4XDTE5MDMxMzIxMDMzMFoXDTM4MDYxNjIxMDMzMFowEjEQMA4GA1UE
|
|
73
|
+
AwwHZ292ZWdhbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANEatWsZ
|
|
74
|
+
1iwGmTxD02dxMI4ci+Au4FzvmWLBWD07H5GGTVFwnqmNOKhP6DHs1EsMZevkUvaG
|
|
75
|
+
CRxZlPYhjNFLZr2c2FnoDZ5nBXlSW6sodXURbMfyT187nDeBXVYFuh4T2eNCatnm
|
|
76
|
+
t3vgdi+pWsF0LbOgpu7GJI2sh5K1imxyB77tJ7PFTDZCSohkK+A+0nDCnJqDUNXD
|
|
77
|
+
5CK8iaBciCbnzp3nRKuM2EmgXno9Repy/HYxIgB7ZodPwDvYNjMGfvs0s9mJIKmc
|
|
78
|
+
CKgkPXVO9y9gaRrrytICcPOs+YoU/PN4Ttg6wzxaWvJgw44vsR8wM/0i4HlXfBdl
|
|
79
|
+
9br+cgn8jukDOgECAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAyNHV6NA+0GfUrvBq
|
|
80
|
+
AHXHNnBE3nzMhGPhF/0B/dO4o0n6pgGZyzRxaUaoo6+5oQnBf/2NmDyLWdalFWX7
|
|
81
|
+
D1WBaxkhK+FU922+qwQKhABlwMxGCnfZ8F+rlk4lNotm3fP4wHbnO1SGIDvvZFt/
|
|
82
|
+
mpMgkhwL4lShUFv57YylXr+D2vSFcAryKiVGk1X3sHMXlFAMLHUm3d97fJnmb1qQ
|
|
83
|
+
wC43BlJCBQF98wKtYNwTUG/9gblfk8lCB2DL1hwmPy3q9KbSDOdUK3HW6a75ZzCD
|
|
84
|
+
6mXc/Y0bJcwweDsywbPBYP13hYUcpw4htcU6hg6DsoAjLNkSrlY+GGo7htx+L9HH
|
|
85
|
+
IwtfRg==
|
|
86
|
+
"""
|
|
87
|
+
|
|
51
88
|
|
|
52
89
|
def _run_basic_sync_and_assert(file_bindings, remote, file_repo, monitor_task):
|
|
53
90
|
body = RepositorySyncURL(remote=remote.pulp_href)
|
|
@@ -274,3 +311,34 @@ def test_certificate_clean(file_remote_factory):
|
|
|
274
311
|
a_remote = file_remote_factory(url="http://example.com/", ca_cert=BAD_CERT)
|
|
275
312
|
with pytest.raises(BadRequestException):
|
|
276
313
|
a_remote = file_remote_factory(url="http://example.com/", client_cert=BAD_CERT)
|
|
314
|
+
|
|
315
|
+
# Check that a no-cert string returns the expected error
|
|
316
|
+
with pytest.raises(BadRequestException):
|
|
317
|
+
a_remote = file_remote_factory(url="http://example.com/", ca_cert=NO_CERT)
|
|
318
|
+
with pytest.raises(BadRequestException):
|
|
319
|
+
a_remote = file_remote_factory(url="http://example.com/", client_cert=NO_CERT)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
@pytest.mark.parallel
|
|
323
|
+
def test_multi_certificate_clean(file_remote_factory):
|
|
324
|
+
multi_cert = GOOD_CERT + GOOD_CERT_TWO
|
|
325
|
+
|
|
326
|
+
# Check that a good multi-cert PEM validates
|
|
327
|
+
a_remote = file_remote_factory(url="http://example.com/", ca_cert=multi_cert)
|
|
328
|
+
assert a_remote.ca_cert == multi_cert
|
|
329
|
+
a_remote = file_remote_factory(url="http://example.com/", client_cert=multi_cert)
|
|
330
|
+
assert a_remote.client_cert == multi_cert
|
|
331
|
+
|
|
332
|
+
# Check that a good-cert-with-comments validates and strips the comments
|
|
333
|
+
multi_cert_with_comment = GOOD_CERT_WITH_COMMENT + GOOD_CERT_TWO
|
|
334
|
+
a_remote = file_remote_factory(url="http://example.com/", ca_cert=multi_cert_with_comment)
|
|
335
|
+
assert a_remote.ca_cert == multi_cert
|
|
336
|
+
a_remote = file_remote_factory(url="http://example.com/", client_cert=multi_cert_with_comment)
|
|
337
|
+
assert a_remote.client_cert == multi_cert
|
|
338
|
+
|
|
339
|
+
# Check that multi-with-bad is rejected
|
|
340
|
+
multi_bad = GOOD_CERT + BAD_CERT
|
|
341
|
+
with pytest.raises(BadRequestException):
|
|
342
|
+
a_remote = file_remote_factory(url="http://example.com/", ca_cert=multi_bad)
|
|
343
|
+
with pytest.raises(BadRequestException):
|
|
344
|
+
a_remote = file_remote_factory(url="http://example.com/", client_cert=multi_bad)
|
pulpcore/app/apps.py
CHANGED
pulpcore/app/replica.py
CHANGED
|
@@ -8,7 +8,7 @@ from pulp_glue.common.context import PulpContext
|
|
|
8
8
|
from pulpcore.app.models import UpstreamPulp
|
|
9
9
|
from pulpcore.tasking.tasks import dispatch
|
|
10
10
|
from pulpcore.app.tasks.base import (
|
|
11
|
-
|
|
11
|
+
ageneral_update,
|
|
12
12
|
general_create,
|
|
13
13
|
general_multi_delete,
|
|
14
14
|
)
|
|
@@ -133,7 +133,7 @@ class Replicator:
|
|
|
133
133
|
needs_update = self.needs_update(remote_fields_dict, remote)
|
|
134
134
|
if needs_update:
|
|
135
135
|
dispatch(
|
|
136
|
-
|
|
136
|
+
ageneral_update,
|
|
137
137
|
task_group=self.task_group,
|
|
138
138
|
shared_resources=[self.server],
|
|
139
139
|
exclusive_resources=[remote],
|
|
@@ -162,7 +162,7 @@ class Replicator:
|
|
|
162
162
|
needs_update = self.needs_update(repo_fields_dict, repository)
|
|
163
163
|
if needs_update:
|
|
164
164
|
dispatch(
|
|
165
|
-
|
|
165
|
+
ageneral_update,
|
|
166
166
|
task_group=self.task_group,
|
|
167
167
|
shared_resources=[self.server],
|
|
168
168
|
exclusive_resources=[repository],
|
|
@@ -197,7 +197,7 @@ class Replicator:
|
|
|
197
197
|
if needs_update:
|
|
198
198
|
# Update the distribution
|
|
199
199
|
dispatch(
|
|
200
|
-
|
|
200
|
+
ageneral_update,
|
|
201
201
|
task_group=self.task_group,
|
|
202
202
|
shared_resources=[repository, self.server],
|
|
203
203
|
exclusive_resources=self.distros_uris,
|
|
@@ -407,14 +407,34 @@ def validate_repo_and_remote(repository, field, **kwargs):
|
|
|
407
407
|
|
|
408
408
|
detail_repo = repository.cast()
|
|
409
409
|
if detail_repo.remote and type(detail_repo.remote.cast()) not in detail_repo.REMOTE_TYPES:
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
410
|
+
repository_version = kwargs.pop("repository_version", None)
|
|
411
|
+
publication = kwargs.pop("publication", None)
|
|
412
|
+
|
|
413
|
+
if repository_version and publication:
|
|
414
|
+
msg_template = _(
|
|
415
|
+
"Type for Remote '{remote}' does not match Repository '{repository}' "
|
|
416
|
+
"from RepositoryVersion '{repository_version}' from Publication '{publication}'."
|
|
417
|
+
)
|
|
418
|
+
elif repository_version:
|
|
419
|
+
msg_template = _(
|
|
420
|
+
"Type for Remote '{remote}' does not match Repository '{repository}' "
|
|
421
|
+
"from RepositoryVersion '{repository_version}'."
|
|
422
|
+
)
|
|
423
|
+
elif publication:
|
|
424
|
+
msg_template = _(
|
|
425
|
+
"Type for Remote '{remote}' does not match Repository '{repository}' "
|
|
426
|
+
"from Publication '{publication}'."
|
|
427
|
+
)
|
|
428
|
+
else:
|
|
429
|
+
msg_template = _("Type for Remote '{remote}' does not match Repository '{repository}'.")
|
|
419
430
|
|
|
420
|
-
raise serializers.ValidationError(
|
|
431
|
+
raise serializers.ValidationError(
|
|
432
|
+
{
|
|
433
|
+
field: msg_template.format(
|
|
434
|
+
remote=get_prn(repository.remote),
|
|
435
|
+
repository=get_prn(repository),
|
|
436
|
+
repository_version=get_prn(repository_version) if repository_version else "",
|
|
437
|
+
publication=get_prn(publication) if publication else "",
|
|
438
|
+
)
|
|
439
|
+
}
|
|
440
|
+
)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import OpenSSL
|
|
2
1
|
import os
|
|
3
|
-
|
|
2
|
+
from cryptography.x509 import load_pem_x509_certificate
|
|
4
3
|
from gettext import gettext as _
|
|
5
4
|
from urllib.parse import urlparse
|
|
6
5
|
|
|
@@ -76,29 +75,41 @@ class RepositorySerializer(ModelSerializer):
|
|
|
76
75
|
|
|
77
76
|
def validate_certificate(which_cert, value):
|
|
78
77
|
"""
|
|
79
|
-
Validate and return *just* the
|
|
78
|
+
Validate and return *just* the certs and not any commentary that came along with them.
|
|
80
79
|
|
|
81
80
|
Args:
|
|
82
81
|
which_cert: The attribute-name whose cert we're validating (only used for error-message).
|
|
83
|
-
value: The string being proposed as a certificate.
|
|
82
|
+
value: The string being proposed as a certificate-containing PEM.
|
|
84
83
|
|
|
85
84
|
Raises:
|
|
86
|
-
ValidationError: When the provided value
|
|
85
|
+
ValidationError: When the provided value has no or an invalid certificate.
|
|
87
86
|
|
|
88
87
|
Returns:
|
|
89
|
-
The
|
|
88
|
+
The pem-string with *just* the validated BEGIN/END CERTIFICATE segments.
|
|
90
89
|
"""
|
|
91
90
|
if value:
|
|
92
91
|
try:
|
|
93
|
-
#
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
# Find any/all CERTIFICATE entries in the proposed PEM and let crypto validate them.
|
|
93
|
+
# NOTE: crypto/39 includes load_certificates(), which will let us remove this whole
|
|
94
|
+
# loop. But we want to fix the current problem on older supported branches that
|
|
95
|
+
# allow 38, so we do it ourselves for now
|
|
96
|
+
certs = list()
|
|
97
|
+
a_cert = ""
|
|
98
|
+
for line in value.split("\n"):
|
|
99
|
+
if "-----BEGIN CERTIFICATE-----" in line or a_cert:
|
|
100
|
+
a_cert += line + "\n"
|
|
101
|
+
if "-----END CERTIFICATE-----" in line:
|
|
102
|
+
load_pem_x509_certificate(bytes(a_cert, "ASCII"))
|
|
103
|
+
certs.append(a_cert.strip())
|
|
104
|
+
a_cert = ""
|
|
105
|
+
if not certs:
|
|
106
|
+
raise serializers.ValidationError(
|
|
107
|
+
"No {} specified in string {}".format(which_cert, value)
|
|
108
|
+
)
|
|
109
|
+
return "\n".join(certs) + "\n"
|
|
110
|
+
except ValueError as e:
|
|
100
111
|
raise serializers.ValidationError(
|
|
101
|
-
|
|
112
|
+
"Invalid {} specified, error '{}'".format(which_cert, e.args)
|
|
102
113
|
)
|
|
103
114
|
|
|
104
115
|
|
|
@@ -401,9 +412,8 @@ class RepositorySyncURLSerializer(ValidateFieldsMixin, serializers.Serializer):
|
|
|
401
412
|
if repository and type(remote.cast()) not in repository.cast().REMOTE_TYPES:
|
|
402
413
|
raise serializers.ValidationError(
|
|
403
414
|
{
|
|
404
|
-
"remote": _(
|
|
405
|
-
|
|
406
|
-
f"does not match Repository '{get_prn(repository)}'."
|
|
415
|
+
"remote": _("Type for Remote '{}' does not match Repository '{}'.").format(
|
|
416
|
+
get_prn(remote), get_prn(repository)
|
|
407
417
|
)
|
|
408
418
|
}
|
|
409
419
|
)
|
pulpcore/app/settings.py
CHANGED
|
@@ -382,7 +382,19 @@ ALLOWED_CONTENT_CHECKSUMS = ["sha224", "sha256", "sha384", "sha512"]
|
|
|
382
382
|
|
|
383
383
|
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
|
384
384
|
|
|
385
|
-
|
|
385
|
+
# Possible diagnostics:
|
|
386
|
+
# * "memory"
|
|
387
|
+
# Logs the task process RSS every couple of seconds
|
|
388
|
+
# * "pyinstrument"
|
|
389
|
+
# Dumps an HTML profile report produced by pyinstrument, showing time spent in various
|
|
390
|
+
# callstacks. This adds ~10% overhead to the task process and consumes extra memory.
|
|
391
|
+
# Tweaking code might be warranted for some advanced settings.
|
|
392
|
+
# * "memray" - Dumps a report produced by memray which logs how much memory was allocated by which
|
|
393
|
+
# lines and functions, at the time of peak RSS of the task process. This adds significant
|
|
394
|
+
# runtime overhead to the task process, 20-40%. Tweaking code might be warranted for
|
|
395
|
+
# some advanced settings.
|
|
396
|
+
# NOTE: "memray" and "pyinstrument" require additional packages to be installed on the system.
|
|
397
|
+
TASK_DIAGNOSTICS = [] # ["memory", "pyinstrument", "memray"]
|
|
386
398
|
|
|
387
399
|
ANALYTICS = True
|
|
388
400
|
|
pulpcore/app/tasks/__init__.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from pulpcore.app.tasks import base, repository, upload
|
|
2
2
|
|
|
3
3
|
from .base import (
|
|
4
|
+
ageneral_update,
|
|
4
5
|
general_create,
|
|
5
6
|
general_create_from_temp_file,
|
|
6
7
|
general_delete,
|
|
7
8
|
general_multi_delete,
|
|
8
|
-
general_update,
|
|
9
9
|
)
|
|
10
10
|
|
|
11
11
|
from .export import fs_publication_export, fs_repo_version_export
|
pulpcore/app/tasks/base.py
CHANGED
|
@@ -2,8 +2,11 @@ from django.db import transaction
|
|
|
2
2
|
|
|
3
3
|
from pulpcore.app.apps import get_plugin_config
|
|
4
4
|
from pulpcore.app.models import CreatedResource
|
|
5
|
+
from pulpcore.app.loggers import deprecation_logger
|
|
5
6
|
from pulpcore.plugin.models import MasterModel
|
|
6
7
|
|
|
8
|
+
from asgiref.sync import sync_to_async
|
|
9
|
+
|
|
7
10
|
|
|
8
11
|
def general_create_from_temp_file(app_label, serializer_name, temp_file_pk, *args, **kwargs):
|
|
9
12
|
"""
|
|
@@ -63,6 +66,10 @@ def general_update(instance_id, app_label, serializer_name, *args, **kwargs):
|
|
|
63
66
|
due to validation error. This theoretically should never occur since validation is
|
|
64
67
|
performed before the task is dispatched.
|
|
65
68
|
"""
|
|
69
|
+
deprecation_logger.warning(
|
|
70
|
+
"`pulpcore.app.tasks.base.general_update` is deprecated and will be removed in Pulp 4. "
|
|
71
|
+
"Use `pulpcore.app.tasks.base.ageneral_update` instead."
|
|
72
|
+
)
|
|
66
73
|
data = kwargs.pop("data", None)
|
|
67
74
|
partial = kwargs.pop("partial", False)
|
|
68
75
|
serializer_class = get_plugin_config(app_label).named_serializers[serializer_name]
|
|
@@ -85,6 +92,10 @@ def general_delete(instance_id, app_label, serializer_name):
|
|
|
85
92
|
app_label (str): the Django app label of the plugin that provides the model
|
|
86
93
|
serializer_name (str): name of the serializer class for the model
|
|
87
94
|
"""
|
|
95
|
+
deprecation_logger.warning(
|
|
96
|
+
"`pulpcore.app.tasks.base.general_delete` is deprecated and will be removed in Pulp 4. "
|
|
97
|
+
"Use `pulpcore.app.tasks.base.ageneral_delete` instead."
|
|
98
|
+
)
|
|
88
99
|
serializer_class = get_plugin_config(app_label).named_serializers[serializer_name]
|
|
89
100
|
instance = serializer_class.Meta.model.objects.get(pk=instance_id)
|
|
90
101
|
if isinstance(instance, MasterModel):
|
|
@@ -111,3 +122,29 @@ def general_multi_delete(instance_ids):
|
|
|
111
122
|
with transaction.atomic():
|
|
112
123
|
for instance in instances:
|
|
113
124
|
instance.delete()
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
async def ageneral_update(instance_id, app_label, serializer_name, *args, **kwargs):
|
|
128
|
+
"""
|
|
129
|
+
Async version of [pulpcore.app.tasks.base.general_update][].
|
|
130
|
+
"""
|
|
131
|
+
data = kwargs.pop("data", None)
|
|
132
|
+
partial = kwargs.pop("partial", False)
|
|
133
|
+
serializer_class = get_plugin_config(app_label).named_serializers[serializer_name]
|
|
134
|
+
instance = await serializer_class.Meta.model.objects.aget(pk=instance_id)
|
|
135
|
+
if isinstance(instance, MasterModel):
|
|
136
|
+
instance = await instance.acast()
|
|
137
|
+
serializer = serializer_class(instance, data=data, partial=partial)
|
|
138
|
+
await sync_to_async(serializer.is_valid)(raise_exception=True)
|
|
139
|
+
await sync_to_async(serializer.save)()
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
async def ageneral_delete(instance_id, app_label, serializer_name):
|
|
143
|
+
"""
|
|
144
|
+
Async version of [pulpcore.app.tasks.base.general_delete][].
|
|
145
|
+
"""
|
|
146
|
+
serializer_class = get_plugin_config(app_label).named_serializers[serializer_name]
|
|
147
|
+
instance = await serializer_class.Meta.model.objects.aget(pk=instance_id)
|
|
148
|
+
if isinstance(instance, MasterModel):
|
|
149
|
+
instance = await instance.acast()
|
|
150
|
+
await instance.adelete()
|
pulpcore/app/tasks/test.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
import backoff
|
|
3
|
+
import time
|
|
2
4
|
from pulpcore.app.models import TaskGroup
|
|
3
5
|
from pulpcore.tasking.tasks import dispatch
|
|
4
6
|
|
|
@@ -9,17 +11,18 @@ def dummy_task():
|
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
def sleep(interval):
|
|
12
|
-
|
|
14
|
+
time.sleep(interval)
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
|
|
17
|
+
async def asleep(interval):
|
|
18
|
+
"""Async function that sleeps."""
|
|
19
|
+
await asyncio.sleep(interval)
|
|
15
20
|
|
|
16
21
|
|
|
17
22
|
@backoff.on_exception(backoff.expo, BaseException)
|
|
18
23
|
def gooey_task(interval):
|
|
19
24
|
"""A sleep task that tries to avoid being killed by ignoring all exceptions."""
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
sleep(interval)
|
|
25
|
+
time.sleep(interval)
|
|
23
26
|
|
|
24
27
|
|
|
25
28
|
def dummy_group_task(inbetween=3, intervals=None):
|
|
@@ -28,5 +31,5 @@ def dummy_group_task(inbetween=3, intervals=None):
|
|
|
28
31
|
task_group = TaskGroup.current()
|
|
29
32
|
for interval in intervals:
|
|
30
33
|
dispatch(sleep, args=(interval,), task_group=task_group)
|
|
31
|
-
sleep(inbetween)
|
|
34
|
+
time.sleep(inbetween)
|
|
32
35
|
task_group.finish()
|
pulpcore/app/viewsets/base.py
CHANGED
|
@@ -492,7 +492,7 @@ class AsyncUpdateMixin(AsyncReservedObjectMixin):
|
|
|
492
492
|
serializer.is_valid(raise_exception=True)
|
|
493
493
|
app_label = instance._meta.app_label
|
|
494
494
|
task = dispatch(
|
|
495
|
-
tasks.base.
|
|
495
|
+
tasks.base.ageneral_update,
|
|
496
496
|
exclusive_resources=self.async_reserved_resources(instance),
|
|
497
497
|
args=(pk, app_label, serializer.__class__.__name__),
|
|
498
498
|
kwargs={"data": request.data, "partial": partial},
|
|
@@ -528,7 +528,7 @@ class AsyncRemoveMixin(AsyncReservedObjectMixin):
|
|
|
528
528
|
serializer = self.get_serializer(instance)
|
|
529
529
|
app_label = instance._meta.app_label
|
|
530
530
|
task = dispatch(
|
|
531
|
-
tasks.base.
|
|
531
|
+
tasks.base.ageneral_delete,
|
|
532
532
|
exclusive_resources=self.async_reserved_resources(instance),
|
|
533
533
|
args=(pk, app_label, serializer.__class__.__name__),
|
|
534
534
|
immediate=self.ALLOW_NON_BLOCKING_DELETE,
|
pulpcore/constants.py
CHANGED
|
@@ -45,6 +45,8 @@ TASK_FINAL_STATES = (
|
|
|
45
45
|
#: Tasks in an incomplete state have not finished their work yet.
|
|
46
46
|
TASK_INCOMPLETE_STATES = (TASK_STATES.WAITING, TASK_STATES.RUNNING, TASK_STATES.CANCELING)
|
|
47
47
|
|
|
48
|
+
#: Timeout for immediate tasks in seconds
|
|
49
|
+
IMMEDIATE_TIMEOUT = 5
|
|
48
50
|
|
|
49
51
|
SYNC_MODES = SimpleNamespace(ADDITIVE="additive", MIRROR="mirror")
|
|
50
52
|
SYNC_CHOICES = (
|
|
@@ -13,6 +13,7 @@ from pulpcore.plugin.models import (
|
|
|
13
13
|
ContentArtifact,
|
|
14
14
|
ProgressReport,
|
|
15
15
|
RemoteArtifact,
|
|
16
|
+
Remote,
|
|
16
17
|
)
|
|
17
18
|
from pulpcore.plugin.sync import sync_to_async_iterable
|
|
18
19
|
|
|
@@ -469,6 +470,9 @@ class ACSArtifactHandler(Stage):
|
|
|
469
470
|
Content Source if available.
|
|
470
471
|
"""
|
|
471
472
|
|
|
473
|
+
def __init__(self, *args, **kwargs):
|
|
474
|
+
self.remote_cache = {}
|
|
475
|
+
|
|
472
476
|
async def run(self):
|
|
473
477
|
async for batch in self.batches():
|
|
474
478
|
# Gather batch d_artifact checksums
|
|
@@ -484,17 +488,19 @@ class ACSArtifactHandler(Stage):
|
|
|
484
488
|
existing_ras = (
|
|
485
489
|
RemoteArtifact.objects.acs()
|
|
486
490
|
.filter(**{f"{checksum_type}__in": batch_checksums[checksum_type]})
|
|
487
|
-
.only("url", checksum_type, "
|
|
488
|
-
.select_related("remote")
|
|
491
|
+
.only("url", checksum_type, "remote_id")
|
|
489
492
|
)
|
|
490
|
-
# todo: we could probably get rid of this select_related by separating
|
|
491
|
-
# out the remote query
|
|
492
493
|
async for ra in existing_ras.aiterator():
|
|
493
494
|
checksum = getattr(ra, checksum_type)
|
|
494
495
|
# pick the first occurence of RA from ACS
|
|
495
496
|
if checksum not in existing_ras_dict:
|
|
497
|
+
if ra.remote_id not in self.remote_cache:
|
|
498
|
+
self.remote_cache[ra.remote_id] = await Remote.objects.aget(
|
|
499
|
+
pk=ra.remote_id
|
|
500
|
+
)
|
|
501
|
+
|
|
496
502
|
existing_ras_dict[checksum] = {
|
|
497
|
-
"remote": ra.
|
|
503
|
+
"remote": self.remote_cache[ra.remote_id],
|
|
498
504
|
"url": ra.url,
|
|
499
505
|
}
|
|
500
506
|
|
pulpcore/plugin/tasking.py
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
from pulpcore.tasking.tasks import dispatch
|
|
3
3
|
|
|
4
4
|
from pulpcore.app.tasks import (
|
|
5
|
+
ageneral_update,
|
|
5
6
|
fs_publication_export,
|
|
6
7
|
fs_repo_version_export,
|
|
7
8
|
general_create,
|
|
8
9
|
general_create_from_temp_file,
|
|
9
10
|
general_delete,
|
|
10
11
|
general_multi_delete,
|
|
11
|
-
general_update,
|
|
12
12
|
orphan_cleanup,
|
|
13
13
|
reclaim_space,
|
|
14
14
|
)
|
|
@@ -16,6 +16,7 @@ from pulpcore.app.tasks.repository import add_and_remove
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
__all__ = [
|
|
19
|
+
"ageneral_update",
|
|
19
20
|
"dispatch",
|
|
20
21
|
"fs_publication_export",
|
|
21
22
|
"fs_repo_version_export",
|
|
@@ -23,7 +24,6 @@ __all__ = [
|
|
|
23
24
|
"general_create_from_temp_file",
|
|
24
25
|
"general_delete",
|
|
25
26
|
"general_multi_delete",
|
|
26
|
-
"general_update",
|
|
27
27
|
"orphan_cleanup",
|
|
28
28
|
"reclaim_space",
|
|
29
29
|
"add_and_remove",
|
pulpcore/pytest_plugin.py
CHANGED
|
@@ -9,6 +9,7 @@ import shutil
|
|
|
9
9
|
import socket
|
|
10
10
|
import ssl
|
|
11
11
|
import subprocess
|
|
12
|
+
import sys
|
|
12
13
|
import threading
|
|
13
14
|
import uuid
|
|
14
15
|
|
|
@@ -1017,6 +1018,7 @@ def dispatch_task(pulpcore_bindings):
|
|
|
1017
1018
|
|
|
1018
1019
|
assert process.returncode == 0
|
|
1019
1020
|
task_href = process.stdout.decode().strip()
|
|
1021
|
+
print(process.stderr.decode(), file=sys.stderr)
|
|
1020
1022
|
return task_href
|
|
1021
1023
|
|
|
1022
1024
|
return _dispatch_task
|
pulpcore/tasking/_util.py
CHANGED
|
@@ -71,8 +71,8 @@ def write_memory_usage(stop_event, path):
|
|
|
71
71
|
current_mb_in_use = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024
|
|
72
72
|
file.write(f"{seconds}\t{current_mb_in_use:.2f}\n")
|
|
73
73
|
file.flush()
|
|
74
|
-
time.sleep(
|
|
75
|
-
seconds +=
|
|
74
|
+
time.sleep(2)
|
|
75
|
+
seconds += 2
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
def child_signal_handler(sig, frame):
|
|
@@ -135,15 +135,21 @@ def perform_task(task_pk, task_working_dir_rel_path):
|
|
|
135
135
|
|
|
136
136
|
def _execute_task_and_profile(task):
|
|
137
137
|
with tempfile.TemporaryDirectory(dir=settings.WORKING_DIRECTORY) as temp_dir:
|
|
138
|
-
|
|
139
|
-
memory_func = _memory_diagnostic_decorator(temp_dir, pyinstrument_func)
|
|
138
|
+
_execute_task = execute_task
|
|
140
139
|
|
|
141
|
-
|
|
140
|
+
if settings.TASK_DIAGNOSTICS is True or "memory" in settings.TASK_DIAGNOSTICS:
|
|
141
|
+
_execute_task = _memory_diagnostic_decorator(temp_dir, _execute_task)
|
|
142
|
+
if settings.TASK_DIAGNOSTICS is True or "pyinstrument" in settings.TASK_DIAGNOSTICS:
|
|
143
|
+
_execute_task = _pyinstrument_diagnostic_decorator(temp_dir, _execute_task)
|
|
144
|
+
if settings.TASK_DIAGNOSTICS is True or "memray" in settings.TASK_DIAGNOSTICS:
|
|
145
|
+
_execute_task = _memray_diagnostic_decorator(temp_dir, _execute_task)
|
|
146
|
+
|
|
147
|
+
_execute_task(task)
|
|
142
148
|
|
|
143
149
|
|
|
144
150
|
def _memory_diagnostic_decorator(temp_dir, func):
|
|
145
151
|
def __memory_diagnostic_decorator(task):
|
|
146
|
-
mem_diagnostics_file_path = os.path.join(temp_dir, "
|
|
152
|
+
mem_diagnostics_file_path = os.path.join(temp_dir, "memory_profile.datum")
|
|
147
153
|
# It would be better to have this recording happen in the parent process instead of here
|
|
148
154
|
# https://github.com/pulp/pulpcore/issues/2337
|
|
149
155
|
stop_event = threading.Event()
|
|
@@ -158,10 +164,10 @@ def _memory_diagnostic_decorator(temp_dir, func):
|
|
|
158
164
|
artifact = Artifact.init_and_validate(mem_diagnostics_file_path)
|
|
159
165
|
with suppress(IntegrityError):
|
|
160
166
|
artifact.save()
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
167
|
+
ProfileArtifact.objects.get_or_create(
|
|
168
|
+
artifact=artifact, name="memory_profile", task=task
|
|
169
|
+
)
|
|
170
|
+
_logger.info("Created memory diagnostic data.")
|
|
165
171
|
|
|
166
172
|
return __memory_diagnostic_decorator
|
|
167
173
|
|
|
@@ -171,7 +177,7 @@ def _pyinstrument_diagnostic_decorator(temp_dir, func):
|
|
|
171
177
|
if importlib.util.find_spec("pyinstrument") is not None:
|
|
172
178
|
from pyinstrument import Profiler
|
|
173
179
|
|
|
174
|
-
with Profiler() as profiler:
|
|
180
|
+
with Profiler(interval=0.002) as profiler:
|
|
175
181
|
func(task)
|
|
176
182
|
|
|
177
183
|
profile_file_path = os.path.join(temp_dir, "pyinstrument.html")
|
|
@@ -182,16 +188,40 @@ def _pyinstrument_diagnostic_decorator(temp_dir, func):
|
|
|
182
188
|
artifact = Artifact.init_and_validate(str(profile_file_path))
|
|
183
189
|
with suppress(IntegrityError):
|
|
184
190
|
artifact.save()
|
|
191
|
+
ProfileArtifact.objects.get_or_create(
|
|
192
|
+
artifact=artifact, name="pyinstrument_profile", task=task
|
|
193
|
+
)
|
|
194
|
+
_logger.info("Created pyinstrument profile data.")
|
|
195
|
+
else:
|
|
196
|
+
func(task)
|
|
185
197
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
198
|
+
return __pyinstrument_diagnostic_decorator
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _memray_diagnostic_decorator(temp_dir, func):
|
|
202
|
+
def __memray_diagnostic_decorator(task):
|
|
203
|
+
if importlib.util.find_spec("memray") is not None:
|
|
204
|
+
import memray
|
|
205
|
+
|
|
206
|
+
profile_file_path = os.path.join(temp_dir, "memray_profile.bin")
|
|
207
|
+
with memray.Tracker(
|
|
208
|
+
profile_file_path,
|
|
209
|
+
native_traces=False,
|
|
210
|
+
file_format=memray.FileFormat.AGGREGATED_ALLOCATIONS,
|
|
211
|
+
):
|
|
212
|
+
func(task)
|
|
189
213
|
|
|
190
|
-
|
|
214
|
+
artifact = Artifact.init_and_validate(str(profile_file_path))
|
|
215
|
+
with suppress(IntegrityError):
|
|
216
|
+
artifact.save()
|
|
217
|
+
ProfileArtifact.objects.get_or_create(
|
|
218
|
+
artifact=artifact, name="memray_profile", task=task
|
|
219
|
+
)
|
|
220
|
+
_logger.info("Created memray memory profile data.")
|
|
191
221
|
else:
|
|
192
222
|
func(task)
|
|
193
223
|
|
|
194
|
-
return
|
|
224
|
+
return __memray_diagnostic_decorator
|
|
195
225
|
|
|
196
226
|
|
|
197
227
|
def dispatch_scheduled_tasks():
|
pulpcore/tasking/tasks.py
CHANGED
|
@@ -7,6 +7,8 @@ import os
|
|
|
7
7
|
import sys
|
|
8
8
|
import traceback
|
|
9
9
|
import tempfile
|
|
10
|
+
import threading
|
|
11
|
+
from asgiref.sync import sync_to_async
|
|
10
12
|
from datetime import timedelta
|
|
11
13
|
from gettext import gettext as _
|
|
12
14
|
|
|
@@ -16,12 +18,13 @@ from django.db.models import Model, Max
|
|
|
16
18
|
from django_guid import get_guid
|
|
17
19
|
from pulpcore.app.apps import MODULE_PLUGIN_VERSIONS
|
|
18
20
|
from pulpcore.app.models import Task, TaskGroup
|
|
19
|
-
from pulpcore.app.util import current_task, get_domain, get_prn
|
|
21
|
+
from pulpcore.app.util import current_task, get_domain, get_prn, deprecation_logger
|
|
20
22
|
from pulpcore.constants import (
|
|
21
23
|
TASK_FINAL_STATES,
|
|
22
24
|
TASK_INCOMPLETE_STATES,
|
|
23
25
|
TASK_STATES,
|
|
24
26
|
TASK_DISPATCH_LOCK,
|
|
27
|
+
IMMEDIATE_TIMEOUT,
|
|
25
28
|
)
|
|
26
29
|
from pulpcore.tasking.kafka import send_task_notification
|
|
27
30
|
|
|
@@ -75,11 +78,38 @@ def _execute_task(task):
|
|
|
75
78
|
func = getattr(module, function_name)
|
|
76
79
|
args = task.enc_args or ()
|
|
77
80
|
kwargs = task.enc_kwargs or {}
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
immediate = task.immediate
|
|
82
|
+
is_coroutine_fn = asyncio.iscoroutinefunction(func)
|
|
83
|
+
|
|
84
|
+
if not is_coroutine_fn:
|
|
85
|
+
if immediate:
|
|
86
|
+
deprecation_logger.warning(
|
|
87
|
+
"Immediate tasks must be coroutine functions. "
|
|
88
|
+
"Support for non-coroutine immediate tasks will be dropped "
|
|
89
|
+
"in pulpcore 3.85."
|
|
90
|
+
)
|
|
91
|
+
func = sync_to_async(func)
|
|
92
|
+
is_coroutine_fn = True
|
|
93
|
+
else:
|
|
94
|
+
func(*args, **kwargs)
|
|
95
|
+
|
|
96
|
+
if is_coroutine_fn:
|
|
80
97
|
_logger.debug("Task is coroutine %s", task.pk)
|
|
98
|
+
coro = func(*args, **kwargs)
|
|
99
|
+
if immediate:
|
|
100
|
+
coro = asyncio.wait_for(coro, timeout=IMMEDIATE_TIMEOUT)
|
|
81
101
|
loop = asyncio.get_event_loop()
|
|
82
|
-
|
|
102
|
+
try:
|
|
103
|
+
loop.run_until_complete(coro)
|
|
104
|
+
except asyncio.TimeoutError:
|
|
105
|
+
_logger.info(
|
|
106
|
+
"Immediate task %s timed out after %s seconds.", task.pk, IMMEDIATE_TIMEOUT
|
|
107
|
+
)
|
|
108
|
+
raise RuntimeError(
|
|
109
|
+
"Immediate task timed out after {timeout} seconds.".format(
|
|
110
|
+
timeout=IMMEDIATE_TIMEOUT,
|
|
111
|
+
)
|
|
112
|
+
)
|
|
83
113
|
|
|
84
114
|
except Exception:
|
|
85
115
|
exc_type, exc, tb = sys.exc_info()
|
|
@@ -101,6 +131,14 @@ def _execute_task(task):
|
|
|
101
131
|
send_task_notification(task)
|
|
102
132
|
|
|
103
133
|
|
|
134
|
+
def running_from_thread_pool() -> bool:
|
|
135
|
+
# TODO: this needs an alternative approach ASAP!
|
|
136
|
+
# Currently we rely on the weak fact that ThreadPoolExecutor names threads like:
|
|
137
|
+
# "ThreadPoolExecutor-0_0"
|
|
138
|
+
thread_name = threading.current_thread().name
|
|
139
|
+
return "ThreadPoolExecutor" in thread_name
|
|
140
|
+
|
|
141
|
+
|
|
104
142
|
def dispatch(
|
|
105
143
|
func,
|
|
106
144
|
args=None,
|
|
@@ -148,6 +186,8 @@ def dispatch(
|
|
|
148
186
|
ValueError: When `resources` is an unsupported type.
|
|
149
187
|
"""
|
|
150
188
|
|
|
189
|
+
# Can't run short tasks immediately if running from thread pool
|
|
190
|
+
immediate = immediate and not running_from_thread_pool()
|
|
151
191
|
assert deferred or immediate, "A task must be at least `deferred` or `immediate`."
|
|
152
192
|
|
|
153
193
|
if callable(func):
|
|
@@ -10,8 +10,10 @@ from urllib.parse import urljoin
|
|
|
10
10
|
from uuid import uuid4
|
|
11
11
|
|
|
12
12
|
from pulpcore.client.pulpcore import ApiException
|
|
13
|
+
from contextlib import contextmanager
|
|
13
14
|
|
|
14
|
-
from pulpcore.tests.functional.utils import download_file
|
|
15
|
+
from pulpcore.tests.functional.utils import download_file, PulpTaskError
|
|
16
|
+
from pulpcore.constants import IMMEDIATE_TIMEOUT
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
@pytest.fixture(scope="module")
|
|
@@ -445,3 +447,151 @@ def test_cancel_task_group(pulpcore_bindings, dispatch_task_group, gen_user):
|
|
|
445
447
|
|
|
446
448
|
with gen_user(model_roles=["core.task_owner"]):
|
|
447
449
|
pulpcore_bindings.TaskGroupsApi.task_groups_cancel(tgroup_href, {"state": "canceled"})
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
LT_TIMEOUT = IMMEDIATE_TIMEOUT / 2
|
|
453
|
+
GT_TIMEOUT = IMMEDIATE_TIMEOUT * 2
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
class TestImmediateTaskWithNoResource:
|
|
457
|
+
|
|
458
|
+
@pytest.mark.parallel
|
|
459
|
+
def test_succeeds_on_api_worker(self, pulpcore_bindings, dispatch_task):
|
|
460
|
+
"""
|
|
461
|
+
GIVEN a task with no resource requirements
|
|
462
|
+
AND the task IS an async function
|
|
463
|
+
WHEN dispatching a task as immediate
|
|
464
|
+
THEN the task completes with no associated worker
|
|
465
|
+
"""
|
|
466
|
+
task_href = dispatch_task(
|
|
467
|
+
"pulpcore.app.tasks.test.asleep", args=(LT_TIMEOUT,), immediate=True
|
|
468
|
+
)
|
|
469
|
+
task = pulpcore_bindings.TasksApi.read(task_href)
|
|
470
|
+
assert task.state == "completed"
|
|
471
|
+
assert task.worker is None
|
|
472
|
+
|
|
473
|
+
@pytest.mark.parallel
|
|
474
|
+
def test_executes_on_api_worker_when_no_async(self, pulpcore_bindings, dispatch_task, capsys):
|
|
475
|
+
"""
|
|
476
|
+
GIVEN a task with no resource requirements
|
|
477
|
+
AND the task IS NOT an async function
|
|
478
|
+
WHEN dispatching a task as immediate
|
|
479
|
+
THEN the task completes with no associated worker
|
|
480
|
+
"""
|
|
481
|
+
# TODO: on 3.85 this should throw an error
|
|
482
|
+
task_href = dispatch_task(
|
|
483
|
+
"pulpcore.app.tasks.test.sleep", args=(LT_TIMEOUT,), immediate=True
|
|
484
|
+
)
|
|
485
|
+
stderr_content = capsys.readouterr().err
|
|
486
|
+
task = pulpcore_bindings.TasksApi.read(task_href)
|
|
487
|
+
assert task.state == "completed"
|
|
488
|
+
assert task.worker is None
|
|
489
|
+
assert "Support for non-coroutine immediate tasks will be dropped" in stderr_content
|
|
490
|
+
|
|
491
|
+
@pytest.mark.parallel
|
|
492
|
+
def test_timeouts_on_api_worker(self, pulpcore_bindings, dispatch_task):
|
|
493
|
+
"""
|
|
494
|
+
GIVEN a task with no resource requirements
|
|
495
|
+
AND the task is an async function
|
|
496
|
+
WHEN dispatching a task as immediate
|
|
497
|
+
AND it takes longer than timeout
|
|
498
|
+
THEN the task fails with a timeout error message
|
|
499
|
+
"""
|
|
500
|
+
task_href = dispatch_task(
|
|
501
|
+
"pulpcore.app.tasks.test.asleep", args=(GT_TIMEOUT,), immediate=True
|
|
502
|
+
)
|
|
503
|
+
task = pulpcore_bindings.TasksApi.read(task_href)
|
|
504
|
+
assert task.worker is None
|
|
505
|
+
assert "task timed out after" in task.error["description"]
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
@pytest.fixture
|
|
509
|
+
def resource_blocker(pulpcore_bindings, dispatch_task):
|
|
510
|
+
|
|
511
|
+
@contextmanager
|
|
512
|
+
def _resource_blocker(exclusive_resources: list[str], duration=20):
|
|
513
|
+
task_href = dispatch_task(
|
|
514
|
+
"pulpcore.app.tasks.test.sleep",
|
|
515
|
+
args=(duration,),
|
|
516
|
+
exclusive_resources=exclusive_resources,
|
|
517
|
+
)
|
|
518
|
+
yield
|
|
519
|
+
# Trying to cancel a finished task will return a 409 code.
|
|
520
|
+
# We can ignore if that's the case, because all we want here is to cut time down.
|
|
521
|
+
# Otherwise it might be a real error.
|
|
522
|
+
try:
|
|
523
|
+
pulpcore_bindings.TasksApi.tasks_cancel(task_href, {"state": "canceled"})
|
|
524
|
+
except ApiException as e:
|
|
525
|
+
if e.status != 409:
|
|
526
|
+
raise
|
|
527
|
+
|
|
528
|
+
return _resource_blocker
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
class TestImmediateTaskWithBlockedResource:
|
|
532
|
+
|
|
533
|
+
@pytest.mark.parallel
|
|
534
|
+
def test_executes_in_task_worker(
|
|
535
|
+
self, resource_blocker, dispatch_task, monitor_task, pulpcore_bindings
|
|
536
|
+
):
|
|
537
|
+
"""
|
|
538
|
+
GIVEN an async task requiring busy resources
|
|
539
|
+
WHEN dispatching a task as immediate
|
|
540
|
+
THEN the task completes with a worker
|
|
541
|
+
"""
|
|
542
|
+
COMMON_RESOURCE = str(uuid4())
|
|
543
|
+
with resource_blocker(exclusive_resources=[COMMON_RESOURCE]):
|
|
544
|
+
task_href = dispatch_task(
|
|
545
|
+
"pulpcore.app.tasks.test.asleep",
|
|
546
|
+
args=(LT_TIMEOUT,),
|
|
547
|
+
immediate=True,
|
|
548
|
+
exclusive_resources=[COMMON_RESOURCE],
|
|
549
|
+
)
|
|
550
|
+
task = monitor_task(task_href)
|
|
551
|
+
assert task.state == "completed"
|
|
552
|
+
assert task.worker is not None
|
|
553
|
+
|
|
554
|
+
@pytest.mark.parallel
|
|
555
|
+
def test_throws_when_non_deferrable(
|
|
556
|
+
self, resource_blocker, pulpcore_bindings, dispatch_task, monitor_task
|
|
557
|
+
):
|
|
558
|
+
"""
|
|
559
|
+
GIVEN an async task requiring busy resources
|
|
560
|
+
WHEN dispatching as immediate and not deferrable
|
|
561
|
+
THEN an error is raised
|
|
562
|
+
"""
|
|
563
|
+
COMMON_RESOURCE = str(uuid4())
|
|
564
|
+
with resource_blocker(exclusive_resources=[COMMON_RESOURCE]):
|
|
565
|
+
task_href = dispatch_task(
|
|
566
|
+
"pulpcore.app.tasks.test.asleep",
|
|
567
|
+
args=(0,),
|
|
568
|
+
immediate=True,
|
|
569
|
+
deferred=False,
|
|
570
|
+
exclusive_resources=[COMMON_RESOURCE],
|
|
571
|
+
)
|
|
572
|
+
task = pulpcore_bindings.TasksApi.read(task_href)
|
|
573
|
+
assert task.state == "canceled"
|
|
574
|
+
assert task.worker is None
|
|
575
|
+
assert "Resources temporarily unavailable." in task.error["reason"]
|
|
576
|
+
|
|
577
|
+
@pytest.mark.parallel
|
|
578
|
+
def test_times_out_on_task_worker(
|
|
579
|
+
self, resource_blocker, pulpcore_bindings, dispatch_task, monitor_task
|
|
580
|
+
):
|
|
581
|
+
"""
|
|
582
|
+
GIVEN an async task requiring busy resources
|
|
583
|
+
WHEN dispatching a task as immediate
|
|
584
|
+
AND it takes longer than timeout
|
|
585
|
+
THEN an error is raised
|
|
586
|
+
"""
|
|
587
|
+
COMMON_RESOURCE = str(uuid4())
|
|
588
|
+
with pytest.raises(PulpTaskError) as ctx:
|
|
589
|
+
with resource_blocker(exclusive_resources=[COMMON_RESOURCE]):
|
|
590
|
+
task_href = dispatch_task(
|
|
591
|
+
"pulpcore.app.tasks.test.asleep",
|
|
592
|
+
args=(GT_TIMEOUT,),
|
|
593
|
+
immediate=True,
|
|
594
|
+
exclusive_resources=[COMMON_RESOURCE],
|
|
595
|
+
)
|
|
596
|
+
monitor_task(task_href)
|
|
597
|
+
assert "task timed out after" in ctx.value.task.error["description"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pulpcore
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.77.0
|
|
4
4
|
Summary: Pulp Django Application and Related Modules
|
|
5
5
|
Author-email: Pulp Team <pulp-list@redhat.com>
|
|
6
6
|
Project-URL: Homepage, https://pulpproject.org
|
|
@@ -21,14 +21,14 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
21
21
|
Requires-Python: >=3.9
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
License-File: LICENSE
|
|
24
|
-
Requires-Dist: aiodns<=3.
|
|
24
|
+
Requires-Dist: aiodns<=3.3.0,>=3.0
|
|
25
25
|
Requires-Dist: aiofiles<24.2.0,>=22.1
|
|
26
26
|
Requires-Dist: aiohttp<3.12,>=3.8.1
|
|
27
27
|
Requires-Dist: asyncio-throttle<=1.0.2,>=1.0
|
|
28
28
|
Requires-Dist: async-timeout<4.0.4,>=4.0.3; python_version < "3.11"
|
|
29
29
|
Requires-Dist: backoff<2.2.2,>=2.1.2
|
|
30
30
|
Requires-Dist: click<=8.1.8,>=8.1.0
|
|
31
|
-
Requires-Dist: cryptography<44.0.
|
|
31
|
+
Requires-Dist: cryptography<44.0.4,>=38.0.1
|
|
32
32
|
Requires-Dist: Django~=4.2.0
|
|
33
33
|
Requires-Dist: django-filter<=25.1,>=23.1
|
|
34
34
|
Requires-Dist: django-guid<=3.5.1,>=3.3
|
|
@@ -52,13 +52,13 @@ Requires-Dist: opentelemetry-exporter-otlp-proto-http<1.33,>=1.27.0
|
|
|
52
52
|
Requires-Dist: protobuf<6.0,>=4.21.1
|
|
53
53
|
Requires-Dist: pulp-glue<0.33,>=0.18.0
|
|
54
54
|
Requires-Dist: pygtrie<=2.5.0,>=2.5
|
|
55
|
-
Requires-Dist: psycopg[binary]<=3.2.
|
|
55
|
+
Requires-Dist: psycopg[binary]<=3.2.7,>=3.1.8
|
|
56
56
|
Requires-Dist: pyparsing<=3.2.3,>=3.1.0
|
|
57
57
|
Requires-Dist: python-gnupg<=0.5.4,>=0.5
|
|
58
58
|
Requires-Dist: PyYAML<=6.0.2,>=5.1.1
|
|
59
59
|
Requires-Dist: redis<5.2.2,>=4.3
|
|
60
60
|
Requires-Dist: tablib<3.6.0
|
|
61
|
-
Requires-Dist: url-normalize<=2.2.
|
|
61
|
+
Requires-Dist: url-normalize<=2.2.1,>=1.4.3
|
|
62
62
|
Requires-Dist: uuid6<=2024.7.10,>=2023.5.2
|
|
63
63
|
Requires-Dist: whitenoise<6.10.0,>=5.0
|
|
64
64
|
Requires-Dist: yarl<1.20.1,>=1.8
|
|
@@ -75,6 +75,9 @@ Requires-Dist: django-prometheus; extra == "prometheus"
|
|
|
75
75
|
Provides-Extra: kafka
|
|
76
76
|
Requires-Dist: cloudevents==1.11.0; extra == "kafka"
|
|
77
77
|
Requires-Dist: confluent-kafka<2.10.0,>=2.4.0; extra == "kafka"
|
|
78
|
+
Provides-Extra: diagnostics
|
|
79
|
+
Requires-Dist: pyinstrument~=5.0; extra == "diagnostics"
|
|
80
|
+
Requires-Dist: memray~=1.17; extra == "diagnostics"
|
|
78
81
|
Dynamic: license-file
|
|
79
82
|
|
|
80
83
|
|
|
@@ -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=Ri9QtsoSI0bmv_5qz0wCvWhDbrGkCr8nUXdTtLNS8QM,297
|
|
4
4
|
pulp_certguard/app/models.py,sha256=xy5IWxf0LQxayIDmQw25Y2YhB_NrlTGvuvdY-YW7QBU,8119
|
|
5
5
|
pulp_certguard/app/serializers.py,sha256=3jxWu82vU3xA578Qbyz-G4Q9Zlh3MFLGRHzX62M0RF8,1826
|
|
6
6
|
pulp_certguard/app/utils.py,sha256=O6T1Npdb8fu3XqIkDJd8PQdEFJWPUeQ-i_aHXBl7MEc,816
|
|
@@ -49,7 +49,7 @@ pulp_certguard/tests/unit/test_models.py,sha256=TBI0yKsrdbnJSPeBFfxSqhXK7zaNvR6q
|
|
|
49
49
|
pulp_file/__init__.py,sha256=0vOCXofR6Eyxkg4y66esnOGPeESCe23C1cNBHj56w44,61
|
|
50
50
|
pulp_file/manifest.py,sha256=1WwIOJrPSkFcmkRm7CkWifVOCoZvo_nnANgce6uuG7U,3796
|
|
51
51
|
pulp_file/pytest_plugin.py,sha256=Fi_p-Vle_I-VYUSe4Zlg7esb_Ul5fpB8Rx9UGLK5UNQ,13281
|
|
52
|
-
pulp_file/app/__init__.py,sha256=
|
|
52
|
+
pulp_file/app/__init__.py,sha256=jbAB2BH6-V4jKXVeEoaxYLmvFY-CRmc2LSOL3mBWyEw,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
|
|
@@ -94,23 +94,23 @@ pulp_file/tests/functional/api/test_mime_types.py,sha256=ZTZVpEnYXcXsDVo1PaaWEXY
|
|
|
94
94
|
pulp_file/tests/functional/api/test_publish.py,sha256=Bjb-IHknmlXS0gY15OUDvQFNJJQJqWaXU7uFmORBOOQ,5844
|
|
95
95
|
pulp_file/tests/functional/api/test_pulp_export.py,sha256=j8MJs1H4-fdRZecxroYpKHEu0aqcsPw21Fxx6YC3b10,10275
|
|
96
96
|
pulp_file/tests/functional/api/test_rbac.py,sha256=8smU2gy94Bj03CiKC_8nIbB-AdZxoLbJT3G2rzGENgk,12423
|
|
97
|
-
pulp_file/tests/functional/api/test_remote_settings.py,sha256=
|
|
97
|
+
pulp_file/tests/functional/api/test_remote_settings.py,sha256=gpIgzuPCR2y_fJF-lOIA5SFFMcVEWfFxF6S0PiHAl7s,12034
|
|
98
98
|
pulp_file/tests/functional/api/test_sync.py,sha256=jN87UoibkoJkqBV36ctvB9v72JKQHFnciRxFA-_1VfA,5673
|
|
99
99
|
pulp_file/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
100
100
|
pulp_file/tests/unit/test_safe_paths.py,sha256=CRJX3-MdIZF_4-hVK-7brH9LSK2i97GdIYdqpe3Ao84,3796
|
|
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=06lih8sVRzHCrBXGmoT3Q-9ZkKZUEEYZ8EoeFfxEq04,4673
|
|
105
105
|
pulpcore/filters.py,sha256=dD5oRRkWg65s3LoObr-ipRvRsxZK_3Zr0lKMNr9Sg5o,16682
|
|
106
106
|
pulpcore/metrics.py,sha256=Mfq-nnRjRf3vBHFO-ux-4d1I3yE7TgeptwgiSgGz4rA,2230
|
|
107
107
|
pulpcore/middleware.py,sha256=tJB2rGnulvNBN1fZ6lyN4zd60ja5QUNYD4l5dLHHaoY,5079
|
|
108
108
|
pulpcore/migrations.py,sha256=gzUTxcXnbYkM0_vN8Rfr_XWuwsGWedVZAwNy9JqJ8sQ,2476
|
|
109
|
-
pulpcore/pytest_plugin.py,sha256=
|
|
109
|
+
pulpcore/pytest_plugin.py,sha256=Tq_xlO8Z2iyjFtbnaKHbWQogq6jxcRpjji9XbKrs5_U,37780
|
|
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=Dyk1l_Cch5VavYZp-bbWsJA1SP9RcqQN9dPjHEKmtRE,17860
|
|
114
114
|
pulpcore/app/authentication.py,sha256=1LIJW6HIQQlZrliHy__jdzkDEh6Oj7xKgd0V-vRcDus,2855
|
|
115
115
|
pulpcore/app/checks.py,sha256=jbfTF7nmftBbky4AQXHigpyCaGydKasvRUXsd72JZVg,1946
|
|
116
116
|
pulpcore/app/entrypoint.py,sha256=HRfaHDkveSIfcTOtWEWYqg1poTmTo0J9hzzmj0yDcEM,4885
|
|
@@ -125,10 +125,10 @@ pulpcore/app/openpgp.py,sha256=jyvOBlu_wGDH_aem3TN8hw51Dx2dd3NyLzCw4Q9Xlf0,17246
|
|
|
125
125
|
pulpcore/app/pulp_hashlib.py,sha256=NoVCO8duLz9rggPcilg0smi6fTDnsn-zS9dXgO831Pg,1327
|
|
126
126
|
pulpcore/app/pulpcore_gunicorn_application.py,sha256=caqbDg9dhzECbx9Ss76biuEARhquj9gQaSL6v3XLy2w,2612
|
|
127
127
|
pulpcore/app/redis_connection.py,sha256=VTdG0ulXuyESjYV6SJdG_jLzkLZH-MlLcD6pielwRSk,952
|
|
128
|
-
pulpcore/app/replica.py,sha256=
|
|
128
|
+
pulpcore/app/replica.py,sha256=b6r-QF4H4G94N5HoaV3PGHeOD4-BqVb7YVsRNHx0h9Y,11675
|
|
129
129
|
pulpcore/app/response.py,sha256=hYH_jSBrxmRsBr2bknmXE1qfs2g8JjDTXYcQ5ZWlF_c,1950
|
|
130
130
|
pulpcore/app/role_util.py,sha256=84HSt8_9fxB--dtfSyg_TumVgOdyBbyP6rBaiAfTpOU,22393
|
|
131
|
-
pulpcore/app/settings.py,sha256=
|
|
131
|
+
pulpcore/app/settings.py,sha256=34pHnUfM1AzF1nKNtt31nthuFyQBd006fcH_Hq4ZmxI,22509
|
|
132
132
|
pulpcore/app/urls.py,sha256=0gdI74CAdycJStXSw1gknviDGe3J3k0UhS4J8RYa5dg,8120
|
|
133
133
|
pulpcore/app/util.py,sha256=kenzRmvDl1obKFb806ETlEE2qs8h3Y1KcCe-Q8AtYGY,24442
|
|
134
134
|
pulpcore/app/wsgi.py,sha256=7rpZ_1NHEN_UfeNZCj8206bas1WeqRkHnGdxpd7rdDI,492
|
|
@@ -318,19 +318,19 @@ pulpcore/app/serializers/importer.py,sha256=PVSNs5U0dfAm-XlRKpMqOXK0VmUErxJauNJC
|
|
|
318
318
|
pulpcore/app/serializers/openpgp.py,sha256=3Svxskj_-HmOVbjay7QI82zXnKTsbtaSlZZ03CoT-MQ,8966
|
|
319
319
|
pulpcore/app/serializers/orphans.py,sha256=Vhyaj0fqYT4pkiYoNjgmsy1u5BiR_aHwZm2y7rk9cbk,1967
|
|
320
320
|
pulpcore/app/serializers/progress.py,sha256=j4IQDLb_XOrLzTud4Fq8T-8kkOqLewReMVkbS5uCEIg,2575
|
|
321
|
-
pulpcore/app/serializers/publication.py,sha256=
|
|
321
|
+
pulpcore/app/serializers/publication.py,sha256=9Lzvn5e04TQ8EVMR_aR5NWK-P3X_4PYSUaWAfD2rHQg,16439
|
|
322
322
|
pulpcore/app/serializers/purge.py,sha256=CnjKWUvkuI207QMbqwmNs7FqMdOMUh1cujagby3vVM0,779
|
|
323
323
|
pulpcore/app/serializers/reclaim.py,sha256=-ewdNqu-Ck1B_IUWJHG0pvN5zCMMEK9RiWI45g7D0ro,1710
|
|
324
324
|
pulpcore/app/serializers/repair.py,sha256=uKrxTnhoarxyyGCixPRn9pmG19gRRVUTM7nPwCVp6_8,554
|
|
325
325
|
pulpcore/app/serializers/replica.py,sha256=E3jwn1vfBqT4Y4s9pWsTrUEJKPO9pO0q2ZmwcpIDVh4,4044
|
|
326
|
-
pulpcore/app/serializers/repository.py,sha256=
|
|
326
|
+
pulpcore/app/serializers/repository.py,sha256=fSM92qJTjQIGXgnmA4xr62jRG9atYj6tkI_ZM6VFaM0,20224
|
|
327
327
|
pulpcore/app/serializers/status.py,sha256=nIrQl-MlOzUIvV2DrkgC19gqGmRVNKvWVN4pIBELgcQ,3815
|
|
328
328
|
pulpcore/app/serializers/task.py,sha256=IGJGoSEC_wKS8t77JGnZWRqK-Mk5-4rXSj8j0Ha6nRA,10026
|
|
329
329
|
pulpcore/app/serializers/upload.py,sha256=4r6iBegbYHmgFYjBYPcqB8J7eSxXgY4ukayMxJZNh_M,2402
|
|
330
330
|
pulpcore/app/serializers/user.py,sha256=gw-Qju1akkDtjxiehNM10jnoeaoApY1MATNfpboAFoY,17122
|
|
331
|
-
pulpcore/app/tasks/__init__.py,sha256=
|
|
331
|
+
pulpcore/app/tasks/__init__.py,sha256=6fhLD0Z9LMluzqyBwQkatId71qI_2U7-o2-ZI1JH1Ls,576
|
|
332
332
|
pulpcore/app/tasks/analytics.py,sha256=eB3p-sdocH5yyNoe0OG5rUzwiVOfayOfHNzkohAfx-U,4722
|
|
333
|
-
pulpcore/app/tasks/base.py,sha256=
|
|
333
|
+
pulpcore/app/tasks/base.py,sha256=4I88Bn5SttqEvvVlNJmIwkPv2IWe7OhpM-kbQiQ9T_U,5929
|
|
334
334
|
pulpcore/app/tasks/export.py,sha256=dRg-KcnM7HumXUx8mjgJ-EVMcz2RbzSOPmMkzVtJEnI,19320
|
|
335
335
|
pulpcore/app/tasks/importer.py,sha256=tQXCQZslaMySeN6BS6hLZtiGvq-XE-bwjsEjF7fAJNc,23247
|
|
336
336
|
pulpcore/app/tasks/migrate.py,sha256=wCjGskoF-XWzbINEyC_crgcigFZlC8EHqZTbjkLQykg,2452
|
|
@@ -340,7 +340,7 @@ pulpcore/app/tasks/reclaim_space.py,sha256=FZ7KFasbScPAU7A6lzK98pdylmqgThssgnNMe
|
|
|
340
340
|
pulpcore/app/tasks/replica.py,sha256=x-Yjd8Z4EUhrhuF1DCX5jCa6F7FTAE3th-161lnLN2g,4509
|
|
341
341
|
pulpcore/app/tasks/repository.py,sha256=tPQ8KvsAUgX8Gd_hXsSc64uCmhVRQqHh36bykHlUPIw,9631
|
|
342
342
|
pulpcore/app/tasks/telemetry.py,sha256=QXOcYi7VIx_TBPCfs2BfcaiiVzRCiTFPZCN8MlC-hw8,1338
|
|
343
|
-
pulpcore/app/tasks/test.py,sha256=
|
|
343
|
+
pulpcore/app/tasks/test.py,sha256=_3BdJzdtEGdyL7qnzl0apwAoGeleYPeZTr7IJ5COFyo,912
|
|
344
344
|
pulpcore/app/tasks/upload.py,sha256=3YJa32XYUFgqkEEWoERRPB9Q6ph9a6ashMtMi24R15k,1413
|
|
345
345
|
pulpcore/app/templates/rest_framework/api.html,sha256=n2ymhyLN7tQ5dYc5uceRSqS5L8fsPnSHIfCBsFMshnM,246
|
|
346
346
|
pulpcore/app/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -353,7 +353,7 @@ pulpcore/app/views/status.py,sha256=snoAyU7KCfaxe04Tc9UF9Go8A8-zCxpKoZ6nxFfmaVU,
|
|
|
353
353
|
pulpcore/app/viewsets/__init__.py,sha256=iaDmZbjJalbU5BQ8q9sTKRX-64ToAnnyuHiLiFoyE-Y,2225
|
|
354
354
|
pulpcore/app/viewsets/access_policy.py,sha256=Tjo443gpPfR9gRAgfQfTuV15eMWylZa7lPLucTAIKhQ,2447
|
|
355
355
|
pulpcore/app/viewsets/acs.py,sha256=JabJntgGAMELbarKlTXDWrgMSYdMPgv6evJxoRdj66Y,2078
|
|
356
|
-
pulpcore/app/viewsets/base.py,sha256=
|
|
356
|
+
pulpcore/app/viewsets/base.py,sha256=7FgUMLl3ZOIflnzCEcrXr6spKRLNXyfffAHnuE3gQA8,27137
|
|
357
357
|
pulpcore/app/viewsets/content.py,sha256=PLKdY6l_D5_5i3aFOYdVLAz5zpjKEJmXKrEFJOrcOFg,7919
|
|
358
358
|
pulpcore/app/viewsets/custom_filters.py,sha256=_O3HPCbZ_we4ZO4gxCMQwWvDjk8JMisGIRwpkk2rkSs,14465
|
|
359
359
|
pulpcore/app/viewsets/domain.py,sha256=HLdd3AvAa4gp64JPGQa0iYveSqVjFdsEIVvBksl7LCk,6059
|
|
@@ -404,7 +404,7 @@ pulpcore/plugin/repo_version_utils.py,sha256=nuo55r5rQgDoFfdaobuyvqINW1B8k5xM618
|
|
|
404
404
|
pulpcore/plugin/responses.py,sha256=VcgJtVaTzCPjdIGz_AS4nQwO4ooh4O5T9KBEa1FGA1w,62
|
|
405
405
|
pulpcore/plugin/storage.py,sha256=CMoWFPfZG82-SOmuuaf8aPDYerK7mvxlER_cgWdJzQA,82
|
|
406
406
|
pulpcore/plugin/sync.py,sha256=IwAUZ_7vVYuba2Uhm0ndMyEnNZTkOhX0kOVWtb8SgxE,1002
|
|
407
|
-
pulpcore/plugin/tasking.py,sha256=
|
|
407
|
+
pulpcore/plugin/tasking.py,sha256=Ij9Zqamzn566Qf-8uvcm2q1AD4nZ6Mqi7FZnJow8Q2Y,677
|
|
408
408
|
pulpcore/plugin/util.py,sha256=Az0DDhdC6fEIPApC5ffdvM4oMwbqteISJ-b1yEcFRBE,1470
|
|
409
409
|
pulpcore/plugin/authentication/__init__.py,sha256=0qx9U7Poy96Ql3zu7DZwmzsA8Cx_yd1zHeeGKLeLXHg,69
|
|
410
410
|
pulpcore/plugin/cache/__init__.py,sha256=0P1OqLmYxJdAaxhND6flNZzYa-korgIrzS1eOiTT_kc,74
|
|
@@ -415,18 +415,18 @@ pulpcore/plugin/serializers/__init__.py,sha256=TSGHag4b_fUIlINCD9dq6pLToHiQz41ps
|
|
|
415
415
|
pulpcore/plugin/serializers/content.py,sha256=l2VKp5qLstI8InuisjxISTo_YimbxSorDfWncx5VY0U,9072
|
|
416
416
|
pulpcore/plugin/stages/__init__.py,sha256=ZSMmgOKoPjEfg1VhNpldJf2bUvqezCG4gj_FBkJ4CpU,466
|
|
417
417
|
pulpcore/plugin/stages/api.py,sha256=6iet7K6H5c9vk5lS9oE3gCyLlqdDKoqPMfF-lNIA-GQ,8435
|
|
418
|
-
pulpcore/plugin/stages/artifact_stages.py,sha256=
|
|
418
|
+
pulpcore/plugin/stages/artifact_stages.py,sha256=yKJQc06YevDiWGDsQDuWXzL0juj49UZ_wrE718Bd4CI,22870
|
|
419
419
|
pulpcore/plugin/stages/content_stages.py,sha256=kyoJfZY3K8QncmbuVMOCyG9PcLYp8athFvz6E7weL-Q,16082
|
|
420
420
|
pulpcore/plugin/stages/declarative_version.py,sha256=Ml0baZHY4om4Ai12azUIuIR6xdINuJSoxHqlGlKXh14,7503
|
|
421
421
|
pulpcore/plugin/stages/models.py,sha256=0b7xs9d64WTG2yHog1Zo_Z_-pomFAe-gC4u9wksY7H0,7490
|
|
422
422
|
pulpcore/plugin/viewsets/__init__.py,sha256=G2zE-NRWz6PFYp8OMZrv01RYBQELFWfW702bRvxXs3k,2281
|
|
423
423
|
pulpcore/plugin/viewsets/content.py,sha256=MHvmLOxsKSQfk6y5t1s9CVxkce9YNeU-dYb1Ldyf83I,6432
|
|
424
424
|
pulpcore/tasking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
425
|
-
pulpcore/tasking/_util.py,sha256=
|
|
425
|
+
pulpcore/tasking/_util.py,sha256=giR8f8fNvsjsTiuJOU9X21Dyb14fFntSYU7xXGwQZzo,9705
|
|
426
426
|
pulpcore/tasking/entrypoint.py,sha256=Npnn41e39soGvJ7CTaZXT5MjIhOO7UtQmpmNaZtfKYg,1120
|
|
427
427
|
pulpcore/tasking/kafka.py,sha256=76z4DzeXM1WL5uu1HlKnduWeLO3-b-czvGBXdWR6054,3845
|
|
428
428
|
pulpcore/tasking/storage.py,sha256=zQkwlpC_FDQtmZGZ8vKwHqxvD6CLO_gAS4Q7wijZE-k,3106
|
|
429
|
-
pulpcore/tasking/tasks.py,sha256=
|
|
429
|
+
pulpcore/tasking/tasks.py,sha256=b0YzBoxXiBXC8piZlzV63ehRHsw8V3uq6t4v8Ec8OIg,13935
|
|
430
430
|
pulpcore/tasking/worker.py,sha256=NpBACe6z_xFYOEeJYRne0hlwQDVrOAYGwpNCzSL-3C4,23819
|
|
431
431
|
pulpcore/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
432
432
|
pulpcore/tests/functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -453,7 +453,7 @@ pulpcore/tests/functional/api/test_scoping.py,sha256=uiLOsx5_7puRMcvrpPKEYQziqlu
|
|
|
453
453
|
pulpcore/tests/functional/api/test_signing_service.py,sha256=yr1HXBrNoliBHJNAGAN4PAN0eBKPIvAQP-uMoMSrO_I,222
|
|
454
454
|
pulpcore/tests/functional/api/test_status.py,sha256=NYOoYIiIifv0jO74EvPZlqws7Hob6bE8Pk2ro9tvlyU,5456
|
|
455
455
|
pulpcore/tests/functional/api/test_task_purge.py,sha256=Av4DrUdCqf-JegfoP1pkY4B-teoUzYd1LBZKAhDa-08,7273
|
|
456
|
-
pulpcore/tests/functional/api/test_tasking.py,sha256=
|
|
456
|
+
pulpcore/tests/functional/api/test_tasking.py,sha256=LPJtsRK9Ggh7CUsVuATcLYUnhdclbbS2zPUwAJGo2fg,21566
|
|
457
457
|
pulpcore/tests/functional/api/test_upload.py,sha256=oLP1ZmQgPzgK5jAQwGeXS8uLFHgAzVeLW0GfANMWexI,6794
|
|
458
458
|
pulpcore/tests/functional/api/test_users_groups.py,sha256=YFG0xtyJuIRraczR7ERl_UNS7dlJfKd2eUmXgD1lLBU,2926
|
|
459
459
|
pulpcore/tests/functional/api/test_workers.py,sha256=u3oQnErjf6qPCg08XMRZzecGetLLDWmvHvoZIk-AUAA,4659
|
|
@@ -526,9 +526,9 @@ pulpcore/tests/unit/stages/test_artifactdownloader.py,sha256=qB1ANdFmNtUnljg8fCd
|
|
|
526
526
|
pulpcore/tests/unit/stages/test_stages.py,sha256=H1a2BQLjdZlZvcb_qULp62huZ1xy6ItTcthktVyGU0w,4735
|
|
527
527
|
pulpcore/tests/unit/viewsets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
528
528
|
pulpcore/tests/unit/viewsets/test_viewset_base.py,sha256=W9o3V6758bZctR6krMPPQytb0xJuF-jb4uBWTNDoD_U,4837
|
|
529
|
-
pulpcore-3.
|
|
530
|
-
pulpcore-3.
|
|
531
|
-
pulpcore-3.
|
|
532
|
-
pulpcore-3.
|
|
533
|
-
pulpcore-3.
|
|
534
|
-
pulpcore-3.
|
|
529
|
+
pulpcore-3.77.0.dist-info/licenses/LICENSE,sha256=dhnHU8rJXUdAIgIjveSKAyYG_KzN5eVG-bxETIGrNW0,17988
|
|
530
|
+
pulpcore-3.77.0.dist-info/METADATA,sha256=KwDSPdPh-YRNIQvRh9sEpF7cyW7j3UiWEKTJaq5Fo_k,4260
|
|
531
|
+
pulpcore-3.77.0.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
|
|
532
|
+
pulpcore-3.77.0.dist-info/entry_points.txt,sha256=OZven4wzXzQA5b5q9MpP4HUpIPPQCSvIOvkKtNInrK0,452
|
|
533
|
+
pulpcore-3.77.0.dist-info/top_level.txt,sha256=6h-Lm3FKQSaT_nL1KSxu_hBnzKE15bcvf_BoU-ea4CI,34
|
|
534
|
+
pulpcore-3.77.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|