serializers.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. from drf_yasg.utils import swagger_serializer_method
  2. from rest_framework import serializers
  3. from dcim.api.nested_serializers import NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer
  4. from dcim.choices import InterfaceModeChoices
  5. from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer
  6. from ipam.models import VLAN
  7. from netbox.api import ChoiceField, SerializedPKRelatedField
  8. from netbox.api.serializers import NetBoxModelSerializer
  9. from tenancy.api.nested_serializers import NestedTenantSerializer
  10. from virtualization.choices import *
  11. from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
  12. from .nested_serializers import *
  13. #
  14. # Clusters
  15. #
  16. class ClusterTypeSerializer(NetBoxModelSerializer):
  17. url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustertype-detail')
  18. cluster_count = serializers.IntegerField(read_only=True)
  19. class Meta:
  20. model = ClusterType
  21. fields = [
  22. 'id', 'url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
  23. 'cluster_count',
  24. ]
  25. class ClusterGroupSerializer(NetBoxModelSerializer):
  26. url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustergroup-detail')
  27. cluster_count = serializers.IntegerField(read_only=True)
  28. class Meta:
  29. model = ClusterGroup
  30. fields = [
  31. 'id', 'url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
  32. 'cluster_count',
  33. ]
  34. class ClusterSerializer(NetBoxModelSerializer):
  35. url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail')
  36. type = NestedClusterTypeSerializer()
  37. group = NestedClusterGroupSerializer(required=False, allow_null=True, default=None)
  38. tenant = NestedTenantSerializer(required=False, allow_null=True)
  39. site = NestedSiteSerializer(required=False, allow_null=True, default=None)
  40. device_count = serializers.IntegerField(read_only=True)
  41. virtualmachine_count = serializers.IntegerField(read_only=True)
  42. class Meta:
  43. model = Cluster
  44. fields = [
  45. 'id', 'url', 'display', 'name', 'type', 'group', 'tenant', 'site', 'comments', 'tags', 'custom_fields',
  46. 'created', 'last_updated', 'device_count', 'virtualmachine_count',
  47. ]
  48. #
  49. # Virtual machines
  50. #
  51. class VirtualMachineSerializer(NetBoxModelSerializer):
  52. url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualmachine-detail')
  53. status = ChoiceField(choices=VirtualMachineStatusChoices, required=False)
  54. site = NestedSiteSerializer(read_only=True)
  55. cluster = NestedClusterSerializer()
  56. role = NestedDeviceRoleSerializer(required=False, allow_null=True)
  57. tenant = NestedTenantSerializer(required=False, allow_null=True)
  58. platform = NestedPlatformSerializer(required=False, allow_null=True)
  59. primary_ip = NestedIPAddressSerializer(read_only=True)
  60. primary_ip4 = NestedIPAddressSerializer(required=False, allow_null=True)
  61. primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
  62. class Meta:
  63. model = VirtualMachine
  64. fields = [
  65. 'id', 'url', 'display', 'name', 'status', 'site', 'cluster', 'role', 'tenant', 'platform', 'primary_ip',
  66. 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'comments', 'local_context_data', 'tags',
  67. 'custom_fields', 'created', 'last_updated',
  68. ]
  69. validators = []
  70. class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer):
  71. config_context = serializers.SerializerMethodField()
  72. class Meta(VirtualMachineSerializer.Meta):
  73. fields = [
  74. 'id', 'url', 'display', 'name', 'status', 'site', 'cluster', 'role', 'tenant', 'platform', 'primary_ip',
  75. 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'comments', 'local_context_data', 'tags',
  76. 'custom_fields', 'config_context', 'created', 'last_updated',
  77. ]
  78. @swagger_serializer_method(serializer_or_field=serializers.DictField)
  79. def get_config_context(self, obj):
  80. return obj.get_config_context()
  81. #
  82. # VM interfaces
  83. #
  84. class VMInterfaceSerializer(NetBoxModelSerializer):
  85. url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:vminterface-detail')
  86. virtual_machine = NestedVirtualMachineSerializer()
  87. parent = NestedVMInterfaceSerializer(required=False, allow_null=True)
  88. bridge = NestedVMInterfaceSerializer(required=False, allow_null=True)
  89. mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False)
  90. untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
  91. tagged_vlans = SerializedPKRelatedField(
  92. queryset=VLAN.objects.all(),
  93. serializer=NestedVLANSerializer,
  94. required=False,
  95. many=True
  96. )
  97. vrf = NestedVRFSerializer(required=False, allow_null=True)
  98. count_ipaddresses = serializers.IntegerField(read_only=True)
  99. count_fhrp_groups = serializers.IntegerField(read_only=True)
  100. class Meta:
  101. model = VMInterface
  102. fields = [
  103. 'id', 'url', 'display', 'virtual_machine', 'name', 'enabled', 'parent', 'bridge', 'mtu', 'mac_address',
  104. 'description', 'mode', 'untagged_vlan', 'tagged_vlans', 'vrf', 'tags', 'custom_fields', 'created',
  105. 'last_updated', 'count_ipaddresses', 'count_fhrp_groups',
  106. ]
  107. def validate(self, data):
  108. # Validate many-to-many VLAN assignments
  109. virtual_machine = self.instance.virtual_machine if self.instance else data.get('virtual_machine')
  110. for vlan in data.get('tagged_vlans', []):
  111. if vlan.site not in [virtual_machine.site, None]:
  112. raise serializers.ValidationError({
  113. 'tagged_vlans': f"VLAN {vlan} must belong to the same site as the interface's parent virtual "
  114. f"machine, or it must be global."
  115. })
  116. return super().validate(data)