mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Fixes #3868: Fix creation of interfaces for virtual machines
This commit is contained in:
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
@ -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(
|
||||||
|
@ -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'),
|
||||||
|
)
|
||||||
|
@ -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,
|
choices=VMInterfaceTypeChoices,
|
||||||
initial=InterfaceTypeChoices.TYPE_VIRTUAL,
|
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,
|
choices=VMInterfaceTypeChoices,
|
||||||
initial=InterfaceTypeChoices.TYPE_VIRTUAL,
|
initial=VMInterfaceTypeChoices.TYPE_VIRTUAL,
|
||||||
widget=forms.HiddenInput()
|
widget=forms.HiddenInput()
|
||||||
)
|
)
|
||||||
enabled = forms.BooleanField(
|
enabled = forms.BooleanField(
|
||||||
|
Reference in New Issue
Block a user