netbox/netbox/ipam/views.py
2025-01-31 14:33:26 -05:00

1484 lines
48 KiB
Python

from django.contrib.contenttypes.models import ContentType
from django.db.models import Prefetch
from django.db.models.expressions import RawSQL
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from circuits.models import Provider
from dcim.filtersets import InterfaceFilterSet
from dcim.forms import InterfaceFilterForm
from dcim.models import Interface, Site
from ipam.tables import VLANTranslationRuleTable
from netbox.views import generic
from tenancy.views import ObjectContactsView
from utilities.query import count_related
from utilities.tables import get_table_ordering
from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
from virtualization.filtersets import VMInterfaceFilterSet
from virtualization.forms import VMInterfaceFilterForm
from virtualization.models import VMInterface
from . import filtersets, forms, tables
from .choices import PrefixStatusChoices
from .constants import *
from .models import *
from .utils import add_requested_prefixes, add_available_ipaddresses, add_available_vlans
#
# VRFs
#
@register_model_view(VRF, 'list', path='', detail=False)
class VRFListView(generic.ObjectListView):
queryset = VRF.objects.all()
filterset = filtersets.VRFFilterSet
filterset_form = forms.VRFFilterForm
table = tables.VRFTable
@register_model_view(VRF)
class VRFView(GetRelatedModelsMixin, generic.ObjectView):
queryset = VRF.objects.all()
def get_extra_context(self, request, instance):
import_targets_table = tables.RouteTargetTable(
instance.import_targets.all(),
orderable=False
)
export_targets_table = tables.RouteTargetTable(
instance.export_targets.all(),
orderable=False
)
return {
'related_models': self.get_related_models(request, instance, omit=[Interface, VMInterface]),
'import_targets_table': import_targets_table,
'export_targets_table': export_targets_table,
}
@register_model_view(VRF, 'add', detail=False)
@register_model_view(VRF, 'edit')
class VRFEditView(generic.ObjectEditView):
queryset = VRF.objects.all()
form = forms.VRFForm
@register_model_view(VRF, 'delete')
class VRFDeleteView(generic.ObjectDeleteView):
queryset = VRF.objects.all()
@register_model_view(VRF, 'bulk_import', detail=False)
class VRFBulkImportView(generic.BulkImportView):
queryset = VRF.objects.all()
model_form = forms.VRFImportForm
@register_model_view(VRF, 'bulk_edit', path='edit', detail=False)
class VRFBulkEditView(generic.BulkEditView):
queryset = VRF.objects.all()
filterset = filtersets.VRFFilterSet
table = tables.VRFTable
form = forms.VRFBulkEditForm
@register_model_view(VRF, 'bulk_delete', path='delete', detail=False)
class VRFBulkDeleteView(generic.BulkDeleteView):
queryset = VRF.objects.all()
filterset = filtersets.VRFFilterSet
table = tables.VRFTable
#
# Route targets
#
@register_model_view(RouteTarget, 'list', path='', detail=False)
class RouteTargetListView(generic.ObjectListView):
queryset = RouteTarget.objects.all()
filterset = filtersets.RouteTargetFilterSet
filterset_form = forms.RouteTargetFilterForm
table = tables.RouteTargetTable
@register_model_view(RouteTarget)
class RouteTargetView(generic.ObjectView):
queryset = RouteTarget.objects.all()
@register_model_view(RouteTarget, 'add', detail=False)
@register_model_view(RouteTarget, 'edit')
class RouteTargetEditView(generic.ObjectEditView):
queryset = RouteTarget.objects.all()
form = forms.RouteTargetForm
@register_model_view(RouteTarget, 'delete')
class RouteTargetDeleteView(generic.ObjectDeleteView):
queryset = RouteTarget.objects.all()
@register_model_view(RouteTarget, 'bulk_import', detail=False)
class RouteTargetBulkImportView(generic.BulkImportView):
queryset = RouteTarget.objects.all()
model_form = forms.RouteTargetImportForm
@register_model_view(RouteTarget, 'bulk_edit', path='edit', detail=False)
class RouteTargetBulkEditView(generic.BulkEditView):
queryset = RouteTarget.objects.all()
filterset = filtersets.RouteTargetFilterSet
table = tables.RouteTargetTable
form = forms.RouteTargetBulkEditForm
@register_model_view(RouteTarget, 'bulk_delete', path='delete', detail=False)
class RouteTargetBulkDeleteView(generic.BulkDeleteView):
queryset = RouteTarget.objects.all()
filterset = filtersets.RouteTargetFilterSet
table = tables.RouteTargetTable
#
# RIRs
#
@register_model_view(RIR, 'list', path='', detail=False)
class RIRListView(generic.ObjectListView):
queryset = RIR.objects.annotate(
aggregate_count=count_related(Aggregate, 'rir')
)
filterset = filtersets.RIRFilterSet
filterset_form = forms.RIRFilterForm
table = tables.RIRTable
@register_model_view(RIR)
class RIRView(GetRelatedModelsMixin, generic.ObjectView):
queryset = RIR.objects.all()
def get_extra_context(self, request, instance):
return {
'related_models': self.get_related_models(request, instance),
}
@register_model_view(RIR, 'add', detail=False)
@register_model_view(RIR, 'edit')
class RIREditView(generic.ObjectEditView):
queryset = RIR.objects.all()
form = forms.RIRForm
@register_model_view(RIR, 'delete')
class RIRDeleteView(generic.ObjectDeleteView):
queryset = RIR.objects.all()
@register_model_view(RIR, 'bulk_import', detail=False)
class RIRBulkImportView(generic.BulkImportView):
queryset = RIR.objects.all()
model_form = forms.RIRImportForm
@register_model_view(RIR, 'bulk_edit', path='edit', detail=False)
class RIRBulkEditView(generic.BulkEditView):
queryset = RIR.objects.annotate(
aggregate_count=count_related(Aggregate, 'rir')
)
filterset = filtersets.RIRFilterSet
table = tables.RIRTable
form = forms.RIRBulkEditForm
@register_model_view(RIR, 'bulk_delete', path='delete', detail=False)
class RIRBulkDeleteView(generic.BulkDeleteView):
queryset = RIR.objects.annotate(
aggregate_count=count_related(Aggregate, 'rir')
)
filterset = filtersets.RIRFilterSet
table = tables.RIRTable
#
# ASN ranges
#
@register_model_view(ASNRange, 'list', path='', detail=False)
class ASNRangeListView(generic.ObjectListView):
queryset = ASNRange.objects.annotate_asn_counts()
filterset = filtersets.ASNRangeFilterSet
filterset_form = forms.ASNRangeFilterForm
table = tables.ASNRangeTable
@register_model_view(ASNRange)
class ASNRangeView(generic.ObjectView):
queryset = ASNRange.objects.all()
@register_model_view(ASNRange, 'asns')
class ASNRangeASNsView(generic.ObjectChildrenView):
queryset = ASNRange.objects.all()
child_model = ASN
table = tables.ASNTable
filterset = filtersets.ASNFilterSet
filterset_form = forms.ASNFilterForm
tab = ViewTab(
label=_('ASNs'),
badge=lambda x: x.get_child_asns().count(),
permission='ipam.view_asn',
weight=500
)
def get_children(self, request, parent):
return parent.get_child_asns().restrict(request.user, 'view').annotate(
site_count=count_related(Site, 'asns'),
provider_count=count_related(Provider, 'asns')
)
@register_model_view(ASNRange, 'add', detail=False)
@register_model_view(ASNRange, 'edit')
class ASNRangeEditView(generic.ObjectEditView):
queryset = ASNRange.objects.all()
form = forms.ASNRangeForm
@register_model_view(ASNRange, 'delete')
class ASNRangeDeleteView(generic.ObjectDeleteView):
queryset = ASNRange.objects.all()
@register_model_view(ASNRange, 'bulk_import', detail=False)
class ASNRangeBulkImportView(generic.BulkImportView):
queryset = ASNRange.objects.all()
model_form = forms.ASNRangeImportForm
@register_model_view(ASNRange, 'bulk_edit', path='edit', detail=False)
class ASNRangeBulkEditView(generic.BulkEditView):
queryset = ASNRange.objects.annotate_asn_counts()
filterset = filtersets.ASNRangeFilterSet
table = tables.ASNRangeTable
form = forms.ASNRangeBulkEditForm
@register_model_view(ASNRange, 'bulk_delete', path='delete', detail=False)
class ASNRangeBulkDeleteView(generic.BulkDeleteView):
queryset = ASNRange.objects.annotate_asn_counts()
filterset = filtersets.ASNRangeFilterSet
table = tables.ASNRangeTable
#
# ASNs
#
@register_model_view(ASN, 'list', path='', detail=False)
class ASNListView(generic.ObjectListView):
queryset = ASN.objects.annotate(
site_count=count_related(Site, 'asns'),
provider_count=count_related(Provider, 'asns')
)
filterset = filtersets.ASNFilterSet
filterset_form = forms.ASNFilterForm
table = tables.ASNTable
@register_model_view(ASN)
class ASNView(GetRelatedModelsMixin, generic.ObjectView):
queryset = ASN.objects.all()
def get_extra_context(self, request, instance):
return {
'related_models': self.get_related_models(
request,
instance,
extra=(
(Site.objects.restrict(request.user, 'view').filter(asns__in=[instance]), 'asn_id'),
(Provider.objects.restrict(request.user, 'view').filter(asns__in=[instance]), 'asn_id'),
),
),
}
@register_model_view(ASN, 'add', detail=False)
@register_model_view(ASN, 'edit')
class ASNEditView(generic.ObjectEditView):
queryset = ASN.objects.all()
form = forms.ASNForm
@register_model_view(ASN, 'delete')
class ASNDeleteView(generic.ObjectDeleteView):
queryset = ASN.objects.all()
@register_model_view(ASN, 'bulk_import', detail=False)
class ASNBulkImportView(generic.BulkImportView):
queryset = ASN.objects.all()
model_form = forms.ASNImportForm
@register_model_view(ASN, 'bulk_edit', path='edit', detail=False)
class ASNBulkEditView(generic.BulkEditView):
queryset = ASN.objects.annotate(
site_count=count_related(Site, 'asns')
)
filterset = filtersets.ASNFilterSet
table = tables.ASNTable
form = forms.ASNBulkEditForm
@register_model_view(ASN, 'bulk_delete', path='delete', detail=False)
class ASNBulkDeleteView(generic.BulkDeleteView):
queryset = ASN.objects.annotate(
site_count=count_related(Site, 'asns')
)
filterset = filtersets.ASNFilterSet
table = tables.ASNTable
#
# Aggregates
#
@register_model_view(Aggregate, 'list', path='', detail=False)
class AggregateListView(generic.ObjectListView):
queryset = Aggregate.objects.annotate(
child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
)
filterset = filtersets.AggregateFilterSet
filterset_form = forms.AggregateFilterForm
table = tables.AggregateTable
@register_model_view(Aggregate)
class AggregateView(generic.ObjectView):
queryset = Aggregate.objects.all()
@register_model_view(Aggregate, 'prefixes')
class AggregatePrefixesView(generic.ObjectChildrenView):
queryset = Aggregate.objects.all()
child_model = Prefix
table = tables.PrefixTable
filterset = filtersets.PrefixFilterSet
filterset_form = forms.PrefixFilterForm
template_name = 'ipam/aggregate/prefixes.html'
tab = ViewTab(
label=_('Prefixes'),
badge=lambda x: x.get_child_prefixes().count(),
permission='ipam.view_prefix',
weight=500
)
def get_children(self, request, parent):
return Prefix.objects.restrict(request.user, 'view').filter(
prefix__net_contained_or_equal=str(parent.prefix)
).prefetch_related('scope', 'role', 'tenant', 'tenant__group', 'vlan')
def prep_table_data(self, request, queryset, parent):
# Determine whether to show assigned prefixes, available prefixes, or both
show_available = bool(request.GET.get('show_available', 'true') == 'true')
show_assigned = bool(request.GET.get('show_assigned', 'true') == 'true')
return add_requested_prefixes(parent.prefix, queryset, show_available, show_assigned)
def get_extra_context(self, request, instance):
return {
'bulk_querystring': f'within={instance.prefix}',
'first_available_prefix': instance.get_first_available_prefix(),
'show_available': bool(request.GET.get('show_available', 'true') == 'true'),
'show_assigned': bool(request.GET.get('show_assigned', 'true') == 'true'),
}
@register_model_view(Aggregate, 'add', detail=False)
@register_model_view(Aggregate, 'edit')
class AggregateEditView(generic.ObjectEditView):
queryset = Aggregate.objects.all()
form = forms.AggregateForm
@register_model_view(Aggregate, 'delete')
class AggregateDeleteView(generic.ObjectDeleteView):
queryset = Aggregate.objects.all()
@register_model_view(Aggregate, 'bulk_import', detail=False)
class AggregateBulkImportView(generic.BulkImportView):
queryset = Aggregate.objects.all()
model_form = forms.AggregateImportForm
@register_model_view(Aggregate, 'bulk_edit', path='edit', detail=False)
class AggregateBulkEditView(generic.BulkEditView):
queryset = Aggregate.objects.annotate(
child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
)
filterset = filtersets.AggregateFilterSet
table = tables.AggregateTable
form = forms.AggregateBulkEditForm
@register_model_view(Aggregate, 'bulk_delete', path='delete', detail=False)
class AggregateBulkDeleteView(generic.BulkDeleteView):
queryset = Aggregate.objects.annotate(
child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
)
filterset = filtersets.AggregateFilterSet
table = tables.AggregateTable
@register_model_view(Aggregate, 'contacts')
class AggregateContactsView(ObjectContactsView):
queryset = Aggregate.objects.all()
#
# Prefix/VLAN roles
#
@register_model_view(Role, 'list', path='', detail=False)
class RoleListView(generic.ObjectListView):
queryset = Role.objects.annotate(
prefix_count=count_related(Prefix, 'role'),
iprange_count=count_related(IPRange, 'role'),
vlan_count=count_related(VLAN, 'role')
)
filterset = filtersets.RoleFilterSet
filterset_form = forms.RoleFilterForm
table = tables.RoleTable
@register_model_view(Role)
class RoleView(GetRelatedModelsMixin, generic.ObjectView):
queryset = Role.objects.all()
def get_extra_context(self, request, instance):
return {
'related_models': self.get_related_models(request, instance),
}
@register_model_view(Role, 'add', detail=False)
@register_model_view(Role, 'edit')
class RoleEditView(generic.ObjectEditView):
queryset = Role.objects.all()
form = forms.RoleForm
@register_model_view(Role, 'delete')
class RoleDeleteView(generic.ObjectDeleteView):
queryset = Role.objects.all()
@register_model_view(Role, 'bulk_import', detail=False)
class RoleBulkImportView(generic.BulkImportView):
queryset = Role.objects.all()
model_form = forms.RoleImportForm
@register_model_view(Role, 'bulk_edit', path='edit', detail=False)
class RoleBulkEditView(generic.BulkEditView):
queryset = Role.objects.all()
filterset = filtersets.RoleFilterSet
table = tables.RoleTable
form = forms.RoleBulkEditForm
@register_model_view(Role, 'bulk_delete', path='delete', detail=False)
class RoleBulkDeleteView(generic.BulkDeleteView):
queryset = Role.objects.all()
filterset = filtersets.RoleFilterSet
table = tables.RoleTable
#
# Prefixes
#
@register_model_view(Prefix, 'list', path='', detail=False)
class PrefixListView(generic.ObjectListView):
queryset = Prefix.objects.all()
filterset = filtersets.PrefixFilterSet
filterset_form = forms.PrefixFilterForm
table = tables.PrefixTable
template_name = 'ipam/prefix_list.html'
@register_model_view(Prefix)
class PrefixView(generic.ObjectView):
queryset = Prefix.objects.all()
def get_extra_context(self, request, instance):
try:
aggregate = Aggregate.objects.restrict(request.user, 'view').get(
prefix__net_contains_or_equals=str(instance.prefix)
)
except Aggregate.DoesNotExist:
aggregate = None
# Parent prefixes table
parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
Q(vrf=instance.vrf) | Q(vrf__isnull=True, status=PrefixStatusChoices.STATUS_CONTAINER)
).filter(
prefix__net_contains=str(instance.prefix)
).prefetch_related(
'scope', 'role', 'tenant', 'vlan',
)
parent_prefix_table = tables.PrefixTable(
list(parent_prefixes),
exclude=('vrf', 'utilization'),
orderable=False
)
# Duplicate prefixes table
duplicate_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
vrf=instance.vrf, prefix=str(instance.prefix)
).exclude(
pk=instance.pk
).prefetch_related(
'scope', 'role', 'tenant', 'vlan',
)
duplicate_prefix_table = tables.PrefixTable(
list(duplicate_prefixes),
exclude=('vrf', 'utilization'),
orderable=False
)
return {
'aggregate': aggregate,
'parent_prefix_table': parent_prefix_table,
'duplicate_prefix_table': duplicate_prefix_table,
}
@register_model_view(Prefix, 'prefixes')
class PrefixPrefixesView(generic.ObjectChildrenView):
queryset = Prefix.objects.all()
child_model = Prefix
table = tables.PrefixTable
filterset = filtersets.PrefixFilterSet
filterset_form = forms.PrefixFilterForm
template_name = 'ipam/prefix/prefixes.html'
tab = ViewTab(
label=_('Child Prefixes'),
badge=lambda x: x.get_child_prefixes().count(),
permission='ipam.view_prefix',
weight=500
)
def get_children(self, request, parent):
return parent.get_child_prefixes().restrict(request.user, 'view').prefetch_related(
'scope', 'vrf', 'vlan', 'role', 'tenant', 'tenant__group'
)
def prep_table_data(self, request, queryset, parent):
# Determine whether to show assigned prefixes, available prefixes, or both
show_available = bool(request.GET.get('show_available', 'true') == 'true')
show_assigned = bool(request.GET.get('show_assigned', 'true') == 'true')
return add_requested_prefixes(parent.prefix, queryset, show_available, show_assigned)
def get_extra_context(self, request, instance):
return {
'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&within={instance.prefix}",
'first_available_prefix': instance.get_first_available_prefix(),
'show_available': bool(request.GET.get('show_available', 'true') == 'true'),
'show_assigned': bool(request.GET.get('show_assigned', 'true') == 'true'),
}
@register_model_view(Prefix, 'ipranges', path='ip-ranges')
class PrefixIPRangesView(generic.ObjectChildrenView):
queryset = Prefix.objects.all()
child_model = IPRange
table = tables.IPRangeTable
filterset = filtersets.IPRangeFilterSet
filterset_form = forms.IPRangeFilterForm
template_name = 'ipam/prefix/ip_ranges.html'
tab = ViewTab(
label=_('Child Ranges'),
badge=lambda x: x.get_child_ranges().count(),
permission='ipam.view_iprange',
weight=600
)
def get_children(self, request, parent):
return parent.get_child_ranges().restrict(request.user, 'view').prefetch_related(
'tenant__group',
)
def get_extra_context(self, request, instance):
return {
'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&parent={instance.prefix}",
'first_available_ip': instance.get_first_available_ip(),
}
@register_model_view(Prefix, 'ipaddresses', path='ip-addresses')
class PrefixIPAddressesView(generic.ObjectChildrenView):
queryset = Prefix.objects.all()
child_model = IPAddress
table = tables.IPAddressTable
filterset = filtersets.IPAddressFilterSet
filterset_form = forms.IPAddressFilterForm
template_name = 'ipam/prefix/ip_addresses.html'
tab = ViewTab(
label=_('IP Addresses'),
badge=lambda x: x.get_child_ips().count(),
permission='ipam.view_ipaddress',
weight=700
)
def get_children(self, request, parent):
return parent.get_child_ips().restrict(request.user, 'view').prefetch_related('vrf', 'tenant', 'tenant__group')
def prep_table_data(self, request, queryset, parent):
if not request.GET.get('q') and not get_table_ordering(request, self.table):
return add_available_ipaddresses(parent.prefix, queryset, parent.is_pool)
return queryset
def get_extra_context(self, request, instance):
return {
'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&parent={instance.prefix}",
'first_available_ip': instance.get_first_available_ip(),
}
@register_model_view(Prefix, 'add', detail=False)
@register_model_view(Prefix, 'edit')
class PrefixEditView(generic.ObjectEditView):
queryset = Prefix.objects.all()
form = forms.PrefixForm
@register_model_view(Prefix, 'delete')
class PrefixDeleteView(generic.ObjectDeleteView):
queryset = Prefix.objects.all()
@register_model_view(Prefix, 'bulk_import', detail=False)
class PrefixBulkImportView(generic.BulkImportView):
queryset = Prefix.objects.all()
model_form = forms.PrefixImportForm
@register_model_view(Prefix, 'bulk_edit', path='edit', detail=False)
class PrefixBulkEditView(generic.BulkEditView):
queryset = Prefix.objects.prefetch_related('vrf__tenant')
filterset = filtersets.PrefixFilterSet
table = tables.PrefixTable
form = forms.PrefixBulkEditForm
@register_model_view(Prefix, 'bulk_delete', path='delete', detail=False)
class PrefixBulkDeleteView(generic.BulkDeleteView):
queryset = Prefix.objects.prefetch_related('vrf__tenant')
filterset = filtersets.PrefixFilterSet
table = tables.PrefixTable
@register_model_view(Prefix, 'contacts')
class PrefixContactsView(ObjectContactsView):
queryset = Prefix.objects.all()
#
# IP Ranges
#
@register_model_view(IPRange, 'list', path='', detail=False)
class IPRangeListView(generic.ObjectListView):
queryset = IPRange.objects.all()
filterset = filtersets.IPRangeFilterSet
filterset_form = forms.IPRangeFilterForm
table = tables.IPRangeTable
@register_model_view(IPRange)
class IPRangeView(generic.ObjectView):
queryset = IPRange.objects.all()
def get_extra_context(self, request, instance):
# Parent prefixes table
parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
Q(prefix__net_contains_or_equals=str(instance.start_address.ip)),
Q(prefix__net_contains_or_equals=str(instance.end_address.ip)),
vrf=instance.vrf
).prefetch_related(
'scope', 'role', 'tenant', 'vlan', 'role'
)
parent_prefixes_table = tables.PrefixTable(
list(parent_prefixes),
exclude=('vrf', 'utilization'),
orderable=False
)
return {
'parent_prefixes_table': parent_prefixes_table,
}
@register_model_view(IPRange, 'ipaddresses', path='ip-addresses')
class IPRangeIPAddressesView(generic.ObjectChildrenView):
queryset = IPRange.objects.all()
child_model = IPAddress
table = tables.IPAddressTable
filterset = filtersets.IPAddressFilterSet
filterset_form = forms.IPRangeFilterForm
template_name = 'ipam/iprange/ip_addresses.html'
tab = ViewTab(
label=_('IP Addresses'),
badge=lambda x: x.get_child_ips().count(),
permission='ipam.view_ipaddress',
weight=500
)
def get_children(self, request, parent):
return parent.get_child_ips().restrict(request.user, 'view')
@register_model_view(IPRange, 'add', detail=False)
@register_model_view(IPRange, 'edit')
class IPRangeEditView(generic.ObjectEditView):
queryset = IPRange.objects.all()
form = forms.IPRangeForm
@register_model_view(IPRange, 'delete')
class IPRangeDeleteView(generic.ObjectDeleteView):
queryset = IPRange.objects.all()
@register_model_view(IPRange, 'bulk_import', detail=False)
class IPRangeBulkImportView(generic.BulkImportView):
queryset = IPRange.objects.all()
model_form = forms.IPRangeImportForm
@register_model_view(IPRange, 'bulk_edit', path='edit', detail=False)
class IPRangeBulkEditView(generic.BulkEditView):
queryset = IPRange.objects.all()
filterset = filtersets.IPRangeFilterSet
table = tables.IPRangeTable
form = forms.IPRangeBulkEditForm
@register_model_view(IPRange, 'bulk_delete', path='delete', detail=False)
class IPRangeBulkDeleteView(generic.BulkDeleteView):
queryset = IPRange.objects.all()
filterset = filtersets.IPRangeFilterSet
table = tables.IPRangeTable
@register_model_view(IPRange, 'contacts')
class IPRangeContactsView(ObjectContactsView):
queryset = IPRange.objects.all()
#
# IP addresses
#
@register_model_view(IPAddress, 'list', path='', detail=False)
class IPAddressListView(generic.ObjectListView):
queryset = IPAddress.objects.all()
filterset = filtersets.IPAddressFilterSet
filterset_form = forms.IPAddressFilterForm
table = tables.IPAddressTable
@register_model_view(IPAddress)
class IPAddressView(generic.ObjectView):
queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
def get_extra_context(self, request, instance):
# Parent prefixes table
parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
vrf=instance.vrf,
prefix__net_contains_or_equals=str(instance.address.ip)
).prefetch_related(
'scope', 'role'
)
parent_prefixes_table = tables.PrefixTable(
list(parent_prefixes),
exclude=('vrf', 'utilization'),
orderable=False
)
# Duplicate IPs table
duplicate_ips = IPAddress.objects.restrict(request.user, 'view').filter(
vrf=instance.vrf,
address=str(instance.address)
).exclude(
pk=instance.pk
).prefetch_related(
'nat_inside'
)
# Exclude anycast IPs if this IP is anycast
if instance.role == IPAddressRoleChoices.ROLE_ANYCAST:
duplicate_ips = duplicate_ips.exclude(role=IPAddressRoleChoices.ROLE_ANYCAST)
# Limit to a maximum of 10 duplicates displayed here
duplicate_ips_table = tables.IPAddressTable(duplicate_ips[:10], orderable=False)
return {
'parent_prefixes_table': parent_prefixes_table,
'duplicate_ips_table': duplicate_ips_table,
}
@register_model_view(IPAddress, 'add', detail=False)
@register_model_view(IPAddress, 'edit')
class IPAddressEditView(generic.ObjectEditView):
queryset = IPAddress.objects.all()
form = forms.IPAddressForm
template_name = 'ipam/ipaddress_edit.html'
def alter_object(self, obj, request, url_args, url_kwargs):
if 'interface' in request.GET:
try:
obj.assigned_object = Interface.objects.get(pk=request.GET['interface'])
except (ValueError, Interface.DoesNotExist):
pass
elif 'vminterface' in request.GET:
try:
obj.assigned_object = VMInterface.objects.get(pk=request.GET['vminterface'])
except (ValueError, VMInterface.DoesNotExist):
pass
elif 'fhrpgroup' in request.GET:
try:
obj.assigned_object = FHRPGroup.objects.get(pk=request.GET['fhrpgroup'])
except (ValueError, FHRPGroup.DoesNotExist):
pass
return obj
def get_extra_addanother_params(self, request):
if 'interface' in request.GET:
return {'interface': request.GET['interface']}
elif 'vminterface' in request.GET:
return {'vminterface': request.GET['vminterface']}
# TODO: Standardize or remove this view
@register_model_view(IPAddress, 'assign', path='assign', detail=False)
class IPAddressAssignView(generic.ObjectView):
"""
Search for IPAddresses to be assigned to an Interface.
"""
queryset = IPAddress.objects.all()
def dispatch(self, request, *args, **kwargs):
# Redirect user if an interface has not been provided
if 'interface' not in request.GET and 'vminterface' not in request.GET:
return redirect('ipam:ipaddress_add')
return super().dispatch(request, *args, **kwargs)
def get(self, request):
form = forms.IPAddressAssignForm()
return render(request, 'ipam/ipaddress_assign.html', {
'form': form,
'return_url': request.GET.get('return_url', ''),
})
def post(self, request):
form = forms.IPAddressAssignForm(request.POST)
table = None
if form.is_valid():
addresses = self.queryset.prefetch_related('vrf', 'tenant')
# Limit to 100 results
addresses = filtersets.IPAddressFilterSet(request.POST, addresses).qs[:100]
table = tables.IPAddressAssignTable(addresses)
return render(request, 'ipam/ipaddress_assign.html', {
'form': form,
'table': table,
'return_url': request.GET.get('return_url'),
})
@register_model_view(IPAddress, 'delete')
class IPAddressDeleteView(generic.ObjectDeleteView):
queryset = IPAddress.objects.all()
@register_model_view(IPAddress, 'bulk_add', path='bulk-add', detail=False)
class IPAddressBulkCreateView(generic.BulkCreateView):
queryset = IPAddress.objects.all()
form = forms.IPAddressBulkCreateForm
model_form = forms.IPAddressBulkAddForm
pattern_target = 'address'
template_name = 'ipam/ipaddress_bulk_add.html'
@register_model_view(IPAddress, 'bulk_import', detail=False)
class IPAddressBulkImportView(generic.BulkImportView):
queryset = IPAddress.objects.all()
model_form = forms.IPAddressImportForm
@register_model_view(IPAddress, 'bulk_edit', path='edit', detail=False)
class IPAddressBulkEditView(generic.BulkEditView):
queryset = IPAddress.objects.prefetch_related('vrf__tenant')
filterset = filtersets.IPAddressFilterSet
table = tables.IPAddressTable
form = forms.IPAddressBulkEditForm
@register_model_view(IPAddress, 'bulk_delete', path='delete', detail=False)
class IPAddressBulkDeleteView(generic.BulkDeleteView):
queryset = IPAddress.objects.prefetch_related('vrf__tenant')
filterset = filtersets.IPAddressFilterSet
table = tables.IPAddressTable
@register_model_view(IPAddress, 'related_ips', path='related-ip-addresses')
class IPAddressRelatedIPsView(generic.ObjectChildrenView):
queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
child_model = IPAddress
table = tables.IPAddressTable
filterset = filtersets.IPAddressFilterSet
filterset_form = forms.IPAddressFilterForm
tab = ViewTab(
label=_('Related IPs'),
badge=lambda x: x.get_related_ips().count(),
weight=500,
hide_if_empty=True,
)
def get_children(self, request, parent):
return parent.get_related_ips().restrict(request.user, 'view')
@register_model_view(IPAddress, 'contacts')
class IPAddressContactsView(ObjectContactsView):
queryset = IPAddress.objects.all()
#
# VLAN groups
#
@register_model_view(VLANGroup, 'list', path='', detail=False)
class VLANGroupListView(generic.ObjectListView):
queryset = VLANGroup.objects.annotate_utilization()
filterset = filtersets.VLANGroupFilterSet
filterset_form = forms.VLANGroupFilterForm
table = tables.VLANGroupTable
@register_model_view(VLANGroup)
class VLANGroupView(GetRelatedModelsMixin, generic.ObjectView):
queryset = VLANGroup.objects.annotate_utilization()
def get_extra_context(self, request, instance):
return {
'related_models': self.get_related_models(request, instance),
}
@register_model_view(VLANGroup, 'add', detail=False)
@register_model_view(VLANGroup, 'edit')
class VLANGroupEditView(generic.ObjectEditView):
queryset = VLANGroup.objects.all()
form = forms.VLANGroupForm
@register_model_view(VLANGroup, 'delete')
class VLANGroupDeleteView(generic.ObjectDeleteView):
queryset = VLANGroup.objects.all()
@register_model_view(VLANGroup, 'bulk_import', detail=False)
class VLANGroupBulkImportView(generic.BulkImportView):
queryset = VLANGroup.objects.all()
model_form = forms.VLANGroupImportForm
@register_model_view(VLANGroup, 'bulk_edit', path='edit', detail=False)
class VLANGroupBulkEditView(generic.BulkEditView):
queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
filterset = filtersets.VLANGroupFilterSet
table = tables.VLANGroupTable
form = forms.VLANGroupBulkEditForm
@register_model_view(VLANGroup, 'bulk_delete', path='delete', detail=False)
class VLANGroupBulkDeleteView(generic.BulkDeleteView):
queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
filterset = filtersets.VLANGroupFilterSet
table = tables.VLANGroupTable
@register_model_view(VLANGroup, 'vlans')
class VLANGroupVLANsView(generic.ObjectChildrenView):
queryset = VLANGroup.objects.all()
child_model = VLAN
table = tables.VLANTable
filterset = filtersets.VLANFilterSet
filterset_form = forms.VLANFilterForm
tab = ViewTab(
label=_('VLANs'),
badge=lambda x: x.get_child_vlans().count(),
permission='ipam.view_vlan',
weight=500
)
def get_children(self, request, parent):
return parent.get_child_vlans().restrict(request.user, 'view').prefetch_related(
Prefetch('prefixes', queryset=Prefix.objects.restrict(request.user)),
'tenant', 'site', 'role',
)
def prep_table_data(self, request, queryset, parent):
if not get_table_ordering(request, self.table):
return add_available_vlans(queryset, parent)
return queryset
#
# VLAN Translation Policies
#
@register_model_view(VLANTranslationPolicy, 'list', path='', detail=False)
class VLANTranslationPolicyListView(generic.ObjectListView):
queryset = VLANTranslationPolicy.objects.annotate(
rule_count=count_related(VLANTranslationRule, 'policy'),
)
filterset = filtersets.VLANTranslationPolicyFilterSet
filterset_form = forms.VLANTranslationPolicyFilterForm
table = tables.VLANTranslationPolicyTable
@register_model_view(VLANTranslationPolicy)
class VLANTranslationPolicyView(GetRelatedModelsMixin, generic.ObjectView):
queryset = VLANTranslationPolicy.objects.all()
def get_extra_context(self, request, instance):
vlan_translation_table = VLANTranslationRuleTable(
data=instance.rules.all(),
orderable=False
)
return {
'vlan_translation_table': vlan_translation_table,
}
@register_model_view(VLANTranslationPolicy, 'add', detail=False)
@register_model_view(VLANTranslationPolicy, 'edit')
class VLANTranslationPolicyEditView(generic.ObjectEditView):
queryset = VLANTranslationPolicy.objects.all()
form = forms.VLANTranslationPolicyForm
@register_model_view(VLANTranslationPolicy, 'delete')
class VLANTranslationPolicyDeleteView(generic.ObjectDeleteView):
queryset = VLANTranslationPolicy.objects.all()
@register_model_view(VLANTranslationPolicy, 'bulk_import', detail=False)
class VLANTranslationPolicyBulkImportView(generic.BulkImportView):
queryset = VLANTranslationPolicy.objects.all()
model_form = forms.VLANTranslationPolicyImportForm
@register_model_view(VLANTranslationPolicy, 'bulk_edit', path='edit', detail=False)
class VLANTranslationPolicyBulkEditView(generic.BulkEditView):
queryset = VLANTranslationPolicy.objects.all()
filterset = filtersets.VLANTranslationPolicyFilterSet
table = tables.VLANTranslationPolicyTable
form = forms.VLANTranslationPolicyBulkEditForm
@register_model_view(VLANTranslationPolicy, 'bulk_delete', path='delete', detail=False)
class VLANTranslationPolicyBulkDeleteView(generic.BulkDeleteView):
queryset = VLANTranslationPolicy.objects.all()
filterset = filtersets.VLANTranslationPolicyFilterSet
table = tables.VLANTranslationPolicyTable
#
# VLAN Translation Rules
#
@register_model_view(VLANTranslationRule, 'list', path='', detail=False)
class VLANTranslationRuleListView(generic.ObjectListView):
queryset = VLANTranslationRule.objects.all()
filterset = filtersets.VLANTranslationRuleFilterSet
filterset_form = forms.VLANTranslationRuleFilterForm
table = tables.VLANTranslationRuleTable
@register_model_view(VLANTranslationRule)
class VLANTranslationRuleView(GetRelatedModelsMixin, generic.ObjectView):
queryset = VLANTranslationRule.objects.all()
def get_extra_context(self, request, instance):
return {
'related_models': self.get_related_models(request, instance),
}
@register_model_view(VLANTranslationRule, 'add', detail=False)
@register_model_view(VLANTranslationRule, 'edit')
class VLANTranslationRuleEditView(generic.ObjectEditView):
queryset = VLANTranslationRule.objects.all()
form = forms.VLANTranslationRuleForm
@register_model_view(VLANTranslationRule, 'delete')
class VLANTranslationRuleDeleteView(generic.ObjectDeleteView):
queryset = VLANTranslationRule.objects.all()
@register_model_view(VLANTranslationRule, 'bulk_import', detail=False)
class VLANTranslationRuleBulkImportView(generic.BulkImportView):
queryset = VLANTranslationRule.objects.all()
model_form = forms.VLANTranslationRuleImportForm
@register_model_view(VLANTranslationRule, 'bulk_edit', path='edit', detail=False)
class VLANTranslationRuleBulkEditView(generic.BulkEditView):
queryset = VLANTranslationRule.objects.all()
filterset = filtersets.VLANTranslationRuleFilterSet
table = tables.VLANTranslationRuleTable
form = forms.VLANTranslationRuleBulkEditForm
@register_model_view(VLANTranslationRule, 'bulk_delete', path='delete', detail=False)
class VLANTranslationRuleBulkDeleteView(generic.BulkDeleteView):
queryset = VLANTranslationRule.objects.all()
filterset = filtersets.VLANTranslationRuleFilterSet
table = tables.VLANTranslationRuleTable
#
# FHRP groups
#
@register_model_view(FHRPGroup, 'list', path='', detail=False)
class FHRPGroupListView(generic.ObjectListView):
queryset = FHRPGroup.objects.annotate(
member_count=count_related(FHRPGroupAssignment, 'group')
)
filterset = filtersets.FHRPGroupFilterSet
filterset_form = forms.FHRPGroupFilterForm
table = tables.FHRPGroupTable
@register_model_view(FHRPGroup)
class FHRPGroupView(generic.ObjectView):
queryset = FHRPGroup.objects.all()
def get_extra_context(self, request, instance):
# Get assigned interfaces
members_table = tables.FHRPGroupAssignmentTable(
data=FHRPGroupAssignment.objects.restrict(request.user, 'view').filter(group=instance),
orderable=False
)
members_table.columns.hide('group')
return {
'members_table': members_table,
'member_count': FHRPGroupAssignment.objects.filter(group=instance).count(),
}
@register_model_view(FHRPGroup, 'add', detail=False)
@register_model_view(FHRPGroup, 'edit')
class FHRPGroupEditView(generic.ObjectEditView):
queryset = FHRPGroup.objects.all()
form = forms.FHRPGroupForm
def get_return_url(self, request, obj=None):
return_url = super().get_return_url(request, obj)
# If we're redirecting the user to the FHRPGroupAssignment creation form,
# initialize the group field with the FHRPGroup we just saved.
if return_url.startswith(reverse('ipam:fhrpgroupassignment_add')):
return_url += f'&group={obj.pk}'
return return_url
def alter_object(self, obj, request, url_args, url_kwargs):
# Workaround to solve #10719. Capture the current user on the FHRPGroup instance so that
# we can evaluate permissions during the creation of a new IPAddress within the form.
obj._user = request.user
return obj
@register_model_view(FHRPGroup, 'delete')
class FHRPGroupDeleteView(generic.ObjectDeleteView):
queryset = FHRPGroup.objects.all()
@register_model_view(FHRPGroup, 'bulk_import', detail=False)
class FHRPGroupBulkImportView(generic.BulkImportView):
queryset = FHRPGroup.objects.all()
model_form = forms.FHRPGroupImportForm
@register_model_view(FHRPGroup, 'bulk_edit', path='edit', detail=False)
class FHRPGroupBulkEditView(generic.BulkEditView):
queryset = FHRPGroup.objects.all()
filterset = filtersets.FHRPGroupFilterSet
table = tables.FHRPGroupTable
form = forms.FHRPGroupBulkEditForm
@register_model_view(FHRPGroup, 'bulk_delete', path='delete', detail=False)
class FHRPGroupBulkDeleteView(generic.BulkDeleteView):
queryset = FHRPGroup.objects.all()
filterset = filtersets.FHRPGroupFilterSet
table = tables.FHRPGroupTable
#
# FHRP group assignments
#
@register_model_view(FHRPGroupAssignment, 'add', detail=False)
@register_model_view(FHRPGroupAssignment, 'edit')
class FHRPGroupAssignmentEditView(generic.ObjectEditView):
queryset = FHRPGroupAssignment.objects.all()
form = forms.FHRPGroupAssignmentForm
def alter_object(self, instance, request, args, kwargs):
if not instance.pk:
# Assign the interface based on URL kwargs
content_type = get_object_or_404(ContentType, pk=request.GET.get('interface_type'))
instance.interface = get_object_or_404(content_type.model_class(), pk=request.GET.get('interface_id'))
return instance
def get_extra_addanother_params(self, request):
return {
'interface_type': request.GET.get('interface_type'),
'interface_id': request.GET.get('interface_id'),
}
@register_model_view(FHRPGroupAssignment, 'delete')
class FHRPGroupAssignmentDeleteView(generic.ObjectDeleteView):
queryset = FHRPGroupAssignment.objects.all()
#
# VLANs
#
@register_model_view(VLAN, 'list', path='', detail=False)
class VLANListView(generic.ObjectListView):
queryset = VLAN.objects.all()
filterset = filtersets.VLANFilterSet
filterset_form = forms.VLANFilterForm
table = tables.VLANTable
@register_model_view(VLAN)
class VLANView(generic.ObjectView):
queryset = VLAN.objects.all()
def get_extra_context(self, request, instance):
prefixes = Prefix.objects.restrict(request.user, 'view').filter(vlan=instance).prefetch_related(
'vrf', 'scope', 'role', 'tenant'
)
prefix_table = tables.PrefixTable(list(prefixes), exclude=('vlan', 'utilization'), orderable=False)
return {
'prefix_table': prefix_table,
}
@register_model_view(VLAN, 'interfaces')
class VLANInterfacesView(generic.ObjectChildrenView):
queryset = VLAN.objects.all()
child_model = Interface
table = tables.VLANDevicesTable
filterset = InterfaceFilterSet
filterset_form = InterfaceFilterForm
tab = ViewTab(
label=_('Device Interfaces'),
badge=lambda x: x.get_interfaces().count(),
permission='dcim.view_interface',
weight=500
)
def get_children(self, request, parent):
return parent.get_interfaces().restrict(request.user, 'view')
@register_model_view(VLAN, 'vminterfaces', path='vm-interfaces')
class VLANVMInterfacesView(generic.ObjectChildrenView):
queryset = VLAN.objects.all()
child_model = VMInterface
table = tables.VLANVirtualMachinesTable
filterset = VMInterfaceFilterSet
filterset_form = VMInterfaceFilterForm
tab = ViewTab(
label=_('VM Interfaces'),
badge=lambda x: x.get_vminterfaces().count(),
permission='virtualization.view_vminterface',
weight=510
)
def get_children(self, request, parent):
return parent.get_vminterfaces().restrict(request.user, 'view')
@register_model_view(VLAN, 'add', detail=False)
@register_model_view(VLAN, 'edit')
class VLANEditView(generic.ObjectEditView):
queryset = VLAN.objects.all()
form = forms.VLANForm
template_name = 'ipam/vlan_edit.html'
@register_model_view(VLAN, 'delete')
class VLANDeleteView(generic.ObjectDeleteView):
queryset = VLAN.objects.all()
@register_model_view(VLAN, 'bulk_import', detail=False)
class VLANBulkImportView(generic.BulkImportView):
queryset = VLAN.objects.all()
model_form = forms.VLANImportForm
@register_model_view(VLAN, 'bulk_edit', path='edit', detail=False)
class VLANBulkEditView(generic.BulkEditView):
queryset = VLAN.objects.all()
filterset = filtersets.VLANFilterSet
table = tables.VLANTable
form = forms.VLANBulkEditForm
@register_model_view(VLAN, 'bulk_delete', path='delete', detail=False)
class VLANBulkDeleteView(generic.BulkDeleteView):
queryset = VLAN.objects.all()
filterset = filtersets.VLANFilterSet
table = tables.VLANTable
#
# Service templates
#
@register_model_view(ServiceTemplate, 'list', path='', detail=False)
class ServiceTemplateListView(generic.ObjectListView):
queryset = ServiceTemplate.objects.all()
filterset = filtersets.ServiceTemplateFilterSet
filterset_form = forms.ServiceTemplateFilterForm
table = tables.ServiceTemplateTable
@register_model_view(ServiceTemplate)
class ServiceTemplateView(generic.ObjectView):
queryset = ServiceTemplate.objects.all()
@register_model_view(ServiceTemplate, 'add', detail=False)
@register_model_view(ServiceTemplate, 'edit')
class ServiceTemplateEditView(generic.ObjectEditView):
queryset = ServiceTemplate.objects.all()
form = forms.ServiceTemplateForm
@register_model_view(ServiceTemplate, 'delete')
class ServiceTemplateDeleteView(generic.ObjectDeleteView):
queryset = ServiceTemplate.objects.all()
@register_model_view(ServiceTemplate, 'bulk_import', detail=False)
class ServiceTemplateBulkImportView(generic.BulkImportView):
queryset = ServiceTemplate.objects.all()
model_form = forms.ServiceTemplateImportForm
@register_model_view(ServiceTemplate, 'bulk_edit', path='edit', detail=False)
class ServiceTemplateBulkEditView(generic.BulkEditView):
queryset = ServiceTemplate.objects.all()
filterset = filtersets.ServiceTemplateFilterSet
table = tables.ServiceTemplateTable
form = forms.ServiceTemplateBulkEditForm
@register_model_view(ServiceTemplate, 'bulk_delete', path='delete', detail=False)
class ServiceTemplateBulkDeleteView(generic.BulkDeleteView):
queryset = ServiceTemplate.objects.all()
filterset = filtersets.ServiceTemplateFilterSet
table = tables.ServiceTemplateTable
#
# Services
#
@register_model_view(Service, 'list', path='', detail=False)
class ServiceListView(generic.ObjectListView):
queryset = Service.objects.prefetch_related('device', 'virtual_machine')
filterset = filtersets.ServiceFilterSet
filterset_form = forms.ServiceFilterForm
table = tables.ServiceTable
@register_model_view(Service)
class ServiceView(generic.ObjectView):
queryset = Service.objects.all()
@register_model_view(Service, 'add', detail=False)
class ServiceCreateView(generic.ObjectEditView):
queryset = Service.objects.all()
form = forms.ServiceCreateForm
@register_model_view(Service, 'edit')
class ServiceEditView(generic.ObjectEditView):
queryset = Service.objects.all()
form = forms.ServiceForm
@register_model_view(Service, 'delete')
class ServiceDeleteView(generic.ObjectDeleteView):
queryset = Service.objects.all()
@register_model_view(Service, 'bulk_import', detail=False)
class ServiceBulkImportView(generic.BulkImportView):
queryset = Service.objects.all()
model_form = forms.ServiceImportForm
@register_model_view(Service, 'bulk_edit', path='edit', detail=False)
class ServiceBulkEditView(generic.BulkEditView):
queryset = Service.objects.prefetch_related('device', 'virtual_machine')
filterset = filtersets.ServiceFilterSet
table = tables.ServiceTable
form = forms.ServiceBulkEditForm
@register_model_view(Service, 'bulk_delete', path='delete', detail=False)
class ServiceBulkDeleteView(generic.BulkDeleteView):
queryset = Service.objects.prefetch_related('device', 'virtual_machine')
filterset = filtersets.ServiceFilterSet
table = tables.ServiceTable
@register_model_view(Service, 'contacts')
class ServiceContactsView(ObjectContactsView):
queryset = Service.objects.all()