pulp-ansible 0.26.0__py3-none-any.whl → 0.27.1__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.
- pulp_ansible/app/__init__.py +2 -1
- pulp_ansible/app/galaxy/v3/serializers.py +18 -7
- pulp_ansible/app/galaxy/v3/views.py +35 -13
- pulp_ansible/app/galaxy/v3/viewsets.py +2 -2
- pulp_ansible/app/galaxy/views.py +7 -2
- pulp_ansible/app/migrations/0062_pivot_collectionversion_tags.py +140 -0
- pulp_ansible/app/migrations/0063_domain_support.py +118 -0
- pulp_ansible/app/migrations/0064_alter_collection_unique_together_and_more.py +68 -0
- pulp_ansible/app/modelresource.py +1 -24
- pulp_ansible/app/models.py +25 -35
- pulp_ansible/app/serializers.py +50 -53
- pulp_ansible/app/settings.py +2 -0
- pulp_ansible/app/tasks/collections.py +80 -94
- pulp_ansible/app/tasks/signature.py +10 -11
- pulp_ansible/app/tasks/test_tasks.py +6 -3
- pulp_ansible/app/tasks/upload.py +3 -15
- pulp_ansible/app/urls.py +15 -4
- pulp_ansible/app/viewsets.py +59 -62
- pulp_ansible/pytest_plugin.py +12 -2
- pulp_ansible/tests/functional/api/collection/v3/test_collection.py +9 -2
- pulp_ansible/tests/functional/api/collection/v3/test_deprecation.py +29 -8
- pulp_ansible/tests/functional/api/test_domain.py +74 -0
- pulp_ansible/tests/functional/api/test_export_import.py +11 -0
- pulp_ansible/tests/unit/test_search.py +6 -8
- pulp_ansible/tests/unit/test_serializers.py +3 -3
- pulp_ansible/tests/unit/utils.py +5 -1
- {pulp_ansible-0.26.0.dist-info → pulp_ansible-0.27.1.dist-info}/METADATA +2 -2
- {pulp_ansible-0.26.0.dist-info → pulp_ansible-0.27.1.dist-info}/RECORD +32 -28
- {pulp_ansible-0.26.0.dist-info → pulp_ansible-0.27.1.dist-info}/WHEEL +0 -0
- {pulp_ansible-0.26.0.dist-info → pulp_ansible-0.27.1.dist-info}/entry_points.txt +0 -0
- {pulp_ansible-0.26.0.dist-info → pulp_ansible-0.27.1.dist-info}/licenses/LICENSE +0 -0
- {pulp_ansible-0.26.0.dist-info → pulp_ansible-0.27.1.dist-info}/top_level.txt +0 -0
pulp_ansible/app/__init__.py
CHANGED
|
@@ -3,19 +3,25 @@ from django.conf import settings
|
|
|
3
3
|
from drf_spectacular.utils import extend_schema_field, extend_schema_serializer
|
|
4
4
|
from drf_spectacular.types import OpenApiTypes
|
|
5
5
|
from rest_framework.reverse import reverse
|
|
6
|
-
from rest_framework import serializers
|
|
6
|
+
from rest_framework import serializers
|
|
7
7
|
|
|
8
|
-
from
|
|
8
|
+
from pulpcore.plugin.util import get_domain
|
|
9
9
|
from pulpcore.plugin.models import RepositoryVersion
|
|
10
10
|
from pulpcore.plugin import serializers as core_serializers
|
|
11
11
|
|
|
12
|
+
from pulp_ansible.app import models, fields, serializers as ansible_serializers
|
|
13
|
+
|
|
14
|
+
DOMAIN_ENABLED = settings.DOMAIN_ENABLED
|
|
15
|
+
|
|
12
16
|
|
|
13
17
|
def _get_distro_context(context):
|
|
14
18
|
distro_context = {}
|
|
15
|
-
if "path"
|
|
16
|
-
distro_context["path"] =
|
|
19
|
+
if path := context.get("path") or context.get("distro_base_path"):
|
|
20
|
+
distro_context["path"] = path
|
|
17
21
|
if "distro_base_path" in context:
|
|
18
22
|
distro_context["distro_base_path"] = context["distro_base_path"]
|
|
23
|
+
if DOMAIN_ENABLED:
|
|
24
|
+
distro_context["pulp_domain"] = get_domain().name
|
|
19
25
|
return distro_context
|
|
20
26
|
|
|
21
27
|
|
|
@@ -165,8 +171,6 @@ class CollectionMetadataSerializer(serializers.ModelSerializer):
|
|
|
165
171
|
A serializer for a CollectionVersion metadata.
|
|
166
172
|
"""
|
|
167
173
|
|
|
168
|
-
tags = relations.ManyRelatedField(relations.StringRelatedField())
|
|
169
|
-
|
|
170
174
|
class Meta:
|
|
171
175
|
model = models.CollectionVersion
|
|
172
176
|
fields = (
|
|
@@ -265,9 +269,16 @@ class UnpaginatedCollectionVersionSerializer(CollectionVersionListSerializer):
|
|
|
265
269
|
# because using the request context to generate the full URL causes the download URL
|
|
266
270
|
# to be inaccessible when pulp is running behind a reverse proxy.
|
|
267
271
|
host = settings.ANSIBLE_API_HOSTNAME.strip("/")
|
|
272
|
+
extra_args = {}
|
|
273
|
+
if DOMAIN_ENABLED:
|
|
274
|
+
extra_args["pulp_domain"] = get_domain().name
|
|
268
275
|
path = reverse(
|
|
269
276
|
settings.ANSIBLE_URL_NAMESPACE + "collection-artifact-download",
|
|
270
|
-
kwargs={
|
|
277
|
+
kwargs={
|
|
278
|
+
"distro_base_path": distro_base_path,
|
|
279
|
+
"filename": filename_path,
|
|
280
|
+
**extra_args,
|
|
281
|
+
},
|
|
271
282
|
).strip("/")
|
|
272
283
|
|
|
273
284
|
return f"{host}/{path}"
|
|
@@ -40,6 +40,7 @@ from pulpcore.plugin.viewsets import (
|
|
|
40
40
|
NAME_FILTER_OPTIONS,
|
|
41
41
|
)
|
|
42
42
|
from pulpcore.plugin.tasking import add_and_remove, dispatch, general_create
|
|
43
|
+
from pulpcore.plugin.util import get_domain, get_domain_pk, get_url
|
|
43
44
|
|
|
44
45
|
from pulp_ansible.app.galaxy.v3.exceptions import ExceptionHandlerMixin
|
|
45
46
|
from pulp_ansible.app.galaxy.v3.serializers import (
|
|
@@ -81,6 +82,8 @@ from pulp_ansible.app.tasks.deletion import delete_collection_version, delete_co
|
|
|
81
82
|
from pulp_ansible.app.utils import filter_content_for_repo_version
|
|
82
83
|
|
|
83
84
|
|
|
85
|
+
DOMAIN_ENABLED = settings.DOMAIN_ENABLED
|
|
86
|
+
|
|
84
87
|
_CAN_VIEW_REPO_CONTENT = {
|
|
85
88
|
"action": ["list", "retrieve", "download"],
|
|
86
89
|
"principal": "authenticated",
|
|
@@ -131,6 +134,7 @@ class AnsibleDistributionMixin:
|
|
|
131
134
|
"base_path", "repository_version", "repository"
|
|
132
135
|
).select_related("repository__ansible_ansiblerepository"),
|
|
133
136
|
base_path=path,
|
|
137
|
+
pulp_domain=get_domain_pk(),
|
|
134
138
|
)
|
|
135
139
|
if distro.repository_version_id:
|
|
136
140
|
self.pulp_context = {path: distro.repository_version}
|
|
@@ -334,7 +338,7 @@ class CollectionViewSet(
|
|
|
334
338
|
)
|
|
335
339
|
|
|
336
340
|
download_count_qs = CollectionDownloadCount.objects.filter(
|
|
337
|
-
name=OuterRef("name"), namespace=OuterRef("namespace")
|
|
341
|
+
name=OuterRef("name"), namespace=OuterRef("namespace"), pulp_domain=get_domain()
|
|
338
342
|
)
|
|
339
343
|
|
|
340
344
|
qs = (
|
|
@@ -460,7 +464,9 @@ def get_collection_dependents(parent):
|
|
|
460
464
|
"""Given a parent collection, return a list of collection versions that depend on it."""
|
|
461
465
|
key = f"{parent.namespace}.{parent.name}"
|
|
462
466
|
return list(
|
|
463
|
-
CollectionVersion.objects.exclude(collection=parent).filter(
|
|
467
|
+
CollectionVersion.objects.exclude(collection=parent).filter(
|
|
468
|
+
dependencies__has_key=key, pulp_domain=get_domain()
|
|
469
|
+
)
|
|
464
470
|
)
|
|
465
471
|
|
|
466
472
|
|
|
@@ -477,7 +483,9 @@ def get_unique_dependents(parent):
|
|
|
477
483
|
other_versions.append(semantic_version.Version(v.version))
|
|
478
484
|
|
|
479
485
|
dependents = []
|
|
480
|
-
for child in CollectionVersion.objects.filter(
|
|
486
|
+
for child in CollectionVersion.objects.filter(
|
|
487
|
+
dependencies__has_key=key, pulp_domain=get_domain()
|
|
488
|
+
):
|
|
481
489
|
spec = semantic_version.SimpleSpec(child.dependencies[key])
|
|
482
490
|
|
|
483
491
|
# If this collection matches the parent collections version and there are no other
|
|
@@ -567,7 +575,7 @@ class CollectionUploadViewSet(
|
|
|
567
575
|
serializer.is_valid(raise_exception=True)
|
|
568
576
|
|
|
569
577
|
# Check that namespace, name and version can be extracted
|
|
570
|
-
request.data["repository"] =
|
|
578
|
+
request.data["repository"] = get_url(repo)
|
|
571
579
|
serializer = CollectionVersionUploadSerializer(
|
|
572
580
|
data=request.data, context=self.get_serializer_context()
|
|
573
581
|
)
|
|
@@ -585,10 +593,14 @@ class CollectionUploadViewSet(
|
|
|
585
593
|
)
|
|
586
594
|
# Create CollectionImport and response
|
|
587
595
|
CollectionImport.objects.create(task_id=task.pk)
|
|
596
|
+
if DOMAIN_ENABLED:
|
|
597
|
+
kwargs = {"pk": task.pk, "pulp_domain": get_domain().name}
|
|
598
|
+
else:
|
|
599
|
+
kwargs = {"pk": task.pk}
|
|
588
600
|
data = {
|
|
589
601
|
"task": reverse(
|
|
590
602
|
settings.ANSIBLE_URL_NAMESPACE + "collection-imports-detail",
|
|
591
|
-
kwargs=
|
|
603
|
+
kwargs=kwargs,
|
|
592
604
|
request=None,
|
|
593
605
|
)
|
|
594
606
|
}
|
|
@@ -704,11 +716,14 @@ class CollectionArtifactDownloadView(GalaxyAuthMixin, views.APIView, AnsibleDist
|
|
|
704
716
|
def get(self, request, *args, **kwargs):
|
|
705
717
|
"""Download collection."""
|
|
706
718
|
distro_base_path = self.kwargs["distro_base_path"]
|
|
707
|
-
distribution = AnsibleDistribution.objects.get(
|
|
719
|
+
distribution = AnsibleDistribution.objects.get(
|
|
720
|
+
base_path=distro_base_path, pulp_domain=get_domain()
|
|
721
|
+
)
|
|
708
722
|
|
|
709
|
-
url = "{host}/{prefix}/{distro_base_path}/{filename}".format(
|
|
723
|
+
url = "{host}/{prefix}{domain}/{distro_base_path}/{filename}".format(
|
|
710
724
|
host=settings.CONTENT_ORIGIN.strip("/"),
|
|
711
725
|
prefix=settings.CONTENT_PATH_PREFIX.strip("/"),
|
|
726
|
+
domain="/" + get_domain().name if DOMAIN_ENABLED else "",
|
|
712
727
|
distro_base_path=distro_base_path,
|
|
713
728
|
filename=self.kwargs["filename"],
|
|
714
729
|
)
|
|
@@ -799,7 +814,9 @@ class AnsibleNamespaceViewSet(
|
|
|
799
814
|
except IntegrityError:
|
|
800
815
|
# if artifact already exists, let's use it
|
|
801
816
|
try:
|
|
802
|
-
artifact = Artifact.objects.get(
|
|
817
|
+
artifact = Artifact.objects.get(
|
|
818
|
+
sha256=artifact.sha256, pulp_domain=get_domain()
|
|
819
|
+
)
|
|
803
820
|
artifact.touch()
|
|
804
821
|
except (Artifact.DoesNotExist, DatabaseError):
|
|
805
822
|
# the artifact has since been removed from when we first attempted to save it
|
|
@@ -831,7 +848,9 @@ class AnsibleNamespaceViewSet(
|
|
|
831
848
|
serializer.validated_data.setdefault(name, serializer.data[name])
|
|
832
849
|
context = {}
|
|
833
850
|
if "avatar" not in request.data and namespace.avatar_sha256:
|
|
834
|
-
context["artifact"] = Artifact.objects.get(
|
|
851
|
+
context["artifact"] = Artifact.objects.get(
|
|
852
|
+
sha256=namespace.avatar_sha256, pulp_domain=get_domain()
|
|
853
|
+
).pk
|
|
835
854
|
return self._create(request, data=serializer.validated_data, context=context)
|
|
836
855
|
|
|
837
856
|
def delete(self, request, *args, **kwargs):
|
|
@@ -1283,7 +1302,10 @@ def redirect_view_generator(actions, url, viewset, distro_view=True, responses={
|
|
|
1283
1302
|
# remove the old path kwarg since we're redirecting to the new api endpoints
|
|
1284
1303
|
del kwargs["path"]
|
|
1285
1304
|
|
|
1286
|
-
kwargs
|
|
1305
|
+
kwargs["distro_base_path"] = path
|
|
1306
|
+
|
|
1307
|
+
if DOMAIN_ENABLED:
|
|
1308
|
+
kwargs["pulp_domain"] = get_domain().name
|
|
1287
1309
|
|
|
1288
1310
|
# don't pass request. redirects work with just the path and this solves the client
|
|
1289
1311
|
# redirect issues for aiohttp
|
|
@@ -1293,9 +1315,9 @@ def redirect_view_generator(actions, url, viewset, distro_view=True, responses={
|
|
|
1293
1315
|
# request=self.request,
|
|
1294
1316
|
)
|
|
1295
1317
|
|
|
1296
|
-
|
|
1297
|
-
if
|
|
1298
|
-
url = "%s?%s" % (url,
|
|
1318
|
+
qs = self.request.META.get("QUERY_STRING", "")
|
|
1319
|
+
if qs:
|
|
1320
|
+
url = "%s?%s" % (url, qs)
|
|
1299
1321
|
|
|
1300
1322
|
return url
|
|
1301
1323
|
|
|
@@ -9,7 +9,7 @@ from pulp_ansible.app.galaxy.v3.serializers import (
|
|
|
9
9
|
)
|
|
10
10
|
from pulp_ansible.app.galaxy.mixins import GalaxyAuthMixin
|
|
11
11
|
|
|
12
|
-
from pulpcore.plugin.util import get_url
|
|
12
|
+
from pulpcore.plugin.util import get_url, get_domain_pk
|
|
13
13
|
|
|
14
14
|
from pulp_ansible.app.models import CrossRepositoryCollectionVersionIndex, AnsibleDistribution
|
|
15
15
|
|
|
@@ -83,7 +83,7 @@ class CollectionVersionSearchViewSet(GalaxyAuthMixin, viewsets.ModelViewSet):
|
|
|
83
83
|
.select_related("collection_version")
|
|
84
84
|
.select_related("repository_version")
|
|
85
85
|
.select_related("namespace_metadata")
|
|
86
|
-
.
|
|
86
|
+
.filter(repository__pulp_domain_id=get_domain_pk())
|
|
87
87
|
)
|
|
88
88
|
|
|
89
89
|
for permission_class in self.get_permissions():
|
pulp_ansible/app/galaxy/views.py
CHANGED
|
@@ -3,6 +3,7 @@ import re
|
|
|
3
3
|
from django.shortcuts import get_object_or_404
|
|
4
4
|
from drf_spectacular.utils import extend_schema, extend_schema_view
|
|
5
5
|
from rest_framework import generics, response, views
|
|
6
|
+
from pulpcore.plugin.util import get_domain
|
|
6
7
|
|
|
7
8
|
from pulp_ansible.app.models import AnsibleDistribution, Role
|
|
8
9
|
|
|
@@ -89,7 +90,9 @@ class RoleList(DistributionMixin, generics.ListAPIView):
|
|
|
89
90
|
"""
|
|
90
91
|
Get the list of items for this view.
|
|
91
92
|
"""
|
|
92
|
-
roles = Role.objects.distinct("namespace", "name").filter(
|
|
93
|
+
roles = Role.objects.distinct("namespace", "name").filter(
|
|
94
|
+
pk__in=self._distro_content, pulp_domain=get_domain()
|
|
95
|
+
)
|
|
93
96
|
|
|
94
97
|
namespace = self.request.query_params.get("owner__username", None)
|
|
95
98
|
if namespace:
|
|
@@ -117,5 +120,7 @@ class RoleVersionList(DistributionMixin, generics.ListAPIView):
|
|
|
117
120
|
Get the list of items for this view.
|
|
118
121
|
"""
|
|
119
122
|
namespace, name = re.split(r"\.", self.kwargs["role_pk"])
|
|
120
|
-
versions = Role.objects.filter(
|
|
123
|
+
versions = Role.objects.filter(
|
|
124
|
+
pk__in=self._distro_content, name=name, namespace=namespace, pulp_domain=get_domain()
|
|
125
|
+
)
|
|
121
126
|
return versions
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Generated by Django 4.2.19 on 2025-05-21 13:50
|
|
2
|
+
|
|
3
|
+
import django.contrib.postgres.fields
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
from pulpcore.plugin.migrations import RequireVersion
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def migrate_missing_tags_up(apps, schema):
|
|
9
|
+
CollectionVersion = apps.get_model("ansible", "CollectionVersion")
|
|
10
|
+
cv_to_update = []
|
|
11
|
+
for cv in CollectionVersion.objects.filter(new_tags=None).prefetch_related("tags"):
|
|
12
|
+
cv.new_tags = [t.name for t in cv.tags.all()]
|
|
13
|
+
cv_to_update.append(cv)
|
|
14
|
+
if len(cv_to_update) >= 100:
|
|
15
|
+
CollectionVersion.objects.bulk_update(cv_to_update, ["new_tags"])
|
|
16
|
+
cv_to_update = []
|
|
17
|
+
if len(cv_to_update) > 0:
|
|
18
|
+
CollectionVersion.objects.bulk_update(cv_to_update, ["new_tags"])
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def migrate_missing_tags_down(apps, schema):
|
|
22
|
+
# Warning, this Down-Migration is not Zero-Downtime safe.
|
|
23
|
+
# Also it's not optimized.
|
|
24
|
+
Tag = apps.get_model("ansible", "Tag")
|
|
25
|
+
CollectionVersion = apps.get_model("ansible", "CollectionVersion")
|
|
26
|
+
for cv in CollectionVersion.objects.filter(new_tags__len__gt=0):
|
|
27
|
+
for tag_name in cv.new_tags:
|
|
28
|
+
tag, created = Tag.objects.get_or_create(name=tag_name)
|
|
29
|
+
cv.tags.add(tag)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# This query generates full text search index based
|
|
33
|
+
# the following data ranked from A to D:
|
|
34
|
+
# - Namespace name (weight A)
|
|
35
|
+
# - Collection name (weight A)
|
|
36
|
+
# - Collection tags (weight B)
|
|
37
|
+
# - Collection content names (weight C)
|
|
38
|
+
# - Collection description (weight D)
|
|
39
|
+
NEW_TS_VECTOR_SELECT = """
|
|
40
|
+
setweight(to_tsvector(coalesce(NEW.namespace,'')), 'A')
|
|
41
|
+
|| setweight(to_tsvector(coalesce(NEW.name, '')), 'A')
|
|
42
|
+
|| setweight(to_tsvector(array_to_string(coalesce(NEW.tags, ARRAY[]::bpchar[]), ' ')), 'B')
|
|
43
|
+
|| (
|
|
44
|
+
SELECT
|
|
45
|
+
setweight(to_tsvector(coalesce(string_agg(cvc ->> 'name', ' '), '')), 'C')
|
|
46
|
+
FROM jsonb_array_elements(NEW.contents) AS cvc
|
|
47
|
+
)
|
|
48
|
+
|| setweight(to_tsvector(coalesce(NEW.description, '')), 'D')
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
OLD_TS_VECTOR_SELECT = """
|
|
52
|
+
SELECT
|
|
53
|
+
setweight(to_tsvector(coalesce(namespace,'')), 'A')
|
|
54
|
+
|| setweight(to_tsvector(coalesce(name, '')), 'A')
|
|
55
|
+
|| (
|
|
56
|
+
SELECT
|
|
57
|
+
setweight(to_tsvector(
|
|
58
|
+
coalesce(string_agg("ansible_tag"."name", ' '), '')
|
|
59
|
+
), 'B')
|
|
60
|
+
FROM
|
|
61
|
+
"ansible_tag" INNER JOIN "ansible_collectionversion_tags"
|
|
62
|
+
ON
|
|
63
|
+
("ansible_tag"."pulp_id" = "ansible_collectionversion_tags"."tag_id" )
|
|
64
|
+
WHERE
|
|
65
|
+
"ansible_collectionversion_tags"."collectionversion_id" = cv.content_ptr_id
|
|
66
|
+
)
|
|
67
|
+
|| (
|
|
68
|
+
SELECT
|
|
69
|
+
setweight(to_tsvector(
|
|
70
|
+
coalesce(string_agg(cvc ->> 'name', ' '), '')
|
|
71
|
+
), 'C')
|
|
72
|
+
FROM jsonb_array_elements(cv.contents) AS cvc
|
|
73
|
+
)
|
|
74
|
+
|| setweight(to_tsvector(coalesce(description, '')), 'D')
|
|
75
|
+
FROM ansible_collectionversion cv
|
|
76
|
+
WHERE cv.content_ptr_id = NEW.content_ptr_id
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
# Creates a database function and a trigger to update collection search
|
|
80
|
+
# vector field.
|
|
81
|
+
# In the new version, tags are availabel at create and content should never be updated,
|
|
82
|
+
# so having both insert and update in the trigger from now on is probably fast _and_ safe.
|
|
83
|
+
UPDATE_COLLECTIONS_TS_VECTOR_TRIGGER = """
|
|
84
|
+
SET CONSTRAINTS ALL IMMEDIATE;
|
|
85
|
+
CREATE OR REPLACE FUNCTION update_collection_ts_vector()
|
|
86
|
+
RETURNS TRIGGER AS
|
|
87
|
+
$$
|
|
88
|
+
BEGIN
|
|
89
|
+
NEW.search_vector := ({TS_VECTOR_SELECT});
|
|
90
|
+
RETURN NEW;
|
|
91
|
+
END;
|
|
92
|
+
$$ LANGUAGE plpgsql;
|
|
93
|
+
DROP TRIGGER IF EXISTS update_ts_vector ON ansible_collectionversion;
|
|
94
|
+
CREATE TRIGGER update_ts_vector
|
|
95
|
+
{WHEN}
|
|
96
|
+
ON ansible_collectionversion
|
|
97
|
+
FOR EACH ROW
|
|
98
|
+
EXECUTE FUNCTION update_collection_ts_vector();
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class Migration(migrations.Migration):
|
|
103
|
+
|
|
104
|
+
dependencies = [
|
|
105
|
+
("ansible", "0061_collectionversion_new_tags"),
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
operations = [
|
|
109
|
+
RequireVersion("ansible", "0.26.0"),
|
|
110
|
+
migrations.RunPython(code=migrate_missing_tags_up, reverse_code=migrate_missing_tags_down),
|
|
111
|
+
migrations.RunSQL(
|
|
112
|
+
sql=UPDATE_COLLECTIONS_TS_VECTOR_TRIGGER.format(
|
|
113
|
+
TS_VECTOR_SELECT=NEW_TS_VECTOR_SELECT,
|
|
114
|
+
WHEN="BEFORE INSERT OR UPDATE",
|
|
115
|
+
),
|
|
116
|
+
reverse_sql=UPDATE_COLLECTIONS_TS_VECTOR_TRIGGER.format(
|
|
117
|
+
TS_VECTOR_SELECT=OLD_TS_VECTOR_SELECT,
|
|
118
|
+
WHEN="BEFORE UPDATE",
|
|
119
|
+
),
|
|
120
|
+
),
|
|
121
|
+
migrations.RemoveField(
|
|
122
|
+
model_name="collectionversion",
|
|
123
|
+
name="tags",
|
|
124
|
+
),
|
|
125
|
+
migrations.DeleteModel(
|
|
126
|
+
name="Tag",
|
|
127
|
+
),
|
|
128
|
+
migrations.RenameField(
|
|
129
|
+
model_name="collectionversion",
|
|
130
|
+
old_name="new_tags",
|
|
131
|
+
new_name="tags",
|
|
132
|
+
),
|
|
133
|
+
migrations.AlterField(
|
|
134
|
+
model_name="collectionversion",
|
|
135
|
+
name="tags",
|
|
136
|
+
field=django.contrib.postgres.fields.ArrayField(
|
|
137
|
+
base_field=models.CharField(max_length=64, unique=True), default=list, size=None
|
|
138
|
+
),
|
|
139
|
+
),
|
|
140
|
+
]
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Generated by Django 4.2.19 on 2025-04-15 16:27
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
import django.db.models.deletion
|
|
5
|
+
import pulpcore.app.util
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
("core", "0117_task_unblocked_at"),
|
|
12
|
+
("ansible", "0062_pivot_collectionversion_tags"),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.AlterUniqueTogether(
|
|
17
|
+
name="ansiblecollectiondeprecated",
|
|
18
|
+
unique_together=set(),
|
|
19
|
+
),
|
|
20
|
+
migrations.AlterUniqueTogether(
|
|
21
|
+
name="ansiblenamespacemetadata",
|
|
22
|
+
unique_together=set(),
|
|
23
|
+
),
|
|
24
|
+
migrations.AlterUniqueTogether(
|
|
25
|
+
name="collectionversion",
|
|
26
|
+
unique_together=set(),
|
|
27
|
+
),
|
|
28
|
+
migrations.AlterUniqueTogether(
|
|
29
|
+
name="collectionversionmark",
|
|
30
|
+
unique_together=set(),
|
|
31
|
+
),
|
|
32
|
+
migrations.AlterUniqueTogether(
|
|
33
|
+
name="collectionversionsignature",
|
|
34
|
+
unique_together=set(),
|
|
35
|
+
),
|
|
36
|
+
migrations.AlterUniqueTogether(
|
|
37
|
+
name="role",
|
|
38
|
+
unique_together=set(),
|
|
39
|
+
),
|
|
40
|
+
migrations.AddField(
|
|
41
|
+
model_name="ansiblecollectiondeprecated",
|
|
42
|
+
name="_pulp_domain",
|
|
43
|
+
field=models.ForeignKey(
|
|
44
|
+
default=pulpcore.app.util.get_domain_pk,
|
|
45
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
46
|
+
to="core.domain",
|
|
47
|
+
),
|
|
48
|
+
),
|
|
49
|
+
migrations.AddField(
|
|
50
|
+
model_name="ansiblenamespacemetadata",
|
|
51
|
+
name="_pulp_domain",
|
|
52
|
+
field=models.ForeignKey(
|
|
53
|
+
default=pulpcore.app.util.get_domain_pk,
|
|
54
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
55
|
+
to="core.domain",
|
|
56
|
+
),
|
|
57
|
+
),
|
|
58
|
+
migrations.AddField(
|
|
59
|
+
model_name="collectionversion",
|
|
60
|
+
name="_pulp_domain",
|
|
61
|
+
field=models.ForeignKey(
|
|
62
|
+
default=pulpcore.app.util.get_domain_pk,
|
|
63
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
64
|
+
to="core.domain",
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
migrations.AddField(
|
|
68
|
+
model_name="collectionversionmark",
|
|
69
|
+
name="_pulp_domain",
|
|
70
|
+
field=models.ForeignKey(
|
|
71
|
+
default=pulpcore.app.util.get_domain_pk,
|
|
72
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
73
|
+
to="core.domain",
|
|
74
|
+
),
|
|
75
|
+
),
|
|
76
|
+
migrations.AddField(
|
|
77
|
+
model_name="collectionversionsignature",
|
|
78
|
+
name="_pulp_domain",
|
|
79
|
+
field=models.ForeignKey(
|
|
80
|
+
default=pulpcore.app.util.get_domain_pk,
|
|
81
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
82
|
+
to="core.domain",
|
|
83
|
+
),
|
|
84
|
+
),
|
|
85
|
+
migrations.AddField(
|
|
86
|
+
model_name="role",
|
|
87
|
+
name="_pulp_domain",
|
|
88
|
+
field=models.ForeignKey(
|
|
89
|
+
default=pulpcore.app.util.get_domain_pk,
|
|
90
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
91
|
+
to="core.domain",
|
|
92
|
+
),
|
|
93
|
+
),
|
|
94
|
+
migrations.AlterUniqueTogether(
|
|
95
|
+
name="ansiblecollectiondeprecated",
|
|
96
|
+
unique_together={("namespace", "name", "_pulp_domain")},
|
|
97
|
+
),
|
|
98
|
+
migrations.AlterUniqueTogether(
|
|
99
|
+
name="ansiblenamespacemetadata",
|
|
100
|
+
unique_together={("metadata_sha256", "_pulp_domain")},
|
|
101
|
+
),
|
|
102
|
+
migrations.AlterUniqueTogether(
|
|
103
|
+
name="collectionversion",
|
|
104
|
+
unique_together={("sha256", "_pulp_domain")},
|
|
105
|
+
),
|
|
106
|
+
migrations.AlterUniqueTogether(
|
|
107
|
+
name="collectionversionmark",
|
|
108
|
+
unique_together={("value", "marked_collection", "_pulp_domain")},
|
|
109
|
+
),
|
|
110
|
+
migrations.AlterUniqueTogether(
|
|
111
|
+
name="collectionversionsignature",
|
|
112
|
+
unique_together={("pubkey_fingerprint", "signed_collection", "_pulp_domain")},
|
|
113
|
+
),
|
|
114
|
+
migrations.AlterUniqueTogether(
|
|
115
|
+
name="role",
|
|
116
|
+
unique_together={("version", "name", "namespace", "_pulp_domain")},
|
|
117
|
+
),
|
|
118
|
+
]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Generated by Django 4.2.22 on 2025-07-01 14:04
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
import django.db.models.deletion
|
|
5
|
+
import pulpcore.app.util
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
("core", "0123_upstreampulp_q_select"),
|
|
12
|
+
("ansible", "0063_domain_support"),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.AlterUniqueTogether(
|
|
17
|
+
name="collection",
|
|
18
|
+
unique_together=set(),
|
|
19
|
+
),
|
|
20
|
+
migrations.AlterUniqueTogether(
|
|
21
|
+
name="collectiondownloadcount",
|
|
22
|
+
unique_together=set(),
|
|
23
|
+
),
|
|
24
|
+
migrations.AddField(
|
|
25
|
+
model_name="ansiblenamespace",
|
|
26
|
+
name="pulp_domain",
|
|
27
|
+
field=models.ForeignKey(
|
|
28
|
+
default=pulpcore.app.util.get_domain_pk,
|
|
29
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
30
|
+
to="core.domain",
|
|
31
|
+
),
|
|
32
|
+
),
|
|
33
|
+
migrations.AddField(
|
|
34
|
+
model_name="collection",
|
|
35
|
+
name="pulp_domain",
|
|
36
|
+
field=models.ForeignKey(
|
|
37
|
+
default=pulpcore.app.util.get_domain_pk,
|
|
38
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
39
|
+
to="core.domain",
|
|
40
|
+
),
|
|
41
|
+
),
|
|
42
|
+
migrations.AddField(
|
|
43
|
+
model_name="collectiondownloadcount",
|
|
44
|
+
name="pulp_domain",
|
|
45
|
+
field=models.ForeignKey(
|
|
46
|
+
default=pulpcore.app.util.get_domain_pk,
|
|
47
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
48
|
+
to="core.domain",
|
|
49
|
+
),
|
|
50
|
+
),
|
|
51
|
+
migrations.AlterField(
|
|
52
|
+
model_name="ansiblenamespace",
|
|
53
|
+
name="name",
|
|
54
|
+
field=models.CharField(max_length=64),
|
|
55
|
+
),
|
|
56
|
+
migrations.AlterUniqueTogether(
|
|
57
|
+
name="ansiblenamespace",
|
|
58
|
+
unique_together={("pulp_domain", "name")},
|
|
59
|
+
),
|
|
60
|
+
migrations.AlterUniqueTogether(
|
|
61
|
+
name="collection",
|
|
62
|
+
unique_together={("pulp_domain", "namespace", "name")},
|
|
63
|
+
),
|
|
64
|
+
migrations.AlterUniqueTogether(
|
|
65
|
+
name="collectiondownloadcount",
|
|
66
|
+
unique_together={("pulp_domain", "namespace", "name")},
|
|
67
|
+
),
|
|
68
|
+
]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
|
|
3
3
|
from import_export import fields
|
|
4
|
-
from import_export.widgets import
|
|
4
|
+
from import_export.widgets import Widget
|
|
5
5
|
from pulpcore.plugin.importexport import BaseContentResource, QueryModelResource
|
|
6
6
|
from pulp_ansible.app.models import (
|
|
7
7
|
AnsibleCollectionDeprecated,
|
|
@@ -10,7 +10,6 @@ from pulp_ansible.app.models import (
|
|
|
10
10
|
CollectionVersionMark,
|
|
11
11
|
Role,
|
|
12
12
|
Collection,
|
|
13
|
-
Tag,
|
|
14
13
|
CollectionVersion,
|
|
15
14
|
CollectionVersionSignature,
|
|
16
15
|
)
|
|
@@ -99,10 +98,6 @@ class CollectionVersionContentResource(BaseContentResource):
|
|
|
99
98
|
Resource for import/export of ansible_collectionversion-content entities.
|
|
100
99
|
"""
|
|
101
100
|
|
|
102
|
-
tags = fields.Field(
|
|
103
|
-
column_name="tags", attribute="tags", widget=ManyToManyWidget(Tag, field="name")
|
|
104
|
-
)
|
|
105
|
-
|
|
106
101
|
def before_import_row(self, row, **kwargs):
|
|
107
102
|
"""
|
|
108
103
|
Finds and sets collection using name and namespace.
|
|
@@ -222,29 +217,11 @@ class CollectionDeprecationResource(BaseContentResource):
|
|
|
222
217
|
import_id_fields = ("namespace", "name")
|
|
223
218
|
|
|
224
219
|
|
|
225
|
-
class TagResource(QueryModelResource):
|
|
226
|
-
"""
|
|
227
|
-
Resource for import/export of ansible_tag entities.
|
|
228
|
-
"""
|
|
229
|
-
|
|
230
|
-
def set_up_queryset(self):
|
|
231
|
-
"""
|
|
232
|
-
:return: Tags specific to a specified repo-version.
|
|
233
|
-
"""
|
|
234
|
-
collection_versions = CollectionVersion.objects.filter(pk__in=self.repo_version.content)
|
|
235
|
-
return Tag.objects.filter(pk__in=collection_versions.values_list("tags", flat=True))
|
|
236
|
-
|
|
237
|
-
class Meta:
|
|
238
|
-
model = Tag
|
|
239
|
-
import_id_fields = ("name",)
|
|
240
|
-
|
|
241
|
-
|
|
242
220
|
IMPORT_ORDER = [
|
|
243
221
|
AnsibleNamespaceResource,
|
|
244
222
|
AnsibleNamespaceMetadataResource,
|
|
245
223
|
CollectionResource,
|
|
246
224
|
CollectionDeprecationResource,
|
|
247
|
-
TagResource,
|
|
248
225
|
CollectionVersionContentResource,
|
|
249
226
|
CollectionVersionMarkResource,
|
|
250
227
|
CollectionVersionSignatureResource,
|