From 630c38bc513bbda88b354a091127ccd0609f2b01 Mon Sep 17 00:00:00 2001 From: Tobias Grigo Date: Thu, 14 Nov 2024 16:31:42 +0100 Subject: [PATCH] Fixed PRC not getting removed when modifying repositories closes #1190 --- CHANGES/1190.bugfix | 1 + pulp_deb/app/viewsets/repository.py | 37 +++++++++- pulp_deb/tests/functional/api/test_publish.py | 71 +++++++++++++++++++ 3 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 CHANGES/1190.bugfix diff --git a/CHANGES/1190.bugfix b/CHANGES/1190.bugfix new file mode 100644 index 000000000..7932acaa1 --- /dev/null +++ b/CHANGES/1190.bugfix @@ -0,0 +1 @@ +Removing packages from a repository using the modify API endpoint now also removes all associated PackageReleaseComponents. diff --git a/pulp_deb/app/viewsets/repository.py b/pulp_deb/app/viewsets/repository.py index 477b07e9d..1804853d1 100644 --- a/pulp_deb/app/viewsets/repository.py +++ b/pulp_deb/app/viewsets/repository.py @@ -5,11 +5,16 @@ from rest_framework import viewsets from rest_framework.serializers import ValidationError as DRFValidationError +from pulp_deb.app.models.content.content import Package +from pulp_deb.app.models.content.structure_content import PackageReleaseComponent from pulp_deb.app.serializers import AptRepositorySyncURLSerializer -from pulpcore.plugin.util import extract_pk +from pulpcore.plugin.util import extract_pk, get_url from pulpcore.plugin.actions import ModifyRepositoryActionMixin -from pulpcore.plugin.serializers import AsyncOperationResponseSerializer +from pulpcore.plugin.serializers import ( + AsyncOperationResponseSerializer, + RepositoryAddRemoveContentSerializer, +) from pulpcore.plugin.models import RepositoryVersion from pulpcore.plugin.tasking import dispatch from pulpcore.plugin.viewsets import ( @@ -22,7 +27,33 @@ from pulp_deb.app import models, serializers, tasks -class AptRepositoryViewSet(RepositoryViewSet, ModifyRepositoryActionMixin): +class AptModifyRepositoryActionMixin(ModifyRepositoryActionMixin): + @extend_schema( + description="Trigger an asynchronous task to create a new repository version.", + summary="Modify Repository Content", + responses={202: AsyncOperationResponseSerializer}, + ) + @action(detail=True, methods=["post"], serializer_class=RepositoryAddRemoveContentSerializer) + def modify(self, request, pk): + remove_content_units = request.data.get("remove_content_units", []) + package_hrefs = [href for href in remove_content_units if "/packages/" in href] + + if package_hrefs: + prc_hrefs = self._get_matching_prc_hrefs(package_hrefs) + remove_content_units.extend(prc_hrefs) + request.data["remove_content_units"] = remove_content_units + + return super().modify(request, pk) + + def _get_matching_prc_hrefs(self, package_hrefs): + package_ids = [extract_pk(href) for href in package_hrefs] + matching_packages = Package.objects.filter(pulp_id__in=package_ids) + matching_prcs = PackageReleaseComponent.objects.filter(package__in=matching_packages) + prc_hrefs = [get_url(component) for component in matching_prcs] + return prc_hrefs + + +class AptRepositoryViewSet(AptModifyRepositoryActionMixin, RepositoryViewSet): # The doc string is a top level element of the user facing REST API documentation: """ An AptRepository is the locally stored, Pulp-internal representation of a APT repository. diff --git a/pulp_deb/tests/functional/api/test_publish.py b/pulp_deb/tests/functional/api/test_publish.py index 9108e7082..c51a2ed34 100644 --- a/pulp_deb/tests/functional/api/test_publish.py +++ b/pulp_deb/tests/functional/api/test_publish.py @@ -12,6 +12,7 @@ DEB_FIXTURE_SINGLE_DIST, DEB_PACKAGE_INDEX_NAME, DEB_PACKAGE_NAME, + DEB_PACKAGE_RELEASE_COMPONENT_NAME, DEB_PUBLICATION_ARGS_ALL, DEB_PUBLICATION_ARGS_ONLY_SIMPLE, DEB_PUBLICATION_ARGS_ONLY_STRUCTURED, @@ -475,6 +476,76 @@ def test_publish_complex_dists( assert_equal_package_index(remote, published) +@pytest.mark.parallel +def test_remove_package_from_repository( + create_publication_and_verify_repo_version, + deb_get_content_types, + deb_modify_repository, + deb_get_repository_by_href, +): + """Test whether removing content in a structured publication removes all relevant content.""" + remote_args = {"distributions": DEB_FIXTURE_DISTRIBUTIONS} + _, repo, _, _ = create_publication_and_verify_repo_version( + remote_args, + publication_args=DEB_PUBLICATION_ARGS_ONLY_STRUCTURED, + is_modified=False, + ) + + package = deb_get_content_types( + "apt_package_api", DEB_PACKAGE_NAME, repo, repo.latest_version_href + )[0] + prcs = deb_get_content_types( + "apt_package_release_components_api", + DEB_PACKAGE_RELEASE_COMPONENT_NAME, + repo, + repo.latest_version_href, + ) + deb_modify_repository( + repo, + {"remove_content_units": [package.pulp_href]}, + ) + repo = deb_get_repository_by_href(repo.pulp_href) + prcs_new = deb_get_content_types( + "apt_package_release_components_api", + DEB_PACKAGE_RELEASE_COMPONENT_NAME, + repo, + repo.latest_version_href, + ) + + assert not any(package.pulp_href == prc.package for prc in prcs_new) + assert len(prcs_new) == len(prcs) - 1 + + +@pytest.mark.parallel +def test_remove_all_content_from_repository( + create_publication_and_verify_repo_version, + deb_get_content_types, + deb_modify_repository, + deb_get_repository_by_href, +): + """Test whether removing all content from a structured publication removes relevant content.""" + remote_args = {"distributions": DEB_FIXTURE_DISTRIBUTIONS} + _, repo, _, _ = create_publication_and_verify_repo_version( + remote_args, + publication_args=DEB_PUBLICATION_ARGS_ONLY_STRUCTURED, + is_modified=False, + ) + + deb_modify_repository( + repo, + {"remove_content_units": ["*"]}, + ) + repo = deb_get_repository_by_href(repo.pulp_href) + prcs = deb_get_content_types( + "apt_package_release_components_api", + DEB_PACKAGE_RELEASE_COMPONENT_NAME, + repo, + repo.latest_version_href, + ) + + assert len(prcs) == 0 + + def assert_equal_package_index(orig, new): """In-detail check of two PackageIndex file-strings""" parsed_orig = parse_package_index(orig)