mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-25 22:57:45 -06:00
Merge branch 'develop' into develop-2.3
This commit is contained in:
@@ -78,8 +78,11 @@ class VRFBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
||||
class VRFFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
model = VRF
|
||||
q = forms.CharField(required=False, label='Search')
|
||||
tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('vrfs')), to_field_name='slug',
|
||||
null_option=(0, None))
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(filter_count=Count('vrfs')),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
@@ -368,23 +371,23 @@ class PrefixFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
queryset=VRF.objects.annotate(filter_count=Count('prefixes')),
|
||||
to_field_name='rd',
|
||||
label='VRF',
|
||||
null_option=(0, 'Global')
|
||||
null_label='-- Global --'
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(filter_count=Count('prefixes')),
|
||||
to_field_name='slug',
|
||||
null_option=(0, 'None')
|
||||
null_label='-- None --'
|
||||
)
|
||||
status = forms.MultipleChoiceField(choices=prefix_status_choices, required=False)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(filter_count=Count('prefixes')),
|
||||
to_field_name='slug',
|
||||
null_option=(0, 'None')
|
||||
null_label='-- None --'
|
||||
)
|
||||
role = FilterChoiceField(
|
||||
queryset=Role.objects.annotate(filter_count=Count('prefixes')),
|
||||
to_field_name='slug',
|
||||
null_option=(0, 'None')
|
||||
null_label='-- None --'
|
||||
)
|
||||
expand = forms.BooleanField(required=False, label='Expand prefix hierarchy')
|
||||
|
||||
@@ -719,12 +722,12 @@ class IPAddressFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
queryset=VRF.objects.annotate(filter_count=Count('ip_addresses')),
|
||||
to_field_name='rd',
|
||||
label='VRF',
|
||||
null_option=(0, 'Global')
|
||||
null_label='-- Global --'
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(filter_count=Count('ip_addresses')),
|
||||
to_field_name='slug',
|
||||
null_option=(0, 'None')
|
||||
null_label='-- None --'
|
||||
)
|
||||
status = forms.MultipleChoiceField(choices=ipaddress_status_choices, required=False)
|
||||
role = forms.MultipleChoiceField(choices=ipaddress_role_choices, required=False)
|
||||
@@ -766,7 +769,7 @@ class VLANGroupFilterForm(BootstrapMixin, forms.Form):
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(filter_count=Count('vlan_groups')),
|
||||
to_field_name='slug',
|
||||
null_option=(0, 'Global')
|
||||
null_label='-- Global --'
|
||||
)
|
||||
|
||||
|
||||
@@ -896,23 +899,23 @@ class VLANFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(filter_count=Count('vlans')),
|
||||
to_field_name='slug',
|
||||
null_option=(0, 'Global')
|
||||
null_label='-- Global --'
|
||||
)
|
||||
group_id = FilterChoiceField(
|
||||
queryset=VLANGroup.objects.annotate(filter_count=Count('vlans')),
|
||||
label='VLAN group',
|
||||
null_option=(0, 'None')
|
||||
null_label='-- None --'
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(filter_count=Count('vlans')),
|
||||
to_field_name='slug',
|
||||
null_option=(0, 'None')
|
||||
null_label='-- None --'
|
||||
)
|
||||
status = forms.MultipleChoiceField(choices=vlan_status_choices, required=False)
|
||||
role = FilterChoiceField(
|
||||
queryset=Role.objects.annotate(filter_count=Count('vlans')),
|
||||
to_field_name='slug',
|
||||
null_option=(0, 'None')
|
||||
null_label='-- None --'
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -298,10 +298,20 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel):
|
||||
|
||||
def get_child_ips(self):
|
||||
"""
|
||||
Return all IPAddresses within this Prefix.
|
||||
Return all IPAddresses within this Prefix and VRF.
|
||||
"""
|
||||
return IPAddress.objects.filter(address__net_host_contained=str(self.prefix), vrf=self.vrf)
|
||||
|
||||
def get_available_prefixes(self):
|
||||
"""
|
||||
Return all available Prefixes within this prefix as an IPSet.
|
||||
"""
|
||||
prefix = netaddr.IPSet(self.prefix)
|
||||
child_prefixes = netaddr.IPSet([child.prefix for child in self.get_child_prefixes()])
|
||||
available_prefixes = prefix - child_prefixes
|
||||
|
||||
return available_prefixes
|
||||
|
||||
def get_available_ips(self):
|
||||
"""
|
||||
Return all available IPs within this prefix as an IPSet.
|
||||
@@ -319,15 +329,23 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel):
|
||||
|
||||
return available_ips
|
||||
|
||||
def get_first_available_prefix(self):
|
||||
"""
|
||||
Return the first available child prefix within the prefix (or None).
|
||||
"""
|
||||
available_prefixes = self.get_available_prefixes()
|
||||
if not available_prefixes:
|
||||
return None
|
||||
return available_prefixes.iter_cidrs()[0]
|
||||
|
||||
def get_first_available_ip(self):
|
||||
"""
|
||||
Return the first available IP within the prefix (or None).
|
||||
"""
|
||||
available_ips = self.get_available_ips()
|
||||
if available_ips:
|
||||
return '{}/{}'.format(next(available_ips.__iter__()), self.prefix.prefixlen)
|
||||
else:
|
||||
if not available_ips:
|
||||
return None
|
||||
return '{}/{}'.format(next(available_ips.__iter__()), self.prefix.prefixlen)
|
||||
|
||||
def get_utilization(self):
|
||||
"""
|
||||
@@ -345,17 +363,6 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel):
|
||||
prefix_size -= 2
|
||||
return int(float(child_count) / prefix_size * 100)
|
||||
|
||||
@property
|
||||
def new_subnet(self):
|
||||
if self.family == 4:
|
||||
if self.prefix.prefixlen <= 30:
|
||||
return netaddr.IPNetwork('{}/{}'.format(self.prefix.network, self.prefix.prefixlen + 1))
|
||||
return None
|
||||
if self.family == 6:
|
||||
if self.prefix.prefixlen <= 126:
|
||||
return netaddr.IPNetwork('{}/{}'.format(self.prefix.network, self.prefix.prefixlen + 1))
|
||||
return None
|
||||
|
||||
|
||||
class IPAddressManager(models.Manager):
|
||||
|
||||
|
||||
@@ -48,13 +48,7 @@ PREFIX_LINK = """
|
||||
{% else %}
|
||||
<span class="text-nowrap" style="padding-left: {{ record.depth }}9px">
|
||||
{% endif %}
|
||||
<a href="{% if record.pk %}{% url 'ipam:prefix' pk=record.pk %}{% else %}{% url 'ipam:prefix_add' %}?prefix={{ record }}{% if parent.vrf %}&vrf={{ parent.vrf.pk }}{% endif %}{% if parent.site %}&site={{ parent.site.pk }}{% endif %}{% endif %}">{{ record.prefix }}</a>
|
||||
</span>
|
||||
"""
|
||||
|
||||
PREFIX_LINK_BRIEF = """
|
||||
<span style="padding-left: {{ record.depth }}0px">
|
||||
<a href="{% if record.pk %}{% url 'ipam:prefix' pk=record.pk %}{% else %}{% url 'ipam:prefix_add' %}?prefix={{ record }}{% if parent.vrf %}&vrf={{ parent.vrf.pk }}{% endif %}{% if parent.site %}&site={{ parent.site.pk }}{% endif %}{% endif %}">{{ record.prefix }}</a>
|
||||
<a href="{% if record.pk %}{% url 'ipam:prefix' pk=record.pk %}{% else %}{% url 'ipam:prefix_add' %}?prefix={{ record }}{% if parent.vrf %}&vrf={{ parent.vrf.pk }}{% endif %}{% if parent.site %}&site={{ parent.site.pk }}{% endif %}{% if parent.tenant %}&tenant_group={{ parent.tenant.group.pk }}&tenant={{ parent.tenant.pk }}{% endif %}{% endif %}">{{ record.prefix }}</a>
|
||||
</span>
|
||||
"""
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ urlpatterns = [
|
||||
url(r'^prefixes/(?P<pk>\d+)/$', views.PrefixView.as_view(), name='prefix'),
|
||||
url(r'^prefixes/(?P<pk>\d+)/edit/$', views.PrefixEditView.as_view(), name='prefix_edit'),
|
||||
url(r'^prefixes/(?P<pk>\d+)/delete/$', views.PrefixDeleteView.as_view(), name='prefix_delete'),
|
||||
url(r'^prefixes/(?P<pk>\d+)/prefixes/$', views.PrefixPrefixesView.as_view(), name='prefix_prefixes'),
|
||||
url(r'^prefixes/(?P<pk>\d+)/ip-addresses/$', views.PrefixIPAddressesView.as_view(), name='prefix_ipaddresses'),
|
||||
|
||||
# IP addresses
|
||||
|
||||
@@ -476,6 +476,20 @@ class PrefixView(View):
|
||||
duplicate_prefix_table = tables.PrefixTable(list(duplicate_prefixes), orderable=False)
|
||||
duplicate_prefix_table.exclude = ('vrf',)
|
||||
|
||||
return render(request, 'ipam/prefix.html', {
|
||||
'prefix': prefix,
|
||||
'aggregate': aggregate,
|
||||
'parent_prefix_table': parent_prefix_table,
|
||||
'duplicate_prefix_table': duplicate_prefix_table,
|
||||
})
|
||||
|
||||
|
||||
class PrefixPrefixesView(View):
|
||||
|
||||
def get(self, request, pk):
|
||||
|
||||
prefix = get_object_or_404(Prefix.objects.all(), pk=pk)
|
||||
|
||||
# Child prefixes table
|
||||
child_prefixes = Prefix.objects.filter(
|
||||
vrf=prefix.vrf, prefix__net_contained=str(prefix.prefix)
|
||||
@@ -484,15 +498,16 @@ class PrefixView(View):
|
||||
).annotate_depth(limit=0)
|
||||
if child_prefixes:
|
||||
child_prefixes = add_available_prefixes(prefix.prefix, child_prefixes)
|
||||
child_prefix_table = tables.PrefixDetailTable(child_prefixes)
|
||||
|
||||
prefix_table = tables.PrefixDetailTable(child_prefixes)
|
||||
if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'):
|
||||
child_prefix_table.columns.show('pk')
|
||||
prefix_table.columns.show('pk')
|
||||
|
||||
paginate = {
|
||||
'klass': EnhancedPaginator,
|
||||
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
|
||||
}
|
||||
RequestConfig(request, paginate).configure(child_prefix_table)
|
||||
RequestConfig(request, paginate).configure(prefix_table)
|
||||
|
||||
# Compile permissions list for rendering the object table
|
||||
permissions = {
|
||||
@@ -501,15 +516,12 @@ class PrefixView(View):
|
||||
'delete': request.user.has_perm('ipam.delete_prefix'),
|
||||
}
|
||||
|
||||
return render(request, 'ipam/prefix.html', {
|
||||
return render(request, 'ipam/prefix_prefixes.html', {
|
||||
'prefix': prefix,
|
||||
'aggregate': aggregate,
|
||||
'parent_prefix_table': parent_prefix_table,
|
||||
'child_prefix_table': child_prefix_table,
|
||||
'duplicate_prefix_table': duplicate_prefix_table,
|
||||
'bulk_querystring': 'vrf_id={}&within={}'.format(prefix.vrf or '0', prefix.prefix),
|
||||
'first_available_prefix': prefix.get_first_available_prefix(),
|
||||
'prefix_table': prefix_table,
|
||||
'permissions': permissions,
|
||||
'return_url': prefix.get_absolute_url(),
|
||||
'bulk_querystring': 'vrf_id={}&within={}'.format(prefix.vrf.pk if prefix.vrf else '0', prefix.prefix),
|
||||
})
|
||||
|
||||
|
||||
@@ -544,6 +556,7 @@ class PrefixIPAddressesView(View):
|
||||
|
||||
return render(request, 'ipam/prefix_ipaddresses.html', {
|
||||
'prefix': prefix,
|
||||
'first_available_ip': prefix.get_first_available_ip(),
|
||||
'ip_table': ip_table,
|
||||
'permissions': permissions,
|
||||
'bulk_querystring': 'vrf_id={}&parent={}'.format(prefix.vrf.pk if prefix.vrf else '0', prefix.prefix),
|
||||
|
||||
Reference in New Issue
Block a user