From cceaa5da5153d7b7684697fbca41866c8159a859 Mon Sep 17 00:00:00 2001 From: Arthur Date: Fri, 24 Mar 2023 08:32:52 -0700 Subject: [PATCH 01/38] 12049 fix passsword typo --- 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 7061274f1..a6abb8b73 100644 --- a/docs/configuration/system.md +++ b/docs/configuration/system.md @@ -38,7 +38,7 @@ In order to send email, NetBox needs an email server configured. The following i * `SERVER` - Hostname or IP address of the email server (use `localhost` if running locally) * `PORT` - TCP port to use for the connection (default: `25`) * `USERNAME` - Username with which to authenticate -* `PASSSWORD` - Password with which to authenticate +* `PASSWORD` - Password with which to authenticate * `USE_SSL` - Use SSL when connecting to the server (default: `False`) * `USE_TLS` - Use TLS when connecting to the server (default: `False`) * `SSL_CERTFILE` - Path to the PEM-formatted SSL certificate file (optional) From a7b776329a4e15ea4dca6a31f58260a637ca484e Mon Sep 17 00:00:00 2001 From: Austin de Coup-Crank <94914780+decoupca@users.noreply.github.com> Date: Tue, 28 Mar 2023 07:44:24 -0500 Subject: [PATCH 02/38] Fixes #11977: Multiple remote authentication backends (#12012) * Add suppport for REMOTE_AUTH_BACKEND as iterable * Closes #11977: Support for multiple auth backends * Tweak list casting --------- Co-authored-by: jeremystretch --- docs/configuration/remote-authentication.md | 2 +- netbox/netbox/settings.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/configuration/remote-authentication.md b/docs/configuration/remote-authentication.md index 07adf5c6a..1fda8d0d3 100644 --- a/docs/configuration/remote-authentication.md +++ b/docs/configuration/remote-authentication.md @@ -16,7 +16,7 @@ If true, NetBox will automatically create local accounts for users authenticated Default: `'netbox.authentication.RemoteUserBackend'` -This is the Python path to the custom [Django authentication backend](https://docs.djangoproject.com/en/stable/topics/auth/customizing/) to use for external user authentication. NetBox provides two built-in backends (listed below), though custom authentication backends may also be provided by other packages or plugins. +This is the Python path to the custom [Django authentication backend](https://docs.djangoproject.com/en/stable/topics/auth/customizing/) to use for external user authentication. NetBox provides two built-in backends (listed below), though custom authentication backends may also be provided by other packages or plugins. Provide a string for a single backend, or an iterable for multiple backends, which will be attempted in the order given. * `netbox.authentication.RemoteUserBackend` * `netbox.authentication.LDAPBackend` diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 45fe32841..cf2b06a8b 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -396,8 +396,10 @@ TEMPLATES = [ ] # Set up authentication backends +if type(REMOTE_AUTH_BACKEND) not in (list, tuple): + REMOTE_AUTH_BACKEND = [REMOTE_AUTH_BACKEND] AUTHENTICATION_BACKENDS = [ - REMOTE_AUTH_BACKEND, + *REMOTE_AUTH_BACKEND, 'netbox.authentication.ObjectPermissionBackend', ] From d93852b380277eaa984ce95c174f7171fd3e8a46 Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 21 Mar 2023 15:35:44 -0700 Subject: [PATCH 03/38] 12008 make export templates cloneable --- netbox/extras/models/models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index e608f81b1..3b44b4b6b 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -280,7 +280,7 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogged } -class ExportTemplate(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel): +class ExportTemplate(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel): content_types = models.ManyToManyField( to=ContentType, related_name='export_templates', @@ -313,6 +313,10 @@ class ExportTemplate(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel): help_text=_("Download file as attachment") ) + clone_fields = ( + 'content_types', 'template_code', 'mime_type', 'file_extension', 'as_attachment', + ) + class Meta: ordering = ('name',) From af44854f8b7de6fda10a971a903dd2c0a7c3816c Mon Sep 17 00:00:00 2001 From: Arthur Date: Fri, 24 Mar 2023 08:40:59 -0700 Subject: [PATCH 04/38] 12038 fix clone tag --- netbox/extras/models/tags.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/netbox/extras/models/tags.py b/netbox/extras/models/tags.py index 827d969e3..a5a202614 100644 --- a/netbox/extras/models/tags.py +++ b/netbox/extras/models/tags.py @@ -5,7 +5,7 @@ from django.utils.text import slugify from taggit.models import TagBase, GenericTaggedItemBase from netbox.models import ChangeLoggedModel -from netbox.models.features import ExportTemplatesMixin, WebhooksMixin +from netbox.models.features import CloningMixin, ExportTemplatesMixin, WebhooksMixin from utilities.choices import ColorChoices from utilities.fields import ColorField @@ -14,7 +14,7 @@ from utilities.fields import ColorField # Tags # -class Tag(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel, TagBase): +class Tag(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel, TagBase): id = models.BigAutoField( primary_key=True ) @@ -26,6 +26,10 @@ class Tag(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel, TagBase): blank=True, ) + clone_fields = ( + 'color', 'description', + ) + class Meta: ordering = ['name'] From a958a6361992077871e0a04af6d4881d10ec39d7 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Tue, 28 Mar 2023 06:53:57 -0700 Subject: [PATCH 05/38] 11933 saved filters clone of content-types and add m2m field cloning (#12014) * 11933 saved filters clone of content-types and add m2m field cloning * Fix JSON rendering * Add content_types to CustomLink.clone() --------- Co-authored-by: jeremystretch --- netbox/extras/forms/model_forms.py | 8 ++++---- netbox/extras/models/models.py | 4 ++-- netbox/netbox/models/features.py | 7 ++++++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/netbox/extras/forms/model_forms.py b/netbox/extras/forms/model_forms.py index a21cf21e2..3fb8062e6 100644 --- a/netbox/extras/forms/model_forms.py +++ b/netbox/extras/forms/model_forms.py @@ -1,6 +1,7 @@ +import json + from django import forms from django.contrib.contenttypes.models import ContentType -from django.http import QueryDict from django.utils.translation import gettext as _ from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup @@ -128,11 +129,10 @@ class SavedFilterForm(BootstrapMixin, forms.ModelForm): def __init__(self, *args, initial=None, **kwargs): - # Convert any parameters delivered via initial data to a dictionary + # Convert any parameters delivered via initial data to JSON data if initial and 'parameters' in initial: if type(initial['parameters']) is str: - # TODO: Make a utility function for this - initial['parameters'] = dict(QueryDict(initial['parameters']).lists()) + initial['parameters'] = json.loads(initial['parameters']) super().__init__(*args, initial=initial, **kwargs) diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index 3b44b4b6b..bb22c9851 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -245,7 +245,7 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogged ) clone_fields = ( - 'enabled', 'weight', 'group_name', 'button_class', 'new_window', + 'content_types', 'enabled', 'weight', 'group_name', 'button_class', 'new_window', ) class Meta: @@ -410,7 +410,7 @@ class SavedFilter(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge parameters = models.JSONField() clone_fields = ( - 'enabled', 'weight', + 'content_types', 'weight', 'enabled', 'parameters', ) class Meta: diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index 62482a26f..71c1a7c5c 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -1,3 +1,4 @@ +import json from collections import defaultdict from functools import cached_property @@ -111,7 +112,11 @@ class CloningMixin(models.Model): for field_name in getattr(self, 'clone_fields', []): field = self._meta.get_field(field_name) field_value = field.value_from_object(self) - if field_value not in (None, ''): + if field_value and isinstance(field, models.ManyToManyField): + attrs[field_name] = [v.pk for v in field_value] + elif field_value and isinstance(field, models.JSONField): + attrs[field_name] = json.dumps(field_value) + elif field_value not in (None, ''): attrs[field_name] = field_value # Include tags (if applicable) From 78bf9fb5a2f550ce1a38bd7676bea6f49d2d4c52 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 27 Mar 2023 09:13:05 -0700 Subject: [PATCH 06/38] 12058 add clone to config context --- netbox/extras/models/configcontexts.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/netbox/extras/models/configcontexts.py b/netbox/extras/models/configcontexts.py index d8d3510d7..4a38115dd 100644 --- a/netbox/extras/models/configcontexts.py +++ b/netbox/extras/models/configcontexts.py @@ -5,7 +5,7 @@ from django.urls import reverse from extras.querysets import ConfigContextQuerySet from netbox.models import ChangeLoggedModel -from netbox.models.features import WebhooksMixin +from netbox.models.features import CloningMixin, WebhooksMixin from utilities.utils import deepmerge @@ -19,7 +19,7 @@ __all__ = ( # Config contexts # -class ConfigContext(WebhooksMixin, ChangeLoggedModel): +class ConfigContext(CloningMixin, WebhooksMixin, ChangeLoggedModel): """ A ConfigContext represents a set of arbitrary data available to any Device or VirtualMachine matching its assigned qualifiers (region, site, etc.). For example, the data stored in a ConfigContext assigned to site A and tenant B @@ -108,6 +108,12 @@ class ConfigContext(WebhooksMixin, ChangeLoggedModel): objects = ConfigContextQuerySet.as_manager() + clone_fields = ( + 'weight', 'is_active', 'regions', 'site_groups', 'sites', 'locations', 'device_types', + 'roles', 'platforms', 'cluster_types', 'cluster_groups', 'clusters', 'tenant_groups', + 'tenants', 'tags', 'data', + ) + class Meta: ordering = ['weight', 'name'] From 518e9bbb8715f8267dcf1a56ed3e3f28e8c6339c Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 28 Mar 2023 10:00:15 -0400 Subject: [PATCH 07/38] #12058: Fix initial JSON population --- netbox/extras/forms/model_forms.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/netbox/extras/forms/model_forms.py b/netbox/extras/forms/model_forms.py index 3fb8062e6..040882d27 100644 --- a/netbox/extras/forms/model_forms.py +++ b/netbox/extras/forms/model_forms.py @@ -254,6 +254,15 @@ class ConfigContextForm(BootstrapMixin, forms.ModelForm): 'tenants', 'tags', ) + def __init__(self, *args, initial=None, **kwargs): + + # Convert data delivered via initial data to JSON data + if initial and 'data' in initial: + if type(initial['data']) is str: + initial['data'] = json.loads(initial['data']) + + super().__init__(*args, initial=initial, **kwargs) + class ImageAttachmentForm(BootstrapMixin, forms.ModelForm): From f8a6fb51eb0be8085a9d39eff528025ff6b5b6a3 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 28 Mar 2023 10:02:29 -0400 Subject: [PATCH 08/38] Update changelog --- docs/release-notes/version-3.4.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/release-notes/version-3.4.md b/docs/release-notes/version-3.4.md index 6ed66a61d..3f86df99d 100644 --- a/docs/release-notes/version-3.4.md +++ b/docs/release-notes/version-3.4.md @@ -5,11 +5,19 @@ ### Enhancements * [#11833](https://github.com/netbox-community/netbox/issues/11833) - Add fieldset support for custom script forms +* [#11973](https://github.com/netbox-community/netbox/issues/11833) - Use SSID for representing wireless links, if set +* [#11977](https://github.com/netbox-community/netbox/issues/11977) - Support designating multiple backends via `REMOTE_AUTH_BACKEND` config parameter +* [#11990](https://github.com/netbox-community/netbox/issues/11990) - Improve error reporting for duplicate CSV column headings ### Bug Fixes +* [#11914](https://github.com/netbox-community/netbox/issues/11914) - Include parameters when exporting saved filters +* [#11933](https://github.com/netbox-community/netbox/issues/11933) - Fix cloning of saved filters * [#11984](https://github.com/netbox-community/netbox/issues/11984) - Remove erroneous 802.3az PoE type * [#11979](https://github.com/netbox-community/netbox/issues/11979) - Correct URL for tags in route targets list +* [#12008](https://github.com/netbox-community/netbox/issues/12008) - Enable cloning of export templates +* [#12048](https://github.com/netbox-community/netbox/issues/12048) - Enable cloning of tags +* [#12058](https://github.com/netbox-community/netbox/issues/12058) - Enable cloning of config contexts --- From c1f8a7d49f6c64470cb8364d694d4aa1a4490159 Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 21 Mar 2023 17:48:29 -0700 Subject: [PATCH 09/38] 12029 add description to virtual description add --- netbox/dcim/forms/object_create.py | 2 +- netbox/templates/dcim/virtualchassis_add.html | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/netbox/dcim/forms/object_create.py b/netbox/dcim/forms/object_create.py index 6de193043..46f783cb7 100644 --- a/netbox/dcim/forms/object_create.py +++ b/netbox/dcim/forms/object_create.py @@ -359,7 +359,7 @@ class VirtualChassisCreateForm(NetBoxModelForm): class Meta: model = VirtualChassis fields = [ - 'name', 'domain', 'region', 'site_group', 'site', 'rack', 'members', 'initial_position', 'tags', + 'name', 'domain', 'description', 'region', 'site_group', 'site', 'rack', 'members', 'initial_position', 'tags', ] def clean(self): diff --git a/netbox/templates/dcim/virtualchassis_add.html b/netbox/templates/dcim/virtualchassis_add.html index 3c0b10826..fe68a9fc7 100644 --- a/netbox/templates/dcim/virtualchassis_add.html +++ b/netbox/templates/dcim/virtualchassis_add.html @@ -8,6 +8,7 @@ {% render_field form.name %} {% render_field form.domain %} + {% render_field form.description %} {% render_field form.tags %} From 5aa58f4ea776f258c120458dfac0c23cf376a926 Mon Sep 17 00:00:00 2001 From: Arthur Date: Fri, 24 Mar 2023 08:14:24 -0700 Subject: [PATCH 10/38] 12038 show vc priority with placeholder --- netbox/templates/dcim/device.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index aa31db97c..896e4d8a5 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -139,7 +139,7 @@ {% if object.virtual_chassis.master == vc_member %}{% endif %} - {{ vc_member.vc_priority|default:"" }} + {{ vc_member.vc_priority|placeholder }} {% endfor %} From 6f9bdc122ece463d1e79d9bbb8711a9854beab75 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Tue, 28 Mar 2023 19:49:18 +0530 Subject: [PATCH 11/38] Updated _schedule_at to use local time when _interval is set (#12006) * updated _schedule_at to use local time when _interval is set * updated schedule_at to use local time when interval is set --- netbox/extras/forms/reports.py | 10 +++++++--- netbox/extras/forms/scripts.py | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/netbox/extras/forms/reports.py b/netbox/extras/forms/reports.py index d2ec01006..ed7f49304 100644 --- a/netbox/extras/forms/reports.py +++ b/netbox/extras/forms/reports.py @@ -25,12 +25,16 @@ class ReportForm(BootstrapMixin, forms.Form): help_text=_("Interval at which this report is re-run (in minutes)") ) - def clean_schedule_at(self): + def clean(self): scheduled_time = self.cleaned_data['schedule_at'] - if scheduled_time and scheduled_time < timezone.now(): + if scheduled_time and scheduled_time < local_now(): raise forms.ValidationError(_('Scheduled time must be in the future.')) - return scheduled_time + # When interval is used without schedule at, raise an exception + if self.cleaned_data['interval'] and not scheduled_time: + self.cleaned_data['schedule_at'] = local_now() + + return self.cleaned_data def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/netbox/extras/forms/scripts.py b/netbox/extras/forms/scripts.py index 8216c5413..ca7398132 100644 --- a/netbox/extras/forms/scripts.py +++ b/netbox/extras/forms/scripts.py @@ -52,7 +52,7 @@ class ScriptForm(BootstrapMixin, forms.Form): # When interval is used without schedule at, raise an exception if self.cleaned_data['_interval'] and not scheduled_time: - raise forms.ValidationError(_('Scheduled time must be set when recurs is used.')) + self.cleaned_data['_schedule_at'] = local_now() return self.cleaned_data From 1f84120cbc584043794a8c8f42383fc83ec22e3f Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 28 Mar 2023 10:21:38 -0400 Subject: [PATCH 12/38] Update changelog for #11645, #12029, #12038 --- docs/release-notes/version-3.4.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/release-notes/version-3.4.md b/docs/release-notes/version-3.4.md index 3f86df99d..fa2ba157b 100644 --- a/docs/release-notes/version-3.4.md +++ b/docs/release-notes/version-3.4.md @@ -4,6 +4,7 @@ ### Enhancements +* [#11645](https://github.com/netbox-community/netbox/issues/11645) - Automatically set the scheduled time when executing reports/scripts at a recurring interval * [#11833](https://github.com/netbox-community/netbox/issues/11833) - Add fieldset support for custom script forms * [#11973](https://github.com/netbox-community/netbox/issues/11833) - Use SSID for representing wireless links, if set * [#11977](https://github.com/netbox-community/netbox/issues/11977) - Support designating multiple backends via `REMOTE_AUTH_BACKEND` config parameter @@ -16,6 +17,8 @@ * [#11984](https://github.com/netbox-community/netbox/issues/11984) - Remove erroneous 802.3az PoE type * [#11979](https://github.com/netbox-community/netbox/issues/11979) - Correct URL for tags in route targets list * [#12008](https://github.com/netbox-community/netbox/issues/12008) - Enable cloning of export templates +* [#12029](https://github.com/netbox-community/netbox/issues/12029) - Restore missing description field on virtual chassis form +* [#12038](https://github.com/netbox-community/netbox/issues/12038) - Correct display of zero values for virtual chassis member priority * [#12048](https://github.com/netbox-community/netbox/issues/12048) - Enable cloning of tags * [#12058](https://github.com/netbox-community/netbox/issues/12058) - Enable cloning of config contexts From 0c574714febc4c7ed6176f65649bb2a6121b0ba1 Mon Sep 17 00:00:00 2001 From: kkthxbye <400797+kkthxbye-code@users.noreply.github.com> Date: Tue, 28 Mar 2023 19:20:23 +0200 Subject: [PATCH 13/38] Fixes #11991 - Add vdcs to InterfaceImportForm and InterfaceBulkEditForm (#11996) * Add vdcs to InterfaceImportForm and InterfaceBulkEditForm * Filter vdcs queryset by device when bulk importing interfaces --- netbox/dcim/forms/bulk_edit.py | 12 ++++++++++-- netbox/dcim/forms/bulk_import.py | 19 +++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index bd466ca48..24bd3e62d 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -1175,6 +1175,14 @@ class InterfaceBulkEditForm( }, label=_('LAG') ) + vdcs = DynamicModelMultipleChoiceField( + queryset=VirtualDeviceContext.objects.all(), + required=False, + label='Virtual Device Contexts', + query_params={ + 'device_id': '$device', + } + ) speed = forms.IntegerField( required=False, widget=SelectSpeedWidget(), @@ -1240,14 +1248,14 @@ class InterfaceBulkEditForm( fieldsets = ( (None, ('module', 'type', 'label', 'speed', 'duplex', 'description')), ('Addressing', ('vrf', 'mac_address', 'wwn')), - ('Operation', ('mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')), + ('Operation', ('vdcs', 'mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')), ('PoE', ('poe_mode', 'poe_type')), ('Related Interfaces', ('parent', 'bridge', 'lag')), ('802.1Q Switching', ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), ('Wireless', ('rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width')), ) nullable_fields = ( - 'module', 'label', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'mtu', 'description', + 'module', 'label', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'vdcs', 'mtu', 'description', 'poe_mode', 'poe_type', 'mode', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'vlan_group', 'untagged_vlan', 'tagged_vlans', 'vrf', ) diff --git a/netbox/dcim/forms/bulk_import.py b/netbox/dcim/forms/bulk_import.py index da658d732..d29e8e250 100644 --- a/netbox/dcim/forms/bulk_import.py +++ b/netbox/dcim/forms/bulk_import.py @@ -11,7 +11,9 @@ from dcim.models import * from ipam.models import VRF from netbox.forms import NetBoxModelImportForm from tenancy.models import Tenant -from utilities.forms import CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVTypedChoiceField, SlugField +from utilities.forms import ( + CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVTypedChoiceField, SlugField, CSVModelMultipleChoiceField +) from virtualization.models import Cluster from wireless.choices import WirelessRoleChoices from .common import ModuleCommonForm @@ -667,6 +669,12 @@ class InterfaceImportForm(NetBoxModelImportForm): to_field_name='name', help_text=_('Parent LAG interface') ) + vdcs = CSVModelMultipleChoiceField( + queryset=VirtualDeviceContext.objects.all(), + required=False, + to_field_name='name', + help_text='VDC names separated by commas, encased with double quotes (e.g. "vdc1, vdc2, vdc3")' + ) type = CSVChoiceField( choices=InterfaceTypeChoices, help_text=_('Physical medium') @@ -706,7 +714,7 @@ class InterfaceImportForm(NetBoxModelImportForm): model = Interface fields = ( 'device', 'name', 'label', 'parent', 'bridge', 'lag', 'type', 'speed', 'duplex', 'enabled', - 'mark_connected', 'mac_address', 'wwn', 'mtu', 'mgmt_only', 'description', 'poe_mode', 'poe_type', 'mode', + 'mark_connected', 'mac_address', 'wwn', 'vdcs', 'mtu', 'mgmt_only', 'description', 'poe_mode', 'poe_type', 'mode', 'vrf', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'tags' ) @@ -722,6 +730,7 @@ class InterfaceImportForm(NetBoxModelImportForm): self.fields['parent'].queryset = self.fields['parent'].queryset.filter(**params) self.fields['bridge'].queryset = self.fields['bridge'].queryset.filter(**params) self.fields['lag'].queryset = self.fields['lag'].queryset.filter(**params) + self.fields['vdcs'].queryset = self.fields['vdcs'].queryset.filter(**params) def clean_enabled(self): # Make sure enabled is True when it's not included in the uploaded data @@ -730,6 +739,12 @@ class InterfaceImportForm(NetBoxModelImportForm): else: return self.cleaned_data['enabled'] + def clean_vdcs(self): + for vdc in self.cleaned_data['vdcs']: + if vdc.device != self.cleaned_data['device']: + raise forms.ValidationError(f"VDC {vdc} is not assigned to device {self.cleaned_data['device']}") + return self.cleaned_data['vdcs'] + class FrontPortImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( From 43680e8cb992fd85060085176d8dd8e194a5f910 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 28 Mar 2023 13:46:43 -0400 Subject: [PATCH 14/38] Release v3.4.7 --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- .github/ISSUE_TEMPLATE/feature_request.yaml | 2 +- base_requirements.txt | 3 ++- docs/release-notes/version-3.4.md | 3 ++- netbox/netbox/settings.py | 2 +- requirements.txt | 12 ++++++------ 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 51c0a5a0d..54f4f7eae 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.4.6 + placeholder: v3.4.7 validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 7c6b4e151..c9bc56ffc 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.4.6 + placeholder: v3.4.7 validations: required: true - type: dropdown diff --git a/base_requirements.txt b/base_requirements.txt index 7292c676b..f3303e6e3 100644 --- a/base_requirements.txt +++ b/base_requirements.txt @@ -121,7 +121,8 @@ social-auth-core # Django app for social-auth-core # https://github.com/python-social-auth/social-app-django -social-auth-app-django +# See https://github.com/python-social-auth/social-app-django/issues/429 +social-auth-app-django==5.0.0 # SVG image rendering (used for rack elevations) # https://github.com/mozman/svgwrite diff --git a/docs/release-notes/version-3.4.md b/docs/release-notes/version-3.4.md index fa2ba157b..c14acca66 100644 --- a/docs/release-notes/version-3.4.md +++ b/docs/release-notes/version-3.4.md @@ -1,6 +1,6 @@ # NetBox v3.4 -## v3.4.7 (FUTURE) +## v3.4.7 (2023-03-28) ### Enhancements @@ -9,6 +9,7 @@ * [#11973](https://github.com/netbox-community/netbox/issues/11833) - Use SSID for representing wireless links, if set * [#11977](https://github.com/netbox-community/netbox/issues/11977) - Support designating multiple backends via `REMOTE_AUTH_BACKEND` config parameter * [#11990](https://github.com/netbox-community/netbox/issues/11990) - Improve error reporting for duplicate CSV column headings +* [#11991](https://github.com/netbox-community/netbox/issues/11991) - Enable VDC assignment during bulk import/edit of interfaces ### Bug Fixes diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index cf2b06a8b..17414d4e1 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -24,7 +24,7 @@ from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW # Environment setup # -VERSION = '3.4.7-dev' +VERSION = '3.4.7' # Hostname HOSTNAME = platform.node() diff --git a/requirements.txt b/requirements.txt index 92f60335a..5844f62b0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ bleach==5.0.1 Django==4.1.7 django-cors-headers==3.14.0 django-debug-toolbar==3.8.1 -django-filter==22.1 +django-filter==23.1 django-graphiql-debug-toolbar==0.2.0 django-mptt==0.14 django-pglocks==1.0.4 @@ -19,18 +19,18 @@ graphene-django==3.0.0 gunicorn==20.1.0 Jinja2==3.1.2 Markdown==3.3.7 -mkdocs-material==9.1.2 +mkdocs-material==9.1.4 mkdocstrings[python-legacy]==0.20.0 netaddr==0.8.0 Pillow==9.4.0 psycopg2-binary==2.9.5 PyYAML==6.0 -sentry-sdk==1.16.0 +sentry-sdk==1.18.0 social-auth-app-django==5.0.0 -social-auth-core[openidconnect]==4.3.0 +social-auth-core[openidconnect]==4.4.0 svgwrite==1.4.3 -tablib==3.3.0 -tzdata==2022.7 +tablib==3.4.0 +tzdata==2023.2 # Workaround for #7401 jsonschema==3.2.0 From 8818401ba80add3e7f6dec89631a873257847667 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 13 Mar 2023 11:59:57 -0400 Subject: [PATCH 15/38] PRVB --- docs/release-notes/version-3.4.md | 4 ++++ netbox/netbox/settings.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.4.md b/docs/release-notes/version-3.4.md index 43f4dab5e..d754123c6 100644 --- a/docs/release-notes/version-3.4.md +++ b/docs/release-notes/version-3.4.md @@ -1,5 +1,9 @@ # NetBox v3.4 +## v3.4.7 (FUTURE) + +--- + ## v3.4.6 (2023-03-13) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index c87303649..45fe32841 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -24,7 +24,7 @@ from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW # Environment setup # -VERSION = '3.4.6' +VERSION = '3.4.7-dev' # Hostname HOSTNAME = platform.node() From 87f28b3fd716389ee4ef77061d8e64c63247828c Mon Sep 17 00:00:00 2001 From: Ryan Merolle Date: Tue, 14 Mar 2023 15:50:49 -0400 Subject: [PATCH 16/38] Add fieldsets functionality to scripts to allow for form field groupings (#11880) * update script template * update docs * introduce default_fieldset * correct custom script docs * default to use fieldsets in scripts * update scripts docs for new behavior * Misc cleanup --------- Co-authored-by: jeremystretch --- docs/customization/custom-scripts.md | 19 +++++++++++++++++-- netbox/extras/scripts.py | 12 ++++++++++++ netbox/templates/extras/script.html | 26 ++++++++++++++++++++++---- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/docs/customization/custom-scripts.md b/docs/customization/custom-scripts.md index af1e9b5b6..ccbe50885 100644 --- a/docs/customization/custom-scripts.md +++ b/docs/customization/custom-scripts.md @@ -79,7 +79,22 @@ A human-friendly description of what your script does. ### `field_order` -By default, script variables will be ordered in the form as they are defined in the script. `field_order` may be defined as an iterable of field names to determine the order in which variables are rendered. Any fields not included in this iterable be listed last. +By default, script variables will be ordered in the form as they are defined in the script. `field_order` may be defined as an iterable of field names to determine the order in which variables are rendered within a default "Script Data" group. Any fields not included in this iterable be listed last. If `fieldsets` is defined, `field_order` will be ignored. A fieldset group for "Script Execution Parameters" will be added to the end of the form by default for the user. + +### `fieldsets` + +`fieldsets` may be defined as an iterable of field groups and their field names to determine the order in which variables are group and rendered. Any fields not included in this iterable will not be displayed in the form. If `fieldsets` is defined, `field_order` will be ignored. A fieldset group for "Script Execution Parameters" will be added to the end of the fieldsets by default for the user. + +An example fieldset definition is provided below: + +```python +class MyScript(Script): + class Meta: + fieldsets = ( + ('First group', ('field1', 'field2', 'field3')), + ('Second group', ('field4', 'field5')), + ) +``` ### `commit_default` @@ -302,7 +317,7 @@ Optionally `schedule_at` can be passed in the form data with a datetime string t Scripts can be run on the CLI by invoking the management command: ``` -python3 manage.py runscript [--commit] [--loglevel {debug,info,warning,error,critical}] [--data ""] .