From 090336233484aeb3ce8f5e6532effb204a37dd52 Mon Sep 17 00:00:00 2001 From: Moh Ahmed Date: Tue, 17 Sep 2019 15:51:29 -0400 Subject: [PATCH 01/26] Adding a reference to deploying NetBox via Kubernetes manifests --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dc673221d..617268c69 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ and run `upgrade.sh`. * [Docker container](https://github.com/netbox-community/netbox-docker) (via [@cimnine](https://github.com/cimnine)) * [Vagrant deployment](https://github.com/ryanmerolle/netbox-vagrant) (via [@ryanmerolle](https://github.com/ryanmerolle)) * [Ansible deployment](https://github.com/lae/ansible-role-netbox) (via [@lae](https://github.com/lae)) +* [Kubernetes deployment](https://github.com/CENGN/netbox-kubernetes) (via [@CENGN](https://github.com/CENGN)) # Related projects From a1216fc1b7f48be207de7ea99ea1a957a9a1a458 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Thu, 19 Sep 2019 10:32:47 -0500 Subject: [PATCH 02/26] Fixed thrown error in parseURL --- netbox/project-static/js/forms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/project-static/js/forms.js b/netbox/project-static/js/forms.js index 287c19465..4e50095ef 100644 --- a/netbox/project-static/js/forms.js +++ b/netbox/project-static/js/forms.js @@ -75,7 +75,7 @@ $(document).ready(function() { var rendered_url = url; var filter_field; while (match = filter_regex.exec(url)) { - filter_field = $('#id_' + match[1]);untagged + filter_field = $('#id_' + match[1]); var custom_attr = $('option:selected', filter_field).attr('api-value'); if (custom_attr) { rendered_url = rendered_url.replace(match[0], custom_attr); From 0798533201eb4b13b7357853b35264eadb421ee9 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 20 Sep 2019 09:10:32 -0400 Subject: [PATCH 03/26] Add docs link for custom scripts; arrange links alphabetically --- mkdocs.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 99f77d06c..932536d66 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -27,17 +27,18 @@ pages: - Secrets: 'core-functionality/secrets.md' - Tenancy: 'core-functionality/tenancy.md' - Additional Features: - - Tags: 'additional-features/tags.md' - - Custom Fields: 'additional-features/custom-fields.md' + - Caching: 'additional-features/caching.md' + - Change Logging: 'additional-features/change-logging.md' - Context Data: 'additional-features/context-data.md' + - Custom Fields: 'additional-features/custom-fields.md' + - Custom Scripts: 'additional-features/custom-scripts.md' - Export Templates: 'additional-features/export-templates.md' - Graphs: 'additional-features/graphs.md' - - Topology Maps: 'additional-features/topology-maps.md' - - Reports: 'additional-features/reports.md' - - Webhooks: 'additional-features/webhooks.md' - - Change Logging: 'additional-features/change-logging.md' - - Caching: 'additional-features/caching.md' - Prometheus Metrics: 'additional-features/prometheus-metrics.md' + - Reports: 'additional-features/reports.md' + - Tags: 'additional-features/tags.md' + - Topology Maps: 'additional-features/topology-maps.md' + - Webhooks: 'additional-features/webhooks.md' - Administration: - Replicating NetBox: 'administration/replicating-netbox.md' - NetBox Shell: 'administration/netbox-shell.md' From f8e10f66e136a05db4ee70206f506ad28c663153 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 23 Sep 2019 09:21:38 -0400 Subject: [PATCH 04/26] Remove extraneous demo scripts --- netbox/scripts/examples.py | 66 ------------------------------------- netbox/scripts/myscripts.py | 54 ------------------------------ 2 files changed, 120 deletions(-) delete mode 100644 netbox/scripts/examples.py delete mode 100644 netbox/scripts/myscripts.py diff --git a/netbox/scripts/examples.py b/netbox/scripts/examples.py deleted file mode 100644 index b2adf8da4..000000000 --- a/netbox/scripts/examples.py +++ /dev/null @@ -1,66 +0,0 @@ -from django.utils.text import slugify - -from dcim.constants import * -from dcim.models import Device, DeviceRole, DeviceType, Site -from extras.scripts import * - - -class NewBranchScript(Script): - script_name = "New Branch" - script_description = "Provision a new branch site" - script_fields = ['site_name', 'switch_count', 'switch_model'] - - site_name = StringVar( - description="Name of the new site" - ) - switch_count = IntegerVar( - description="Number of access switches to create" - ) - switch_model = ObjectVar( - description="Access switch model", - queryset=DeviceType.objects.filter( - manufacturer__name='Cisco', - model__in=['Catalyst 3560X-48T', 'Catalyst 3750X-48T'] - ) - ) - x = BooleanVar( - description="Check me out" - ) - - def run(self, data): - - # Create the new site - site = Site( - name=data['site_name'], - slug=slugify(data['site_name']), - status=SITE_STATUS_PLANNED - ) - site.save() - self.log_success("Created new site: {}".format(site)) - - # Create access switches - switch_role = DeviceRole.objects.get(name='Access Switch') - for i in range(1, data['switch_count'] + 1): - switch = Device( - device_type=data['switch_model'], - name='{}-switch{}'.format(site.slug, i), - site=site, - status=DEVICE_STATUS_PLANNED, - device_role=switch_role - ) - switch.save() - self.log_success("Created new switch: {}".format(switch)) - - # Generate a CSV table of new devices - output = [ - 'name,make,model' - ] - for switch in Device.objects.filter(site=site): - attrs = [ - switch.name, - switch.device_type.manufacturer.name, - switch.device_type.model - ] - output.append(','.join(attrs)) - - return '\n'.join(output) diff --git a/netbox/scripts/myscripts.py b/netbox/scripts/myscripts.py deleted file mode 100644 index f3542c368..000000000 --- a/netbox/scripts/myscripts.py +++ /dev/null @@ -1,54 +0,0 @@ -from dcim.models import Site -from extras.scripts import Script, BooleanVar, IntegerVar, ObjectVar, StringVar - - -class NoInputScript(Script): - description = "This script does not require any input" - - def run(self, data): - - self.log_debug("This a debug message.") - self.log_info("This an info message.") - self.log_success("This a success message.") - self.log_warning("This a warning message.") - self.log_failure("This a failure message.") - - -class DemoScript(Script): - name = "Script Demo" - description = "A quick demonstration of the available field types" - - my_string1 = StringVar( - description="Input a string between 3 and 10 characters", - min_length=3, - max_length=10 - ) - my_string2 = StringVar( - description="This field enforces a regex: three letters followed by three numbers", - regex=r'[a-z]{3}\d{3}' - ) - my_number = IntegerVar( - description="Pick a number between 1 and 255 (inclusive)", - min_value=1, - max_value=255 - ) - my_boolean = BooleanVar( - description="Use the checkbox to toggle true/false" - ) - my_object = ObjectVar( - description="Select a NetBox site", - queryset=Site.objects.all() - ) - - def run(self, data): - - self.log_info("Your string was {}".format(data['my_string1'])) - self.log_info("Your second string was {}".format(data['my_string2'])) - self.log_info("Your number was {}".format(data['my_number'])) - if data['my_boolean']: - self.log_info("You ticked the checkbox") - else: - self.log_info("You did not tick the checkbox") - self.log_info("You chose the sites {}".format(data['my_object'])) - - return "Here's some output" From a17060c060392862ba51a2650a2821f44426d53f Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Mon, 23 Sep 2019 13:04:13 -0500 Subject: [PATCH 05/26] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0facf5f62..85d9124f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +v2.6.5 (FUTURE) + +## Bug Fixes + +* [#3521](https://github.com/netbox-community/netbox/issues/3521) - Fixed error in parseURL related to {{variables}} in API url + v2.6.4 (2019-09-19) ## Enhancements From b0724dfd1466e22ed1e21c23c5788fbdcbfe205e Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 23 Sep 2019 14:57:01 -0400 Subject: [PATCH 06/26] Add developer guidance --- CONTRIBUTING.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f27317deb..a688be9b3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -117,3 +117,25 @@ Only comment on an issue if you are sharing a relevant idea or constructive feedback. **Do not** comment on an issue just to show your support (give the top post a :+1: instead) or ask for an ETA. These comments will be deleted to reduce noise in the discussion. + +## Maintainer Guidance + +* Maintainers are expected to contribute at least four hours per week to the + project on average. This can be employer-sponsored or individual time, with + the understanding that all contributions are submitted under the Apache 2.0 + license and that your employer may not make claim to any contributions. + Contributions include code work, issue management, and community support. All + development must be in accordance with our [development guidance](https://netbox.readthedocs.io/en/stable/development/). + +* Maintainers are expected to attend (where feasible) our biweekly ~30-minute + sync to review agenda items. This meeting provides opportunity to present and + discuss pressing topics. Meetings are held as virtual audio/video conferences. + +* Official channels for communication include: + + * GitHub issues/pull requests + * The [netbox-discuss](https://groups.google.com/forum/#!forum/netbox-discuss) mailing list + * The **#netbox** channel on [NetworkToCode Slack](https://networktocode.slack.com/) + +* Maintainers with no substantial recorded activity in a 60-day period will be + removed from the project. From 8996c530c92522652796224be312dfcc3b655dc5 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 24 Sep 2019 08:39:41 -0500 Subject: [PATCH 07/26] Fixes: #3534 - Add none option for untagged vlan field --- netbox/dcim/forms.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index aec7a6723..939470756 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -2220,7 +2220,7 @@ class InterfaceForm(InterfaceCommonForm, BootstrapMixin, forms.ModelForm): [(vlan.pk, vlan) for vlan in site_group_vlans] )) - self.fields['untagged_vlan'].choices = vlan_choices + self.fields['untagged_vlan'].choices = [(None, '---------')] + vlan_choices self.fields['tagged_vlans'].choices = vlan_choices @@ -2330,7 +2330,7 @@ class InterfaceCreateForm(InterfaceCommonForm, ComponentForm, forms.Form): [(vlan.pk, vlan) for vlan in site_group_vlans] )) - self.fields['untagged_vlan'].choices = vlan_choices + self.fields['untagged_vlan'].choices = [(None, '---------')] + vlan_choices self.fields['tagged_vlans'].choices = vlan_choices @@ -2442,7 +2442,7 @@ class InterfaceBulkEditForm(InterfaceCommonForm, BootstrapMixin, AddRemoveTagsFo [(vlan.pk, vlan) for vlan in site_group_vlans] )) - self.fields['untagged_vlan'].choices = vlan_choices + self.fields['untagged_vlan'].choices = [(None, '---------')] + vlan_choices self.fields['tagged_vlans'].choices = vlan_choices From fb34507defb09f96c5591d42ba294f6f5e7e0696 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 24 Sep 2019 08:45:31 -0500 Subject: [PATCH 08/26] Fixes: #3532 - add device to graph type for documentation --- docs/additional-features/graphs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/additional-features/graphs.md b/docs/additional-features/graphs.md index 7b37276e8..b20a6b424 100644 --- a/docs/additional-features/graphs.md +++ b/docs/additional-features/graphs.md @@ -2,7 +2,7 @@ NetBox does not have the ability to generate graphs natively, but this feature allows you to embed contextual graphs from an external resources (such as a monitoring system) inside the site, provider, and interface views. Each embedded graph must be defined with the following parameters: -* **Type:** Site, provider, or interface. This determines in which view the graph will be displayed. +* **Type:** Site, device, provider, or interface. This determines in which view the graph will be displayed. * **Weight:** Determines the order in which graphs are displayed (lower weights are displayed first). Graphs with equal weights will be ordered alphabetically by name. * **Name:** The title to display above the graph. * **Source URL:** The source of the image to be embedded. The associated object will be available as a template variable named `obj`. From 6fdd35785edf6e0806432268521ac0ad6c3771bc Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 24 Sep 2019 08:50:23 -0500 Subject: [PATCH 09/26] Fixes: #3531 - Fix FG Color for Rack Role --- netbox/dcim/tables.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netbox/dcim/tables.py b/netbox/dcim/tables.py index 250173d79..ae42c507e 100644 --- a/netbox/dcim/tables.py +++ b/netbox/dcim/tables.py @@ -74,7 +74,8 @@ RACKROLE_ACTIONS = """ RACK_ROLE = """ {% if record.role %} - + {% load helpers %} + {% else %} — {% endif %} From 17ec9aa170fee176209a0dcb327145d9b19a4f20 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 24 Sep 2019 09:39:06 -0500 Subject: [PATCH 10/26] Fixes: #3464 - Change color picker to dynamic coloring from static CSS --- netbox/project-static/css/base.css | 110 ------------------ netbox/project-static/js/forms.js | 7 +- .../templates/widgets/colorselect_option.html | 3 +- 3 files changed, 4 insertions(+), 116 deletions(-) diff --git a/netbox/project-static/css/base.css b/netbox/project-static/css/base.css index 24cf9a9ea..d37a2106e 100644 --- a/netbox/project-static/css/base.css +++ b/netbox/project-static/css/base.css @@ -133,116 +133,6 @@ input[name="pk"] { margin-top: 0; } -/* Color Selections */ -.color-selection-aa1409 { - background-color: #aa1409; - color: #ffffff; -} -.color-selection-f44336 { - background-color: #f44336; - color: #ffffff; -} -.color-selection-e91e63 { - background-color: #e91e63; - color: #ffffff; -} -.color-selection-ffe4e1 { - background-color: #ffe4e1; - color: #000000; -} -.color-selection-ff66ff { - background-color: #ff66ff; - color: #ffffff; -} -.color-selection-9c27b0 { - background-color: #9c27b0; - color: #ffffff; -} -.color-selection-673ab7 { - background-color: #673ab7; - color: #ffffff; -} -.color-selection-3f51b5 { - background-color: #3f51b5; - color: #ffffff; -} -.color-selection-2196f3 { - background-color: #2196f3; - color: #ffffff; -} -.color-selection-03a9f4 { - background-color: #03a9f4; - color: #ffffff; -} -.color-selection-00bcd4 { - background-color: #00bcd4; - color: #ffffff; -} -.color-selection-009688 { - background-color: #009688; - color: #ffffff; -} -.color-selection-00ffff { - background-color: #00ffff; - color: #ffffff; -} -.color-selection-2f6a31 { - background-color: #2f6a31; - color: #ffffff; -} -.color-selection-4caf50 { - background-color: #4caf50; - color: #ffffff; -} -.color-selection-8bc34a { - background-color: #8bc34a; - color: #ffffff; -} -.color-selection-cddc39 { - background-color: #cddc39; - color: #000000; -} -.color-selection-ffeb3b { - background-color: #ffeb3b; - color: #000000; -} -.color-selection-ffc107 { - background-color: #ffc107; - color: #000000; -} -.color-selection-ff9800 { - background-color: #ff9800; - color: #ffffff; -} -.color-selection-ff5722 { - background-color: #ff5722; - color: #ffffff; -} -.color-selection-795548 { - background-color: #795548; - color: #ffffff; -} -.color-selection-c0c0c0 { - background-color: #c0c0c0; - color: #000000; -} -.color-selection-9e9e9e { - background-color: #9e9e9e; - color: #ffffff; -} -.color-selection-607d8b { - background-color: #607d8b; - color: #ffffff; -} -.color-selection-111111 { - background-color: #111111; - color: #ffffff; -} -.color-selection-ffffff { - background-color: #ffffff; - color: #000000; -} - /* Tables */ th.pk, td.pk { diff --git a/netbox/project-static/js/forms.js b/netbox/project-static/js/forms.js index 4e50095ef..0c5bc2a2e 100644 --- a/netbox/project-static/js/forms.js +++ b/netbox/project-static/js/forms.js @@ -91,11 +91,8 @@ $(document).ready(function() { // Assign color picker selection classes function colorPickerClassCopy(data, container) { if (data.element) { - // Remove any existing color-selection classes - $(container).attr('class', function(i, c) { - return c.replace(/(^|\s)color-selection-\S+/g, ''); - }); - $(container).addClass($(data.element).attr("class")); + // Swap the style + $(container).attr('style', $(data.element).attr("style")); } return data.text; } diff --git a/netbox/utilities/templates/widgets/colorselect_option.html b/netbox/utilities/templates/widgets/colorselect_option.html index a0e488f18..db40173de 100644 --- a/netbox/utilities/templates/widgets/colorselect_option.html +++ b/netbox/utilities/templates/widgets/colorselect_option.html @@ -1 +1,2 @@ - +{% load helpers %} + From ffc6eec48393f94fb9c2a95ccd6928eeba74b30c Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 24 Sep 2019 15:07:54 -0400 Subject: [PATCH 11/26] Fixes #3519: Prevent cables from being terminated to virtual/wireless interfaces --- CHANGELOG.md | 3 ++- netbox/dcim/models.py | 28 ++++++++++++++-------------- netbox/dcim/tests/test_models.py | 23 ++++++++++++++++------- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85d9124f3..d4c72299a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ v2.6.5 (FUTURE) ## Bug Fixes -* [#3521](https://github.com/netbox-community/netbox/issues/3521) - Fixed error in parseURL related to {{variables}} in API url +* [#3519](https://github.com/netbox-community/netbox/issues/3519) - Prevent cables from being terminated to virtual/wireless interfaces via API +* [#3521](https://github.com/netbox-community/netbox/issues/3521) - Fix error in `parseURL` related to variables in API URL v2.6.4 (2019-09-19) diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 88d2aee1d..302056edc 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -2817,6 +2817,20 @@ class Cable(ChangeLoggedModel): type_a = self.termination_a_type.model type_b = self.termination_b_type.model + # Validate interface types + if type_a == 'interface' and self.termination_a.type in NONCONNECTABLE_IFACE_TYPES: + raise ValidationError({ + 'termination_a_id': 'Cables cannot be terminated to {} interfaces'.format( + self.termination_a.get_type_display() + ) + }) + if type_b == 'interface' and self.termination_b.type in NONCONNECTABLE_IFACE_TYPES: + raise ValidationError({ + 'termination_b_id': 'Cables cannot be terminated to {} interfaces'.format( + self.termination_b.get_type_display() + ) + }) + # Check that termination types are compatible if type_b not in COMPATIBLE_TERMINATION_TYPES.get(type_a): raise ValidationError("Incompatible termination types: {} and {}".format( @@ -2858,20 +2872,6 @@ class Cable(ChangeLoggedModel): self.termination_b, self.termination_b.cable_id )) - # Virtual interfaces cannot be connected - endpoint_a, endpoint_b, _ = self.get_path_endpoints() - if ( - ( - isinstance(endpoint_a, Interface) and - endpoint_a.type == IFACE_TYPE_VIRTUAL - ) or - ( - isinstance(endpoint_b, Interface) and - endpoint_b.type == IFACE_TYPE_VIRTUAL - ) - ): - raise ValidationError("Cannot connect to a virtual interface") - # Validate length and length_unit if self.length is not None and self.length_unit is None: raise ValidationError("Must specify a unit when setting a cable length") diff --git a/netbox/dcim/tests/test_models.py b/netbox/dcim/tests/test_models.py index 2135aba66..2b5bed283 100644 --- a/netbox/dcim/tests/test_models.py +++ b/netbox/dcim/tests/test_models.py @@ -343,7 +343,7 @@ class CableTestCase(TestCase): def test_cable_validates_compatibale_types(self): """ - The clean method should have a check to ensure only compatiable port types can be connected by a cable + The clean method should have a check to ensure only compatible port types can be connected by a cable """ # An interface cannot be connected to a power port cable = Cable(termination_a=self.interface1, termination_b=self.power_port1) @@ -360,30 +360,39 @@ class CableTestCase(TestCase): def test_cable_front_port_cannot_connect_to_corresponding_rear_port(self): """ - A cable cannot connect a front port to its sorresponding rear port + A cable cannot connect a front port to its corresponding rear port """ cable = Cable(termination_a=self.front_port, termination_b=self.rear_port) with self.assertRaises(ValidationError): cable.clean() - def test_cable_cannot_be_connected_to_an_existing_connection(self): + def test_cable_cannot_terminate_to_an_existing_connection(self): """ - Either side of a cable cannot be terminated when that side aready has a connection + Either side of a cable cannot be terminated when that side already has a connection """ # Try to create a cable with the same interface terminations cable = Cable(termination_a=self.interface2, termination_b=self.interface1) with self.assertRaises(ValidationError): cable.clean() - def test_cable_cannot_connect_to_a_virtual_inteface(self): + def test_cable_cannot_terminate_to_a_virtual_inteface(self): """ - A cable connection cannot include a virtual interface + A cable cannot terminate to a virtual interface """ - virtual_interface = Interface(device=self.device1, name="V1", type=0) + virtual_interface = Interface(device=self.device1, name="V1", type=IFACE_TYPE_VIRTUAL) cable = Cable(termination_a=self.interface2, termination_b=virtual_interface) with self.assertRaises(ValidationError): cable.clean() + def test_cable_cannot_terminate_to_a_wireless_inteface(self): + """ + A cable cannot terminate to a wireless interface + """ + wireless_interface = Interface(device=self.device1, name="W1", type=IFACE_TYPE_80211A) + cable = Cable(termination_a=self.interface2, termination_b=wireless_interface) + with self.assertRaises(ValidationError): + cable.clean() + class CablePathTestCase(TestCase): From 51baaab74be49bc133529f1093df2d4d191bf88b Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 24 Sep 2019 15:14:22 -0400 Subject: [PATCH 12/26] Changelog for #3464 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4c72299a..bb3f95e5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ v2.6.5 (FUTURE) ## Bug Fixes +* [#3464](https://github.com/netbox-community/netbox/issues/3464) - Fix foreground text color on color picker fields * [#3519](https://github.com/netbox-community/netbox/issues/3519) - Prevent cables from being terminated to virtual/wireless interfaces via API * [#3521](https://github.com/netbox-community/netbox/issues/3521) - Fix error in `parseURL` related to variables in API URL From fe85dc1186132bfd668f949c8557db8093b94e9d Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 24 Sep 2019 15:27:47 -0400 Subject: [PATCH 13/26] Closes #3524: Enable bulk editing of power outlet/power port associations --- CHANGELOG.md | 4 ++++ netbox/dcim/forms.py | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb3f95e5a..deaf6265c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ v2.6.5 (FUTURE) +## Enhancements + +* [#3524](https://github.com/netbox-community/netbox/issues/3524) - Enable bulk editing of power outlet/power port associations + ## Bug Fixes * [#3464](https://github.com/netbox-community/netbox/issues/3464) - Fix foreground text color on color picker fields diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 939470756..2e0ba2d40 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -2106,6 +2106,10 @@ class PowerOutletBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): choices=add_blank_choice(POWERFEED_LEG_CHOICES), required=False, ) + power_port = forms.ModelChoiceField( + queryset=PowerPort.objects.all(), + required=False + ) description = forms.CharField( max_length=100, required=False @@ -2113,9 +2117,15 @@ class PowerOutletBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): class Meta: nullable_fields = [ - 'feed_leg', 'description', + 'feed_leg', 'power_port', 'description', ] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Limit power_port queryset to PowerPorts which belong to the parent Device + self.fields['power_port'].queryset = PowerPort.objects.filter(device=self.parent_obj) + class PowerOutletBulkRenameForm(BulkRenameForm): pk = forms.ModelMultipleChoiceField( From d0597cd289ac67469c85832104e755732ad5145f Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 24 Sep 2019 14:36:41 -0500 Subject: [PATCH 14/26] Fix ordering for Rack Positioning --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index deaf6265c..3f7d07380 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ v2.6.5 (FUTURE) * [#3464](https://github.com/netbox-community/netbox/issues/3464) - Fix foreground text color on color picker fields * [#3519](https://github.com/netbox-community/netbox/issues/3519) - Prevent cables from being terminated to virtual/wireless interfaces via API * [#3521](https://github.com/netbox-community/netbox/issues/3521) - Fix error in `parseURL` related to variables in API URL +* [#3531](https://github.com/netbox-community/netbox/issues/3531) - Fixed rack role foreground color +* [#3532](https://github.com/netbox-community/netbox/issues/3532) - Added "device" to graph documentation under "type" field +* [#3534](https://github.com/netbox-community/netbox/issues/3534) - Added blank option for untagged vlans v2.6.4 (2019-09-19) From a4690ec5cef2b32b9ad6e459b467cf2b7b8688ab Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Tue, 24 Sep 2019 15:08:57 -0500 Subject: [PATCH 15/26] Fix ordering for rack positioning --- netbox/project-static/js/forms.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox/project-static/js/forms.js b/netbox/project-static/js/forms.js index 0c5bc2a2e..ae3501cae 100644 --- a/netbox/project-static/js/forms.js +++ b/netbox/project-static/js/forms.js @@ -197,7 +197,7 @@ $(document).ready(function() { $(element).children('option').attr('disabled', false); var results = data.results; - results = results.reduce((results,record) => { + results = results.reduce((results,record,idx) => { record.text = record[element.getAttribute('display-field')] || record.name; record.id = record[element.getAttribute('value-field')] || record.id; if(element.getAttribute('disabled-indicator') && record[element.getAttribute('disabled-indicator')]) { @@ -222,7 +222,7 @@ $(document).ready(function() { results['global'].children.push(record); } else { - results[record.id] = record + results[idx] = record } return results; From b8d8cb33ff7ea4e004fa640e7f97173eabb1e302 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 25 Sep 2019 09:21:21 -0400 Subject: [PATCH 16/26] Closes #3529: Enable filtering circuits list by region --- CHANGELOG.md | 4 ++-- netbox/circuits/forms.py | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f7d07380..8a6a4be55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ v2.6.5 (FUTURE) ## Enhancements * [#3524](https://github.com/netbox-community/netbox/issues/3524) - Enable bulk editing of power outlet/power port associations +* [#3529](https://github.com/netbox-community/netbox/issues/3529) - Enable filtering circuits list by region ## Bug Fixes @@ -10,8 +11,7 @@ v2.6.5 (FUTURE) * [#3519](https://github.com/netbox-community/netbox/issues/3519) - Prevent cables from being terminated to virtual/wireless interfaces via API * [#3521](https://github.com/netbox-community/netbox/issues/3521) - Fix error in `parseURL` related to variables in API URL * [#3531](https://github.com/netbox-community/netbox/issues/3531) - Fixed rack role foreground color -* [#3532](https://github.com/netbox-community/netbox/issues/3532) - Added "device" to graph documentation under "type" field -* [#3534](https://github.com/netbox-community/netbox/issues/3534) - Added blank option for untagged vlans +* [#3534](https://github.com/netbox-community/netbox/issues/3534) - Added blank option for untagged VLANs v2.6.4 (2019-09-19) diff --git a/netbox/circuits/forms.py b/netbox/circuits/forms.py index 100c6334f..a64dfc11e 100644 --- a/netbox/circuits/forms.py +++ b/netbox/circuits/forms.py @@ -1,7 +1,7 @@ from django import forms from taggit.forms import TagField -from dcim.models import Site +from dcim.models import Region, Site from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm from tenancy.forms import TenancyForm from tenancy.forms import TenancyFilterForm @@ -268,7 +268,9 @@ class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm): model = Circuit - field_order = ['q', 'type', 'provider', 'status', 'site', 'tenant_group', 'tenant', 'commit_rate'] + field_order = [ + 'q', 'type', 'provider', 'status', 'region', 'site', 'tenant_group', 'tenant', 'commit_rate', + ] q = forms.CharField( required=False, label='Search' @@ -294,6 +296,15 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm required=False, widget=StaticSelect2Multiple() ) + region = forms.ModelMultipleChoiceField( + queryset=Region.objects.all(), + to_field_name='slug', + required=False, + widget=APISelectMultiple( + api_url="/api/dcim/regions/", + value_field="slug", + ) + ) site = FilterChoiceField( queryset=Site.objects.all(), to_field_name='slug', From 86cef1c50215faab72f34985e46cfa8838c20a10 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 25 Sep 2019 09:39:03 -0400 Subject: [PATCH 17/26] Fixes #3435: Change IP/prefix CSV export to reference VRF name instead of RD --- CHANGELOG.md | 1 + netbox/ipam/models.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a6a4be55..1458d60e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ v2.6.5 (FUTURE) ## Bug Fixes +* [#3435](https://github.com/netbox-community/netbox/issues/3435) - Change IP/prefix CSV export to reference VRF name instead of RD * [#3464](https://github.com/netbox-community/netbox/issues/3464) - Fix foreground text color on color picker fields * [#3519](https://github.com/netbox-community/netbox/issues/3519) - Prevent cables from being terminated to virtual/wireless interfaces via API * [#3521](https://github.com/netbox-community/netbox/issues/3521) - Fix error in `parseURL` related to variables in API URL diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index 5e867e1d6..3304c27dd 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -382,7 +382,7 @@ class Prefix(ChangeLoggedModel, CustomFieldModel): def to_csv(self): return ( self.prefix, - self.vrf.rd if self.vrf else None, + self.vrf.name if self.vrf else None, self.tenant.name if self.tenant else None, self.site.name if self.site else None, self.vlan.group.name if self.vlan and self.vlan.group else None, @@ -674,7 +674,7 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel): return ( self.address, - self.vrf.rd if self.vrf else None, + self.vrf.name if self.vrf else None, self.tenant.name if self.tenant else None, self.get_status_display(), self.get_role_display(), From d183a9e7b5f18379038b3215945d476b601d936b Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 25 Sep 2019 10:11:41 -0400 Subject: [PATCH 18/26] Closes #3352: Enable filtering changelog API by changed_object_id --- CHANGELOG.md | 1 + netbox/extras/api/serializers.py | 4 ++-- netbox/extras/filters.py | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1458d60e4..4850bf734 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ v2.6.5 (FUTURE) ## Enhancements +* [#3352](https://github.com/netbox-community/netbox/issues/3352) - Enable filtering changelog API by `changed_object_id` * [#3524](https://github.com/netbox-community/netbox/issues/3524) - Enable bulk editing of power outlet/power port associations * [#3529](https://github.com/netbox-community/netbox/issues/3529) - Enable filtering circuits list by region diff --git a/netbox/extras/api/serializers.py b/netbox/extras/api/serializers.py index abf0d8cf5..8cbddc860 100644 --- a/netbox/extras/api/serializers.py +++ b/netbox/extras/api/serializers.py @@ -235,8 +235,8 @@ class ObjectChangeSerializer(serializers.ModelSerializer): class Meta: model = ObjectChange fields = [ - 'id', 'time', 'user', 'user_name', 'request_id', 'action', 'changed_object_type', 'changed_object', - 'object_data', + 'id', 'time', 'user', 'user_name', 'request_id', 'action', 'changed_object_type', 'changed_object_id', + 'changed_object', 'object_data', ] @swagger_serializer_method(serializer_or_field=serializers.DictField) diff --git a/netbox/extras/filters.py b/netbox/extras/filters.py index b31271230..66a7fe637 100644 --- a/netbox/extras/filters.py +++ b/netbox/extras/filters.py @@ -230,7 +230,9 @@ class ObjectChangeFilter(django_filters.FilterSet): class Meta: model = ObjectChange - fields = ['user', 'user_name', 'request_id', 'action', 'changed_object_type', 'object_repr'] + fields = [ + 'user', 'user_name', 'request_id', 'action', 'changed_object_type', 'changed_object_id', 'object_repr', + ] def search(self, queryset, name, value): if not value.strip(): From eeb343434954ef9f8dc6631db93cfc7bfae70835 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 25 Sep 2019 10:22:02 -0400 Subject: [PATCH 19/26] Closes #3347: Extend upgrade script to automatically remove stale content types --- CHANGELOG.md | 1 + upgrade.sh | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4850bf734..101ba9f6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ v2.6.5 (FUTURE) ## Enhancements +* [#3347](https://github.com/netbox-community/netbox/issues/3347) - Extend upgrade script to automatically remove stale content types * [#3352](https://github.com/netbox-community/netbox/issues/3352) - Enable filtering changelog API by `changed_object_id` * [#3524](https://github.com/netbox-community/netbox/issues/3524) - Enable bulk editing of power outlet/power port associations * [#3529](https://github.com/netbox-community/netbox/issues/3529) - Enable filtering circuits list by region diff --git a/upgrade.sh b/upgrade.sh index 793e72cda..d1157e3ca 100755 --- a/upgrade.sh +++ b/upgrade.sh @@ -25,6 +25,11 @@ COMMAND="${PYTHON} netbox/manage.py migrate" echo "Applying database migrations ($COMMAND)..." eval $COMMAND +# Delete any stale content types +COMMAND="${PYTHON} netbox/manage.py remove_stale_contenttypes --no-input" +echo "Removing stale content types ($COMMAND)..." +eval $COMMAND + # Collect static files COMMAND="${PYTHON} netbox/manage.py collectstatic --no-input" echo "Collecting static files ($COMMAND)..." From 458251683cbfbf7de3047d4219a2e9392cc04a2f Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Wed, 25 Sep 2019 09:28:23 -0500 Subject: [PATCH 20/26] Fixes: #3540 - Changed interface edit to use new inline vlan edit fields --- .../virtualization/interface_edit.html | 30 ++----------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/netbox/templates/virtualization/interface_edit.html b/netbox/templates/virtualization/interface_edit.html index 7977f9fed..437b960c9 100644 --- a/netbox/templates/virtualization/interface_edit.html +++ b/netbox/templates/virtualization/interface_edit.html @@ -11,20 +11,11 @@ {% render_field form.mtu %} {% render_field form.description %} {% render_field form.mode %} + {% render_field form.untagged_vlan %} + {% render_field form.tagged_vlans %} {% render_field form.tags %} - {% if obj.mode %} -
-
802.1Q VLANs
- {% include 'dcim/inc/interface_vlans_table.html' %} - -
- {% endif %} {% endblock %} {% block buttons %} @@ -36,19 +27,4 @@ {% endif %} Cancel -{% endblock %} - -{% block javascript %} - -{% endblock %} +{% endblock %} \ No newline at end of file From a359d888970d2014c0907b11ebe4d8a38df3034a Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Wed, 25 Sep 2019 09:29:54 -0500 Subject: [PATCH 21/26] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 101ba9f6f..2cd8eb5e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ v2.6.5 (FUTURE) * [#3521](https://github.com/netbox-community/netbox/issues/3521) - Fix error in `parseURL` related to variables in API URL * [#3531](https://github.com/netbox-community/netbox/issues/3531) - Fixed rack role foreground color * [#3534](https://github.com/netbox-community/netbox/issues/3534) - Added blank option for untagged VLANs +* [#3540](https://github.com/netbox-community/netbox/issues/3540) - Fixed virtual machine interface edit with new inline vlan edit fields v2.6.4 (2019-09-19) From f54774f6a1d339c573dde5cdde467950335bb60b Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 25 Sep 2019 10:54:08 -0400 Subject: [PATCH 22/26] Closes #3297: Include reserved units when calculating rack utilization --- CHANGELOG.md | 1 + netbox/dcim/models.py | 17 ++++++++++++++--- netbox/templates/dcim/rack.html | 4 ++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cd8eb5e8..bb24017bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ v2.6.5 (FUTURE) ## Enhancements +* [#3297](https://github.com/netbox-community/netbox/issues/3297) - Include reserved units when calculating rack utilization * [#3347](https://github.com/netbox-community/netbox/issues/3347) - Extend upgrade script to automatically remove stale content types * [#3352](https://github.com/netbox-community/netbox/issues/3352) - Enable filtering changelog API by `changed_object_id` * [#3524](https://github.com/netbox-community/netbox/issues/3524) - Enable bulk editing of power outlet/power port associations diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 302056edc..5ffd15842 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -732,10 +732,21 @@ class Rack(ChangeLoggedModel, CustomFieldModel): def get_utilization(self): """ - Determine the utilization rate of the rack and return it as a percentage. + Determine the utilization rate of the rack and return it as a percentage. Occupied and reserved units both count + as utilized. """ - u_available = len(self.get_available_units()) - return int(float(self.u_height - u_available) / self.u_height * 100) + # Determine unoccupied units + available_units = self.get_available_units() + + # Remove reserved units + for u in self.get_reserved_units(): + if u in available_units: + available_units.remove(u) + + occupied_unit_count = self.u_height - len(available_units) + percentage = int(float(occupied_unit_count) / self.u_height * 100) + + return percentage def get_power_utilization(self): """ diff --git a/netbox/templates/dcim/rack.html b/netbox/templates/dcim/rack.html index 60a70c36c..2a347e6e6 100644 --- a/netbox/templates/dcim/rack.html +++ b/netbox/templates/dcim/rack.html @@ -135,6 +135,10 @@ {{ rack.devices.count }} + + Utilization + {% utilization_graph rack.get_utilization %} +
From a84dbbf48235114a5af68da5024dfda0eacd7f27 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Wed, 25 Sep 2019 10:48:33 -0500 Subject: [PATCH 23/26] Fixes: #3543 - Adds inline vlan editing to virtual machine interfaces --- CHANGELOG.md | 1 + netbox/virtualization/forms.py | 164 ++++++++++++++++++++++++++++++++- 2 files changed, 163 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb24017bc..3303a71d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ v2.6.5 (FUTURE) * [#3531](https://github.com/netbox-community/netbox/issues/3531) - Fixed rack role foreground color * [#3534](https://github.com/netbox-community/netbox/issues/3534) - Added blank option for untagged VLANs * [#3540](https://github.com/netbox-community/netbox/issues/3540) - Fixed virtual machine interface edit with new inline vlan edit fields +* [#3543](https://github.com/netbox-community/netbox/issues/3543) - Added inline VLAN editing to virtual machine interfaces v2.6.4 (2019-09-19) diff --git a/netbox/virtualization/forms.py b/netbox/virtualization/forms.py index 55672514e..d3fc4b83b 100644 --- a/netbox/virtualization/forms.py +++ b/netbox/virtualization/forms.py @@ -2,11 +2,11 @@ from django import forms from django.core.exceptions import ValidationError from taggit.forms import TagField -from dcim.constants import IFACE_TYPE_VIRTUAL, IFACE_MODE_ACCESS, IFACE_MODE_TAGGED_ALL +from dcim.constants import IFACE_TYPE_VIRTUAL, IFACE_MODE_ACCESS, IFACE_MODE_TAGGED_ALL, IFACE_MODE_CHOICES from dcim.forms import INTERFACE_MODE_HELP_TEXT from dcim.models import Device, DeviceRole, Interface, Platform, Rack, Region, Site from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFilterForm -from ipam.models import IPAddress +from ipam.models import IPAddress, VLANGroup, VLAN from tenancy.forms import TenancyForm from tenancy.forms import TenancyFilterForm from tenancy.models import Tenant @@ -616,6 +616,24 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFil # class InterfaceForm(BootstrapMixin, forms.ModelForm): + untagged_vlan = forms.ModelChoiceField( + queryset=VLAN.objects.all(), + required=False, + widget=APISelect( + api_url="/api/ipam/vlans/", + display_field='display_name', + full=True + ) + ) + tagged_vlans = forms.ModelMultipleChoiceField( + queryset=VLAN.objects.all(), + required=False, + widget=APISelectMultiple( + api_url="/api/ipam/vlans/", + display_field='display_name', + full=True + ) + ) tags = TagField( required=False ) @@ -638,6 +656,39 @@ class InterfaceForm(BootstrapMixin, forms.ModelForm): 'mode': INTERFACE_MODE_HELP_TEXT, } + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Limit VLan choices to those in: global vlans, global groups, the current site's group, the current site + vlan_choices = [] + global_vlans = VLAN.objects.filter(site=None, group=None) + vlan_choices.append( + ('Global', [(vlan.pk, vlan) for vlan in global_vlans]) + ) + for group in VLANGroup.objects.filter(site=None): + global_group_vlans = VLAN.objects.filter(group=group) + vlan_choices.append( + (group.name, [(vlan.pk, vlan) for vlan in global_group_vlans]) + ) + + site = getattr(self.instance.device, 'site', None) + if site is not None: + + # Add non-grouped site VLANs + site_vlans = VLAN.objects.filter(site=site, group=None) + vlan_choices.append((site.name, [(vlan.pk, vlan) for vlan in site_vlans])) + + # Add grouped site VLANs + for group in VLANGroup.objects.filter(site=site): + site_group_vlans = VLAN.objects.filter(group=group) + vlan_choices.append(( + '{} / {}'.format(group.site.name, group.name), + [(vlan.pk, vlan) for vlan in site_group_vlans] + )) + + self.fields['untagged_vlan'].choices = [(None, '---------')] + vlan_choices + self.fields['tagged_vlans'].choices = vlan_choices + def clean(self): super().clean() @@ -681,6 +732,29 @@ class InterfaceCreateForm(ComponentForm): max_length=100, required=False ) + mode = forms.ChoiceField( + choices=add_blank_choice(IFACE_MODE_CHOICES), + required=False, + widget=StaticSelect2(), + ) + untagged_vlan = forms.ModelChoiceField( + queryset=VLAN.objects.all(), + required=False, + widget=APISelect( + api_url="/api/ipam/vlans/", + display_field='display_name', + full=True + ) + ) + tagged_vlans = forms.ModelMultipleChoiceField( + queryset=VLAN.objects.all(), + required=False, + widget=APISelectMultiple( + api_url="/api/ipam/vlans/", + display_field='display_name', + full=True + ) + ) tags = TagField( required=False ) @@ -693,6 +767,36 @@ class InterfaceCreateForm(ComponentForm): super().__init__(*args, **kwargs) + # Limit VLan choices to those in: global vlans, global groups, the current site's group, the current site + vlan_choices = [] + global_vlans = VLAN.objects.filter(site=None, group=None) + vlan_choices.append( + ('Global', [(vlan.pk, vlan) for vlan in global_vlans]) + ) + for group in VLANGroup.objects.filter(site=None): + global_group_vlans = VLAN.objects.filter(group=group) + vlan_choices.append( + (group.name, [(vlan.pk, vlan) for vlan in global_group_vlans]) + ) + + site = getattr(self.parent.cluster, 'site', None) + if site is not None: + + # Add non-grouped site VLANs + site_vlans = VLAN.objects.filter(site=site, group=None) + vlan_choices.append((site.name, [(vlan.pk, vlan) for vlan in site_vlans])) + + # Add grouped site VLANs + for group in VLANGroup.objects.filter(site=site): + site_group_vlans = VLAN.objects.filter(group=group) + vlan_choices.append(( + '{} / {}'.format(group.site.name, group.name), + [(vlan.pk, vlan) for vlan in site_group_vlans] + )) + + self.fields['untagged_vlan'].choices = [(None, '---------')] + vlan_choices + self.fields['tagged_vlans'].choices = vlan_choices + class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm): pk = forms.ModelMultipleChoiceField( @@ -713,12 +817,68 @@ class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm): max_length=100, required=False ) + mode = forms.ChoiceField( + choices=add_blank_choice(IFACE_MODE_CHOICES), + required=False, + widget=StaticSelect2() + ) + untagged_vlan = forms.ModelChoiceField( + queryset=VLAN.objects.all(), + required=False, + widget=APISelect( + api_url="/api/ipam/vlans/", + display_field='display_name', + full=True + ) + ) + tagged_vlans = forms.ModelMultipleChoiceField( + queryset=VLAN.objects.all(), + required=False, + widget=APISelectMultiple( + api_url="/api/ipam/vlans/", + display_field='display_name', + full=True + ) + ) class Meta: nullable_fields = [ 'mtu', 'description', ] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Limit VLan choices to those in: global vlans, global groups, the current site's group, the current site + vlan_choices = [] + global_vlans = VLAN.objects.filter(site=None, group=None) + vlan_choices.append( + ('Global', [(vlan.pk, vlan) for vlan in global_vlans]) + ) + for group in VLANGroup.objects.filter(site=None): + global_group_vlans = VLAN.objects.filter(group=group) + vlan_choices.append( + (group.name, [(vlan.pk, vlan) for vlan in global_group_vlans]) + ) + if self.parent_obj.cluster is not None: + site = getattr(self.parent_obj.cluster, 'site', None) + if site is not None: + + # Add non-grouped site VLANs + site_vlans = VLAN.objects.filter(site=site, group=None) + vlan_choices.append((site.name, [(vlan.pk, vlan) for vlan in site_vlans])) + + # Add grouped site VLANs + for group in VLANGroup.objects.filter(site=site): + site_group_vlans = VLAN.objects.filter(group=group) + vlan_choices.append(( + '{} / {}'.format(group.site.name, group.name), + [(vlan.pk, vlan) for vlan in site_group_vlans] + )) + + self.fields['untagged_vlan'].choices = [(None, '---------')] + vlan_choices + self.fields['tagged_vlans'].choices = vlan_choices + # # Bulk VirtualMachine component creation From b7b04045de2f17bd2078677e7e491df43a82b9a3 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 25 Sep 2019 12:07:41 -0400 Subject: [PATCH 24/26] Closes #3515: Enable export templates for inventory items --- CHANGELOG.md | 1 + netbox/extras/constants.py | 1 + netbox/extras/models.py | 11 ++++++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3303a71d4..a51653e4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ v2.6.5 (FUTURE) * [#3297](https://github.com/netbox-community/netbox/issues/3297) - Include reserved units when calculating rack utilization * [#3347](https://github.com/netbox-community/netbox/issues/3347) - Extend upgrade script to automatically remove stale content types * [#3352](https://github.com/netbox-community/netbox/issues/3352) - Enable filtering changelog API by `changed_object_id` +* [#3515](https://github.com/netbox-community/netbox/issues/3515) - Enable export templates for inventory items * [#3524](https://github.com/netbox-community/netbox/issues/3524) - Enable bulk editing of power outlet/power port associations * [#3529](https://github.com/netbox-community/netbox/issues/3529) - Enable filtering circuits list by region diff --git a/netbox/extras/constants.py b/netbox/extras/constants.py index d136d3271..2545b34d5 100644 --- a/netbox/extras/constants.py +++ b/netbox/extras/constants.py @@ -107,6 +107,7 @@ EXPORTTEMPLATE_MODELS = [ 'dcim.device', 'dcim.devicetype', 'dcim.interface', + 'dcim.inventoryitem', 'dcim.manufacturer', 'dcim.powerpanel', 'dcim.powerport', diff --git a/netbox/extras/models.py b/netbox/extras/models.py index d764e3d31..04caf3376 100644 --- a/netbox/extras/models.py +++ b/netbox/extras/models.py @@ -435,14 +435,19 @@ class ExportTemplate(models.Model): choices=TEMPLATE_LANGUAGE_CHOICES, default=TEMPLATE_LANGUAGE_JINJA2 ) - template_code = models.TextField() + template_code = models.TextField( + help_text='The list of objects being exported is passed as a context variable named queryset.' + ) mime_type = models.CharField( max_length=50, - blank=True + blank=True, + verbose_name='MIME type', + help_text='Defaults to text/plain' ) file_extension = models.CharField( max_length=15, - blank=True + blank=True, + help_text='Extension to append to the rendered filename' ) class Meta: From 3e4cd59fc0c2501ee7caffc0b7feae2e9bb537f0 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 25 Sep 2019 13:24:28 -0400 Subject: [PATCH 25/26] Releae v2.6.5 --- CHANGELOG.md | 2 +- netbox/netbox/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a51653e4b..34d4b7f5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -v2.6.5 (FUTURE) +v2.6.5 (2019-09-25) ## Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 2fbdc6ac7..39380cf7c 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -12,7 +12,7 @@ from django.core.exceptions import ImproperlyConfigured # Environment setup # -VERSION = '2.6.5-dev' +VERSION = '2.6.5' # Hostname HOSTNAME = platform.node() From ef1fa559021f9667babf011e6be16b1c8539fff3 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 25 Sep 2019 13:29:22 -0400 Subject: [PATCH 26/26] Post-release version bump --- 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 39380cf7c..0175d89f2 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -12,7 +12,7 @@ from django.core.exceptions import ImproperlyConfigured # Environment setup # -VERSION = '2.6.5' +VERSION = '2.6.6-dev' # Hostname HOSTNAME = platform.node()