From bc091ada514332328f8659505765b2ccd91cdc25 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 5 Jan 2021 21:10:58 -0500 Subject: [PATCH 01/30] 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 4c36332fc..ed1f9c732 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -16,7 +16,7 @@ from django.core.validators import URLValidator # Environment setup # -VERSION = '2.10.3' +VERSION = '2.10.4-dev' # Hostname HOSTNAME = platform.node() From 7eef706036d6a3d5ddc2ef84d6ad20f6ababa1b4 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 Jan 2021 11:19:11 -0500 Subject: [PATCH 02/30] Fixes #5584: Restore power utilization panel under device view --- docs/release-notes/version-2.10.md | 8 ++++++++ netbox/templates/dcim/device.html | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index a3ab5968c..9773ec1b7 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -1,5 +1,13 @@ # NetBox v2.10 +## v2.10.4 (FUTURE) + +### Bug Fixes + +* [#5584](https://github.com/netbox-community/netbox/issues/5584) - Restore power utilization panel under device view + +--- + ## v2.10.3 (2021-01-05) ### Bug Fixes diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index 97f7c8953..55be343ac 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -204,7 +204,7 @@ {% plugin_left_page object %}
- {% if power_ports and poweroutlets %} + {% if object.powerports.exists and object.poweroutlets.exists %}
Power Utilization @@ -217,10 +217,10 @@ Available Utilization - {% for pp in power_ports %} - {% with utilization=pp.get_power_draw powerfeed=pp.connected_endpoint %} + {% for powerport in object.powerports.all %} + {% with utilization=powerport.get_power_draw powerfeed=powerport.connected_endpoint %} - {{ pp }} + {{ powerport }} {{ utilization.outlet_count }} {{ utilization.allocated }}VA {% if powerfeed.available_power %} From 7bab4b0899c02bb09fc7872081f6c2a2360875a8 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 7 Jan 2021 11:29:59 -0500 Subject: [PATCH 03/30] Closes #5570: Add "management only" filter widget for interfaces list --- docs/release-notes/version-2.10.md | 4 ++++ netbox/dcim/forms.py | 6 ++++++ netbox/dcim/tables/devices.py | 1 + 3 files changed, 11 insertions(+) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index 9773ec1b7..f9dee5dec 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -2,6 +2,10 @@ ## v2.10.4 (FUTURE) +### Enhancements + +* [#5570](https://github.com/netbox-community/netbox/issues/5570) - Add "management only" filter widget for interfaces list + ### Bug Fixes * [#5584](https://github.com/netbox-community/netbox/issues/5584) - Restore power utilization panel under device view diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index f7eb510ec..18fdbdb40 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -2687,6 +2687,12 @@ class InterfaceFilterForm(DeviceComponentFilterForm): choices=BOOLEAN_WITH_BLANK_CHOICES ) ) + mgmt_only = forms.NullBooleanField( + required=False, + widget=StaticSelect2( + choices=BOOLEAN_WITH_BLANK_CHOICES + ) + ) mac_address = forms.CharField( required=False, label='MAC address' diff --git a/netbox/dcim/tables/devices.py b/netbox/dcim/tables/devices.py index 663206505..2b067a69d 100644 --- a/netbox/dcim/tables/devices.py +++ b/netbox/dcim/tables/devices.py @@ -406,6 +406,7 @@ class BaseInterfaceTable(BaseTable): class InterfaceTable(DeviceComponentTable, BaseInterfaceTable, PathEndpointTable): + mgmt_only = BooleanColumn() tags = TagColumn( url_name='dcim:interface_list' ) From a14281a34a04ed4c463d6c152efe7e4e94b898cf Mon Sep 17 00:00:00 2001 From: Mikhail Yohman Date: Fri, 8 Jan 2021 19:30:27 -0700 Subject: [PATCH 04/30] Closes 5586: Adds name, master, and master_id filtering --- netbox/dcim/filters.py | 12 +++++++++++- netbox/dcim/tests/test_filters.py | 17 ++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 3046a0f33..05ae08923 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -1016,6 +1016,16 @@ class VirtualChassisFilterSet(BaseFilterSet): method='search', label='Search', ) + master_id = django_filters.ModelMultipleChoiceFilter( + queryset=Device.objects.all(), + label='Master (ID)', + ) + master = django_filters.ModelMultipleChoiceFilter( + field_name='master__name', + queryset=Device.objects.all(), + to_field_name='name', + label='Master (name)', + ) region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='master__site__region', @@ -1055,7 +1065,7 @@ class VirtualChassisFilterSet(BaseFilterSet): class Meta: model = VirtualChassis - fields = ['id', 'domain'] + fields = ['id', 'domain', 'name'] def search(self, queryset, name, value): if not value.strip(): diff --git a/netbox/dcim/tests/test_filters.py b/netbox/dcim/tests/test_filters.py index c701c47cf..a76788e65 100644 --- a/netbox/dcim/tests/test_filters.py +++ b/netbox/dcim/tests/test_filters.py @@ -2399,9 +2399,9 @@ class VirtualChassisTestCase(TestCase): Device.objects.bulk_create(devices) virtual_chassis = ( - VirtualChassis(master=devices[0], domain='Domain 1'), - VirtualChassis(master=devices[2], domain='Domain 2'), - VirtualChassis(master=devices[4], domain='Domain 3'), + VirtualChassis(name='VC 1', master=devices[0], domain='Domain 1'), + VirtualChassis(name='VC 2', master=devices[2], domain='Domain 2'), + VirtualChassis(name='VC 3', master=devices[4], domain='Domain 3'), ) VirtualChassis.objects.bulk_create(virtual_chassis) @@ -2417,6 +2417,17 @@ class VirtualChassisTestCase(TestCase): params = {'domain': ['Domain 1', 'Domain 2']} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_master(self): + masters = Device.objects.all() + params = {'master_id': [masters[0].pk, masters[2].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'master': [masters[0].name, masters[2].name]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_name(self): + params = {'name': ['VC 1', 'VC 2']} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_region(self): regions = Region.objects.all()[:2] params = {'region_id': [regions[0].pk, regions[1].pk]} From 5a725dc467aa570b5058b3140e3ed863c7ff9483 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 11 Jan 2021 11:28:03 -0500 Subject: [PATCH 05/30] Fixes #5597: Fix ordering devices by primary IP address --- docs/release-notes/version-2.10.md | 1 + netbox/dcim/tables/devices.py | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index f9dee5dec..870a11890 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -9,6 +9,7 @@ ### Bug Fixes * [#5584](https://github.com/netbox-community/netbox/issues/5584) - Restore power utilization panel under device view +* [#5597](https://github.com/netbox-community/netbox/issues/5597) - Fix ordering devices by primary IP address --- diff --git a/netbox/dcim/tables/devices.py b/netbox/dcim/tables/devices.py index 2b067a69d..edd9e7a43 100644 --- a/netbox/dcim/tables/devices.py +++ b/netbox/dcim/tables/devices.py @@ -129,6 +129,7 @@ class DeviceTable(BaseTable): ) primary_ip = tables.Column( linkify=True, + order_by=('primary_ip6', 'primary_ip4'), verbose_name='IP Address' ) primary_ip4 = tables.Column( From 72c19971bdffd1d5a5e8e9576e07bb4ed419af53 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Sun, 17 Jan 2021 14:08:59 -0500 Subject: [PATCH 06/30] Don't pin Ubuntu installations to Python 3.6 --- docs/installation/3-netbox.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation/3-netbox.md b/docs/installation/3-netbox.md index 9745df1f3..f2461b40d 100644 --- a/docs/installation/3-netbox.md +++ b/docs/installation/3-netbox.md @@ -7,12 +7,12 @@ This section of the documentation discusses installing and configuring the NetBo Begin by installing all system packages required by NetBox and its dependencies. !!! note - NetBox v2.8.0 and later require Python 3.6, 3.7, or 3.8. This documentation assumes Python 3.6. + NetBox v2.8.0 and later require Python 3.6, 3.7, or 3.8. ### Ubuntu ```no-highlight -sudo apt install -y python3.6 python3-pip python3-venv python3-dev build-essential libxml2-dev libxslt1-dev libffi-dev libpq-dev libssl-dev zlib1g-dev +sudo apt install -y python3 python3-pip python3-venv python3-dev build-essential libxml2-dev libxslt1-dev libffi-dev libpq-dev libssl-dev zlib1g-dev ``` ### CentOS From 7d3b12ba2ecf5b678ca31af76e924dfccf2585c8 Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Mon, 18 Jan 2021 14:06:28 +0100 Subject: [PATCH 07/30] Add choices for GG45 and TERA connectors and Cat7a/Cat8 cables Fixes #5612 --- netbox/dcim/choices.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/netbox/dcim/choices.py b/netbox/dcim/choices.py index d8f8e3e27..d4cc0ecf4 100644 --- a/netbox/dcim/choices.py +++ b/netbox/dcim/choices.py @@ -873,6 +873,10 @@ class PortTypeChoices(ChoiceSet): TYPE_8P6C = '8p6c' TYPE_8P4C = '8p4c' TYPE_8P2C = '8p2c' + TYPE_GG45 = 'gg45' + TYPE_TERA4P = 'tera-4p' + TYPE_TERA2P = 'tera-2p' + TYPE_TERA1P = 'tera-1p' TYPE_110_PUNCH = '110-punch' TYPE_BNC = 'bnc' TYPE_MRJ21 = 'mrj21' @@ -898,6 +902,10 @@ class PortTypeChoices(ChoiceSet): (TYPE_8P6C, '8P6C'), (TYPE_8P4C, '8P4C'), (TYPE_8P2C, '8P2C'), + (TYPE_GG45, 'GG45'), + (TYPE_TERA4P, 'TERA 4P'), + (TYPE_TERA2P, 'TERA 2P'), + (TYPE_TERA1P, 'TERA 1P'), (TYPE_110_PUNCH, '110 Punch'), (TYPE_BNC, 'BNC'), (TYPE_MRJ21, 'MRJ21'), @@ -936,6 +944,8 @@ class CableTypeChoices(ChoiceSet): TYPE_CAT6 = 'cat6' TYPE_CAT6A = 'cat6a' TYPE_CAT7 = 'cat7' + TYPE_CAT7A = 'cat7a' + TYPE_CAT8 = 'cat8' TYPE_DAC_ACTIVE = 'dac-active' TYPE_DAC_PASSIVE = 'dac-passive' TYPE_MRJ21_TRUNK = 'mrj21-trunk' @@ -960,6 +970,8 @@ class CableTypeChoices(ChoiceSet): (TYPE_CAT6, 'CAT6'), (TYPE_CAT6A, 'CAT6a'), (TYPE_CAT7, 'CAT7'), + (TYPE_CAT7A, 'CAT7a'), + (TYPE_CAT8, 'CAT8'), (TYPE_DAC_ACTIVE, 'Direct Attach Copper (Active)'), (TYPE_DAC_PASSIVE, 'Direct Attach Copper (Passive)'), (TYPE_MRJ21_TRUNK, 'MRJ21 Trunk'), From 6593668674a453a6b3deb6ddd648ccc9480efd60 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 19 Jan 2021 09:41:49 -0500 Subject: [PATCH 08/30] Changelog for #5586 and #5612 --- docs/release-notes/version-2.10.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index 870a11890..63eec8083 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -5,6 +5,8 @@ ### Enhancements * [#5570](https://github.com/netbox-community/netbox/issues/5570) - Add "management only" filter widget for interfaces list +* [#5586](https://github.com/netbox-community/netbox/issues/5586) - Allow filtering virtual chassis by name and master +* [#5612](https://github.com/netbox-community/netbox/issues/5612) - Add GG45 and TERA port types, and CAT7a and CAT8 cable types ### Bug Fixes From 9331d5130d4bcb10f55779b4cfe79c419ceeb86e Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 19 Jan 2021 10:49:56 -0500 Subject: [PATCH 09/30] Fixes #5574: Restrict the creation of device bay templates on non-parent device types --- docs/release-notes/version-2.10.md | 1 + netbox/dcim/models/device_component_templates.py | 6 ++++++ netbox/dcim/tests/test_api.py | 5 ++++- netbox/dcim/tests/test_views.py | 5 +++-- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index 63eec8083..a653173f9 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -10,6 +10,7 @@ ### Bug Fixes +* [#5574](https://github.com/netbox-community/netbox/issues/5574) - Restrict the creation of device bay templates on non-parent device types * [#5584](https://github.com/netbox-community/netbox/issues/5584) - Restore power utilization panel under device view * [#5597](https://github.com/netbox-community/netbox/issues/5597) - Fix ordering devices by primary IP address diff --git a/netbox/dcim/models/device_component_templates.py b/netbox/dcim/models/device_component_templates.py index 58233f3bf..e52fe2602 100644 --- a/netbox/dcim/models/device_component_templates.py +++ b/netbox/dcim/models/device_component_templates.py @@ -363,3 +363,9 @@ class DeviceBayTemplate(ComponentTemplateModel): name=self.name, label=self.label ) + + def clean(self): + if self.device_type and self.device_type.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT: + raise ValidationError( + f"Subdevice role of device type ({self.device_type}) must be set to \"parent\" to allow device bays." + ) diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index 77c3b4786..ad1ca930c 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -740,7 +740,10 @@ class DeviceBayTemplateTest(APIViewTestCases.APIViewTestCase): def setUpTestData(cls): manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1') devicetype = DeviceType.objects.create( - manufacturer=manufacturer, model='Device Type 1', slug='device-type-1' + manufacturer=manufacturer, + model='Device Type 1', + slug='device-type-1', + subdevice_role=SubdeviceRoleChoices.ROLE_PARENT ) device_bay_templates = ( diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 91ec8776c..86518af84 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -396,6 +396,7 @@ manufacturer: Generic model: TEST-1000 slug: test-1000 u_height: 2 +subdevice_role: parent comments: test comment console-ports: - name: Console Port 1 @@ -831,8 +832,8 @@ class DeviceBayTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCas def setUpTestData(cls): manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') devicetypes = ( - DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'), - DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1', subdevice_role=SubdeviceRoleChoices.ROLE_PARENT), + DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2', subdevice_role=SubdeviceRoleChoices.ROLE_PARENT), ) DeviceType.objects.bulk_create(devicetypes) From fd7f5fbb552abae7b6082615eabb6a36598c1e66 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 19 Jan 2021 11:24:34 -0500 Subject: [PATCH 10/30] Fixes #5639: Fix filtering connection lists by device name --- docs/release-notes/version-2.10.md | 1 + netbox/dcim/filters.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index a653173f9..f3cf87764 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -13,6 +13,7 @@ * [#5574](https://github.com/netbox-community/netbox/issues/5574) - Restrict the creation of device bay templates on non-parent device types * [#5584](https://github.com/netbox-community/netbox/issues/5584) - Restore power utilization panel under device view * [#5597](https://github.com/netbox-community/netbox/issues/5597) - Fix ordering devices by primary IP address +* [#5639](https://github.com/netbox-community/netbox/issues/5639) - Fix filtering connection lists by device name --- diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 05ae08923..03deca2a4 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -1152,7 +1152,7 @@ class ConnectionFilterSet: def filter_device(self, queryset, name, value): if not value: return queryset - return queryset.filter(device_id__in=value) + return queryset.filter(**{f'{name}__in': value}) class ConsoleConnectionFilterSet(ConnectionFilterSet, BaseFilterSet): From b2dde111a77672c9540a0ca1578010c1373838a5 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 20 Jan 2021 15:18:13 -0500 Subject: [PATCH 11/30] Fixes #5640: Fix permissions assessment when adding VM interfaces in bulk --- docs/release-notes/version-2.10.md | 1 + netbox/templates/virtualization/virtualmachine_list.html | 2 +- netbox/virtualization/views.py | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index f3cf87764..0ef5f2a0f 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -14,6 +14,7 @@ * [#5584](https://github.com/netbox-community/netbox/issues/5584) - Restore power utilization panel under device view * [#5597](https://github.com/netbox-community/netbox/issues/5597) - Fix ordering devices by primary IP address * [#5639](https://github.com/netbox-community/netbox/issues/5639) - Fix filtering connection lists by device name +* [#5640](https://github.com/netbox-community/netbox/issues/5640) - Fix permissions assessment when adding VM interfaces in bulk --- diff --git a/netbox/templates/virtualization/virtualmachine_list.html b/netbox/templates/virtualization/virtualmachine_list.html index 9d8c1720f..245e55092 100644 --- a/netbox/templates/virtualization/virtualmachine_list.html +++ b/netbox/templates/virtualization/virtualmachine_list.html @@ -7,7 +7,7 @@ Add Components
{% endif %} diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index 9ef4a0863..dcf9ebcda 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -396,3 +396,6 @@ class VirtualMachineBulkAddInterfaceView(generic.BulkComponentCreateView): model_form = forms.VMInterfaceForm filterset = filters.VirtualMachineFilterSet table = tables.VirtualMachineTable + + def get_required_permission(self): + return f'virtualization.add_vminterface' From cad2f31aaa6f3b4b54f93fc5545ae9433ae4129a Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 20 Jan 2021 15:36:04 -0500 Subject: [PATCH 12/30] Add NetBox installation video to docs --- docs/installation/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/installation/index.md b/docs/installation/index.md index 730176e0c..71e669295 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -11,6 +11,10 @@ The following sections detail how to set up a new instance of NetBox: 5. [HTTP server](5-http-server.md) 6. [LDAP authentication](6-ldap.md) (optional) +The video below demonstrates the installation of NetBox v2.10.3 on Ubuntu 20.04 for your reference. + + + ## Requirements | Dependency | Minimum Version | From 23b17b8303d3a0513fc9301dec7aa16e13ee83ee Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 20 Jan 2021 23:52:54 +0000 Subject: [PATCH 13/30] Fix white cables --- netbox/templates/dcim/trace/cable.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/templates/dcim/trace/cable.html b/netbox/templates/dcim/trace/cable.html index 4235768a6..7a7fbcf55 100644 --- a/netbox/templates/dcim/trace/cable.html +++ b/netbox/templates/dcim/trace/cable.html @@ -1,6 +1,6 @@ {% load helpers %} -
+
{% if cable.label %}{{ cable.label }}{% else %}Cable #{{ cable.pk }}{% endif %} From b938f5cfa258e91f02cc7113172de82535463ff4 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 20 Jan 2021 20:48:24 -0500 Subject: [PATCH 14/30] Changelog for #5603 --- docs/release-notes/version-2.10.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index 0ef5f2a0f..16d48dba7 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -13,6 +13,7 @@ * [#5574](https://github.com/netbox-community/netbox/issues/5574) - Restrict the creation of device bay templates on non-parent device types * [#5584](https://github.com/netbox-community/netbox/issues/5584) - Restore power utilization panel under device view * [#5597](https://github.com/netbox-community/netbox/issues/5597) - Fix ordering devices by primary IP address +* [#5603](https://github.com/netbox-community/netbox/issues/5603) - Fix display of white cables in trace view * [#5639](https://github.com/netbox-community/netbox/issues/5639) - Fix filtering connection lists by device name * [#5640](https://github.com/netbox-community/netbox/issues/5640) - Fix permissions assessment when adding VM interfaces in bulk From 44d848eab2aae980f056406daf7b0405d648c3b5 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 20 Jan 2021 21:29:23 -0500 Subject: [PATCH 15/30] Closes #5542: Show cable trace lengths in both meters and feet --- docs/release-notes/version-2.10.md | 1 + netbox/templates/dcim/cable_trace.html | 3 ++- netbox/utilities/templatetags/helpers.py | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index 16d48dba7..27d9fef49 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -4,6 +4,7 @@ ### Enhancements +* [#5542](https://github.com/netbox-community/netbox/issues/5542) - Show cable trace lengths in both meters and feet * [#5570](https://github.com/netbox-community/netbox/issues/5570) - Add "management only" filter widget for interfaces list * [#5586](https://github.com/netbox-community/netbox/issues/5586) - Allow filtering virtual chassis by name and master * [#5612](https://github.com/netbox-community/netbox/issues/5612) - Add GG45 and TERA port types, and CAT7a and CAT8 cable types diff --git a/netbox/templates/dcim/cable_trace.html b/netbox/templates/dcim/cable_trace.html index a36922612..a39ada1ce 100644 --- a/netbox/templates/dcim/cable_trace.html +++ b/netbox/templates/dcim/cable_trace.html @@ -69,7 +69,8 @@
Total segments: {{ traced_path|length }}
Total length: {% if total_length %} - {{ total_length|floatformat:"-2" }} Meters + {{ total_length|floatformat:"-2" }} Meters / + {{ total_length|meters_to_feet|floatformat:"-2" }} Feet {% else %} N/A {% endif %} diff --git a/netbox/utilities/templatetags/helpers.py b/netbox/utilities/templatetags/helpers.py index 29c920d4f..01dce8479 100644 --- a/netbox/utilities/templatetags/helpers.py +++ b/netbox/utilities/templatetags/helpers.py @@ -220,6 +220,14 @@ def as_range(n): return range(n) +@register.filter() +def meters_to_feet(n): + """ + Convert a length from meters to feet. + """ + return float(n) * 3.28084 + + # # Tags # From 39c0133b3030b0dc93950042749bffee8d927b66 Mon Sep 17 00:00:00 2001 From: Riley Littlefield Date: Sat, 23 Jan 2021 13:41:48 -0500 Subject: [PATCH 16/30] Fixes typo --- docs/configuration/required-settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/required-settings.md b/docs/configuration/required-settings.md index 2edf6c7c7..f03745930 100644 --- a/docs/configuration/required-settings.md +++ b/docs/configuration/required-settings.md @@ -5,7 +5,7 @@ This is a list of valid fully-qualified domain names (FQDNs) and/or IP addresses that can be used to reach the NetBox service. Usually this is the same as the hostname for the NetBox server, but can also be different; for example, when using a reverse proxy serving the NetBox website under a different FQDN than the hostname of the NetBox server. To help guard against [HTTP Host header attackes](https://docs.djangoproject.com/en/3.0/topics/security/#host-headers-virtual-hosting), NetBox will not permit access to the server via any other hostnames (or IPs). !!! note - This parameter must always be defined as a list or tuple, even if only value is provided. + This parameter must always be defined as a list or tuple, even if only a single value is provided. The value of this option is also used to set `CSRF_TRUSTED_ORIGINS`, which restricts POST requests to the same set of hosts (more about this [here](https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-CSRF_TRUSTED_ORIGINS)). Keep in mind that NetBox, by default, sets `USE_X_FORWARDED_HOST` to true, which means that if you're using a reverse proxy, it's the FQDN used to reach that reverse proxy which needs to be in this list (more about this [here](https://docs.djangoproject.com/en/stable/ref/settings/#allowed-hosts)). From 2cd0677803377315c950fd70bf1c17d2c3de360a Mon Sep 17 00:00:00 2001 From: Riley Littlefield Date: Sat, 23 Jan 2021 13:54:44 -0500 Subject: [PATCH 17/30] Fixes another typo --- docs/configuration/required-settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/required-settings.md b/docs/configuration/required-settings.md index f03745930..dba8cdc8c 100644 --- a/docs/configuration/required-settings.md +++ b/docs/configuration/required-settings.md @@ -101,7 +101,7 @@ REDIS = { If you are using [Redis Sentinel](https://redis.io/topics/sentinel) for high-availability purposes, there is minimal configuration necessary to convert NetBox to recognize it. It requires the removal of the `HOST` and `PORT` keys from -above and the addition of two new keys. +above and the addition of three new keys. * `SENTINELS`: List of tuples or tuple of tuples with each inner tuple containing the name or IP address of the Redis server and port for each sentinel instance to connect to From 5988b5d73bdcdfc8b3c9d8f6dc3074292565bb05 Mon Sep 17 00:00:00 2001 From: Riley Littlefield Date: Sat, 23 Jan 2021 14:06:48 -0500 Subject: [PATCH 18/30] Fixes small typo in optional settings --- docs/configuration/optional-settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/optional-settings.md b/docs/configuration/optional-settings.md index 91c0e7597..4af83493e 100644 --- a/docs/configuration/optional-settings.md +++ b/docs/configuration/optional-settings.md @@ -56,7 +56,7 @@ BASE_PATH = 'netbox/' Default: 900 -The number of seconds to cache entries will be retained before expiring. +The number of seconds that cache entries will be retained before expiring. --- From c7a354dfb502358b3d5a60dce827fc5f8935545a Mon Sep 17 00:00:00 2001 From: Thomas Fargeix Date: Sun, 24 Jan 2021 21:20:55 +0100 Subject: [PATCH 19/30] Fix how SECRET_KEY is generated Use secrets.choice instead of random.sample to generate the secret key. --- netbox/generate_secret_key.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/netbox/generate_secret_key.py b/netbox/generate_secret_key.py index 3c88aa710..c3de29cee 100755 --- a/netbox/generate_secret_key.py +++ b/netbox/generate_secret_key.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # This script will generate a random 50-character string suitable for use as a SECRET_KEY. -import random +import secrets charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*(-_=+)' -secure_random = random.SystemRandom() -print(''.join(secure_random.sample(charset, 50))) +print(''.join(secrets.choice(charset) for _ in range(50))) From e2887911ff59829690409433e7227b79e4a4d79a Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 25 Jan 2021 14:19:32 -0500 Subject: [PATCH 20/30] Fixes #5665: Validate rack group is assigned to same site when creating a rack --- docs/release-notes/version-2.10.md | 1 + netbox/dcim/models/racks.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index 27d9fef49..98595ff4a 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -17,6 +17,7 @@ * [#5603](https://github.com/netbox-community/netbox/issues/5603) - Fix display of white cables in trace view * [#5639](https://github.com/netbox-community/netbox/issues/5639) - Fix filtering connection lists by device name * [#5640](https://github.com/netbox-community/netbox/issues/5640) - Fix permissions assessment when adding VM interfaces in bulk +* [#5665](https://github.com/netbox-community/netbox/issues/5665) - Validate rack group is assigned to same site when creating a rack --- diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index ccc775954..dfaf7da61 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -299,6 +299,10 @@ class Rack(ChangeLoggedModel, CustomFieldModel): def clean(self): super().clean() + # Validate group/site assignment + if self.site and self.group and self.group.site != self.site: + raise ValidationError(f"Assigned rack group must belong to parent site ({self.site}).") + # Validate outer dimensions and unit if (self.outer_width is not None or self.outer_depth is not None) and not self.outer_unit: raise ValidationError("Must specify a unit when setting an outer width/depth") From 12c7d4cab28d99570569e3f26ed49463c8eb76e1 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 25 Jan 2021 14:29:03 -0500 Subject: [PATCH 21/30] Fixes #5648: Include VC member interfaces on interfaces tab count when viewing VC master --- docs/release-notes/version-2.10.md | 1 + netbox/templates/dcim/device/base.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index 98595ff4a..05b48a896 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -17,6 +17,7 @@ * [#5603](https://github.com/netbox-community/netbox/issues/5603) - Fix display of white cables in trace view * [#5639](https://github.com/netbox-community/netbox/issues/5639) - Fix filtering connection lists by device name * [#5640](https://github.com/netbox-community/netbox/issues/5640) - Fix permissions assessment when adding VM interfaces in bulk +* [#5648](https://github.com/netbox-community/netbox/issues/5648) - Include VC member interfaces on interfaces tab count when viewing VC master * [#5665](https://github.com/netbox-community/netbox/issues/5665) - Validate rack group is assigned to same site when creating a rack --- diff --git a/netbox/templates/dcim/device/base.html b/netbox/templates/dcim/device/base.html index 631abde89..8f488b284 100644 --- a/netbox/templates/dcim/device/base.html +++ b/netbox/templates/dcim/device/base.html @@ -90,7 +90,7 @@ - {% with interface_count=object.interfaces.count %} + {% with interface_count=object.vc_interfaces.count %} {% if interface_count %}
- {% with rack=object.rack %} -
-
-
-

Front

-
- {% include 'dcim/inc/rack_elevation.html' with face='front' %} -
-
-
-

Rear

-
- {% include 'dcim/inc/rack_elevation.html' with face='rear' %} +
+
+
+

Front

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

Rear

+
+ {% include 'dcim/inc/rack_elevation.html' with object=object.rack face='rear' %} +
+
{% plugin_right_page object %}
From 3ec4a2e4d44669368f50ee5094754318e3ba4060 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 26 Jan 2021 10:17:58 -0500 Subject: [PATCH 23/30] Closes #5678: Show available type choices for all device component import forms --- docs/release-notes/version-2.10.md | 1 + netbox/dcim/forms.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index 1d954d383..02897b614 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -8,6 +8,7 @@ * [#5570](https://github.com/netbox-community/netbox/issues/5570) - Add "management only" filter widget for interfaces list * [#5586](https://github.com/netbox-community/netbox/issues/5586) - Allow filtering virtual chassis by name and master * [#5612](https://github.com/netbox-community/netbox/issues/5612) - Add GG45 and TERA port types, and CAT7a and CAT8 cable types +* [#5678](https://github.com/netbox-community/netbox/issues/5678) - Show available type choices for all device component import forms ### Bug Fixes diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 18fdbdb40..fd533b6ac 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -2352,6 +2352,10 @@ class ConsolePortCSVForm(CSVModelForm): queryset=Device.objects.all(), to_field_name='name' ) + type = CSVChoiceField( + choices=ConsolePortTypeChoices, + help_text='Port type' + ) class Meta: model = ConsolePort @@ -2425,6 +2429,10 @@ class ConsoleServerPortCSVForm(CSVModelForm): queryset=Device.objects.all(), to_field_name='name' ) + type = CSVChoiceField( + choices=ConsolePortTypeChoices, + help_text='Port type' + ) class Meta: model = ConsoleServerPort @@ -2510,6 +2518,10 @@ class PowerPortCSVForm(CSVModelForm): queryset=Device.objects.all(), to_field_name='name' ) + type = CSVChoiceField( + choices=PowerPortTypeChoices, + help_text='Port type' + ) class Meta: model = PowerPort @@ -2630,6 +2642,10 @@ class PowerOutletCSVForm(CSVModelForm): queryset=Device.objects.all(), to_field_name='name' ) + type = CSVChoiceField( + choices=PowerOutletTypeChoices, + help_text='Outlet type' + ) power_port = CSVModelChoiceField( queryset=PowerPort.objects.all(), required=False, From fdaa49b03bc52dd9874b4cd83a7f6df685c9d9eb Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 26 Jan 2021 10:35:03 -0500 Subject: [PATCH 24/30] Certain component types are optional --- netbox/dcim/forms.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index fd533b6ac..40c16d59f 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -2354,6 +2354,7 @@ class ConsolePortCSVForm(CSVModelForm): ) type = CSVChoiceField( choices=ConsolePortTypeChoices, + required=False, help_text='Port type' ) @@ -2431,6 +2432,7 @@ class ConsoleServerPortCSVForm(CSVModelForm): ) type = CSVChoiceField( choices=ConsolePortTypeChoices, + required=False, help_text='Port type' ) @@ -2520,6 +2522,7 @@ class PowerPortCSVForm(CSVModelForm): ) type = CSVChoiceField( choices=PowerPortTypeChoices, + required=False, help_text='Port type' ) @@ -2644,6 +2647,7 @@ class PowerOutletCSVForm(CSVModelForm): ) type = CSVChoiceField( choices=PowerOutletTypeChoices, + required=False, help_text='Outlet type' ) power_port = CSVModelChoiceField( From d50201df943b9c287373e107c3db3edc6591cf16 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 26 Jan 2021 11:20:06 -0500 Subject: [PATCH 25/30] Emphasize use of GitHub discussions in README --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 68927463d..a12daa783 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,7 @@ complete list of requirements, see `requirements.txt`. The code is available [on The complete documentation for NetBox can be found at [Read the Docs](https://netbox.readthedocs.io/en/stable/). -Questions? Comments? Please start a [discussion on GitHub](https://github.com/netbox-community/netbox/discussions), -or join us in the **#netbox** Slack channel on [NetworkToCode](https://networktocode.slack.com/)! +Questions? Comments? Start by perusing our [GitHub discussions](https://github.com/netbox-community/netbox/discussions) for the topic you have in mind. ### Build Status From 4465c1a3ae155a8b26f804ecca6c413749566288 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 26 Jan 2021 10:34:07 -0600 Subject: [PATCH 26/30] Fixes: #5232 - Corrects swagger definition --- docs/release-notes/version-2.10.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index 02897b614..9be3f22d1 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -12,6 +12,7 @@ ### Bug Fixes +* [#5232](https://github.com/netbox-community/netbox/issues/5232) - Correct swagger definition for ip_prefixes_available-ips_create API * [#5574](https://github.com/netbox-community/netbox/issues/5574) - Restrict the creation of device bay templates on non-parent device types * [#5584](https://github.com/netbox-community/netbox/issues/5584) - Restore power utilization panel under device view * [#5597](https://github.com/netbox-community/netbox/issues/5597) - Fix ordering devices by primary IP address From e4c5e90055020f316f759f738554a5040fda9074 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 26 Jan 2021 10:34:07 -0600 Subject: [PATCH 27/30] Fixes: #5232 - Corrects swagger definition --- docs/release-notes/version-2.10.md | 1 + netbox/ipam/api/views.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index 02897b614..9be3f22d1 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -12,6 +12,7 @@ ### Bug Fixes +* [#5232](https://github.com/netbox-community/netbox/issues/5232) - Correct swagger definition for ip_prefixes_available-ips_create API * [#5574](https://github.com/netbox-community/netbox/issues/5574) - Restrict the creation of device bay templates on non-parent device types * [#5584](https://github.com/netbox-community/netbox/issues/5584) - Restore power utilization panel under device view * [#5597](https://github.com/netbox-community/netbox/issues/5597) - Fix ordering devices by primary IP address diff --git a/netbox/ipam/api/views.py b/netbox/ipam/api/views.py index d9eae69aa..c322c249d 100644 --- a/netbox/ipam/api/views.py +++ b/netbox/ipam/api/views.py @@ -178,7 +178,7 @@ class PrefixViewSet(CustomFieldModelViewSet): @swagger_auto_schema(method='get', responses={200: serializers.AvailableIPSerializer(many=True)}) @swagger_auto_schema(method='post', responses={201: serializers.AvailableIPSerializer(many=True)}, - request_body=serializers.AvailableIPSerializer(many=False)) + request_body=serializers.AvailableIPSerializer(many=True)) @action(detail=True, url_path='available-ips', methods=['get', 'post'], queryset=IPAddress.objects.all()) @advisory_lock(ADVISORY_LOCK_KEYS['available-ips']) def available_ips(self, request, pk=None): From 4966443804e7291010a5b53da840c787d9f48923 Mon Sep 17 00:00:00 2001 From: Aaron Date: Tue, 26 Jan 2021 11:47:33 -0600 Subject: [PATCH 28/30] update python package name At least on ubuntu 20.04, the python3 package is now 3.8, but the package 'python3' points to the current best version of python available without needing to specialize a minor version and should require fewer changes to the document. --- docs/installation/3-netbox.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/3-netbox.md b/docs/installation/3-netbox.md index 9745df1f3..7698be4ad 100644 --- a/docs/installation/3-netbox.md +++ b/docs/installation/3-netbox.md @@ -12,7 +12,7 @@ Begin by installing all system packages required by NetBox and its dependencies. ### Ubuntu ```no-highlight -sudo apt install -y python3.6 python3-pip python3-venv python3-dev build-essential libxml2-dev libxslt1-dev libffi-dev libpq-dev libssl-dev zlib1g-dev +sudo apt install -y python3 python3-pip python3-venv python3-dev build-essential libxml2-dev libxslt1-dev libffi-dev libpq-dev libssl-dev zlib1g-dev ``` ### CentOS From 20296237f85b6b2f28d97197e9ff8375cf8e0e56 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 26 Jan 2021 13:06:29 -0500 Subject: [PATCH 29/30] Release v2.10.4 --- docs/release-notes/version-2.10.md | 2 +- netbox/netbox/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-2.10.md b/docs/release-notes/version-2.10.md index 9be3f22d1..b6bc33229 100644 --- a/docs/release-notes/version-2.10.md +++ b/docs/release-notes/version-2.10.md @@ -1,6 +1,6 @@ # NetBox v2.10 -## v2.10.4 (FUTURE) +## v2.10.4 (2021-01-26) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index ed1f9c732..3dd780b26 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -16,7 +16,7 @@ from django.core.validators import URLValidator # Environment setup # -VERSION = '2.10.4-dev' +VERSION = '2.10.4' # Hostname HOSTNAME = platform.node() From e2189292037ca11df88d923d64108491aad5a212 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 26 Jan 2021 14:03:46 -0600 Subject: [PATCH 30/30] Corrects error with ListSerializer as request_body --- netbox/utilities/custom_inspectors.py | 51 ++++++++++++++++----------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/netbox/utilities/custom_inspectors.py b/netbox/utilities/custom_inspectors.py index 95c647fb8..b110a9123 100644 --- a/netbox/utilities/custom_inspectors.py +++ b/netbox/utilities/custom_inspectors.py @@ -28,29 +28,38 @@ class NetBoxSwaggerAutoSchema(SwaggerAutoSchema): serializer = super().get_request_serializer() if serializer is not None and self.method in self.implicit_body_methods: - properties = {} - for child_name, child in serializer.fields.items(): - if isinstance(child, (ChoiceField, WritableNestedSerializer)): - properties[child_name] = None - elif isinstance(child, ManyRelatedField) and isinstance(child.child_relation, SerializedPKRelatedField): - properties[child_name] = None - - if properties: - if type(serializer) not in self.writable_serializers: - writable_name = 'Writable' + type(serializer).__name__ - meta_class = getattr(type(serializer), 'Meta', None) - if meta_class: - ref_name = 'Writable' + get_serializer_ref_name(serializer) - writable_meta = type('Meta', (meta_class,), {'ref_name': ref_name}) - properties['Meta'] = writable_meta - - self.writable_serializers[type(serializer)] = type(writable_name, (type(serializer),), properties) - - writable_class = self.writable_serializers[type(serializer)] - serializer = writable_class() - + writable_class = self.get_writable_class(serializer) + if writable_class is not None: + if hasattr(serializer, 'child'): + child_serializer = self.get_writable_class(serializer.child) + serializer = writable_class(child=child_serializer) + else: + serializer = writable_class() return serializer + def get_writable_class(self, serializer): + properties = {} + fields = {} if hasattr(serializer, 'child') else serializer.fields + for child_name, child in fields.items(): + if isinstance(child, (ChoiceField, WritableNestedSerializer)): + properties[child_name] = None + elif isinstance(child, ManyRelatedField) and isinstance(child.child_relation, SerializedPKRelatedField): + properties[child_name] = None + + if properties: + if type(serializer) not in self.writable_serializers: + writable_name = 'Writable' + type(serializer).__name__ + meta_class = getattr(type(serializer), 'Meta', None) + if meta_class: + ref_name = 'Writable' + get_serializer_ref_name(serializer) + writable_meta = type('Meta', (meta_class,), {'ref_name': ref_name}) + properties['Meta'] = writable_meta + + self.writable_serializers[type(serializer)] = type(writable_name, (type(serializer),), properties) + + writable_class = self.writable_serializers[type(serializer)] + return writable_class + class SerializedPKRelatedFieldInspector(FieldInspector): def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):