From 8edaff860c1f3b28136fc7818275c4f1faead0e1 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 27 Dec 2016 15:07:52 -0500 Subject: [PATCH] Fixes #658: Added is_pool field to Prefix model --- netbox/ipam/api/serializers.py | 2 +- netbox/ipam/forms.py | 12 +----- .../migrations/0013_prefix_add_is_pool.py | 37 +++++++++++++++++++ netbox/ipam/models.py | 10 +++-- netbox/ipam/views.py | 17 ++++----- netbox/templates/ipam/prefix.html | 10 +++++ netbox/templates/ipam/prefix_edit.html | 1 + netbox/templates/ipam/prefix_import.html | 7 +++- 8 files changed, 71 insertions(+), 25 deletions(-) create mode 100644 netbox/ipam/migrations/0013_prefix_add_is_pool.py diff --git a/netbox/ipam/api/serializers.py b/netbox/ipam/api/serializers.py index d6bb87c5c..e3f902605 100644 --- a/netbox/ipam/api/serializers.py +++ b/netbox/ipam/api/serializers.py @@ -138,7 +138,7 @@ class PrefixSerializer(CustomFieldSerializer, serializers.ModelSerializer): class Meta: model = Prefix - fields = ['id', 'family', 'prefix', 'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'description', + fields = ['id', 'family', 'prefix', 'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'is_pool', 'description', 'custom_fields'] diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index d74695c76..7cb04cc60 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -158,15 +158,7 @@ class PrefixForm(BootstrapMixin, CustomFieldForm): class Meta: model = Prefix - fields = ['prefix', 'vrf', 'tenant', 'site', 'vlan', 'status', 'role', 'description'] - help_texts = { - 'prefix': "IPv4 or IPv6 network", - 'vrf': "VRF (if applicable)", - 'site': "The site to which this prefix is assigned (if applicable)", - 'vlan': "The VLAN to which this prefix is assigned (if applicable)", - 'status': "Operational status of this prefix", - 'role': "The primary function of this prefix", - } + fields = ['prefix', 'vrf', 'tenant', 'site', 'vlan', 'status', 'role', 'is_pool', 'description'] def __init__(self, *args, **kwargs): super(PrefixForm, self).__init__(*args, **kwargs) @@ -197,7 +189,7 @@ class PrefixFromCSVForm(forms.ModelForm): class Meta: model = Prefix - fields = ['prefix', 'vrf', 'tenant', 'site', 'vlan_group_name', 'vlan_vid', 'status_name', 'role', + fields = ['prefix', 'vrf', 'tenant', 'site', 'vlan_group_name', 'vlan_vid', 'status_name', 'role', 'is_pool', 'description'] def clean(self): diff --git a/netbox/ipam/migrations/0013_prefix_add_is_pool.py b/netbox/ipam/migrations/0013_prefix_add_is_pool.py new file mode 100644 index 000000000..fd1493610 --- /dev/null +++ b/netbox/ipam/migrations/0013_prefix_add_is_pool.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.4 on 2016-12-27 19:34 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import ipam.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('ipam', '0012_services'), + ] + + operations = [ + migrations.AddField( + model_name='prefix', + name='is_pool', + field=models.BooleanField(default=False, help_text=b'All IP addresses within this prefix are considered usable', verbose_name=b'Is a pool'), + ), + migrations.AlterField( + model_name='prefix', + name='prefix', + field=ipam.fields.IPNetworkField(help_text=b'IPv4 or IPv6 network with mask'), + ), + migrations.AlterField( + model_name='prefix', + name='role', + field=models.ForeignKey(blank=True, help_text=b'The primary function of this prefix', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='prefixes', to='ipam.Role'), + ), + migrations.AlterField( + model_name='prefix', + name='status', + field=models.PositiveSmallIntegerField(choices=[(0, b'Container'), (1, b'Active'), (2, b'Reserved'), (3, b'Deprecated')], default=1, help_text=b'Operational status of this prefix', verbose_name=b'Status'), + ), + ] diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index 854a6afa0..d4fc5f30a 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -269,15 +269,19 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel): assigned to a VLAN where appropriate. """ family = models.PositiveSmallIntegerField(choices=AF_CHOICES, editable=False) - prefix = IPNetworkField() + prefix = IPNetworkField(help_text="IPv4 or IPv6 network with mask") site = models.ForeignKey('dcim.Site', related_name='prefixes', on_delete=models.PROTECT, blank=True, null=True) vrf = models.ForeignKey('VRF', related_name='prefixes', on_delete=models.PROTECT, blank=True, null=True, verbose_name='VRF') tenant = models.ForeignKey(Tenant, related_name='prefixes', blank=True, null=True, on_delete=models.PROTECT) vlan = models.ForeignKey('VLAN', related_name='prefixes', on_delete=models.PROTECT, blank=True, null=True, verbose_name='VLAN') - status = models.PositiveSmallIntegerField('Status', choices=PREFIX_STATUS_CHOICES, default=1) - role = models.ForeignKey('Role', related_name='prefixes', on_delete=models.SET_NULL, blank=True, null=True) + status = models.PositiveSmallIntegerField('Status', choices=PREFIX_STATUS_CHOICES, default=PREFIX_STATUS_ACTIVE, + help_text="Operational status of this prefix") + role = models.ForeignKey('Role', related_name='prefixes', on_delete=models.SET_NULL, blank=True, null=True, + help_text="The primary function of this prefix") + is_pool = models.BooleanField(verbose_name='Is a pool', default=False, + help_text="All IP addresses within this prefix are considered usable") description = models.CharField(max_length=100, blank=True) custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id') diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 30f2d5ab4..c7fc4ea31 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -38,24 +38,21 @@ def add_available_prefixes(parent, prefix_list): return prefix_list -def add_available_ipaddresses(prefix, ipaddress_list): +def add_available_ipaddresses(prefix, ipaddress_list, is_pool=False): """ - Annotate ranges of available IP addresses within a given prefix. + Annotate ranges of available IP addresses within a given prefix. If is_pool is True, the first and last IP will be + considered usable (regardless of mask length). """ output = [] prev_ip = None - # Ignore the "network address" for IPv4 prefixes larger than /31 - if prefix.version == 4 and prefix.prefixlen < 31: + # Ignore the network and broadcast addresses for non-pool IPv4 prefixes larger than /31. + if prefix.version == 4 and prefix.prefixlen < 31 and not is_pool: first_ip_in_prefix = netaddr.IPAddress(prefix.first + 1) - else: - first_ip_in_prefix = netaddr.IPAddress(prefix.first) - - # Ignore the broadcast address for IPv4 prefixes larger than /31 - if prefix.version == 4 and prefix.prefixlen < 31: last_ip_in_prefix = netaddr.IPAddress(prefix.last - 1) else: + first_ip_in_prefix = netaddr.IPAddress(prefix.first) last_ip_in_prefix = netaddr.IPAddress(prefix.last) if not ipaddress_list: @@ -476,7 +473,7 @@ def prefix_ipaddresses(request, pk): # Find all IPAddresses belonging to this Prefix ipaddresses = IPAddress.objects.filter(vrf=prefix.vrf, address__net_contained_or_equal=str(prefix.prefix))\ .select_related('vrf', 'interface__device', 'primary_ip4_for', 'primary_ip6_for') - ipaddresses = add_available_ipaddresses(prefix.prefix, ipaddresses) + ipaddresses = add_available_ipaddresses(prefix.prefix, ipaddresses, prefix.is_pool) ip_table = tables.IPAddressTable(ipaddresses) if request.user.has_perm('ipam.change_ipaddress') or request.user.has_perm('ipam.delete_ipaddress'): diff --git a/netbox/templates/ipam/prefix.html b/netbox/templates/ipam/prefix.html index 2245eb4be..4ad5dba05 100644 --- a/netbox/templates/ipam/prefix.html +++ b/netbox/templates/ipam/prefix.html @@ -85,6 +85,16 @@ {% endif %} + + Is a pool + + {% if prefix.is_pool %} + + {% else %} + + {% endif %} + + Description diff --git a/netbox/templates/ipam/prefix_edit.html b/netbox/templates/ipam/prefix_edit.html index b91d58969..ca5de43b3 100644 --- a/netbox/templates/ipam/prefix_edit.html +++ b/netbox/templates/ipam/prefix_edit.html @@ -12,6 +12,7 @@ {% render_field form.vlan %} {% render_field form.status %} {% render_field form.role %} + {% render_field form.is_pool %} {% render_field form.description %} diff --git a/netbox/templates/ipam/prefix_import.html b/netbox/templates/ipam/prefix_import.html index 413732d3f..c42958cf4 100644 --- a/netbox/templates/ipam/prefix_import.html +++ b/netbox/templates/ipam/prefix_import.html @@ -68,6 +68,11 @@ Functional role (optional) Customer + + Is a pool + True if all IPs are considered usable + False + Description Short description (optional) @@ -76,7 +81,7 @@

Example

-
192.168.42.0/24,65000:123,ABC01,HQ,Customers,801,Active,Customer,7th floor WiFi
+
192.168.42.0/24,65000:123,ABC01,HQ,Customers,801,Active,Customer,False,7th floor WiFi
{% endblock %}