1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

IPAddress.role to slug (#3569)

This commit is contained in:
Jeremy Stretch
2019-11-27 22:09:16 -05:00
parent ba8f324b12
commit 14a7a33cc2
9 changed files with 104 additions and 56 deletions

View File

@ -202,7 +202,7 @@ class IPAddressSerializer(TaggitSerializer, CustomFieldModelSerializer):
vrf = NestedVRFSerializer(required=False, allow_null=True)
tenant = NestedTenantSerializer(required=False, allow_null=True)
status = ChoiceField(choices=IPAddressStatusChoices, required=False)
role = ChoiceField(choices=IPADDRESS_ROLE_CHOICES, required=False, allow_null=True)
role = ChoiceField(choices=IPAddressRoleChoices, required=False, allow_null=True)
interface = IPAddressInterfaceSerializer(required=False, allow_null=True)
nat_inside = NestedIPAddressSerializer(required=False, allow_null=True)
nat_outside = NestedIPAddressSerializer(read_only=True)

View File

@ -51,3 +51,37 @@ class IPAddressStatusChoices(ChoiceSet):
STATUS_DEPRECATED: 3,
STATUS_DHCP: 5,
}
class IPAddressRoleChoices(ChoiceSet):
ROLE_LOOPBACK = 'loopback'
ROLE_SECONDARY = 'secondary'
ROLE_ANYCAST = 'anycast'
ROLE_VIP = 'vip'
ROLE_VRRP = 'vrrp'
ROLE_HSRP = 'hsrp'
ROLE_GLBP = 'glbp'
ROLE_CARP = 'carp'
CHOICES = (
(ROLE_LOOPBACK, 'Loopback'),
(ROLE_SECONDARY, 'Secondary'),
(ROLE_ANYCAST, 'Anycast'),
(ROLE_VIP, 'VIP'),
(ROLE_VRRP, 'VRRP'),
(ROLE_HSRP, 'HSRP'),
(ROLE_GLBP, 'GLBP'),
(ROLE_CARP, 'CARP'),
)
LEGACY_MAP = {
ROLE_LOOPBACK: 10,
ROLE_SECONDARY: 20,
ROLE_ANYCAST: 30,
ROLE_VIP: 40,
ROLE_VRRP: 41,
ROLE_HSRP: 42,
ROLE_GLBP: 43,
ROLE_CARP: 44,
}

View File

@ -4,36 +4,6 @@ AF_CHOICES = (
(6, 'IPv6'),
)
# IP address roles
IPADDRESS_ROLE_LOOPBACK = 10
IPADDRESS_ROLE_SECONDARY = 20
IPADDRESS_ROLE_ANYCAST = 30
IPADDRESS_ROLE_VIP = 40
IPADDRESS_ROLE_VRRP = 41
IPADDRESS_ROLE_HSRP = 42
IPADDRESS_ROLE_GLBP = 43
IPADDRESS_ROLE_CARP = 44
IPADDRESS_ROLE_CHOICES = (
(IPADDRESS_ROLE_LOOPBACK, 'Loopback'),
(IPADDRESS_ROLE_SECONDARY, 'Secondary'),
(IPADDRESS_ROLE_ANYCAST, 'Anycast'),
(IPADDRESS_ROLE_VIP, 'VIP'),
(IPADDRESS_ROLE_VRRP, 'VRRP'),
(IPADDRESS_ROLE_HSRP, 'HSRP'),
(IPADDRESS_ROLE_GLBP, 'GLBP'),
(IPADDRESS_ROLE_CARP, 'CARP'),
)
IPADDRESS_ROLES_NONUNIQUE = (
# IPAddress roles which are exempt from unique address enforcement
IPADDRESS_ROLE_ANYCAST,
IPADDRESS_ROLE_VIP,
IPADDRESS_ROLE_VRRP,
IPADDRESS_ROLE_HSRP,
IPADDRESS_ROLE_GLBP,
IPADDRESS_ROLE_CARP,
)
# VLAN statuses
VLAN_STATUS_ACTIVE = 1
VLAN_STATUS_RESERVED = 2
@ -53,16 +23,7 @@ STATUS_CHOICE_CLASSES = {
4: 'warning',
5: 'success',
}
ROLE_CHOICE_CLASSES = {
10: 'default',
20: 'primary',
30: 'warning',
40: 'success',
41: 'success',
42: 'success',
43: 'success',
44: 'success',
}
# IP protocols (for services)
IP_PROTOCOL_TCP = 6

View File

@ -315,7 +315,7 @@ class IPAddressFilter(TenancyFilterSet, CustomFieldFilterSet):
null_value=None
)
role = django_filters.MultipleChoiceFilter(
choices=IPADDRESS_ROLE_CHOICES
choices=IPAddressRoleChoices
)
tag = TagFilter()

View File

@ -769,7 +769,7 @@ class IPAddressCSVForm(forms.ModelForm):
help_text='Operational status'
)
role = CSVChoiceField(
choices=IPADDRESS_ROLE_CHOICES,
choices=IPAddressRoleChoices,
required=False,
help_text='Functional role'
)
@ -899,7 +899,7 @@ class IPAddressBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
widget=StaticSelect2()
)
role = forms.ChoiceField(
choices=add_blank_choice(IPADDRESS_ROLE_CHOICES),
choices=add_blank_choice(IPAddressRoleChoices),
required=False,
widget=StaticSelect2()
)
@ -978,7 +978,7 @@ class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterFo
widget=StaticSelect2Multiple()
)
role = forms.MultipleChoiceField(
choices=IPADDRESS_ROLE_CHOICES,
choices=IPAddressRoleChoices,
required=False,
widget=StaticSelect2Multiple()
)

View File

@ -8,6 +8,17 @@ IPADDRESS_STATUS_CHOICES = (
(3, 'deprecated'),
)
IPADDRESS_ROLE_CHOICES = (
(10, 'loopback'),
(20, 'secondary'),
(30, 'anycast'),
(40, 'vip'),
(41, 'vrrp'),
(42, 'hsrp'),
(43, 'glbp'),
(44, 'carp'),
)
def ipaddress_status_to_slug(apps, schema_editor):
IPAddress = apps.get_model('ipam', 'IPAddress')
@ -15,6 +26,12 @@ def ipaddress_status_to_slug(apps, schema_editor):
IPAddress.objects.filter(status=str(id)).update(status=slug)
def ipaddress_role_to_slug(apps, schema_editor):
IPAddress = apps.get_model('ipam', 'IPAddress')
for id, slug in IPADDRESS_STATUS_CHOICES:
IPAddress.objects.filter(role=str(id)).update(role=slug)
class Migration(migrations.Migration):
atomic = False
@ -34,4 +51,19 @@ class Migration(migrations.Migration):
code=ipaddress_status_to_slug
),
# IPAddress.role
migrations.AlterField(
model_name='ipaddress',
name='role',
field=models.CharField(blank=True, default='', max_length=50),
),
migrations.RunPython(
code=ipaddress_role_to_slug
),
migrations.AlterField(
model_name='ipaddress',
name='role',
field=models.CharField(blank=True, max_length=50),
),
]

View File

@ -21,6 +21,17 @@ from .querysets import PrefixQuerySet
from .validators import DNSValidator
IPADDRESS_ROLES_NONUNIQUE = (
# IPAddress roles which are exempt from unique address enforcement
IPAddressRoleChoices.ROLE_ANYCAST,
IPAddressRoleChoices.ROLE_VIP,
IPAddressRoleChoices.ROLE_VRRP,
IPAddressRoleChoices.ROLE_HSRP,
IPAddressRoleChoices.ROLE_GLBP,
IPAddressRoleChoices.ROLE_CARP,
)
class VRF(ChangeLoggedModel, CustomFieldModel):
"""
A virtual routing and forwarding (VRF) table represents a discrete layer three forwarding domain (e.g. a routing
@ -565,11 +576,10 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
default=IPAddressStatusChoices.STATUS_ACTIVE,
help_text='The operational status of this IP'
)
role = models.PositiveSmallIntegerField(
verbose_name='Role',
choices=IPADDRESS_ROLE_CHOICES,
role = models.CharField(
max_length=50,
choices=IPAddressRoleChoices,
blank=True,
null=True,
help_text='The functional role of this IP'
)
interface = models.ForeignKey(
@ -620,6 +630,17 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
'dhcp': 'success',
}
ROLE_CLASS_MAP = {
'loopback': 'default',
'secondary': 'primary',
'anycast': 'warning',
'vip': 'success',
'vrrp': 'success',
'hsrp': 'success',
'glbp': 'success',
'carp': 'success',
}
class Meta:
ordering = ['family', 'address']
verbose_name = 'IP address'
@ -756,7 +777,7 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
return self.STATUS_CLASS_MAP.get(self.status)
def get_role_class(self):
return ROLE_CHOICE_CLASSES[self.role]
return self.ROLE_CLASS_MAP[self.role]
class VLANGroup(ChangeLoggedModel):

View File

@ -2,7 +2,7 @@ import netaddr
from django.core.exceptions import ValidationError
from django.test import TestCase, override_settings
from ipam.constants import IPADDRESS_ROLE_VIP
from ipam.choices import IPAddressRoleChoices
from ipam.models import IPAddress, Prefix, VRF
@ -61,5 +61,5 @@ class TestIPAddress(TestCase):
@override_settings(ENFORCE_GLOBAL_UNIQUE=True)
def test_duplicate_nonunique_role(self):
IPAddress.objects.create(address=netaddr.IPNetwork('192.0.2.1/24'), role=IPADDRESS_ROLE_VIP)
IPAddress.objects.create(address=netaddr.IPNetwork('192.0.2.1/24'), role=IPADDRESS_ROLE_VIP)
IPAddress.objects.create(address=netaddr.IPNetwork('192.0.2.1/24'), role=IPAddressRoleChoices.ROLE_VIP)
IPAddress.objects.create(address=netaddr.IPNetwork('192.0.2.1/24'), role=IPAddressRoleChoices.ROLE_VIP)

View File

@ -14,7 +14,7 @@ from utilities.views import (
)
from virtualization.models import VirtualMachine
from . import filters, forms, tables
from .choices import PrefixStatusChoices
from .choices import *
from .constants import *
from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
@ -666,8 +666,8 @@ class IPAddressView(PermissionRequiredMixin, View):
'nat_inside', 'interface__device'
)
# Exclude anycast IPs if this IP is anycast
if ipaddress.role == IPADDRESS_ROLE_ANYCAST:
duplicate_ips = duplicate_ips.exclude(role=IPADDRESS_ROLE_ANYCAST)
if ipaddress.role == IPAddressRoleChoices.ROLE_ANYCAST:
duplicate_ips = duplicate_ips.exclude(role=IPAddressRoleChoices.ROLE_ANYCAST)
duplicate_ips_table = tables.IPAddressTable(list(duplicate_ips), orderable=False)
# Related IP table