diff --git a/netbox/ipam/api/serializers.py b/netbox/ipam/api/serializers.py index e571ba777..f8eb1c509 100644 --- a/netbox/ipam/api/serializers.py +++ b/netbox/ipam/api/serializers.py @@ -369,13 +369,14 @@ class RequestAvailableIPSerializer(IPAddressSerializer): """ Representation of a request for new available IP """ + mask_length = serializers.IntegerField(required=False) class Meta: model = IPAddress fields = [ 'tenant', 'status', 'role', 'assigned_object_type', 'assigned_object', 'nat_inside', 'dns_name', 'description', 'tags', - 'custom_fields' + 'custom_fields', 'mask_length' ] diff --git a/netbox/ipam/api/views.py b/netbox/ipam/api/views.py index 15f35a082..73ae3d7af 100644 --- a/netbox/ipam/api/views.py +++ b/netbox/ipam/api/views.py @@ -294,7 +294,8 @@ class AvailableIPAddressesView(ObjectValidationMixin, APIView): # Assign addresses from the list of available IPs and copy VRF assignment from the parent available_ips = iter(available_ips) for requested_ip in requested_ips: - requested_ip['address'] = f'{next(available_ips)}/{parent.mask_length}' + mask_length = requested_ip.get('mask_length') or parent.mask_length + requested_ip['address'] = f'{next(available_ips)}/{mask_length}' requested_ip['vrf'] = parent.vrf.pk if parent.vrf else None # Initialize the serializer with a list or a single object depending on what was requested diff --git a/netbox/ipam/tests/test_api.py b/netbox/ipam/tests/test_api.py index 478c7f29b..be6818998 100644 --- a/netbox/ipam/tests/test_api.py +++ b/netbox/ipam/tests/test_api.py @@ -379,8 +379,8 @@ class PrefixTest(APIViewTestCases.APIViewTestCase): url = reverse('ipam-api:prefix-available-ips', kwargs={'pk': prefix.pk}) self.add_permissions('ipam.view_prefix', 'ipam.add_ipaddress') - # Create all four available IPs with individual requests - for i in range(1, 5): + # Create three available IPs with individual requests + for i in range(1, 4): data = { 'description': 'Test IP {}'.format(i) } @@ -388,6 +388,18 @@ class PrefixTest(APIViewTestCases.APIViewTestCase): self.assertHttpStatus(response, status.HTTP_201_CREATED) self.assertEqual(response.data['vrf']['id'], vrf.pk) self.assertEqual(response.data['description'], data['description']) + self.assertEqual(IPNetwork(response.data['address']).prefixlen, 30) + + # Create one more IP with a specified mask length + data = { + 'description': 'Test IP 4', + 'mask_length': 32 + } + response = self.client.post(url, data, format='json', **self.header) + self.assertHttpStatus(response, status.HTTP_201_CREATED) + self.assertEqual(response.data['vrf']['id'], vrf.pk) + self.assertEqual(response.data['description'], data['description']) + self.assertEqual(IPNetwork(response.data['address']).prefixlen, 32) # Try to create one more IP response = self.client.post(url, {}, **self.header)