From 18a4232783ae436f1bd976140a3631a9b4ed4a0a Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Wed, 28 Jul 2021 16:00:38 -0400 Subject: [PATCH 01/22] PRVB --- netbox/netbox/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index f28f72a2748..d44d87b2318 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -16,7 +16,7 @@ # Environment setup # -VERSION = '2.11.10' +VERSION = '2.11.11-dev' # Hostname HOSTNAME = platform.node() From 27f3816fc63c8fc1410c5adf1c383df9772dd512 Mon Sep 17 00:00:00 2001 From: Ursadon Date: Thu, 29 Jul 2021 15:45:32 +0700 Subject: [PATCH 02/22] Escaping angle brackets in a device config file The configuration file may contain brackets (">" or "<"), which must be escaped --- netbox/templates/dcim/device/config.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/netbox/templates/dcim/device/config.html b/netbox/templates/dcim/device/config.html index 4b73a25777d..c6508f6019d 100644 --- a/netbox/templates/dcim/device/config.html +++ b/netbox/templates/dcim/device/config.html @@ -39,9 +39,9 @@ url: "{% url 'dcim-api:device-napalm' pk=object.pk %}?method=get_config", dataType: 'json', success: function(json) { - $('#running_config').html($.trim(json['get_config']['running'])); - $('#startup_config').html($.trim(json['get_config']['startup'])); - $('#candidate_config').html($.trim(json['get_config']['candidate'])); + $('#running_config').text($.trim(json['get_config']['running'])); + $('#startup_config').text($.trim(json['get_config']['startup'])); + $('#candidate_config').text($.trim(json['get_config']['candidate'])); }, error: function(xhr) { alert(xhr.responseText); From 288bf477ce8f970335bb605aae1af1f65e757387 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 29 Jul 2021 09:07:23 -0400 Subject: [PATCH 03/22] Bump GitHub stale action to v4.0 --- .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 0f617e8aafe..d8099923fb1 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -8,7 +8,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v3 + - uses: actions/stale@v4 with: close-issue-message: > This issue has been automatically closed due to lack of activity. In an From 76df55dfc070b8caae8c43a47b4b8701b9d065d2 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Fri, 30 Jul 2021 10:28:56 -0400 Subject: [PATCH 04/22] Fixes #6740: Add import button to VM interfaces list --- docs/release-notes/version-2.11.md | 8 ++++++++ netbox/virtualization/views.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 736807e2c17..b29ae6ef22c 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -1,5 +1,13 @@ # NetBox v2.11 +## v2.11.11 (FUTURE) + +### Bug Fixes + +* [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list + +--- + ## v2.11.10 (2021-07-28) ### Enhancements diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index 4fdca3078ee..0d1b720517e 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -414,7 +414,7 @@ class VMInterfaceListView(generic.ObjectListView): filterset = filtersets.VMInterfaceFilterSet filterset_form = forms.VMInterfaceFilterForm table = tables.VMInterfaceTable - action_buttons = ('export',) + action_buttons = ('import', 'export') class VMInterfaceView(generic.ObjectView): From 55cdbd57ccecb9991e2cc68ac62eecf34c18e2b0 Mon Sep 17 00:00:00 2001 From: Brian Ellwood Date: Wed, 4 Aug 2021 12:06:39 -0400 Subject: [PATCH 05/22] Add power outlet/port choice for C21/C22 Resolves #6883 --- netbox/dcim/choices.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netbox/dcim/choices.py b/netbox/dcim/choices.py index 9a12e6a1917..4216d935551 100644 --- a/netbox/dcim/choices.py +++ b/netbox/dcim/choices.py @@ -252,6 +252,7 @@ class PowerPortTypeChoices(ChoiceSet): TYPE_IEC_C14 = 'iec-60320-c14' TYPE_IEC_C16 = 'iec-60320-c16' TYPE_IEC_C20 = 'iec-60320-c20' + TYPE_IEC_C22 = 'iec-60320-c22' # IEC 60309 TYPE_IEC_PNE4H = 'iec-60309-p-n-e-4h' TYPE_IEC_PNE6H = 'iec-60309-p-n-e-6h' @@ -351,6 +352,7 @@ class PowerPortTypeChoices(ChoiceSet): (TYPE_IEC_C14, 'C14'), (TYPE_IEC_C16, 'C16'), (TYPE_IEC_C20, 'C20'), + (TYPE_IEC_C22, 'C22'), )), ('IEC 60309', ( (TYPE_IEC_PNE4H, 'P+N+E 4H'), @@ -467,6 +469,7 @@ class PowerOutletTypeChoices(ChoiceSet): TYPE_IEC_C13 = 'iec-60320-c13' TYPE_IEC_C15 = 'iec-60320-c15' TYPE_IEC_C19 = 'iec-60320-c19' + TYPE_IEC_C21 = 'iec-60320-c21' # IEC 60309 TYPE_IEC_PNE4H = 'iec-60309-p-n-e-4h' TYPE_IEC_PNE6H = 'iec-60309-p-n-e-6h' @@ -558,6 +561,7 @@ class PowerOutletTypeChoices(ChoiceSet): (TYPE_IEC_C13, 'C13'), (TYPE_IEC_C15, 'C15'), (TYPE_IEC_C19, 'C19'), + (TYPE_IEC_C21, 'C21'), )), ('IEC 60309', ( (TYPE_IEC_PNE4H, 'P+N+E 4H'), From ee8fd701ae2d86ad74ab2d88ead341a9974226ff Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Wed, 4 Aug 2021 13:26:53 -0400 Subject: [PATCH 06/22] Changelog for #6883 --- docs/release-notes/version-2.11.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index b29ae6ef22c..459fdbd17c5 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -2,6 +2,10 @@ ## v2.11.11 (FUTURE) +### Enhancements + +* [#6883](https://github.com/netbox-community/netbox/issues/6883) - Add C21 & C22 power types + ### Bug Fixes * [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list From 46d0af6cef3e98b0352fd8be72ceb76f8f07523a Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 5 Aug 2021 11:12:08 -0400 Subject: [PATCH 07/22] Fixes #6892: Fix validation of unit ranges when creating a rack reservation --- docs/release-notes/version-2.11.md | 1 + netbox/utilities/forms/utils.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 459fdbd17c5..711b6f4b19e 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -9,6 +9,7 @@ ### Bug Fixes * [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list +* [#6892](https://github.com/netbox-community/netbox/issues/6892) - Fix validation of unit ranges when creating a rack reservation --- diff --git a/netbox/utilities/forms/utils.py b/netbox/utilities/forms/utils.py index 503a2e8a00e..90df55b9cea 100644 --- a/netbox/utilities/forms/utils.py +++ b/netbox/utilities/forms/utils.py @@ -32,7 +32,10 @@ def parse_numeric_range(string, base=10): begin, end = dash_range.split('-') except ValueError: begin, end = dash_range, dash_range - begin, end = int(begin.strip(), base=base), int(end.strip(), base=base) + 1 + try: + begin, end = int(begin.strip(), base=base), int(end.strip(), base=base) + 1 + except ValueError: + raise forms.ValidationError(f'Range "{dash_range}" is invalid.') values.extend(range(begin, end)) return list(set(values)) @@ -64,7 +67,7 @@ def parse_alphanumeric_range(string): else: # Not a valid range (more than a single character) if not len(begin) == len(end) == 1: - raise forms.ValidationError('Range "{}" is invalid.'.format(dash_range)) + raise forms.ValidationError(f'Range "{dash_range}" is invalid.') for n in list(range(ord(begin), ord(end) + 1)): values.append(chr(n)) return values From d347b97f20f212184f0144d3601aca509e3c926f Mon Sep 17 00:00:00 2001 From: Joel McGuire Date: Thu, 5 Aug 2021 10:28:32 -0700 Subject: [PATCH 08/22] Fixes #6887 Add Examples in the Lookup Expression Docs (#6898) Fixes #6887 Add Examples in the Lookup Expression Docs Co-authored-by: joel --- docs/rest-api/filtering.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/rest-api/filtering.md b/docs/rest-api/filtering.md index 471beffeeff..45dfcfa36ce 100644 --- a/docs/rest-api/filtering.md +++ b/docs/rest-api/filtering.md @@ -69,6 +69,12 @@ Numeric based fields (ASN, VLAN ID, etc) support these lookup expressions: | `gt` | Greater than | | `gte` | Greater than or equal to | +Here is an example of a numeric field lookup expression that will return all VLANs with a VLAN ID greater than 900: + +```no-highlight +GET /api/ipam/vlans/?vid__gt=900 +``` + ### String Fields String based (char) fields (Name, Address, etc) support these lookup expressions: @@ -86,7 +92,17 @@ String based (char) fields (Name, Address, etc) support these lookup expressions | `nie` | Inverse exact match (case-insensitive) | | `empty` | Is empty (boolean) | +Here is an example of a lookup expression on a string field that will return all devices with `switch` in the name: + +```no-highlight +GET /api/dcim/devices/?name__ic=switch +``` + ### Foreign Keys & Other Fields Certain other fields, namely foreign key relationships support just the negation -expression: `n`. +expression: `n`. Here is an example of a lookup expression on a foreign key, it would return all the VLANs that don't have a VLAN Group ID of 3203: + +```no-highlight +GET /api/ipam/vlans/?group_id__n=3203 +``` From 7c8612aaddea00aa956e21ae8c2c3b383e6272c4 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 5 Aug 2021 15:51:24 -0400 Subject: [PATCH 09/22] Update application architecture diagram --- .../installation/netbox_application_stack.png | Bin 25852 -> 35722 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/media/installation/netbox_application_stack.png b/docs/media/installation/netbox_application_stack.png index e8634490074d8e38883ca333896c2cdf513e5631..c860b964b1a27228423f414ca546150b1ff33393 100644 GIT binary patch literal 35722 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

gKTQXYPvSk>}1lH%cih8Aet3&Ak>; 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 P;3F-rAXX+~@b&)y`t&Ir literal 25852 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 EAB}B!RR910 From f23dc2d405be10fac2fd7a74395a314566cd60e5 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Fri, 6 Aug 2021 09:55:47 -0400 Subject: [PATCH 10/22] Fixes #6902: Populate device field when cloning device components --- docs/release-notes/version-2.11.md | 1 + netbox/dcim/models/device_components.py | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 711b6f4b19e..162bbaf132c 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -10,6 +10,7 @@ * [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list * [#6892](https://github.com/netbox-community/netbox/issues/6892) - Fix validation of unit ranges when creating a rack reservation +* [#6902](https://github.com/netbox-community/netbox/issues/6902) - Populate device field when cloning device components --- diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 6ac0d7753ae..6b67ad302e3 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -230,6 +230,7 @@ class ConsolePort(ComponentModel, CableTermination, PathEndpoint): ) csv_headers = ['device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description'] + clone_fields = ['device', 'type', 'speed'] class Meta: ordering = ('device', '_name') @@ -273,6 +274,7 @@ class ConsoleServerPort(ComponentModel, CableTermination, PathEndpoint): ) csv_headers = ['device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description'] + clone_fields = ['device', 'type', 'speed'] class Meta: ordering = ('device', '_name') @@ -324,6 +326,7 @@ class PowerPort(ComponentModel, CableTermination, PathEndpoint): csv_headers = [ 'device', 'name', 'label', 'type', 'mark_connected', 'maximum_draw', 'allocated_draw', 'description', ] + clone_fields = ['device', 'maximum_draw', 'allocated_draw'] class Meta: ordering = ('device', '_name') @@ -434,6 +437,7 @@ class PowerOutlet(ComponentModel, CableTermination, PathEndpoint): ) csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'power_port', 'feed_leg', 'description'] + clone_fields = ['device', 'type', 'power_port', 'feed_leg'] class Meta: ordering = ('device', '_name') @@ -577,6 +581,7 @@ class Interface(ComponentModel, BaseInterface, CableTermination, PathEndpoint): 'device', 'name', 'label', 'parent', 'lag', 'type', 'enabled', 'mark_connected', 'mac_address', 'mtu', 'mgmt_only', 'description', 'mode', ] + clone_fields = ['device', 'parent', 'lag', 'type', 'mgmt_only'] class Meta: ordering = ('device', CollateAsChar('_name')) @@ -711,6 +716,7 @@ class FrontPort(ComponentModel, CableTermination): csv_headers = [ 'device', 'name', 'label', 'type', 'mark_connected', 'rear_port', 'rear_port_position', 'description', ] + clone_fields = ['device', 'type'] class Meta: ordering = ('device', '_name') @@ -767,6 +773,7 @@ class RearPort(ComponentModel, CableTermination): MaxValueValidator(REARPORT_POSITIONS_MAX) ] ) + clone_fields = ['device', 'type', 'positions'] csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'positions', 'description'] @@ -818,6 +825,7 @@ class DeviceBay(ComponentModel): ) csv_headers = ['device', 'name', 'label', 'installed_device', 'description'] + clone_fields = ['device'] class Meta: ordering = ('device', '_name') @@ -913,6 +921,7 @@ class InventoryItem(MPTTModel, ComponentModel): csv_headers = [ 'device', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered', 'description', ] + clone_fields = ['device', 'parent', 'manufacturer', 'part_id'] class Meta: ordering = ('device__id', 'parent__id', '_name') From b8021278017b5db7154e77b08878272ff9d9d064 Mon Sep 17 00:00:00 2001 From: Brian Candler Date: Sun, 8 Aug 2021 10:19:30 +0100 Subject: [PATCH 11/22] Documentation consistency on installation of libpq-dev(el) --- docs/installation/1-postgresql.md | 4 ++-- docs/installation/3-netbox.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/installation/1-postgresql.md b/docs/installation/1-postgresql.md index 39008f18875..644b2715c6d 100644 --- a/docs/installation/1-postgresql.md +++ b/docs/installation/1-postgresql.md @@ -11,13 +11,13 @@ This section entails the installation and configuration of a local PostgreSQL da ```no-highlight sudo apt update - sudo apt install -y postgresql libpq-dev + sudo apt install -y postgresql ``` === "CentOS" ```no-highlight - sudo yum install -y postgresql-server libpq-devel + sudo yum install -y postgresql-server sudo postgresql-setup --initdb ``` diff --git a/docs/installation/3-netbox.md b/docs/installation/3-netbox.md index e54bf6f3e65..eb717093d60 100644 --- a/docs/installation/3-netbox.md +++ b/docs/installation/3-netbox.md @@ -18,7 +18,7 @@ Begin by installing all system packages required by NetBox and its dependencies. === "CentOS" ```no-highlight - sudo yum install -y gcc python36 python36-devel python3-pip libxml2-devel libxslt-devel libffi-devel openssl-devel redhat-rpm-config + sudo yum install -y gcc python36 python36-devel python3-pip libxml2-devel libxslt-devel libffi-devel libpq-devel openssl-devel redhat-rpm-config ``` Before continuing with either platform, update pip (Python's package management tool) to its latest release: From b04f26264261990f58f0505f1d0c3f134f1ed07f Mon Sep 17 00:00:00 2001 From: Brian Candler Date: Mon, 9 Aug 2021 07:37:46 +0100 Subject: [PATCH 12/22] Change example ADMINS to show a tuple Fixes #6919 --- netbox/netbox/configuration.example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/configuration.example.py b/netbox/netbox/configuration.example.py index a5c5521f32e..cac4a9c85e4 100644 --- a/netbox/netbox/configuration.example.py +++ b/netbox/netbox/configuration.example.py @@ -69,7 +69,7 @@ # Specify one or more name and email address tuples representing NetBox administrators. These people will be notified of # application errors (assuming correct email settings are provided). ADMINS = [ - # ['John Doe', 'jdoe@example.com'], + # ('John Doe', 'jdoe@example.com'), ] # URL schemes that are allowed within links in NetBox From a8b6902829065d5aa0b44cd4df9ab4bef8c150fa Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 9 Aug 2021 09:17:08 -0400 Subject: [PATCH 13/22] Fixes #6909: Remove extraneous site column from VLAN group import form --- docs/release-notes/version-2.11.md | 1 + netbox/ipam/forms.py | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 162bbaf132c..f1e3bf83804 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -11,6 +11,7 @@ * [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list * [#6892](https://github.com/netbox-community/netbox/issues/6892) - Fix validation of unit ranges when creating a rack reservation * [#6902](https://github.com/netbox-community/netbox/issues/6902) - Populate device field when cloning device components +* [#6909](https://github.com/netbox-community/netbox/issues/6909) - Remove extraneous `site` column from VLAN group import form --- diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 1b38b63f4c3..673e090cbe5 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -1238,12 +1238,6 @@ def clean(self): class VLANGroupCSVForm(CustomFieldModelCSVForm): - site = CSVModelChoiceField( - queryset=Site.objects.all(), - required=False, - to_field_name='name', - help_text='Assigned site' - ) slug = SlugField() class Meta: From 7bcebd5b0ffaaa0a20ece90d9f7ffa26bd47151d Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 9 Aug 2021 09:20:22 -0400 Subject: [PATCH 14/22] Fixes #6910: Fix exception on invalid CSV import column name --- docs/release-notes/version-2.11.md | 1 + netbox/netbox/views/generic.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index f1e3bf83804..94528336f01 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -12,6 +12,7 @@ * [#6892](https://github.com/netbox-community/netbox/issues/6892) - Fix validation of unit ranges when creating a rack reservation * [#6902](https://github.com/netbox-community/netbox/issues/6902) - Populate device field when cloning device components * [#6909](https://github.com/netbox-community/netbox/issues/6909) - Remove extraneous `site` column from VLAN group import form +* [#6910](https://github.com/netbox-community/netbox/issues/6910) - Fix exception on invalid CSV import column name --- diff --git a/netbox/netbox/views/generic.py b/netbox/netbox/views/generic.py index bd3d6300af7..d26b56464e7 100644 --- a/netbox/netbox/views/generic.py +++ b/netbox/netbox/views/generic.py @@ -675,7 +675,7 @@ class ImportForm(BootstrapMixin, Form): ) def clean(self): - csv_rows = self.cleaned_data['csv'][1] + csv_rows = self.cleaned_data['csv'][1] if 'csv' in self.cleaned_data else None csv_file = self.files.get('csv_file') # Check that the user has not submitted both text data and a file From 1bb596fc7e481074a9d479799f301f8571db955a Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 9 Aug 2021 09:54:27 -0400 Subject: [PATCH 15/22] Fixes #6908: Allow assignment of scope to VLAN groups upon import --- docs/release-notes/version-2.11.md | 1 + netbox/ipam/forms.py | 14 +++++++++++--- netbox/ipam/tests/test_views.py | 8 ++++---- netbox/utilities/forms/fields.py | 2 ++ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 94528336f01..35fa923c5b0 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -11,6 +11,7 @@ * [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list * [#6892](https://github.com/netbox-community/netbox/issues/6892) - Fix validation of unit ranges when creating a rack reservation * [#6902](https://github.com/netbox-community/netbox/issues/6902) - Populate device field when cloning device components +* [#6908](https://github.com/netbox-community/netbox/issues/6908) - Allow assignment of scope to VLAN groups upon import * [#6909](https://github.com/netbox-community/netbox/issues/6909) - Remove extraneous `site` column from VLAN group import form * [#6910](https://github.com/netbox-community/netbox/issues/6910) - Fix exception on invalid CSV import column name diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 673e090cbe5..d130c589524 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -11,9 +11,9 @@ from tenancy.models import Tenant from utilities.forms import ( add_blank_choice, BootstrapMixin, BulkEditNullBooleanSelect, ContentTypeChoiceField, CSVChoiceField, - CSVModelChoiceField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableIPAddressField, - NumericArrayField, ReturnURLForm, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField, - BOOLEAN_WITH_BLANK_CHOICES, + CSVContentTypeField, CSVModelChoiceField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField, + ExpandableIPAddressField, NumericArrayField, ReturnURLForm, SlugField, StaticSelect2, StaticSelect2Multiple, + TagFilterField, BOOLEAN_WITH_BLANK_CHOICES, ) from virtualization.models import Cluster, ClusterGroup, VirtualMachine, VMInterface from .choices import * @@ -1239,10 +1239,18 @@ def clean(self): class VLANGroupCSVForm(CustomFieldModelCSVForm): slug = SlugField() + scope_type = CSVContentTypeField( + queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES), + required=False, + label='Scope type (app & model)' + ) class Meta: model = VLANGroup fields = VLANGroup.csv_headers + labels = { + 'scope_id': 'Scope ID', + } class VLANGroupBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm): diff --git a/netbox/ipam/tests/test_views.py b/netbox/ipam/tests/test_views.py index 057f9383f21..5a80fd5f1d6 100644 --- a/netbox/ipam/tests/test_views.py +++ b/netbox/ipam/tests/test_views.py @@ -333,10 +333,10 @@ def setUpTestData(cls): } cls.csv_data = ( - "name,slug,description", - "VLAN Group 4,vlan-group-4,Fourth VLAN group", - "VLAN Group 5,vlan-group-5,Fifth VLAN group", - "VLAN Group 6,vlan-group-6,Sixth VLAN group", + f"name,slug,scope_type,scope_id,description", + f"VLAN Group 4,vlan-group-4,,,Fourth VLAN group", + f"VLAN Group 5,vlan-group-5,dcim.site,{sites[0].pk},Fifth VLAN group", + f"VLAN Group 6,vlan-group-6,dcim.site,{sites[1].pk},Sixth VLAN group", ) cls.bulk_edit_data = { diff --git a/netbox/utilities/forms/fields.py b/netbox/utilities/forms/fields.py index 7cb2cd705f7..233549e0edd 100644 --- a/netbox/utilities/forms/fields.py +++ b/netbox/utilities/forms/fields.py @@ -269,6 +269,8 @@ def prepare_value(self, value): return f'{value.app_label}.{value.model}' def to_python(self, value): + if not value: + return None try: app_label, model = value.split('.') except ValueError: From 35b8fc6e837dfcc027a23e5263eb5eca9d4f2d9f Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 10 Aug 2021 20:24:57 -0400 Subject: [PATCH 16/22] Fixes #6936: Add missing parent column to inventory item import form --- docs/release-notes/version-2.11.md | 1 + netbox/dcim/forms.py | 21 +++++++++++++++++++++ netbox/dcim/tests/test_views.py | 8 ++++---- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 35fa923c5b0..580d8eb1948 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -14,6 +14,7 @@ * [#6908](https://github.com/netbox-community/netbox/issues/6908) - Allow assignment of scope to VLAN groups upon import * [#6909](https://github.com/netbox-community/netbox/issues/6909) - Remove extraneous `site` column from VLAN group import form * [#6910](https://github.com/netbox-community/netbox/issues/6910) - Fix exception on invalid CSV import column name +* [#6936](https://github.com/netbox-community/netbox/issues/6936) - Add missing `parent` column to inventory item import form --- diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 565a75c45b2..97f8721a5ce 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -3852,11 +3852,32 @@ class InventoryItemCSVForm(CustomFieldModelCSVForm): to_field_name='name', required=False ) + parent = CSVModelChoiceField( + queryset=Device.objects.all(), + to_field_name='name', + required=False, + help_text='Parent inventory item' + ) class Meta: model = InventoryItem fields = InventoryItem.csv_headers + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Limit parent choices to inventory items belonging to this device + device = None + if self.is_bound and 'device' in self.data: + try: + device = self.fields['device'].to_python(self.data['device']) + except forms.ValidationError: + pass + if device: + self.fields['parent'].queryset = InventoryItem.objects.filter(device=device) + else: + self.fields['parent'].queryset = InventoryItem.objects.none() + class InventoryItemBulkCreateForm( form_from_model(InventoryItem, ['manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered']), diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 4942b27c20a..c4e552b9952 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1736,10 +1736,10 @@ def setUpTestData(cls): } cls.csv_data = ( - "device,name", - "Device 1,Inventory Item 4", - "Device 1,Inventory Item 5", - "Device 1,Inventory Item 6", + "device,name,parent", + "Device 1,Inventory Item 4,Inventory Item 1", + "Device 1,Inventory Item 5,Inventory Item 2", + "Device 1,Inventory Item 6,Inventory Item 3", ) From 7bceeb714b53d4b241356c9ed1bc0e4460bc97c5 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 10 Aug 2021 20:35:39 -0400 Subject: [PATCH 17/22] Fixes #6935: Remove extraneous columns from inventory item and device bay tables --- docs/release-notes/version-2.11.md | 1 + netbox/dcim/tables/devices.py | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 580d8eb1948..4ca76526442 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -14,6 +14,7 @@ * [#6908](https://github.com/netbox-community/netbox/issues/6908) - Allow assignment of scope to VLAN groups upon import * [#6909](https://github.com/netbox-community/netbox/issues/6909) - Remove extraneous `site` column from VLAN group import form * [#6910](https://github.com/netbox-community/netbox/issues/6910) - Fix exception on invalid CSV import column name +* [#6935](https://github.com/netbox-community/netbox/issues/6935) - Remove extraneous columns from inventory item and device bay tables * [#6936](https://github.com/netbox-community/netbox/issues/6936) - Add missing `parent` column to inventory item import form --- diff --git a/netbox/dcim/tables/devices.py b/netbox/dcim/tables/devices.py index 258e712d53e..b5d1b64ed35 100644 --- a/netbox/dcim/tables/devices.py +++ b/netbox/dcim/tables/devices.py @@ -232,10 +232,6 @@ class DeviceComponentTable(BaseTable): linkify=True, order_by=('_name',) ) - cable = tables.Column( - linkify=True - ) - mark_connected = BooleanColumn() class Meta(BaseTable.Meta): order_by = ('device', 'name') From db359719a90c6da8800f4d37f3ba12ee01321fa0 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 10 Aug 2021 20:52:45 -0400 Subject: [PATCH 18/22] Closes #6921: Employ a sandbox when rendering Jinja2 code for increased security --- docs/additional-features/custom-links.md | 3 +++ docs/additional-features/export-templates.md | 5 ++++- docs/additional-features/webhooks.md | 3 +++ docs/release-notes/version-2.11.md | 1 + netbox/utilities/utils.py | 4 ++-- 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/additional-features/custom-links.md b/docs/additional-features/custom-links.md index 0a00b6d68a9..196371ce31d 100644 --- a/docs/additional-features/custom-links.md +++ b/docs/additional-features/custom-links.md @@ -17,6 +17,9 @@ When viewing a device named Router4, this link would render as: Custom links appear as buttons at the top right corner of the page. Numeric weighting can be used to influence the ordering of links. +!!! warning + Custom links rely on user-created code to generate arbitrary HTML output, which may be dangerous. Only grant permission to create or modify custom links to trusted users. + ## Context Data The following context data is available within the template when rendering a custom link's text or URL. diff --git a/docs/additional-features/export-templates.md b/docs/additional-features/export-templates.md index b3f585beeec..6608074443f 100644 --- a/docs/additional-features/export-templates.md +++ b/docs/additional-features/export-templates.md @@ -4,10 +4,13 @@ NetBox allows users to define custom templates that can be used when exporting o Each export template is associated with a certain type of object. For instance, if you create an export template for VLANs, your custom template will appear under the "Export" button on the VLANs list. Each export template must have a name, and may optionally designate a specific export [MIME type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) and/or file extension. +Export templates must be written in [Jinja2](https://jinja.palletsprojects.com/). + !!! note The name `table` is reserved for internal use. -Export templates must be written in [Jinja2](https://jinja.palletsprojects.com/). +!!! warning + Export templates are rendered using user-submitted code, which may pose security risks under certain conditions. Only grant permission to create or modify export templates to trusted users. The list of objects returned from the database when rendering an export template is stored in the `queryset` variable, which you'll typically want to iterate through using a `for` loop. Object properties can be access by name. For example: diff --git a/docs/additional-features/webhooks.md b/docs/additional-features/webhooks.md index f3dd803372a..4fce4e037e5 100644 --- a/docs/additional-features/webhooks.md +++ b/docs/additional-features/webhooks.md @@ -2,6 +2,9 @@ A webhook is a mechanism for conveying to some external system a change that took place in NetBox. For example, you may want to notify a monitoring system whenever the status of a device is updated in NetBox. This can be done by creating a webhook for the device model in NetBox and identifying the webhook receiver. When NetBox detects a change to a device, an HTTP request containing the details of the change and who made it be sent to the specified receiver. Webhooks are configured in the admin UI under Extras > Webhooks. +!!! warning + Webhooks support the inclusion of user-submitted code to generate custom headers and payloads, which may pose security risks under certain conditions. Only grant permission to create or modify webhooks to trusted users. + ## Configuration * **Name** - A unique name for the webhook. The name is not included with outbound messages. diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 4ca76526442..705472ac52f 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -5,6 +5,7 @@ ### Enhancements * [#6883](https://github.com/netbox-community/netbox/issues/6883) - Add C21 & C22 power types +* [#6921](https://github.com/netbox-community/netbox/issues/6921) - Employ a sandbox when rendering Jinja2 code for increased security ### Bug Fixes diff --git a/netbox/utilities/utils.py b/netbox/utilities/utils.py index 1cffab1ebc0..1b43c8b6bc9 100644 --- a/netbox/utilities/utils.py +++ b/netbox/utilities/utils.py @@ -6,7 +6,7 @@ from django.core.serializers import serialize from django.db.models import Count, OuterRef, Subquery from django.db.models.functions import Coalesce -from jinja2 import Environment +from jinja2.sandbox import SandboxedEnvironment from mptt.models import MPTTModel from dcim.choices import CableLengthUnitChoices @@ -213,7 +213,7 @@ def render_jinja2(template_code, context): """ Render a Jinja2 template with the provided context. Return the rendered content. """ - return Environment().from_string(source=template_code).render(**context) + return SandboxedEnvironment().from_string(source=template_code).render(**context) def prepare_cloned_fields(instance): From 42c71984f93047d7434704a5af02bfaa14cdd3dd Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Wed, 11 Aug 2021 21:15:45 -0400 Subject: [PATCH 19/22] Fixes #6896: Fix validation of IP address assigned as device/VM primary via NAT relation --- docs/release-notes/version-2.11.md | 1 + netbox/ipam/models/ip.py | 21 +++++++++------------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 705472ac52f..cd15c8459b5 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -11,6 +11,7 @@ * [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list * [#6892](https://github.com/netbox-community/netbox/issues/6892) - Fix validation of unit ranges when creating a rack reservation +* [#6896](https://github.com/netbox-community/netbox/issues/6896) - Fix validation of IP address assigned as device/VM primary via NAT relation * [#6902](https://github.com/netbox-community/netbox/issues/6902) - Populate device field when cloning device components * [#6908](https://github.com/netbox-community/netbox/issues/6908) - Allow assignment of scope to VLAN groups upon import * [#6909](https://github.com/netbox-community/netbox/issues/6909) - Remove extraneous `site` column from VLAN group import form diff --git a/netbox/ipam/models/ip.py b/netbox/ipam/models/ip.py index cd5b89cfe2c..b428e4be726 100644 --- a/netbox/ipam/models/ip.py +++ b/netbox/ipam/models/ip.py @@ -649,18 +649,15 @@ def clean(self): # Check for primary IP assignment that doesn't match the assigned device/VM if self.pk: - device = Device.objects.filter(Q(primary_ip4=self) | Q(primary_ip6=self)).first() - if device: - if getattr(self.assigned_object, 'device', None) != device: - raise ValidationError({ - 'interface': f"IP address is primary for device {device} but not assigned to it!" - }) - vm = VirtualMachine.objects.filter(Q(primary_ip4=self) | Q(primary_ip6=self)).first() - if vm: - if getattr(self.assigned_object, 'virtual_machine', None) != vm: - raise ValidationError({ - 'vminterface': f"IP address is primary for virtual machine {vm} but not assigned to it!" - }) + for cls, attr in ((Device, 'device'), (VirtualMachine, 'virtual_machine')): + parent = cls.objects.filter(Q(primary_ip4=self) | Q(primary_ip6=self)).first() + if parent and getattr(self.assigned_object, attr) != parent: + # Check for a NAT relationship + if not self.nat_inside or getattr(self.nat_inside.assigned_object, attr) != parent: + raise ValidationError({ + 'interface': f"IP address is primary for {cls._meta.model_name} {parent} but " + f"not assigned to it!" + }) # Validate IP status selection if self.status == IPAddressStatusChoices.STATUS_SLAAC and self.family != 6: From 3105e9545a4735e77692b76d6f1caf058d72049a Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 12 Aug 2021 10:12:42 -0400 Subject: [PATCH 20/22] Fixes #6918: Fix return URL persistence when adding multiple objects sequentially --- docs/release-notes/version-2.11.md | 1 + netbox/ipam/forms.py | 6 +++--- netbox/netbox/views/generic.py | 17 +++++++++-------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index cd15c8459b5..722657587af 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -16,6 +16,7 @@ * [#6908](https://github.com/netbox-community/netbox/issues/6908) - Allow assignment of scope to VLAN groups upon import * [#6909](https://github.com/netbox-community/netbox/issues/6909) - Remove extraneous `site` column from VLAN group import form * [#6910](https://github.com/netbox-community/netbox/issues/6910) - Fix exception on invalid CSV import column name +* [#6918](https://github.com/netbox-community/netbox/issues/6918) - Fix return URL persistence when adding multiple objects sequentially * [#6935](https://github.com/netbox-community/netbox/issues/6935) - Remove extraneous columns from inventory item and device bay tables * [#6936](https://github.com/netbox-community/netbox/issues/6936) - Add missing `parent` column to inventory item import form diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index d130c589524..c19131ca6d2 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -12,8 +12,8 @@ from utilities.forms import ( add_blank_choice, BootstrapMixin, BulkEditNullBooleanSelect, ContentTypeChoiceField, CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField, - ExpandableIPAddressField, NumericArrayField, ReturnURLForm, SlugField, StaticSelect2, StaticSelect2Multiple, - TagFilterField, BOOLEAN_WITH_BLANK_CHOICES, + ExpandableIPAddressField, NumericArrayField, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField, + BOOLEAN_WITH_BLANK_CHOICES, ) from virtualization.models import Cluster, ClusterGroup, VirtualMachine, VMInterface from .choices import * @@ -682,7 +682,7 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm) # IP addresses # -class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModelForm): +class IPAddressForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): device = DynamicModelChoiceField( queryset=Device.objects.all(), required=False, diff --git a/netbox/netbox/views/generic.py b/netbox/netbox/views/generic.py index d26b56464e7..ae2840a428c 100644 --- a/netbox/netbox/views/generic.py +++ b/netbox/netbox/views/generic.py @@ -306,19 +306,20 @@ def post(self, request, *args, **kwargs): messages.success(request, mark_safe(msg)) if '_addanother' in request.POST: + redirect_url = request.path + return_url = request.GET.get('return_url') + if return_url is not None and is_safe_url(url=return_url, allowed_hosts=request.get_host()): + redirect_url = f'{redirect_url}?return_url={return_url}' # If the object has clone_fields, pre-populate a new instance of the form if hasattr(obj, 'clone_fields'): - url = '{}?{}'.format(request.path, prepare_cloned_fields(obj)) - return redirect(url) + redirect_url += f"{'&' if return_url else '?'}{prepare_cloned_fields(obj)}" - return redirect(request.get_full_path()) + return redirect(redirect_url) - return_url = form.cleaned_data.get('return_url') - if return_url is not None and is_safe_url(url=return_url, allowed_hosts=request.get_host()): - return redirect(return_url) - else: - return redirect(self.get_return_url(request, obj)) + return_url = self.get_return_url(request, obj) + + return redirect(return_url) except PermissionsViolation: msg = "Object save failed due to object-level permissions violation" From b2faf8044dd3fcb138b5aa052d5e595b24e878d0 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 12 Aug 2021 11:22:57 -0400 Subject: [PATCH 21/22] Release v2.11.11 --- docs/release-notes/version-2.11.md | 2 +- netbox/netbox/settings.py | 2 +- requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 722657587af..40df841c0e8 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -1,6 +1,6 @@ # NetBox v2.11 -## v2.11.11 (FUTURE) +## v2.11.11 (2021-08-12) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index d44d87b2318..f9cab85be51 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -16,7 +16,7 @@ # Environment setup # -VERSION = '2.11.11-dev' +VERSION = '2.11.11' # Hostname HOSTNAME = platform.node() diff --git a/requirements.txt b/requirements.txt index d35cba435e6..65ce1de50d9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -Django==3.2.5 +Django==3.2.6 django-cacheops==6.0 django-cors-headers==3.7.0 django-debug-toolbar==3.2.1 From badd92a50e6c8b59b589157c4f8f58e48281bde1 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 12 Aug 2021 11:28:55 -0400 Subject: [PATCH 22/22] Update GitHub issue templates --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- .github/ISSUE_TEMPLATE/feature_request.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index ef31324fe2c..b0c021af2bf 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -17,7 +17,7 @@ body: What version of NetBox are you currently running? (If you don't have access to the most recent NetBox release, consider testing on our [demo instance](https://demo.netbox.dev/) before opening a bug report to see if your issue has already been addressed.) - placeholder: v2.11.10 + placeholder: v2.11.11 validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 319538cda3e..f13d45c3f5a 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: v2.11.10 + placeholder: v2.11.11 validations: required: true - type: dropdown