From b514d7c087af400f92d1e6d1398106a140958e53 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Wed, 8 Jan 2020 17:23:09 +0000 Subject: [PATCH 01/20] Fixes #3623: Word expansion for interfaces --- docs/release-notes/version-2.6.md | 1 + netbox/utilities/forms.py | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-2.6.md b/docs/release-notes/version-2.6.md index f3ff8798a..f5fc4beba 100644 --- a/docs/release-notes/version-2.6.md +++ b/docs/release-notes/version-2.6.md @@ -4,6 +4,7 @@ * [#2050](https://github.com/netbox-community/netbox/issues/2050) - Preview image attachments when hovering the link * [#3187](https://github.com/netbox-community/netbox/issues/3187) - Add rack selection field to rack elevations +* [#3623](https://github.com/netbox-community/netbox/issues/3623) - Add word expansion during interface creation ## Bug Fixes diff --git a/netbox/utilities/forms.py b/netbox/utilities/forms.py index eeee719ae..4cd92ca12 100644 --- a/netbox/utilities/forms.py +++ b/netbox/utilities/forms.py @@ -60,8 +60,13 @@ def parse_alphanumeric_range(string): for n in list(range(int(begin), int(end) + 1)): values.append(n) else: - for n in list(range(ord(begin), ord(end) + 1)): - values.append(chr(n)) + # Value-based + if begin == end: + values.append(begin) + # Range-based + else: + for n in list(range(ord(begin), ord(end) + 1)): + values.append(chr(n)) return values From d751c853b8e315380616a47994c76a709904898c Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Wed, 8 Jan 2020 17:28:31 +0000 Subject: [PATCH 02/20] Added example and handled invalid ranges gracefully --- netbox/utilities/forms.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netbox/utilities/forms.py b/netbox/utilities/forms.py index 4cd92ca12..39422c265 100644 --- a/netbox/utilities/forms.py +++ b/netbox/utilities/forms.py @@ -65,6 +65,9 @@ def parse_alphanumeric_range(string): values.append(begin) # Range-based else: + # Not a valid range (more than a single character) + if not len(begin) == len(end) == 1: + raise forms.ValidationError('Range "{}" is invalid.'.format(dash_range)) for n in list(range(ord(begin), ord(end) + 1)): values.append(chr(n)) return values @@ -486,6 +489,7 @@ class ExpandableNameField(forms.CharField): 'Mixed cases and types within a single range are not supported.
' \ 'Examples:' def to_python(self, value): From b931b2b272b5228a2529d7821c52ad988b24bd62 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Thu, 9 Jan 2020 10:00:02 +0000 Subject: [PATCH 03/20] Fixes #3668: search address by DNS name when assigning --- docs/release-notes/version-2.6.md | 1 + netbox/ipam/forms.py | 7 ++++++- netbox/ipam/tables.py | 2 +- netbox/ipam/views.py | 1 + netbox/templates/ipam/ipaddress_assign.html | 1 + 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-2.6.md b/docs/release-notes/version-2.6.md index f3ff8798a..341e62a79 100644 --- a/docs/release-notes/version-2.6.md +++ b/docs/release-notes/version-2.6.md @@ -4,6 +4,7 @@ * [#2050](https://github.com/netbox-community/netbox/issues/2050) - Preview image attachments when hovering the link * [#3187](https://github.com/netbox-community/netbox/issues/3187) - Add rack selection field to rack elevations +* [#3668](https://github.com/netbox-community/netbox/issues/3668) - Search by DNS name when assigning IP address ## Bug Fixes diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 413e72eaf..f4bcfb2e6 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -943,7 +943,12 @@ class IPAddressAssignForm(BootstrapMixin, forms.Form): ) ) address = forms.CharField( - label='IP Address' + label='IP Address', + required=False, + ) + dns_name = forms.CharField( + label='DNS Name', + required=False, ) diff --git a/netbox/ipam/tables.py b/netbox/ipam/tables.py index e4d2bf8b4..d6e26f6a1 100644 --- a/netbox/ipam/tables.py +++ b/netbox/ipam/tables.py @@ -373,7 +373,7 @@ class IPAddressAssignTable(BaseTable): class Meta(BaseTable.Meta): model = IPAddress - fields = ('address', 'vrf', 'status', 'role', 'tenant', 'parent', 'interface', 'description') + fields = ('address', 'dns_name', 'vrf', 'status', 'role', 'tenant', 'parent', 'interface', 'description') orderable = False diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 2cc1a0ea8..d38366d54 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -745,6 +745,7 @@ class IPAddressAssignView(PermissionRequiredMixin, View): ).filter( vrf=form.cleaned_data['vrf'], address__istartswith=form.cleaned_data['address'], + dns_name__icontains=form.cleaned_data['dns_name'], )[:100] # Limit to 100 results table = tables.IPAddressAssignTable(queryset) diff --git a/netbox/templates/ipam/ipaddress_assign.html b/netbox/templates/ipam/ipaddress_assign.html index 579f2d98b..349c06919 100644 --- a/netbox/templates/ipam/ipaddress_assign.html +++ b/netbox/templates/ipam/ipaddress_assign.html @@ -26,6 +26,7 @@
{% render_field form.vrf %} {% render_field form.address %} + {% render_field form.dns_name %}
From 202c2dcb5ae5b7d83aaa4b5a0d4d8d2e13300e48 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Thu, 9 Jan 2020 16:26:11 +0000 Subject: [PATCH 04/20] Changed to `q` filter --- netbox/ipam/forms.py | 10 +++------- netbox/ipam/views.py | 12 +++++------- netbox/templates/ipam/ipaddress_assign.html | 5 ++--- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index f4bcfb2e6..c3387a5aa 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -933,7 +933,7 @@ class IPAddressBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd class IPAddressAssignForm(BootstrapMixin, forms.Form): - vrf = forms.ModelChoiceField( + vrf_id = forms.ModelChoiceField( queryset=VRF.objects.all(), required=False, label='VRF', @@ -942,13 +942,9 @@ class IPAddressAssignForm(BootstrapMixin, forms.Form): api_url="/api/ipam/vrfs/" ) ) - address = forms.CharField( - label='IP Address', - required=False, - ) - dns_name = forms.CharField( - label='DNS Name', + q = forms.CharField( required=False, + label='Search', ) diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index d6cada398..084cf1205 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -749,14 +749,12 @@ class IPAddressAssignView(PermissionRequiredMixin, View): if form.is_valid(): - queryset = IPAddress.objects.prefetch_related( + addresses = IPAddress.objects.prefetch_related( 'vrf', 'tenant', 'interface__device', 'interface__virtual_machine' - ).filter( - vrf=form.cleaned_data['vrf'], - address__istartswith=form.cleaned_data['address'], - dns_name__icontains=form.cleaned_data['dns_name'], - )[:100] # Limit to 100 results - table = tables.IPAddressAssignTable(queryset) + ) + # Limit to 100 results + addresses = filters.IPAddressFilter(request.POST, addresses).qs[:100] + table = tables.IPAddressAssignTable(addresses) return render(request, 'ipam/ipaddress_assign.html', { 'form': form, diff --git a/netbox/templates/ipam/ipaddress_assign.html b/netbox/templates/ipam/ipaddress_assign.html index 349c06919..ab163533f 100644 --- a/netbox/templates/ipam/ipaddress_assign.html +++ b/netbox/templates/ipam/ipaddress_assign.html @@ -24,9 +24,8 @@
Select IP Address
- {% render_field form.vrf %} - {% render_field form.address %} - {% render_field form.dns_name %} + {% render_field form.vrf_id %} + {% render_field form.q %}
From 3195219ed40563c6bbaef5bd0ad5a09209bc5dbe Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Thu, 9 Jan 2020 16:30:13 +0000 Subject: [PATCH 05/20] Added changelog for 3009 --- docs/release-notes/version-2.6.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/version-2.6.md b/docs/release-notes/version-2.6.md index 1f3e9a430..afc9b87c1 100644 --- a/docs/release-notes/version-2.6.md +++ b/docs/release-notes/version-2.6.md @@ -4,6 +4,7 @@ * [#2050](https://github.com/netbox-community/netbox/issues/2050) - Preview image attachments when hovering the link * [#2589](https://github.com/netbox-community/netbox/issues/2589) - Toggle for showing available prefixes/ip addresses +* [#3009](https://github.com/netbox-community/netbox/issues/3009) - Search by description when assigning IP address * [#3187](https://github.com/netbox-community/netbox/issues/3187) - Add rack selection field to rack elevations * [#3668](https://github.com/netbox-community/netbox/issues/3668) - Search by DNS name when assigning IP address * [#3851](https://github.com/netbox-community/netbox/issues/3851) - Allow passing initial data to custom script forms From 01de358d4e08bf29d2c8a5fca064732b1e2f9b9a Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Thu, 9 Jan 2020 16:32:01 +0000 Subject: [PATCH 06/20] Added changelog for 3009 again as I accidentally removed it while merging --- docs/release-notes/version-2.6.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/version-2.6.md b/docs/release-notes/version-2.6.md index a6e54cbef..e054e7684 100644 --- a/docs/release-notes/version-2.6.md +++ b/docs/release-notes/version-2.6.md @@ -4,6 +4,7 @@ * [#2050](https://github.com/netbox-community/netbox/issues/2050) - Preview image attachments when hovering the link * [#2589](https://github.com/netbox-community/netbox/issues/2589) - Toggle for showing available prefixes/ip addresses +* [#3009](https://github.com/netbox-community/netbox/issues/3009) - Search by description when assigning IP address * [#3090](https://github.com/netbox-community/netbox/issues/3090) - Add filter field for device interfaces * [#3187](https://github.com/netbox-community/netbox/issues/3187) - Add rack selection field to rack elevations * [#3440](https://github.com/netbox-community/netbox/issues/3440) - Add total length to cable trace From 7e37ffab80d43992565c8e3d8b54c0f08bae9933 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Thu, 9 Jan 2020 18:26:10 +0000 Subject: [PATCH 07/20] Added tests for IPv4 --- netbox/utilities/tests/test_forms.py | 69 ++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 netbox/utilities/tests/test_forms.py diff --git a/netbox/utilities/tests/test_forms.py b/netbox/utilities/tests/test_forms.py new file mode 100644 index 000000000..0434ff137 --- /dev/null +++ b/netbox/utilities/tests/test_forms.py @@ -0,0 +1,69 @@ +from django.test import TestCase + +from utilities.forms import * + + +class ExpandIPAddress(TestCase): + """ + Validate the operation of expand_ipaddress_pattern(). + """ + def test_ipv4_range(self): + input = '1.2.3.[9-10]/32' + output = sorted([ + '1.2.3.9/32', + '1.2.3.10/32', + ]) + + self.assertEqual(sorted(list(expand_ipaddress_pattern(input, 4))), output) + + def test_ipv4_set(self): + input = '1.2.3.[4,44]/32' + output = sorted([ + '1.2.3.4/32', + '1.2.3.44/32', + ]) + + self.assertEqual(sorted(list(expand_ipaddress_pattern(input, 4))), output) + + def test_ipv4_multiple_ranges(self): + input = '1.[9-10].3.[9-11]/32' + output = sorted([ + '1.9.3.9/32', + '1.9.3.10/32', + '1.9.3.11/32', + '1.10.3.9/32', + '1.10.3.10/32', + '1.10.3.11/32', + ]) + + self.assertEqual(sorted(list(expand_ipaddress_pattern(input, 4))), output) + + def test_ipv4_multiple_sets(self): + input = '1.[2,22].3.[4,44]/32' + output = sorted([ + '1.2.3.4/32', + '1.2.3.44/32', + '1.22.3.4/32', + '1.22.3.44/32', + ]) + + self.assertEqual(sorted(list(expand_ipaddress_pattern(input, 4))), output) + + + def test_ipv4_set_and_range(self): + input = '1.[2,22].3.[9-11]/32' + output = sorted([ + '1.2.3.9/32', + '1.2.3.10/32', + '1.2.3.11/32', + '1.22.3.9/32', + '1.22.3.10/32', + '1.22.3.11/32', + ]) + + self.assertEqual(sorted(list(expand_ipaddress_pattern(input, 4))), output) + + # TODO: IPv6 + # TODO: negative tests + +# TODO: alphanumeric From 98706bb9272257f82319533b6eed1cd309b7a206 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Thu, 9 Jan 2020 20:10:51 +0000 Subject: [PATCH 08/20] Fixes #3393: Paginate circuits at the provider details view --- docs/release-notes/version-2.6.md | 1 + netbox/circuits/views.py | 12 +++++- netbox/templates/circuits/provider.html | 54 +------------------------ 3 files changed, 14 insertions(+), 53 deletions(-) diff --git a/docs/release-notes/version-2.6.md b/docs/release-notes/version-2.6.md index ee6ea2e4d..7d6609863 100644 --- a/docs/release-notes/version-2.6.md +++ b/docs/release-notes/version-2.6.md @@ -9,6 +9,7 @@ * [#3090](https://github.com/netbox-community/netbox/issues/3090) - Add filter field for device interfaces * [#3187](https://github.com/netbox-community/netbox/issues/3187) - Add rack selection field to rack elevations * [#3440](https://github.com/netbox-community/netbox/issues/3440) - Add total length to cable trace +* [#3393](https://github.com/netbox-community/netbox/issues/3393) - Paginate the circuits at the provider details view * [#3851](https://github.com/netbox-community/netbox/issues/3851) - Allow passing initial data to custom script forms ## Bug Fixes diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 655b714d7..73b3e5d3e 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import permission_required from django.contrib.auth.mixins import PermissionRequiredMixin @@ -5,9 +6,11 @@ from django.db import transaction from django.db.models import Count, OuterRef, Subquery from django.shortcuts import get_object_or_404, redirect, render from django.views.generic import View +from django_tables2 import RequestConfig from extras.models import Graph, GRAPH_TYPE_PROVIDER from utilities.forms import ConfirmationForm +from utilities.paginator import EnhancedPaginator from utilities.views import ( BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView, ) @@ -36,11 +39,18 @@ class ProviderView(PermissionRequiredMixin, View): provider = get_object_or_404(Provider, slug=slug) circuits = Circuit.objects.filter(provider=provider).prefetch_related('type', 'tenant', 'terminations__site') + circuits_table = tables.CircuitTable(circuits, orderable=False) show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists() + paginate = { + 'paginator_class': EnhancedPaginator, + 'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT) + } + RequestConfig(request, paginate).configure(circuits_table) + return render(request, 'circuits/provider.html', { 'provider': provider, - 'circuits': circuits, + 'circuits_table': circuits_table, 'show_graphs': show_graphs, }) diff --git a/netbox/templates/circuits/provider.html b/netbox/templates/circuits/provider.html index a83a5337a..178e488d8 100644 --- a/netbox/templates/circuits/provider.html +++ b/netbox/templates/circuits/provider.html @@ -125,58 +125,7 @@
Circuits
- - - - - - - - - - {% for c in circuits %} - - - - - - - - - {% empty %} - - - - {% endfor %} -
Circuit IDTypeTenantA SideZ SideDescription
- {{ c.cid }} - - {{ c.type }} - - {% if c.tenant %} - {{ c.tenant }} - {% else %} - - {% endif %} - - {% if c.termination_a %} - {{ c.termination_a.site }} - {% else %} - - {% endif %} - - {% if c.termination_z %} - {{ c.termination_z.site }} - {% else %} - - {% endif %} - - {% if c.description %} - {{ c.description }} - {% else %} - - {% endif %} -
None
+ {% include 'inc/table.html' with table=circuits_table %} {% if perms.circuits.add_circuit %} {% endif %} + {% include 'inc/paginator.html' with paginator=circuits_table.paginator page=circuits_table.page %} {% include 'inc/modal.html' with modal_name='graphs' %} From 6440dd6211c0e73b6ecc92ce2b7f8e2ba020e5e8 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Thu, 9 Jan 2020 20:15:22 +0000 Subject: [PATCH 09/20] Hid the provider column --- netbox/circuits/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 73b3e5d3e..5d76e38ee 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -39,9 +39,11 @@ class ProviderView(PermissionRequiredMixin, View): provider = get_object_or_404(Provider, slug=slug) circuits = Circuit.objects.filter(provider=provider).prefetch_related('type', 'tenant', 'terminations__site') - circuits_table = tables.CircuitTable(circuits, orderable=False) show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists() + circuits_table = tables.CircuitTable(circuits, orderable=False) + circuits_table.columns.hide('provider') + paginate = { 'paginator_class': EnhancedPaginator, 'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT) From d564de0b8eed4908bce9456282df2dbda14fd0bc Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Thu, 9 Jan 2020 20:23:16 +0000 Subject: [PATCH 10/20] Corrected placement of changelog --- docs/release-notes/version-2.6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/version-2.6.md b/docs/release-notes/version-2.6.md index 7d6609863..f4691f34e 100644 --- a/docs/release-notes/version-2.6.md +++ b/docs/release-notes/version-2.6.md @@ -8,8 +8,8 @@ * [#2589](https://github.com/netbox-community/netbox/issues/2589) - Toggle for showing available prefixes/ip addresses * [#3090](https://github.com/netbox-community/netbox/issues/3090) - Add filter field for device interfaces * [#3187](https://github.com/netbox-community/netbox/issues/3187) - Add rack selection field to rack elevations -* [#3440](https://github.com/netbox-community/netbox/issues/3440) - Add total length to cable trace * [#3393](https://github.com/netbox-community/netbox/issues/3393) - Paginate the circuits at the provider details view +* [#3440](https://github.com/netbox-community/netbox/issues/3440) - Add total length to cable trace * [#3851](https://github.com/netbox-community/netbox/issues/3851) - Allow passing initial data to custom script forms ## Bug Fixes From 6f9fcc741e1fc054ff19cf028f9a005959bfe875 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Thu, 9 Jan 2020 21:12:35 +0000 Subject: [PATCH 11/20] Fixes #3876: set min and max values for ASN field --- docs/release-notes/version-2.6.md | 1 + netbox/dcim/fields.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/docs/release-notes/version-2.6.md b/docs/release-notes/version-2.6.md index ee6ea2e4d..abc65f12c 100644 --- a/docs/release-notes/version-2.6.md +++ b/docs/release-notes/version-2.6.md @@ -21,6 +21,7 @@ * [#3862](https://github.com/netbox-community/netbox/issues/3862) - Allow filtering device components by multiple device names * [#3864](https://github.com/netbox-community/netbox/issues/3864) - Disallow /0 masks * [#3872](https://github.com/netbox-community/netbox/issues/3872) - Paginate related IPs of an address +* [#3876](https://github.com/netbox-community/netbox/issues/3876) - Fixed min/max to ASN input field at the site creation page --- diff --git a/netbox/dcim/fields.py b/netbox/dcim/fields.py index 9624ce0a3..d8fef0d53 100644 --- a/netbox/dcim/fields.py +++ b/netbox/dcim/fields.py @@ -11,6 +11,11 @@ class ASNField(models.BigIntegerField): MaxValueValidator(4294967295), ] + def formfield(self, **kwargs): + defaults = {'min_value': 1, 'max_value': 4294967295} + defaults.update(**kwargs) + return super().formfield(**defaults) + class mac_unix_expanded_uppercase(mac_unix_expanded): word_fmt = '%.2X' From 6f89c9a54d36738dffc9af88bae65bf292ba2642 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Thu, 9 Jan 2020 21:58:38 +0000 Subject: [PATCH 12/20] Replaced ASN bounds with constants --- netbox/dcim/constants.py | 4 ++++ netbox/dcim/fields.py | 8 +++++--- netbox/dcim/forms.py | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/netbox/dcim/constants.py b/netbox/dcim/constants.py index ccaa48636..f325e34d4 100644 --- a/netbox/dcim/constants.py +++ b/netbox/dcim/constants.py @@ -1,4 +1,8 @@ +# BGP ASN bounds +BGP_ASN_MIN = 1 +BGP_ASN_MAX = 2**32 - 1 + # Rack types RACK_TYPE_2POST = 100 RACK_TYPE_4POST = 200 diff --git a/netbox/dcim/fields.py b/netbox/dcim/fields.py index d8fef0d53..719b6755a 100644 --- a/netbox/dcim/fields.py +++ b/netbox/dcim/fields.py @@ -3,16 +3,18 @@ from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models from netaddr import AddrFormatError, EUI, mac_unix_expanded +from .constants import * + class ASNField(models.BigIntegerField): description = "32-bit ASN field" default_validators = [ - MinValueValidator(1), - MaxValueValidator(4294967295), + MinValueValidator(BGP_ASN_MIN), + MaxValueValidator(BGP_ASN_MAX), ] def formfield(self, **kwargs): - defaults = {'min_value': 1, 'max_value': 4294967295} + defaults = {'min_value': BGP_ASN_MIN, 'max_value': BGP_ASN_MAX} defaults.update(**kwargs) return super().formfield(**defaults) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index dbb9cff15..6086491d0 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -292,8 +292,8 @@ class SiteBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor ) ) asn = forms.IntegerField( - min_value=1, - max_value=4294967295, + min_value=BGP_ASN_MIN, + max_value=BGP_ASN_MAX, required=False, label='ASN' ) From bd95503ffaba40675520e501c6f8d949101fa9b5 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 9 Jan 2020 20:13:21 -0500 Subject: [PATCH 13/20] Add configuration file for GitHub Stale bot --- .github/lock.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/lock.yml diff --git a/.github/lock.yml b/.github/lock.yml new file mode 100644 index 000000000..36a41b04e --- /dev/null +++ b/.github/lock.yml @@ -0,0 +1,23 @@ +# Configuration for Lock (https://github.com/apps/lock) + +# Number of days of inactivity before a closed issue or pull request is locked +daysUntilLock: 90 + +# Skip issues and pull requests created before a given timestamp. Timestamp must +# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable +skipCreatedBefore: 2020-01-01 + +# Issues and pull requests with these labels will be ignored. Set to `[]` to disable +exemptLabels: [] + +# Label to add before locking, such as `outdated`. Set to `false` to disable +lockLabel: false + +# Comment to post before locking. Set to `false` to disable +lockComment: false + +# Assign `resolved` as the reason for locking. Set to `false` to disable +setLockReason: true + +# Limit to only `issues` or `pulls` +# only: issues From bc86a994a6f44f53e8985436e501a31a09bc98e0 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 9 Jan 2020 20:14:31 -0500 Subject: [PATCH 14/20] Clean up Stale bot config formatting --- .github/stale.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/stale.yml b/.github/stale.yml index 7c8d03f12..61201cc4e 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,20 +1,27 @@ +# Configuration for Stale (https://github.com/apps/stale) + # Number of days of inactivity before an issue becomes stale daysUntilStale: 14 + # Number of days of inactivity before a stale issue is closed daysUntilClose: 7 + # Issues with these labels will never be considered stale exemptLabels: - "status: accepted" - "status: gathering feedback" - "status: blocked" + # Label to use when marking an issue as stale staleLabel: wontfix + # Comment to post when marking an issue as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. NetBox is governed by a small group of core maintainers which means not all opened issues may receive direct feedback. Please see our [contributing guide](https://github.com/netbox-community/netbox/blob/develop/CONTRIBUTING.md). + # Comment to post when closing a stale issue. Set to `false` to disable closeComment: > This issue has been automatically closed due to lack of activity. In an From 14d0b741d5840267f9ee8c0dfbe6db5347afcd07 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Fri, 10 Jan 2020 10:26:46 +0000 Subject: [PATCH 15/20] Removed redundant list call --- netbox/utilities/tests/test_forms.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/netbox/utilities/tests/test_forms.py b/netbox/utilities/tests/test_forms.py index 0434ff137..1fd09341c 100644 --- a/netbox/utilities/tests/test_forms.py +++ b/netbox/utilities/tests/test_forms.py @@ -14,7 +14,7 @@ class ExpandIPAddress(TestCase): '1.2.3.10/32', ]) - self.assertEqual(sorted(list(expand_ipaddress_pattern(input, 4))), output) + self.assertEqual(sorted(expand_ipaddress_pattern(input, 4)), output) def test_ipv4_set(self): input = '1.2.3.[4,44]/32' @@ -23,7 +23,7 @@ class ExpandIPAddress(TestCase): '1.2.3.44/32', ]) - self.assertEqual(sorted(list(expand_ipaddress_pattern(input, 4))), output) + self.assertEqual(sorted(expand_ipaddress_pattern(input, 4)), output) def test_ipv4_multiple_ranges(self): input = '1.[9-10].3.[9-11]/32' @@ -36,7 +36,7 @@ class ExpandIPAddress(TestCase): '1.10.3.11/32', ]) - self.assertEqual(sorted(list(expand_ipaddress_pattern(input, 4))), output) + self.assertEqual(sorted(expand_ipaddress_pattern(input, 4)), output) def test_ipv4_multiple_sets(self): input = '1.[2,22].3.[4,44]/32' @@ -47,8 +47,7 @@ class ExpandIPAddress(TestCase): '1.22.3.44/32', ]) - self.assertEqual(sorted(list(expand_ipaddress_pattern(input, 4))), output) - + self.assertEqual(sorted(expand_ipaddress_pattern(input, 4)), output) def test_ipv4_set_and_range(self): input = '1.[2,22].3.[9-11]/32' @@ -61,7 +60,7 @@ class ExpandIPAddress(TestCase): '1.22.3.11/32', ]) - self.assertEqual(sorted(list(expand_ipaddress_pattern(input, 4))), output) + self.assertEqual(sorted(expand_ipaddress_pattern(input, 4)), output) # TODO: IPv6 # TODO: negative tests From 260a26e1b0b3a3c5589e211962c26af904d19492 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Fri, 10 Jan 2020 11:06:01 +0000 Subject: [PATCH 16/20] Added tests for IPv6 --- netbox/utilities/tests/test_forms.py | 67 +++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/netbox/utilities/tests/test_forms.py b/netbox/utilities/tests/test_forms.py index 1fd09341c..ea693f42c 100644 --- a/netbox/utilities/tests/test_forms.py +++ b/netbox/utilities/tests/test_forms.py @@ -62,7 +62,72 @@ class ExpandIPAddress(TestCase): self.assertEqual(sorted(expand_ipaddress_pattern(input, 4)), output) - # TODO: IPv6 + def test_ipv6_range(self): + input = 'fec::abcd:[9-b]/64' + output = sorted([ + 'fec::abcd:9/64', + 'fec::abcd:a/64', + 'fec::abcd:b/64', + ]) + + self.assertEqual(sorted(expand_ipaddress_pattern(input, 6)), output) + + def test_ipv6_range_multichar_field(self): + input = 'fec::abcd:[f-11]/64' + output = sorted([ + 'fec::abcd:f/64', + 'fec::abcd:10/64', + 'fec::abcd:11/64', + ]) + + self.assertEqual(sorted(expand_ipaddress_pattern(input, 6)), output) + + def test_ipv6_set(self): + input = 'fec::abcd:[9,ab]/64' + output = sorted([ + 'fec::abcd:9/64', + 'fec::abcd:ab/64', + ]) + + self.assertEqual(sorted(expand_ipaddress_pattern(input, 6)), output) + + def test_ipv6_multiple_ranges(self): + input = 'fec::[1-2]bcd:[9-b]/64' + output = sorted([ + 'fec::1bcd:9/64', + 'fec::1bcd:a/64', + 'fec::1bcd:b/64', + 'fec::2bcd:9/64', + 'fec::2bcd:a/64', + 'fec::2bcd:b/64', + ]) + + self.assertEqual(sorted(expand_ipaddress_pattern(input, 6)), output) + + def test_ipv6_multiple_sets(self): + input = 'fec::[a,f]bcd:[9,ab]/64' + output = sorted([ + 'fec::abcd:9/64', + 'fec::abcd:ab/64', + 'fec::fbcd:9/64', + 'fec::fbcd:ab/64', + ]) + + self.assertEqual(sorted(expand_ipaddress_pattern(input, 6)), output) + + def test_ipv6_set_and_range(self): + input = 'fec::[dead,beaf]:[9-b]/64' + output = sorted([ + 'fec::dead:9/64', + 'fec::dead:a/64', + 'fec::dead:b/64', + 'fec::beaf:9/64', + 'fec::beaf:a/64', + 'fec::beaf:b/64', + ]) + + self.assertEqual(sorted(expand_ipaddress_pattern(input, 6)), output) + # TODO: negative tests # TODO: alphanumeric From c31309a013bedca63fb8f54ad4d649b1feb5f88f Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Fri, 10 Jan 2020 11:21:37 +0000 Subject: [PATCH 17/20] Negative tests for expand_ipaddress_pattern --- netbox/utilities/tests/test_forms.py | 34 +++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/netbox/utilities/tests/test_forms.py b/netbox/utilities/tests/test_forms.py index ea693f42c..7bad34e3c 100644 --- a/netbox/utilities/tests/test_forms.py +++ b/netbox/utilities/tests/test_forms.py @@ -128,6 +128,38 @@ class ExpandIPAddress(TestCase): self.assertEqual(sorted(expand_ipaddress_pattern(input, 6)), output) - # TODO: negative tests + def test_invalid_address_family(self): + with self.assertRaisesRegex(Exception, 'Invalid IP address family: 5'): + sorted(expand_ipaddress_pattern(None, 5)) + + def test_invalid_non_pattern(self): + with self.assertRaises(ValueError): + sorted(expand_ipaddress_pattern('1.2.3.4/32', 4)) + + def test_invalid_range(self): + with self.assertRaises(ValueError): + sorted(expand_ipaddress_pattern('1.2.3.[4-]/32', 4)) + + with self.assertRaises(ValueError): + sorted(expand_ipaddress_pattern('1.2.3.[-4]/32', 4)) + + with self.assertRaises(ValueError): + sorted(expand_ipaddress_pattern('1.2.3.[4--5]/32', 4)) + + def test_invalid_range_bounds(self): + self.assertEqual(sorted(expand_ipaddress_pattern('1.2.3.[4-3]/32', 6)), []) + + def test_invalid_set(self): + with self.assertRaises(ValueError): + sorted(expand_ipaddress_pattern('1.2.3.[4]/32', 4)) + + with self.assertRaises(ValueError): + sorted(expand_ipaddress_pattern('1.2.3.[4,]/32', 4)) + + with self.assertRaises(ValueError): + sorted(expand_ipaddress_pattern('1.2.3.[,4]/32', 4)) + + with self.assertRaises(ValueError): + sorted(expand_ipaddress_pattern('1.2.3.[4,,5]/32', 4)) # TODO: alphanumeric From 86433215a4379ef7e541f8f1c3caadda244ccde1 Mon Sep 17 00:00:00 2001 From: Saria Hajjar Date: Fri, 10 Jan 2020 11:54:43 +0000 Subject: [PATCH 18/20] Added tests for alphanumeric --- netbox/utilities/tests/test_forms.py | 120 ++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/netbox/utilities/tests/test_forms.py b/netbox/utilities/tests/test_forms.py index 7bad34e3c..2d7235505 100644 --- a/netbox/utilities/tests/test_forms.py +++ b/netbox/utilities/tests/test_forms.py @@ -1,3 +1,4 @@ +from django import forms from django.test import TestCase from utilities.forms import * @@ -162,4 +163,121 @@ class ExpandIPAddress(TestCase): with self.assertRaises(ValueError): sorted(expand_ipaddress_pattern('1.2.3.[4,,5]/32', 4)) -# TODO: alphanumeric + +class ExpandAlphanumeric(TestCase): + """ + Validate the operation of expand_alphanumeric_pattern(). + """ + def test_range_numberic(self): + input = 'r[9-11]a' + output = sorted([ + 'r9a', + 'r10a', + 'r11a', + ]) + + self.assertEqual(sorted(expand_alphanumeric_pattern(input)), output) + + def test_range_alpha(self): + input = '[r-t]1a' + output = sorted([ + 'r1a', + 's1a', + 't1a', + ]) + + self.assertEqual(sorted(expand_alphanumeric_pattern(input)), output) + + def test_set(self): + input = '[r,t]1a' + output = sorted([ + 'r1a', + 't1a', + ]) + + self.assertEqual(sorted(expand_alphanumeric_pattern(input)), output) + + def test_set_multichar(self): + input = '[ra,tb]1a' + output = sorted([ + 'ra1a', + 'tb1a', + ]) + + self.assertEqual(sorted(expand_alphanumeric_pattern(input)), output) + + def test_multiple_ranges(self): + input = '[r-t]1[a-b]' + output = sorted([ + 'r1a', + 'r1b', + 's1a', + 's1b', + 't1a', + 't1b', + ]) + + self.assertEqual(sorted(expand_alphanumeric_pattern(input)), output) + + def test_multiple_sets(self): + input = '[ra,tb]1[ax,by]' + output = sorted([ + 'ra1ax', + 'ra1by', + 'tb1ax', + 'tb1by', + ]) + + self.assertEqual(sorted(expand_alphanumeric_pattern(input)), output) + + def test_set_and_range(self): + input = '[ra,tb]1[a-c]' + output = sorted([ + 'ra1a', + 'ra1b', + 'ra1c', + 'tb1a', + 'tb1b', + 'tb1c', + ]) + + self.assertEqual(sorted(expand_alphanumeric_pattern(input)), output) + + def test_invalid_non_pattern(self): + with self.assertRaises(ValueError): + sorted(expand_alphanumeric_pattern('r9a')) + + def test_invalid_range(self): + with self.assertRaises(ValueError): + sorted(expand_alphanumeric_pattern('r[8-]a')) + + with self.assertRaises(ValueError): + sorted(expand_alphanumeric_pattern('r[-8]a')) + + with self.assertRaises(ValueError): + sorted(expand_alphanumeric_pattern('r[8--9]a')) + + def test_invalid_range_alphanumeric(self): + self.assertEqual(sorted(expand_alphanumeric_pattern('r[9-a]a')), []) + self.assertEqual(sorted(expand_alphanumeric_pattern('r[a-9]a')), []) + + def test_invalid_range_bounds(self): + self.assertEqual(sorted(expand_alphanumeric_pattern('r[9-8]a')), []) + self.assertEqual(sorted(expand_alphanumeric_pattern('r[b-a]a')), []) + + def test_invalid_range_len(self): + with self.assertRaises(forms.ValidationError): + sorted(expand_alphanumeric_pattern('r[a-bb]a')) + + def test_invalid_set(self): + with self.assertRaises(ValueError): + sorted(expand_alphanumeric_pattern('r[a]a')) + + with self.assertRaises(ValueError): + sorted(expand_alphanumeric_pattern('r[a,]a')) + + with self.assertRaises(ValueError): + sorted(expand_alphanumeric_pattern('r[,a]a')) + + with self.assertRaises(ValueError): + sorted(expand_alphanumeric_pattern('r[a,,b]a')) From df9b175d559d7bf65738aab0f1819589e18a3df9 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 10 Jan 2020 10:21:11 -0500 Subject: [PATCH 19/20] Fixes #3882: Fix filtering of devices by rack group --- docs/release-notes/version-2.6.md | 1 + netbox/dcim/forms.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/release-notes/version-2.6.md b/docs/release-notes/version-2.6.md index 025994856..d7832a823 100644 --- a/docs/release-notes/version-2.6.md +++ b/docs/release-notes/version-2.6.md @@ -26,6 +26,7 @@ * [#3864](https://github.com/netbox-community/netbox/issues/3864) - Disallow /0 masks * [#3872](https://github.com/netbox-community/netbox/issues/3872) - Paginate related IPs of an address * [#3876](https://github.com/netbox-community/netbox/issues/3876) - Fixed min/max to ASN input field at the site creation page +* [#3882](https://github.com/netbox-community/netbox/issues/3882) - Fix filtering of devices by rack group --- diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 6086491d0..f0b91c2f5 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -739,7 +739,7 @@ class RackElevationFilterForm(RackFilterForm): # Filter the rack field based on the site and group self.fields['site'].widget.add_filter_for('id', 'site') - self.fields['group_id'].widget.add_filter_for('id', 'group_id') + self.fields['rack_group_id'].widget.add_filter_for('id', 'group_id') # @@ -1791,7 +1791,7 @@ class DeviceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilterForm, CustomFieldFilterForm): model = Device field_order = [ - 'q', 'region', 'site', 'group_id', 'rack_id', 'status', 'role', 'tenant_group', 'tenant', + 'q', 'region', 'site', 'rack_group_id', 'rack_id', 'status', 'role', 'tenant_group', 'tenant', 'manufacturer_id', 'device_type_id', 'mac_address', 'has_primary_ip', ] q = forms.CharField( @@ -1817,12 +1817,12 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt api_url="/api/dcim/sites/", value_field="slug", filter_for={ - 'group_id': 'site', + 'rack_group_id': 'site', 'rack_id': 'site', } ) ) - group_id = FilterChoiceField( + rack_group_id = FilterChoiceField( queryset=RackGroup.objects.prefetch_related( 'site' ), From d0139e064c8b2425708a4d33d58706acdb3c7156 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 10 Jan 2020 12:24:47 -0500 Subject: [PATCH 20/20] Extend section regarding test adaptation --- docs/development/extending-models.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/development/extending-models.md b/docs/development/extending-models.md index 0070c5545..dd44bb2ab 100644 --- a/docs/development/extending-models.md +++ b/docs/development/extending-models.md @@ -69,6 +69,14 @@ If the new field will be included in the object list view, add a column to the m Edit the object's view template to display the new field. There may also be a custom add/edit form template that needs to be updated. -### 11. Adjust API and model tests +### 11. Create/extend test cases -Extend the model and/or API tests to verify that the new field and any accompanying validation logic perform as expected. This is especially important for relational fields. +Create or extend the relevant test cases to verify that the new field and any accompanying validation logic perform as expected. This is especially important for relational fields. NetBox incorporates various test suites, including: + +* API serializer/view tests +* Filter tests +* Form tests +* Model tests +* View tests + +Be diligent to ensure all of the relevant test suites are adapted or extended as necessary to test any new functionality.