nautobot 2.4.5__py3-none-any.whl → 2.4.6__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.
- nautobot/core/api/mixins.py +10 -0
- nautobot/core/celery/encoders.py +2 -2
- nautobot/core/forms/fields.py +21 -5
- nautobot/core/forms/utils.py +1 -0
- nautobot/core/jobs/bulk_actions.py +1 -1
- nautobot/core/management/commands/generate_test_data.py +1 -1
- nautobot/core/models/name_color_content_types.py +9 -0
- nautobot/core/models/validators.py +7 -0
- nautobot/core/settings.py +0 -14
- nautobot/core/settings.yaml +0 -28
- nautobot/core/tables.py +6 -1
- nautobot/core/templates/generic/object_retrieve.html +1 -1
- nautobot/core/testing/api.py +18 -0
- nautobot/core/tests/nautobot_config.py +0 -2
- nautobot/core/tests/runner.py +17 -140
- nautobot/core/tests/test_api.py +4 -4
- nautobot/core/tests/test_authentication.py +83 -4
- nautobot/core/tests/test_forms.py +11 -8
- nautobot/core/tests/test_graphql.py +9 -0
- nautobot/core/tests/test_jobs.py +7 -0
- nautobot/core/ui/object_detail.py +31 -0
- nautobot/dcim/factory.py +2 -0
- nautobot/dcim/filters/__init__.py +5 -0
- nautobot/dcim/forms.py +17 -1
- nautobot/dcim/migrations/0068_alter_softwareimagefile_download_url.py +19 -0
- nautobot/dcim/migrations/0069_softwareimagefile_external_integration.py +25 -0
- nautobot/dcim/models/devices.py +9 -2
- nautobot/dcim/tables/devices.py +1 -0
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +4 -0
- nautobot/dcim/tests/test_api.py +74 -31
- nautobot/dcim/tests/test_filters.py +2 -0
- nautobot/dcim/tests/test_models.py +65 -0
- nautobot/dcim/tests/test_views.py +3 -0
- nautobot/extras/forms/forms.py +7 -3
- nautobot/extras/plugins/marketplace_manifest.yml +18 -0
- nautobot/extras/tables.py +4 -5
- nautobot/extras/templates/extras/inc/panel_changelog.html +1 -1
- nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
- nautobot/extras/templates/extras/status.html +1 -37
- nautobot/extras/tests/integration/test_notes.py +1 -1
- nautobot/extras/tests/test_api.py +22 -7
- nautobot/extras/tests/test_changelog.py +4 -4
- nautobot/extras/tests/test_customfields.py +3 -0
- nautobot/extras/tests/test_plugins.py +19 -13
- nautobot/extras/tests/test_relationships.py +9 -0
- nautobot/extras/tests/test_tags.py +2 -2
- nautobot/extras/tests/test_views.py +15 -6
- nautobot/extras/urls.py +1 -30
- nautobot/extras/views.py +10 -54
- nautobot/ipam/tables.py +6 -2
- nautobot/ipam/templates/ipam/namespace_retrieve.html +0 -41
- nautobot/ipam/templates/ipam/service.html +2 -46
- nautobot/ipam/templates/ipam/service_edit.html +1 -17
- nautobot/ipam/templates/ipam/service_retrieve.html +7 -0
- nautobot/ipam/tests/migration/__init__.py +0 -0
- nautobot/ipam/tests/migration/test_migrations.py +510 -0
- nautobot/ipam/tests/test_api.py +66 -36
- nautobot/ipam/tests/test_filters.py +0 -10
- nautobot/ipam/tests/test_views.py +44 -2
- nautobot/ipam/urls.py +2 -47
- nautobot/ipam/utils/migrations.py +185 -152
- nautobot/ipam/utils/testing.py +177 -0
- nautobot/ipam/views.py +95 -157
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +47 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +18 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +63 -0
- nautobot/project-static/docs/development/apps/api/testing.html +0 -87
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +1 -1
- nautobot/project-static/docs/development/core/best-practices.html +3 -3
- nautobot/project-static/docs/development/core/getting-started.html +78 -107
- nautobot/project-static/docs/development/core/release-checklist.html +1 -1
- nautobot/project-static/docs/development/core/style-guide.html +1 -1
- nautobot/project-static/docs/development/core/testing.html +24 -198
- nautobot/project-static/docs/media/user-guide/administration/getting-started/nautobot-cloud.png +0 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +1 -1
- nautobot/project-static/docs/release-notes/version-2.4.html +226 -1
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +290 -290
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +2 -48
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +71 -0
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +3 -1
- nautobot/project-static/docs/user-guide/administration/installation/index.html +257 -16
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +1 -1
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +2 -2
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +4 -0
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +8 -8
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +1 -0
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +40 -25
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +4 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +1 -1
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +77 -5
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +1 -1
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +0 -1
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +1 -1
- nautobot/project-static/docs/user-guide/index.html +89 -2
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +207 -122
- nautobot/virtualization/forms.py +20 -0
- nautobot/virtualization/templates/virtualization/clustergroup.html +1 -39
- nautobot/virtualization/templates/virtualization/clustertype.html +1 -0
- nautobot/virtualization/tests/test_api.py +14 -3
- nautobot/virtualization/tests/test_views.py +10 -2
- nautobot/virtualization/urls.py +10 -93
- nautobot/virtualization/views.py +33 -72
- {nautobot-2.4.5.dist-info → nautobot-2.4.6.dist-info}/METADATA +6 -5
- {nautobot-2.4.5.dist-info → nautobot-2.4.6.dist-info}/RECORD +113 -108
- {nautobot-2.4.5.dist-info → nautobot-2.4.6.dist-info}/WHEEL +1 -1
- nautobot/core/tests/performance_baselines.yml +0 -8900
- nautobot/ipam/tests/test_migrations.py +0 -462
- /nautobot/ipam/templates/ipam/{namespace_ipaddresses.html → namespace_ip_addresses.html} +0 -0
- {nautobot-2.4.5.dist-info → nautobot-2.4.6.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.5.dist-info → nautobot-2.4.6.dist-info}/NOTICE +0 -0
- {nautobot-2.4.5.dist-info → nautobot-2.4.6.dist-info}/entry_points.txt +0 -0
|
@@ -1,462 +0,0 @@
|
|
|
1
|
-
from unittest import skip, skipIf
|
|
2
|
-
import uuid
|
|
3
|
-
|
|
4
|
-
from django.db import connection
|
|
5
|
-
|
|
6
|
-
from nautobot.core.models.fields import TagsField
|
|
7
|
-
from nautobot.core.models.utils import serialize_object
|
|
8
|
-
from nautobot.core.testing.migrations import NautobotDataMigrationTest
|
|
9
|
-
from nautobot.extras import choices as extras_choices
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@skip("test skipped until base test can be fixed to handle new migrations")
|
|
13
|
-
class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
|
|
14
|
-
"""Test data migrations removing the Aggregate model and replacing with Prefix in v2.0"""
|
|
15
|
-
|
|
16
|
-
migrate_from = [("ipam", "0021_prefix_add_rir_and_date_allocated")]
|
|
17
|
-
migrate_to = [("ipam", "0022_aggregate_to_prefix_data_migration")]
|
|
18
|
-
|
|
19
|
-
def _create_objectchange(self, instance, change_context_detail):
|
|
20
|
-
instance.refresh_from_db()
|
|
21
|
-
return self.object_change.objects.create(
|
|
22
|
-
action=extras_choices.ObjectChangeActionChoices.ACTION_UPDATE,
|
|
23
|
-
change_context=extras_choices.ObjectChangeEventContextChoices.CONTEXT_ORM,
|
|
24
|
-
change_context_detail=change_context_detail,
|
|
25
|
-
changed_object_id=instance.pk,
|
|
26
|
-
changed_object_type=self.content_type.objects.get_for_model(instance.__class__),
|
|
27
|
-
object_data=serialize_object(instance),
|
|
28
|
-
object_repr="",
|
|
29
|
-
request_id=uuid.uuid4(),
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
def populateDataBeforeMigration(self, installed_apps):
|
|
33
|
-
"""Populate Aggregate data before migrating to Prefixes"""
|
|
34
|
-
|
|
35
|
-
self.aggregate = installed_apps.get_model("ipam", "Aggregate")
|
|
36
|
-
# Workaround for django-taggit manager not working in migrations.
|
|
37
|
-
# https://github.com/jazzband/django-taggit/issues/101
|
|
38
|
-
# https://github.com/jazzband/django-taggit/issues/454
|
|
39
|
-
self.aggregate.tags = TagsField()
|
|
40
|
-
self.computed_field = installed_apps.get_model("extras", "computedfield")
|
|
41
|
-
self.content_type = installed_apps.get_model("contenttypes", "ContentType")
|
|
42
|
-
self.custom_field = installed_apps.get_model("extras", "customfield")
|
|
43
|
-
self.custom_link = installed_apps.get_model("extras", "customlink")
|
|
44
|
-
self.dynamic_group = installed_apps.get_model("extras", "DynamicGroup")
|
|
45
|
-
self.note = installed_apps.get_model("extras", "note")
|
|
46
|
-
self.object_change = installed_apps.get_model("extras", "objectchange")
|
|
47
|
-
self.object_permission = installed_apps.get_model("users", "objectpermission")
|
|
48
|
-
self.prefix = installed_apps.get_model("ipam", "prefix")
|
|
49
|
-
self.prefix.tags = TagsField()
|
|
50
|
-
self.relationship = installed_apps.get_model("extras", "relationship")
|
|
51
|
-
self.relationship_association = installed_apps.get_model("extras", "relationshipassociation")
|
|
52
|
-
self.rir = installed_apps.get_model("ipam", "RIR")
|
|
53
|
-
self.status = installed_apps.get_model("extras", "status")
|
|
54
|
-
self.tag = installed_apps.get_model("extras", "tag")
|
|
55
|
-
|
|
56
|
-
self.aggregate_ct = self.content_type.objects.get_for_model(self.aggregate)
|
|
57
|
-
self.prefix_ct = self.content_type.objects.get_for_model(self.prefix)
|
|
58
|
-
|
|
59
|
-
self.prefix_status = self.status.objects.create(name="Active")
|
|
60
|
-
self.prefix_status.content_types.add(self.prefix_ct)
|
|
61
|
-
|
|
62
|
-
self.rir1 = self.rir.objects.create(name="RFC1918", is_private=True)
|
|
63
|
-
self.rir2 = self.rir.objects.create(name="ARIN")
|
|
64
|
-
|
|
65
|
-
# Create 4 prefixes that will be merged into by Aggregates with duplicate network/prefix_length
|
|
66
|
-
self.prefix1 = self.prefix.objects.create(
|
|
67
|
-
network="10.1.0.0", prefix_length=24, status=self.prefix_status, description="PrefixDesc"
|
|
68
|
-
)
|
|
69
|
-
self.prefix2 = self.prefix.objects.create(
|
|
70
|
-
network="10.2.0.0", prefix_length=25, status=self.prefix_status, description="PrefixDesc"
|
|
71
|
-
)
|
|
72
|
-
self.prefix3 = self.prefix.objects.create(network="10.3.0.0", prefix_length=26, status=self.prefix_status)
|
|
73
|
-
self.prefix4 = self.prefix.objects.create(network="10.4.0.0", prefix_length=27, status=self.prefix_status)
|
|
74
|
-
self.aggregate1 = self.aggregate.objects.create(network="10.1.0.0", rir=self.rir1, prefix_length=24)
|
|
75
|
-
self.aggregate2 = self.aggregate.objects.create(network="10.2.0.0", rir=self.rir1, prefix_length=25)
|
|
76
|
-
self.aggregate3 = self.aggregate.objects.create(
|
|
77
|
-
network="10.3.0.0", rir=self.rir1, prefix_length=26, description="AggregateDesc"
|
|
78
|
-
)
|
|
79
|
-
self.aggregate4 = self.aggregate.objects.create(
|
|
80
|
-
network="10.4.0.0", rir=self.rir1, prefix_length=27, description="AggregateDesc"
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
# Create 8 prefixes that are not duplicated by Aggregates and will not be touched by migration
|
|
84
|
-
# self.prefix5(10.5.0.0)
|
|
85
|
-
# ...
|
|
86
|
-
# self.prefix12(10.12.0.0)
|
|
87
|
-
for i in range(8):
|
|
88
|
-
prefix = self.prefix.objects.create(network=f"10.{i+5}.0.0", prefix_length=28, status=self.prefix_status)
|
|
89
|
-
setattr(self, f"prefix{i+5}", prefix)
|
|
90
|
-
|
|
91
|
-
# Create 16 aggregates that will be migrated to new Prefixes
|
|
92
|
-
# self.aggregate5(8.5.0.0)
|
|
93
|
-
# ...
|
|
94
|
-
# self.aggregate20(8.20.0.0)
|
|
95
|
-
for i in range(16):
|
|
96
|
-
aggregate = self.aggregate.objects.create(
|
|
97
|
-
network=f"8.{i+5}.0.0", rir=self.rir2, prefix_length=29, description="AggregateDesc"
|
|
98
|
-
)
|
|
99
|
-
setattr(self, f"aggregate{i+5}", aggregate)
|
|
100
|
-
|
|
101
|
-
# tags
|
|
102
|
-
self.prefix_tag_a = self.tag.objects.create(name="PrefixTagA")
|
|
103
|
-
self.prefix_tag_b = self.tag.objects.create(name="PrefixTagB")
|
|
104
|
-
self.prefix_tag_a.content_types.add(self.prefix_ct)
|
|
105
|
-
self.prefix_tag_b.content_types.add(self.prefix_ct)
|
|
106
|
-
self.aggregate_tag_a = self.tag.objects.create(name="AggregateTagA")
|
|
107
|
-
self.aggregate_tag_b = self.tag.objects.create(name="AggregateTagB")
|
|
108
|
-
self.aggregate_tag_a.content_types.add(self.aggregate_ct)
|
|
109
|
-
self.aggregate_tag_b.content_types.add(self.aggregate_ct)
|
|
110
|
-
self.prefix1.tags.add("PrefixTagA")
|
|
111
|
-
self.prefix2.tags.add("PrefixTagA")
|
|
112
|
-
self.prefix3.tags.add("PrefixTagA")
|
|
113
|
-
self.prefix4.tags.add("PrefixTagA")
|
|
114
|
-
self.aggregate1.tags.add("AggregateTagA", "AggregateTagB")
|
|
115
|
-
self.aggregate2.tags.add("AggregateTagA")
|
|
116
|
-
self.aggregate3.tags.add("AggregateTagB")
|
|
117
|
-
self.aggregate5.tags.add("AggregateTagA", "AggregateTagB") # pylint: disable=no-member
|
|
118
|
-
self.aggregate6.tags.add("AggregateTagB") # pylint: disable=no-member
|
|
119
|
-
|
|
120
|
-
# notes
|
|
121
|
-
self.note.objects.create(
|
|
122
|
-
note="Prefix1 test note",
|
|
123
|
-
assigned_object_type=self.prefix_ct,
|
|
124
|
-
assigned_object_id=self.prefix1.id,
|
|
125
|
-
)
|
|
126
|
-
self.note.objects.create(
|
|
127
|
-
note="Prefix2 test note",
|
|
128
|
-
assigned_object_type=self.prefix_ct,
|
|
129
|
-
assigned_object_id=self.prefix2.id,
|
|
130
|
-
)
|
|
131
|
-
self.note.objects.create(
|
|
132
|
-
note="Aggregate1 test note",
|
|
133
|
-
assigned_object_type=self.aggregate_ct,
|
|
134
|
-
assigned_object_id=self.aggregate1.id,
|
|
135
|
-
)
|
|
136
|
-
self.note.objects.create(
|
|
137
|
-
note="Aggregate3 test note",
|
|
138
|
-
assigned_object_type=self.aggregate_ct,
|
|
139
|
-
assigned_object_id=self.aggregate3.id,
|
|
140
|
-
)
|
|
141
|
-
self.note.objects.create(
|
|
142
|
-
note="Aggregate5 test note",
|
|
143
|
-
assigned_object_type=self.aggregate_ct,
|
|
144
|
-
assigned_object_id=self.aggregate5.id, # pylint: disable=no-member
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
# object permissions
|
|
148
|
-
object_permission1 = self.object_permission.objects.create(
|
|
149
|
-
name="Aggregate permission 1", actions=["view", "add", "change", "delete"]
|
|
150
|
-
)
|
|
151
|
-
object_permission2 = self.object_permission.objects.create(
|
|
152
|
-
name="Aggregate permission 2", actions=["add", "delete"], enabled=False
|
|
153
|
-
)
|
|
154
|
-
object_permission1.object_types.add(self.aggregate_ct)
|
|
155
|
-
object_permission2.object_types.add(self.aggregate_ct)
|
|
156
|
-
|
|
157
|
-
# object changes
|
|
158
|
-
self._create_objectchange(self.prefix1, "Pre-migration object change for prefix1")
|
|
159
|
-
self._create_objectchange(self.prefix4, "Pre-migration object change for prefix4")
|
|
160
|
-
self._create_objectchange(self.prefix5, "Pre-migration object change for prefix5") # pylint: disable=no-member
|
|
161
|
-
self._create_objectchange(self.aggregate5, "Pre-migration object change for aggregate5") # pylint: disable=no-member
|
|
162
|
-
|
|
163
|
-
# custom fields
|
|
164
|
-
prefix_cf1 = self.custom_field.objects.create(name="prefixcf1")
|
|
165
|
-
prefix_cf1.content_types.add(self.prefix_ct)
|
|
166
|
-
aggregate_cf1 = self.custom_field.objects.create(name="aggregatecf1")
|
|
167
|
-
aggregate_cf1.content_types.add(self.aggregate_ct)
|
|
168
|
-
prefixaggregate_cf1 = self.custom_field.objects.create(name="prefixaggregatecf1")
|
|
169
|
-
prefixaggregate_cf1.content_types.add(self.aggregate_ct, self.prefix_ct)
|
|
170
|
-
|
|
171
|
-
self.prefix1._custom_field_data["prefixcf1"] = "testdata prefixcf1 prefix1"
|
|
172
|
-
self.prefix1._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 prefix1"
|
|
173
|
-
self.aggregate1._custom_field_data["aggregatecf1"] = "testdata aggregatecf1 aggregate1"
|
|
174
|
-
|
|
175
|
-
self.prefix2._custom_field_data["prefixcf1"] = "testdata prefixcf1 prefix2"
|
|
176
|
-
self.prefix2._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 prefix2"
|
|
177
|
-
self.aggregate2._custom_field_data["aggregatecf1"] = "testdata aggregatecf1 aggregate2"
|
|
178
|
-
self.aggregate2._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 aggregate2"
|
|
179
|
-
|
|
180
|
-
self.aggregate3._custom_field_data["aggregatecf1"] = "testdata aggregatecf1 aggregate3"
|
|
181
|
-
|
|
182
|
-
self.prefix5._custom_field_data["prefixcf1"] = "testdata prefixcf1 prefix5" # pylint: disable=no-member
|
|
183
|
-
self.prefix5._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 prefix5" # pylint: disable=no-member
|
|
184
|
-
|
|
185
|
-
self.aggregate5._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 aggregate5" # pylint: disable=no-member
|
|
186
|
-
self.aggregate5._custom_field_data["aggregatecf1"] = "testdata aggregatecf1 aggregate5" # pylint: disable=no-member
|
|
187
|
-
|
|
188
|
-
self.aggregate6._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 aggregate6" # pylint: disable=no-member
|
|
189
|
-
|
|
190
|
-
self.prefix1.save()
|
|
191
|
-
self.prefix2.save()
|
|
192
|
-
self.prefix3.save()
|
|
193
|
-
self.prefix4.save()
|
|
194
|
-
self.prefix5.save() # pylint: disable=no-member
|
|
195
|
-
self.aggregate1.save()
|
|
196
|
-
self.aggregate2.save()
|
|
197
|
-
self.aggregate3.save()
|
|
198
|
-
self.aggregate5.save() # pylint: disable=no-member
|
|
199
|
-
self.aggregate6.save() # pylint: disable=no-member
|
|
200
|
-
|
|
201
|
-
@skipIf(
|
|
202
|
-
connection.vendor != "postgresql",
|
|
203
|
-
"mysql does not support rollbacks",
|
|
204
|
-
)
|
|
205
|
-
def test_aggregate_to_prefix_migration_object_count(self):
|
|
206
|
-
with self.subTest("Test Prefix count"):
|
|
207
|
-
self.assertEqual(self.prefix.objects.count(), 28)
|
|
208
|
-
with self.subTest("Test Aggregate count"):
|
|
209
|
-
self.assertEqual(self.aggregate.objects.count(), 20)
|
|
210
|
-
|
|
211
|
-
@skipIf(
|
|
212
|
-
connection.vendor != "postgresql",
|
|
213
|
-
"mysql does not support rollbacks",
|
|
214
|
-
)
|
|
215
|
-
def test_aggregate_to_prefix_migration_network(self):
|
|
216
|
-
for i in range(16):
|
|
217
|
-
self.assertTrue(
|
|
218
|
-
self.prefix.objects.filter(network=f"8.{i+5}.0.0", prefix_length=29, rir=self.rir2).exists()
|
|
219
|
-
)
|
|
220
|
-
|
|
221
|
-
@skipIf(
|
|
222
|
-
connection.vendor != "postgresql",
|
|
223
|
-
"mysql does not support rollbacks",
|
|
224
|
-
)
|
|
225
|
-
def test_aggregate_to_prefix_migration_rir(self):
|
|
226
|
-
with self.subTest(f"prefix.rir = {self.rir1.name}"):
|
|
227
|
-
self.assertEqual(self.prefix.objects.get(network="10.1.0.0").rir, self.rir1)
|
|
228
|
-
self.assertEqual(self.prefix.objects.get(network="10.2.0.0").rir, self.rir1)
|
|
229
|
-
self.assertEqual(self.prefix.objects.get(network="10.3.0.0").rir, self.rir1)
|
|
230
|
-
self.assertEqual(self.prefix.objects.get(network="10.4.0.0").rir, self.rir1)
|
|
231
|
-
with self.subTest(f"prefix.rir = {self.rir2.name}"):
|
|
232
|
-
for i in range(16):
|
|
233
|
-
prefix = self.prefix.objects.get(network=f"8.{i+5}.0.0")
|
|
234
|
-
self.assertEqual(prefix.rir, self.rir2)
|
|
235
|
-
with self.subTest("prefix.rir is None"):
|
|
236
|
-
for i in range(8):
|
|
237
|
-
prefix = self.prefix.objects.get(network=f"10.{i+5}.0.0")
|
|
238
|
-
self.assertIsNone(prefix.rir)
|
|
239
|
-
|
|
240
|
-
@skipIf(
|
|
241
|
-
connection.vendor != "postgresql",
|
|
242
|
-
"mysql does not support rollbacks",
|
|
243
|
-
)
|
|
244
|
-
def test_aggregate_to_prefix_migration_description(self):
|
|
245
|
-
self.assertEqual(self.prefix.objects.filter(description="PrefixDesc").count(), 2)
|
|
246
|
-
self.assertEqual(self.prefix.objects.filter(description="").count(), 10)
|
|
247
|
-
self.assertEqual(self.prefix.objects.filter(description="AggregateDesc").count(), 16)
|
|
248
|
-
|
|
249
|
-
@skipIf(
|
|
250
|
-
connection.vendor != "postgresql",
|
|
251
|
-
"mysql does not support rollbacks",
|
|
252
|
-
)
|
|
253
|
-
def test_aggregate_to_prefix_migration_status(self):
|
|
254
|
-
self.assertEqual(self.prefix.objects.filter(status=self.prefix_status).count(), self.prefix.objects.count())
|
|
255
|
-
|
|
256
|
-
@skipIf(
|
|
257
|
-
connection.vendor != "postgresql",
|
|
258
|
-
"mysql does not support rollbacks",
|
|
259
|
-
)
|
|
260
|
-
def test_aggregate_to_prefix_migration_tags(self):
|
|
261
|
-
with self.subTest("Prefix content type was added to Aggregate Tags"):
|
|
262
|
-
prefix_tags = self.tag.objects.filter(content_types=self.prefix_ct)
|
|
263
|
-
self.assertIn(self.aggregate_tag_a, prefix_tags)
|
|
264
|
-
self.assertIn(self.aggregate_tag_b, prefix_tags)
|
|
265
|
-
|
|
266
|
-
# assert that tags were migrated to new prefix instances
|
|
267
|
-
# compare list of PKs since tag managers don't work in migrations
|
|
268
|
-
self.assertCountEqual(
|
|
269
|
-
self.prefix.objects.get(network="10.1.0.0").tags.values_list("id", flat=True),
|
|
270
|
-
self.tag.objects.filter(name__in=["PrefixTagA", "AggregateTagA", "AggregateTagB"]).values_list(
|
|
271
|
-
"id", flat=True
|
|
272
|
-
),
|
|
273
|
-
)
|
|
274
|
-
self.assertCountEqual(
|
|
275
|
-
self.prefix.objects.get(network="10.2.0.0").tags.values_list("id", flat=True),
|
|
276
|
-
self.tag.objects.filter(name__in=["PrefixTagA", "AggregateTagA"]).values_list("id", flat=True),
|
|
277
|
-
)
|
|
278
|
-
self.assertCountEqual(
|
|
279
|
-
self.prefix.objects.get(network="10.3.0.0").tags.values_list("id", flat=True),
|
|
280
|
-
self.tag.objects.filter(name__in=["PrefixTagA", "AggregateTagB"]).values_list("id", flat=True),
|
|
281
|
-
)
|
|
282
|
-
self.assertCountEqual(
|
|
283
|
-
self.prefix.objects.get(network="10.4.0.0").tags.values_list("id", flat=True),
|
|
284
|
-
self.tag.objects.filter(name="PrefixTagA").values_list("id", flat=True),
|
|
285
|
-
)
|
|
286
|
-
self.assertCountEqual(
|
|
287
|
-
self.prefix.objects.get(network="8.5.0.0").tags.values_list("id", flat=True),
|
|
288
|
-
self.tag.objects.filter(name__in=["AggregateTagA", "AggregateTagB"]).values_list("id", flat=True),
|
|
289
|
-
)
|
|
290
|
-
self.assertCountEqual(
|
|
291
|
-
self.prefix.objects.get(network="8.6.0.0").tags.values_list("id", flat=True),
|
|
292
|
-
self.tag.objects.filter(name="AggregateTagB").values_list("id", flat=True),
|
|
293
|
-
)
|
|
294
|
-
for i in range(7, 21):
|
|
295
|
-
prefix = self.prefix.objects.get(network=f"8.{i}.0.0")
|
|
296
|
-
self.assertCountEqual(prefix.tags.values_list("id", flat=True), [])
|
|
297
|
-
|
|
298
|
-
@skipIf(
|
|
299
|
-
connection.vendor != "postgresql",
|
|
300
|
-
"mysql does not support rollbacks",
|
|
301
|
-
)
|
|
302
|
-
def test_aggregate_to_prefix_migration_notes(self):
|
|
303
|
-
# no notes are assigned to aggregates
|
|
304
|
-
self.assertQuerysetEqual(
|
|
305
|
-
self.note.objects.filter(assigned_object_type=self.aggregate_ct), self.note.objects.none()
|
|
306
|
-
)
|
|
307
|
-
# no extra notes were created
|
|
308
|
-
self.assertEqual(self.note.objects.count(), 5)
|
|
309
|
-
|
|
310
|
-
# aggregate1 note added on top of existing note on prefix1
|
|
311
|
-
self.assertQuerysetEqual(
|
|
312
|
-
self.note.objects.filter(assigned_object_type=self.prefix_ct, assigned_object_id=self.prefix1.id),
|
|
313
|
-
self.note.objects.filter(note__in=["Prefix1 test note", "Aggregate1 test note"]),
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
# prefix2 note was unchanged
|
|
317
|
-
self.assertQuerysetEqual(
|
|
318
|
-
self.note.objects.filter(assigned_object_type=self.prefix_ct, assigned_object_id=self.prefix2.id),
|
|
319
|
-
self.note.objects.filter(note="Prefix2 test note"),
|
|
320
|
-
)
|
|
321
|
-
|
|
322
|
-
# aggregate3 note was migrated to prefix3
|
|
323
|
-
self.assertQuerysetEqual(
|
|
324
|
-
self.note.objects.filter(assigned_object_type=self.prefix_ct, assigned_object_id=self.prefix3.id),
|
|
325
|
-
self.note.objects.filter(note="Aggregate3 test note"),
|
|
326
|
-
)
|
|
327
|
-
|
|
328
|
-
# no notes for prefix4
|
|
329
|
-
self.assertQuerysetEqual(
|
|
330
|
-
self.note.objects.filter(assigned_object_type=self.prefix_ct, assigned_object_id=self.prefix4.id),
|
|
331
|
-
self.note.objects.none(),
|
|
332
|
-
)
|
|
333
|
-
|
|
334
|
-
# aggregate5 note was migrated to new prefix object
|
|
335
|
-
aggregate5_migrated_prefix = self.prefix.objects.get(network="8.5.0.0")
|
|
336
|
-
self.assertQuerysetEqual(
|
|
337
|
-
self.note.objects.filter(
|
|
338
|
-
assigned_object_type=self.prefix_ct,
|
|
339
|
-
assigned_object_id=aggregate5_migrated_prefix.id,
|
|
340
|
-
),
|
|
341
|
-
self.note.objects.filter(note="Aggregate5 test note"),
|
|
342
|
-
)
|
|
343
|
-
|
|
344
|
-
# no other notes are related to remaining prefixes
|
|
345
|
-
for i in range(5, 13):
|
|
346
|
-
prefix = self.prefix.objects.get(network=f"10.{i}.0.0")
|
|
347
|
-
self.assertQuerysetEqual(
|
|
348
|
-
self.note.objects.filter(assigned_object_type=self.prefix_ct, assigned_object_id=prefix.id),
|
|
349
|
-
self.note.objects.none(),
|
|
350
|
-
)
|
|
351
|
-
for i in range(6, 21):
|
|
352
|
-
prefix = self.prefix.objects.get(network=f"8.{i}.0.0")
|
|
353
|
-
self.assertQuerysetEqual(
|
|
354
|
-
self.note.objects.filter(assigned_object_type=self.prefix_ct, assigned_object_id=prefix.id),
|
|
355
|
-
self.note.objects.none(),
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
@skipIf(
|
|
359
|
-
connection.vendor != "postgresql",
|
|
360
|
-
"mysql does not support rollbacks",
|
|
361
|
-
)
|
|
362
|
-
def test_aggregate_to_prefix_migration_permissions(self):
|
|
363
|
-
self.assertEqual(self.object_permission.objects.count(), 2)
|
|
364
|
-
|
|
365
|
-
# assert prefix content type was added to object permission 1
|
|
366
|
-
object_permission1 = self.object_permission.objects.filter(
|
|
367
|
-
name="Aggregate permission 1", actions=["view", "add", "change", "delete"]
|
|
368
|
-
)
|
|
369
|
-
self.assertTrue(object_permission1.exists())
|
|
370
|
-
self.assertTrue(object_permission1.first().object_types.filter(id=self.prefix_ct.id).exists())
|
|
371
|
-
|
|
372
|
-
# assert prefix content type was added to object permission 2
|
|
373
|
-
object_permission2 = self.object_permission.objects.filter(
|
|
374
|
-
name="Aggregate permission 2", actions=["add", "delete"], enabled=False
|
|
375
|
-
)
|
|
376
|
-
self.assertTrue(object_permission2.exists())
|
|
377
|
-
self.assertTrue(object_permission2.first().object_types.filter(id=self.prefix_ct.id).exists())
|
|
378
|
-
|
|
379
|
-
@skipIf(
|
|
380
|
-
connection.vendor != "postgresql",
|
|
381
|
-
"mysql does not support rollbacks",
|
|
382
|
-
)
|
|
383
|
-
def test_aggregate_to_prefix_migration_object_changes(self):
|
|
384
|
-
self.assertEqual(self.object_change.objects.filter(changed_object_type=self.prefix_ct).count(), 24)
|
|
385
|
-
self.assertEqual(self.object_change.objects.filter(changed_object_type=self.aggregate_ct).count(), 0)
|
|
386
|
-
|
|
387
|
-
for prefix in (self.prefix1, self.prefix4, self.prefix.objects.get(network="8.5.0.0")):
|
|
388
|
-
self.assertEqual(
|
|
389
|
-
self.object_change.objects.filter(changed_object_id=prefix.id).count(),
|
|
390
|
-
2,
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
for prefix in (self.prefix2, self.prefix3, self.prefix5): # pylint: disable=no-member
|
|
394
|
-
self.assertEqual(
|
|
395
|
-
self.object_change.objects.filter(changed_object_id=prefix.id).count(),
|
|
396
|
-
1,
|
|
397
|
-
)
|
|
398
|
-
|
|
399
|
-
for i in range(6, 13):
|
|
400
|
-
prefix = self.prefix.objects.get(network=f"10.{i}.0.0")
|
|
401
|
-
self.assertEqual(
|
|
402
|
-
self.object_change.objects.filter(changed_object_id=prefix.id).count(),
|
|
403
|
-
0,
|
|
404
|
-
)
|
|
405
|
-
|
|
406
|
-
for i in range(6, 21):
|
|
407
|
-
prefix = self.prefix.objects.get(network=f"8.{i}.0.0")
|
|
408
|
-
self.assertEqual(
|
|
409
|
-
self.object_change.objects.filter(changed_object_id=prefix.id).count(),
|
|
410
|
-
1,
|
|
411
|
-
)
|
|
412
|
-
|
|
413
|
-
@skipIf(
|
|
414
|
-
connection.vendor != "postgresql",
|
|
415
|
-
"mysql does not support rollbacks",
|
|
416
|
-
)
|
|
417
|
-
def test_aggregate_to_prefix_migration_custom_fields(self):
|
|
418
|
-
# This change is necessary because name attribute is not specified now in example_app's signal.py
|
|
419
|
-
self.assertEqual(self.custom_field.objects.exclude(name="").count(), 3)
|
|
420
|
-
self.assertEqual(self.custom_field.objects.filter(content_types=self.prefix_ct).count(), 3)
|
|
421
|
-
self.assertEqual(self.custom_field.objects.filter(content_types=self.aggregate_ct).count(), 2)
|
|
422
|
-
|
|
423
|
-
expected = {
|
|
424
|
-
"prefix1": {
|
|
425
|
-
"prefixcf1": "testdata prefixcf1 prefix1",
|
|
426
|
-
"prefixaggregatecf1": "testdata prefixaggregatecf1 prefix1",
|
|
427
|
-
"aggregatecf1": "testdata aggregatecf1 aggregate1",
|
|
428
|
-
},
|
|
429
|
-
"prefix2": {
|
|
430
|
-
"prefixcf1": "testdata prefixcf1 prefix2",
|
|
431
|
-
"prefixaggregatecf1": "testdata prefixaggregatecf1 prefix2",
|
|
432
|
-
"aggregatecf1": "testdata aggregatecf1 aggregate2",
|
|
433
|
-
},
|
|
434
|
-
"prefix3": {
|
|
435
|
-
"aggregatecf1": "testdata aggregatecf1 aggregate3",
|
|
436
|
-
},
|
|
437
|
-
"prefix4": {},
|
|
438
|
-
"prefix5": {
|
|
439
|
-
"prefixcf1": "testdata prefixcf1 prefix5",
|
|
440
|
-
"prefixaggregatecf1": "testdata prefixaggregatecf1 prefix5",
|
|
441
|
-
},
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
for i in range(1, 6):
|
|
445
|
-
with self.subTest(f"Custom fields for prefix{i}"):
|
|
446
|
-
prefix = self.prefix.objects.get(network=f"10.{i}.0.0")
|
|
447
|
-
self.assertDictEqual(prefix._custom_field_data, expected[f"prefix{i}"])
|
|
448
|
-
|
|
449
|
-
with self.subTest("Custom fields for prefix 8.5.0.0"):
|
|
450
|
-
expected = {
|
|
451
|
-
"prefixaggregatecf1": "testdata prefixaggregatecf1 aggregate5",
|
|
452
|
-
"aggregatecf1": "testdata aggregatecf1 aggregate5",
|
|
453
|
-
}
|
|
454
|
-
prefix = self.prefix.objects.get(network="8.5.0.0")
|
|
455
|
-
self.assertDictEqual(prefix._custom_field_data, expected)
|
|
456
|
-
|
|
457
|
-
with self.subTest("Custom fields for prefix 8.6.0.0"):
|
|
458
|
-
expected = {
|
|
459
|
-
"prefixaggregatecf1": "testdata prefixaggregatecf1 aggregate6",
|
|
460
|
-
}
|
|
461
|
-
prefix = self.prefix.objects.get(network="8.6.0.0")
|
|
462
|
-
self.assertDictEqual(prefix._custom_field_data, expected)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|