2
0

ip.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. from django.contrib.contenttypes.models import ContentType
  2. from rest_framework import serializers
  3. from dcim.constants import LOCATION_SCOPE_TYPES
  4. from ipam.choices import *
  5. from ipam.constants import IPADDRESS_ASSIGNMENT_MODELS
  6. from ipam.models import Aggregate, IPAddress, IPRange, Prefix
  7. from netbox.api.fields import ChoiceField, ContentTypeField
  8. from netbox.api.gfk_fields import GFKSerializerField
  9. from netbox.api.serializers import PrimaryModelSerializer
  10. from tenancy.api.serializers_.tenants import TenantSerializer
  11. from .asns import RIRSerializer
  12. from .nested import NestedIPAddressSerializer
  13. from .roles import RoleSerializer
  14. from .vlans import VLANSerializer
  15. from .vrfs import VRFSerializer
  16. from ..field_serializers import IPAddressField, IPNetworkField
  17. __all__ = (
  18. 'AggregateSerializer',
  19. 'AvailableIPSerializer',
  20. 'AvailableIPRequestSerializer',
  21. 'AvailablePrefixSerializer',
  22. 'IPAddressSerializer',
  23. 'IPRangeSerializer',
  24. 'PrefixLengthSerializer',
  25. 'PrefixSerializer',
  26. )
  27. class AggregateSerializer(PrimaryModelSerializer):
  28. family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
  29. rir = RIRSerializer(nested=True)
  30. tenant = TenantSerializer(nested=True, required=False, allow_null=True)
  31. prefix = IPNetworkField()
  32. class Meta:
  33. model = Aggregate
  34. fields = [
  35. 'id', 'url', 'display_url', 'display', 'family', 'prefix', 'rir', 'tenant', 'date_added', 'description',
  36. 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
  37. ]
  38. brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description')
  39. class PrefixSerializer(PrimaryModelSerializer):
  40. family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
  41. vrf = VRFSerializer(nested=True, required=False, allow_null=True)
  42. scope_type = ContentTypeField(
  43. queryset=ContentType.objects.filter(
  44. model__in=LOCATION_SCOPE_TYPES
  45. ),
  46. allow_null=True,
  47. required=False,
  48. default=None
  49. )
  50. scope_id = serializers.IntegerField(allow_null=True, required=False, default=None)
  51. scope = GFKSerializerField(read_only=True)
  52. tenant = TenantSerializer(nested=True, required=False, allow_null=True)
  53. vlan = VLANSerializer(nested=True, required=False, allow_null=True)
  54. status = ChoiceField(choices=PrefixStatusChoices, required=False)
  55. role = RoleSerializer(nested=True, required=False, allow_null=True)
  56. children = serializers.IntegerField(read_only=True)
  57. _depth = serializers.IntegerField(read_only=True)
  58. prefix = IPNetworkField()
  59. class Meta:
  60. model = Prefix
  61. fields = [
  62. 'id', 'url', 'display_url', 'display', 'family', 'prefix', 'vrf', 'scope_type', 'scope_id', 'scope',
  63. 'tenant', 'vlan', 'status', 'role', 'is_pool', 'mark_utilized', 'description', 'owner', 'comments', 'tags',
  64. 'custom_fields', 'created', 'last_updated', 'children', '_depth',
  65. ]
  66. brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description', '_depth')
  67. class PrefixLengthSerializer(serializers.Serializer):
  68. prefix_length = serializers.IntegerField()
  69. def to_internal_value(self, data):
  70. requested_prefix = data.get('prefix_length')
  71. if requested_prefix is None:
  72. raise serializers.ValidationError({
  73. 'prefix_length': 'this field can not be missing'
  74. })
  75. if not isinstance(requested_prefix, int):
  76. raise serializers.ValidationError({
  77. 'prefix_length': 'this field must be int type'
  78. })
  79. prefix = self.context.get('prefix')
  80. if prefix.family == 4 and requested_prefix > 32:
  81. raise serializers.ValidationError({
  82. 'prefix_length': 'Invalid prefix length ({}) for IPv4'.format(requested_prefix)
  83. })
  84. elif prefix.family == 6 and requested_prefix > 128:
  85. raise serializers.ValidationError({
  86. 'prefix_length': 'Invalid prefix length ({}) for IPv6'.format(requested_prefix)
  87. })
  88. return data
  89. class AvailablePrefixSerializer(serializers.Serializer):
  90. """
  91. Representation of a prefix which does not exist in the database.
  92. """
  93. family = serializers.IntegerField(read_only=True)
  94. prefix = serializers.CharField(read_only=True)
  95. vrf = VRFSerializer(nested=True, read_only=True, allow_null=True)
  96. def to_representation(self, instance):
  97. if self.context.get('vrf'):
  98. vrf = VRFSerializer(self.context['vrf'], nested=True, context={'request': self.context['request']}).data
  99. else:
  100. vrf = None
  101. return {
  102. 'family': instance.version,
  103. 'prefix': str(instance),
  104. 'vrf': vrf,
  105. }
  106. #
  107. # IP ranges
  108. #
  109. class IPRangeSerializer(PrimaryModelSerializer):
  110. family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
  111. start_address = IPAddressField()
  112. end_address = IPAddressField()
  113. vrf = VRFSerializer(nested=True, required=False, allow_null=True)
  114. tenant = TenantSerializer(nested=True, required=False, allow_null=True)
  115. status = ChoiceField(choices=IPRangeStatusChoices, required=False)
  116. role = RoleSerializer(nested=True, required=False, allow_null=True)
  117. class Meta:
  118. model = IPRange
  119. fields = [
  120. 'id', 'url', 'display_url', 'display', 'family', 'start_address', 'end_address', 'size', 'vrf', 'tenant',
  121. 'status', 'role', 'description', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
  122. 'mark_populated', 'mark_utilized',
  123. ]
  124. brief_fields = ('id', 'url', 'display', 'family', 'start_address', 'end_address', 'description')
  125. #
  126. # IP addresses
  127. #
  128. class AvailableIPRequestSerializer(serializers.Serializer):
  129. """
  130. Request payload for creating IP addresses from the available-ips endpoint.
  131. """
  132. prefix_length = serializers.IntegerField(required=False)
  133. def to_internal_value(self, data):
  134. data = super().to_internal_value(data)
  135. prefix_length = data.get('prefix_length')
  136. if prefix_length is None:
  137. # No override requested; the parent prefix/range mask length will be used.
  138. return data
  139. parent = self.context.get('parent')
  140. if parent is None:
  141. return data
  142. # Validate the requested prefix length
  143. if prefix_length < parent.mask_length:
  144. raise serializers.ValidationError({
  145. 'prefix_length': 'Prefix length must be greater than or equal to the parent mask length ({})'.format(
  146. parent.mask_length
  147. )
  148. })
  149. elif parent.family == 4 and prefix_length > 32:
  150. raise serializers.ValidationError({
  151. 'prefix_length': 'Invalid prefix length ({}) for IPv6'.format(prefix_length)
  152. })
  153. elif parent.family == 6 and prefix_length > 128:
  154. raise serializers.ValidationError({
  155. 'prefix_length': 'Invalid prefix length ({}) for IPv4'.format(prefix_length)
  156. })
  157. return data
  158. class IPAddressSerializer(PrimaryModelSerializer):
  159. family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
  160. address = IPAddressField()
  161. vrf = VRFSerializer(nested=True, required=False, allow_null=True)
  162. tenant = TenantSerializer(nested=True, required=False, allow_null=True)
  163. status = ChoiceField(choices=IPAddressStatusChoices, required=False)
  164. role = ChoiceField(choices=IPAddressRoleChoices, allow_blank=True, required=False)
  165. assigned_object_type = ContentTypeField(
  166. queryset=ContentType.objects.filter(IPADDRESS_ASSIGNMENT_MODELS),
  167. required=False,
  168. allow_null=True
  169. )
  170. assigned_object = GFKSerializerField(read_only=True)
  171. nat_inside = NestedIPAddressSerializer(required=False, allow_null=True)
  172. nat_outside = NestedIPAddressSerializer(many=True, read_only=True)
  173. class Meta:
  174. model = IPAddress
  175. fields = [
  176. 'id', 'url', 'display_url', 'display', 'family', 'address', 'vrf', 'tenant', 'status', 'role',
  177. 'assigned_object_type', 'assigned_object_id', 'assigned_object', 'nat_inside', 'nat_outside',
  178. 'dns_name', 'description', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
  179. ]
  180. brief_fields = ('id', 'url', 'display', 'family', 'address', 'description')
  181. class AvailableIPSerializer(serializers.Serializer):
  182. """
  183. Representation of an IP address which does not exist in the database.
  184. """
  185. family = serializers.IntegerField(read_only=True)
  186. address = serializers.CharField(read_only=True)
  187. vrf = VRFSerializer(nested=True, read_only=True, allow_null=True)
  188. description = serializers.CharField(required=False)
  189. def to_representation(self, instance):
  190. if self.context.get('vrf'):
  191. vrf = VRFSerializer(self.context['vrf'], nested=True, context={'request': self.context['request']}).data
  192. else:
  193. vrf = None
  194. return {
  195. 'family': self.context['parent'].family,
  196. 'address': f"{instance}/{self.context['parent'].mask_length}",
  197. 'vrf': vrf,
  198. }