mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Closes #2658: Avalable VLANs API endpoint for VLAN groups
This commit is contained in:
@@ -213,6 +213,40 @@ class VLANSerializer(PrimaryModelSerializer):
|
||||
]
|
||||
|
||||
|
||||
class AvailableVLANSerializer(serializers.Serializer):
|
||||
"""
|
||||
Representation of a VLAN which does not exist in the database.
|
||||
"""
|
||||
vid = serializers.IntegerField(read_only=True)
|
||||
group = NestedVLANGroupSerializer(read_only=True)
|
||||
|
||||
def to_representation(self, instance):
|
||||
return OrderedDict([
|
||||
('vid', instance),
|
||||
('group', NestedVLANGroupSerializer(
|
||||
self.context['group'],
|
||||
context={'request': self.context['request']}
|
||||
).data),
|
||||
])
|
||||
|
||||
|
||||
class CreateAvailableVLANSerializer(PrimaryModelSerializer):
|
||||
site = NestedSiteSerializer(required=False, allow_null=True)
|
||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||
status = ChoiceField(choices=VLANStatusChoices, required=False)
|
||||
role = NestedRoleSerializer(required=False, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = VLAN
|
||||
fields = [
|
||||
'name', 'site', 'tenant', 'status', 'role', 'description', 'tags', 'custom_fields',
|
||||
]
|
||||
|
||||
def validate(self, data):
|
||||
# Bypass model validation since we don't have a VID yet
|
||||
return data
|
||||
|
||||
|
||||
#
|
||||
# Prefixes
|
||||
#
|
||||
|
@@ -62,6 +62,11 @@ urlpatterns = [
|
||||
views.PrefixAvailableIPAddressesView.as_view(),
|
||||
name='prefix-available-ips'
|
||||
),
|
||||
path(
|
||||
'vlan-groups/<int:pk>/available-vlans/',
|
||||
views.AvailableVLANsView.as_view(),
|
||||
name='vlangroup-available-vlans'
|
||||
),
|
||||
]
|
||||
|
||||
urlpatterns += router.urls
|
||||
|
@@ -327,3 +327,75 @@ class IPRangeAvailableIPAddressesView(AvailableIPAddressesView):
|
||||
|
||||
def get_parent(self, request, pk):
|
||||
return get_object_or_404(IPRange.objects.restrict(request.user), pk=pk)
|
||||
|
||||
|
||||
class AvailableVLANsView(ObjectValidationMixin, APIView):
|
||||
queryset = VLAN.objects.all()
|
||||
|
||||
@swagger_auto_schema(responses={200: serializers.AvailableVLANSerializer(many=True)})
|
||||
def get(self, request, pk):
|
||||
vlangroup = get_object_or_404(VLANGroup.objects.restrict(request.user), pk=pk)
|
||||
available_vlans = vlangroup.get_available_vids()
|
||||
|
||||
serializer = serializers.AvailableVLANSerializer(available_vlans, many=True, context={
|
||||
'request': request,
|
||||
'group': vlangroup,
|
||||
})
|
||||
|
||||
return Response(serializer.data)
|
||||
|
||||
@swagger_auto_schema(
|
||||
request_body=serializers.CreateAvailableVLANSerializer,
|
||||
responses={201: serializers.VLANSerializer(many=True)}
|
||||
)
|
||||
@advisory_lock(ADVISORY_LOCK_KEYS['available-vlans'])
|
||||
def post(self, request, pk):
|
||||
self.queryset = self.queryset.restrict(request.user, 'add')
|
||||
vlangroup = get_object_or_404(VLANGroup.objects.restrict(request.user), pk=pk)
|
||||
available_vlans = vlangroup.get_available_vids()
|
||||
many = isinstance(request.data, list)
|
||||
|
||||
# Validate requested VLANs
|
||||
serializer = serializers.CreateAvailableVLANSerializer(
|
||||
data=request.data if many else [request.data],
|
||||
many=True,
|
||||
context={
|
||||
'request': request,
|
||||
'group': vlangroup,
|
||||
}
|
||||
)
|
||||
if not serializer.is_valid():
|
||||
return Response(
|
||||
serializer.errors,
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
requested_vlans = serializer.validated_data
|
||||
|
||||
for i, requested_vlan in enumerate(requested_vlans):
|
||||
try:
|
||||
requested_vlan['vid'] = available_vlans.pop(0)
|
||||
requested_vlan['group'] = vlangroup.pk
|
||||
except IndexError:
|
||||
return Response({
|
||||
"detail": "The requested number of VLANs is not available"
|
||||
}, status=status.HTTP_409_CONFLICT)
|
||||
|
||||
# Initialize the serializer with a list or a single object depending on what was requested
|
||||
context = {'request': request}
|
||||
if many:
|
||||
serializer = serializers.VLANSerializer(data=requested_vlans, many=True, context=context)
|
||||
else:
|
||||
serializer = serializers.VLANSerializer(data=requested_vlans[0], context=context)
|
||||
|
||||
# Create the new VLAN(s)
|
||||
if serializer.is_valid():
|
||||
try:
|
||||
with transaction.atomic():
|
||||
created = serializer.save()
|
||||
self._validate_objects(created)
|
||||
except ObjectDoesNotExist:
|
||||
raise PermissionDenied()
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
Reference in New Issue
Block a user