From da50cd0f03ff388b58fb86a33f72dd16b1eb0b9c Mon Sep 17 00:00:00 2001 From: bellwood Date: Tue, 12 Jul 2016 14:42:47 -0400 Subject: [PATCH 01/25] allow filtering by rack group adds the ability to filter devices by rack group --- netbox/dcim/forms.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 89292717b..6f03c09ae 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -502,6 +502,11 @@ def device_site_choices(): return [(s.slug, '{} ({})'.format(s.name, s.device_count)) for s in site_choices] +def rack_group_choices(): + group_choices = RackGroup.objects.select_related('site').annotate(rack_count=Count('racks')) + return [(g.pk, '{} ({})'.format(g, g.rack_count)) for g in group_choices] + + def device_role_choices(): role_choices = DeviceRole.objects.annotate(device_count=Count('devices')) return [(r.slug, '{} ({})'.format(r.name, r.device_count)) for r in role_choices] @@ -520,6 +525,8 @@ def device_platform_choices(): class DeviceFilterForm(forms.Form, BootstrapMixin): site = forms.MultipleChoiceField(required=False, choices=device_site_choices, widget=forms.SelectMultiple(attrs={'size': 8})) + group_id = forms.MultipleChoiceField(required=False, choices=rack_group_choices, + widget=forms.SelectMultiple(attrs={'size': 8})) role = forms.MultipleChoiceField(required=False, choices=device_role_choices, widget=forms.SelectMultiple(attrs={'size': 8})) device_type_id = forms.MultipleChoiceField(required=False, choices=device_type_choices, label='Type', From 6a6cf14a38f37ae0e7911c1cda9ae61168307187 Mon Sep 17 00:00:00 2001 From: bellwood Date: Tue, 12 Jul 2016 15:12:36 -0400 Subject: [PATCH 02/25] Update forms.py added label --- netbox/dcim/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 6f03c09ae..b18372e78 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -525,7 +525,7 @@ def device_platform_choices(): class DeviceFilterForm(forms.Form, BootstrapMixin): site = forms.MultipleChoiceField(required=False, choices=device_site_choices, widget=forms.SelectMultiple(attrs={'size': 8})) - group_id = forms.MultipleChoiceField(required=False, choices=rack_group_choices, + group_id = forms.MultipleChoiceField(required=False, choices=rack_group_choices, label='Rack Group', widget=forms.SelectMultiple(attrs={'size': 8})) role = forms.MultipleChoiceField(required=False, choices=device_role_choices, widget=forms.SelectMultiple(attrs={'size': 8})) From 69affb7a6e1b97d17a2852ab5aa766590f57ef84 Mon Sep 17 00:00:00 2001 From: bellwood Date: Tue, 12 Jul 2016 15:16:32 -0400 Subject: [PATCH 03/25] fixed "rack group" filter label for/dcim/racks/ --- netbox/dcim/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index b18372e78..9e91fc113 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -186,7 +186,7 @@ def rack_group_choices(): class RackFilterForm(forms.Form, BootstrapMixin): site = forms.MultipleChoiceField(required=False, choices=rack_site_choices, widget=forms.SelectMultiple(attrs={'size': 8})) - group_id = forms.MultipleChoiceField(required=False, choices=rack_group_choices, + group_id = forms.MultipleChoiceField(required=False, choices=rack_group_choices, label='Rack Group', widget=forms.SelectMultiple(attrs={'size': 8})) From 35a2671525c5597766c5c1d0fa7f036a63454154 Mon Sep 17 00:00:00 2001 From: Johann Schmitz Date: Wed, 13 Jul 2016 15:39:59 +0200 Subject: [PATCH 04/25] Use overflow-y: scoll on html element to avoid jumping around when the previous/next page adds a vertical scrollbar. --- netbox/project-static/css/base.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/netbox/project-static/css/base.css b/netbox/project-static/css/base.css index b1a9e88c3..9f4bb5e24 100644 --- a/netbox/project-static/css/base.css +++ b/netbox/project-static/css/base.css @@ -2,6 +2,9 @@ * { margin: 0; } +html { + overflow-y: scroll; +} html, body { height: 100%; } From 9098001bcb67d56ae5d5ac0b8bfd9c04c40d56e9 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 13 Jul 2016 12:11:10 -0400 Subject: [PATCH 05/25] 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 13bc4bda5..3c479219d 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -12,7 +12,7 @@ except ImportError: "the documentation.") -VERSION = '1.2.1' +VERSION = '1.2.2-dev' # Import local configuration for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']: From 9421ec040c62f79ddb63579ce01326c7e5c8308e Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 13 Jul 2016 13:07:02 -0400 Subject: [PATCH 06/25] Fixes #271: Add rack group filter for devices --- netbox/dcim/filters.py | 5 +++++ netbox/dcim/forms.py | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 9712899a8..8872e5747 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -122,6 +122,11 @@ class DeviceFilter(django_filters.FilterSet): to_field_name='slug', label='Site name (slug)', ) + rack_group_id = django_filters.ModelMultipleChoiceFilter( + name='rack__group', + queryset=RackGroup.objects.all(), + label='Rack group (ID)', + ) rack_id = django_filters.ModelMultipleChoiceFilter( name='rack', queryset=Rack.objects.all(), diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 9e91fc113..e3db78ec4 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -502,9 +502,9 @@ def device_site_choices(): return [(s.slug, '{} ({})'.format(s.name, s.device_count)) for s in site_choices] -def rack_group_choices(): - group_choices = RackGroup.objects.select_related('site').annotate(rack_count=Count('racks')) - return [(g.pk, '{} ({})'.format(g, g.rack_count)) for g in group_choices] +def device_rack_group_choices(): + group_choices = RackGroup.objects.select_related('site').annotate(device_count=Count('racks__devices')) + return [(g.pk, '{} ({})'.format(g, g.device_count)) for g in group_choices] def device_role_choices(): @@ -525,8 +525,8 @@ def device_platform_choices(): class DeviceFilterForm(forms.Form, BootstrapMixin): site = forms.MultipleChoiceField(required=False, choices=device_site_choices, widget=forms.SelectMultiple(attrs={'size': 8})) - group_id = forms.MultipleChoiceField(required=False, choices=rack_group_choices, label='Rack Group', - widget=forms.SelectMultiple(attrs={'size': 8})) + rack_group_id = forms.MultipleChoiceField(required=False, choices=device_rack_group_choices, label='Rack Group', + widget=forms.SelectMultiple(attrs={'size': 8})) role = forms.MultipleChoiceField(required=False, choices=device_role_choices, widget=forms.SelectMultiple(attrs={'size': 8})) device_type_id = forms.MultipleChoiceField(required=False, choices=device_type_choices, label='Type', From bafbc052e2aed145697001d7954c5afa9b870c26 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 13 Jul 2016 13:07:02 -0400 Subject: [PATCH 07/25] Fixes #270: Add rack group filter for devices --- netbox/dcim/filters.py | 5 +++++ netbox/dcim/forms.py | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 9712899a8..8872e5747 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -122,6 +122,11 @@ class DeviceFilter(django_filters.FilterSet): to_field_name='slug', label='Site name (slug)', ) + rack_group_id = django_filters.ModelMultipleChoiceFilter( + name='rack__group', + queryset=RackGroup.objects.all(), + label='Rack group (ID)', + ) rack_id = django_filters.ModelMultipleChoiceFilter( name='rack', queryset=Rack.objects.all(), diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 9e91fc113..e3db78ec4 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -502,9 +502,9 @@ def device_site_choices(): return [(s.slug, '{} ({})'.format(s.name, s.device_count)) for s in site_choices] -def rack_group_choices(): - group_choices = RackGroup.objects.select_related('site').annotate(rack_count=Count('racks')) - return [(g.pk, '{} ({})'.format(g, g.rack_count)) for g in group_choices] +def device_rack_group_choices(): + group_choices = RackGroup.objects.select_related('site').annotate(device_count=Count('racks__devices')) + return [(g.pk, '{} ({})'.format(g, g.device_count)) for g in group_choices] def device_role_choices(): @@ -525,8 +525,8 @@ def device_platform_choices(): class DeviceFilterForm(forms.Form, BootstrapMixin): site = forms.MultipleChoiceField(required=False, choices=device_site_choices, widget=forms.SelectMultiple(attrs={'size': 8})) - group_id = forms.MultipleChoiceField(required=False, choices=rack_group_choices, label='Rack Group', - widget=forms.SelectMultiple(attrs={'size': 8})) + rack_group_id = forms.MultipleChoiceField(required=False, choices=device_rack_group_choices, label='Rack Group', + widget=forms.SelectMultiple(attrs={'size': 8})) role = forms.MultipleChoiceField(required=False, choices=device_role_choices, widget=forms.SelectMultiple(attrs={'size': 8})) device_type_id = forms.MultipleChoiceField(required=False, choices=device_type_choices, label='Type', From d3a5b82d9325af3915c57d9a411075242e4e5f64 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 13 Jul 2016 13:50:50 -0400 Subject: [PATCH 08/25] Fixes #282: De-select "all" checkbox if one or more objects are deselected --- netbox/project-static/js/forms.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/netbox/project-static/js/forms.js b/netbox/project-static/js/forms.js index 4ba61f13a..fd510af3f 100644 --- a/netbox/project-static/js/forms.js +++ b/netbox/project-static/js/forms.js @@ -1,9 +1,15 @@ $(document).ready(function() { // "Select all" checkbox in a table header - $('th input:checkbox').click(function (event) { + $('th input:checkbox[name=_all]').click(function (event) { $(this).parents('table').find('td input:checkbox').prop('checked', $(this).prop('checked')); }); + // Uncheck the "select all" checkbox if an item is unchecked + $('input:checkbox[name=pk]').click(function (event) { + if (!$(this).attr('checked')) { + $(this).parents('table').find('input:checkbox[name=_all]').prop('checked', false); + } + }); // Slugify function slugify(s, num_chars) { From 024c7da15b016838075536e97a190ddea02ed555 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 13 Jul 2016 14:05:21 -0400 Subject: [PATCH 09/25] Fixes #115: Fix deprecated django.core.context_processors reference --- 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 3c479219d..507a133df 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -138,7 +138,7 @@ TEMPLATES = [ 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'utilities.context_processors.settings', - 'django.core.context_processors.request', + 'django.template.context_processors.request', ], }, }, From 404d934736b455dab20ddd0c740f83a79bc6165d Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 13 Jul 2016 14:08:46 -0400 Subject: [PATCH 10/25] Removed redundant template context processor --- netbox/netbox/settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 507a133df..7e1697a82 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -138,7 +138,6 @@ TEMPLATES = [ 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'utilities.context_processors.settings', - 'django.template.context_processors.request', ], }, }, From 9e181c20c73c61484b9731941a5a5f1aeb6c2df8 Mon Sep 17 00:00:00 2001 From: bellwood Date: Wed, 13 Jul 2016 15:26:24 -0400 Subject: [PATCH 11/25] Add 'filter' glyphicon to filter panel header --- netbox/templates/inc/filter_panel.html | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/templates/inc/filter_panel.html b/netbox/templates/inc/filter_panel.html index 1a7b70704..32a7e21f8 100644 --- a/netbox/templates/inc/filter_panel.html +++ b/netbox/templates/inc/filter_panel.html @@ -2,6 +2,7 @@
+ Filter
From 4913d25d186c996f9850f83e5cad8796db7e73a1 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 13 Jul 2016 15:30:15 -0400 Subject: [PATCH 12/25] Fixes #268: Added support for full 32-bit ASN space --- .../0003_provider_32bit_asn_support.py | 21 +++++++++++++++++++ netbox/circuits/models.py | 3 ++- netbox/dcim/fields.py | 9 ++++++++ .../migrations/0009_site_32bit_asn_support.py | 21 +++++++++++++++++++ netbox/dcim/models.py | 4 ++-- 5 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 netbox/circuits/migrations/0003_provider_32bit_asn_support.py create mode 100644 netbox/dcim/migrations/0009_site_32bit_asn_support.py diff --git a/netbox/circuits/migrations/0003_provider_32bit_asn_support.py b/netbox/circuits/migrations/0003_provider_32bit_asn_support.py new file mode 100644 index 000000000..f1010064e --- /dev/null +++ b/netbox/circuits/migrations/0003_provider_32bit_asn_support.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-07-13 19:24 +from __future__ import unicode_literals + +import dcim.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('circuits', '0002_auto_20160622_1821'), + ] + + operations = [ + migrations.AlterField( + model_name='provider', + name='asn', + field=dcim.fields.ASNField(blank=True, null=True, verbose_name=b'ASN'), + ), + ] diff --git a/netbox/circuits/models.py b/netbox/circuits/models.py index d785eb1f2..c7c60378e 100644 --- a/netbox/circuits/models.py +++ b/netbox/circuits/models.py @@ -1,6 +1,7 @@ from django.core.urlresolvers import reverse from django.db import models +from dcim.fields import ASNField from dcim.models import Site, Interface from utilities.models import CreatedUpdatedModel @@ -12,7 +13,7 @@ class Provider(CreatedUpdatedModel): """ name = models.CharField(max_length=50, unique=True) slug = models.SlugField(unique=True) - asn = models.PositiveIntegerField(blank=True, null=True, verbose_name='ASN') + asn = ASNField(blank=True, null=True, verbose_name='ASN') account = models.CharField(max_length=30, blank=True, verbose_name='Account number') portal_url = models.URLField(blank=True, verbose_name='Portal') noc_contact = models.TextField(blank=True, verbose_name='NOC contact') diff --git a/netbox/dcim/fields.py b/netbox/dcim/fields.py index e00b1115f..6b45f6e65 100644 --- a/netbox/dcim/fields.py +++ b/netbox/dcim/fields.py @@ -1,11 +1,20 @@ from netaddr import EUI, mac_unix_expanded from django.core.exceptions import ValidationError +from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models from .formfields import MACAddressFormField +class ASNField(models.BigIntegerField): + description = "32-bit ASN field" + default_validators = [ + MinValueValidator(1), + MaxValueValidator(4294967295), + ] + + class mac_unix_expanded_uppercase(mac_unix_expanded): word_fmt = '%.2X' diff --git a/netbox/dcim/migrations/0009_site_32bit_asn_support.py b/netbox/dcim/migrations/0009_site_32bit_asn_support.py new file mode 100644 index 000000000..c93340cea --- /dev/null +++ b/netbox/dcim/migrations/0009_site_32bit_asn_support.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-07-13 19:24 +from __future__ import unicode_literals + +import dcim.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0008_device_remove_primary_ip'), + ] + + operations = [ + migrations.AlterField( + model_name='site', + name='asn', + field=dcim.fields.ASNField(blank=True, null=True, verbose_name=b'ASN'), + ), + ] diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index c51714a71..8bf97224c 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -11,7 +11,7 @@ from extras.rpc import RPC_CLIENTS from utilities.fields import NullableCharField from utilities.models import CreatedUpdatedModel -from .fields import MACAddressField +from .fields import ASNField, MACAddressField RACK_FACE_FRONT = 0 RACK_FACE_REAR = 1 @@ -145,7 +145,7 @@ class Site(CreatedUpdatedModel): name = models.CharField(max_length=50, unique=True) slug = models.SlugField(unique=True) facility = models.CharField(max_length=50, blank=True) - asn = models.PositiveIntegerField(blank=True, null=True, verbose_name='ASN') + asn = ASNField(blank=True, null=True, verbose_name='ASN') physical_address = models.CharField(max_length=200, blank=True) shipping_address = models.CharField(max_length=200, blank=True) comments = models.TextField(blank=True) From aed2180142109512cb89d27bfd6d79c7990b5b95 Mon Sep 17 00:00:00 2001 From: bellwood Date: Wed, 13 Jul 2016 15:32:39 -0400 Subject: [PATCH 13/25] Add 'search' glyphicon to filter panel header --- netbox/templates/dcim/device_list.html | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/templates/dcim/device_list.html b/netbox/templates/dcim/device_list.html index bae95b0ec..ee127cf48 100644 --- a/netbox/templates/dcim/device_list.html +++ b/netbox/templates/dcim/device_list.html @@ -25,6 +25,7 @@
+ Search
From f20e0edb3550a8404f19b37c9b1ad4cec3117ef3 Mon Sep 17 00:00:00 2001 From: bellwood Date: Wed, 13 Jul 2016 15:33:52 -0400 Subject: [PATCH 14/25] Add 'search' glyphicon to filter panel header --- netbox/templates/dcim/rack_list.html | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/templates/dcim/rack_list.html b/netbox/templates/dcim/rack_list.html index ec23d2736..811edb823 100644 --- a/netbox/templates/dcim/rack_list.html +++ b/netbox/templates/dcim/rack_list.html @@ -25,6 +25,7 @@
+ Search
From 4483ba55dd5631c10ed5c4bf31ff38ff628d9e70 Mon Sep 17 00:00:00 2001 From: bellwood Date: Wed, 13 Jul 2016 15:34:23 -0400 Subject: [PATCH 15/25] Add 'search' glyphicon to filter panel header --- netbox/templates/dcim/site_list.html | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/templates/dcim/site_list.html b/netbox/templates/dcim/site_list.html index f3334ec6f..d35410443 100644 --- a/netbox/templates/dcim/site_list.html +++ b/netbox/templates/dcim/site_list.html @@ -21,6 +21,7 @@
+ Search
From 9c32943d73041864ea17ad10d4c3d4b8963992a5 Mon Sep 17 00:00:00 2001 From: bellwood Date: Wed, 13 Jul 2016 15:35:41 -0400 Subject: [PATCH 16/25] Add 'search' glyphicon to filter panel header --- netbox/templates/ipam/ipaddress_list.html | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/templates/ipam/ipaddress_list.html b/netbox/templates/ipam/ipaddress_list.html index edcc140c3..ce09fc97c 100644 --- a/netbox/templates/ipam/ipaddress_list.html +++ b/netbox/templates/ipam/ipaddress_list.html @@ -26,6 +26,7 @@
+ Search
From 51cc0d50839dd08bd22342d63af61913c6f0811c Mon Sep 17 00:00:00 2001 From: bellwood Date: Wed, 13 Jul 2016 15:36:07 -0400 Subject: [PATCH 17/25] Add 'search' glyphicon to filter panel header --- netbox/templates/ipam/vlan_list.html | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/templates/ipam/vlan_list.html b/netbox/templates/ipam/vlan_list.html index f9ed6d816..78ff2b47c 100644 --- a/netbox/templates/ipam/vlan_list.html +++ b/netbox/templates/ipam/vlan_list.html @@ -26,6 +26,7 @@
+ Search by ID
From 2691590aa1f9bbba3cc5f6828ab6496f80b43894 Mon Sep 17 00:00:00 2001 From: bellwood Date: Wed, 13 Jul 2016 15:36:26 -0400 Subject: [PATCH 18/25] Add 'search' glyphicon to filter panel header --- netbox/templates/ipam/prefix_list.html | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/templates/ipam/prefix_list.html b/netbox/templates/ipam/prefix_list.html index 0b871f22a..81fd7b795 100644 --- a/netbox/templates/ipam/prefix_list.html +++ b/netbox/templates/ipam/prefix_list.html @@ -26,6 +26,7 @@
+ Search
From a5f6e64849f281048638a5d03b38609245667698 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 14 Jul 2016 11:30:15 -0400 Subject: [PATCH 19/25] Fixes #290: Added mgmt interfaces table to device type view --- netbox/dcim/views.py | 7 ++++++- netbox/templates/dcim/devicetype.html | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 92c8c029c..bd34c264f 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -273,7 +273,10 @@ def devicetype(request, pk): poweroutlet_table = tables.PowerOutletTemplateTable( natsorted(PowerOutletTemplate.objects.filter(device_type=devicetype), key=attrgetter('name')) ) - interface_table = tables.InterfaceTemplateTable(InterfaceTemplate.objects.filter(device_type=devicetype)) + mgmt_interface_table = tables.InterfaceTemplateTable(InterfaceTemplate.objects.filter(device_type=devicetype, + mgmt_only=True)) + interface_table = tables.InterfaceTemplateTable(InterfaceTemplate.objects.filter(device_type=devicetype, + mgmt_only=False)) devicebay_table = tables.DeviceBayTemplateTable( natsorted(DeviceBayTemplate.objects.filter(device_type=devicetype), key=attrgetter('name')) ) @@ -282,6 +285,7 @@ def devicetype(request, pk): consoleserverport_table.base_columns['pk'].visible = True powerport_table.base_columns['pk'].visible = True poweroutlet_table.base_columns['pk'].visible = True + mgmt_interface_table.base_columns['pk'].visible = True interface_table.base_columns['pk'].visible = True devicebay_table.base_columns['pk'].visible = True @@ -291,6 +295,7 @@ def devicetype(request, pk): 'consoleserverport_table': consoleserverport_table, 'powerport_table': powerport_table, 'poweroutlet_table': poweroutlet_table, + 'mgmt_interface_table': mgmt_interface_table, 'interface_table': interface_table, 'devicebay_table': devicebay_table, }) diff --git a/netbox/templates/dcim/devicetype.html b/netbox/templates/dcim/devicetype.html index f3ae5aa78..eecde771b 100644 --- a/netbox/templates/dcim/devicetype.html +++ b/netbox/templates/dcim/devicetype.html @@ -79,6 +79,7 @@
{% include 'dcim/inc/devicetype_component_table.html' with table=consoleport_table title='Console Ports' add_url='dcim:devicetype_add_consoleport' delete_url='dcim:devicetype_delete_consoleport' %} {% include 'dcim/inc/devicetype_component_table.html' with table=powerport_table title='Power Ports' add_url='dcim:devicetype_add_powerport' delete_url='dcim:devicetype_delete_powerport' %} + {% include 'dcim/inc/devicetype_component_table.html' with table=mgmt_interface_table title='Management Interfaces' add_url='dcim:devicetype_add_interface' delete_url='dcim:devicetype_delete_interface' %}
{% if devicetype.is_parent_device %} From 46b1ac23afd9d5edea692cc3bad072d748c232e7 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 14 Jul 2016 11:39:53 -0400 Subject: [PATCH 20/25] Allow for setting mgmt_only=True in "Add management interfaces" link --- netbox/dcim/views.py | 2 +- netbox/templates/dcim/devicetype.html | 6 +++++- netbox/templates/dcim/inc/devicetype_component_table.html | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index bd34c264f..c97e2a3e1 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -353,7 +353,7 @@ class ComponentTemplateCreateView(View): return render(request, 'dcim/component_template_add.html', { 'devicetype': devicetype, 'component_type': self.model._meta.verbose_name, - 'form': self.form(), + 'form': self.form(initial=request.GET), 'cancel_url': reverse('dcim:devicetype', kwargs={'pk': devicetype.pk}), }) diff --git a/netbox/templates/dcim/devicetype.html b/netbox/templates/dcim/devicetype.html index eecde771b..7f7b0d1f9 100644 --- a/netbox/templates/dcim/devicetype.html +++ b/netbox/templates/dcim/devicetype.html @@ -75,11 +75,15 @@ Is a Network Device {{ devicetype.is_network_device|yesno|capfirst }} + + Parent/Child Role + {{ devicetype.get_subdevice_role_display }} +
{% include 'dcim/inc/devicetype_component_table.html' with table=consoleport_table title='Console Ports' add_url='dcim:devicetype_add_consoleport' delete_url='dcim:devicetype_delete_consoleport' %} {% include 'dcim/inc/devicetype_component_table.html' with table=powerport_table title='Power Ports' add_url='dcim:devicetype_add_powerport' delete_url='dcim:devicetype_delete_powerport' %} - {% include 'dcim/inc/devicetype_component_table.html' with table=mgmt_interface_table title='Management Interfaces' add_url='dcim:devicetype_add_interface' delete_url='dcim:devicetype_delete_interface' %} + {% include 'dcim/inc/devicetype_component_table.html' with table=mgmt_interface_table title='Management Interfaces' add_url='dcim:devicetype_add_interface' add_url_extra='?mgmt_only=1' delete_url='dcim:devicetype_delete_interface' %}
{% if devicetype.is_parent_device %} diff --git a/netbox/templates/dcim/inc/devicetype_component_table.html b/netbox/templates/dcim/inc/devicetype_component_table.html index 55bed30e9..948c2c44c 100644 --- a/netbox/templates/dcim/inc/devicetype_component_table.html +++ b/netbox/templates/dcim/inc/devicetype_component_table.html @@ -4,7 +4,10 @@ {% csrf_token %}
{% render_table table 'table.html' %} From 4ce40891f054b08a09e46c8b7d45eae4d130bedf Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 14 Jul 2016 12:39:55 -0400 Subject: [PATCH 21/25] Prettified device type view --- netbox/templates/dcim/devicetype.html | 70 +++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/netbox/templates/dcim/devicetype.html b/netbox/templates/dcim/devicetype.html index 7f7b0d1f9..df567a102 100644 --- a/netbox/templates/dcim/devicetype.html +++ b/netbox/templates/dcim/devicetype.html @@ -42,7 +42,7 @@ - + @@ -54,7 +54,13 @@ - +
Manufacturer{{ devicetype.manufacturer }}{{ devicetype.manufacturer }}
Model Name
Full Depth{{ devicetype.is_full_depth|yesno|capfirst }} + {% if devicetype.is_full_depth %} + + {% else %} + + {% endif %} +
@@ -64,20 +70,64 @@
- - + + - - + + - - + + - - + +
Is a Console Server{{ devicetype.is_console_server|yesno|capfirst }} + {% if devicetype.is_console_server %} + + {% else %} + + {% endif %} + + Console Server
+ This device {% if devicetype.is_console_server %}has{% else %}does not have{% endif %} console server ports +
Is a PDU{{ devicetype.is_pdu|yesno|capfirst }} + {% if devicetype.is_pdu %} + + {% else %} + + {% endif %} + + PDU
+ This device {% if devicetype.is_pdu %}has{% else %}does not have{% endif %} power outlets +
Is a Network Device{{ devicetype.is_network_device|yesno|capfirst }} + {% if devicetype.is_network_device %} + + {% else %} + + {% endif %} + + Network Device
+ This device {% if devicetype.is_network_device %}has{% else %}does not have{% endif %} non-management network interfaces +
Parent/Child Role{{ devicetype.get_subdevice_role_display }} + {% if devicetype.subdevice_role == True %} + + {% elif devicetype.subdevice_role == False %} + + {% else %} + + {% endif %} + + Parent/Child
+ {% if devicetype.subdevice_role == True %} + This device has device bays for mounting child devices + {% elif devicetype.subdevice_role == False %} + This device can only be mounted in a parent device + {% else %} + This device does not have device bays + {% endif %} +
From 9e4aa9c05692041134153c6af613adbcf44e3493 Mon Sep 17 00:00:00 2001 From: brandon whitehead Date: Thu, 14 Jul 2016 12:33:21 -0500 Subject: [PATCH 22/25] Updated SECRET_KEY instructions for HA installs. Issue 295 --- docs/installation/netbox.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/installation/netbox.md b/docs/installation/netbox.md index fde5ab019..c5173e61e 100644 --- a/docs/installation/netbox.md +++ b/docs/installation/netbox.md @@ -110,6 +110,8 @@ DATABASE = { Generate a random secret key of at least 50 alphanumeric characters. This key must be unique to this installation and must not be shared outside the local system. +In the case of a highly available installation with multiple web servers, SECRET_KEY must be identical between all server in order to maintain a persistent user session state between servers. + You may use the script located at `netbox/generate_secret_key.py` to generate a suitable key. # Run Database Migrations From e5a6a4f05ee289fbda5788970042ead94d0b2258 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 14 Jul 2016 13:53:30 -0400 Subject: [PATCH 23/25] Fixes #174: Added search and site filter to provider list --- netbox/circuits/filters.py | 31 ++++++++++++++++++++ netbox/circuits/forms.py | 10 +++++++ netbox/circuits/views.py | 2 ++ netbox/templates/circuits/provider_list.html | 22 +++++++++++++- 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/netbox/circuits/filters.py b/netbox/circuits/filters.py index 49d5e1b80..fc6628e87 100644 --- a/netbox/circuits/filters.py +++ b/netbox/circuits/filters.py @@ -1,9 +1,40 @@ import django_filters +from django.db.models import Q + from dcim.models import Site from .models import Provider, Circuit, CircuitType +class ProviderFilter(django_filters.FilterSet): + q = django_filters.MethodFilter( + action='search', + label='Search', + ) + site_id = django_filters.ModelMultipleChoiceFilter( + name='circuits__site', + queryset=Site.objects.all(), + label='Site', + ) + site = django_filters.ModelMultipleChoiceFilter( + name='circuits__site', + queryset=Site.objects.all(), + to_field_name='slug', + label='Site (slug)', + ) + + class Meta: + model = Provider + fields = ['q', 'name', 'account', 'asn'] + + def search(self, queryset, value): + value = value.strip() + return queryset.filter( + Q(name__icontains=value) | + Q(account__icontains=value) + ) + + class CircuitFilter(django_filters.FilterSet): q = django_filters.MethodFilter( action='search', diff --git a/netbox/circuits/forms.py b/netbox/circuits/forms.py index 7046b8ec3..847402c7d 100644 --- a/netbox/circuits/forms.py +++ b/netbox/circuits/forms.py @@ -59,6 +59,16 @@ class ProviderBulkDeleteForm(ConfirmationForm): pk = forms.ModelMultipleChoiceField(queryset=Provider.objects.all(), widget=forms.MultipleHiddenInput) +def provider_site_choices(): + site_choices = Site.objects.all() + return [(s.slug, s.name) for s in site_choices] + + +class ProviderFilterForm(forms.Form, BootstrapMixin): + site = forms.MultipleChoiceField(required=False, choices=provider_site_choices, + widget=forms.SelectMultiple(attrs={'size': 8})) + + # # Circuit types # diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 91be2ad54..790b8ba23 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -16,6 +16,8 @@ from .models import Circuit, CircuitType, Provider class ProviderListView(ObjectListView): queryset = Provider.objects.annotate(count_circuits=Count('circuits')) + filter = filters.ProviderFilter + filter_form = forms.ProviderFilterForm table = tables.ProviderTable edit_permissions = ['circuits.change_provider', 'circuits.delete_provider'] template_name = 'circuits/provider_list.html' diff --git a/netbox/templates/circuits/provider_list.html b/netbox/templates/circuits/provider_list.html index 2b5bfc68c..c6b81063b 100644 --- a/netbox/templates/circuits/provider_list.html +++ b/netbox/templates/circuits/provider_list.html @@ -14,8 +14,28 @@

Providers

-
+
{% include 'utilities/obj_table.html' with bulk_edit_url='circuits:provider_bulk_edit' bulk_delete_url='circuits:provider_bulk_delete' %}
+
+
+
+ Search +
+
+
+
+ + + + +
+
+
+
+ {% include 'inc/filter_panel.html' %} +
{% endblock %} From f6bd1f0c4878ca47741efa6cdfdcc5d0ce2cdf00 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 14 Jul 2016 14:03:57 -0400 Subject: [PATCH 24/25] Make the HA warning re: SECRET_KEY a note --- docs/installation/netbox.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/installation/netbox.md b/docs/installation/netbox.md index c5173e61e..813291033 100644 --- a/docs/installation/netbox.md +++ b/docs/installation/netbox.md @@ -110,10 +110,11 @@ DATABASE = { Generate a random secret key of at least 50 alphanumeric characters. This key must be unique to this installation and must not be shared outside the local system. -In the case of a highly available installation with multiple web servers, SECRET_KEY must be identical between all server in order to maintain a persistent user session state between servers. - You may use the script located at `netbox/generate_secret_key.py` to generate a suitable key. +!!! note + In the case of a highly available installation with multiple web servers, `SECRET_KEY` must be identical among all servers in order to maintain a persistent user session state. + # Run Database Migrations Before NetBox can run, we need to install the database schema. This is done by running `./manage.py migrate` from the `netbox` directory (`/opt/netbox/netbox/` in our example): From 026403ed389963208d7ecf13f60bf52adbd3faa7 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 14 Jul 2016 15:21:22 -0400 Subject: [PATCH 25/25] Release v1.2.2 --- 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 7e1697a82..b4e1f1667 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -12,7 +12,7 @@ except ImportError: "the documentation.") -VERSION = '1.2.2-dev' +VERSION = '1.2.2' # Import local configuration for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']: