From f7103353611b75f0c9712e027dbd44abb2910d5d Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 27 Nov 2019 22:27:06 -0500 Subject: [PATCH] Service.protocol to slug (#3569) --- netbox/ipam/api/serializers.py | 5 ++- netbox/ipam/choices.py | 20 +++++++++++ netbox/ipam/constants.py | 14 -------- netbox/ipam/filters.py | 1 - netbox/ipam/forms.py | 5 ++- .../migrations/0031_3569_service_fields.py | 35 +++++++++++++++++++ netbox/ipam/models.py | 12 +++++-- netbox/ipam/tests/test_api.py | 18 +++++----- netbox/ipam/tests/test_views.py | 8 ++--- netbox/ipam/views.py | 1 - 10 files changed, 81 insertions(+), 38 deletions(-) delete mode 100644 netbox/ipam/constants.py create mode 100644 netbox/ipam/migrations/0031_3569_service_fields.py diff --git a/netbox/ipam/api/serializers.py b/netbox/ipam/api/serializers.py index 7aeb37a45..5ebc52390 100644 --- a/netbox/ipam/api/serializers.py +++ b/netbox/ipam/api/serializers.py @@ -9,8 +9,7 @@ from dcim.api.nested_serializers import NestedDeviceSerializer, NestedSiteSerial from dcim.models import Interface from extras.api.customfields import CustomFieldModelSerializer from ipam.choices import * -from ipam.constants import * -from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF +from ipam.models import AF_CHOICES, Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF from tenancy.api.nested_serializers import NestedTenantSerializer from utilities.api import ( ChoiceField, SerializedPKRelatedField, ValidatedModelSerializer, WritableNestedSerializer, @@ -240,7 +239,7 @@ class AvailableIPSerializer(serializers.Serializer): class ServiceSerializer(CustomFieldModelSerializer): device = NestedDeviceSerializer(required=False, allow_null=True) virtual_machine = NestedVirtualMachineSerializer(required=False, allow_null=True) - protocol = ChoiceField(choices=IP_PROTOCOL_CHOICES) + protocol = ChoiceField(choices=ServiceProtocolChoices) ipaddresses = SerializedPKRelatedField( queryset=IPAddress.objects.all(), serializer=NestedIPAddressSerializer, diff --git a/netbox/ipam/choices.py b/netbox/ipam/choices.py index 840a9d8df..543608b33 100644 --- a/netbox/ipam/choices.py +++ b/netbox/ipam/choices.py @@ -108,3 +108,23 @@ class VLANStatusChoices(ChoiceSet): STATUS_RESERVED: 2, STATUS_DEPRECATED: 3, } + + +# +# VLANs +# + +class ServiceProtocolChoices(ChoiceSet): + + PROTOCOL_TCP = 'tcp' + PROTOCOL_UDP = 'udp' + + CHOICES = ( + (PROTOCOL_TCP, 'TCP'), + (PROTOCOL_UDP, 'UDP'), + ) + + LEGACY_MAP = { + PROTOCOL_TCP: 6, + PROTOCOL_UDP: 17, + } diff --git a/netbox/ipam/constants.py b/netbox/ipam/constants.py deleted file mode 100644 index e68213550..000000000 --- a/netbox/ipam/constants.py +++ /dev/null @@ -1,14 +0,0 @@ -# IP address families -AF_CHOICES = ( - (4, 'IPv4'), - (6, 'IPv6'), -) - - -# IP protocols (for services) -IP_PROTOCOL_TCP = 6 -IP_PROTOCOL_UDP = 17 -IP_PROTOCOL_CHOICES = ( - (IP_PROTOCOL_TCP, 'TCP'), - (IP_PROTOCOL_UDP, 'UDP'), -) diff --git a/netbox/ipam/filters.py b/netbox/ipam/filters.py index 148b40269..341962ad4 100644 --- a/netbox/ipam/filters.py +++ b/netbox/ipam/filters.py @@ -10,7 +10,6 @@ from tenancy.filtersets import TenancyFilterSet from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter from virtualization.models import VirtualMachine from .choices import * -from .constants import * from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index bacfbfcff..07fed4f2f 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -14,7 +14,6 @@ from utilities.forms import ( ) from virtualization.models import VirtualMachine from .choices import * -from .constants import * from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF IP_FAMILY_CHOICES = [ @@ -1293,7 +1292,7 @@ class ServiceFilterForm(BootstrapMixin, CustomFieldFilterForm): label='Search' ) protocol = forms.ChoiceField( - choices=add_blank_choice(IP_PROTOCOL_CHOICES), + choices=add_blank_choice(ServiceProtocolChoices), required=False, widget=StaticSelect2Multiple() ) @@ -1308,7 +1307,7 @@ class ServiceBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm): widget=forms.MultipleHiddenInput() ) protocol = forms.ChoiceField( - choices=add_blank_choice(IP_PROTOCOL_CHOICES), + choices=add_blank_choice(ServiceProtocolChoices), required=False, widget=StaticSelect2() ) diff --git a/netbox/ipam/migrations/0031_3569_service_fields.py b/netbox/ipam/migrations/0031_3569_service_fields.py new file mode 100644 index 000000000..f06d9ff84 --- /dev/null +++ b/netbox/ipam/migrations/0031_3569_service_fields.py @@ -0,0 +1,35 @@ +from django.db import migrations, models + + +SERVICE_PROTOCOL_CHOICES = ( + (6, 'tcp'), + (17, 'udp'), +) + + +def service_protocol_to_slug(apps, schema_editor): + Service = apps.get_model('ipam', 'Service') + for id, slug in SERVICE_PROTOCOL_CHOICES: + Service.objects.filter(protocol=str(id)).update(protocol=slug) + + +class Migration(migrations.Migration): + atomic = False + + dependencies = [ + ('ipam', '0030_3569_vlan_fields'), + ] + + operations = [ + + # Service.protocol + migrations.AlterField( + model_name='service', + name='protocol', + field=models.CharField(max_length=50), + ), + migrations.RunPython( + code=service_protocol_to_slug + ), + + ] diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index 00d9f5387..79a6f48ad 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -15,12 +15,17 @@ from utilities.models import ChangeLoggedModel from utilities.utils import serialize_object from virtualization.models import VirtualMachine from .choices import * -from .constants import * from .fields import IPNetworkField, IPAddressField from .querysets import PrefixQuerySet from .validators import DNSValidator +# IP address families +AF_CHOICES = ( + (4, 'IPv4'), + (6, 'IPv6'), +) + IPADDRESS_ROLES_NONUNIQUE = ( # IPAddress roles which are exempt from unique address enforcement IPAddressRoleChoices.ROLE_ANYCAST, @@ -975,8 +980,9 @@ class Service(ChangeLoggedModel, CustomFieldModel): name = models.CharField( max_length=30 ) - protocol = models.PositiveSmallIntegerField( - choices=IP_PROTOCOL_CHOICES + protocol = models.CharField( + max_length=50, + choices=ServiceProtocolChoices ) port = models.PositiveIntegerField( validators=[MinValueValidator(1), MaxValueValidator(65535)], diff --git a/netbox/ipam/tests/test_api.py b/netbox/ipam/tests/test_api.py index 29368090e..988eea0f3 100644 --- a/netbox/ipam/tests/test_api.py +++ b/netbox/ipam/tests/test_api.py @@ -5,7 +5,7 @@ from netaddr import IPNetwork from rest_framework import status from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site -from ipam.constants import IP_PROTOCOL_TCP, IP_PROTOCOL_UDP +from ipam.choices import ServiceProtocolChoices from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF from utilities.testing import APITestCase @@ -996,13 +996,13 @@ class ServiceTest(APITestCase): name='Test Device 2', site=site, device_type=devicetype, device_role=devicerole ) self.service1 = Service.objects.create( - device=self.device1, name='Test Service 1', protocol=IP_PROTOCOL_TCP, port=1 + device=self.device1, name='Test Service 1', protocol=ServiceProtocolChoices.PROTOCOL_TCP, port=1 ) self.service1 = Service.objects.create( - device=self.device1, name='Test Service 2', protocol=IP_PROTOCOL_TCP, port=2 + device=self.device1, name='Test Service 2', protocol=ServiceProtocolChoices.PROTOCOL_TCP, port=2 ) self.service1 = Service.objects.create( - device=self.device1, name='Test Service 3', protocol=IP_PROTOCOL_TCP, port=3 + device=self.device1, name='Test Service 3', protocol=ServiceProtocolChoices.PROTOCOL_TCP, port=3 ) def test_get_service(self): @@ -1024,7 +1024,7 @@ class ServiceTest(APITestCase): data = { 'device': self.device1.pk, 'name': 'Test Service 4', - 'protocol': IP_PROTOCOL_TCP, + 'protocol': ServiceProtocolChoices.PROTOCOL_TCP, 'port': 4, } @@ -1045,19 +1045,19 @@ class ServiceTest(APITestCase): { 'device': self.device1.pk, 'name': 'Test Service 4', - 'protocol': IP_PROTOCOL_TCP, + 'protocol': ServiceProtocolChoices.PROTOCOL_TCP, 'port': 4, }, { 'device': self.device1.pk, 'name': 'Test Service 5', - 'protocol': IP_PROTOCOL_TCP, + 'protocol': ServiceProtocolChoices.PROTOCOL_TCP, 'port': 5, }, { 'device': self.device1.pk, 'name': 'Test Service 6', - 'protocol': IP_PROTOCOL_TCP, + 'protocol': ServiceProtocolChoices.PROTOCOL_TCP, 'port': 6, }, ] @@ -1076,7 +1076,7 @@ class ServiceTest(APITestCase): data = { 'device': self.device2.pk, 'name': 'Test Service X', - 'protocol': IP_PROTOCOL_UDP, + 'protocol': ServiceProtocolChoices.PROTOCOL_UDP, 'port': 99, } diff --git a/netbox/ipam/tests/test_views.py b/netbox/ipam/tests/test_views.py index e14a257d6..e6780c798 100644 --- a/netbox/ipam/tests/test_views.py +++ b/netbox/ipam/tests/test_views.py @@ -5,7 +5,7 @@ from django.test import Client, TestCase from django.urls import reverse from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site -from ipam.constants import IP_PROTOCOL_TCP +from ipam.choices import ServiceProtocolChoices from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF from utilities.testing import create_test_user @@ -264,9 +264,9 @@ class ServiceTestCase(TestCase): device.save() Service.objects.bulk_create([ - Service(device=device, name='Service 1', protocol=IP_PROTOCOL_TCP, port=101), - Service(device=device, name='Service 2', protocol=IP_PROTOCOL_TCP, port=102), - Service(device=device, name='Service 3', protocol=IP_PROTOCOL_TCP, port=103), + Service(device=device, name='Service 1', protocol=ServiceProtocolChoices.PROTOCOL_TCP, port=101), + Service(device=device, name='Service 2', protocol=ServiceProtocolChoices.PROTOCOL_TCP, port=102), + Service(device=device, name='Service 3', protocol=ServiceProtocolChoices.PROTOCOL_TCP, port=103), ]) def test_service_list(self): diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 8bd568df2..362d6173c 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -15,7 +15,6 @@ from utilities.views import ( from virtualization.models import VirtualMachine from . import filters, forms, tables from .choices import * -from .constants import * from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF