|
@@ -1,16 +1,14 @@
|
|
|
-from django.db import transaction
|
|
|
|
|
from django.utils.translation import gettext as _
|
|
from django.utils.translation import gettext as _
|
|
|
from drf_spectacular.utils import extend_schema_field
|
|
from drf_spectacular.utils import extend_schema_field
|
|
|
from netaddr import EUI, AddrFormatError
|
|
from netaddr import EUI, AddrFormatError
|
|
|
from rest_framework import serializers
|
|
from rest_framework import serializers
|
|
|
-from rest_framework.exceptions import PermissionDenied
|
|
|
|
|
|
|
|
|
|
from dcim.api.serializers_.devices import DeviceSerializer, MACAddressSerializer
|
|
from dcim.api.serializers_.devices import DeviceSerializer, MACAddressSerializer
|
|
|
|
|
+from dcim.api.serializers_.mixins import _UNSET, MACAddressShortcutMixin
|
|
|
from dcim.api.serializers_.platforms import PlatformSerializer
|
|
from dcim.api.serializers_.platforms import PlatformSerializer
|
|
|
from dcim.api.serializers_.roles import DeviceRoleSerializer
|
|
from dcim.api.serializers_.roles import DeviceRoleSerializer
|
|
|
from dcim.api.serializers_.sites import SiteSerializer
|
|
from dcim.api.serializers_.sites import SiteSerializer
|
|
|
from dcim.choices import InterfaceModeChoices
|
|
from dcim.choices import InterfaceModeChoices
|
|
|
-from dcim.models import MACAddress
|
|
|
|
|
from extras.api.serializers_.configtemplates import ConfigTemplateSerializer
|
|
from extras.api.serializers_.configtemplates import ConfigTemplateSerializer
|
|
|
from ipam.api.serializers_.ip import IPAddressSerializer
|
|
from ipam.api.serializers_.ip import IPAddressSerializer
|
|
|
from ipam.api.serializers_.vlans import VLANSerializer, VLANTranslationPolicySerializer
|
|
from ipam.api.serializers_.vlans import VLANSerializer, VLANTranslationPolicySerializer
|
|
@@ -27,8 +25,6 @@ from ...models import VirtualDisk, VirtualMachine, VirtualMachineType, VMInterfa
|
|
|
from .clusters import ClusterSerializer
|
|
from .clusters import ClusterSerializer
|
|
|
from .nested import NestedVMInterfaceSerializer
|
|
from .nested import NestedVMInterfaceSerializer
|
|
|
|
|
|
|
|
-_UNSET = object()
|
|
|
|
|
-
|
|
|
|
|
__all__ = (
|
|
__all__ = (
|
|
|
'VMInterfaceSerializer',
|
|
'VMInterfaceSerializer',
|
|
|
'VirtualDiskSerializer',
|
|
'VirtualDiskSerializer',
|
|
@@ -108,7 +104,7 @@ class VirtualMachineSerializer(PrimaryModelSerializer):
|
|
|
# VM interfaces
|
|
# VM interfaces
|
|
|
#
|
|
#
|
|
|
|
|
|
|
|
-class VMInterfaceSerializer(OwnerMixin, NetBoxModelSerializer):
|
|
|
|
|
|
|
+class VMInterfaceSerializer(MACAddressShortcutMixin, OwnerMixin, NetBoxModelSerializer):
|
|
|
virtual_machine = VirtualMachineSerializer(nested=True)
|
|
virtual_machine = VirtualMachineSerializer(nested=True)
|
|
|
parent = NestedVMInterfaceSerializer(required=False, allow_null=True)
|
|
parent = NestedVMInterfaceSerializer(required=False, allow_null=True)
|
|
|
bridge = NestedVMInterfaceSerializer(required=False, allow_null=True)
|
|
bridge = NestedVMInterfaceSerializer(required=False, allow_null=True)
|
|
@@ -192,56 +188,6 @@ class VMInterfaceSerializer(OwnerMixin, NetBoxModelSerializer):
|
|
|
|
|
|
|
|
return data
|
|
return data
|
|
|
|
|
|
|
|
- def create(self, validated_data):
|
|
|
|
|
- mac_address = validated_data.pop('mac_address', None)
|
|
|
|
|
- if mac_address is not None:
|
|
|
|
|
- request = self.context.get('request')
|
|
|
|
|
- if request and not request.user.has_perm('dcim.add_macaddress'):
|
|
|
|
|
- raise PermissionDenied(_('You do not have permission to create MAC addresses.'))
|
|
|
|
|
- with transaction.atomic():
|
|
|
|
|
- instance = super().create(validated_data)
|
|
|
|
|
- if mac_address is not None:
|
|
|
|
|
- mac = MACAddress.objects.create(mac_address=mac_address, assigned_object=instance)
|
|
|
|
|
- instance.primary_mac_address = mac
|
|
|
|
|
- instance.save()
|
|
|
|
|
- instance.__dict__.pop('mac_address', None)
|
|
|
|
|
- return instance
|
|
|
|
|
-
|
|
|
|
|
- def update(self, instance, validated_data):
|
|
|
|
|
- mac_address = validated_data.pop('mac_address', _UNSET)
|
|
|
|
|
-
|
|
|
|
|
- # Check permission and locate any existing MAC before any writes.
|
|
|
|
|
- if mac_address not in (_UNSET, None):
|
|
|
|
|
- existing_mac = instance.mac_addresses.filter(mac_address=mac_address).first()
|
|
|
|
|
- if existing_mac is None:
|
|
|
|
|
- request = self.context.get('request')
|
|
|
|
|
- if request and not request.user.has_perm('dcim.add_macaddress'):
|
|
|
|
|
- raise PermissionDenied(_('You do not have permission to create MAC addresses.'))
|
|
|
|
|
- else:
|
|
|
|
|
- existing_mac = None
|
|
|
|
|
-
|
|
|
|
|
- with transaction.atomic():
|
|
|
|
|
- instance = super().update(instance, validated_data)
|
|
|
|
|
- if mac_address is _UNSET:
|
|
|
|
|
- pass
|
|
|
|
|
- elif mac_address is None:
|
|
|
|
|
- if instance.primary_mac_address_id is not None:
|
|
|
|
|
- instance.snapshot()
|
|
|
|
|
- instance.primary_mac_address = None
|
|
|
|
|
- instance.save()
|
|
|
|
|
- else:
|
|
|
|
|
- # Find-or-create: prefer existing MAC on this interface; create only if absent.
|
|
|
|
|
- mac = existing_mac
|
|
|
|
|
- if mac is None:
|
|
|
|
|
- mac = MACAddress.objects.create(mac_address=mac_address, assigned_object=instance)
|
|
|
|
|
- if instance.primary_mac_address_id != mac.pk:
|
|
|
|
|
- instance.snapshot()
|
|
|
|
|
- instance.primary_mac_address = mac
|
|
|
|
|
- instance.save()
|
|
|
|
|
-
|
|
|
|
|
- instance.__dict__.pop('mac_address', None)
|
|
|
|
|
- return instance
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
#
|
|
#
|
|
|
# Virtual Disk
|
|
# Virtual Disk
|