Przeglądaj źródła

Fixes #3868: Fix creation of interfaces for virtual machines

Jeremy Stretch 6 lat temu
rodzic
commit
fe490d144a

+ 4 - 0
docs/release-notes/version-2.7.md

@@ -235,6 +235,10 @@ PATCH) to maintain backward compatibility. This behavior will be discontinued be
 * [#3706](https://github.com/digitalocean/netbox/issues/3706) - Increase `available_power` maximum value on PowerFeed
 * [#3706](https://github.com/digitalocean/netbox/issues/3706) - Increase `available_power` maximum value on PowerFeed
 * [#3731](https://github.com/digitalocean/netbox/issues/3731) - Change Graph.type to a ContentType foreign key field
 * [#3731](https://github.com/digitalocean/netbox/issues/3731) - Change Graph.type to a ContentType foreign key field
 
 
+## Bug Fixes (From Beta)
+
+* [#3868](https://github.com/digitalocean/netbox/issues/3868) - Fix creation of interfaces for virtual machines
+
 ## API Changes
 ## API Changes
 
 
 * Choice fields now use human-friendly strings for their values instead of integers (see
 * Choice fields now use human-friendly strings for their values instead of integers (see

+ 3 - 2
netbox/dcim/models.py

@@ -22,6 +22,7 @@ from utilities.fields import ColorField
 from utilities.managers import NaturalOrderingManager
 from utilities.managers import NaturalOrderingManager
 from utilities.models import ChangeLoggedModel
 from utilities.models import ChangeLoggedModel
 from utilities.utils import foreground_color, serialize_object, to_meters
 from utilities.utils import foreground_color, serialize_object, to_meters
+from virtualization.choices import VMInterfaceTypeChoices
 
 
 from .choices import *
 from .choices import *
 from .constants import *
 from .constants import *
@@ -2510,9 +2511,9 @@ class Interface(CableTermination, ComponentModel):
             raise ValidationError("An interface must belong to either a device or a virtual machine.")
             raise ValidationError("An interface must belong to either a device or a virtual machine.")
 
 
         # VM interfaces must be virtual
         # VM interfaces must be virtual
-        if self.virtual_machine and self.type is not InterfaceTypeChoices.TYPE_VIRTUAL:
+        if self.virtual_machine and self.type not in VMInterfaceTypeChoices.values():
             raise ValidationError({
             raise ValidationError({
-                'type': "Virtual machines can only have virtual interfaces."
+                'type': "Invalid interface type for a virtual machine: {}".format(self.type)
             })
             })
 
 
         # Virtual interfaces cannot be connected
         # Virtual interfaces cannot be connected

+ 4 - 0
netbox/utilities/choices.py

@@ -16,6 +16,10 @@ class ChoiceSet(metaclass=ChoiceSetMeta):
     CHOICES = list()
     CHOICES = list()
     LEGACY_MAP = dict()
     LEGACY_MAP = dict()
 
 
+    @classmethod
+    def values(cls):
+        return [c[0] for c in cls.CHOICES]
+
     @classmethod
     @classmethod
     def slug_to_id(cls, slug):
     def slug_to_id(cls, slug):
         """
         """

+ 1 - 1
netbox/virtualization/api/serializers.py

@@ -99,7 +99,7 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer):
 
 
 class InterfaceSerializer(TaggitSerializer, ValidatedModelSerializer):
 class InterfaceSerializer(TaggitSerializer, ValidatedModelSerializer):
     virtual_machine = NestedVirtualMachineSerializer()
     virtual_machine = NestedVirtualMachineSerializer()
-    type = ChoiceField(choices=InterfaceTypeChoices, default=InterfaceTypeChoices.TYPE_VIRTUAL, required=False)
+    type = ChoiceField(choices=VMInterfaceTypeChoices, default=VMInterfaceTypeChoices.TYPE_VIRTUAL, required=False)
     mode = ChoiceField(choices=InterfaceModeChoices, required=False, allow_null=True)
     mode = ChoiceField(choices=InterfaceModeChoices, required=False, allow_null=True)
     untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
     untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
     tagged_vlans = SerializedPKRelatedField(
     tagged_vlans = SerializedPKRelatedField(

+ 14 - 0
netbox/virtualization/choices.py

@@ -1,3 +1,4 @@
+from dcim.choices import InterfaceTypeChoices
 from utilities.choices import ChoiceSet
 from utilities.choices import ChoiceSet
 
 
 
 
@@ -22,3 +23,16 @@ class VirtualMachineStatusChoices(ChoiceSet):
         STATUS_ACTIVE: 1,
         STATUS_ACTIVE: 1,
         STATUS_STAGED: 3,
         STATUS_STAGED: 3,
     }
     }
+
+
+#
+# Interface types (for VirtualMachines)
+#
+
+class VMInterfaceTypeChoices(ChoiceSet):
+
+    TYPE_VIRTUAL = InterfaceTypeChoices.TYPE_VIRTUAL
+
+    CHOICES = (
+        (TYPE_VIRTUAL, 'Virtual'),
+    )

+ 5 - 9
netbox/virtualization/forms.py

@@ -2,7 +2,7 @@ from django import forms
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from taggit.forms import TagField
 from taggit.forms import TagField
 
 
-from dcim.choices import InterfaceModeChoices, InterfaceTypeChoices
+from dcim.choices import InterfaceModeChoices
 from dcim.forms import INTERFACE_MODE_HELP_TEXT
 from dcim.forms import INTERFACE_MODE_HELP_TEXT
 from dcim.models import Device, DeviceRole, Interface, Platform, Rack, Region, Site
 from dcim.models import Device, DeviceRole, Interface, Platform, Rack, Region, Site
 from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFilterForm
 from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFilterForm
@@ -18,10 +18,6 @@ from utilities.forms import (
 from .choices import *
 from .choices import *
 from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 
 
-VIFACE_TYPE_CHOICES = (
-    (InterfaceTypeChoices.TYPE_VIRTUAL, 'Virtual'),
-)
-
 
 
 #
 #
 # Cluster types
 # Cluster types
@@ -740,8 +736,8 @@ class InterfaceCreateForm(ComponentForm):
         label='Name'
         label='Name'
     )
     )
     type = forms.ChoiceField(
     type = forms.ChoiceField(
-        choices=VIFACE_TYPE_CHOICES,
-        initial=InterfaceTypeChoices.TYPE_VIRTUAL,
+        choices=VMInterfaceTypeChoices,
+        initial=VMInterfaceTypeChoices.TYPE_VIRTUAL,
         widget=forms.HiddenInput()
         widget=forms.HiddenInput()
     )
     )
     enabled = forms.BooleanField(
     enabled = forms.BooleanField(
@@ -925,8 +921,8 @@ class VirtualMachineBulkAddComponentForm(BootstrapMixin, forms.Form):
 
 
 class VirtualMachineBulkAddInterfaceForm(VirtualMachineBulkAddComponentForm):
 class VirtualMachineBulkAddInterfaceForm(VirtualMachineBulkAddComponentForm):
     type = forms.ChoiceField(
     type = forms.ChoiceField(
-        choices=VIFACE_TYPE_CHOICES,
-        initial=InterfaceTypeChoices.TYPE_VIRTUAL,
+        choices=VMInterfaceTypeChoices,
+        initial=VMInterfaceTypeChoices.TYPE_VIRTUAL,
         widget=forms.HiddenInput()
         widget=forms.HiddenInput()
     )
     )
     enabled = forms.BooleanField(
     enabled = forms.BooleanField(