From 9da2b8e587e9f62f0b236c3bb8a202add8229c1d Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 16 Feb 2017 13:35:34 -0500 Subject: [PATCH] Implemented API endpoints for rack reservations --- netbox/dcim/api/serializers.py | 25 ++++++++++++++++++++++--- netbox/dcim/api/urls.py | 4 ++++ netbox/dcim/api/views.py | 24 +++++++++++++++++++++++- netbox/dcim/filters.py | 14 +++++++++++++- netbox/dcim/models.py | 4 ++-- netbox/dcim/tests/test_apis.py | 1 + 6 files changed, 65 insertions(+), 7 deletions(-) diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index f81f299af..34e0b1a1e 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -4,8 +4,8 @@ from ipam.models import IPAddress from dcim.models import ( ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay, DeviceType, DeviceRole, Interface, InterfaceConnection, InterfaceTemplate, Manufacturer, Module, Platform, PowerOutlet, - PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup, RackRole, RACK_FACE_FRONT, RACK_FACE_REAR, Site, - SUBDEVICE_ROLE_CHILD, SUBDEVICE_ROLE_PARENT, + PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup, RackReservation, RackRole, RACK_FACE_FRONT, + RACK_FACE_REAR, Site, SUBDEVICE_ROLE_CHILD, SUBDEVICE_ROLE_PARENT, ) from extras.api.serializers import CustomFieldSerializer from tenancy.api.serializers import TenantNestedSerializer @@ -70,6 +70,12 @@ class RackRoleNestedSerializer(RackRoleSerializer): # Racks # +class RackReservationNestedSerializer(serializers.ModelSerializer): + + class Meta: + model = RackReservation + fields = ['id', 'units', 'created', 'user', 'description'] + class RackSerializer(CustomFieldSerializer, serializers.ModelSerializer): site = SiteNestedSerializer() @@ -92,10 +98,11 @@ class RackNestedSerializer(RackSerializer): class RackDetailSerializer(RackSerializer): front_units = serializers.SerializerMethodField() rear_units = serializers.SerializerMethodField() + reservations = RackReservationNestedSerializer(many=True) class Meta(RackSerializer.Meta): fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'role', 'type', 'width', - 'u_height', 'desc_units', 'comments', 'custom_fields', 'front_units', 'rear_units'] + 'u_height', 'desc_units', 'reservations', 'comments', 'custom_fields', 'front_units', 'rear_units'] def get_front_units(self, obj): units = obj.get_rack_units(face=RACK_FACE_FRONT) @@ -110,6 +117,18 @@ class RackDetailSerializer(RackSerializer): return units +# +# Rack reservations +# + +class RackReservationSerializer(serializers.ModelSerializer): + rack = RackNestedSerializer() + + class Meta: + model = RackReservation + fields = ['id', 'rack', 'units', 'created', 'user', 'description'] + + # # Manufacturers # diff --git a/netbox/dcim/api/urls.py b/netbox/dcim/api/urls.py index 23787f4b4..432135925 100644 --- a/netbox/dcim/api/urls.py +++ b/netbox/dcim/api/urls.py @@ -27,6 +27,10 @@ urlpatterns = [ url(r'^racks/(?P\d+)/$', RackDetailView.as_view(), name='rack_detail'), url(r'^racks/(?P\d+)/rack-units/$', RackUnitListView.as_view(), name='rack_units'), + # Rack reservations + url(r'^rack-reservations/$', RackReservationListView.as_view(), name='rackreservation_list'), + url(r'^rack-reservations/(?P\d+)/$', RackReservationDetailView.as_view(), name='rackreservation_detail'), + # Manufacturers url(r'^manufacturers/$', ManufacturerListView.as_view(), name='manufacturer_list'), url(r'^manufacturers/(?P\d+)/$', ManufacturerDetailView.as_view(), name='manufacturer_detail'), diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index e76ec82ad..5679df579 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -11,7 +11,8 @@ from django.shortcuts import get_object_or_404 from dcim.models import ( ConsolePort, ConsoleServerPort, Device, DeviceBay, DeviceRole, DeviceType, IFACE_FF_VIRTUAL, Interface, - InterfaceConnection, Manufacturer, Module, Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackRole, Site, + InterfaceConnection, Manufacturer, Module, Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackReservation, + RackRole, Site, ) from dcim import filters from extras.api.views import CustomFieldModelAPIView @@ -134,6 +135,27 @@ class RackUnitListView(APIView): return Response(elevation) +# +# Rack reservations +# + +class RackReservationListView(generics.ListAPIView): + """ + List all rack reservation + """ + queryset = RackReservation.objects.all() + serializer_class = serializers.RackReservationSerializer + filter_class = filters.RackReservationFilter + + +class RackReservationDetailView(generics.RetrieveAPIView): + """ + Retrieve a single rack reservation + """ + queryset = RackReservation.objects.all() + serializer_class = serializers.RackReservationSerializer + + # # Manufacturers # diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 79024b605..256dd0084 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -8,7 +8,7 @@ from tenancy.models import Tenant from utilities.filters import NullableModelMultipleChoiceFilter from .models import ( ConsolePort, ConsoleServerPort, Device, DeviceRole, DeviceType, Interface, InterfaceConnection, Manufacturer, - Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackRole, Site, + Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackReservation, RackRole, Site, ) @@ -122,6 +122,18 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet): ) +class RackReservationFilter(django_filters.FilterSet): + rack_id = django_filters.ModelMultipleChoiceFilter( + name='rack', + queryset=Rack.objects.all(), + label='Rack (ID)', + ) + + class Meta: + model = RackReservation + fields = ['rack', 'user'] + + class DeviceTypeFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index c95b6a823..1225988ca 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -485,10 +485,10 @@ class RackReservation(models.Model): """ One or more reserved units within a Rack. """ - created = models.DateTimeField(auto_now_add=True) - user = models.ForeignKey(User, editable=False, on_delete=models.PROTECT) rack = models.ForeignKey('Rack', related_name='reservations', editable=False, on_delete=models.CASCADE) units = ArrayField(models.PositiveSmallIntegerField()) + created = models.DateTimeField(auto_now_add=True) + user = models.ForeignKey(User, editable=False, on_delete=models.PROTECT) description = models.CharField(max_length=100) class Meta: diff --git a/netbox/dcim/tests/test_apis.py b/netbox/dcim/tests/test_apis.py index 0f7d1bbe3..cec552984 100644 --- a/netbox/dcim/tests/test_apis.py +++ b/netbox/dcim/tests/test_apis.py @@ -151,6 +151,7 @@ class RackTest(APITestCase): 'width', 'u_height', 'desc_units', + 'reservations', 'comments', 'custom_fields', 'front_units',