nautobot 2.4.4__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.
Files changed (139) hide show
  1. nautobot/__init__.py +19 -3
  2. nautobot/core/api/mixins.py +10 -0
  3. nautobot/core/celery/__init__.py +5 -3
  4. nautobot/core/celery/encoders.py +2 -2
  5. nautobot/core/forms/fields.py +21 -5
  6. nautobot/core/forms/utils.py +1 -0
  7. nautobot/core/jobs/__init__.py +3 -2
  8. nautobot/core/jobs/bulk_actions.py +1 -1
  9. nautobot/core/management/commands/generate_test_data.py +1 -1
  10. nautobot/core/models/name_color_content_types.py +9 -0
  11. nautobot/core/models/validators.py +7 -0
  12. nautobot/core/settings.py +0 -14
  13. nautobot/core/settings.yaml +0 -28
  14. nautobot/core/tables.py +6 -1
  15. nautobot/core/templates/generic/object_retrieve.html +1 -1
  16. nautobot/core/testing/__init__.py +2 -0
  17. nautobot/core/testing/api.py +18 -0
  18. nautobot/core/testing/mixins.py +9 -0
  19. nautobot/core/tests/nautobot_config.py +0 -2
  20. nautobot/core/tests/runner.py +17 -140
  21. nautobot/core/tests/test_api.py +4 -4
  22. nautobot/core/tests/test_authentication.py +83 -4
  23. nautobot/core/tests/test_forms.py +11 -8
  24. nautobot/core/tests/test_graphql.py +9 -0
  25. nautobot/core/tests/test_jobs.py +33 -27
  26. nautobot/core/ui/object_detail.py +31 -0
  27. nautobot/dcim/factory.py +2 -0
  28. nautobot/dcim/filters/__init__.py +5 -0
  29. nautobot/dcim/forms.py +17 -1
  30. nautobot/dcim/migrations/0068_alter_softwareimagefile_download_url.py +19 -0
  31. nautobot/dcim/migrations/0069_softwareimagefile_external_integration.py +25 -0
  32. nautobot/dcim/models/devices.py +9 -2
  33. nautobot/dcim/tables/devices.py +1 -0
  34. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +4 -0
  35. nautobot/dcim/tests/test_api.py +74 -31
  36. nautobot/dcim/tests/test_filters.py +2 -0
  37. nautobot/dcim/tests/test_jobs.py +4 -6
  38. nautobot/dcim/tests/test_models.py +65 -0
  39. nautobot/dcim/tests/test_views.py +3 -0
  40. nautobot/extras/choices.py +8 -3
  41. nautobot/extras/forms/forms.py +7 -3
  42. nautobot/extras/jobs.py +181 -103
  43. nautobot/extras/management/utils.py +13 -2
  44. nautobot/extras/models/datasources.py +4 -1
  45. nautobot/extras/models/jobs.py +20 -17
  46. nautobot/extras/plugins/marketplace_manifest.yml +18 -0
  47. nautobot/extras/tables.py +29 -34
  48. nautobot/extras/templates/extras/inc/panel_changelog.html +1 -1
  49. nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
  50. nautobot/extras/templates/extras/status.html +1 -37
  51. nautobot/extras/test_jobs/atomic_transaction.py +6 -6
  52. nautobot/extras/test_jobs/fail.py +75 -1
  53. nautobot/extras/tests/integration/test_notes.py +1 -1
  54. nautobot/extras/tests/test_api.py +23 -8
  55. nautobot/extras/tests/test_changelog.py +4 -4
  56. nautobot/extras/tests/test_customfields.py +3 -0
  57. nautobot/extras/tests/test_datasources.py +64 -54
  58. nautobot/extras/tests/test_jobs.py +69 -62
  59. nautobot/extras/tests/test_models.py +1 -1
  60. nautobot/extras/tests/test_plugins.py +19 -13
  61. nautobot/extras/tests/test_relationships.py +14 -5
  62. nautobot/extras/tests/test_tags.py +2 -2
  63. nautobot/extras/tests/test_views.py +15 -6
  64. nautobot/extras/urls.py +1 -30
  65. nautobot/extras/views.py +17 -55
  66. nautobot/ipam/forms.py +15 -0
  67. nautobot/ipam/querysets.py +6 -0
  68. nautobot/ipam/tables.py +6 -2
  69. nautobot/ipam/templates/ipam/namespace_retrieve.html +0 -41
  70. nautobot/ipam/templates/ipam/rir.html +1 -43
  71. nautobot/ipam/templates/ipam/service.html +2 -46
  72. nautobot/ipam/templates/ipam/service_edit.html +1 -17
  73. nautobot/ipam/templates/ipam/service_retrieve.html +7 -0
  74. nautobot/ipam/tests/migration/__init__.py +0 -0
  75. nautobot/ipam/tests/migration/test_migrations.py +510 -0
  76. nautobot/ipam/tests/test_api.py +66 -36
  77. nautobot/ipam/tests/test_filters.py +0 -10
  78. nautobot/ipam/tests/test_models.py +16 -0
  79. nautobot/ipam/tests/test_views.py +44 -2
  80. nautobot/ipam/urls.py +2 -67
  81. nautobot/ipam/utils/migrations.py +185 -152
  82. nautobot/ipam/utils/testing.py +177 -0
  83. nautobot/ipam/views.py +119 -198
  84. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +43 -5
  85. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +47 -0
  86. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +18 -0
  87. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +35 -0
  88. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +63 -0
  89. nautobot/project-static/docs/development/apps/api/testing.html +0 -87
  90. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +1 -1
  91. nautobot/project-static/docs/development/core/best-practices.html +3 -3
  92. nautobot/project-static/docs/development/core/getting-started.html +78 -107
  93. nautobot/project-static/docs/development/core/release-checklist.html +1 -1
  94. nautobot/project-static/docs/development/core/style-guide.html +1 -1
  95. nautobot/project-static/docs/development/core/testing.html +24 -198
  96. nautobot/project-static/docs/development/jobs/index.html +27 -14
  97. nautobot/project-static/docs/media/user-guide/administration/getting-started/nautobot-cloud.png +0 -0
  98. nautobot/project-static/docs/objects.inv +0 -0
  99. nautobot/project-static/docs/overview/application_stack.html +1 -1
  100. nautobot/project-static/docs/release-notes/version-2.4.html +409 -1
  101. nautobot/project-static/docs/requirements.txt +1 -1
  102. nautobot/project-static/docs/search/search_index.json +1 -1
  103. nautobot/project-static/docs/sitemap.xml +290 -290
  104. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  105. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +2 -48
  106. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +71 -0
  107. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +3 -1
  108. nautobot/project-static/docs/user-guide/administration/installation/index.html +257 -16
  109. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +1 -1
  110. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +2 -2
  111. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +4 -0
  112. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +11 -11
  113. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +8 -8
  114. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +1 -0
  115. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +40 -25
  116. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +4 -4
  117. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +1 -1
  118. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +77 -5
  119. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +1 -1
  120. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +0 -1
  121. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +1 -1
  122. nautobot/project-static/docs/user-guide/index.html +89 -2
  123. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +207 -122
  124. nautobot/virtualization/forms.py +20 -0
  125. nautobot/virtualization/templates/virtualization/clustergroup.html +1 -39
  126. nautobot/virtualization/templates/virtualization/clustertype.html +1 -0
  127. nautobot/virtualization/tests/test_api.py +14 -3
  128. nautobot/virtualization/tests/test_views.py +10 -2
  129. nautobot/virtualization/urls.py +10 -93
  130. nautobot/virtualization/views.py +33 -72
  131. {nautobot-2.4.4.dist-info → nautobot-2.4.6.dist-info}/METADATA +8 -7
  132. {nautobot-2.4.4.dist-info → nautobot-2.4.6.dist-info}/RECORD +137 -132
  133. {nautobot-2.4.4.dist-info → nautobot-2.4.6.dist-info}/WHEEL +1 -1
  134. nautobot/core/tests/performance_baselines.yml +0 -8900
  135. nautobot/ipam/tests/test_migrations.py +0 -462
  136. /nautobot/ipam/templates/ipam/{namespace_ipaddresses.html → namespace_ip_addresses.html} +0 -0
  137. {nautobot-2.4.4.dist-info → nautobot-2.4.6.dist-info}/LICENSE.txt +0 -0
  138. {nautobot-2.4.4.dist-info → nautobot-2.4.6.dist-info}/NOTICE +0 -0
  139. {nautobot-2.4.4.dist-info → nautobot-2.4.6.dist-info}/entry_points.txt +0 -0
nautobot/extras/views.py CHANGED
@@ -2062,7 +2062,13 @@ def get_annotated_jobresult_queryset():
2062
2062
  error_log_count=count_related(
2063
2063
  JobLogEntry,
2064
2064
  "job_result",
2065
- filter_dict={"log_level__in": [LogLevelChoices.LOG_ERROR, LogLevelChoices.LOG_CRITICAL]},
2065
+ filter_dict={
2066
+ "log_level__in": [
2067
+ LogLevelChoices.LOG_FAILURE,
2068
+ LogLevelChoices.LOG_ERROR,
2069
+ LogLevelChoices.LOG_CRITICAL,
2070
+ ],
2071
+ },
2066
2072
  ),
2067
2073
  )
2068
2074
  )
@@ -2923,62 +2929,18 @@ class DynamicGroupBulkAssignView(GetReturnURLMixin, ObjectPermissionRequiredMixi
2923
2929
  #
2924
2930
 
2925
2931
 
2926
- class StatusListView(generic.ObjectListView):
2927
- """List `Status` objects."""
2928
-
2929
- queryset = Status.objects.all()
2930
- filterset = filters.StatusFilterSet
2931
- filterset_form = forms.StatusFilterForm
2932
- table = tables.StatusTable
2933
-
2934
-
2935
- class StatusEditView(generic.ObjectEditView):
2936
- """Edit a single `Status` object."""
2937
-
2938
- queryset = Status.objects.all()
2939
- model_form = forms.StatusForm
2940
-
2941
-
2942
- class StatusBulkEditView(generic.BulkEditView):
2943
- """Edit multiple `Status` objects."""
2944
-
2945
- queryset = Status.objects.all()
2946
- table = tables.StatusTable
2947
- form = forms.StatusBulkEditForm
2948
-
2949
-
2950
- class StatusBulkDeleteView(generic.BulkDeleteView):
2951
- """Delete multiple `Status` objects."""
2952
-
2953
- queryset = Status.objects.all()
2954
- table = tables.StatusTable
2955
- filterset = filters.StatusFilterSet
2956
-
2957
-
2958
- class StatusDeleteView(generic.ObjectDeleteView):
2959
- """Delete a single `Status` object."""
2960
-
2961
- queryset = Status.objects.all()
2962
-
2963
-
2964
- class StatusBulkImportView(generic.BulkImportView): # 3.0 TODO: remove, unused
2965
- """Bulk CSV import of multiple `Status` objects."""
2966
-
2967
- queryset = Status.objects.all()
2968
- table = tables.StatusTable
2969
-
2970
-
2971
- class StatusView(generic.ObjectView):
2972
- """Detail view for a single `Status` object."""
2973
-
2932
+ class StatusUIViewSet(NautobotUIViewSet):
2933
+ bulk_update_form_class = forms.StatusBulkEditForm
2934
+ filterset_class = filters.StatusFilterSet
2935
+ filterset_form_class = forms.StatusFilterForm
2936
+ form_class = forms.StatusForm
2937
+ serializer_class = serializers.StatusSerializer
2938
+ table_class = tables.StatusTable
2974
2939
  queryset = Status.objects.all()
2975
2940
 
2976
- def get_extra_context(self, request, instance):
2977
- """Return ordered content types."""
2978
- return {
2979
- "content_types": instance.content_types.order_by("app_label", "model"),
2980
- **super().get_extra_context(request, instance),
2981
- }
2941
+ object_detail_content = object_detail.ObjectDetailContent(
2942
+ panels=(object_detail.ObjectFieldsPanel(weight=100, section=SectionChoices.LEFT_HALF, fields="__all__"),)
2943
+ )
2982
2944
 
2983
2945
 
2984
2946
  #
nautobot/ipam/forms.py CHANGED
@@ -262,6 +262,21 @@ class RIRFilterForm(NautobotFilterForm):
262
262
  )
263
263
 
264
264
 
265
+ class RIRBulkEditForm(NautobotBulkEditForm):
266
+ pk = forms.ModelMultipleChoiceField(queryset=RIR.objects.all(), widget=forms.MultipleHiddenInput())
267
+ is_private = forms.NullBooleanField(
268
+ required=False,
269
+ label="Private",
270
+ widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
271
+ )
272
+ description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
273
+
274
+ class Meta:
275
+ nullable_fields = [
276
+ "description",
277
+ ]
278
+
279
+
265
280
  #
266
281
  # Prefixes
267
282
  #
@@ -405,6 +405,12 @@ class IPAddressQuerySet(BaseNetworkQuerySet):
405
405
  namespace = kwargs.pop("namespace", None)
406
406
  host = kwargs.get("host")
407
407
  mask_length = kwargs.get("mask_length")
408
+ address = kwargs.get("address")
409
+ if host is None and address is not None:
410
+ address = netaddr.IPNetwork(address)
411
+ host = str(address.ip)
412
+ mask_length = address.prefixlen
413
+
408
414
  # If `host` or `mask_length` is None skip; then there is no way of getting the closest parent;
409
415
  if parent is None and host is not None and mask_length is not None:
410
416
  if namespace is None:
nautobot/ipam/tables.py CHANGED
@@ -355,7 +355,11 @@ class PrefixTable(StatusTableMixin, RoleTableMixin, BaseTable):
355
355
  template_code=PREFIX_COPY_LINK, attrs={"td": {"class": "text-nowrap"}}, order_by=("network", "prefix_length")
356
356
  )
357
357
  vrf_count = LinkedCountColumn(
358
- viewname="ipam:vrf_list", url_params={"prefix": "pk"}, reverse_lookup="prefixes", verbose_name="VRFs"
358
+ viewname="ipam:vrf_list",
359
+ url_params={"prefix": "pk"},
360
+ display_field="name",
361
+ reverse_lookup="prefixes",
362
+ verbose_name="VRFs",
359
363
  )
360
364
  tenant = TenantColumn()
361
365
  namespace = tables.Column(linkify=True)
@@ -364,7 +368,7 @@ class PrefixTable(StatusTableMixin, RoleTableMixin, BaseTable):
364
368
  children = tables.Column(accessor="descendants_count", orderable=False)
365
369
  date_allocated = tables.DateTimeColumn()
366
370
  location_count = LinkedCountColumn(
367
- viewname="dcim:location_list", url_params={"prefixes": "pk"}, verbose_name="Locations"
371
+ viewname="dcim:location_list", url_params={"prefixes": "pk"}, display_field="name", verbose_name="Locations"
368
372
  )
369
373
  cloud_networks_count = LinkedCountColumn(
370
374
  viewname="cloud:cloudnetwork_list", url_params={"prefixes": "pk"}, verbose_name="Cloud Networks"
@@ -1,42 +1 @@
1
1
  {% extends 'generic/object_retrieve.html' %}
2
- {% load helpers %}
3
-
4
- {% block content_left_page %}
5
- <div class="panel panel-default">
6
- <div class="panel-heading">
7
- <strong>Namespace</strong>
8
- </div>
9
- <table class="table table-hover panel-body attr-table">
10
- <tr>
11
- <td>Name</td>
12
- <td>{{ object.name }}</td>
13
- </tr>
14
- <tr>
15
- <td>Description</td>
16
- <td>{{ object.description }}</td>
17
- </tr>
18
- <tr>
19
- <td>Location</td>
20
- <td>{{ object.location | hyperlinked_object }}</td>
21
- </tr>
22
- </table>
23
- </div>
24
- {% endblock content_left_page %}
25
-
26
- {% block extra_nav_tabs %}
27
- {% if perms.ipam.view_vrf %}
28
- <li role="presentation"{% if active_tab == 'vrfs' %} class="active"{% endif %}>
29
- <a href="{% url 'ipam:namespace_vrfs' pk=object.pk %}">VRFs <span class="badge">{{ vrf_count }}</span></a>
30
- </li>
31
- {% endif %}
32
- {% if perms.ipam.view_prefix %}
33
- <li role="presentation"{% if active_tab == 'prefixes' %} class="active"{% endif %}>
34
- <a href="{% url 'ipam:namespace_prefixes' pk=object.pk %}">Prefixes <span class="badge">{{ prefix_count }}</span></a>
35
- </li>
36
- {% endif %}
37
- {% if perms.ipam.view_ipaddress %}
38
- <li role="presentation"{% if active_tab == 'ip-addresses' %} class="active"{% endif %}>
39
- <a href="{% url 'ipam:namespace_ipaddresses' pk=object.pk %}">IP Addresses <span class="badge">{{ ip_address_count }}</span></a>
40
- </li>
41
- {% endif %}
42
- {% endblock extra_nav_tabs %}
@@ -1,44 +1,2 @@
1
1
  {% extends 'generic/object_retrieve.html' %}
2
- {% load helpers %}
3
-
4
- {% block content_left_page %}
5
- <div class="panel panel-default">
6
- <div class="panel-heading">
7
- <strong>RIR</strong>
8
- </div>
9
- <table class="table table-hover panel-body attr-table">
10
- <tr>
11
- <td>Description</td>
12
- <td>{{ object.description|placeholder }}</td>
13
- </tr>
14
- <tr>
15
- <td>Private</td>
16
- <td>{{ object.is_private | render_boolean }}</td>
17
- </tr>
18
- <tr>
19
- <td>Assigned Prefixes</td>
20
- <td>
21
- <a href="{% url 'ipam:prefix_list' %}?rir={{ object.name }}">{{ assigned_prefix_table.rows|length }}</a>
22
- </td>
23
- </tr>
24
- </table>
25
- </div>
26
- {% endblock content_left_page %}
27
-
28
- {% block content_full_width_page %}
29
- <div class="panel panel-default">
30
- <div class="panel-heading">
31
- <strong>Assigned Prefixes</strong>
32
- </div>
33
- {% include 'inc/table.html' with table=assigned_prefix_table %}
34
- {% if perms.ipam.add_prefix %}
35
- <div class="panel-footer text-right noprint">
36
- <a href="{% url 'ipam:prefix_add' %}?rir={{ object.pk }}" class="btn btn-xs btn-primary">
37
- <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add prefix
38
- </a>
39
- </div>
40
- {% endif %}
41
- </div>
42
- {% include 'inc/paginator.html' with paginator=assigned_prefix_table.paginator page=assigned_prefix_table.page %}
43
- <div class="row"></div>
44
- {% endblock content_full_width_page %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -1,46 +1,2 @@
1
- {% extends 'generic/object_retrieve.html' %}
2
- {% load helpers %}
3
-
4
- {% block extra_breadcrumbs %}
5
- <li>{{ object.parent|hyperlinked_object }}</li>
6
- {% endblock extra_breadcrumbs %}
7
-
8
- {% block content_left_page %}
9
- <div class="panel panel-default">
10
- <div class="panel-heading">
11
- <strong>Service</strong>
12
- </div>
13
- <table class="table table-hover panel-body attr-table">
14
- <tr>
15
- <td>Name</td>
16
- <td>{{ object.name }}</td>
17
- </tr>
18
- <tr>
19
- <td>Parent</td>
20
- <td>{{ object.parent|hyperlinked_object }}</td>
21
- </tr>
22
- <tr>
23
- <td>Protocol</td>
24
- <td>{{ object.get_protocol_display }}</td>
25
- </tr>
26
- <tr>
27
- <td>Ports</td>
28
- <td>{{ object.port_list }}</td>
29
- </tr>
30
- <tr>
31
- <td>IP Addresses</td>
32
- <td>
33
- {% for ipaddress in object.ip_addresses.all %}
34
- {{ ipaddress|hyperlinked_object }}<br>
35
- {% empty %}
36
- <span class="text-muted">None</span>
37
- {% endfor %}
38
- </td>
39
- </tr>
40
- <tr>
41
- <td>Description</td>
42
- <td>{{ object.description|placeholder }}</td>
43
- </tr>
44
- </table>
45
- </div>
46
- {% endblock content_left_page %}
1
+ {% extends 'ipam/service_retrieve.html' %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -1,18 +1,2 @@
1
1
  {% extends 'generic/object_create.html' %}
2
- {% load form_helpers %}
3
-
4
- {% block form %}
5
- <div class="panel panel-default">
6
- <div class="panel-heading"><strong>Service</strong></div>
7
- <div class="panel-body">
8
- {% render_field form.device %}
9
- {% render_field form.virtual_machine %}
10
- {% render_field form.name %}
11
- {% render_field form.protocol %}
12
- {% render_field form.ports %}
13
- {% render_field form.ip_addresses %}
14
- {% render_field form.description %}
15
- </div>
16
- </div>
17
- {% include 'inc/extras_features_edit_form_fields.html' %}
18
- {% endblock %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -0,0 +1,7 @@
1
+ {% extends 'generic/object_retrieve.html' %}
2
+ {% load helpers %}
3
+
4
+ {% block extra_breadcrumbs %}
5
+ <li>{{ object.parent|hyperlinked_object }}</li>
6
+ {% endblock extra_breadcrumbs %}
7
+
File without changes