import django_tables2 as tables from django.utils.safestring import mark_safe from django_tables2.utils import Accessor from dcim.models import Interface from tenancy.tables import TenantColumn from utilities.tables import ( BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ContentTypeColumn, LinkedCountColumn, TagColumn, ToggleColumn, UtilizationColumn, ) from virtualization.models import VMInterface from .models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF AVAILABLE_LABEL = mark_safe('Available') PREFIX_LINK = """ {% load helpers %} {% for i in record.depth|as_range %} {% endfor %} {{ record.prefix }} """ PREFIX_ROLE_LINK = """ {% if record.role %} {{ record.role }} {% else %} — {% endif %} """ IPADDRESS_LINK = """ {% if record.pk %} {{ record.address }} {% elif perms.ipam.add_ipaddress %} {% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available {% else %} {% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available {% endif %} """ IPADDRESS_ASSIGN_LINK = """ {{ record }} """ VRF_LINK = """ {% if record.vrf %} {{ record.vrf }} {% elif object.vrf %} {{ object.vrf }} {% else %} Global {% endif %} """ VRF_TARGETS = """ {% for rt in value.all %} {{ rt }}{% if not forloop.last %}
{% endif %} {% empty %} — {% endfor %} """ VLAN_LINK = """ {% if record.pk %} {{ record.vid }} {% elif perms.ipam.add_vlan %} {{ record.available }} VLAN{{ record.available|pluralize }} available {% else %} {{ record.available }} VLAN{{ record.available|pluralize }} available {% endif %} """ VLAN_PREFIXES = """ {% for prefix in record.prefixes.all %} {{ prefix }}{% if not forloop.last %}
{% endif %} {% empty %} — {% endfor %} """ VLAN_ROLE_LINK = """ {% if record.role %} {{ record.role }} {% else %} — {% endif %} """ VLANGROUP_ADD_VLAN = """ {% with next_vid=record.get_next_available_vid %} {% if next_vid and perms.ipam.add_vlan %} {% endif %} {% endwith %} """ VLAN_MEMBER_TAGGED = """ {% if record.untagged_vlan_id == object.pk %} {% else %} {% endif %} """ # # VRFs # class VRFTable(BaseTable): pk = ToggleColumn() name = tables.Column( linkify=True ) rd = tables.Column( verbose_name='RD' ) tenant = TenantColumn() enforce_unique = BooleanColumn( verbose_name='Unique' ) import_targets = tables.TemplateColumn( template_code=VRF_TARGETS, orderable=False ) export_targets = tables.TemplateColumn( template_code=VRF_TARGETS, orderable=False ) tags = TagColumn( url_name='ipam:vrf_list' ) class Meta(BaseTable.Meta): model = VRF fields = ( 'pk', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'tags', ) default_columns = ('pk', 'name', 'rd', 'tenant', 'description') # # Route targets # class RouteTargetTable(BaseTable): pk = ToggleColumn() name = tables.Column( linkify=True ) tenant = TenantColumn() tags = TagColumn( url_name='ipam:vrf_list' ) class Meta(BaseTable.Meta): model = RouteTarget fields = ('pk', 'name', 'tenant', 'description', 'tags') default_columns = ('pk', 'name', 'tenant', 'description') # # RIRs # class RIRTable(BaseTable): pk = ToggleColumn() name = tables.Column( linkify=True ) is_private = BooleanColumn( verbose_name='Private' ) aggregate_count = LinkedCountColumn( viewname='ipam:aggregate_list', url_params={'rir_id': 'pk'}, verbose_name='Aggregates' ) actions = ButtonsColumn(RIR) class Meta(BaseTable.Meta): model = RIR fields = ('pk', 'name', 'slug', 'is_private', 'aggregate_count', 'description', 'actions') default_columns = ('pk', 'name', 'is_private', 'aggregate_count', 'description', 'actions') # # Aggregates # class AggregateTable(BaseTable): pk = ToggleColumn() prefix = tables.Column( linkify=True, verbose_name='Aggregate' ) tenant = TenantColumn() date_added = tables.DateColumn( format="Y-m-d", verbose_name='Added' ) class Meta(BaseTable.Meta): model = Aggregate fields = ('pk', 'prefix', 'rir', 'tenant', 'date_added', 'description') class AggregateDetailTable(AggregateTable): child_count = tables.Column( verbose_name='Prefixes' ) utilization = UtilizationColumn( accessor='get_utilization', orderable=False ) tags = TagColumn( url_name='ipam:aggregate_list' ) class Meta(AggregateTable.Meta): fields = ('pk', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description', 'tags') default_columns = ('pk', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description') # # Roles # class RoleTable(BaseTable): pk = ToggleColumn() name = tables.Column( linkify=True ) prefix_count = LinkedCountColumn( viewname='ipam:prefix_list', url_params={'role_id': 'pk'}, verbose_name='Prefixes' ) vlan_count = LinkedCountColumn( viewname='ipam:vlan_list', url_params={'role_id': 'pk'}, verbose_name='VLANs' ) actions = ButtonsColumn(Role) class Meta(BaseTable.Meta): model = Role fields = ('pk', 'name', 'slug', 'prefix_count', 'vlan_count', 'description', 'weight', 'actions') default_columns = ('pk', 'name', 'prefix_count', 'vlan_count', 'description', 'actions') # # Prefixes # class PrefixUtilizationColumn(UtilizationColumn): """ Extend UtilizationColumn to allow disabling the warning & danger thresholds for prefixes marked as fully utilized. """ template_code = """ {% load helpers %} {% if record.pk and record.mark_utilized %} {% utilization_graph value warning_threshold=0 danger_threshold=0 %} {% elif record.pk %} {% utilization_graph value %} {% endif %} """ class PrefixTable(BaseTable): pk = ToggleColumn() prefix = tables.TemplateColumn( template_code=PREFIX_LINK, attrs={'td': {'class': 'text-nowrap'}} ) prefix_flat = tables.Column( accessor=Accessor('prefix'), linkify=True, verbose_name='Prefix (Flat)' ) depth = tables.Column( accessor=Accessor('_depth'), verbose_name='Depth' ) children = LinkedCountColumn( accessor=Accessor('_children'), viewname='ipam:prefix_list', url_params={ 'vrf_id': 'vrf_id', 'within': 'prefix', }, verbose_name='Children' ) status = ChoiceFieldColumn( default=AVAILABLE_LABEL ) vrf = tables.TemplateColumn( template_code=VRF_LINK, verbose_name='VRF' ) tenant = TenantColumn() site = tables.Column( linkify=True ) vlan = tables.Column( linkify=True, verbose_name='VLAN' ) role = tables.TemplateColumn( template_code=PREFIX_ROLE_LINK ) is_pool = BooleanColumn( verbose_name='Pool' ) mark_utilized = BooleanColumn( verbose_name='Marked Utilized' ) class Meta(BaseTable.Meta): model = Prefix fields = ( 'pk', 'prefix', 'prefix_flat', 'status', 'depth', 'children', 'vrf', 'tenant', 'site', 'vlan', 'role', 'is_pool', 'mark_utilized', 'description', ) default_columns = ('pk', 'prefix', 'status', 'vrf', 'tenant', 'site', 'vlan', 'role', 'description') row_attrs = { 'class': lambda record: 'success' if not record.pk else '', } class PrefixDetailTable(PrefixTable): utilization = PrefixUtilizationColumn( accessor='get_utilization', orderable=False ) tags = TagColumn( url_name='ipam:prefix_list' ) class Meta(PrefixTable.Meta): fields = ( 'pk', 'prefix', 'prefix_flat', 'status', 'children', 'vrf', 'utilization', 'tenant', 'site', 'vlan', 'role', 'is_pool', 'mark_utilized', 'description', 'tags', ) default_columns = ( 'pk', 'prefix', 'status', 'children', 'vrf', 'utilization', 'tenant', 'site', 'vlan', 'role', 'description', ) # # IPAddresses # class IPAddressTable(BaseTable): pk = ToggleColumn() address = tables.TemplateColumn( template_code=IPADDRESS_LINK, verbose_name='IP Address' ) vrf = tables.TemplateColumn( template_code=VRF_LINK, verbose_name='VRF' ) status = ChoiceFieldColumn( default=AVAILABLE_LABEL ) role = ChoiceFieldColumn() tenant = TenantColumn() assigned_object = tables.Column( linkify=True, orderable=False, verbose_name='Interface' ) assigned_object_parent = tables.Column( accessor='assigned_object.parent_object', linkify=True, orderable=False, verbose_name='Device/VM' ) class Meta(BaseTable.Meta): model = IPAddress fields = ( 'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'assigned_object', 'assigned_object_parent', 'dns_name', 'description', ) row_attrs = { 'class': lambda record: 'success' if not isinstance(record, IPAddress) else '', } class IPAddressDetailTable(IPAddressTable): nat_inside = tables.Column( linkify=True, orderable=False, verbose_name='NAT (Inside)' ) tenant = TenantColumn() assigned = BooleanColumn( accessor='assigned_object_id', verbose_name='Assigned' ) tags = TagColumn( url_name='ipam:ipaddress_list' ) class Meta(IPAddressTable.Meta): fields = ( 'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'nat_inside', 'assigned', 'dns_name', 'description', 'tags', ) default_columns = ( 'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'assigned', 'dns_name', 'description', ) class IPAddressAssignTable(BaseTable): address = tables.TemplateColumn( template_code=IPADDRESS_ASSIGN_LINK, verbose_name='IP Address' ) status = ChoiceFieldColumn() assigned_object = tables.Column( orderable=False ) class Meta(BaseTable.Meta): model = IPAddress fields = ('address', 'dns_name', 'vrf', 'status', 'role', 'tenant', 'assigned_object', 'description') orderable = False class InterfaceIPAddressTable(BaseTable): """ List IP addresses assigned to a specific Interface. """ address = tables.Column( linkify=True, verbose_name='IP Address' ) vrf = tables.TemplateColumn( template_code=VRF_LINK, verbose_name='VRF' ) status = ChoiceFieldColumn() tenant = TenantColumn() actions = ButtonsColumn( model=IPAddress ) class Meta(BaseTable.Meta): model = IPAddress fields = ('address', 'vrf', 'status', 'role', 'tenant', 'description') # # VLAN groups # class VLANGroupTable(BaseTable): pk = ToggleColumn() name = tables.Column(linkify=True) scope_type = ContentTypeColumn() scope = tables.Column( linkify=True, orderable=False ) vlan_count = LinkedCountColumn( viewname='ipam:vlan_list', url_params={'group_id': 'pk'}, verbose_name='VLANs' ) actions = ButtonsColumn( model=VLANGroup, prepend_template=VLANGROUP_ADD_VLAN ) class Meta(BaseTable.Meta): model = VLANGroup fields = ('pk', 'name', 'scope_type', 'scope', 'vlan_count', 'slug', 'description', 'actions') default_columns = ('pk', 'name', 'scope_type', 'scope', 'vlan_count', 'description', 'actions') # # VLANs # class VLANTable(BaseTable): pk = ToggleColumn() vid = tables.TemplateColumn( template_code=VLAN_LINK, verbose_name='ID' ) site = tables.Column( linkify=True ) group = tables.Column( linkify=True ) tenant = TenantColumn() status = ChoiceFieldColumn( default=AVAILABLE_LABEL ) role = tables.TemplateColumn( template_code=VLAN_ROLE_LINK ) class Meta(BaseTable.Meta): model = VLAN fields = ('pk', 'vid', 'site', 'group', 'name', 'tenant', 'status', 'role', 'description') row_attrs = { 'class': lambda record: 'success' if not isinstance(record, VLAN) else '', } class VLANDetailTable(VLANTable): prefixes = tables.TemplateColumn( template_code=VLAN_PREFIXES, orderable=False, verbose_name='Prefixes' ) tenant = TenantColumn() tags = TagColumn( url_name='ipam:vlan_list' ) class Meta(VLANTable.Meta): fields = ('pk', 'vid', 'site', 'group', 'name', 'prefixes', 'tenant', 'status', 'role', 'description', 'tags') default_columns = ('pk', 'vid', 'site', 'group', 'name', 'prefixes', 'tenant', 'status', 'role', 'description') class VLANMembersTable(BaseTable): """ Base table for Interface and VMInterface assignments """ name = tables.Column( linkify=True, verbose_name='Interface' ) tagged = tables.TemplateColumn( template_code=VLAN_MEMBER_TAGGED, orderable=False ) class VLANDevicesTable(VLANMembersTable): device = tables.Column( linkify=True ) actions = ButtonsColumn(Interface, buttons=['edit']) class Meta(BaseTable.Meta): model = Interface fields = ('device', 'name', 'tagged', 'actions') class VLANVirtualMachinesTable(VLANMembersTable): virtual_machine = tables.Column( linkify=True ) actions = ButtonsColumn(VMInterface, buttons=['edit']) class Meta(BaseTable.Meta): model = VMInterface fields = ('virtual_machine', 'name', 'tagged', 'actions') class InterfaceVLANTable(BaseTable): """ List VLANs assigned to a specific Interface. """ vid = tables.Column( linkify=True, verbose_name='ID' ) tagged = BooleanColumn() site = tables.Column( linkify=True ) group = tables.Column( accessor=Accessor('group__name'), verbose_name='Group' ) tenant = TenantColumn() status = ChoiceFieldColumn() role = tables.TemplateColumn( template_code=VLAN_ROLE_LINK ) class Meta(BaseTable.Meta): model = VLAN fields = ('vid', 'tagged', 'site', 'group', 'name', 'tenant', 'status', 'role', 'description') def __init__(self, interface, *args, **kwargs): self.interface = interface super().__init__(*args, **kwargs) # # Services # class ServiceTable(BaseTable): pk = ToggleColumn() name = tables.Column( linkify=True ) parent = tables.Column( linkify=True, order_by=('device', 'virtual_machine') ) ports = tables.TemplateColumn( template_code='{{ record.port_list }}', verbose_name='Ports' ) tags = TagColumn( url_name='ipam:service_list' ) class Meta(BaseTable.Meta): model = Service fields = ('pk', 'name', 'parent', 'protocol', 'ports', 'ipaddresses', 'description', 'tags') default_columns = ('pk', 'name', 'parent', 'protocol', 'ports', 'description')