mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-25 06:37:46 -06:00
Initial push to public repo
This commit is contained in:
0
netbox/dcim/api/__init__.py
Normal file
0
netbox/dcim/api/__init__.py
Normal file
6
netbox/dcim/api/exceptions.py
Normal file
6
netbox/dcim/api/exceptions.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from rest_framework.exceptions import APIException
|
||||
|
||||
|
||||
class MissingFilterException(APIException):
|
||||
status_code = 400
|
||||
default_detail = "One or more required filters is missing from the request."
|
||||
300
netbox/dcim/api/serializers.py
Normal file
300
netbox/dcim/api/serializers.py
Normal file
@@ -0,0 +1,300 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from ipam.models import IPAddress
|
||||
from dcim.models import Site, Rack, RackGroup, Manufacturer, DeviceType, DeviceRole, Platform, Device, ConsolePort,\
|
||||
ConsoleServerPort, PowerPort, PowerOutlet, Interface, InterfaceConnection, RACK_FACE_FRONT, RACK_FACE_REAR
|
||||
|
||||
|
||||
#
|
||||
# Sites
|
||||
#
|
||||
|
||||
class SiteSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Site
|
||||
fields = ['id', 'name', 'slug', 'facility', 'asn', 'physical_address', 'shipping_address', 'comments',
|
||||
'count_prefixes', 'count_vlans', 'count_racks', 'count_devices', 'count_circuits']
|
||||
|
||||
|
||||
class SiteNestedSerializer(SiteSerializer):
|
||||
|
||||
class Meta(SiteSerializer.Meta):
|
||||
fields = ['id', 'name', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Rack groups
|
||||
#
|
||||
|
||||
class RackGroupSerializer(serializers.ModelSerializer):
|
||||
site = SiteNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = RackGroup
|
||||
fields = ['id', 'name', 'slug', 'site']
|
||||
|
||||
|
||||
class RackGroupNestedSerializer(SiteSerializer):
|
||||
|
||||
class Meta(SiteSerializer.Meta):
|
||||
fields = ['id', 'name', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Racks
|
||||
#
|
||||
|
||||
|
||||
class RackSerializer(serializers.ModelSerializer):
|
||||
display_name = serializers.SerializerMethodField()
|
||||
site = SiteNestedSerializer()
|
||||
group = RackGroupNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Rack
|
||||
fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'u_height', 'comments']
|
||||
|
||||
def get_display_name(self, obj):
|
||||
return str(obj)
|
||||
|
||||
|
||||
class RackNestedSerializer(RackSerializer):
|
||||
|
||||
class Meta(RackSerializer.Meta):
|
||||
fields = ['id', 'name', 'facility_id', 'display_name']
|
||||
|
||||
|
||||
class RackDetailSerializer(RackSerializer):
|
||||
front_units = serializers.SerializerMethodField()
|
||||
rear_units = serializers.SerializerMethodField()
|
||||
|
||||
class Meta(RackSerializer.Meta):
|
||||
fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'u_height', 'comments', 'front_units',
|
||||
'rear_units']
|
||||
|
||||
def get_front_units(self, obj):
|
||||
units = obj.get_rack_units(face=RACK_FACE_FRONT)
|
||||
for u in units:
|
||||
u['device'] = DeviceNestedSerializer(u['device']).data if u['device'] else None
|
||||
return units
|
||||
|
||||
def get_rear_units(self, obj):
|
||||
units = obj.get_rack_units(face=RACK_FACE_REAR)
|
||||
for u in units:
|
||||
u['device'] = DeviceNestedSerializer(u['device']).data if u['device'] else None
|
||||
return units
|
||||
|
||||
|
||||
#
|
||||
# Manufacturers
|
||||
#
|
||||
|
||||
class ManufacturerSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Manufacturer
|
||||
fields = ['id', 'name', 'slug']
|
||||
|
||||
|
||||
class ManufacturerNestedSerializer(ManufacturerSerializer):
|
||||
|
||||
class Meta(ManufacturerSerializer.Meta):
|
||||
pass
|
||||
|
||||
|
||||
#
|
||||
# Device types
|
||||
#
|
||||
|
||||
class DeviceTypeSerializer(serializers.ModelSerializer):
|
||||
manufacturer = ManufacturerNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = DeviceType
|
||||
fields = ['id', 'manufacturer', 'model', 'slug', 'u_height', 'is_console_server', 'is_pdu', 'is_network_device']
|
||||
|
||||
|
||||
class DeviceTypeNestedSerializer(DeviceTypeSerializer):
|
||||
|
||||
class Meta(DeviceTypeSerializer.Meta):
|
||||
fields = ['id', 'manufacturer', 'model', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Device roles
|
||||
#
|
||||
|
||||
class DeviceRoleSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = DeviceRole
|
||||
fields = ['id', 'name', 'slug', 'color']
|
||||
|
||||
|
||||
class DeviceRoleNestedSerializer(DeviceRoleSerializer):
|
||||
|
||||
class Meta(DeviceRoleSerializer.Meta):
|
||||
fields = ['id', 'name', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Platforms
|
||||
#
|
||||
|
||||
class PlatformSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Platform
|
||||
fields = ['id', 'name', 'slug', 'rpc_client']
|
||||
|
||||
|
||||
class PlatformNestedSerializer(PlatformSerializer):
|
||||
|
||||
class Meta(PlatformSerializer.Meta):
|
||||
fields = ['id', 'name', 'slug']
|
||||
|
||||
|
||||
#
|
||||
# Devices
|
||||
#
|
||||
|
||||
# Cannot import ipam.api.IPAddressNestedSerializer due to circular dependency
|
||||
class DeviceIPAddressNestedSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = IPAddress
|
||||
fields = ['id', 'family', 'address']
|
||||
|
||||
|
||||
class DeviceSerializer(serializers.ModelSerializer):
|
||||
device_type = DeviceTypeNestedSerializer()
|
||||
device_role = DeviceRoleNestedSerializer()
|
||||
platform = PlatformNestedSerializer()
|
||||
rack = RackNestedSerializer()
|
||||
primary_ip = DeviceIPAddressNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Device
|
||||
fields = ['id', 'name', 'display_name', 'device_type', 'device_role', 'platform', 'serial', 'rack', 'position',
|
||||
'face', 'status', 'primary_ip', 'ro_snmp', 'comments']
|
||||
|
||||
|
||||
class DeviceNestedSerializer(DeviceSerializer):
|
||||
|
||||
class Meta(DeviceSerializer.Meta):
|
||||
model = Device
|
||||
fields = ['id', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Console server ports
|
||||
#
|
||||
|
||||
class ConsoleServerPortSerializer(serializers.ModelSerializer):
|
||||
device = DeviceNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = ConsoleServerPort
|
||||
fields = ['id', 'device', 'name', 'connected_console']
|
||||
|
||||
|
||||
class ConsoleServerPortNestedSerializer(ConsoleServerPortSerializer):
|
||||
|
||||
class Meta(ConsoleServerPortSerializer.Meta):
|
||||
fields = ['id', 'device', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Console ports
|
||||
#
|
||||
|
||||
class ConsolePortSerializer(serializers.ModelSerializer):
|
||||
device = DeviceNestedSerializer()
|
||||
cs_port = ConsoleServerPortNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = ConsolePort
|
||||
fields = ['id', 'device', 'name', 'cs_port', 'connection_status']
|
||||
|
||||
|
||||
class ConsolePortNestedSerializer(ConsolePortSerializer):
|
||||
|
||||
class Meta(ConsolePortSerializer.Meta):
|
||||
fields = ['id', 'device', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Power outlets
|
||||
#
|
||||
|
||||
class PowerOutletSerializer(serializers.ModelSerializer):
|
||||
device = DeviceNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = PowerOutlet
|
||||
fields = ['id', 'device', 'name', 'connected_port']
|
||||
|
||||
|
||||
class PowerOutletNestedSerializer(PowerOutletSerializer):
|
||||
|
||||
class Meta(PowerOutletSerializer.Meta):
|
||||
fields = ['id', 'device', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Power ports
|
||||
#
|
||||
|
||||
class PowerPortSerializer(serializers.ModelSerializer):
|
||||
device = DeviceNestedSerializer()
|
||||
power_outlet = PowerOutletNestedSerializer()
|
||||
|
||||
class Meta:
|
||||
model = PowerPort
|
||||
fields = ['id', 'device', 'name', 'power_outlet', 'connection_status']
|
||||
|
||||
|
||||
class PowerPortNestedSerializer(PowerPortSerializer):
|
||||
|
||||
class Meta(PowerPortSerializer.Meta):
|
||||
fields = ['id', 'device', 'name']
|
||||
|
||||
|
||||
#
|
||||
# Interfaces
|
||||
#
|
||||
|
||||
class InterfaceSerializer(serializers.ModelSerializer):
|
||||
device = DeviceNestedSerializer()
|
||||
form_factor = serializers.ReadOnlyField(source='get_form_factor_display')
|
||||
|
||||
class Meta:
|
||||
model = Interface
|
||||
fields = ['id', 'device', 'name', 'form_factor', 'mgmt_only', 'description', 'is_connected']
|
||||
|
||||
|
||||
class InterfaceNestedSerializer(InterfaceSerializer):
|
||||
form_factor = serializers.ReadOnlyField(source='get_form_factor_display')
|
||||
|
||||
class Meta(InterfaceSerializer.Meta):
|
||||
fields = ['id', 'device', 'name']
|
||||
|
||||
|
||||
class InterfaceDetailSerializer(InterfaceSerializer):
|
||||
connected_interface = InterfaceSerializer(source='get_connected_interface')
|
||||
|
||||
class Meta(InterfaceSerializer.Meta):
|
||||
fields = ['id', 'device', 'name', 'form_factor', 'mgmt_only', 'description', 'is_connected',
|
||||
'connected_interface']
|
||||
|
||||
|
||||
#
|
||||
# Interface connections
|
||||
#
|
||||
|
||||
class InterfaceConnectionSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = InterfaceConnection
|
||||
fields = ['id', 'interface_a', 'interface_b', 'connection_status']
|
||||
581
netbox/dcim/api/tests.py
Normal file
581
netbox/dcim/api/tests.py
Normal file
@@ -0,0 +1,581 @@
|
||||
import json
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
|
||||
class SiteTest(APITestCase):
|
||||
|
||||
fixtures = [
|
||||
'dcim',
|
||||
'ipam',
|
||||
'extras',
|
||||
]
|
||||
|
||||
standard_fields = [
|
||||
'id',
|
||||
'name',
|
||||
'slug',
|
||||
'facility',
|
||||
'asn',
|
||||
'physical_address',
|
||||
'shipping_address',
|
||||
'comments',
|
||||
'count_prefixes',
|
||||
'count_vlans',
|
||||
'count_racks',
|
||||
'count_devices',
|
||||
'count_circuits'
|
||||
]
|
||||
|
||||
nested_fields = [
|
||||
'id',
|
||||
'name',
|
||||
'slug'
|
||||
]
|
||||
|
||||
rack_fields = [
|
||||
'id',
|
||||
'name',
|
||||
'facility_id',
|
||||
'display_name',
|
||||
'site',
|
||||
'group',
|
||||
'u_height',
|
||||
'comments'
|
||||
]
|
||||
|
||||
graph_fields = [
|
||||
'name',
|
||||
'embed_url',
|
||||
'link',
|
||||
]
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/sites/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in content:
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
|
||||
def test_get_detail(self, endpoint='/api/dcim/sites/1/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
sorted(content.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
|
||||
def test_get_site_list_rack(self, endpoint='/api/dcim/sites/1/racks/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in json.loads(response.content):
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(self.rack_fields),
|
||||
)
|
||||
# Check Nested Serializer.
|
||||
self.assertEqual(
|
||||
sorted(i.get('site').keys()),
|
||||
sorted(self.nested_fields),
|
||||
)
|
||||
|
||||
def test_get_site_list_graphs(self, endpoint='/api/dcim/sites/1/graphs/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in json.loads(response.content):
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(self.graph_fields),
|
||||
)
|
||||
|
||||
|
||||
class RackTest(APITestCase):
|
||||
fixtures = [
|
||||
'dcim',
|
||||
'ipam'
|
||||
]
|
||||
|
||||
nested_fields = [
|
||||
'id',
|
||||
'name',
|
||||
'facility_id',
|
||||
'display_name'
|
||||
]
|
||||
|
||||
standard_fields = [
|
||||
'id',
|
||||
'name',
|
||||
'facility_id',
|
||||
'display_name',
|
||||
'site',
|
||||
'group',
|
||||
'u_height',
|
||||
'comments'
|
||||
]
|
||||
|
||||
detail_fields = [
|
||||
'id',
|
||||
'name',
|
||||
'facility_id',
|
||||
'display_name',
|
||||
'site',
|
||||
'group',
|
||||
'u_height',
|
||||
'comments',
|
||||
'front_units',
|
||||
'rear_units'
|
||||
]
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/racks/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in content:
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(i.get('site').keys()),
|
||||
sorted(SiteTest.nested_fields),
|
||||
)
|
||||
|
||||
def test_get_detail(self, endpoint='/api/dcim/racks/1/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
sorted(content.keys()),
|
||||
sorted(self.detail_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(content.get('site').keys()),
|
||||
sorted(SiteTest.nested_fields),
|
||||
)
|
||||
|
||||
|
||||
class ManufacturersTest(APITestCase):
|
||||
|
||||
fixtures = [
|
||||
'dcim',
|
||||
'ipam'
|
||||
]
|
||||
|
||||
standard_fields = [
|
||||
'id',
|
||||
'name',
|
||||
'slug',
|
||||
]
|
||||
|
||||
nested_fields = standard_fields
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/manufacturers/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in content:
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
|
||||
def test_get_detail(self, endpoint='/api/dcim/manufacturers/1/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
sorted(content.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
|
||||
|
||||
class DeviceTypeTest(APITestCase):
|
||||
|
||||
fixtures = ['dcim', 'ipam']
|
||||
|
||||
standard_fields = [
|
||||
'id',
|
||||
'manufacturer',
|
||||
'model',
|
||||
'slug',
|
||||
'u_height',
|
||||
'is_console_server',
|
||||
'is_pdu',
|
||||
'is_network_device'
|
||||
]
|
||||
|
||||
nested_fields = [
|
||||
'id',
|
||||
'manufacturer',
|
||||
'model',
|
||||
'slug'
|
||||
]
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/device-types/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in content:
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
|
||||
def test_detail_list(self, endpoint='/api/dcim/device-types/1/'):
|
||||
# TODO: details returns list view.
|
||||
# response = self.client.get(endpoint)
|
||||
# content = json.loads(response.content)
|
||||
# self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
# self.assertEqual(
|
||||
# sorted(content.keys()),
|
||||
# sorted(self.standard_fields),
|
||||
# )
|
||||
# self.assertEqual(
|
||||
# sorted(content.get('manufacturer').keys()),
|
||||
# sorted(ManufacturersTest.nested_fields),
|
||||
# )
|
||||
pass
|
||||
|
||||
|
||||
class DeviceRolesTest(APITestCase):
|
||||
|
||||
fixtures = ['dcim', 'ipam']
|
||||
|
||||
standard_fields = ['id', 'name', 'slug', 'color']
|
||||
|
||||
nested_fields = ['id', 'name', 'slug']
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/device-roles/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in content:
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
|
||||
def test_get_detail(self, endpoint='/api/dcim/device-roles/1/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
sorted(content.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
|
||||
|
||||
class PlatformsTest(APITestCase):
|
||||
|
||||
fixtures = ['dcim', 'ipam']
|
||||
|
||||
standard_fields = ['id', 'name', 'slug', 'rpc_client']
|
||||
|
||||
nested_fields = ['id', 'name', 'slug']
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/platforms/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in content:
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
|
||||
def test_get_detail(self, endpoint='/api/dcim/platforms/1/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
sorted(content.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
|
||||
|
||||
class DeviceTest(APITestCase):
|
||||
|
||||
fixtures = ['dcim', 'ipam']
|
||||
|
||||
standard_fields = [
|
||||
'id',
|
||||
'name',
|
||||
'display_name',
|
||||
'device_type',
|
||||
'device_role',
|
||||
'platform',
|
||||
'serial',
|
||||
'rack',
|
||||
'position',
|
||||
'face',
|
||||
'status',
|
||||
'primary_ip',
|
||||
'ro_snmp',
|
||||
'comments',
|
||||
]
|
||||
|
||||
nested_fields = ['id', 'name']
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/devices/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for device in content:
|
||||
self.assertEqual(
|
||||
sorted(device.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(device.get('device_type')),
|
||||
sorted(DeviceTypeTest.nested_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(device.get('device_role')),
|
||||
sorted(DeviceRolesTest.nested_fields),
|
||||
)
|
||||
if device.get('platform'):
|
||||
self.assertEqual(
|
||||
sorted(device.get('platform')),
|
||||
sorted(PlatformsTest.nested_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(device.get('rack')),
|
||||
sorted(RackTest.nested_fields),
|
||||
)
|
||||
|
||||
def test_get_detail(self, endpoint='/api/dcim/devices/1/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
sorted(content.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
|
||||
|
||||
class ConsoleServerPortsTest(APITestCase):
|
||||
|
||||
fixtures = ['dcim', 'ipam']
|
||||
|
||||
standard_fields = ['id', 'device', 'name', 'connected_console']
|
||||
|
||||
nested_fields = ['id', 'device', 'name']
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/devices/9/console-server-ports/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for console_port in content:
|
||||
self.assertEqual(
|
||||
sorted(console_port.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(console_port.get('device')),
|
||||
sorted(DeviceTest.nested_fields),
|
||||
)
|
||||
|
||||
|
||||
class ConsolePortsTest(APITestCase):
|
||||
fixtures = ['dcim', 'ipam']
|
||||
|
||||
standard_fields = ['id', 'device', 'name', 'cs_port', 'connection_status']
|
||||
|
||||
nested_fields = ['id', 'device', 'name']
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/devices/1/console-ports/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for console_port in content:
|
||||
self.assertEqual(
|
||||
sorted(console_port.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(console_port.get('device')),
|
||||
sorted(DeviceTest.nested_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(console_port.get('cs_port')),
|
||||
sorted(ConsoleServerPortsTest.nested_fields),
|
||||
)
|
||||
|
||||
def test_get_detail(self, endpoint='/api/dcim/console-ports/1/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
sorted(content.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(content.get('device')),
|
||||
sorted(DeviceTest.nested_fields),
|
||||
)
|
||||
|
||||
|
||||
class PowerPortsTest(APITestCase):
|
||||
fixtures = ['dcim', 'ipam']
|
||||
|
||||
standard_fields = ['id', 'device', 'name', 'power_outlet', 'connection_status']
|
||||
|
||||
nested_fields = ['id', 'device', 'name']
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/devices/1/power-ports/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in content:
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(i.get('device')),
|
||||
sorted(DeviceTest.nested_fields),
|
||||
)
|
||||
|
||||
def test_get_detail(self, endpoint='/api/dcim/power-ports/1/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
sorted(content.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(content.get('device')),
|
||||
sorted(DeviceTest.nested_fields),
|
||||
)
|
||||
|
||||
|
||||
class PowerOutletsTest(APITestCase):
|
||||
fixtures = ['dcim', 'ipam']
|
||||
|
||||
standard_fields = ['id', 'device', 'name', 'connected_port']
|
||||
|
||||
nested_fields = ['id', 'device', 'name']
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/devices/11/power-outlets/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in content:
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(i.get('device')),
|
||||
sorted(DeviceTest.nested_fields),
|
||||
)
|
||||
|
||||
|
||||
class InterfaceTest(APITestCase):
|
||||
fixtures = ['dcim', 'ipam', 'extras']
|
||||
|
||||
standard_fields = [
|
||||
'id',
|
||||
'device',
|
||||
'name',
|
||||
'form_factor',
|
||||
'mgmt_only',
|
||||
'description',
|
||||
'is_connected'
|
||||
]
|
||||
|
||||
nested_fields = ['id', 'device', 'name']
|
||||
|
||||
detail_fields = [
|
||||
'id',
|
||||
'device',
|
||||
'name',
|
||||
'form_factor',
|
||||
'mgmt_only',
|
||||
'description',
|
||||
'is_connected',
|
||||
'connected_interface'
|
||||
]
|
||||
|
||||
connection_fields = [
|
||||
'id',
|
||||
'interface_a',
|
||||
'interface_b',
|
||||
'connection_status',
|
||||
]
|
||||
|
||||
def test_get_list(self, endpoint='/api/dcim/devices/1/interfaces/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in content:
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(i.get('device')),
|
||||
sorted(DeviceTest.nested_fields),
|
||||
)
|
||||
|
||||
def test_get_detail(self, endpoint='/api/dcim/interfaces/1/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
sorted(content.keys()),
|
||||
sorted(self.detail_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted(content.get('device')),
|
||||
sorted(DeviceTest.nested_fields),
|
||||
)
|
||||
|
||||
def test_get_graph_list(self, endpoint='/api/dcim/interfaces/1/graphs/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
for i in content:
|
||||
self.assertEqual(
|
||||
sorted(i.keys()),
|
||||
sorted(SiteTest.graph_fields),
|
||||
)
|
||||
|
||||
def test_get_interface_connections(self, endpoint='/api/dcim/interface-connections/4/'):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
sorted(content.keys()),
|
||||
sorted(self.connection_fields),
|
||||
)
|
||||
|
||||
|
||||
class RelatedConnectionsTest(APITestCase):
|
||||
|
||||
fixtures = ['dcim', 'ipam']
|
||||
|
||||
standard_fields = [
|
||||
'device',
|
||||
'console-ports',
|
||||
'power-ports',
|
||||
'interfaces',
|
||||
]
|
||||
|
||||
def test_get_list(self, endpoint=(
|
||||
'/api/dcim/related-connections/'
|
||||
'?peer-device=test1-edge1&peer-interface=xe-0/0/3')):
|
||||
response = self.client.get(endpoint)
|
||||
content = json.loads(response.content)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(
|
||||
sorted(content.keys()),
|
||||
sorted(self.standard_fields),
|
||||
)
|
||||
66
netbox/dcim/api/urls.py
Normal file
66
netbox/dcim/api/urls.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from django.conf.urls import url
|
||||
|
||||
from extras.models import GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
|
||||
from extras.api.views import GraphListView
|
||||
|
||||
from .views import *
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
# Sites
|
||||
url(r'^sites/$', SiteListView.as_view(), name='site_list'),
|
||||
url(r'^sites/(?P<pk>\d+)/$', SiteDetailView.as_view(), name='site_detail'),
|
||||
url(r'^sites/(?P<pk>\d+)/graphs/$', GraphListView.as_view(), {'type': GRAPH_TYPE_SITE}, name='site_graphs'),
|
||||
url(r'^sites/(?P<site>\d+)/racks/$', RackListView.as_view(), name='site_racks'),
|
||||
|
||||
# Rack groups
|
||||
url(r'^rack-groups/$', RackGroupListView.as_view(), name='rackgroup_list'),
|
||||
url(r'^rack-groups/(?P<pk>\d+)/$', RackGroupDetailView.as_view(), name='rackgroup_detail'),
|
||||
|
||||
# Racks
|
||||
url(r'^racks/$', RackListView.as_view(), name='rack_list'),
|
||||
url(r'^racks/(?P<pk>\d+)/$', RackDetailView.as_view(), name='rack_detail'),
|
||||
url(r'^racks/(?P<pk>\d+)/rack-units/$', RackUnitListView.as_view(), name='rack_units'),
|
||||
|
||||
# Manufacturers
|
||||
url(r'^manufacturers/$', ManufacturerListView.as_view(), name='manufacturer_list'),
|
||||
url(r'^manufacturers/(?P<pk>\d+)/$', ManufacturerDetailView.as_view(), name='manufacturer_detail'),
|
||||
|
||||
# Device types
|
||||
url(r'^device-types/$', DeviceTypeListView.as_view(), name='devicetype_list'),
|
||||
url(r'^device-types/(?P<pk>\d+)/$', DeviceTypeDetailView.as_view(), name='devicetype_detail'),
|
||||
|
||||
# Device roles
|
||||
url(r'^device-roles/$', DeviceRoleListView.as_view(), name='devicerole_list'),
|
||||
url(r'^device-roles/(?P<pk>\d+)/$', DeviceRoleDetailView.as_view(), name='devicerole_detail'),
|
||||
|
||||
# Platforms
|
||||
url(r'^platforms/$', PlatformListView.as_view(), name='platform_list'),
|
||||
url(r'^platforms/(?P<pk>\d+)/$', PlatformDetailView.as_view(), name='platform_detail'),
|
||||
|
||||
# Devices
|
||||
url(r'^devices/$', DeviceListView.as_view(), name='device_list'),
|
||||
url(r'^devices/(?P<pk>\d+)/$', DeviceDetailView.as_view(), name='device_detail'),
|
||||
url(r'^devices/(?P<pk>\d+)/lldp-neighbors/$', LLDPNeighborsView.as_view(), name='device_lldp-neighbors'),
|
||||
url(r'^devices/(?P<pk>\d+)/console-ports/$', ConsolePortListView.as_view(), name='device_consoleports'),
|
||||
url(r'^devices/(?P<pk>\d+)/console-server-ports/$', ConsoleServerPortListView.as_view(), name='device_consoleserverports'),
|
||||
url(r'^devices/(?P<pk>\d+)/power-ports/$', PowerPortListView.as_view(), name='device_powerports'),
|
||||
url(r'^devices/(?P<pk>\d+)/power-outlets/$', PowerOutletListView.as_view(), name='device_poweroutlets'),
|
||||
url(r'^devices/(?P<pk>\d+)/interfaces/$', InterfaceListView.as_view(), name='device_interfaces'),
|
||||
|
||||
# Console ports
|
||||
url(r'^console-ports/(?P<pk>\d+)/$', ConsolePortView.as_view(), name='consoleport'),
|
||||
|
||||
# Power ports
|
||||
url(r'^power-ports/(?P<pk>\d+)/$', PowerPortView.as_view(), name='powerport'),
|
||||
|
||||
# Interfaces
|
||||
url(r'^interfaces/(?P<pk>\d+)/$', InterfaceDetailView.as_view(), name='interface_detail'),
|
||||
url(r'^interfaces/(?P<pk>\d+)/graphs/$', GraphListView.as_view(), {'type': GRAPH_TYPE_INTERFACE}, name='interface_graphs'),
|
||||
url(r'^interface-connections/(?P<pk>\d+)/$', InterfaceConnectionView.as_view(), name='interfaceconnection'),
|
||||
|
||||
# Miscellaneous
|
||||
url(r'^related-connections/$', RelatedConnectionsView.as_view(), name='related_connections'),
|
||||
|
||||
]
|
||||
438
netbox/dcim/api/views.py
Normal file
438
netbox/dcim/api/views.py
Normal file
@@ -0,0 +1,438 @@
|
||||
from rest_framework import generics
|
||||
from rest_framework.permissions import DjangoModelPermissionsOrAnonReadOnly
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.settings import api_settings
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from django.conf import settings
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from dcim.models import Site, Rack, RackGroup, Manufacturer, DeviceType, DeviceRole, Platform, Device, ConsolePort, \
|
||||
ConsoleServerPort, PowerPort, PowerOutlet, Interface, InterfaceConnection, IFACE_FF_VIRTUAL
|
||||
from dcim.filters import RackGroupFilter, RackFilter, DeviceTypeFilter, DeviceFilter, InterfaceFilter
|
||||
from .exceptions import MissingFilterException
|
||||
from .serializers import SiteSerializer, RackGroupSerializer, RackSerializer, RackDetailSerializer, \
|
||||
ManufacturerSerializer, DeviceTypeSerializer, DeviceRoleSerializer, PlatformSerializer, DeviceSerializer, \
|
||||
DeviceNestedSerializer, ConsolePortSerializer, ConsoleServerPortSerializer, PowerPortSerializer, \
|
||||
PowerOutletSerializer, InterfaceSerializer, InterfaceDetailSerializer, InterfaceConnectionSerializer
|
||||
from extras.api.renderers import BINDZoneRenderer
|
||||
from utilities.api import ServiceUnavailable
|
||||
|
||||
|
||||
#
|
||||
# Sites
|
||||
#
|
||||
|
||||
class SiteListView(generics.ListAPIView):
|
||||
"""
|
||||
List all sites
|
||||
"""
|
||||
queryset = Site.objects.all()
|
||||
serializer_class = SiteSerializer
|
||||
|
||||
|
||||
class SiteDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single site
|
||||
"""
|
||||
queryset = Site.objects.all()
|
||||
serializer_class = SiteSerializer
|
||||
|
||||
|
||||
#
|
||||
# Rack groups
|
||||
#
|
||||
|
||||
class RackGroupListView(generics.ListAPIView):
|
||||
"""
|
||||
List all rack groups
|
||||
"""
|
||||
queryset = RackGroup.objects.all()
|
||||
serializer_class = RackGroupSerializer
|
||||
filter_class = RackGroupFilter
|
||||
|
||||
|
||||
class RackGroupDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single rack group
|
||||
"""
|
||||
queryset = RackGroup.objects.all()
|
||||
serializer_class = RackGroupSerializer
|
||||
|
||||
|
||||
#
|
||||
# Racks
|
||||
#
|
||||
|
||||
class RackListView(generics.ListAPIView):
|
||||
"""
|
||||
List racks (filterable)
|
||||
"""
|
||||
queryset = Rack.objects.select_related('site')
|
||||
serializer_class = RackSerializer
|
||||
filter_class = RackFilter
|
||||
|
||||
|
||||
class RackDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single rack
|
||||
"""
|
||||
queryset = Rack.objects.select_related('site')
|
||||
serializer_class = RackDetailSerializer
|
||||
|
||||
|
||||
#
|
||||
# Rack units
|
||||
#
|
||||
|
||||
class RackUnitListView(APIView):
|
||||
"""
|
||||
List rack units (by rack)
|
||||
"""
|
||||
|
||||
def get(self, request, pk):
|
||||
|
||||
rack = get_object_or_404(Rack, pk=pk)
|
||||
face = request.GET.get('face', 0)
|
||||
elevation = rack.get_rack_units(face)
|
||||
|
||||
# Serialize Devices within the rack elevation
|
||||
for u in elevation:
|
||||
if u['device']:
|
||||
u['device'] = DeviceNestedSerializer(instance=u['device']).data
|
||||
|
||||
return Response(elevation)
|
||||
|
||||
|
||||
#
|
||||
# Manufacturers
|
||||
#
|
||||
|
||||
class ManufacturerListView(generics.ListAPIView):
|
||||
"""
|
||||
List all hardware manufacturers
|
||||
"""
|
||||
queryset = Manufacturer.objects.all()
|
||||
serializer_class = ManufacturerSerializer
|
||||
|
||||
|
||||
class ManufacturerDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single hardware manufacturers
|
||||
"""
|
||||
queryset = Manufacturer.objects.all()
|
||||
serializer_class = ManufacturerSerializer
|
||||
|
||||
|
||||
#
|
||||
# Device Types
|
||||
#
|
||||
|
||||
class DeviceTypeListView(generics.ListAPIView):
|
||||
"""
|
||||
List device types (filterable)
|
||||
"""
|
||||
queryset = DeviceType.objects.select_related('manufacturer')
|
||||
serializer_class = DeviceTypeSerializer
|
||||
filter_class = DeviceTypeFilter
|
||||
|
||||
|
||||
class DeviceTypeDetailView(generics.ListAPIView):
|
||||
"""
|
||||
Retrieve a single device type
|
||||
"""
|
||||
queryset = DeviceType.objects.select_related('manufacturer')
|
||||
serializer_class = DeviceTypeSerializer
|
||||
|
||||
|
||||
#
|
||||
# Device roles
|
||||
#
|
||||
|
||||
class DeviceRoleListView(generics.ListAPIView):
|
||||
"""
|
||||
List all device roles
|
||||
"""
|
||||
queryset = DeviceRole.objects.all()
|
||||
serializer_class = DeviceRoleSerializer
|
||||
|
||||
|
||||
class DeviceRoleDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single device role
|
||||
"""
|
||||
queryset = DeviceRole.objects.all()
|
||||
serializer_class = DeviceRoleSerializer
|
||||
|
||||
|
||||
#
|
||||
# Platforms
|
||||
#
|
||||
|
||||
class PlatformListView(generics.ListAPIView):
|
||||
"""
|
||||
List all platforms
|
||||
"""
|
||||
queryset = Platform.objects.all()
|
||||
serializer_class = PlatformSerializer
|
||||
|
||||
|
||||
class PlatformDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single platform
|
||||
"""
|
||||
queryset = Platform.objects.all()
|
||||
serializer_class = PlatformSerializer
|
||||
|
||||
|
||||
#
|
||||
# Devices
|
||||
#
|
||||
|
||||
class DeviceListView(generics.ListAPIView):
|
||||
"""
|
||||
List devices (filterable)
|
||||
"""
|
||||
queryset = Device.objects.select_related('device_type__manufacturer', 'device_role', 'platform', 'rack__site')\
|
||||
.prefetch_related('primary_ip__nat_outside')
|
||||
serializer_class = DeviceSerializer
|
||||
filter_class = DeviceFilter
|
||||
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + [BINDZoneRenderer]
|
||||
|
||||
|
||||
class DeviceDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single device
|
||||
"""
|
||||
queryset = Device.objects.all()
|
||||
serializer_class = DeviceSerializer
|
||||
|
||||
|
||||
#
|
||||
# Console ports
|
||||
#
|
||||
|
||||
class ConsolePortListView(generics.ListAPIView):
|
||||
"""
|
||||
List console ports (by device)
|
||||
"""
|
||||
serializer_class = ConsolePortSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
||||
return ConsolePort.objects.filter(device=device).select_related('cs_port')
|
||||
|
||||
|
||||
class ConsolePortView(generics.RetrieveUpdateDestroyAPIView):
|
||||
permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
|
||||
serializer_class = ConsolePortSerializer
|
||||
queryset = ConsolePort.objects.all()
|
||||
|
||||
|
||||
#
|
||||
# Console server ports
|
||||
#
|
||||
|
||||
class ConsoleServerPortListView(generics.ListAPIView):
|
||||
"""
|
||||
List console server ports (by device)
|
||||
"""
|
||||
serializer_class = ConsoleServerPortSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
||||
return ConsoleServerPort.objects.filter(device=device).select_related('connected_console')
|
||||
|
||||
|
||||
#
|
||||
# Power ports
|
||||
#
|
||||
|
||||
class PowerPortListView(generics.ListAPIView):
|
||||
"""
|
||||
List power ports (by device)
|
||||
"""
|
||||
serializer_class = PowerPortSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
||||
return PowerPort.objects.filter(device=device).select_related('power_outlet')
|
||||
|
||||
|
||||
class PowerPortView(generics.RetrieveUpdateDestroyAPIView):
|
||||
permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
|
||||
serializer_class = PowerPortSerializer
|
||||
queryset = PowerPort.objects.all()
|
||||
|
||||
|
||||
#
|
||||
# Power outlets
|
||||
#
|
||||
|
||||
class PowerOutletListView(generics.ListAPIView):
|
||||
"""
|
||||
List power outlets (by device)
|
||||
"""
|
||||
serializer_class = PowerOutletSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
||||
return PowerOutlet.objects.filter(device=device).select_related('connected_port')
|
||||
|
||||
|
||||
#
|
||||
# Interfaces
|
||||
#
|
||||
|
||||
class InterfaceListView(generics.ListAPIView):
|
||||
"""
|
||||
List interfaces (by device)
|
||||
"""
|
||||
serializer_class = InterfaceSerializer
|
||||
filter_class = InterfaceFilter
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
||||
queryset = Interface.objects.filter(device=device).select_related('connected_as_a', 'connected_as_b')
|
||||
|
||||
# Filter by type (physical or virtual)
|
||||
iface_type = self.request.query_params.get('type')
|
||||
if iface_type == 'physical':
|
||||
queryset = queryset.exclude(form_factor=IFACE_FF_VIRTUAL)
|
||||
elif iface_type == 'virtual':
|
||||
queryset = queryset.filter(form_factor=IFACE_FF_VIRTUAL)
|
||||
elif iface_type is not None:
|
||||
queryset = queryset.empty()
|
||||
|
||||
return queryset
|
||||
|
||||
|
||||
class InterfaceDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single interface
|
||||
"""
|
||||
queryset = Interface.objects.select_related('device')
|
||||
serializer_class = InterfaceDetailSerializer
|
||||
|
||||
|
||||
class InterfaceConnectionView(generics.RetrieveUpdateDestroyAPIView):
|
||||
permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
|
||||
serializer_class = InterfaceConnectionSerializer
|
||||
queryset = InterfaceConnection.objects.all()
|
||||
|
||||
|
||||
#
|
||||
# Live queries
|
||||
#
|
||||
|
||||
class LLDPNeighborsView(APIView):
|
||||
"""
|
||||
Retrieve live LLDP neighbors of a device
|
||||
"""
|
||||
|
||||
def get(self, request, pk):
|
||||
|
||||
device = get_object_or_404(Device, pk=pk)
|
||||
if not device.primary_ip:
|
||||
raise ServiceUnavailable(detail="No IP configured for this device.")
|
||||
hostname = str(device.primary_ip.address.ip)
|
||||
|
||||
RPC = device.get_rpc_client()
|
||||
if not RPC:
|
||||
raise ServiceUnavailable(detail="No RPC client available for this platform ({}).".format(device.platform))
|
||||
|
||||
# Connect to device and retrieve inventory info
|
||||
try:
|
||||
with RPC(device, username=settings.NETBOX_USERNAME, password=settings.NETBOX_PASSWORD) as rpc_client:
|
||||
lldp_neighbors = rpc_client.get_lldp_neighbors()
|
||||
except:
|
||||
raise ServiceUnavailable(detail="Error connecting to the remote device.")
|
||||
|
||||
return Response(lldp_neighbors)
|
||||
|
||||
|
||||
#
|
||||
# Miscellaneous
|
||||
#
|
||||
|
||||
class RelatedConnectionsView(APIView):
|
||||
"""
|
||||
Retrieve all connections related to a given console/power/interface connection
|
||||
"""
|
||||
|
||||
def get(self, request):
|
||||
|
||||
peer_device = request.GET.get('peer-device')
|
||||
peer_interface = request.GET.get('peer-interface')
|
||||
|
||||
# Search by interface
|
||||
if peer_device and peer_interface:
|
||||
|
||||
# Determine local interface from peer interface's connection
|
||||
try:
|
||||
peer_iface = Interface.objects.get(device__name=peer_device, name=peer_interface)
|
||||
except Interface.DoesNotExist:
|
||||
raise Http404()
|
||||
local_iface = peer_iface.get_connected_interface()
|
||||
if local_iface:
|
||||
device = local_iface.device
|
||||
else:
|
||||
return Response()
|
||||
|
||||
else:
|
||||
raise MissingFilterException(detail='Must specify search parameters (peer-device and peer-interface).')
|
||||
|
||||
# Initialize response skeleton
|
||||
response = dict()
|
||||
response['device'] = DeviceSerializer(device).data
|
||||
response['console-ports'] = []
|
||||
response['power-ports'] = []
|
||||
response['interfaces'] = []
|
||||
|
||||
# Build console connections
|
||||
console_ports = ConsolePort.objects.filter(device=device).select_related('cs_port__device')
|
||||
for cp in console_ports:
|
||||
cp_info = dict()
|
||||
cp_info['name'] = cp.name
|
||||
if cp.cs_port:
|
||||
cp_info['console-server'] = cp.cs_port.device.name
|
||||
cp_info['port'] = cp.cs_port.name
|
||||
else:
|
||||
cp_info['console-server'] = None
|
||||
cp_info['port'] = None
|
||||
response['console-ports'].append(cp_info)
|
||||
|
||||
# Build power connections
|
||||
power_ports = PowerPort.objects.filter(device=device).select_related('power_outlet__device')
|
||||
for pp in power_ports:
|
||||
pp_info = dict()
|
||||
pp_info['name'] = pp.name
|
||||
if pp.power_outlet:
|
||||
pp_info['pdu'] = pp.power_outlet.device.name
|
||||
pp_info['outlet'] = pp.power_outlet.name
|
||||
else:
|
||||
pp_info['pdu'] = None
|
||||
pp_info['outlet'] = None
|
||||
response['power-ports'].append(pp_info)
|
||||
|
||||
# Built interface connections
|
||||
interfaces = Interface.objects.filter(device=device)
|
||||
for iface in interfaces:
|
||||
iface_info = dict()
|
||||
iface_info['name'] = iface.name
|
||||
peer_interface = iface.get_connected_interface()
|
||||
if peer_interface:
|
||||
iface_info['device'] = peer_interface.device.name
|
||||
iface_info['interface'] = peer_interface.name
|
||||
else:
|
||||
iface_info['device'] = None
|
||||
iface_info['interface'] = None
|
||||
response['interfaces'].append(iface_info)
|
||||
|
||||
return Response(response)
|
||||
Reference in New Issue
Block a user