pulp-container 2.26.16__tar.gz → 2.26.18__tar.gz
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.
- {pulp_container-2.26.16 → pulp_container-2.26.18}/CHANGES.md +15 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/PKG-INFO +2 -2
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/__init__.py +1 -1
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/authorization.py +2 -12
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/cache.py +8 -8
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/checks.py +30 -0
- pulp_container-2.26.18/pulp_container/app/management/commands/container-repair-pull-through-distributions.py +73 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/models.py +1 -3
- pulp_container-2.26.18/pulp_container/app/pull_through.py +69 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/registry_api.py +11 -13
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/serializers.py +57 -15
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/viewsets.py +24 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/constants.py +2 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_content_cache.py +1 -1
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_domains.py +3 -2
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_pull_through_cache.py +28 -10
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_remote_filter_pull_through.py +3 -1
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_tagging_images.py +3 -4
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/conftest.py +60 -54
- pulp_container-2.26.18/pulp_container/tests/unit/test_pull_through_repair.py +142 -0
- pulp_container-2.26.18/pulp_container/tests/unit/test_serializers.py +280 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container.egg-info/PKG-INFO +2 -2
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container.egg-info/SOURCES.txt +3 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container.egg-info/requires.txt +1 -1
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pyproject.toml +5 -4
- pulp_container-2.26.16/pulp_container/tests/unit/test_serializers.py +0 -105
- {pulp_container-2.26.16 → pulp_container-2.26.18}/COMMITMENT +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/COPYRIGHT +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/LICENSE +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/MANIFEST.in +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/README.rst +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/functest_requirements.txt +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/__init__.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/access_policy.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/content.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/downloaders.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/exceptions.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/fields.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/global_access_conditions.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/json_schemas.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/management/__init__.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/management/commands/__init__.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/management/commands/container-handle-image-data.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/management/commands/container-repair-media-type.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0001_initial.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0001_squashed_0032_upload_artifact.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0002_containerrepository.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0003_oci_mediatype.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0004_upload.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0005_contentredirectcontentguard.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0006_containerpushrepository.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0007_clear_tags_artifacts_refs.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0008_include_exclude_tags.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0009_container_namespace.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0010_remove_uploadchunk.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0011_add_container_repository_permissions.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0012_add_container_namespace_permissions.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0013_add_pull_push_permissions.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0014_containerdistribution_private.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0015_manage_tags_push_repo.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0016_add_delete_versions_permission.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0017_add_granular_perms.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0018_containerdistribution_description.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0019_DATA_distribution_model_swap.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0020_update_push_repo_perms.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0021_data_move_redirect_content_guard_to_core.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0022_delete_contentredirectcontentguard.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0023_manifestsignature.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0024_containerremote_sigstore.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0025_signature_stored_in_textfield.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0026_manifest_signing_service.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0027_data_translate_perms_to_roles.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0028_add_role_manage_permissions.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0029_remove_blob_media_type.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0030_enforce_tagged_manifest_reference.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0031_replace_charf_with_textf.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0032_upload_artifact.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0033_raise_warning_for_repair.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0034_translate_signed_schema.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0035_alter_blob_content_ptr_and_more.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0036_containerpushrepository_pending_blobs_manifests.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0037_create_pull_through_cache_models.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0038_add_manifest_metadata_fields.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0039_manifest_data.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0040_add_remote_repo_filter.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0041_add_pull_through_pull_permissions.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0042_add_manifest_nature_field.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0043_add_os_arch_image_size_manifest_fields.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0044_add_domain.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/0045_alter_manifest_compressed_image_size.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/migrations/__init__.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/modelresource.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/redirects.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/registry.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/replica.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/settings.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/tasks/__init__.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/tasks/builder.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/tasks/download_image_data.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/tasks/recursive_add.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/tasks/recursive_remove.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/tasks/sign.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/tasks/sync_stages.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/tasks/synchronize.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/tasks/tag.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/tasks/untag.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/token_verification.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/urls.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/utils.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/webserver_snippets/__init__.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/webserver_snippets/apache.conf +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/app/webserver_snippets/nginx.conf +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/__init__.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/__init__.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/__init__.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_build_images.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_crud_distributions.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_crud_remotes.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_flatpak.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_pull_content.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_pulpimportexport.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_push_content.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_push_signatures.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_rbac_push_repositories.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_rbac_remotes.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_rbac_repo_content.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_rbac_repo_versions.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_rbac_sync_repositories.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_recursive_add.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_recursive_remove.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_repositories_list.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_sign_manifests.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_sync.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_sync_signatures.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/api/test_token_authentication.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/constants.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/functional/utils.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/unit/__init__.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/unit/fixtures/ryuk_0.13.0_manifest_list.json +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/unit/test_json_schemas.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/unit/test_models.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container/tests/unit/test_sync_stages.py +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container.egg-info/dependency_links.txt +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container.egg-info/entry_points.txt +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/pulp_container.egg-info/top_level.txt +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/setup.cfg +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/test_requirements.txt +0 -0
- {pulp_container-2.26.16 → pulp_container-2.26.18}/unittest_requirements.txt +0 -0
|
@@ -8,6 +8,21 @@
|
|
|
8
8
|
|
|
9
9
|
[//]: # (towncrier release notes start)
|
|
10
10
|
|
|
11
|
+
## 2.26.18 (2026-10-07) {: #2.26.18 }
|
|
12
|
+
|
|
13
|
+
No significant changes.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2.26.17 (2026-09-23) {: #2.26.17 }
|
|
18
|
+
|
|
19
|
+
#### Bugfixes {: #2.26.17-bugfix }
|
|
20
|
+
|
|
21
|
+
- Prevent container distributions from overlapping other distribution base paths. Pull-through distributions **NEED** to be fixed before upgrading pulpcore; run `pulpcore-manager container-repair-pull-through-distributions` to repair existing distributions.
|
|
22
|
+
[#2494](https://github.com/pulp/pulp_container/issues/2494)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
11
26
|
## 2.26.16 (2026-06-08) {: #2.26.16 }
|
|
12
27
|
|
|
13
28
|
#### Bugfixes {: #2.26.16-bugfix }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pulp-container
|
|
3
|
-
Version: 2.26.
|
|
3
|
+
Version: 2.26.18
|
|
4
4
|
Summary: Container plugin for the Pulp Project
|
|
5
5
|
Author-email: Pulp Team <pulp-list@redhat.com>
|
|
6
6
|
Project-URL: Homepage, https://pulpproject.org
|
|
@@ -19,6 +19,6 @@ Description-Content-Type: text/markdown
|
|
|
19
19
|
License-File: LICENSE
|
|
20
20
|
Requires-Dist: jsonschema<4.25,>=4.4
|
|
21
21
|
Requires-Dist: pulpcore<3.100,>=3.73.2
|
|
22
|
-
Requires-Dist: pyjwt[crypto]<2.
|
|
22
|
+
Requires-Dist: pyjwt[crypto]<2.16,>=2.4
|
|
23
23
|
Requires-Dist: pysequoia<0.2.0,>=0.1.33
|
|
24
24
|
Dynamic: license-file
|
|
@@ -10,7 +10,6 @@ import jwt
|
|
|
10
10
|
from cryptography.hazmat.backends import default_backend
|
|
11
11
|
from cryptography.hazmat.primitives import serialization
|
|
12
12
|
from django.conf import settings
|
|
13
|
-
from django.db.models import F, Value
|
|
14
13
|
from django.http import HttpRequest
|
|
15
14
|
from rest_framework.request import Request
|
|
16
15
|
|
|
@@ -21,10 +20,10 @@ from pulp_container.app.access_policy import RegistryAccessPolicy
|
|
|
21
20
|
from pulp_container.app.models import (
|
|
22
21
|
ContainerDistribution,
|
|
23
22
|
ContainerNamespace,
|
|
24
|
-
ContainerPullThroughDistribution,
|
|
25
23
|
)
|
|
24
|
+
from pulp_container.app.pull_through import get_pull_through_distribution
|
|
26
25
|
|
|
27
|
-
TOKEN_EXPIRATION_TIME = settings
|
|
26
|
+
TOKEN_EXPIRATION_TIME = getattr(settings, "TOKEN_EXPIRATION_TIME", 300)
|
|
28
27
|
|
|
29
28
|
FakeView = namedtuple("FakeView", "action, get_object, get_serializer")
|
|
30
29
|
|
|
@@ -209,15 +208,6 @@ class AuthorizationService:
|
|
|
209
208
|
}
|
|
210
209
|
|
|
211
210
|
|
|
212
|
-
def get_pull_through_distribution(path, domain):
|
|
213
|
-
return (
|
|
214
|
-
ContainerPullThroughDistribution.objects.annotate(path=Value(path))
|
|
215
|
-
.filter(pulp_domain=domain, path__startswith=F("base_path"))
|
|
216
|
-
.order_by("-base_path")
|
|
217
|
-
.first()
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
|
|
221
211
|
class PermissionChecker:
|
|
222
212
|
def __init__(self, user):
|
|
223
213
|
self.user = user
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
from django.core.exceptions import ObjectDoesNotExist
|
|
2
|
-
from django.db.models import F, Value
|
|
3
2
|
|
|
4
3
|
from pulpcore.plugin.cache import AsyncContentCache, CacheKeys, SyncContentCache
|
|
5
4
|
from pulpcore.plugin.util import cache_key, get_domain
|
|
6
5
|
|
|
7
6
|
from pulp_container.app.exceptions import RepositoryNotFound
|
|
8
|
-
from pulp_container.app.models import ContainerDistribution
|
|
7
|
+
from pulp_container.app.models import ContainerDistribution
|
|
8
|
+
from pulp_container.app.pull_through import (
|
|
9
|
+
get_pull_through_distribution,
|
|
10
|
+
get_pull_through_distribution_path,
|
|
11
|
+
)
|
|
9
12
|
|
|
10
13
|
ACCEPT_HEADER_KEY = "accept_header"
|
|
11
14
|
QUERY_KEY = "query"
|
|
@@ -83,15 +86,12 @@ def find_base_path_cached(request, cached):
|
|
|
83
86
|
try:
|
|
84
87
|
distro = ContainerDistribution.objects.get(base_path=path, pulp_domain=domain)
|
|
85
88
|
except ObjectDoesNotExist:
|
|
86
|
-
distro = (
|
|
87
|
-
ContainerPullThroughDistribution.objects.annotate(path=Value(path))
|
|
88
|
-
.filter(path__startswith=F("base_path"), pulp_domain=domain)
|
|
89
|
-
.order_by("-base_path")
|
|
90
|
-
.first()
|
|
91
|
-
)
|
|
89
|
+
distro = get_pull_through_distribution(path, domain)
|
|
92
90
|
if not distro:
|
|
93
91
|
raise RepositoryNotFound(name=path)
|
|
94
92
|
|
|
93
|
+
return cache_key(get_pull_through_distribution_path(distro))
|
|
94
|
+
|
|
95
95
|
return cache_key(distro.base_path)
|
|
96
96
|
|
|
97
97
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
from django.conf import settings
|
|
2
2
|
from django.core.checks import Error as CheckError
|
|
3
|
+
from django.core.checks import Warning as CheckWarning
|
|
3
4
|
from django.core.checks import register
|
|
5
|
+
from django.db import OperationalError, ProgrammingError
|
|
6
|
+
|
|
7
|
+
from pulp_container.app.models import ContainerPullThroughDistribution
|
|
8
|
+
from pulp_container.constants import PULL_THROUGH_DISTRIBUTION_LABEL
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
@register(deploy=True)
|
|
@@ -45,3 +50,28 @@ def container_settings_check(app_configs, **kwargs):
|
|
|
45
50
|
)
|
|
46
51
|
|
|
47
52
|
return errors
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@register()
|
|
56
|
+
def pull_through_distribution_check(app_configs, **kwargs):
|
|
57
|
+
"""Warn when legacy pull-through distributions need repair."""
|
|
58
|
+
try:
|
|
59
|
+
needs_repair = ContainerPullThroughDistribution.objects.exclude(
|
|
60
|
+
pulp_labels__has_key=PULL_THROUGH_DISTRIBUTION_LABEL
|
|
61
|
+
).exists()
|
|
62
|
+
except (OperationalError, ProgrammingError):
|
|
63
|
+
return []
|
|
64
|
+
|
|
65
|
+
if not needs_repair:
|
|
66
|
+
return []
|
|
67
|
+
|
|
68
|
+
return [
|
|
69
|
+
CheckWarning(
|
|
70
|
+
"Pull-through distributions need base-path repair.",
|
|
71
|
+
hint=(
|
|
72
|
+
"Run 'pulpcore-manager container-repair-pull-through-distributions' and "
|
|
73
|
+
"resolve any distributions it reports."
|
|
74
|
+
),
|
|
75
|
+
id="pulp_container.W001",
|
|
76
|
+
)
|
|
77
|
+
]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from gettext import gettext as _
|
|
2
|
+
from uuid import uuid4
|
|
3
|
+
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from django.core.management import BaseCommand
|
|
6
|
+
from django.db import transaction
|
|
7
|
+
|
|
8
|
+
from pulpcore.plugin.cache import SyncContentCache
|
|
9
|
+
|
|
10
|
+
from pulp_container.app.models import ContainerPullThroughDistribution
|
|
11
|
+
from pulp_container.app.pull_through import (
|
|
12
|
+
PULL_THROUGH_DISTRIBUTION_LABEL,
|
|
13
|
+
find_container_distribution_overlaps,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Command(BaseCommand):
|
|
18
|
+
"""Repair pull-through distributions whose registry path is stored as their base path."""
|
|
19
|
+
|
|
20
|
+
help = _("Repair pull-through distribution base paths and report remaining overlaps.")
|
|
21
|
+
|
|
22
|
+
def handle(self, *args, **options):
|
|
23
|
+
"""Move eligible pull-through base paths and report unresolved overlaps."""
|
|
24
|
+
repaired = 0
|
|
25
|
+
migrated_base_paths_and_domain = []
|
|
26
|
+
distributions = ContainerPullThroughDistribution.objects.exclude(
|
|
27
|
+
pulp_labels__has_key=PULL_THROUGH_DISTRIBUTION_LABEL
|
|
28
|
+
).select_related("pulp_domain")
|
|
29
|
+
|
|
30
|
+
for distribution in distributions.iterator():
|
|
31
|
+
old_base_path = distribution.base_path
|
|
32
|
+
distribution.base_path = str(uuid4())
|
|
33
|
+
distribution.pulp_labels = {
|
|
34
|
+
**(distribution.pulp_labels or {}),
|
|
35
|
+
PULL_THROUGH_DISTRIBUTION_LABEL: old_base_path,
|
|
36
|
+
}
|
|
37
|
+
migrated_base_paths_and_domain.append((old_base_path, distribution.pulp_domain))
|
|
38
|
+
with transaction.atomic():
|
|
39
|
+
distribution.save(update_fields=["base_path", "pulp_labels"])
|
|
40
|
+
repaired += 1
|
|
41
|
+
|
|
42
|
+
self.stdout.write(self.style.SUCCESS(f"Repaired {repaired} pull-through distributions."))
|
|
43
|
+
|
|
44
|
+
overlaps = find_container_distribution_overlaps()
|
|
45
|
+
if overlaps:
|
|
46
|
+
self.stdout.write(
|
|
47
|
+
self.style.WARNING(
|
|
48
|
+
"The following container distributions have overlapping base paths:"
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
for distribution, other in overlaps:
|
|
52
|
+
self.stdout.write(
|
|
53
|
+
f" {self._format_distribution(distribution).strip()} overlaps "
|
|
54
|
+
f"{self._format_distribution(other).strip()}"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
if settings.CACHE_ENABLED and migrated_base_paths_and_domain:
|
|
58
|
+
if settings.DOMAIN_ENABLED:
|
|
59
|
+
old_base_paths = [
|
|
60
|
+
f"{domain.name}:{base_path}"
|
|
61
|
+
for base_path, domain in migrated_base_paths_and_domain
|
|
62
|
+
]
|
|
63
|
+
else:
|
|
64
|
+
old_base_paths = [base_path for base_path, _ in migrated_base_paths_and_domain]
|
|
65
|
+
SyncContentCache().delete(base_key=old_base_paths)
|
|
66
|
+
self.stdout.write(self.style.SUCCESS("Flushed repaired distribution cache entries."))
|
|
67
|
+
|
|
68
|
+
@staticmethod
|
|
69
|
+
def _format_distribution(distribution):
|
|
70
|
+
return (
|
|
71
|
+
f" domain={distribution.pulp_domain.name!r} pk={distribution.pk} "
|
|
72
|
+
f"name={distribution.name!r} base_path={distribution.base_path!r}"
|
|
73
|
+
)
|
|
@@ -2,7 +2,6 @@ import json
|
|
|
2
2
|
import os
|
|
3
3
|
import re
|
|
4
4
|
import tempfile
|
|
5
|
-
import time
|
|
6
5
|
from gettext import gettext as _
|
|
7
6
|
from logging import getLogger
|
|
8
7
|
|
|
@@ -937,8 +936,7 @@ INCOMPLETE_EXT = ".part"
|
|
|
937
936
|
|
|
938
937
|
def generate_filename(instance, filename):
|
|
939
938
|
"""Method for generating upload file name"""
|
|
940
|
-
|
|
941
|
-
return time.strftime(filename)
|
|
939
|
+
return os.path.join(instance.upload_dir, str(instance.pk) + INCOMPLETE_EXT)
|
|
942
940
|
|
|
943
941
|
|
|
944
942
|
class Upload(CoreUpload):
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from django.db.models import F, Q, TextField, Value
|
|
2
|
+
from django.db.models.functions import Concat
|
|
3
|
+
|
|
4
|
+
from pulpcore.plugin.models import Distribution
|
|
5
|
+
|
|
6
|
+
from pulp_container.app.models import ContainerDistribution, ContainerPullThroughDistribution
|
|
7
|
+
from pulp_container.constants import (
|
|
8
|
+
PULL_THROUGH_DISTRIBUTION_LABEL,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def is_pull_through_distribution_marked(distribution):
|
|
13
|
+
"""Return whether a pull-through distribution stores its registry path in pulp_labels."""
|
|
14
|
+
return (distribution.pulp_labels or {}).get(PULL_THROUGH_DISTRIBUTION_LABEL)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_pull_through_distribution_path(distribution):
|
|
18
|
+
"""Return the registry path represented by a pull-through distribution."""
|
|
19
|
+
if base_path := is_pull_through_distribution_marked(distribution):
|
|
20
|
+
return base_path
|
|
21
|
+
return distribution.base_path
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _match_path(queryset, path, field):
|
|
25
|
+
"""Return the longest segment-aware path match from a queryset."""
|
|
26
|
+
prefix_field = f"{field}_prefix"
|
|
27
|
+
return (
|
|
28
|
+
queryset.annotate(
|
|
29
|
+
requested_path=Value(path, output_field=TextField()),
|
|
30
|
+
**{prefix_field: Concat(F(field), Value("/"), output_field=TextField())},
|
|
31
|
+
)
|
|
32
|
+
.filter(Q(requested_path=F(field)) | Q(requested_path__startswith=F(prefix_field)))
|
|
33
|
+
.order_by(f"-{field}")
|
|
34
|
+
.first()
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_pull_through_distribution(path, domain):
|
|
39
|
+
"""Find a pull-through distribution using the repaired scheme, then the legacy scheme."""
|
|
40
|
+
distributions = ContainerPullThroughDistribution.objects.filter(pulp_domain=domain)
|
|
41
|
+
marked = distributions.filter(pulp_labels__has_key=PULL_THROUGH_DISTRIBUTION_LABEL)
|
|
42
|
+
if distribution := _match_path(marked, path, f"pulp_labels__{PULL_THROUGH_DISTRIBUTION_LABEL}"):
|
|
43
|
+
return distribution
|
|
44
|
+
|
|
45
|
+
legacy = distributions.exclude(pulp_labels__has_key=PULL_THROUGH_DISTRIBUTION_LABEL)
|
|
46
|
+
return _match_path(legacy, path, "base_path")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def find_container_distribution_overlaps():
|
|
50
|
+
"""Return pairs where a container distribution overlaps any distribution."""
|
|
51
|
+
container_ids = set(ContainerDistribution.objects.values_list("pk", flat=True))
|
|
52
|
+
distributions = Distribution.objects.select_related("pulp_domain").order_by(
|
|
53
|
+
"pulp_domain_id", "base_path", "pk"
|
|
54
|
+
)
|
|
55
|
+
by_domain_and_path = {
|
|
56
|
+
(distribution.pulp_domain_id, distribution.base_path): distribution
|
|
57
|
+
for distribution in distributions.iterator()
|
|
58
|
+
}
|
|
59
|
+
overlaps = []
|
|
60
|
+
|
|
61
|
+
for distribution in by_domain_and_path.values():
|
|
62
|
+
parts = distribution.base_path.split("/")
|
|
63
|
+
for index in range(1, len(parts)):
|
|
64
|
+
parent_path = "/".join(parts[:index])
|
|
65
|
+
if parent := by_domain_and_path.get((distribution.pulp_domain_id, parent_path)):
|
|
66
|
+
if parent.pk in container_ids or distribution.pk in container_ids:
|
|
67
|
+
overlaps.append((parent, distribution))
|
|
68
|
+
|
|
69
|
+
return overlaps
|
|
@@ -66,6 +66,10 @@ from pulp_container.app.exceptions import (
|
|
|
66
66
|
RepositoryInvalid,
|
|
67
67
|
RepositoryNotFound,
|
|
68
68
|
)
|
|
69
|
+
from pulp_container.app.pull_through import (
|
|
70
|
+
get_pull_through_distribution,
|
|
71
|
+
get_pull_through_distribution_path,
|
|
72
|
+
)
|
|
69
73
|
from pulp_container.app.redirects import (
|
|
70
74
|
AzureStorageRedirects,
|
|
71
75
|
FileStorageRedirects,
|
|
@@ -230,7 +234,7 @@ class ContainerRegistryApiMixin:
|
|
|
230
234
|
"""
|
|
231
235
|
List of authentication classes to check for this view.
|
|
232
236
|
"""
|
|
233
|
-
if settings
|
|
237
|
+
if getattr(settings, "TOKEN_AUTH_DISABLED", False):
|
|
234
238
|
return [RegistryAuthentication]
|
|
235
239
|
return [TokenAuthentication]
|
|
236
240
|
|
|
@@ -239,7 +243,7 @@ class ContainerRegistryApiMixin:
|
|
|
239
243
|
"""
|
|
240
244
|
List of permission classes to check for this view.
|
|
241
245
|
"""
|
|
242
|
-
if settings
|
|
246
|
+
if getattr(settings, "TOKEN_AUTH_DISABLED", False):
|
|
243
247
|
return [RegistryPermission]
|
|
244
248
|
return [TokenPermission]
|
|
245
249
|
|
|
@@ -309,18 +313,12 @@ class ContainerRegistryApiMixin:
|
|
|
309
313
|
|
|
310
314
|
def get_pull_through_drv(self, path):
|
|
311
315
|
domain = get_domain()
|
|
312
|
-
pull_through_cache_distribution = (
|
|
313
|
-
models.ContainerPullThroughDistribution.objects.annotate(path=Value(path))
|
|
314
|
-
.filter(path__startswith=F("base_path"), pulp_domain=domain)
|
|
315
|
-
.order_by("-base_path")
|
|
316
|
-
.first()
|
|
317
|
-
)
|
|
316
|
+
pull_through_cache_distribution = get_pull_through_distribution(path, domain)
|
|
318
317
|
if not pull_through_cache_distribution or not self.request.user.is_authenticated:
|
|
319
318
|
raise RepositoryNotFound(name=path)
|
|
320
319
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
)
|
|
320
|
+
pull_through_path = get_pull_through_distribution_path(pull_through_cache_distribution)
|
|
321
|
+
upstream_name = path.split(pull_through_path, maxsplit=1)[1].strip("/")
|
|
324
322
|
try:
|
|
325
323
|
pull_through_remote = models.ContainerPullThroughRemote.objects.get(
|
|
326
324
|
pk=pull_through_cache_distribution.remote_id
|
|
@@ -468,7 +466,7 @@ class VersionView(ContainerRegistryApiMixin, APIView):
|
|
|
468
466
|
"""
|
|
469
467
|
List of permission classes to check for this view.
|
|
470
468
|
"""
|
|
471
|
-
if settings
|
|
469
|
+
if getattr(settings, "TOKEN_AUTH_DISABLED", False):
|
|
472
470
|
return [IsAuthenticated]
|
|
473
471
|
return [TokenPermission]
|
|
474
472
|
|
|
@@ -560,7 +558,7 @@ class CatalogView(ContainerRegistryApiMixin, ListAPIView):
|
|
|
560
558
|
distribution_permission = "container.pull_containerdistribution"
|
|
561
559
|
namespace_permission = "container.namespace_pull_containerdistribution"
|
|
562
560
|
|
|
563
|
-
if settings
|
|
561
|
+
if getattr(settings, "TOKEN_AUTH_DISABLED", False):
|
|
564
562
|
return queryset
|
|
565
563
|
|
|
566
564
|
public_repositories = queryset.filter(private=False)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from gettext import gettext as _
|
|
3
|
+
from uuid import uuid4
|
|
3
4
|
|
|
4
5
|
from django.core.validators import URLValidator
|
|
5
6
|
from pulp_file.app.models import FileContent
|
|
@@ -32,13 +33,31 @@ from pulpcore.plugin.util import get_domain
|
|
|
32
33
|
|
|
33
34
|
from pulp_container.app import fields, models
|
|
34
35
|
from pulp_container.app.utils import get_full_path
|
|
35
|
-
from pulp_container.constants import
|
|
36
|
+
from pulp_container.constants import (
|
|
37
|
+
PULL_THROUGH_DISTRIBUTION_LABEL,
|
|
38
|
+
SIGNATURE_TYPE,
|
|
39
|
+
)
|
|
36
40
|
|
|
37
41
|
VALID_SIGNATURE_NAME_REGEX = r"^sha256:[0-9a-f]{64}@[0-9a-f]{32}$"
|
|
38
42
|
VALID_TAG_REGEX = r"^[A-Za-z0-9][A-Za-z0-9._-]*$"
|
|
39
43
|
VALID_BASE_PATH_REGEX_COMPILED = re.compile(r"^[a-z0-9]+(?:(?:[._]|__|[-]*)[a-z0-9])*$")
|
|
40
44
|
|
|
41
45
|
|
|
46
|
+
def validate_registry_path(value):
|
|
47
|
+
"""Validate a path that will be exposed by the container registry."""
|
|
48
|
+
if len(value) > 255:
|
|
49
|
+
raise serializers.ValidationError(
|
|
50
|
+
_("The entered registry path cannot be longer than 255 characters.")
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if not all(re.match(VALID_BASE_PATH_REGEX_COMPILED, part) for part in value.split("/")):
|
|
54
|
+
raise serializers.ValidationError(
|
|
55
|
+
_("The provided registry path contains forbidden characters.")
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return value
|
|
59
|
+
|
|
60
|
+
|
|
42
61
|
class TagSerializer(NoArtifactContentSerializer):
|
|
43
62
|
"""
|
|
44
63
|
Serializer for Tags.
|
|
@@ -456,17 +475,9 @@ class ContainerDistributionSerializer(DistributionSerializer, GetOrCreateSeriali
|
|
|
456
475
|
|
|
457
476
|
def validate_base_path(self, value):
|
|
458
477
|
"""Check whether the passed repository base path is valid or not."""
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
)
|
|
463
|
-
|
|
464
|
-
if not all(re.match(VALID_BASE_PATH_REGEX_COMPILED, p) for p in value.split("/")):
|
|
465
|
-
raise serializers.ValidationError(
|
|
466
|
-
_("The provided base path contains forbidden characters.")
|
|
467
|
-
)
|
|
468
|
-
|
|
469
|
-
return value
|
|
478
|
+
validate_registry_path(value)
|
|
479
|
+
# Ensure we follow pulpcore's cross-distribution overlap validation in addition to the OCI rules.
|
|
480
|
+
return super().validate_base_path(value)
|
|
470
481
|
|
|
471
482
|
class Meta:
|
|
472
483
|
model = models.ContainerDistribution
|
|
@@ -513,18 +524,49 @@ class ContainerPullThroughDistributionSerializer(DistributionSerializer):
|
|
|
513
524
|
description = serializers.CharField(
|
|
514
525
|
help_text=_("An optional description."), required=False, allow_null=True
|
|
515
526
|
)
|
|
527
|
+
base_path = serializers.CharField(
|
|
528
|
+
help_text=_("The registry path exposed by this pull-through distribution.")
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
def validate_base_path(self, value):
|
|
532
|
+
"""Check whether the passed repository base path is valid or not."""
|
|
533
|
+
validate_registry_path(value)
|
|
534
|
+
# Ensure we follow pulpcore's cross-distribution overlap validation in addition to the OCI rules.
|
|
535
|
+
return super().validate_base_path(value)
|
|
516
536
|
|
|
517
537
|
def validate(self, data):
|
|
518
538
|
validated_data = super().validate(data)
|
|
539
|
+
registry_path = validated_data.get("base_path")
|
|
540
|
+
|
|
541
|
+
# This is the temporary fix for pull-through distros violating core's overlapping base-path rule
|
|
542
|
+
# Save the base_path in pulp_labels to avoid overlapping base-paths with this PT's child distros
|
|
543
|
+
# A permanent fix should have us move off this field or Distributions all together.
|
|
544
|
+
if self.instance is None:
|
|
545
|
+
base_path = validated_data.pop("base_path")
|
|
546
|
+
validated_data["base_path"] = str(uuid4())
|
|
547
|
+
validated_data.setdefault("pulp_labels", {})[PULL_THROUGH_DISTRIBUTION_LABEL] = (
|
|
548
|
+
base_path
|
|
549
|
+
)
|
|
550
|
+
elif (
|
|
551
|
+
"base_path" in validated_data and validated_data["base_path"] != self.instance.base_path
|
|
552
|
+
):
|
|
553
|
+
is_marked = (self.instance.pulp_labels or {}).get(PULL_THROUGH_DISTRIBUTION_LABEL)
|
|
554
|
+
if is_marked:
|
|
555
|
+
message = _("This value cannot be updated.")
|
|
556
|
+
else:
|
|
557
|
+
message = _(
|
|
558
|
+
"Run 'pulpcore-manager container-repair-pull-through-distributions' before "
|
|
559
|
+
"updating this value."
|
|
560
|
+
)
|
|
561
|
+
raise serializers.ValidationError({"base_path": message})
|
|
519
562
|
|
|
520
563
|
if "content_guard" not in validated_data:
|
|
521
564
|
validated_data["content_guard"] = ContentRedirectContentGuardSerializer.get_or_create(
|
|
522
565
|
{"name": "content redirect", "pulp_domain": get_domain()}
|
|
523
566
|
)
|
|
524
567
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
namespace_name = base_path.split("/")[0]
|
|
568
|
+
if registry_path:
|
|
569
|
+
namespace_name = registry_path.split("/")[0]
|
|
528
570
|
validated_data["namespace"] = ContainerNamespaceSerializer.get_or_create(
|
|
529
571
|
{"name": namespace_name, "pulp_domain": get_domain()}
|
|
530
572
|
)
|
|
@@ -12,6 +12,7 @@ from django_filters import CharFilter, MultipleChoiceFilter
|
|
|
12
12
|
from drf_spectacular.utils import extend_schema
|
|
13
13
|
from rest_framework import mixins
|
|
14
14
|
from rest_framework.decorators import action
|
|
15
|
+
from rest_framework.exceptions import ValidationError
|
|
15
16
|
|
|
16
17
|
from pulpcore.plugin.models import Content, PulpTemporaryFile, RepositoryVersion
|
|
17
18
|
from pulpcore.plugin.serializers import AsyncOperationResponseSerializer
|
|
@@ -41,6 +42,7 @@ from pulpcore.plugin.viewsets import (
|
|
|
41
42
|
)
|
|
42
43
|
|
|
43
44
|
from pulp_container.app import models, serializers, tasks
|
|
45
|
+
from pulp_container.constants import PULL_THROUGH_DISTRIBUTION_LABEL
|
|
44
46
|
|
|
45
47
|
log = logging.getLogger(__name__)
|
|
46
48
|
|
|
@@ -1541,6 +1543,28 @@ class ContainerPullThroughDistributionViewSet(DistributionViewSet, RolesMixin):
|
|
|
1541
1543
|
],
|
|
1542
1544
|
}
|
|
1543
1545
|
|
|
1546
|
+
@action(
|
|
1547
|
+
detail=True,
|
|
1548
|
+
methods=["post"],
|
|
1549
|
+
serializer_class=DistributionViewSet.set_label.kwargs["serializer_class"],
|
|
1550
|
+
)
|
|
1551
|
+
def set_label(self, request, pk=None, **kwargs):
|
|
1552
|
+
"""Prevent clients from changing the internal pull-through marker."""
|
|
1553
|
+
if request.data.get("key") == PULL_THROUGH_DISTRIBUTION_LABEL:
|
|
1554
|
+
raise ValidationError("This label is managed by pulp_container.")
|
|
1555
|
+
return super().set_label(request, pk, **kwargs)
|
|
1556
|
+
|
|
1557
|
+
@action(
|
|
1558
|
+
detail=True,
|
|
1559
|
+
methods=["post"],
|
|
1560
|
+
serializer_class=DistributionViewSet.unset_label.kwargs["serializer_class"],
|
|
1561
|
+
)
|
|
1562
|
+
def unset_label(self, request, pk=None, **kwargs):
|
|
1563
|
+
"""Prevent clients from removing the internal pull-through marker."""
|
|
1564
|
+
if request.data.get("key") == PULL_THROUGH_DISTRIBUTION_LABEL:
|
|
1565
|
+
raise ValidationError("This label is managed by pulp_container.")
|
|
1566
|
+
return super().unset_label(request, pk, **kwargs)
|
|
1567
|
+
|
|
1544
1568
|
|
|
1545
1569
|
class ContainerNamespaceViewSet(
|
|
1546
1570
|
NamedModelViewSet,
|
|
@@ -76,7 +76,7 @@ def test_content_cache(
|
|
|
76
76
|
monitor_task,
|
|
77
77
|
):
|
|
78
78
|
"""A test case that verifies the functionality of the Redis caching machinery."""
|
|
79
|
-
if not pulp_settings
|
|
79
|
+
if not getattr(pulp_settings, "CACHE_ENABLED", False):
|
|
80
80
|
pytest.skip("The caching machinery was not enabled")
|
|
81
81
|
|
|
82
82
|
repo = container_repository_factory()
|
|
@@ -222,11 +222,12 @@ def test_cross_domain_pulp_apis(
|
|
|
222
222
|
},
|
|
223
223
|
pulp_domain=domain1.name,
|
|
224
224
|
)
|
|
225
|
+
pt_distribution_name = str(uuid.uuid4())
|
|
225
226
|
with pytest.raises(container_bindings.ApiException) as e:
|
|
226
227
|
container_bindings.DistributionsPullThroughApi.create(
|
|
227
228
|
{
|
|
228
|
-
"name":
|
|
229
|
-
"base_path":
|
|
229
|
+
"name": pt_distribution_name,
|
|
230
|
+
"base_path": pt_distribution_name,
|
|
230
231
|
"remote": pt_remote.pulp_href,
|
|
231
232
|
},
|
|
232
233
|
pulp_domain=domain2.name,
|