Interface.mode to slug (#3569)

This commit is contained in:
Jeremy Stretch 2019-11-21 22:39:15 -05:00
parent f93cd17fee
commit 3fa4ceadb0
10 changed files with 76 additions and 46 deletions

View File

@ -469,7 +469,7 @@ class InterfaceSerializer(TaggitSerializer, ConnectedEndpointSerializer):
device = NestedDeviceSerializer() device = NestedDeviceSerializer()
type = ChoiceField(choices=InterfaceTypeChoices, required=False) type = ChoiceField(choices=InterfaceTypeChoices, required=False)
lag = NestedInterfaceSerializer(required=False, allow_null=True) lag = NestedInterfaceSerializer(required=False, allow_null=True)
mode = ChoiceField(choices=IFACE_MODE_CHOICES, 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(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),

View File

@ -111,9 +111,7 @@ class DeviceFaceChoices(ChoiceSet):
# #
class ConsolePortTypeChoices(ChoiceSet): class ConsolePortTypeChoices(ChoiceSet):
"""
ConsolePort/ConsoleServerPort.type slugs
"""
TYPE_DE9 = 'de-9' TYPE_DE9 = 'de-9'
TYPE_DB25 = 'db-25' TYPE_DB25 = 'db-25'
TYPE_RJ45 = 'rj-45' TYPE_RJ45 = 'rj-45'
@ -152,6 +150,7 @@ class ConsolePortTypeChoices(ChoiceSet):
# #
class PowerPortTypeChoices(ChoiceSet): class PowerPortTypeChoices(ChoiceSet):
# TODO: Add more power port types # TODO: Add more power port types
# IEC 60320 # IEC 60320
TYPE_IEC_C6 = 'iec-60320-c6' TYPE_IEC_C6 = 'iec-60320-c6'
@ -239,6 +238,7 @@ class PowerPortTypeChoices(ChoiceSet):
# #
class PowerOutletTypeChoices(ChoiceSet): class PowerOutletTypeChoices(ChoiceSet):
# TODO: Add more power outlet types # TODO: Add more power outlet types
# IEC 60320 # IEC 60320
TYPE_IEC_C5 = 'iec-60320-c5' TYPE_IEC_C5 = 'iec-60320-c5'
@ -326,9 +326,7 @@ class PowerOutletTypeChoices(ChoiceSet):
# #
class InterfaceTypeChoices(ChoiceSet): class InterfaceTypeChoices(ChoiceSet):
"""
Interface.type slugs
"""
# Virtual # Virtual
TYPE_VIRTUAL = 'virtual' TYPE_VIRTUAL = 'virtual'
TYPE_LAG = 'lag' TYPE_LAG = 'lag'
@ -623,14 +621,31 @@ class InterfaceTypeChoices(ChoiceSet):
} }
class InterfaceModeChoices(ChoiceSet):
MODE_ACCESS = 'access'
MODE_TAGGED = 'tagged'
MODE_TAGGED_ALL = 'tagged-all'
CHOICES = (
(MODE_ACCESS, 'Access'),
(MODE_TAGGED, 'Tagged'),
(MODE_TAGGED_ALL, 'Tagged (All)'),
)
LEGACY_MAP = {
MODE_ACCESS: 100,
MODE_TAGGED: 200,
MODE_TAGGED_ALL: 300,
}
# #
# FrontPorts/RearPorts # FrontPorts/RearPorts
# #
class PortTypeChoices(ChoiceSet): class PortTypeChoices(ChoiceSet):
"""
FrontPort/RearPort.type slugs
"""
TYPE_8P8C = '8p8c' TYPE_8P8C = '8p8c'
TYPE_110_PUNCH = '110-punch' TYPE_110_PUNCH = '110-punch'
TYPE_BNC = 'bnc' TYPE_BNC = 'bnc'

View File

@ -20,14 +20,6 @@ WIRELESS_IFACE_TYPES = [
NONCONNECTABLE_IFACE_TYPES = VIRTUAL_IFACE_TYPES + WIRELESS_IFACE_TYPES NONCONNECTABLE_IFACE_TYPES = VIRTUAL_IFACE_TYPES + WIRELESS_IFACE_TYPES
IFACE_MODE_ACCESS = 100
IFACE_MODE_TAGGED = 200
IFACE_MODE_TAGGED_ALL = 300
IFACE_MODE_CHOICES = [
[IFACE_MODE_ACCESS, 'Access'],
[IFACE_MODE_TAGGED, 'Tagged'],
[IFACE_MODE_TAGGED_ALL, 'Tagged All'],
]
# Pass-through port types # Pass-through port types
PORT_TYPE_8P8C = 1000 PORT_TYPE_8P8C = 1000

View File

@ -66,13 +66,13 @@ class InterfaceCommonForm:
tagged_vlans = self.cleaned_data['tagged_vlans'] tagged_vlans = self.cleaned_data['tagged_vlans']
# Untagged interfaces cannot be assigned tagged VLANs # Untagged interfaces cannot be assigned tagged VLANs
if self.cleaned_data['mode'] == IFACE_MODE_ACCESS and tagged_vlans: if self.cleaned_data['mode'] == InterfaceModeChoices.MODE_ACCESS and tagged_vlans:
raise forms.ValidationError({ raise forms.ValidationError({
'mode': "An access interface cannot have tagged VLANs assigned." 'mode': "An access interface cannot have tagged VLANs assigned."
}) })
# Remove all tagged VLAN assignments from "tagged all" interfaces # Remove all tagged VLAN assignments from "tagged all" interfaces
elif self.cleaned_data['mode'] == IFACE_MODE_TAGGED_ALL: elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED_ALL:
self.cleaned_data['tagged_vlans'] = [] self.cleaned_data['tagged_vlans'] = []
@ -2450,7 +2450,7 @@ class InterfaceCreateForm(InterfaceCommonForm, ComponentForm, forms.Form):
required=False required=False
) )
mode = forms.ChoiceField( mode = forms.ChoiceField(
choices=add_blank_choice(IFACE_MODE_CHOICES), choices=add_blank_choice(InterfaceModeChoices),
required=False, required=False,
widget=StaticSelect2(), widget=StaticSelect2(),
) )
@ -2564,7 +2564,7 @@ class InterfaceBulkEditForm(InterfaceCommonForm, BootstrapMixin, AddRemoveTagsFo
required=False required=False
) )
mode = forms.ChoiceField( mode = forms.ChoiceField(
choices=add_blank_choice(IFACE_MODE_CHOICES), choices=add_blank_choice(InterfaceModeChoices),
required=False, required=False,
widget=StaticSelect2() widget=StaticSelect2()
) )

View File

@ -75,6 +75,13 @@ INTERFACE_TYPE_CHOICES = (
) )
INTERFACE_MODE_CHOICES = (
(100, 'access'),
(200, 'tagged'),
(300, 'tagged-all'),
)
def interfacetemplate_type_to_slug(apps, schema_editor): def interfacetemplate_type_to_slug(apps, schema_editor):
InterfaceTemplate = apps.get_model('dcim', 'InterfaceTemplate') InterfaceTemplate = apps.get_model('dcim', 'InterfaceTemplate')
for id, slug in INTERFACE_TYPE_CHOICES: for id, slug in INTERFACE_TYPE_CHOICES:
@ -87,6 +94,12 @@ def interface_type_to_slug(apps, schema_editor):
Interface.objects.filter(type=id).update(type=slug) Interface.objects.filter(type=id).update(type=slug)
def interface_mode_to_slug(apps, schema_editor):
Interface = apps.get_model('dcim', 'Interface')
for id, slug in INTERFACE_MODE_CHOICES:
Interface.objects.filter(mode=id).update(mode=slug)
class Migration(migrations.Migration): class Migration(migrations.Migration):
atomic = False atomic = False
@ -111,4 +124,17 @@ class Migration(migrations.Migration):
migrations.RunPython( migrations.RunPython(
code=interface_type_to_slug code=interface_type_to_slug
), ),
migrations.AlterField(
model_name='interface',
name='mode',
field=models.CharField(blank=True, default='', max_length=50),
),
migrations.RunPython(
code=interface_mode_to_slug
),
migrations.AlterField(
model_name='interface',
name='mode',
field=models.CharField(blank=True, max_length=50),
),
] ]

View File

@ -2261,10 +2261,10 @@ class Interface(CableTermination, ComponentModel):
verbose_name='OOB Management', verbose_name='OOB Management',
help_text='This interface is used only for out-of-band management' help_text='This interface is used only for out-of-band management'
) )
mode = models.PositiveSmallIntegerField( mode = models.CharField(
choices=IFACE_MODE_CHOICES, max_length=50,
choices=InterfaceModeChoices,
blank=True, blank=True,
null=True
) )
untagged_vlan = models.ForeignKey( untagged_vlan = models.ForeignKey(
to='ipam.VLAN', to='ipam.VLAN',
@ -2373,7 +2373,7 @@ class Interface(CableTermination, ComponentModel):
self.untagged_vlan = None self.untagged_vlan = None
# Only "tagged" interfaces may have tagged VLANs assigned. ("tagged all" implies all VLANs are assigned.) # Only "tagged" interfaces may have tagged VLANs assigned. ("tagged all" implies all VLANs are assigned.)
if self.pk and self.mode is not IFACE_MODE_TAGGED: if self.pk and self.mode is not InterfaceModeChoices.MODE_TAGGED:
self.tagged_vlans.clear() self.tagged_vlans.clear()
return super().save(*args, **kwargs) return super().save(*args, **kwargs)

View File

@ -3,7 +3,7 @@ from netaddr import IPNetwork
from rest_framework import status from rest_framework import status
from circuits.models import Circuit, CircuitTermination, CircuitType, Provider from circuits.models import Circuit, CircuitTermination, CircuitType, Provider
from dcim.choices import SubdeviceRoleChoices from dcim.choices import InterfaceModeChoices, SubdeviceRoleChoices
from dcim.constants import * from dcim.constants import *
from dcim.models import ( from dcim.models import (
Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay, Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
@ -2474,7 +2474,7 @@ class InterfaceTest(APITestCase):
data = { data = {
'device': self.device.pk, 'device': self.device.pk,
'name': 'Test Interface 4', 'name': 'Test Interface 4',
'mode': IFACE_MODE_TAGGED, 'mode': InterfaceModeChoices.MODE_TAGGED,
'untagged_vlan': self.vlan3.id, 'untagged_vlan': self.vlan3.id,
'tagged_vlans': [self.vlan1.id, self.vlan2.id], 'tagged_vlans': [self.vlan1.id, self.vlan2.id],
} }
@ -2521,21 +2521,21 @@ class InterfaceTest(APITestCase):
{ {
'device': self.device.pk, 'device': self.device.pk,
'name': 'Test Interface 4', 'name': 'Test Interface 4',
'mode': IFACE_MODE_TAGGED, 'mode': InterfaceModeChoices.MODE_TAGGED,
'untagged_vlan': self.vlan2.id, 'untagged_vlan': self.vlan2.id,
'tagged_vlans': [self.vlan1.id], 'tagged_vlans': [self.vlan1.id],
}, },
{ {
'device': self.device.pk, 'device': self.device.pk,
'name': 'Test Interface 5', 'name': 'Test Interface 5',
'mode': IFACE_MODE_TAGGED, 'mode': InterfaceModeChoices.MODE_TAGGED,
'untagged_vlan': self.vlan2.id, 'untagged_vlan': self.vlan2.id,
'tagged_vlans': [self.vlan1.id], 'tagged_vlans': [self.vlan1.id],
}, },
{ {
'device': self.device.pk, 'device': self.device.pk,
'name': 'Test Interface 6', 'name': 'Test Interface 6',
'mode': IFACE_MODE_TAGGED, 'mode': InterfaceModeChoices.MODE_TAGGED,
'untagged_vlan': self.vlan2.id, 'untagged_vlan': self.vlan2.id,
'tagged_vlans': [self.vlan1.id], 'tagged_vlans': [self.vlan1.id],
}, },

View File

@ -3,8 +3,7 @@ from rest_framework import serializers
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
from dcim.api.nested_serializers import NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer from dcim.api.nested_serializers import NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer
from dcim.choices import InterfaceTypeChoices from dcim.choices import InterfaceModeChoices, InterfaceTypeChoices
from dcim.constants import IFACE_MODE_CHOICES
from dcim.models import Interface from dcim.models import Interface
from extras.api.customfields import CustomFieldModelSerializer from extras.api.customfields import CustomFieldModelSerializer
from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer
@ -100,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=InterfaceTypeChoices, default=InterfaceTypeChoices.TYPE_VIRTUAL, required=False)
mode = ChoiceField(choices=IFACE_MODE_CHOICES, 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(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),

View File

@ -2,8 +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 InterfaceTypeChoices from dcim.choices import InterfaceModeChoices, InterfaceTypeChoices
from dcim.constants import IFACE_MODE_ACCESS, IFACE_MODE_TAGGED_ALL, IFACE_MODE_CHOICES
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
@ -718,13 +717,13 @@ class InterfaceForm(BootstrapMixin, forms.ModelForm):
tagged_vlans = self.cleaned_data['tagged_vlans'] tagged_vlans = self.cleaned_data['tagged_vlans']
# Untagged interfaces cannot be assigned tagged VLANs # Untagged interfaces cannot be assigned tagged VLANs
if self.cleaned_data['mode'] == IFACE_MODE_ACCESS and tagged_vlans: if self.cleaned_data['mode'] == InterfaceModeChoices.MODE_ACCESS and tagged_vlans:
raise forms.ValidationError({ raise forms.ValidationError({
'mode': "An access interface cannot have tagged VLANs assigned." 'mode': "An access interface cannot have tagged VLANs assigned."
}) })
# Remove all tagged VLAN assignments from "tagged all" interfaces # Remove all tagged VLAN assignments from "tagged all" interfaces
elif self.cleaned_data['mode'] == IFACE_MODE_TAGGED_ALL: elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED_ALL:
self.cleaned_data['tagged_vlans'] = [] self.cleaned_data['tagged_vlans'] = []
@ -755,7 +754,7 @@ class InterfaceCreateForm(ComponentForm):
required=False required=False
) )
mode = forms.ChoiceField( mode = forms.ChoiceField(
choices=add_blank_choice(IFACE_MODE_CHOICES), choices=add_blank_choice(InterfaceModeChoices),
required=False, required=False,
widget=StaticSelect2(), widget=StaticSelect2(),
) )
@ -840,7 +839,7 @@ class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm):
required=False required=False
) )
mode = forms.ChoiceField( mode = forms.ChoiceField(
choices=add_blank_choice(IFACE_MODE_CHOICES), choices=add_blank_choice(InterfaceModeChoices),
required=False, required=False,
widget=StaticSelect2() widget=StaticSelect2()
) )

View File

@ -2,8 +2,7 @@ from django.urls import reverse
from netaddr import IPNetwork from netaddr import IPNetwork
from rest_framework import status from rest_framework import status
from dcim.choices import InterfaceTypeChoices from dcim.choices import InterfaceModeChoices, InterfaceTypeChoices
from dcim.constants import IFACE_MODE_TAGGED
from dcim.models import Interface from dcim.models import Interface
from ipam.models import IPAddress, VLAN from ipam.models import IPAddress, VLAN
from utilities.testing import APITestCase from utilities.testing import APITestCase
@ -552,7 +551,7 @@ class InterfaceTest(APITestCase):
data = { data = {
'virtual_machine': self.virtualmachine.pk, 'virtual_machine': self.virtualmachine.pk,
'name': 'Test Interface 4', 'name': 'Test Interface 4',
'mode': IFACE_MODE_TAGGED, 'mode': InterfaceModeChoices.MODE_TAGGED,
'untagged_vlan': self.vlan3.id, 'untagged_vlan': self.vlan3.id,
'tagged_vlans': [self.vlan1.id, self.vlan2.id], 'tagged_vlans': [self.vlan1.id, self.vlan2.id],
} }
@ -599,21 +598,21 @@ class InterfaceTest(APITestCase):
{ {
'virtual_machine': self.virtualmachine.pk, 'virtual_machine': self.virtualmachine.pk,
'name': 'Test Interface 4', 'name': 'Test Interface 4',
'mode': IFACE_MODE_TAGGED, 'mode': InterfaceModeChoices.MODE_TAGGED,
'untagged_vlan': self.vlan2.id, 'untagged_vlan': self.vlan2.id,
'tagged_vlans': [self.vlan1.id], 'tagged_vlans': [self.vlan1.id],
}, },
{ {
'virtual_machine': self.virtualmachine.pk, 'virtual_machine': self.virtualmachine.pk,
'name': 'Test Interface 5', 'name': 'Test Interface 5',
'mode': IFACE_MODE_TAGGED, 'mode': InterfaceModeChoices.MODE_TAGGED,
'untagged_vlan': self.vlan2.id, 'untagged_vlan': self.vlan2.id,
'tagged_vlans': [self.vlan1.id], 'tagged_vlans': [self.vlan1.id],
}, },
{ {
'virtual_machine': self.virtualmachine.pk, 'virtual_machine': self.virtualmachine.pk,
'name': 'Test Interface 6', 'name': 'Test Interface 6',
'mode': IFACE_MODE_TAGGED, 'mode': InterfaceModeChoices.MODE_TAGGED,
'untagged_vlan': self.vlan2.id, 'untagged_vlan': self.vlan2.id,
'tagged_vlans': [self.vlan1.id], 'tagged_vlans': [self.vlan1.id],
}, },