pulpcore 3.83.2__py3-none-any.whl → 3.85.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_certguard/app/models.py +7 -26
- pulp_certguard/app/serializers.py +0 -2
- pulp_certguard/rhsm/__init__.py +4 -0
- pulp_certguard/rhsm/rhsm_check_path.py +198 -0
- pulp_certguard/tests/unit/certdata.py +249 -0
- pulp_certguard/tests/unit/test_rhsm_check_path.py +213 -0
- pulp_file/app/__init__.py +1 -1
- pulp_file/app/migrations/0001_initial_squashed_0016_add_domain.py +0 -20
- pulp_file/app/migrations/0017_alter_filealternatecontentsource_alternatecontentsource_ptr_and_more.py +1 -1
- pulpcore/app/apps.py +2 -12
- pulpcore/app/entrypoint.py +22 -22
- pulpcore/app/migrations/0001_squashed_0090_char_to_text_field.py +0 -95
- pulpcore/app/migrations/0091_systemid.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
- pulp_file/app/migrations/0006_delete_filefilesystemexporter.py → pulpcore/app/migrations/0136_delete_basedistribution.py +3 -3
- pulpcore/app/migrations/0137_appstatus.py +33 -0
- pulpcore/app/migrations/0138_vulnerabilityreport.py +33 -0
- pulpcore/app/models/__init__.py +4 -1
- pulpcore/app/models/publication.py +0 -41
- pulpcore/app/models/status.py +145 -0
- pulpcore/app/models/task.py +8 -0
- pulpcore/app/models/vulnerability_report.py +34 -0
- pulpcore/app/serializers/__init__.py +1 -0
- pulpcore/app/serializers/content.py +13 -1
- pulpcore/app/serializers/repository.py +8 -1
- pulpcore/app/serializers/vulnerability_report.py +27 -0
- pulpcore/app/settings.py +13 -38
- pulpcore/app/tasks/__init__.py +2 -0
- pulpcore/app/tasks/purge.py +8 -5
- pulpcore/app/tasks/vulnerability_report.py +159 -0
- pulpcore/app/viewsets/__init__.py +1 -0
- pulpcore/app/viewsets/vulnerability_report.py +20 -0
- pulpcore/constants.py +8 -0
- pulpcore/content/__init__.py +23 -22
- pulpcore/content/handler.py +5 -2
- pulpcore/migrations.py +38 -11
- pulpcore/openapi/__init__.py +8 -0
- pulpcore/plugin/models/__init__.py +2 -0
- pulpcore/plugin/serializers/__init__.py +2 -0
- pulpcore/plugin/tasking.py +2 -0
- pulpcore/plugin/viewsets/__init__.py +2 -0
- pulpcore/pytest_plugin.py +21 -21
- pulpcore/tasking/entrypoint.py +12 -2
- pulpcore/tasking/tasks.py +5 -30
- pulpcore/tasking/worker.py +115 -74
- pulpcore/tests/functional/api/test_auth.py +18 -3
- pulpcore/tests/functional/api/test_login.py +62 -32
- pulpcore/tests/functional/api/test_openapi_schema.py +32 -15
- pulpcore/tests/functional/api/using_plugin/test_checkpoint.py +23 -1
- pulpcore/tests/functional/api/using_plugin/test_proxy.py +1 -1
- pulpcore/tests/unit/content/test_heartbeat.py +11 -8
- pulpcore/tests/unit/test_vulnerability_report.py +74 -0
- {pulpcore-3.83.2.dist-info → pulpcore-3.85.0.dist-info}/METADATA +13 -18
- {pulpcore-3.83.2.dist-info → pulpcore-3.85.0.dist-info}/RECORD +60 -156
- pulp_certguard/app/utils.py +0 -28
- pulp_certguard/tests/unit/test_models.py +0 -9
- pulp_file/app/migrations/0001_initial.py +0 -59
- pulp_file/app/migrations/0002_file_related_names.py +0 -55
- pulp_file/app/migrations/0003_auto_20191014_1721.py +0 -18
- pulp_file/app/migrations/0004_filefilesystemexporter.py +0 -21
- pulp_file/app/migrations/0005_filerepository.py +0 -24
- pulp_file/app/migrations/0007_filefilesystemexporter.py +0 -25
- pulp_file/app/migrations/0008_add_manifest_field.py +0 -19
- pulp_file/app/migrations/0009_move_data_to_new_master_distribution_model.py +0 -77
- pulp_file/app/migrations/0010_auto_publish.py +0 -23
- pulp_file/app/migrations/0011_fix_auto_publish.py +0 -36
- pulp_file/app/migrations/0012_delete_filefilesystemexporter.py +0 -28
- pulp_file/app/migrations/0013_file_acs.py +0 -24
- pulp_file/app/migrations/0014_new_rbac_permissions.py +0 -33
- pulp_file/app/migrations/0015_allow_null_manifest.py +0 -23
- pulp_file/app/migrations/0016_add_domain.py +0 -25
- pulpcore/app/migrations/0001_initial.py +0 -451
- pulpcore/app/migrations/0002_increase_artifact_size_field.py +0 -18
- pulpcore/app/migrations/0003_remove_upload_completed.py +0 -17
- pulpcore/app/migrations/0004_add_duplicated_reserved_resources.py +0 -45
- pulpcore/app/migrations/0005_progressreport_code.py +0 -19
- pulpcore/app/migrations/0006_repository_plugin_managed.py +0 -18
- pulpcore/app/migrations/0007_delete_progress_proxies.py +0 -19
- pulpcore/app/migrations/0008_published_metadata_as_content.py +0 -44
- pulpcore/app/migrations/0009_remove_task_non_fatal_errors.py +0 -17
- pulpcore/app/migrations/0010_pulp_fields.py +0 -570
- pulpcore/app/migrations/0011_relative_path.py +0 -28
- pulpcore/app/migrations/0012_auto_20191104_2000.py +0 -31
- pulpcore/app/migrations/0013_repository_pulp_type.py +0 -18
- pulpcore/app/migrations/0014_remove_repository_plugin_managed.py +0 -17
- pulpcore/app/migrations/0015_auto_20191112_1426.py +0 -33
- pulpcore/app/migrations/0016_charfield_to_textfield.py +0 -68
- pulpcore/app/migrations/0017_remove_task_parent.py +0 -17
- pulpcore/app/migrations/0018_auto_20191127_2350.py +0 -20
- pulpcore/app/migrations/0019_add_signing_service_model.py +0 -27
- pulpcore/app/migrations/0020_change_publishedartifact_constraints.py +0 -17
- pulpcore/app/migrations/0021_add_signing_service_foreign_key.py +0 -24
- pulpcore/app/migrations/0022_rename_last_version.py +0 -27
- pulpcore/app/migrations/0023_change_exporter_models.py +0 -82
- pulpcore/app/migrations/0024_use_local_storage_for_uploads.py +0 -19
- pulpcore/app/migrations/0025_task_parent_task.py +0 -19
- pulpcore/app/migrations/0026_task_group.py +0 -32
- pulpcore/app/migrations/0027_export_backend.py +0 -31
- pulpcore/app/migrations/0028_import_importer_pulpimporter_pulpimporterrepository.py +0 -85
- pulpcore/app/migrations/0029_export_delete.py +0 -19
- pulpcore/app/migrations/0030_taskgroup_all_tasks_dispatched.py +0 -24
- pulpcore/app/migrations/0031_import_export_validate_params.py +0 -19
- pulpcore/app/migrations/0032_export_to_chunks.py +0 -27
- pulpcore/app/migrations/0033_increase_remote_artifact_size_field.py +0 -18
- pulpcore/app/migrations/0034_groupprogressreport.py +0 -32
- pulpcore/app/migrations/0035_content_upstream_id.py +0 -18
- pulpcore/app/migrations/0036_unprotect_last_export.py +0 -19
- pulpcore/app/migrations/0037_pulptemporaryfile.py +0 -28
- pulpcore/app/migrations/0038_repository_remote.py +0 -19
- pulpcore/app/migrations/0039_change_download_concurrency.py +0 -25
- pulpcore/app/migrations/0040_set_admin_is_staff.py +0 -28
- pulpcore/app/migrations/0041_accesspolicy.py +0 -29
- pulpcore/app/migrations/0042_rbac_for_tasks.py +0 -56
- pulpcore/app/migrations/0043_toc_attribute.py +0 -19
- pulpcore/app/migrations/0044_temp_file_artifact_field.py +0 -20
- pulpcore/app/migrations/0045_accesspolicy_permissions_allow_null.py +0 -19
- pulpcore/app/migrations/0046_task__resource_job_id.py +0 -35
- pulpcore/app/migrations/0047_improve_orphan_cleanup.py +0 -59
- pulpcore/app/migrations/0048_fips_checksums.py +0 -38
- pulpcore/app/migrations/0049_add_file_field_to_uploadchunk.py +0 -24
- pulpcore/app/migrations/0050_namespace_access_policies.py +0 -28
- pulpcore/app/migrations/0051_timeoutfields.py +0 -34
- pulpcore/app/migrations/0052_tasking_logging_cid.py +0 -18
- pulpcore/app/migrations/0053_remote_headers.py +0 -19
- pulpcore/app/migrations/0054_add_public_key.py +0 -104
- pulpcore/app/migrations/0055_label.py +0 -31
- pulpcore/app/migrations/0056_remote_rate_limit.py +0 -18
- pulpcore/app/migrations/0057_add_label_indexes.py +0 -23
- pulpcore/app/migrations/0058_accesspolicy_customized.py +0 -18
- pulpcore/app/migrations/0059_proxy_creds.py +0 -23
- pulpcore/app/migrations/0060_data_migration_proxy_creds.py +0 -45
- pulpcore/app/migrations/0061_call_handle_artifact_checksums_command.py +0 -87
- pulpcore/app/migrations/0062_add_new_distribution_mastermodel.py +0 -36
- pulpcore/app/migrations/0063_repository_retained_versions.py +0 -18
- pulpcore/app/migrations/0064_add_new_style_task_columns.py +0 -109
- pulpcore/app/migrations/0064_repository_user_hidden.py +0 -18
- pulpcore/app/migrations/0065_merge_20210615_1211.py +0 -14
- pulpcore/app/migrations/0066_download_concurrency_and_retry_changes.py +0 -24
- pulpcore/app/migrations/0067_add_protect_to_task_reservation.py +0 -19
- pulpcore/app/migrations/0068_add_timestamp_of_interest.py +0 -23
- pulpcore/app/migrations/0069_update_json_fields.py +0 -63
- pulpcore/app/migrations/0070_rename_retained_versions.py +0 -18
- pulpcore/app/migrations/0071_filesystemexport_filesystemexporter.py +0 -35
- pulpcore/app/migrations/0072_add_method_to_filesystem_exporter.py +0 -18
- pulpcore/app/migrations/0073_encrypt_remote_fields.py +0 -139
- pulpcore/app/migrations/0074_acs.py +0 -47
- pulpcore/app/migrations/0075_rbaccontentguard.py +0 -25
- pulpcore/app/migrations/0076_remove_reserved_resource.py +0 -39
- pulpcore/app/migrations/0077_move_remote_url_credentials.py +0 -41
- pulpcore/app/migrations/0078_grouprole_role_userrole.py +0 -70
- pulpcore/app/migrations/0079_rename_permissions_assignment_accesspolicy_creation_hooks.py +0 -18
- pulpcore/app/migrations/0080_proxy_group_model.py +0 -37
- pulpcore/app/migrations/0081_reapplabel_group_permissions.py +0 -59
- pulpcore/app/migrations/0082_add_manage_roles_permissions.py +0 -17
- pulpcore/app/migrations/0083_alter_group_options.py +0 -17
- pulpcore/app/migrations/0084_alter_rbaccontentguard_options.py +0 -17
- pulpcore/app/migrations/0085_contentredirectcontentguard.py +0 -26
- pulpcore/app/migrations/0086_task_json_fields.py +0 -77
- pulpcore/app/migrations/0087_taskschedule.py +0 -34
- pulpcore/app/migrations/0088_accesspolicy_queryset_scoping.py +0 -18
- pulpcore/app/migrations/0089_alter_contentredirectcontentguard_options.py +0 -17
- pulpcore/app/migrations/0090_char_to_text_field.py +0 -79
- pulpcore/tests/unit/migration/test_0077_move_remote_url_credentials.py +0 -35
- {pulpcore-3.83.2.dist-info → pulpcore-3.85.0.dist-info}/WHEEL +0 -0
- {pulpcore-3.83.2.dist-info → pulpcore-3.85.0.dist-info}/entry_points.txt +0 -0
- {pulpcore-3.83.2.dist-info → pulpcore-3.85.0.dist-info}/licenses/LICENSE +0 -0
- {pulpcore-3.83.2.dist-info → pulpcore-3.85.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
from cryptography import x509
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from . import certdata
|
|
5
|
+
|
|
6
|
+
from pulp_certguard.rhsm import check_path
|
|
7
|
+
from pulp_certguard.rhsm.rhsm_check_path import (
|
|
8
|
+
bitstream,
|
|
9
|
+
Entitlement,
|
|
10
|
+
HuffmannNode,
|
|
11
|
+
cert_version,
|
|
12
|
+
split_count,
|
|
13
|
+
V1_PATH_OID_REGEX,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture(scope="session")
|
|
18
|
+
def ent_v1() -> x509.Certificate:
|
|
19
|
+
return x509.load_pem_x509_certificate(certdata.ENTITLEMENT_CERT_V1_0.encode())
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture(scope="session")
|
|
23
|
+
def ent_v3_0() -> x509.Certificate:
|
|
24
|
+
return x509.load_pem_x509_certificate(certdata.ENTITLEMENT_CERT_V3_0.encode())
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture(scope="session")
|
|
28
|
+
def ent_v3_2() -> x509.Certificate:
|
|
29
|
+
return x509.load_pem_x509_certificate(certdata.ENTITLEMENT_CERT_V3_2.encode())
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@pytest.fixture(scope="session", params=["3.0", "3.2"])
|
|
33
|
+
def ent_v3_version(request: pytest.FixtureRequest) -> str:
|
|
34
|
+
return request.param
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.fixture(scope="session")
|
|
38
|
+
def ent_v3(ent_v3_version: str) -> x509.Certificate:
|
|
39
|
+
ver = ent_v3_version.replace(".", "_")
|
|
40
|
+
attribute = f"ENTITLEMENT_CERT_V{ver}"
|
|
41
|
+
return x509.load_pem_x509_certificate(getattr(certdata, attribute).encode())
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TestSplitCount:
|
|
45
|
+
"""
|
|
46
|
+
If the first byte is < 128, that is the count itself.
|
|
47
|
+
Otherwise the 7 lsb describe the number of bytes to combine to the count.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
@pytest.mark.parametrize(
|
|
51
|
+
"header, count",
|
|
52
|
+
[
|
|
53
|
+
pytest.param(b"\x00", 0, id="short zero"),
|
|
54
|
+
pytest.param(b"\x0a", 10, id="short ten"),
|
|
55
|
+
pytest.param(b"\x7f", 127, id="short max"),
|
|
56
|
+
pytest.param(b"\x80", 0, id="zero bytes zero"),
|
|
57
|
+
pytest.param(b"\x81\x00", 0, id="one byte zero"),
|
|
58
|
+
pytest.param(b"\x81\x01", 1, id="one byte one"),
|
|
59
|
+
pytest.param(b"\x81\xff", 255, id="one byte max"),
|
|
60
|
+
pytest.param(b"\x84\x00\x00\x00\x00", 0, id="four bytes zero"),
|
|
61
|
+
pytest.param(b"\x84\x00\x00\x00\x01", 1, id="four bytes one"),
|
|
62
|
+
pytest.param(b"\x84\x00\x00\x01\x00", 256, id="four bytes 256"),
|
|
63
|
+
pytest.param(b"\x84\x00\x00\x01\x04", 260, id="four bytes 260"),
|
|
64
|
+
],
|
|
65
|
+
)
|
|
66
|
+
def test_returns_count_from(self, header: bytes, count: int) -> None:
|
|
67
|
+
assert split_count(header + b"\xde\xad\xbe\xaf") == (count, b"\xde\xad\xbe\xaf")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class TestBitstream:
|
|
71
|
+
def test_0000_produces_16_false(self) -> None:
|
|
72
|
+
assert list(bitstream(b"\x00\x00")) == [False] * 16
|
|
73
|
+
|
|
74
|
+
def test_0001_produces_15_false_true(self) -> None:
|
|
75
|
+
assert list(bitstream(b"\x00\x01")) == [False] * 15 + [True]
|
|
76
|
+
|
|
77
|
+
def test_fff0_produces_12_true_4_false(self) -> None:
|
|
78
|
+
assert list(bitstream(b"\xff\xf0")) == [True] * 12 + [False] * 4
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_product_certificate_has_subject() -> None:
|
|
82
|
+
cert = x509.load_pem_x509_certificate(certdata.PRODUCT_CERT_V1_0.encode())
|
|
83
|
+
assert cert.subject.rfc4514_string() == "CN=100000000000002"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class TestV1EntitlementCertificate:
|
|
87
|
+
def test_has_subject(self, ent_v1: x509.Certificate) -> None:
|
|
88
|
+
assert ent_v1.subject.rfc4514_string() == "CN=ff80808138574bd20138574d85a50b2f"
|
|
89
|
+
|
|
90
|
+
def test_has_4_paths(self, ent_v1: x509.Certificate) -> None:
|
|
91
|
+
assert (
|
|
92
|
+
len(
|
|
93
|
+
[ext for ext in ent_v1.extensions if V1_PATH_OID_REGEX.match(ext.oid.dotted_string)]
|
|
94
|
+
)
|
|
95
|
+
== 4
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def test_has_version_1_0(self, ent_v1: x509.Certificate) -> None:
|
|
99
|
+
assert cert_version(ent_v1) == "1.0"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class TestV3EntitlementCertificate:
|
|
103
|
+
def test_cert_version(self, ent_v3_version: str, ent_v3: x509.Certificate) -> None:
|
|
104
|
+
assert cert_version(ent_v3) == ent_v3_version
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class TestEntitlement:
|
|
108
|
+
@pytest.fixture(scope="class")
|
|
109
|
+
def entitlement(self, ent_v3: x509.Certificate) -> Entitlement:
|
|
110
|
+
return Entitlement(ent_v3)
|
|
111
|
+
|
|
112
|
+
@pytest.fixture(scope="class")
|
|
113
|
+
def word_tree(self, ent_v3: x509.Certificate) -> "HuffmannNode[str]":
|
|
114
|
+
lex_data, _, _ = Entitlement._split_payload(Entitlement._read_payload(ent_v3))
|
|
115
|
+
return Entitlement._build_word_tree(lex_data)
|
|
116
|
+
|
|
117
|
+
def test_has_node_count_10(self, ent_v3: x509.Certificate) -> None:
|
|
118
|
+
_, node_count, _ = Entitlement._split_payload(Entitlement._read_payload(ent_v3))
|
|
119
|
+
assert node_count == 10
|
|
120
|
+
|
|
121
|
+
def test_00_decodes_to_empty(self, word_tree: "HuffmannNode[str]") -> None:
|
|
122
|
+
assert word_tree.decode(iter([False, False])) == ""
|
|
123
|
+
|
|
124
|
+
def test_100_decodes_to_path(self, word_tree: "HuffmannNode[str]") -> None:
|
|
125
|
+
assert word_tree.decode(iter([True, False, False])) == "path"
|
|
126
|
+
|
|
127
|
+
def test_path_tree_root_contains_foo_and_path(self, entitlement: Entitlement) -> None:
|
|
128
|
+
assert {"foo", "path"} == entitlement._path_tree.keys()
|
|
129
|
+
|
|
130
|
+
def test_path_tree_contains_foo_path_never(self, entitlement: Entitlement) -> None:
|
|
131
|
+
assert entitlement._path_tree["foo"]["path"]["never"] == {}
|
|
132
|
+
|
|
133
|
+
def test_path_tree_contains_foo_path_var_always(self, entitlement: Entitlement) -> None:
|
|
134
|
+
assert entitlement._path_tree["foo"]["path"]["always"]["$releasever"] == {}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class TestCheckPathV1:
|
|
138
|
+
@pytest.mark.parametrize(
|
|
139
|
+
"path",
|
|
140
|
+
(
|
|
141
|
+
"/foo/path/never",
|
|
142
|
+
"/foo/path/never/",
|
|
143
|
+
"//foo/path/never/",
|
|
144
|
+
"/foo/path/never/bar/a/b/c",
|
|
145
|
+
"/foo/path/never/bar//a/b/c",
|
|
146
|
+
"/foo//path/never/bar//a/b/c",
|
|
147
|
+
),
|
|
148
|
+
)
|
|
149
|
+
def test_matches_foo_path_never(self, ent_v1: x509.Certificate, path: str) -> None:
|
|
150
|
+
assert check_path(ent_v1, path)
|
|
151
|
+
|
|
152
|
+
@pytest.mark.parametrize(
|
|
153
|
+
"path",
|
|
154
|
+
(
|
|
155
|
+
pytest.param("/path/never", id="misses the first part"),
|
|
156
|
+
pytest.param("foo", id="is only the middle part"),
|
|
157
|
+
"/foo",
|
|
158
|
+
"/foo/",
|
|
159
|
+
pytest.param("/foo/path/", id="misses the last part"),
|
|
160
|
+
pytest.param("baz/foo/path/never", id="prepended parts"),
|
|
161
|
+
pytest.param("/path/to//bar/awesomeos", id="substituted an empty string"),
|
|
162
|
+
pytest.param("/path/to/foo/bar/awesomeo", id="misses the last character"),
|
|
163
|
+
pytest.param("/path/to/foo/bar/awesomeos1", id="adds characters at the end"),
|
|
164
|
+
),
|
|
165
|
+
)
|
|
166
|
+
def test_rejects_a_path_that(self, ent_v1: x509.Certificate, path: str) -> None:
|
|
167
|
+
assert not check_path(ent_v1, path)
|
|
168
|
+
|
|
169
|
+
@pytest.mark.parametrize(
|
|
170
|
+
"path",
|
|
171
|
+
(
|
|
172
|
+
"/path/to/foo/bar/awesomeos",
|
|
173
|
+
"/path/to/foo/bar/awesomeos/",
|
|
174
|
+
"/path/to/foo/bar/awesomeos/a/b/c",
|
|
175
|
+
"/path/to//bar/foo/awesomeos",
|
|
176
|
+
),
|
|
177
|
+
)
|
|
178
|
+
def test_matches_path_with_substituted_variables(
|
|
179
|
+
self, ent_v1: x509.Certificate, path: str
|
|
180
|
+
) -> None:
|
|
181
|
+
assert check_path(ent_v1, path)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class TestCheckPathV3:
|
|
185
|
+
@pytest.mark.parametrize(
|
|
186
|
+
"path",
|
|
187
|
+
(
|
|
188
|
+
pytest.param("/foo/path/never", id="exact path without vars"),
|
|
189
|
+
pytest.param("/foo/path/never/a/b/c", id="exact path with extra segments"),
|
|
190
|
+
pytest.param(
|
|
191
|
+
"////foo///path//never///", id="exact path without vars and extra slashes"
|
|
192
|
+
),
|
|
193
|
+
pytest.param("foo/path/always/c-3po", id="exact path with variable"),
|
|
194
|
+
pytest.param("/path/to/awesomeos/x86_64", id="another exact path without vars"),
|
|
195
|
+
pytest.param("/path/to/c-3po/r2-d2/awesomeos", id="another exact path with vars"),
|
|
196
|
+
),
|
|
197
|
+
)
|
|
198
|
+
def test_matches(self, ent_v3: x509.Certificate, path: str) -> None:
|
|
199
|
+
assert check_path(ent_v3, path)
|
|
200
|
+
|
|
201
|
+
@pytest.mark.parametrize(
|
|
202
|
+
"path",
|
|
203
|
+
(
|
|
204
|
+
pytest.param("/a/path/to/wherever", id="lunatic path"),
|
|
205
|
+
pytest.param("", id="empty path"),
|
|
206
|
+
pytest.param("////", id="just slashes"),
|
|
207
|
+
pytest.param("foo", id="to short path"),
|
|
208
|
+
pytest.param("path/never", id="path with front segment missing"),
|
|
209
|
+
pytest.param("content/foo/path/never", id="path with extra front segment"),
|
|
210
|
+
),
|
|
211
|
+
)
|
|
212
|
+
def test_rejects(self, ent_v3: x509.Certificate, path: str) -> None:
|
|
213
|
+
assert not check_path(ent_v3, path)
|
pulp_file/app/__init__.py
CHANGED
|
@@ -7,28 +7,8 @@ import pulpcore.app.util
|
|
|
7
7
|
|
|
8
8
|
class Migration(migrations.Migration):
|
|
9
9
|
|
|
10
|
-
replaces = [
|
|
11
|
-
("file", "0001_initial"),
|
|
12
|
-
("file", "0002_file_related_names"),
|
|
13
|
-
("file", "0003_auto_20191014_1721"),
|
|
14
|
-
("file", "0004_filefilesystemexporter"),
|
|
15
|
-
("file", "0005_filerepository"),
|
|
16
|
-
("file", "0006_delete_filefilesystemexporter"),
|
|
17
|
-
("file", "0007_filefilesystemexporter"),
|
|
18
|
-
("file", "0008_add_manifest_field"),
|
|
19
|
-
("file", "0009_move_data_to_new_master_distribution_model"),
|
|
20
|
-
("file", "0010_auto_publish"),
|
|
21
|
-
("file", "0011_fix_auto_publish"),
|
|
22
|
-
("file", "0012_delete_filefilesystemexporter"),
|
|
23
|
-
("file", "0013_file_acs"),
|
|
24
|
-
("file", "0014_new_rbac_permissions"),
|
|
25
|
-
("file", "0015_allow_null_manifest"),
|
|
26
|
-
("file", "0016_add_domain"),
|
|
27
|
-
]
|
|
28
|
-
|
|
29
10
|
dependencies = [
|
|
30
11
|
("core", "0102_add_domain_relations"),
|
|
31
|
-
("core", "0091_systemid"),
|
|
32
12
|
]
|
|
33
13
|
|
|
34
14
|
operations = [
|
pulpcore/app/apps.py
CHANGED
|
@@ -5,6 +5,7 @@ from gettext import gettext as _
|
|
|
5
5
|
from importlib import import_module
|
|
6
6
|
|
|
7
7
|
from django import apps
|
|
8
|
+
from django.conf import settings
|
|
8
9
|
from django.core.exceptions import ImproperlyConfigured
|
|
9
10
|
from django.db import connection, transaction
|
|
10
11
|
from django.db.models.signals import post_migrate
|
|
@@ -67,15 +68,6 @@ class PulpPluginAppConfig(apps.AppConfig):
|
|
|
67
68
|
|
|
68
69
|
def __init__(self, app_name, app_module):
|
|
69
70
|
super().__init__(app_name, app_module)
|
|
70
|
-
# begin Compatilibity layer for DEFAULT_FILE_STORAGE deprecation
|
|
71
|
-
# Remove on pulpcore=3.85 or pulpcore=4.0
|
|
72
|
-
# * Workaround for getting the up-to-date settings instance, otherwise is doesnt
|
|
73
|
-
# get the patch in settings.py
|
|
74
|
-
# * Update code in signal handlers to use module-level imports again
|
|
75
|
-
from django.conf import settings
|
|
76
|
-
|
|
77
|
-
self.settings = settings
|
|
78
|
-
# end
|
|
79
71
|
|
|
80
72
|
try:
|
|
81
73
|
self.version
|
|
@@ -247,7 +239,7 @@ class PulpAppConfig(PulpPluginAppConfig):
|
|
|
247
239
|
label = "core"
|
|
248
240
|
|
|
249
241
|
# The version of this app
|
|
250
|
-
version = "3.
|
|
242
|
+
version = "3.85.0"
|
|
251
243
|
|
|
252
244
|
# The python package name providing this app
|
|
253
245
|
python_package_name = "pulpcore"
|
|
@@ -322,7 +314,6 @@ def _populate_system_id(sender, apps, verbosity, **kwargs):
|
|
|
322
314
|
|
|
323
315
|
|
|
324
316
|
def _ensure_default_domain(sender, **kwargs):
|
|
325
|
-
settings = sender.settings
|
|
326
317
|
table_names = connection.introspection.table_names()
|
|
327
318
|
if "core_domain" in table_names:
|
|
328
319
|
from pulpcore.app.util import get_default_domain
|
|
@@ -402,7 +393,6 @@ def adjust_roles(apps, role_prefix, desired_roles, verbosity=1):
|
|
|
402
393
|
|
|
403
394
|
|
|
404
395
|
def _populate_artifact_serving_distribution(sender, apps, verbosity, **kwargs):
|
|
405
|
-
settings = sender.settings
|
|
406
396
|
if (
|
|
407
397
|
settings.STORAGES["default"]["BACKEND"] == "pulpcore.app.models.storage.FileSystem"
|
|
408
398
|
or not settings.REDIRECT_TO_OBJECT_STORAGE
|
pulpcore/app/entrypoint.py
CHANGED
|
@@ -7,7 +7,8 @@ import click
|
|
|
7
7
|
import django
|
|
8
8
|
from django.conf import settings
|
|
9
9
|
from django.db import connection
|
|
10
|
-
from django.db.utils import InterfaceError, DatabaseError
|
|
10
|
+
from django.db.utils import IntegrityError, InterfaceError, DatabaseError
|
|
11
|
+
from gunicorn.arbiter import Arbiter
|
|
11
12
|
from gunicorn.workers.sync import SyncWorker
|
|
12
13
|
|
|
13
14
|
from pulpcore.app.apps import pulp_plugin_configs
|
|
@@ -27,26 +28,21 @@ class PulpApiWorker(SyncWorker):
|
|
|
27
28
|
|
|
28
29
|
def heartbeat(self):
|
|
29
30
|
try:
|
|
30
|
-
self.
|
|
31
|
-
name=self.name, defaults={"versions": self.versions}
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
if not created:
|
|
35
|
-
self.api_app_status.save_heartbeat()
|
|
36
|
-
|
|
37
|
-
if self.api_app_status.versions != self.versions:
|
|
38
|
-
self.api_app_status.versions = self.versions
|
|
39
|
-
self.api_app_status.save(update_fields=["versions"])
|
|
40
|
-
|
|
31
|
+
self.app_status.save_heartbeat()
|
|
41
32
|
logger.debug(self.beat_msg)
|
|
42
33
|
except (InterfaceError, DatabaseError):
|
|
43
34
|
connection.close_if_unusable_or_obsolete()
|
|
44
|
-
|
|
35
|
+
try:
|
|
36
|
+
self.app_status.save_heartbeat()
|
|
37
|
+
logger.debug(self.beat_msg)
|
|
38
|
+
except (InterfaceError, DatabaseError):
|
|
39
|
+
logger.error(self.fail_beat_msg)
|
|
40
|
+
exit(Arbiter.WORKER_BOOT_ERROR)
|
|
45
41
|
|
|
46
42
|
def init_process(self):
|
|
47
43
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pulpcore.app.settings")
|
|
48
44
|
django.setup()
|
|
49
|
-
from pulpcore.app.models import
|
|
45
|
+
from pulpcore.app.models import AppStatus
|
|
50
46
|
|
|
51
47
|
if settings.API_APP_TTL < 2 * self.timeout:
|
|
52
48
|
logger.warning(
|
|
@@ -56,9 +52,6 @@ class PulpApiWorker(SyncWorker):
|
|
|
56
52
|
self.timeout,
|
|
57
53
|
)
|
|
58
54
|
|
|
59
|
-
self.ApiAppStatus = ApiAppStatus
|
|
60
|
-
self.api_app_status = None
|
|
61
|
-
|
|
62
55
|
self.name = "{pid}@{hostname}".format(pid=self.pid, hostname=socket.gethostname())
|
|
63
56
|
self.versions = {app.label: app.version for app in pulp_plugin_configs()}
|
|
64
57
|
self.beat_msg = (
|
|
@@ -67,9 +60,16 @@ class PulpApiWorker(SyncWorker):
|
|
|
67
60
|
)
|
|
68
61
|
)
|
|
69
62
|
self.fail_beat_msg = (
|
|
70
|
-
"Api App '{name}' failed to write a heartbeat to the database
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
"Api App '{name}' failed to write a heartbeat to the database."
|
|
64
|
+
).format(name=self.name)
|
|
65
|
+
try:
|
|
66
|
+
self.app_status = AppStatus.objects.create(
|
|
67
|
+
name=self.name, app_type="api", versions=self.versions
|
|
68
|
+
)
|
|
69
|
+
except IntegrityError:
|
|
70
|
+
logger.error(f"An API app with name {self.name} already exists in the database.")
|
|
71
|
+
exit(Arbiter.WORKER_BOOT_ERROR)
|
|
72
|
+
|
|
73
73
|
super().init_process()
|
|
74
74
|
|
|
75
75
|
def run(self):
|
|
@@ -77,8 +77,8 @@ class PulpApiWorker(SyncWorker):
|
|
|
77
77
|
super().run()
|
|
78
78
|
finally:
|
|
79
79
|
# cleanup
|
|
80
|
-
if self.
|
|
81
|
-
self.
|
|
80
|
+
if self.app_status:
|
|
81
|
+
self.app_status.delete()
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
class PulpcoreApiApplication(PulpcoreGunicornApplication):
|
|
@@ -20,105 +20,10 @@ import uuid
|
|
|
20
20
|
|
|
21
21
|
class Migration(migrations.Migration):
|
|
22
22
|
|
|
23
|
-
replaces = [
|
|
24
|
-
("core", "0001_initial"),
|
|
25
|
-
("core", "0002_increase_artifact_size_field"),
|
|
26
|
-
("core", "0003_remove_upload_completed"),
|
|
27
|
-
("core", "0004_add_duplicated_reserved_resources"),
|
|
28
|
-
("core", "0005_progressreport_code"),
|
|
29
|
-
("core", "0006_repository_plugin_managed"),
|
|
30
|
-
("core", "0007_delete_progress_proxies"),
|
|
31
|
-
("core", "0008_published_metadata_as_content"),
|
|
32
|
-
("core", "0009_remove_task_non_fatal_errors"),
|
|
33
|
-
("core", "0010_pulp_fields"),
|
|
34
|
-
("core", "0011_relative_path"),
|
|
35
|
-
("core", "0012_auto_20191104_2000"),
|
|
36
|
-
("core", "0013_repository_pulp_type"),
|
|
37
|
-
("core", "0014_remove_repository_plugin_managed"),
|
|
38
|
-
("core", "0015_auto_20191112_1426"),
|
|
39
|
-
("core", "0016_charfield_to_textfield"),
|
|
40
|
-
("core", "0017_remove_task_parent"),
|
|
41
|
-
("core", "0018_auto_20191127_2350"),
|
|
42
|
-
("core", "0019_add_signing_service_model"),
|
|
43
|
-
("core", "0020_change_publishedartifact_constraints"),
|
|
44
|
-
("core", "0021_add_signing_service_foreign_key"),
|
|
45
|
-
("core", "0022_rename_last_version"),
|
|
46
|
-
("core", "0023_change_exporter_models"),
|
|
47
|
-
("core", "0024_use_local_storage_for_uploads"),
|
|
48
|
-
("core", "0025_task_parent_task"),
|
|
49
|
-
("core", "0026_task_group"),
|
|
50
|
-
("core", "0027_export_backend"),
|
|
51
|
-
("core", "0028_import_importer_pulpimporter_pulpimporterrepository"),
|
|
52
|
-
("core", "0029_export_delete"),
|
|
53
|
-
("core", "0030_taskgroup_all_tasks_dispatched"),
|
|
54
|
-
("core", "0031_import_export_validate_params"),
|
|
55
|
-
("core", "0032_export_to_chunks"),
|
|
56
|
-
("core", "0033_increase_remote_artifact_size_field"),
|
|
57
|
-
("core", "0034_groupprogressreport"),
|
|
58
|
-
("core", "0035_content_upstream_id"),
|
|
59
|
-
("core", "0036_unprotect_last_export"),
|
|
60
|
-
("core", "0037_pulptemporaryfile"),
|
|
61
|
-
("core", "0038_repository_remote"),
|
|
62
|
-
("core", "0039_change_download_concurrency"),
|
|
63
|
-
("core", "0040_set_admin_is_staff"),
|
|
64
|
-
("core", "0041_accesspolicy"),
|
|
65
|
-
("core", "0042_rbac_for_tasks"),
|
|
66
|
-
("core", "0043_toc_attribute"),
|
|
67
|
-
("core", "0044_temp_file_artifact_field"),
|
|
68
|
-
("core", "0045_accesspolicy_permissions_allow_null"),
|
|
69
|
-
("core", "0046_task__resource_job_id"),
|
|
70
|
-
("core", "0047_improve_orphan_cleanup"),
|
|
71
|
-
("core", "0048_fips_checksums"),
|
|
72
|
-
("core", "0049_add_file_field_to_uploadchunk"),
|
|
73
|
-
("core", "0050_namespace_access_policies"),
|
|
74
|
-
("core", "0051_timeoutfields"),
|
|
75
|
-
("core", "0052_tasking_logging_cid"),
|
|
76
|
-
("core", "0053_remote_headers"),
|
|
77
|
-
("core", "0054_add_public_key"),
|
|
78
|
-
("core", "0055_label"),
|
|
79
|
-
("core", "0056_remote_rate_limit"),
|
|
80
|
-
("core", "0057_add_label_indexes"),
|
|
81
|
-
("core", "0058_accesspolicy_customized"),
|
|
82
|
-
("core", "0059_proxy_creds"),
|
|
83
|
-
("core", "0060_data_migration_proxy_creds"),
|
|
84
|
-
("core", "0061_call_handle_artifact_checksums_command"),
|
|
85
|
-
("core", "0062_add_new_distribution_mastermodel"),
|
|
86
|
-
("core", "0063_repository_retained_versions"),
|
|
87
|
-
("core", "0064_repository_user_hidden"),
|
|
88
|
-
("core", "0064_add_new_style_task_columns"),
|
|
89
|
-
("core", "0065_merge_20210615_1211"),
|
|
90
|
-
("core", "0066_download_concurrency_and_retry_changes"),
|
|
91
|
-
("core", "0067_add_protect_to_task_reservation"),
|
|
92
|
-
("core", "0068_add_timestamp_of_interest"),
|
|
93
|
-
("core", "0069_update_json_fields"),
|
|
94
|
-
("core", "0070_rename_retained_versions"),
|
|
95
|
-
("core", "0071_filesystemexport_filesystemexporter"),
|
|
96
|
-
("core", "0072_add_method_to_filesystem_exporter"),
|
|
97
|
-
("core", "0073_encrypt_remote_fields"),
|
|
98
|
-
("core", "0074_acs"),
|
|
99
|
-
("core", "0075_rbaccontentguard"),
|
|
100
|
-
("core", "0076_remove_reserved_resource"),
|
|
101
|
-
("core", "0077_move_remote_url_credentials"),
|
|
102
|
-
("core", "0078_grouprole_role_userrole"),
|
|
103
|
-
("core", "0079_rename_permissions_assignment_accesspolicy_creation_hooks"),
|
|
104
|
-
("core", "0080_proxy_group_model"),
|
|
105
|
-
("core", "0081_reapplabel_group_permissions"),
|
|
106
|
-
("core", "0082_add_manage_roles_permissions"),
|
|
107
|
-
("core", "0083_alter_group_options"),
|
|
108
|
-
("core", "0084_alter_rbaccontentguard_options"),
|
|
109
|
-
("core", "0085_contentredirectcontentguard"),
|
|
110
|
-
("core", "0086_task_json_fields"),
|
|
111
|
-
("core", "0087_taskschedule"),
|
|
112
|
-
("core", "0088_accesspolicy_queryset_scoping"),
|
|
113
|
-
("core", "0089_alter_contentredirectcontentguard_options"),
|
|
114
|
-
("core", "0090_char_to_text_field"),
|
|
115
|
-
]
|
|
116
|
-
|
|
117
23
|
initial = True
|
|
118
24
|
|
|
119
25
|
dependencies = [
|
|
120
26
|
("auth", "0012_alter_user_first_name_max_length"),
|
|
121
|
-
("auth", "__first__"),
|
|
122
27
|
("contenttypes", "0002_remove_content_type_name"),
|
|
123
28
|
]
|
|
124
29
|
|
|
@@ -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
|
+
]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Generated by Django
|
|
1
|
+
# Generated by Django 4.2.16 on 2024-12-05 12:37
|
|
2
2
|
|
|
3
3
|
from django.db import migrations
|
|
4
4
|
|
|
@@ -6,11 +6,11 @@ from django.db import migrations
|
|
|
6
6
|
class Migration(migrations.Migration):
|
|
7
7
|
|
|
8
8
|
dependencies = [
|
|
9
|
-
(
|
|
9
|
+
("core", "0135_task_pulp_task_resources_index"),
|
|
10
10
|
]
|
|
11
11
|
|
|
12
12
|
operations = [
|
|
13
13
|
migrations.DeleteModel(
|
|
14
|
-
name=
|
|
14
|
+
name="BaseDistribution",
|
|
15
15
|
),
|
|
16
16
|
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Generated by Django 4.2.23 on 2025-08-07 08:46
|
|
2
|
+
|
|
3
|
+
import django.contrib.postgres.fields.hstore
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
import django_lifecycle.mixins
|
|
6
|
+
import pulpcore.app.models.base
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Migration(migrations.Migration):
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
('core', '0136_delete_basedistribution'),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.CreateModel(
|
|
17
|
+
name='AppStatus',
|
|
18
|
+
fields=[
|
|
19
|
+
('pulp_id', models.UUIDField(default=pulpcore.app.models.base.pulp_uuid, editable=False, primary_key=True, serialize=False)),
|
|
20
|
+
('pulp_created', models.DateTimeField(auto_now_add=True)),
|
|
21
|
+
('pulp_last_updated', models.DateTimeField(auto_now=True, null=True)),
|
|
22
|
+
('app_type', models.CharField(choices=[('api', 'api'), ('content', 'content'), ('worker', 'worker')], max_length=10)),
|
|
23
|
+
('name', models.TextField(db_index=True, unique=True)),
|
|
24
|
+
('versions', django.contrib.postgres.fields.hstore.HStoreField(default=dict)),
|
|
25
|
+
('ttl', models.DurationField()),
|
|
26
|
+
('last_heartbeat', models.DateTimeField(auto_now=True)),
|
|
27
|
+
],
|
|
28
|
+
options={
|
|
29
|
+
'abstract': False,
|
|
30
|
+
},
|
|
31
|
+
bases=(django_lifecycle.mixins.LifecycleModelMixin, models.Model),
|
|
32
|
+
),
|
|
33
|
+
]
|