Skip to content

Commit

Permalink
implements netbox-community#150 - inteface vlan tagging
Browse files Browse the repository at this point in the history
  • Loading branch information
lampwins committed Oct 13, 2017
1 parent 34259d5 commit 2335b90
Show file tree
Hide file tree
Showing 9 changed files with 434 additions and 59 deletions.
44 changes: 42 additions & 2 deletions netbox/dcim/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator

from ipam.models import IPAddress
from ipam.models import IPAddress, VLAN
from circuits.models import Circuit, CircuitTermination
from dcim.constants import *
from dcim.models import (
CONNECTION_STATUS_CHOICES, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device,
DeviceBay, DeviceBayTemplate, DeviceType, DeviceRole, IFACE_FF_CHOICES, IFACE_ORDERING_CHOICES, Interface,
Expand Down Expand Up @@ -624,19 +625,31 @@ class Meta:
]


# Cannot import ipam.api.NestedVLANSerializer due to circular dependency
class InterfaceVLANSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlan-detail')

class Meta:
model = VLAN
fields = ['id', 'url', 'vid', 'name', 'display_name']


class InterfaceSerializer(serializers.ModelSerializer):
device = NestedDeviceSerializer()
form_factor = ChoiceFieldSerializer(choices=IFACE_FF_CHOICES)
lag = NestedInterfaceSerializer()
is_connected = serializers.SerializerMethodField(read_only=True)
interface_connection = serializers.SerializerMethodField(read_only=True)
circuit_termination = InterfaceCircuitTerminationSerializer()
untagged_vlan = InterfaceVLANSerializer()
mode = ChoiceFieldSerializer(choices=IFACE_MODE_CHOICES)
tagged_vlans = InterfaceVLANSerializer(many=True)

class Meta:
model = Interface
fields = [
'id', 'device', 'name', 'form_factor', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only', 'description',
'is_connected', 'interface_connection', 'circuit_termination',
'is_connected', 'interface_connection', 'circuit_termination', 'mode', 'untagged_vlan', 'tagged_vlans',
]

def get_is_connected(self, obj):
Expand Down Expand Up @@ -681,8 +694,35 @@ class Meta:
model = Interface
fields = [
'id', 'device', 'name', 'form_factor', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only', 'description',
'mode', 'untagged_vlan', 'tagged_vlans',
]

def validate(self, data):

# Get the device for later use
if self.instance:
device = self.instance.device
else:
device = data.get('device')

# Validate VLANs belong to the device's site or global
# We have to do this here decause of the ManyToMany relationship
native_vlan = data.get('native_vlan')
if native_vlan:
if native_vlan.site != device.site and native_vlan.site is not None:
raise serializers.ValidationError("Native VLAN is invalid for the interface's device.")

tagged_vlan_members = data.get('tagged_vlan_members')
if tagged_vlan_members:
for vlan in tagged_vlan_members:
if vlan.site != device.site and vlan.site is not None:
raise serializers.ValidationError("Tagged VLAN {} is invalid for the interface's device.".format(vlan))

# Enforce model validation
super(WritableInterfaceSerializer, self).validate(data)

return data


#
# Device bays
Expand Down
9 changes: 9 additions & 0 deletions netbox/dcim/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,15 @@

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'],
]

# Device statuses
STATUS_OFFLINE = 0
STATUS_ACTIVE = 1
Expand Down
Loading

0 comments on commit 2335b90

Please sign in to comment.