From 1b62c11db5c01c8dbc2c2ddf2f2bd18ddd6a9098 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Fri, 16 Sep 2022 13:41:09 -0400 Subject: [PATCH 01/39] PRVB --- docs/release-notes/version-3.3.md | 4 ++++ netbox/netbox/settings.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index a51089c70..d779e1a93 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -1,5 +1,9 @@ # NetBox v3.3 +## v3.3.5 (FUTURE) + +--- + ## v3.3.4 (2022-09-16) ### Bug Fixes diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index e24ac6492..cfd4d231c 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -29,7 +29,7 @@ django.utils.encoding.force_text = force_str # Environment setup # -VERSION = '3.3.4' +VERSION = '3.3.5-dev' # Hostname HOSTNAME = platform.node() From 695ad47fe9e4f5fa3193fe4f08afd985d6eac4d6 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 Sep 2022 10:46:16 -0700 Subject: [PATCH 02/39] 10408 add error message if already exists --- netbox/netbox/views/generic/object_views.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/netbox/netbox/views/generic/object_views.py b/netbox/netbox/views/generic/object_views.py index a56a832b6..85604cd8f 100644 --- a/netbox/netbox/views/generic/object_views.py +++ b/netbox/netbox/views/generic/object_views.py @@ -3,7 +3,7 @@ from copy import deepcopy from django.contrib import messages from django.core.exceptions import ObjectDoesNotExist -from django.db import transaction +from django.db import transaction, IntegrityError from django.db.models import ProtectedError from django.forms.widgets import HiddenInput from django.shortcuts import redirect, render @@ -421,7 +421,11 @@ class ObjectEditView(GetReturnURLMixin, BaseObjectView): return redirect(return_url) - except (AbortRequest, PermissionsViolation) as e: + except IntegrityError: + form.add_error(None, f"{obj} already exists") + clear_webhooks.send(sender=self) + + except (IntegrityError, AbortRequest, PermissionsViolation) as e: logger.debug(e.message) form.add_error(None, e.message) clear_webhooks.send(sender=self) From 71d71a6b1b70e5800d599f5a5217d696e194b67c Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 20 Sep 2022 09:26:40 -0500 Subject: [PATCH 03/39] Fixes #9497 - Change filter for sites/locations --- netbox/dcim/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 6ee74377a..b1f94d785 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -355,7 +355,7 @@ class SiteView(generic.ObjectView): nonracked_devices = Device.objects.filter( site=instance, - position__isnull=True, + rack__isnull=True, parent_bay__isnull=True ).prefetch_related('device_type__manufacturer', 'parent_bay', 'device_role') @@ -450,7 +450,7 @@ class LocationView(generic.ObjectView): nonracked_devices = Device.objects.filter( location=instance, - position__isnull=True, + rack__isnull=True, parent_bay__isnull=True ).prefetch_related('device_type__manufacturer', 'parent_bay', 'device_role') From 86d366be4d4d489a4a4cde53e0bd187529fe09e8 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 20 Sep 2022 09:46:23 -0500 Subject: [PATCH 04/39] Fixes #9651 - Document Pre-Change process for scripts --- docs/customization/custom-scripts.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/customization/custom-scripts.md b/docs/customization/custom-scripts.md index 230b003c6..e5d5a1ef5 100644 --- a/docs/customization/custom-scripts.md +++ b/docs/customization/custom-scripts.md @@ -129,6 +129,19 @@ The Script object provides a set of convenient functions for recording messages Log messages are returned to the user upon execution of the script. Markdown rendering is supported for log messages. +## Change Logging + +To generate the correct change log data when editing an existing object, a snapshot of the object must be taken before making any changes to the object. + +```python +if obj.pk and hasattr(obj, 'snapshot'): + obj.snapshot() + +obj.property = "New Value" +obj.full_clean() +obj.save() +``` + ## Variable Reference ### Default Options From 75c91232b49386d3014e450e6d6ef619d9b506b9 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 20 Sep 2022 09:49:46 -0500 Subject: [PATCH 05/39] Update changelog for #9497 --- docs/release-notes/version-3.3.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index d779e1a93..71f5605f9 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -8,6 +8,7 @@ ### Bug Fixes +* [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view * [#10383](https://github.com/netbox-community/netbox/issues/10383) - Fix assignment of component templates to module types via web UI * [#10387](https://github.com/netbox-community/netbox/issues/10387) - Fix `MultiValueDictKeyError` exception when editing a device interface From 360172cad01c0b54ef02328ad0d9a198068ba13d Mon Sep 17 00:00:00 2001 From: Jonathan Senecal Date: Wed, 21 Sep 2022 15:19:40 -0400 Subject: [PATCH 06/39] Add [tool.pyright] to pyproject.toml --- pyproject.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 6d579b737..177b44d86 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,3 +11,12 @@ profile = "black" [tool.pylint] max-line-length = 120 + +[tool.pyright] +include = ["netbox"] +exclude = [ + "**/node_modules", + "**/__pycache__", +] +reportMissingImports = true +reportMissingTypeStubs = false From 7735634649933e1c64d410a4fbc69f6bc8c975e6 Mon Sep 17 00:00:00 2001 From: Arthur Date: Thu, 22 Sep 2022 10:34:37 -0700 Subject: [PATCH 07/39] 10435 check if vm.cluster in qs --- netbox/ipam/querysets.py | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/netbox/ipam/querysets.py b/netbox/ipam/querysets.py index 7edac2eff..b64ae04b8 100644 --- a/netbox/ipam/querysets.py +++ b/netbox/ipam/querysets.py @@ -81,30 +81,31 @@ class VLANQuerySet(RestrictedQuerySet): # Find all relevant VLANGroups q = Q() - if vm.cluster.site: - if vm.cluster.site.region: + if vm.cluster: + if vm.cluster.site: + if vm.cluster.site.region: + q |= Q( + scope_type=ContentType.objects.get_by_natural_key('dcim', 'region'), + scope_id__in=vm.cluster.site.region.get_ancestors(include_self=True) + ) + if vm.cluster.site.group: + q |= Q( + scope_type=ContentType.objects.get_by_natural_key('dcim', 'sitegroup'), + scope_id__in=vm.cluster.site.group.get_ancestors(include_self=True) + ) q |= Q( - scope_type=ContentType.objects.get_by_natural_key('dcim', 'region'), - scope_id__in=vm.cluster.site.region.get_ancestors(include_self=True) + scope_type=ContentType.objects.get_by_natural_key('dcim', 'site'), + scope_id=vm.cluster.site_id ) - if vm.cluster.site.group: + if vm.cluster.group: q |= Q( - scope_type=ContentType.objects.get_by_natural_key('dcim', 'sitegroup'), - scope_id__in=vm.cluster.site.group.get_ancestors(include_self=True) + scope_type=ContentType.objects.get_by_natural_key('virtualization', 'clustergroup'), + scope_id=vm.cluster.group_id ) q |= Q( - scope_type=ContentType.objects.get_by_natural_key('dcim', 'site'), - scope_id=vm.cluster.site_id + scope_type=ContentType.objects.get_by_natural_key('virtualization', 'cluster'), + scope_id=vm.cluster_id ) - if vm.cluster.group: - q |= Q( - scope_type=ContentType.objects.get_by_natural_key('virtualization', 'clustergroup'), - scope_id=vm.cluster.group_id - ) - q |= Q( - scope_type=ContentType.objects.get_by_natural_key('virtualization', 'cluster'), - scope_id=vm.cluster_id - ) vlan_groups = VLANGroup.objects.filter(q) # Return all applicable VLANs @@ -113,7 +114,7 @@ class VLANQuerySet(RestrictedQuerySet): Q(group__scope_id__isnull=True, site__isnull=True) | # Global group VLANs Q(group__isnull=True, site__isnull=True) # Global VLANs ) - if vm.cluster.site: + if vm.cluster and vm.cluster.site: q |= Q(site=vm.cluster.site) return self.filter(q) From c97d2d4fe9c9fdc4f348fc03facdae79c7f2894b Mon Sep 17 00:00:00 2001 From: "Artem I. Kotik" Date: Sat, 24 Sep 2022 15:49:23 +0400 Subject: [PATCH 08/39] Add widget for Airflow field in DeviceTypeForm --- netbox/dcim/forms/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/dcim/forms/models.py b/netbox/dcim/forms/models.py index 5728e7f2d..b33023ece 100644 --- a/netbox/dcim/forms/models.py +++ b/netbox/dcim/forms/models.py @@ -373,6 +373,7 @@ class DeviceTypeForm(NetBoxModelForm): 'front_image', 'rear_image', 'comments', 'tags', ] widgets = { + 'airflow': StaticSelect(), 'subdevice_role': StaticSelect(), 'front_image': ClearableFileInput(attrs={ 'accept': DEVICETYPE_IMAGE_FORMATS From 39129ecedfb5755ac1c1c827abf60f5904670d80 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Mon, 26 Sep 2022 06:17:02 -0700 Subject: [PATCH 09/39] 10407 fix documentation link to requests (#10409) * 10407 fix documentation link to requests * Append page heading to URL Co-authored-by: jeremystretch --- docs/configuration/system.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/system.md b/docs/configuration/system.md index 21607e566..93f8fa902 100644 --- a/docs/configuration/system.md +++ b/docs/configuration/system.md @@ -58,7 +58,7 @@ Email is sent from NetBox only for critical events or if configured for [logging Default: None -A dictionary of HTTP proxies to use for outbound requests originating from NetBox (e.g. when sending webhook requests). Proxies should be specified by schema (HTTP and HTTPS) as per the [Python requests library documentation](https://2.python-requests.org/en/master/user/advanced/). For example: +A dictionary of HTTP proxies to use for outbound requests originating from NetBox (e.g. when sending webhook requests). Proxies should be specified by schema (HTTP and HTTPS) as per the [Python requests library documentation](https://requests.readthedocs.io/en/latest/user/advanced/#proxies). For example: ```python HTTP_PROXIES = { From 3ad337dd15b569a644e7f0a1a22fed4970ccf295 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 26 Sep 2022 10:08:54 -0400 Subject: [PATCH 10/39] Filter VLANs and VLANGroups by site or cluster site for VM --- netbox/ipam/querysets.py | 41 +++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/netbox/ipam/querysets.py b/netbox/ipam/querysets.py index b64ae04b8..9f4463f61 100644 --- a/netbox/ipam/querysets.py +++ b/netbox/ipam/querysets.py @@ -81,31 +81,34 @@ class VLANQuerySet(RestrictedQuerySet): # Find all relevant VLANGroups q = Q() + site = vm.site or vm.cluster.site if vm.cluster: - if vm.cluster.site: - if vm.cluster.site.region: - q |= Q( - scope_type=ContentType.objects.get_by_natural_key('dcim', 'region'), - scope_id__in=vm.cluster.site.region.get_ancestors(include_self=True) - ) - if vm.cluster.site.group: - q |= Q( - scope_type=ContentType.objects.get_by_natural_key('dcim', 'sitegroup'), - scope_id__in=vm.cluster.site.group.get_ancestors(include_self=True) - ) - q |= Q( - scope_type=ContentType.objects.get_by_natural_key('dcim', 'site'), - scope_id=vm.cluster.site_id - ) + # Add VLANGroups scoped to the assigned cluster (or its group) + q |= Q( + scope_type=ContentType.objects.get_by_natural_key('virtualization', 'cluster'), + scope_id=vm.cluster_id + ) if vm.cluster.group: q |= Q( scope_type=ContentType.objects.get_by_natural_key('virtualization', 'clustergroup'), scope_id=vm.cluster.group_id ) + if site: + # Add VLANGroups scoped to the assigned site (or its group or region) q |= Q( - scope_type=ContentType.objects.get_by_natural_key('virtualization', 'cluster'), - scope_id=vm.cluster_id + scope_type=ContentType.objects.get_by_natural_key('dcim', 'site'), + scope_id=site.pk ) + if site.region: + q |= Q( + scope_type=ContentType.objects.get_by_natural_key('dcim', 'region'), + scope_id__in=site.region.get_ancestors(include_self=True) + ) + if site.group: + q |= Q( + scope_type=ContentType.objects.get_by_natural_key('dcim', 'sitegroup'), + scope_id__in=site.group.get_ancestors(include_self=True) + ) vlan_groups = VLANGroup.objects.filter(q) # Return all applicable VLANs @@ -114,7 +117,7 @@ class VLANQuerySet(RestrictedQuerySet): Q(group__scope_id__isnull=True, site__isnull=True) | # Global group VLANs Q(group__isnull=True, site__isnull=True) # Global VLANs ) - if vm.cluster and vm.cluster.site: - q |= Q(site=vm.cluster.site) + if site: + q |= Q(site=site) return self.filter(q) From fd89ef04b6eac975bf7acf2cbada4810442c0bf3 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 26 Sep 2022 10:24:40 -0400 Subject: [PATCH 11/39] Revert "10408 add error message if already exists" --- netbox/netbox/views/generic/object_views.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/netbox/netbox/views/generic/object_views.py b/netbox/netbox/views/generic/object_views.py index 85604cd8f..a56a832b6 100644 --- a/netbox/netbox/views/generic/object_views.py +++ b/netbox/netbox/views/generic/object_views.py @@ -3,7 +3,7 @@ from copy import deepcopy from django.contrib import messages from django.core.exceptions import ObjectDoesNotExist -from django.db import transaction, IntegrityError +from django.db import transaction from django.db.models import ProtectedError from django.forms.widgets import HiddenInput from django.shortcuts import redirect, render @@ -421,11 +421,7 @@ class ObjectEditView(GetReturnURLMixin, BaseObjectView): return redirect(return_url) - except IntegrityError: - form.add_error(None, f"{obj} already exists") - clear_webhooks.send(sender=self) - - except (IntegrityError, AbortRequest, PermissionsViolation) as e: + except (AbortRequest, PermissionsViolation) as e: logger.debug(e.message) form.add_error(None, e.message) clear_webhooks.send(sender=self) From 96784640e371d12c0dcd97d15ceae4a45663f8c0 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 26 Sep 2022 10:27:35 -0400 Subject: [PATCH 12/39] Changelog for #10435, #10439 --- docs/release-notes/version-3.3.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 71f5605f9..2955e17d5 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -2,13 +2,17 @@ ## v3.3.5 (FUTURE) +### Bug Fixes + +* [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view +* [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned +* [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field + --- ## v3.3.4 (2022-09-16) ### Bug Fixes - -* [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view * [#10383](https://github.com/netbox-community/netbox/issues/10383) - Fix assignment of component templates to module types via web UI * [#10387](https://github.com/netbox-community/netbox/issues/10387) - Fix `MultiValueDictKeyError` exception when editing a device interface From a0b17887fdbcc23a4629cacd704e58834c01d3cc Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 26 Sep 2022 15:45:58 -0400 Subject: [PATCH 13/39] Fixes #10445: Avoid rounding virtual machine memory values --- docs/release-notes/version-3.3.md | 1 + netbox/utilities/templatetags/helpers.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 2955e17d5..7a5553b41 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -7,6 +7,7 @@ * [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view * [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned * [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field +* [#10445](https://github.com/netbox-community/netbox/issues/10445) - Avoid rounding virtual machine memory values --- diff --git a/netbox/utilities/templatetags/helpers.py b/netbox/utilities/templatetags/helpers.py index 67ed553b2..462b37feb 100644 --- a/netbox/utilities/templatetags/helpers.py +++ b/netbox/utilities/templatetags/helpers.py @@ -73,9 +73,9 @@ def humanize_megabytes(mb): """ if not mb: return '' - if mb >= 1048576: + if not mb % 1048576: # 1024^2 return f'{int(mb / 1048576)} TB' - if mb >= 1024: + if not mb % 1024: return f'{int(mb / 1024)} GB' return f'{mb} MB' From 2463e4efd3f4c38ba4f3db0622f0c4c5576bf587 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 26 Sep 2022 16:42:11 -0400 Subject: [PATCH 14/39] Fixes #10461: Enable filtering by read-only custom fields in the UI --- docs/release-notes/version-3.3.md | 1 + netbox/extras/forms/customfields.py | 11 +++-------- netbox/extras/models/customfields.py | 9 ++++++++- netbox/netbox/forms/base.py | 6 +++--- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 7a5553b41..d4d2d35f5 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -8,6 +8,7 @@ * [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned * [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field * [#10445](https://github.com/netbox-community/netbox/issues/10445) - Avoid rounding virtual machine memory values +* [#10461](https://github.com/netbox-community/netbox/issues/10461) - Enable filtering by read-only custom fields in the UI --- diff --git a/netbox/extras/forms/customfields.py b/netbox/extras/forms/customfields.py index 7574f4f2b..40d068450 100644 --- a/netbox/extras/forms/customfields.py +++ b/netbox/extras/forms/customfields.py @@ -34,7 +34,9 @@ class CustomFieldsMixin: return ContentType.objects.get_for_model(self.model) def _get_custom_fields(self, content_type): - return CustomField.objects.filter(content_types=content_type) + return CustomField.objects.filter(content_types=content_type).exclude( + ui_visibility=CustomFieldVisibilityChoices.VISIBILITY_HIDDEN + ) def _get_form_field(self, customfield): return customfield.to_form_field() @@ -50,13 +52,6 @@ class CustomFieldsMixin: field_name = f'cf_{customfield.name}' self.fields[field_name] = self._get_form_field(customfield) - if customfield.ui_visibility == CustomFieldVisibilityChoices.VISIBILITY_READ_ONLY: - self.fields[field_name].disabled = True - if self.fields[field_name].help_text: - self.fields[field_name].help_text += '
' - self.fields[field_name].help_text += ' ' \ - 'Field is set to read-only.' - # Annotate the field in the list of CustomField form fields self.custom_fields[field_name] = customfield if customfield.group_name not in self.custom_field_groups: diff --git a/netbox/extras/models/customfields.py b/netbox/extras/models/customfields.py index 43c4f9671..d52d73848 100644 --- a/netbox/extras/models/customfields.py +++ b/netbox/extras/models/customfields.py @@ -297,12 +297,13 @@ class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge return model.objects.filter(pk__in=value) return value - def to_form_field(self, set_initial=True, enforce_required=True, for_csv_import=False): + def to_form_field(self, set_initial=True, enforce_required=True, enforce_visibility=True, for_csv_import=False): """ Return a form field suitable for setting a CustomField's value for an object. set_initial: Set initial data for the field. This should be False when generating a field for bulk editing. enforce_required: Honor the value of CustomField.required. Set to False for filtering/bulk editing. + enforce_visibility: Honor the value of CustomField.ui_visibility. Set to False for filtering. for_csv_import: Return a form field suitable for bulk import of objects in CSV format. """ initial = self.default if set_initial else None @@ -398,6 +399,12 @@ class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge if self.description: field.help_text = escape(self.description) + # Annotate read-only fields + if enforce_visibility and self.ui_visibility == CustomFieldVisibilityChoices.VISIBILITY_READ_ONLY: + field.disabled = True + prepend = '
' if field.help_text else '' + field.help_text += f'{prepend} Field is set to read-only.' + return field def to_filter(self, lookup_expr=None): diff --git a/netbox/netbox/forms/base.py b/netbox/netbox/forms/base.py index 2676e4cde..fa741faf7 100644 --- a/netbox/netbox/forms/base.py +++ b/netbox/netbox/forms/base.py @@ -2,7 +2,7 @@ from django import forms from django.contrib.contenttypes.models import ContentType from django.db.models import Q -from extras.choices import CustomFieldFilterLogicChoices, CustomFieldTypeChoices +from extras.choices import CustomFieldFilterLogicChoices, CustomFieldTypeChoices, CustomFieldVisibilityChoices from extras.forms.customfields import CustomFieldsMixin from extras.models import CustomField, Tag from utilities.forms import BootstrapMixin, CSVModelForm @@ -125,10 +125,10 @@ class NetBoxModelFilterSetForm(BootstrapMixin, CustomFieldsMixin, forms.Form): ) def _get_custom_fields(self, content_type): - return CustomField.objects.filter(content_types=content_type).exclude( + return super()._get_custom_fields(content_type).exclude( Q(filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED) | Q(type=CustomFieldTypeChoices.TYPE_JSON) ) def _get_form_field(self, customfield): - return customfield.to_form_field(set_initial=False, enforce_required=False) + return customfield.to_form_field(set_initial=False, enforce_required=False, enforce_visibility=False) From dda193247adf92df860ad799bb2127e34f2fe2b4 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 26 Sep 2022 16:47:34 -0400 Subject: [PATCH 15/39] Fixes #10470: Omit read-only custom fields from CSV import forms --- docs/release-notes/version-3.3.md | 1 + netbox/netbox/forms/base.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index d4d2d35f5..60d8b5381 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -9,6 +9,7 @@ * [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field * [#10445](https://github.com/netbox-community/netbox/issues/10445) - Avoid rounding virtual machine memory values * [#10461](https://github.com/netbox-community/netbox/issues/10461) - Enable filtering by read-only custom fields in the UI +* [#10470](https://github.com/netbox-community/netbox/issues/10470) - Omit read-only custom fields from CSV import forms --- diff --git a/netbox/netbox/forms/base.py b/netbox/netbox/forms/base.py index fa741faf7..2cbc67971 100644 --- a/netbox/netbox/forms/base.py +++ b/netbox/netbox/forms/base.py @@ -63,6 +63,11 @@ class NetBoxModelCSVForm(CSVModelForm, NetBoxModelForm): """ tags = None # Temporary fix in lieu of tag import support (see #9158) + def _get_custom_fields(self, content_type): + return CustomField.objects.filter(content_types=content_type).filter( + ui_visibility=CustomFieldVisibilityChoices.VISIBILITY_READ_WRITE + ) + def _get_form_field(self, customfield): return customfield.to_form_field(for_csv_import=True) From 43b18c13e3406febf41f95812d1351ab74af5336 Mon Sep 17 00:00:00 2001 From: Patrick Hurrelmann Date: Tue, 27 Sep 2022 13:23:51 +0200 Subject: [PATCH 16/39] Fixes: #10480 Fix link-target on cable-trace svg to open link in the same window. --- netbox/dcim/svg/cables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/dcim/svg/cables.py b/netbox/dcim/svg/cables.py index 3872bc4fe..9a847acc9 100644 --- a/netbox/dcim/svg/cables.py +++ b/netbox/dcim/svg/cables.py @@ -35,7 +35,7 @@ class Node(Hyperlink): """ def __init__(self, position, width, url, color, labels, radius=10, **extra): - super(Node, self).__init__(href=url, target='_blank', **extra) + super(Node, self).__init__(href=url, target='_parent', **extra) x, y = position From 669e86f96e5866124db04e7efc1542b84966987a Mon Sep 17 00:00:00 2001 From: Patrick Hurrelmann Date: Tue, 27 Sep 2022 17:24:19 +0200 Subject: [PATCH 17/39] Fixes: #10465 Format all remaining displayed rackunits with floatformat (#10481) * Fixes: #10465 Try to finish #10268 and format all remaining displayed rackunits with floatformat * #10465: PEP8 fix Co-authored-by: Patrick Hurrelmann Co-authored-by: jeremystretch --- netbox/dcim/svg/racks.py | 3 ++- netbox/dcim/tables/devicetypes.py | 3 +++ netbox/templates/dcim/device.html | 4 ++-- netbox/templates/dcim/devicetype.html | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/netbox/dcim/svg/racks.py b/netbox/dcim/svg/racks.py index 573fc966c..6c57e6023 100644 --- a/netbox/dcim/svg/racks.py +++ b/netbox/dcim/svg/racks.py @@ -9,6 +9,7 @@ from svgwrite.text import Text from django.conf import settings from django.core.exceptions import FieldError from django.db.models import Q +from django.template.defaultfilters import floatformat from django.urls import reverse from django.utils.http import urlencode @@ -41,7 +42,7 @@ def get_device_description(device): device.device_role, device.device_type.manufacturer.name, device.device_type.model, - device.device_type.u_height, + floatformat(device.device_type.u_height), device.asset_tag or '', device.serial or '' ) diff --git a/netbox/dcim/tables/devicetypes.py b/netbox/dcim/tables/devicetypes.py index 3ed4d8c08..ec71245f7 100644 --- a/netbox/dcim/tables/devicetypes.py +++ b/netbox/dcim/tables/devicetypes.py @@ -85,6 +85,9 @@ class DeviceTypeTable(NetBoxTable): tags = columns.TagColumn( url_name='dcim:devicetype_list' ) + u_height = columns.TemplateColumn( + template_code='{{ value|floatformat }}' + ) class Meta(NetBoxTable.Meta): model = DeviceType diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index 6cc859749..253d905f2 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -66,7 +66,7 @@ {% with object.parent_bay.device as parent %} {{ parent|linkify }} / {{ object.parent_bay }} {% if parent.position %} - (U{{ parent.position }} / {{ parent.get_face_display }}) + (U{{ parent.position|floatformat }} / {{ parent.get_face_display }}) {% endif %} {% endwith %} {% elif object.rack and object.position %} @@ -90,7 +90,7 @@ Device Type - {{ object.device_type|linkify:"get_full_name" }} ({{ object.device_type.u_height }}U) + {{ object.device_type|linkify:"get_full_name" }} ({{ object.device_type.u_height|floatformat }}U) diff --git a/netbox/templates/dcim/devicetype.html b/netbox/templates/dcim/devicetype.html index bb3ec9d2e..1fde72d27 100644 --- a/netbox/templates/dcim/devicetype.html +++ b/netbox/templates/dcim/devicetype.html @@ -29,7 +29,7 @@ Height (U) - {{ object.u_height }} + {{ object.u_height|floatformat }} Full Depth From 05542324fc57aee1a7939f7ea7e497a2490d0f9d Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 27 Sep 2022 11:53:11 -0400 Subject: [PATCH 18/39] Changelog for #10465, #10480 --- docs/release-notes/version-3.3.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 60d8b5381..4edda4e9b 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -2,6 +2,10 @@ ## v3.3.5 (FUTURE) +### Enhancements + +* [#10465](https://github.com/netbox-community/netbox/issues/10465) - Improve formatting of device heights and rack positions + ### Bug Fixes * [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view @@ -10,12 +14,14 @@ * [#10445](https://github.com/netbox-community/netbox/issues/10445) - Avoid rounding virtual machine memory values * [#10461](https://github.com/netbox-community/netbox/issues/10461) - Enable filtering by read-only custom fields in the UI * [#10470](https://github.com/netbox-community/netbox/issues/10470) - Omit read-only custom fields from CSV import forms +* [#10480](https://github.com/netbox-community/netbox/issues/10480) - Cable trace SVG links should not force a new window --- ## v3.3.4 (2022-09-16) ### Bug Fixes + * [#10383](https://github.com/netbox-community/netbox/issues/10383) - Fix assignment of component templates to module types via web UI * [#10387](https://github.com/netbox-community/netbox/issues/10387) - Fix `MultiValueDictKeyError` exception when editing a device interface From 2d9852d6f108b745181f23b39c4e72ee970bb7f8 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 27 Sep 2022 13:11:57 -0400 Subject: [PATCH 19/39] Fixes #10408: Fix validation when attempting to add redundant contact assignments --- docs/release-notes/version-3.3.md | 1 + netbox/templates/tenancy/contactassignment_edit.html | 3 +++ netbox/tenancy/forms/models.py | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 4edda4e9b..e91e825f5 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -9,6 +9,7 @@ ### Bug Fixes * [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view +* [#10408](https://github.com/netbox-community/netbox/issues/10408) - Fix validation when attempting to add redundant contact assignments * [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned * [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field * [#10445](https://github.com/netbox-community/netbox/issues/10445) - Avoid rounding virtual machine memory values diff --git a/netbox/templates/tenancy/contactassignment_edit.html b/netbox/templates/tenancy/contactassignment_edit.html index 4d1747e72..d904deead 100644 --- a/netbox/templates/tenancy/contactassignment_edit.html +++ b/netbox/templates/tenancy/contactassignment_edit.html @@ -3,6 +3,9 @@ {% load form_helpers %} {% block form %} + {% for field in form.hidden_fields %} + {{ field }} + {% endfor %}
Contact Assignment
diff --git a/netbox/tenancy/forms/models.py b/netbox/tenancy/forms/models.py index 021e36a5b..eabcb1d0f 100644 --- a/netbox/tenancy/forms/models.py +++ b/netbox/tenancy/forms/models.py @@ -119,8 +119,10 @@ class ContactAssignmentForm(BootstrapMixin, forms.ModelForm): class Meta: model = ContactAssignment fields = ( - 'group', 'contact', 'role', 'priority', + 'content_type', 'object_id', 'group', 'contact', 'role', 'priority', ) widgets = { + 'content_type': forms.HiddenInput(), + 'object_id': forms.HiddenInput(), 'priority': StaticSelect(), } From 3c32c09a5a1a1156340193c2d6eda98c8a4876eb Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Wed, 28 Sep 2022 09:30:38 -0400 Subject: [PATCH 20/39] Fixes #10496: Use page.canonical_url to identify ReadTheDocs builds --- docs/_theme/main.html | 4 ++-- mkdocs.yml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/_theme/main.html b/docs/_theme/main.html index 4dfc4e14e..3ff44b9cb 100644 --- a/docs/_theme/main.html +++ b/docs/_theme/main.html @@ -2,8 +2,8 @@ {% block site_meta %} {{ super() }} - {# Disable search indexing unless we're building for ReadTheDocs #} - {% if not config.extra.readthedocs %} + {# Disable search indexing unless we're building for ReadTheDocs (see #10496) #} + {% if page.canonical_url != 'https://docs.netbox.dev/' %} {% endif %} {% endblock %} diff --git a/mkdocs.yml b/mkdocs.yml index 530c6d52e..a10fd6e67 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -38,7 +38,6 @@ plugins: show_root_toc_entry: false show_source: false extra: - readthedocs: !ENV READTHEDOCS social: - icon: fontawesome/brands/github link: https://github.com/netbox-community/netbox From 4cb6984a6591b63d3870e3a7e8b7351794f0166e Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 29 Sep 2022 18:41:33 +0300 Subject: [PATCH 21/39] GitHub Workflows security hardening (#10456) * build: harden lock.yml permissions Signed-off-by: Alex * build: harden stale.yml permissions Signed-off-by: Alex * build: harden ci.yml permissions Signed-off-by: Alex Signed-off-by: Alex --- .github/workflows/ci.yml | 2 ++ .github/workflows/lock.yml | 5 +++++ .github/workflows/stale.yml | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67f5028cd..9431863b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,7 @@ name: CI on: [push, pull_request] +permissions: + contents: read # to fetch code (actions/checkout) jobs: build: runs-on: ubuntu-latest diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 9df4bc441..b928fc128 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -5,8 +5,13 @@ on: schedule: - cron: '0 3 * * *' +permissions: {} jobs: lock: + permissions: + issues: write # to lock issues (dessant/lock-threads) + pull-requests: write # to lock PRs (dessant/lock-threads) + runs-on: ubuntu-latest steps: - uses: dessant/lock-threads@v3 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 57666417a..1df1c7044 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -4,8 +4,13 @@ on: schedule: - cron: '0 4 * * *' +permissions: {} jobs: stale: + permissions: + issues: write # to close stale issues (actions/stale) + pull-requests: write # to close stale PRs (actions/stale) + runs-on: ubuntu-latest steps: - uses: actions/stale@v5 From 309a70df8908b354cb6634071913878dd1aea4e1 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 29 Sep 2022 11:59:15 -0400 Subject: [PATCH 22/39] Tweak workflow permissions --- .github/workflows/lock.yml | 5 ++--- .github/workflows/stale.yml | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index b928fc128..4f73f66f0 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -5,12 +5,11 @@ on: schedule: - cron: '0 3 * * *' -permissions: {} jobs: lock: permissions: - issues: write # to lock issues (dessant/lock-threads) - pull-requests: write # to lock PRs (dessant/lock-threads) + issues: write + pull-requests: write runs-on: ubuntu-latest steps: diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 1df1c7044..70a2511c8 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -4,12 +4,11 @@ on: schedule: - cron: '0 4 * * *' -permissions: {} jobs: stale: permissions: - issues: write # to close stale issues (actions/stale) - pull-requests: write # to close stale PRs (actions/stale) + issues: write + pull-requests: write runs-on: ubuntu-latest steps: From cbbfcd0e7b9acba46dbaa725fd7bd02366aa1303 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 29 Sep 2022 12:00:44 -0400 Subject: [PATCH 23/39] Bump stale to v6 --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 70a2511c8..cbc8d8b87 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/stale@v5 + - uses: actions/stale@v6 with: close-issue-message: > This issue has been automatically closed due to lack of activity. In an From 04738587e80ca0cc9ecdf3a833c9af555877e902 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 29 Sep 2022 12:17:10 -0400 Subject: [PATCH 24/39] Move permissions block to root --- .github/workflows/lock.yml | 9 ++++----- .github/workflows/stale.yml | 8 +++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 4f73f66f0..a53cf728c 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -5,17 +5,16 @@ on: schedule: - cron: '0 3 * * *' +permissions: + issues: write + pull-requests: write + jobs: lock: - permissions: - issues: write - pull-requests: write - runs-on: ubuntu-latest steps: - uses: dessant/lock-threads@v3 with: - github-token: ${{ github.token }} issue-inactive-days: 90 pr-inactive-days: 30 issue-lock-reason: 'resolved' diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index cbc8d8b87..68e475f24 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,14 +1,16 @@ # close-stale-issues (https://github.com/marketplace/actions/close-stale-issues) name: 'Close stale issues/PRs' + on: schedule: - cron: '0 4 * * *' +permissions: + issues: write + pull-requests: write + jobs: stale: - permissions: - issues: write - pull-requests: write runs-on: ubuntu-latest steps: From 62820ea2b8fc4d61f2e68390520d72bccdfff53e Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 29 Sep 2022 12:36:10 -0400 Subject: [PATCH 25/39] Add workflow_dispatch event --- .github/workflows/ci.yml | 2 +- .github/workflows/lock.yml | 1 + .github/workflows/stale.yml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9431863b7..d75f98fbc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,7 @@ name: CI on: [push, pull_request] permissions: - contents: read # to fetch code (actions/checkout) + contents: read jobs: build: runs-on: ubuntu-latest diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index a53cf728c..6019cef5d 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -4,6 +4,7 @@ name: 'Lock threads' on: schedule: - cron: '0 3 * * *' + workflow_dispatch: permissions: issues: write diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 68e475f24..ab259af2a 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -4,6 +4,7 @@ name: 'Close stale issues/PRs' on: schedule: - cron: '0 4 * * *' + workflow_dispatch: permissions: issues: write From 02ffc2ddeed9483de6e765f7f5b4205ce10ea2b3 Mon Sep 17 00:00:00 2001 From: Arthur Date: Fri, 30 Sep 2022 09:09:21 -0700 Subject: [PATCH 26/39] 10491 improve error message for ProtectedError on contact assignment --- netbox/tenancy/models/contacts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox/tenancy/models/contacts.py b/netbox/tenancy/models/contacts.py index 41881f853..1dba814a6 100644 --- a/netbox/tenancy/models/contacts.py +++ b/netbox/tenancy/models/contacts.py @@ -163,8 +163,8 @@ class ContactAssignment(WebhooksMixin, ChangeLoggedModel): def __str__(self): if self.priority: - return f"{self.contact} ({self.get_priority_display()})" - return str(self.contact) + return f"{self.contact} ({self.get_priority_display()}) -> {self.object}" + return str(f"{self.contact} -> {self.object}") def get_absolute_url(self): return reverse('tenancy:contact', args=[self.contact.pk]) From 9ef24d3f43022f61044756741f40e095e9290bc1 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 3 Oct 2022 10:39:03 -0400 Subject: [PATCH 27/39] Fixes #10513: Disable the reassignment of a module to a new device --- docs/release-notes/version-3.3.md | 1 + netbox/dcim/forms/models.py | 1 + netbox/dcim/models/devices.py | 8 ++++++++ netbox/dcim/tests/test_views.py | 5 +++-- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index e91e825f5..2c2db9e47 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -16,6 +16,7 @@ * [#10461](https://github.com/netbox-community/netbox/issues/10461) - Enable filtering by read-only custom fields in the UI * [#10470](https://github.com/netbox-community/netbox/issues/10470) - Omit read-only custom fields from CSV import forms * [#10480](https://github.com/netbox-community/netbox/issues/10480) - Cable trace SVG links should not force a new window +* [#10513](https://github.com/netbox-community/netbox/issues/10513) - Disable the reassignment of a module to a new device --- diff --git a/netbox/dcim/forms/models.py b/netbox/dcim/forms/models.py index b33023ece..1f1c869a5 100644 --- a/netbox/dcim/forms/models.py +++ b/netbox/dcim/forms/models.py @@ -679,6 +679,7 @@ class ModuleForm(NetBoxModelForm): super().__init__(*args, **kwargs) if self.instance.pk: + self.fields['device'].disabled = True self.fields['replicate_components'].initial = False self.fields['replicate_components'].disabled = True self.fields['adopt_components'].initial = False diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index ccf4613bf..4c542341e 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -987,6 +987,14 @@ class Module(NetBoxModel, ConfigContextModel): def get_absolute_url(self): return reverse('dcim:module', args=[self.pk]) + def clean(self): + super().clean() + + if self.module_bay.device != self.device: + raise ValidationError( + f"Module must be installed within a module bay belonging to the assigned device ({self.device})." + ) + def save(self, *args, **kwargs): is_new = self.pk is None diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 50b36e36d..db3495521 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1778,10 +1778,12 @@ class ModuleTestCase( ModuleBay(device=devices[0], name='Module Bay 2'), ModuleBay(device=devices[0], name='Module Bay 3'), ModuleBay(device=devices[0], name='Module Bay 4'), + ModuleBay(device=devices[0], name='Module Bay 5'), ModuleBay(device=devices[1], name='Module Bay 1'), ModuleBay(device=devices[1], name='Module Bay 2'), ModuleBay(device=devices[1], name='Module Bay 3'), ModuleBay(device=devices[1], name='Module Bay 4'), + ModuleBay(device=devices[1], name='Module Bay 5'), ) ModuleBay.objects.bulk_create(module_bays) @@ -1795,7 +1797,7 @@ class ModuleTestCase( tags = create_tags('Alpha', 'Bravo', 'Charlie') cls.form_data = { - 'device': devices[1].pk, + 'device': devices[0].pk, 'module_bay': module_bays[3].pk, 'module_type': module_types[0].pk, 'serial': 'A', @@ -1867,7 +1869,6 @@ class ModuleTestCase( self.assertIsNone(interface.module) # Create a module with adopted components - form_data['module_bay'] = ModuleBay.objects.filter(device=device).first() form_data['module_type'] = module_type form_data['replicate_components'] = False form_data['adopt_components'] = True From 0b6a3898fe0970b77928c9cf99588af8c7f2dc4a Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Mon, 3 Oct 2022 10:55:05 -0700 Subject: [PATCH 28/39] 8424 device location (#10544) * 8424 fix merge * 8424 fix merge * 8424 fix merge * 8424 fix merge --- netbox/dcim/views.py | 1 + netbox/templates/dcim/device.html | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 7a6aecc8e..5930d6b2d 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -1616,6 +1616,7 @@ class DeviceView(generic.ObjectView): return { 'services': services, 'vc_members': vc_members, + 'svg_extra': f'highlight=id:{instance.pk}' } diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index 253d905f2..d800658a5 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -7,7 +7,7 @@ {% block content %}
-
+
Device @@ -153,7 +153,7 @@ {% include 'inc/panels/comments.html' %} {% plugin_left_page object %}
-
+
Management
@@ -286,6 +286,22 @@
{% include 'inc/panels/contacts.html' %} {% include 'inc/panels/image_attachments.html' %} + {% if object.rack and object.position %} +
+
+
+

Front

+ {% include 'dcim/inc/rack_elevation.html' with object=object.rack face='front' extra_params=svg_extra %} +
+
+
+
+

Rear

+ {% include 'dcim/inc/rack_elevation.html' with object=object.rack face='rear' extra_params=svg_extra %} +
+
+
+ {% endif %} {% plugin_right_page object %}
From cf062b5b6aeb1f496f2a0670090c8349efa8fc73 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 3 Oct 2022 13:56:46 -0400 Subject: [PATCH 29/39] Closes #10346: Document how to access plugin config parameters --- docs/plugins/development/index.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/plugins/development/index.md b/docs/plugins/development/index.md index 98db9e0bb..a2f3b8ce9 100644 --- a/docs/plugins/development/index.md +++ b/docs/plugins/development/index.md @@ -112,6 +112,14 @@ NetBox looks for the `config` variable within a plugin's `__init__.py` to load i All required settings must be configured by the user. If a configuration parameter is listed in both `required_settings` and `default_settings`, the default setting will be ignored. +!!! tip "Accessing Config Parameters" + Plugin configuration parameters can be accessed in `settings.PLUGINS_CONFIG`, mapped by plugin name. For example: + + ```python + from django.conf import settings + settings.PLUGINS_CONFIG['myplugin']['verbose_name'] + ``` + ## Create setup.py `setup.py` is the [setup script](https://docs.python.org/3.8/distutils/setupscript.html) used to package and install our plugin once it's finished. The primary function of this script is to call the setuptools library's `setup()` function to create a Python distribution package. We can pass a number of keyword arguments to control the package creation as well as to provide metadata about the plugin. An example `setup.py` is below: From aabee05a6ab02adcf008e51a3b71c52d5ce1685b Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 3 Oct 2022 13:58:04 -0400 Subject: [PATCH 30/39] Changelog for #8424, #10491 --- docs/release-notes/version-3.3.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 2c2db9e47..897cd7f38 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -4,6 +4,7 @@ ### Enhancements +* [#8424](https://github.com/netbox-community/netbox/issues/8424) - Include rack elevation under device view * [#10465](https://github.com/netbox-community/netbox/issues/10465) - Improve formatting of device heights and rack positions ### Bug Fixes @@ -16,6 +17,7 @@ * [#10461](https://github.com/netbox-community/netbox/issues/10461) - Enable filtering by read-only custom fields in the UI * [#10470](https://github.com/netbox-community/netbox/issues/10470) - Omit read-only custom fields from CSV import forms * [#10480](https://github.com/netbox-community/netbox/issues/10480) - Cable trace SVG links should not force a new window +* [#10491](https://github.com/netbox-community/netbox/issues/10491) - Clarify representation of blocking contact assignments during contact deletion * [#10513](https://github.com/netbox-community/netbox/issues/10513) - Disable the reassignment of a module to a new device --- From d1efbf662005aeed91fa21fa26e34de3e307bb50 Mon Sep 17 00:00:00 2001 From: PieterL75 <74899468+PieterL75@users.noreply.github.com> Date: Mon, 3 Oct 2022 20:32:01 +0200 Subject: [PATCH 31/39] Issue10352 removegetvariables (#10475) * Add javascript to disable empty form fields * add js cleanGetUrl * use addEventListener submit * use addEventListener * update collectstatics * Use FormData to remove empty fields * optimeze ts-ignore * update ts-ignore comment * oneline of ts-ignore * one line of ts-ingnore * fix tsc errors by adding types (as per kkthxbye) Co-authored-by: Pieter Lambrecht --- netbox/project-static/dist/netbox.js | Bin 374422 -> 374623 bytes netbox/project-static/dist/netbox.js.map | Bin 344131 -> 344325 bytes netbox/project-static/src/netbox.ts | 14 ++++++++++++++ 3 files changed, 14 insertions(+) diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index 6d0aa15358c6a96b7df28bd75793d2fd96670267..fe7a7e56901cbd2a09c93c5ff269ded0f07d8d84 100644 GIT binary patch delta 237 zcmW-au}T9$6h%?97Gm11*DaPA2&1JCrVtei3mdJ(V#vNt0yB5w+gU+GwAeooOzjt# zLhy6^0{sPjvAMqF`>lTPk^R0OHjzU+mQ;6+3qlc_B0&>OpfroM zN%3m2AU<|2DQ#_ec6wP>6}`M&F7M3ln|JP5~@n+?ler*G*7*9!_qOEOSX-LsT7HUGb*&xK1_YVass}N* z=j?RA&U&WonMoj*S`%Iwr#~(lW33PYaz&s9*lK%LjXp){AWjUP&r?aB5p705aPoXt G#p4HLC_O9y delta 28 jcmZo|5Ry*;zDq0{sd2iA!Ij=c#` diff --git a/netbox/project-static/src/netbox.ts b/netbox/project-static/src/netbox.ts index c178a2dbd..9bf23410d 100644 --- a/netbox/project-static/src/netbox.ts +++ b/netbox/project-static/src/netbox.ts @@ -37,6 +37,20 @@ function initDocument(): void { } function initWindow(): void { + + const documentForms = document.forms + for (var documentForm of documentForms) { + if (documentForm.method.toUpperCase() == 'GET') { + // @ts-ignore: Our version of typescript seems to be too old for FormDataEvent + documentForm.addEventListener('formdata', function(event: FormDataEvent) { + let formData: FormData = event.formData; + for (let [name, value] of Array.from(formData.entries())) { + if (value === '') formData.delete(name); + } + }); + } + } + const contentContainer = document.querySelector('.content-container'); if (contentContainer !== null) { // Focus the content container for accessible navigation. From 7feb86fe55db68827fcae8c81ce6668eb1bfd0dd Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 3 Oct 2022 15:03:28 -0400 Subject: [PATCH 32/39] Changelog for #10352 --- docs/release-notes/version-3.3.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 897cd7f38..378eb993e 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -5,6 +5,7 @@ ### Enhancements * [#8424](https://github.com/netbox-community/netbox/issues/8424) - Include rack elevation under device view +* [#10352](https://github.com/netbox-community/netbox/issues/10352) - Omit extraneous URL query attributes during search * [#10465](https://github.com/netbox-community/netbox/issues/10465) - Improve formatting of device heights and rack positions ### Bug Fixes From 7712b81ab9f634c4281023588aba284041dda5a3 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 3 Oct 2022 15:35:45 -0400 Subject: [PATCH 33/39] Fixes #10517: Automatically inherit site assignment from cluster when creating a virtual machine --- docs/release-notes/version-3.3.md | 1 + netbox/virtualization/models.py | 4 +++- netbox/virtualization/tests/test_models.py | 7 ++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 378eb993e..6d2bb3b5c 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -20,6 +20,7 @@ * [#10480](https://github.com/netbox-community/netbox/issues/10480) - Cable trace SVG links should not force a new window * [#10491](https://github.com/netbox-community/netbox/issues/10491) - Clarify representation of blocking contact assignments during contact deletion * [#10513](https://github.com/netbox-community/netbox/issues/10513) - Disable the reassignment of a module to a new device +* [#10517](https://github.com/netbox-community/netbox/issues/10517) - Automatically inherit site assignment from cluster when creating a virtual machine --- diff --git a/netbox/virtualization/models.py b/netbox/virtualization/models.py index abad57f88..69376d9c5 100644 --- a/netbox/virtualization/models.py +++ b/netbox/virtualization/models.py @@ -347,10 +347,12 @@ class VirtualMachine(NetBoxModel, ConfigContextModel): }) # Validate site for cluster & device - if self.cluster and self.cluster.site != self.site: + if self.cluster and self.site and self.cluster.site != self.site: raise ValidationError({ 'cluster': f'The selected cluster ({self.cluster} is not assigned to this site ({self.site}).' }) + elif self.cluster: + self.site = self.cluster.site if self.device and self.device.site != self.site: raise ValidationError({ 'device': f'The selected device ({self.device} is not assigned to this site ({self.site}).' diff --git a/netbox/virtualization/tests/test_models.py b/netbox/virtualization/tests/test_models.py index df5816efa..e916486b0 100644 --- a/netbox/virtualization/tests/test_models.py +++ b/netbox/virtualization/tests/test_models.py @@ -68,6 +68,7 @@ class VirtualMachineTestCase(TestCase): with self.assertRaises(ValidationError): VirtualMachine(name='vm1', site=sites[0], cluster=clusters[1]).full_clean() - # VM with cluster site but no direct site should fail - with self.assertRaises(ValidationError): - VirtualMachine(name='vm1', site=None, cluster=clusters[0]).full_clean() + # VM with cluster site but no direct site should have its site set automatically + vm = VirtualMachine(name='vm1', site=None, cluster=clusters[0]) + vm.full_clean() + self.assertEqual(vm.site, sites[0]) From eef5cefb5d8a8c5f60a015c09f0051a76b0d12ca Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 3 Oct 2022 16:11:24 -0400 Subject: [PATCH 34/39] Fixes #10460: Restore missing connection details for device components --- docs/release-notes/version-3.3.md | 1 + netbox/templates/dcim/consoleport.html | 104 ++++++------------ netbox/templates/dcim/consoleserverport.html | 104 ++++++------------ .../templates/dcim/inc/cabletermination.html | 14 --- .../dcim/inc/connection_endpoints.html | 36 ++++++ netbox/templates/dcim/interface.html | 86 +-------------- netbox/templates/dcim/powerfeed.html | 88 ++++----------- netbox/templates/dcim/poweroutlet.html | 82 ++++---------- netbox/templates/dcim/powerport.html | 102 ++++++----------- 9 files changed, 178 insertions(+), 439 deletions(-) delete mode 100644 netbox/templates/dcim/inc/cabletermination.html create mode 100644 netbox/templates/dcim/inc/connection_endpoints.html diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 6d2bb3b5c..4b7b76270 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -15,6 +15,7 @@ * [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned * [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field * [#10445](https://github.com/netbox-community/netbox/issues/10445) - Avoid rounding virtual machine memory values +* [#10460](https://github.com/netbox-community/netbox/issues/10460) - Restore missing connection details for device components * [#10461](https://github.com/netbox-community/netbox/issues/10461) - Enable filtering by read-only custom fields in the UI * [#10470](https://github.com/netbox-community/netbox/issues/10470) - Omit read-only custom fields from CSV import forms * [#10480](https://github.com/netbox-community/netbox/issues/10480) - Cable trace SVG links should not force a new window diff --git a/netbox/templates/dcim/consoleport.html b/netbox/templates/dcim/consoleport.html index 39ffbf552..ad4f15c9d 100644 --- a/netbox/templates/dcim/consoleport.html +++ b/netbox/templates/dcim/consoleport.html @@ -54,80 +54,40 @@ {% plugin_left_page object %}
-
-
- Connection -
-
- {% if object.mark_connected %} - Marked as connected - {% elif object.cable %} - - - - - - {% if object.connected_endpoint %} - - - - - - - - - - - - - - - - - - - - - {% endif %} -
Cable - {{ object.cable|linkify }} - - - -
Device{{ object.connected_endpoint.device|linkify }}
Name{{ object.connected_endpoint|linkify:"name" }}
Type{{ object.connected_endpoint.get_type_display|placeholder }}
Description{{ object.connected_endpoint.description|placeholder }}
Path Status - {% if object.path.is_active %} - Reachable - {% else %} - Not Reachable - {% endif %} -
- {% else %} -
- Not Connected - {% if perms.dcim.add_cable %} - - {% endif %} -
- {% endif %} +
+
Connection
+
+ {% if object.mark_connected %} + Marked as connected + {% elif object.cable %} + {% include 'dcim/inc/connection_endpoints.html' %} + {% else %} +
+ Not Connected + {% if perms.dcim.add_cable %} + + {% endif %}
+ {% endif %}
- {% include 'dcim/inc/panels/inventory_items.html' %} - {% plugin_right_page object %} +
+ {% include 'dcim/inc/panels/inventory_items.html' %} + {% plugin_right_page object %}
diff --git a/netbox/templates/dcim/consoleserverport.html b/netbox/templates/dcim/consoleserverport.html index 642e758a3..a543cd5ff 100644 --- a/netbox/templates/dcim/consoleserverport.html +++ b/netbox/templates/dcim/consoleserverport.html @@ -54,82 +54,40 @@ {% plugin_left_page object %}
-
-
- Connection -
-
- {% if object.mark_connected %} - Marked as connected - {% elif object.cable %} - - - - - - {% if object.connected_endpoint %} - - - - - - - - - - - - - - - - - - - - - {% endif %} -
Cable - {{ object.cable|linkify }} - - - -
Device - {{ object.connected_endpoint.device|linkify }} -
Name{{ object.connected_endpoint|linkify:"name" }}
Type{{ object.connected_endpoint.get_type_display|placeholder }}
Description{{ object.connected_endpoint.description|placeholder }}
Path Status - {% if object.path.is_active %} - Reachable - {% else %} - Not Reachable - {% endif %} -
- {% else %} -
- Not Connected - {% if perms.dcim.add_cable %} - - {% endif %} +
+
Connection
+
+ {% if object.mark_connected %} + Marked as connected + {% elif object.cable %} + {% include 'dcim/inc/connection_endpoints.html' %} + {% else %} +
+ Not Connected + {% if perms.dcim.add_cable %} + - {% endif %} + {% endif %}
+ {% endif %}
- {% include 'dcim/inc/panels/inventory_items.html' %} - {% plugin_right_page object %} +
+ {% include 'dcim/inc/panels/inventory_items.html' %} + {% plugin_right_page object %}
diff --git a/netbox/templates/dcim/inc/cabletermination.html b/netbox/templates/dcim/inc/cabletermination.html deleted file mode 100644 index c7fa7918a..000000000 --- a/netbox/templates/dcim/inc/cabletermination.html +++ /dev/null @@ -1,14 +0,0 @@ - - {% if termination.parent_object.provider %} - - - {{ termination.parent_object.provider }} - {{ termination.parent_object }} - - {% else %} - {{ termination.parent_object|linkify }} - {% endif %} - - - {{ termination|linkify }} - diff --git a/netbox/templates/dcim/inc/connection_endpoints.html b/netbox/templates/dcim/inc/connection_endpoints.html new file mode 100644 index 000000000..fb994a492 --- /dev/null +++ b/netbox/templates/dcim/inc/connection_endpoints.html @@ -0,0 +1,36 @@ + + + + + + + + + + + + + +
Cable + {{ object.cable|linkify }} + + + +
Path Status + {% if object.path.is_complete and object.path.is_active %} + Reachable + {% else %} + Not Reachable + {% endif %} +
Path Endpoints + {% for endpoint in object.connected_endpoints %} + {% if endpoint.parent_object %} + {{ endpoint.parent_object|linkify }} + + {% endif %} + {{ endpoint|linkify }} + {% if not forloop.last %}
{% endif %} + {% empty %} + {{ ''|placeholder }} + {% endfor %} +
diff --git a/netbox/templates/dcim/interface.html b/netbox/templates/dcim/interface.html index 1216f3e88..887433d7b 100644 --- a/netbox/templates/dcim/interface.html +++ b/netbox/templates/dcim/interface.html @@ -144,89 +144,7 @@ Marked as Connected
{% elif object.cable %} - - {% if object.connected_endpoint.device %} - - - - {% endif %} - - - - - {% if object.connected_endpoint.device %} - {% with iface=object.connected_endpoint %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {% endwith %} - {% elif object.connected_endpoint.circuit %} - {% with ct=object.connected_endpoint %} - - - - - - - - - - - - - {% endwith %} - {% endif %} - - - - -
- {% if object.connected_endpoint.enabled %} - Enabled - {% else %} - Disabled - {% endif %} -
Cable - {{ object.cable|linkify }} - - - -
Device{{ iface.device|linkify }}
Name{{ iface|linkify:"name" }}
Type{{ iface.get_type_display }}
LAG{{ iface.lag|linkify|placeholder }}
Description{{ iface.description|placeholder }}
MTU{{ iface.mtu|placeholder }}
MAC Address{{ iface.mac_address|placeholder }}
802.1Q Mode{{ iface.get_mode_display }}
Provider{{ ct.circuit.provider|linkify }}
Circuit{{ ct.circuit|linkify }}
Side{{ ct.term_side }}
Path Status - {% if object.path.is_complete and object.path.is_active %} - Reachable - {% else %} - Not Reachable - {% endif %} -
+ {% include 'dcim/inc/connection_endpoints.html' %} {% elif object.wireless_link %} @@ -238,7 +156,7 @@ - {% with peer_interface=object.connected_endpoint %} + {% with peer_interface=object.link_peers.0 %} diff --git a/netbox/templates/dcim/powerfeed.html b/netbox/templates/dcim/powerfeed.html index 584454df8..adb779ce3 100644 --- a/netbox/templates/dcim/powerfeed.html +++ b/netbox/templates/dcim/powerfeed.html @@ -100,73 +100,33 @@ {% plugin_left_page object %}
-
-
- Connection -
-
- {% if object.mark_connected %} -
- Marked as connected -
- {% elif object.cable %} -
Device {{ peer_interface.device|linkify }}
- - - - - {% if object.connected_endpoint %} - - - - - - - - - - - - - - - - - - - - - {% endif %} -
Cable - {{ object.cable|linkify }} - - - -
Device{{ object.connected_endpoint.device|linkify }}
Name{{ object.connected_endpoint|linkify:"name" }}
Type{{ object.connected_endpoint.get_type_display|placeholder }}
Description{{ object.connected_endpoint.description|placeholder }}
Path Status - {% if object.path.is_active %} - Reachable - {% else %} - Not Reachable - {% endif %} -
- {% else %} -
- Not connected -
- {% endif %} +
+
Connection
+
+ {% if object.mark_connected %} +
+ Marked as connected
- {% if not object.mark_connected and not object.cable %} - - {% include 'inc/panels/comments.html' %} - {% plugin_right_page object %} + {% if not object.mark_connected and not object.cable %} + + {% endif %} +
+ {% include 'inc/panels/comments.html' %} + {% plugin_right_page object %}
diff --git a/netbox/templates/dcim/poweroutlet.html b/netbox/templates/dcim/poweroutlet.html index 26f4a07f8..fb6de8ddb 100644 --- a/netbox/templates/dcim/poweroutlet.html +++ b/netbox/templates/dcim/poweroutlet.html @@ -58,69 +58,29 @@ {% plugin_left_page object %}
-
-
- Connection -
-
- {% if object.mark_connected %} -
- Marked as Connected -
- {% elif object.cable %} - - - - - - {% if object.connected_endpoint %} - - - - - - - - - - - - - - - - - - - - - {% endif %} -
Cable - {{ object.cable|linkify }} - - - -
Device{{ object.connected_endpoint.device|linkify }}
Name{{ object.connected_endpoint|linkify:"name" }}
Type{{ object.connected_endpoint.get_type_display|placeholder }}
Description{{ object.connected_endpoint.description|placeholder }}
Path Status - {% if object.path.is_active %} - Reachable - {% else %} - Not Reachable - {% endif %} -
- {% else %} -
- Not Connected - {% if perms.dcim.add_cable %} - - Connect - - {% endif %} -
- {% endif %} +
+
Connection
+
+ {% if object.mark_connected %} +
+ Marked as Connected
+ {% elif object.cable %} + {% include 'dcim/inc/connection_endpoints.html' %} + {% else %} +
+ Not Connected + {% if perms.dcim.add_cable %} + + Connect + + {% endif %} +
+ {% endif %}
- {% include 'dcim/inc/panels/inventory_items.html' %} - {% plugin_right_page object %} +
+ {% include 'dcim/inc/panels/inventory_items.html' %} + {% plugin_right_page object %}
diff --git a/netbox/templates/dcim/powerport.html b/netbox/templates/dcim/powerport.html index c5eccbf14..c552c2398 100644 --- a/netbox/templates/dcim/powerport.html +++ b/netbox/templates/dcim/powerport.html @@ -58,79 +58,39 @@ {% plugin_left_page object %}
-
-
- Connection -
-
- {% if object.mark_connected %} -
- Marked as Connected -
- {% elif object.cable %} - - - - - - {% if object.connected_endpoint %} - - - - - - - - - - - - - - - - - - - - - {% endif %} -
Cable - {{ object.cable|linkify }} - - - -
Device{{ object.connected_endpoint.device|linkify }}
Name{{ object.connected_endpoint|linkify:"name" }}
Type{{ object.connected_endpoint.get_type_display|placeholder }}
Description{{ object.connected_endpoint.description|placeholder }}
Path Status - {% if object.path.is_active %} - Reachable - {% else %} - Not Reachable - {% endif %} -
- {% else %} -
- Not Connected - {% if perms.dcim.add_cable %} - - - - - {% endif %} -
- {% endif %} +
+
Connection
+
+ {% if object.mark_connected %} +
+ Marked as Connected
+ {% elif object.cable %} + {% include 'dcim/inc/connection_endpoints.html' %} + {% else %} +
+ Not Connected + {% if perms.dcim.add_cable %} + + + + + {% endif %} +
+ {% endif %}
- {% include 'dcim/inc/panels/inventory_items.html' %} - {% plugin_right_page object %} +
+ {% include 'dcim/inc/panels/inventory_items.html' %} + {% plugin_right_page object %}
From 53f5f4603735980c18c1890217b6e9e442f8fe19 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 4 Oct 2022 14:36:14 -0400 Subject: [PATCH 35/39] #10460: Fix PowerFeed details --- netbox/templates/dcim/powerfeed.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/netbox/templates/dcim/powerfeed.html b/netbox/templates/dcim/powerfeed.html index adb779ce3..54ac96bab 100644 --- a/netbox/templates/dcim/powerfeed.html +++ b/netbox/templates/dcim/powerfeed.html @@ -41,8 +41,8 @@ Connected Device - {% if object.connected_endpoint %} - {{ object.connected_endpoint.device|linkify }} ({{ object.connected_endpoint }}) + {% if object.connected_endpoints %} + {{ object.connected_endpoints.0.device|linkify }} ({{ object.connected_endpoints.0|linkify:"name" }}) {% else %} {{ ''|placeholder }} {% endif %} @@ -50,7 +50,7 @@ Utilization (Allocated) - {% with utilization=object.connected_endpoint.get_power_draw %} + {% with utilization=object.connected_endpoints.0.get_power_draw %} {% if utilization %} {{ utilization.allocated }}VA / {{ object.available_power }}VA From fec8d1bc2f1459018d248a277ee69853f1a2beb4 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 4 Oct 2022 15:26:52 -0400 Subject: [PATCH 36/39] Fixes #10423: Enforce object type validation when creating journal entries --- docs/release-notes/version-3.3.md | 1 + netbox/extras/models/models.py | 8 ++++++++ netbox/netbox/models/__init__.py | 3 +-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 4b7b76270..92d93f5c8 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -12,6 +12,7 @@ * [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view * [#10408](https://github.com/netbox-community/netbox/issues/10408) - Fix validation when attempting to add redundant contact assignments +* [#10423](https://github.com/netbox-community/netbox/issues/10423) - Enforce object type validation when creating journal entries * [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned * [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field * [#10445](https://github.com/netbox-community/netbox/issues/10445) - Avoid rounding virtual machine memory values diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index 0df34c146..1bcc91d62 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -463,6 +463,14 @@ class JournalEntry(CustomFieldsMixin, CustomLinksMixin, TagsMixin, WebhooksMixin def get_absolute_url(self): return reverse('extras:journalentry', args=[self.pk]) + def clean(self): + super().clean() + + # Prevent the creation of journal entries on unsupported models + permitted_types = ContentType.objects.filter(FeatureQuery('journaling').get_query()) + if self.assigned_object_type not in permitted_types: + raise ValidationError(f"Journaling is not supported for this object type ({self.assigned_object_type}).") + def get_kind_color(self): return JournalEntryKindChoices.colors.get(self.kind) diff --git a/netbox/netbox/models/__init__.py b/netbox/netbox/models/__init__.py index aefb733b4..1385dd585 100644 --- a/netbox/netbox/models/__init__.py +++ b/netbox/netbox/models/__init__.py @@ -20,7 +20,6 @@ class NetBoxFeatureSet( CustomLinksMixin, CustomValidationMixin, ExportTemplatesMixin, - JournalingMixin, TagsMixin, WebhooksMixin ): @@ -51,7 +50,7 @@ class ChangeLoggedModel(ChangeLoggingMixin, CustomValidationMixin, models.Model) abstract = True -class NetBoxModel(CloningMixin, NetBoxFeatureSet, models.Model): +class NetBoxModel(CloningMixin, JournalingMixin, NetBoxFeatureSet, models.Model): """ Primary models represent real objects within the infrastructure being modeled. """ From 03946f2ca868dc21d8819f4db29107822b2a2c74 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 4 Oct 2022 15:46:55 -0400 Subject: [PATCH 37/39] Fixes #10559: Permit the pinning of a VM to a particular device within a cluster which has no site assignment --- docs/release-notes/version-3.3.md | 1 + netbox/templates/virtualization/cluster.html | 4 ++-- netbox/virtualization/models.py | 8 ++------ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 92d93f5c8..d4dcc83d6 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -23,6 +23,7 @@ * [#10491](https://github.com/netbox-community/netbox/issues/10491) - Clarify representation of blocking contact assignments during contact deletion * [#10513](https://github.com/netbox-community/netbox/issues/10513) - Disable the reassignment of a module to a new device * [#10517](https://github.com/netbox-community/netbox/issues/10517) - Automatically inherit site assignment from cluster when creating a virtual machine +* [#10559](https://github.com/netbox-community/netbox/issues/10559) - Permit the pinning of a VM to a particular device within a cluster which has no site assignment --- diff --git a/netbox/templates/virtualization/cluster.html b/netbox/templates/virtualization/cluster.html index 8acbb61f4..bf7c8a69a 100644 --- a/netbox/templates/virtualization/cluster.html +++ b/netbox/templates/virtualization/cluster.html @@ -21,7 +21,7 @@ Group - {{ object.group|linkify }} + {{ object.group|linkify|placeholder }} Tenant @@ -34,7 +34,7 @@ Site - {{ object.site|linkify }} + {{ object.site|linkify|placeholder }} Virtual Machines diff --git a/netbox/virtualization/models.py b/netbox/virtualization/models.py index 69376d9c5..b07e51790 100644 --- a/netbox/virtualization/models.py +++ b/netbox/virtualization/models.py @@ -349,14 +349,10 @@ class VirtualMachine(NetBoxModel, ConfigContextModel): # Validate site for cluster & device if self.cluster and self.site and self.cluster.site != self.site: raise ValidationError({ - 'cluster': f'The selected cluster ({self.cluster} is not assigned to this site ({self.site}).' + 'cluster': f'The selected cluster ({self.cluster}) is not assigned to this site ({self.site}).' }) elif self.cluster: self.site = self.cluster.site - if self.device and self.device.site != self.site: - raise ValidationError({ - 'device': f'The selected device ({self.device} is not assigned to this site ({self.site}).' - }) # Validate assigned cluster device if self.device and not self.cluster: @@ -365,7 +361,7 @@ class VirtualMachine(NetBoxModel, ConfigContextModel): }) if self.device and self.device not in self.cluster.devices.all(): raise ValidationError({ - 'device': f'The selected device ({self.device} is not assigned to this cluster ({self.cluster}).' + 'device': f'The selected device ({self.device}) is not assigned to this cluster ({self.cluster}).' }) # Validate primary IP addresses From bdefd8ea8c91d2d31fefd2133312451896e27042 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Wed, 5 Oct 2022 08:13:33 -0400 Subject: [PATCH 38/39] Fixes #10562: Correct URL for contacts table tags column --- docs/release-notes/version-3.3.md | 1 + netbox/tenancy/tables/tenants.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index d4dcc83d6..9314cc8eb 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -24,6 +24,7 @@ * [#10513](https://github.com/netbox-community/netbox/issues/10513) - Disable the reassignment of a module to a new device * [#10517](https://github.com/netbox-community/netbox/issues/10517) - Automatically inherit site assignment from cluster when creating a virtual machine * [#10559](https://github.com/netbox-community/netbox/issues/10559) - Permit the pinning of a VM to a particular device within a cluster which has no site assignment +* [#10562](https://github.com/netbox-community/netbox/issues/10562) - Correct URL for contacts table tags column --- diff --git a/netbox/tenancy/tables/tenants.py b/netbox/tenancy/tables/tenants.py index 8f18423be..f18f1db09 100644 --- a/netbox/tenancy/tables/tenants.py +++ b/netbox/tenancy/tables/tenants.py @@ -42,7 +42,7 @@ class TenantTable(NetBoxTable): linkify_item=True ) tags = columns.TagColumn( - url_name='tenancy:tenant_list' + url_name='tenancy:contact_list' ) class Meta(NetBoxTable.Meta): From 1c69bfaf2c8aa39f0764281d694accdc84e36883 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Wed, 5 Oct 2022 09:47:55 -0400 Subject: [PATCH 39/39] Release v3.3.5 --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- .github/ISSUE_TEMPLATE/feature_request.yaml | 2 +- base_requirements.txt | 5 +++-- docs/release-notes/version-3.3.md | 2 +- netbox/netbox/settings.py | 2 +- requirements.txt | 18 +++++++++--------- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 11b7e9aff..907ad6cf7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.3.4 + placeholder: v3.3.5 validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index bc00a3921..3cd9bc4ee 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.3.4 + placeholder: v3.3.5 validations: required: true - type: dropdown diff --git a/base_requirements.txt b/base_requirements.txt index 363f97b31..cc8695d6c 100644 --- a/base_requirements.txt +++ b/base_requirements.txt @@ -68,7 +68,7 @@ drf-yasg[validation] # Django wrapper for Graphene (GraphQL support) # https://github.com/graphql-python/graphene-django -graphene_django +graphene_django<3.0 # WSGI HTTP server # https://gunicorn.org/ @@ -80,7 +80,8 @@ Jinja2 # Simple markup language for rendering HTML # https://github.com/Python-Markdown/markdown -Markdown +# mkdocs currently requires Markdown v3.3 +Markdown<3.4 # File inclusion plugin for Python-Markdown # https://github.com/cmacmackin/markdown-include diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index 9314cc8eb..daf542022 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -1,6 +1,6 @@ # NetBox v3.3 -## v3.3.5 (FUTURE) +## v3.3.5 (2022-10-05) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index cfd4d231c..03e7eacc0 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -29,7 +29,7 @@ django.utils.encoding.force_text = force_str # Environment setup # -VERSION = '3.3.5-dev' +VERSION = '3.3.5' # Hostname HOSTNAME = platform.node() diff --git a/requirements.txt b/requirements.txt index f868c4f0d..ead32eeae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,10 @@ bleach==5.0.1 -Django==4.0.7 +Django==4.0.8 django-cors-headers==3.13.0 -django-debug-toolbar==3.6.0 +django-debug-toolbar==3.7.0 django-filter==22.1 django-graphiql-debug-toolbar==0.2.0 -django-mptt==0.13.4 +django-mptt==0.14 django-pglocks==1.0.4 django-prometheus==2.2.0 django-redis==5.2.0 @@ -13,24 +13,24 @@ django-rq==2.5.1 django-tables2==2.4.1 django-taggit==3.0.0 django-timezone-field==5.0 -djangorestframework==3.13.1 -drf-yasg[validation]==1.21.3 +djangorestframework==3.14.0 +drf-yasg[validation]==1.21.4 graphene-django==2.15.0 gunicorn==20.1.0 Jinja2==3.1.2 -Markdown==3.4.1 -mkdocs-material==8.5.1 +Markdown==3.3.7 +mkdocs-material==8.5.6 mkdocstrings[python-legacy]==0.19.0 netaddr==0.8.0 Pillow==9.2.0 psycopg2-binary==2.9.3 PyYAML==6.0 -sentry-sdk==1.9.8 +sentry-sdk==1.9.10 social-auth-app-django==5.0.0 social-auth-core==4.3.0 svgwrite==1.4.3 tablib==3.2.1 -tzdata==2022.2 +tzdata==2022.4 # Workaround for #7401 jsonschema==3.2.0