Просмотр исходного кода

Fixes #2567: Introduced proxy models to represent console/power/interface connections

Jeremy Stretch 7 лет назад
Родитель
Сommit
0dee55885b
4 измененных файлов с 170 добавлено и 42 удалено
  1. 1 0
      CHANGELOG.md
  2. 129 8
      netbox/dcim/models.py
  3. 32 27
      netbox/dcim/tables.py
  4. 8 7
      netbox/dcim/views.py

+ 1 - 0
CHANGELOG.md

@@ -40,6 +40,7 @@ NetBox now supports modeling physical cables for console, power, and interface c
 ## Bug Fixes (from v2.5-beta1)
 
 * [#2563](https://github.com/digitalocean/netbox/issues/2563) - Enable export templates for cables
+* [#2567](https://github.com/digitalocean/netbox/issues/2567) - Introduced proxy models to represent console/power/interface connections
 
 ## API Changes
 

+ 129 - 8
netbox/dcim/models.py

@@ -1698,7 +1698,7 @@ class ConsolePort(CableTermination, ComponentModel):
     objects = DeviceComponentManager()
     tags = TaggableManager()
 
-    csv_headers = ['console_server', 'connected_endpoint', 'device', 'console_port', 'connection_status']
+    csv_headers = ['device', 'name']
 
     class Meta:
         ordering = ['device', 'name']
@@ -1712,11 +1712,8 @@ class ConsolePort(CableTermination, ComponentModel):
 
     def to_csv(self):
         return (
-            self.connected_endpoint.device.identifier if self.connected_endpoint else None,
-            self.connected_endpoint.name if self.connected_endpoint else None,
             self.device.identifier,
             self.name,
-            self.get_connection_status_display(),
         )
 
 
@@ -1740,6 +1737,8 @@ class ConsoleServerPort(CableTermination, ComponentModel):
     objects = DeviceComponentManager()
     tags = TaggableManager()
 
+    csv_headers = ['device', 'name']
+
     class Meta:
         unique_together = ['device', 'name']
 
@@ -1749,6 +1748,12 @@ class ConsoleServerPort(CableTermination, ComponentModel):
     def get_absolute_url(self):
         return self.device.get_absolute_url()
 
+    def to_csv(self):
+        return (
+            self.device.identifier,
+            self.name,
+        )
+
 
 #
 # Power ports
@@ -1781,7 +1786,7 @@ class PowerPort(CableTermination, ComponentModel):
     objects = DeviceComponentManager()
     tags = TaggableManager()
 
-    csv_headers = ['pdu', 'connected_endpoint', 'device', 'power_port', 'connection_status']
+    csv_headers = ['device', 'name']
 
     class Meta:
         ordering = ['device', 'name']
@@ -1795,11 +1800,8 @@ class PowerPort(CableTermination, ComponentModel):
 
     def to_csv(self):
         return (
-            self.connected_endpoint.device.identifier if self.connected_endpoint else None,
-            self.connected_endpoint.name if self.connected_endpoint else None,
             self.device.identifier,
             self.name,
-            self.get_connection_status_display(),
         )
 
 
@@ -1823,6 +1825,8 @@ class PowerOutlet(CableTermination, ComponentModel):
     objects = DeviceComponentManager()
     tags = TaggableManager()
 
+    csv_headers = ['device', 'name']
+
     class Meta:
         unique_together = ['device', 'name']
 
@@ -1832,6 +1836,12 @@ class PowerOutlet(CableTermination, ComponentModel):
     def get_absolute_url(self):
         return self.device.get_absolute_url()
 
+    def to_csv(self):
+        return (
+            self.device.identifier,
+            self.name,
+        )
+
 
 #
 # Interfaces
@@ -1935,6 +1945,11 @@ class Interface(CableTermination, ComponentModel):
     objects = InterfaceManager()
     tags = TaggableManager()
 
+    csv_headers = [
+        'device', 'virtual_machine', 'name', 'lag', 'form_factor', 'enabled', 'mac_address', 'mtu', 'mgmt_only',
+        'description', 'mode',
+    ]
+
     class Meta:
         ordering = ['device', 'name']
         unique_together = ['device', 'name']
@@ -1945,6 +1960,21 @@ class Interface(CableTermination, ComponentModel):
     def get_absolute_url(self):
         return reverse('dcim:interface', kwargs={'pk': self.pk})
 
+    def to_csv(self):
+        return (
+            self.device.identifier if self.device else None,
+            self.virtual_machine.name if self.virtual_machine else None,
+            self.name,
+            self.lag.name if self.lag else None,
+            self.get_form_factor_display(),
+            self.enabled,
+            self.mac_address,
+            self.mtu,
+            self.mgmt_only,
+            self.description,
+            self.get_mode_display(),
+        )
+
     def clean(self):
 
         # An Interface must belong to a Device *or* to a VirtualMachine
@@ -2112,6 +2142,8 @@ class FrontPort(CableTermination, ComponentModel):
     objects = DeviceComponentManager()
     tags = TaggableManager()
 
+    csv_headers = ['device', 'name', 'type', 'rear_port', 'rear_port_position']
+
     class Meta:
         ordering = ['device', 'name']
         unique_together = [
@@ -2122,6 +2154,15 @@ class FrontPort(CableTermination, ComponentModel):
     def __str__(self):
         return self.name
 
+    def to_csv(self):
+        return (
+            self.device.identifier,
+            self.name,
+            self.get_type_display(),
+            self.rear_port.name,
+            self.rear_port_position,
+        )
+
     def clean(self):
 
         # Validate rear port assignment
@@ -2162,6 +2203,8 @@ class RearPort(CableTermination, ComponentModel):
     objects = DeviceComponentManager()
     tags = TaggableManager()
 
+    csv_headers = ['device', 'name', 'type', 'positions']
+
     class Meta:
         ordering = ['device', 'name']
         unique_together = ['device', 'name']
@@ -2169,6 +2212,14 @@ class RearPort(CableTermination, ComponentModel):
     def __str__(self):
         return self.name
 
+    def to_csv(self):
+        return (
+            self.device.identifier,
+            self.name,
+            self.get_type_display(),
+            self.positions,
+        )
+
 
 #
 # Device bays
@@ -2198,6 +2249,8 @@ class DeviceBay(ComponentModel):
     objects = DeviceComponentManager()
     tags = TaggableManager()
 
+    csv_headers = ['device', 'name', 'installed_device']
+
     class Meta:
         ordering = ['device', 'name']
         unique_together = ['device', 'name']
@@ -2208,6 +2261,13 @@ class DeviceBay(ComponentModel):
     def get_absolute_url(self):
         return self.device.get_absolute_url()
 
+    def to_csv(self):
+        return (
+            self.device.identifier,
+            self.name,
+            self.installed_device.identifier if self.installed_device else None,
+        )
+
     def clean(self):
 
         # Validate that the parent Device can have DeviceBays
@@ -2535,3 +2595,64 @@ class Cable(ChangeLoggedModel):
             return trace_cable(far_end, position)
 
         return trace_cable(self.termination_a), trace_cable(self.termination_b)
+
+
+#
+# Connection proxy models
+#
+
+class ConsoleConnection(ConsolePort):
+
+    csv_headers = [
+        'console_server', 'port', 'device', 'console_port', 'connection_status',
+    ]
+
+    class Meta:
+        proxy = True
+
+    def to_csv(self):
+        return (
+            self.connected_endpoint.device.identifier if self.connected_endpoint else None,
+            self.connected_endpoint.name if self.connected_endpoint else None,
+            self.device.identifier,
+            self.name,
+            self.get_connection_status_display(),
+        )
+
+
+class PowerConnection(PowerPort):
+
+    csv_headers = [
+        'pdu', 'outlet', 'device', 'power_port', 'connection_status',
+    ]
+
+    class Meta:
+        proxy = True
+
+    def to_csv(self):
+        return (
+            self.connected_endpoint.device.identifier if self.connected_endpoint else None,
+            self.connected_endpoint.name if self.connected_endpoint else None,
+            self.device.identifier,
+            self.name,
+            self.get_connection_status_display(),
+        )
+
+
+class InterfaceConnection(Interface):
+
+    csv_headers = [
+        'device_a', 'interface_a', 'device_b', 'interface_b', 'connection_status',
+    ]
+
+    class Meta:
+        proxy = True
+
+    def to_csv(self):
+        return (
+            self.connected_endpoint.device.identifier if self.connected_endpoint else None,
+            self.connected_endpoint.name if self.connected_endpoint else None,
+            self.device.identifier,
+            self.name,
+            self.get_connection_status_display(),
+        )

+ 32 - 27
netbox/dcim/tables.py

@@ -4,10 +4,11 @@ from django_tables2.utils import Accessor
 from tenancy.tables import COL_TENANT
 from utilities.tables import BaseTable, BooleanColumn, ColorColumn, ToggleColumn
 from .models import (
-    Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
-    DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
-    InventoryItem, Manufacturer, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack,
-    RackGroup, RackReservation, RearPort, RearPortTemplate, Region, Site, VirtualChassis,
+    Cable, ConsoleConnection, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device,
+    DeviceBay, DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceConnection,
+    InterfaceTemplate, InventoryItem, Manufacturer, Platform, PowerConnection, PowerOutlet, PowerOutletTemplate,
+    PowerPort, PowerPortTemplate, Rack, RackGroup, RackReservation, RearPort, RearPortTemplate, Region, Site,
+    VirtualChassis,
 )
 
 REGION_LINK = """
@@ -668,19 +669,22 @@ class ConsoleConnectionTable(BaseTable):
         viewname='dcim:device',
         accessor=Accessor('connected_endpoint.device'),
         args=[Accessor('connected_endpoint.device.pk')],
-        verbose_name='Console server'
+        verbose_name='Console Server'
     )
-    connected_endpoint = tables.Column(verbose_name='Port')
-    device = tables.LinkColumn('dcim:device', args=[Accessor('device.pk')], verbose_name='Device')
-    name = tables.Column(verbose_name='Console port')
-    cable = tables.LinkColumn(
-        viewname='dcim:cable',
-        args=[Accessor('cable.pk')]
+    connected_endpoint = tables.Column(
+        verbose_name='Port'
+    )
+    device = tables.LinkColumn(
+        viewname='dcim:device',
+        args=[Accessor('device.pk')]
+    )
+    name = tables.Column(
+        verbose_name='Console Port'
     )
 
     class Meta(BaseTable.Meta):
-        model = ConsolePort
-        fields = ('console_server', 'connected_endpoint', 'device', 'name', 'cable')
+        model = ConsoleConnection
+        fields = ('console_server', 'connected_endpoint', 'device', 'name', 'connection_status')
 
 
 class PowerConnectionTable(BaseTable):
@@ -690,17 +694,20 @@ class PowerConnectionTable(BaseTable):
         args=[Accessor('connected_endpoint.device.pk')],
         verbose_name='PDU'
     )
-    connected_endpoint = tables.Column(verbose_name='Outlet')
-    device = tables.LinkColumn('dcim:device', args=[Accessor('device.pk')], verbose_name='Device')
-    name = tables.Column(verbose_name='Power Port')
-    cable = tables.LinkColumn(
-        viewname='dcim:cable',
-        args=[Accessor('cable.pk')]
+    connected_endpoint = tables.Column(
+        verbose_name='Outlet'
+    )
+    device = tables.LinkColumn(
+        viewname='dcim:device',
+        args=[Accessor('device.pk')]
+    )
+    name = tables.Column(
+        verbose_name='Power Port'
     )
 
     class Meta(BaseTable.Meta):
-        model = PowerPort
-        fields = ('pdu', 'connected_endpoint', 'device', 'name', 'cable')
+        model = PowerConnection
+        fields = ('pdu', 'connected_endpoint', 'device', 'name', 'connection_status')
 
 
 class InterfaceConnectionTable(BaseTable):
@@ -736,14 +743,12 @@ class InterfaceConnectionTable(BaseTable):
         accessor=Accessor('connected_endpoint.description'),
         verbose_name='Description'
     )
-    cable = tables.LinkColumn(
-        viewname='dcim:cable',
-        args=[Accessor('cable.pk')]
-    )
 
     class Meta(BaseTable.Meta):
-        model = Interface
-        fields = ('device_a', 'interface_a', 'description_a', 'device_b', 'interface_b', 'description_b', 'cable')
+        model = InterfaceConnection
+        fields = (
+            'device_a', 'interface_a', 'description_a', 'device_b', 'interface_b', 'description_b', 'connection_status',
+        )
 
 
 #

+ 8 - 7
netbox/dcim/views.py

@@ -24,10 +24,11 @@ from utilities.views import (
 from virtualization.models import VirtualMachine
 from . import filters, forms, tables
 from .models import (
-    Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
-    DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
-    Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack,
-    RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site, VirtualChassis,
+    Cable, ConsoleConnection, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device,
+    DeviceBay, DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceConnection,
+    InterfaceTemplate, InventoryItem, Manufacturer, Platform, PowerConnection, PowerOutlet, PowerOutletTemplate,
+    PowerPort, PowerPortTemplate, Rack, RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site,
+    VirtualChassis,
 )
 
 
@@ -1686,7 +1687,7 @@ class CableBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 #
 
 class ConsoleConnectionsListView(ObjectListView):
-    queryset = ConsolePort.objects.select_related(
+    queryset = ConsoleConnection.objects.select_related(
         'device', 'connected_endpoint__device'
     ).filter(
         connected_endpoint__isnull=False
@@ -1700,7 +1701,7 @@ class ConsoleConnectionsListView(ObjectListView):
 
 
 class PowerConnectionsListView(ObjectListView):
-    queryset = PowerPort.objects.select_related(
+    queryset = PowerConnection.objects.select_related(
         'device', 'connected_endpoint__device'
     ).filter(
         connected_endpoint__isnull=False
@@ -1714,7 +1715,7 @@ class PowerConnectionsListView(ObjectListView):
 
 
 class InterfaceConnectionsListView(ObjectListView):
-    queryset = Interface.objects.select_related(
+    queryset = InterfaceConnection.objects.select_related(
         'device', 'cable', '_connected_interface__device'
     ).filter(
         # Avoid duplicate connections by only selecting the lower PK in a connected pair