serializers.py 5.4 KB

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