diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index caf27bad9..553830e5b 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -1271,6 +1271,16 @@ class IPAddressForm(BootstrapMixin, CustomFieldForm): class ServicePortForm(forms.ModelForm, BootstrapMixin): + class Meta: + model = ServicePort + fields = ['device', 'ip_address', 'protocol', 'port', 'name', 'description'] + widgets = { + 'device': forms.HiddenInput(), + } + + +class ServicePortCreateForm(forms.ModelForm, BootstrapMixin): + class Meta: model = ServicePort fields = ['ip_address', 'protocol', 'port', 'name', 'description'] @@ -1284,7 +1294,7 @@ class ServicePortForm(forms.ModelForm, BootstrapMixin): } def __init__(self, device, *args, **kwargs): - super(ServicePortForm, self).__init__(*args, **kwargs) + super(ServicePortCreateForm, self).__init__(*args, **kwargs) self.fields['ip_address'].queryset = IPAddress.objects.filter(interface__device=device) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 3ef706725..aa049431b 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -576,7 +576,7 @@ def device(request, pk): # Find all IP addresses assigned to this device ip_addresses = IPAddress.objects.filter(interface__device=device).select_related('interface', 'vrf')\ .order_by('address') - service_ports = ServicePort.objects.filter(ip_address__interface__device=device).order_by('ip_address', 'port') + service_ports = ServicePort.objects.filter(device=device).order_by('ip_address', 'port') # Find any related devices for convenient linking in the UI related_devices = [] @@ -1606,12 +1606,21 @@ def serviceport_assign(request, pk): device = get_object_or_404(Device, pk=pk) if request.method == 'POST': - form = forms.ServicePortForm(device, request.POST) + form = forms.ServicePortCreateForm(device, request.POST) if form.is_valid(): - service_port = form.save(commit=False) - service_port.save() - messages.success(request, "Added new port {0} to IP Address {1}".format(service_port, - service_port.ip_address)) + serv_form = forms.ServicePortForm({ + 'device': device.pk, + 'ip_address': form.cleaned_data['ip_address'].pk, + 'protocol': form.cleaned_data['protocol'], + 'port': form.cleaned_data['port'], + 'name': form.cleaned_data['name'], + 'description': form.cleaned_data['description'], + }) + if serv_form.is_valid(): + service_port = serv_form.save(commit=False) + service_port.save() + messages.success(request, "Added new port {0} for device {1}".format(service_port, + service_port.device)) if '_addanother' in request.POST: return redirect('dcim:serviceport_assign', pk=device.pk) @@ -1619,7 +1628,7 @@ def serviceport_assign(request, pk): return redirect('dcim:device', pk=device.pk) else: - form = forms.ServicePortForm(device) + form = forms.ServicePortCreateForm(device) return render(request, 'dcim/serviceport_assign.html', { 'device': device, diff --git a/netbox/ipam/api/views.py b/netbox/ipam/api/views.py index dbeffba5b..72ba88718 100644 --- a/netbox/ipam/api/views.py +++ b/netbox/ipam/api/views.py @@ -143,7 +143,7 @@ class ServicePortListView(generics.ListAPIView): """ List IP addresses (filterable) """ - queryset = ServicePort.objects.select_related('ip_address', 'port', 'protocol', 'name', 'description') + queryset = ServicePort.objects.select_related('device', 'ip_address', 'port', 'protocol', 'name', 'description') serializer_class = serializers.ServicePortSerializer @@ -151,7 +151,7 @@ class ServicePortDetailView(generics.RetrieveAPIView): """ Retrieve a single IP address """ - queryset = ServicePort.objects.select_related('ip_address', 'port', 'protocol', 'name', 'description') + queryset = ServicePort.objects.select_related('device', 'ip_address', 'port', 'protocol', 'name', 'description') serializer_class = serializers.ServicePortSerializer diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 58e9b1836..c2dbda748 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -461,6 +461,11 @@ class ServicePortForm(forms.ModelForm, BootstrapMixin): 'ip_address': "IP Address", } + def __init__(self, *args, **kwargs): + super(ServicePortForm, self).__init__(*args, **kwargs) + # self.fields['device']. + self.fields['ip_address'].queryset = IPAddress.objects.filter(interface__device=kwargs['instance'].device) + # # VLAN groups diff --git a/netbox/ipam/migrations/0011_add_service_port.py b/netbox/ipam/migrations/0011_add_service_port.py index 96a69c984..ec9c29b52 100644 --- a/netbox/ipam/migrations/0011_add_service_port.py +++ b/netbox/ipam/migrations/0011_add_service_port.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10 on 2016-10-01 13:31 +# Generated by Django 1.10 on 2016-11-22 22:05 from __future__ import unicode_literals from django.db import migrations, models @@ -9,6 +9,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ + ('dcim', '0021_add_ff_flexstack'), ('ipam', '0010_ipaddress_help_texts'), ] @@ -19,20 +20,21 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created', models.DateField(auto_now_add=True)), ('last_updated', models.DateTimeField(auto_now=True)), - ('protocol', models.PositiveSmallIntegerField(choices=[(0, b'TCP'), (1, b'UDP')], default=0)), + ('protocol', models.PositiveSmallIntegerField(choices=[(6, b'TCP'), (17, b'UDP')], default=0)), ('port', models.PositiveIntegerField()), ('name', models.CharField(max_length=30)), ('description', models.TextField(blank=True)), - ('ip_address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='service_ports', to='ipam.IPAddress', verbose_name=b'ip_address')), + ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='service_ports', to='dcim.Device', verbose_name=b'device')), + ('ip_address', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='service_ports', to='ipam.IPAddress', verbose_name=b'ip_address')), ], options={ - 'ordering': ['ip_address', 'port'], + 'ordering': ['device', 'ip_address', 'port'], 'verbose_name': 'Service Port', 'verbose_name_plural': 'Service Ports', }, ), migrations.AlterUniqueTogether( name='serviceport', - unique_together={('ip_address', 'port', 'protocol')}, + unique_together={('device', 'ip_address', 'port', 'protocol')}, ), ] diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index 4ce72cca9..b0737ce8d 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -23,8 +23,8 @@ AF_CHOICES = ( ) SERVICE_PORT_CHOICES = ( - (0, 'TCP'), - (1, 'UDP'), + (6, 'TCP'), + (17, 'UDP'), ) PREFIX_STATUS_CONTAINER = 0 @@ -456,8 +456,11 @@ class ServicePort(CreatedUpdatedModel): it cannot be assigned to any other IPAddress on the same Device. """ + device = models.ForeignKey('dcim.Device', related_name='service_ports', on_delete=models.CASCADE, + blank=False, null=False, verbose_name='device') + ip_address = models.ForeignKey('IPAddress', related_name='service_ports', on_delete=models.CASCADE, - blank=False, null=False, verbose_name='ip_address') + blank=True, null=True, verbose_name='ip_address') protocol = models.PositiveSmallIntegerField(choices=SERVICE_PORT_CHOICES, default=0) port = models.PositiveIntegerField() @@ -465,10 +468,10 @@ class ServicePort(CreatedUpdatedModel): description = models.TextField(blank=True) class Meta: - ordering = ['ip_address', 'port'] + ordering = ['device', 'ip_address', 'port'] verbose_name = 'Service Port' verbose_name_plural = 'Service Ports' - unique_together = ['ip_address', 'port', 'protocol'] + unique_together = ['device', 'ip_address', 'port', 'protocol'] def __unicode__(self): port_protocol = dict(SERVICE_PORT_CHOICES).get(self.protocol) diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 5721e98c2..1571882cd 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -651,7 +651,7 @@ class IPAddressBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): # def serviceport(request, pk): - service_port = get_object_or_404(ServicePort.objects.select_related('ip_address__interface__device'), pk=pk) + service_port = get_object_or_404(ServicePort.objects.select_related('device'), pk=pk) return render(request, 'ipam/serviceport.html', { 'service_port': service_port, @@ -667,7 +667,7 @@ class ServicePortEditView(PermissionRequiredMixin, ObjectEditView): def post(self, request, *args, **kwargs): service_port = self.get_object(kwargs) - device_url = reverse('dcim:device', kwargs={'pk': service_port.ip_address.device.pk}) + device_url = reverse('dcim:device', kwargs={'pk': service_port.device.pk}) self.success_url = device_url self.cancel_url = device_url @@ -680,7 +680,7 @@ class ServicePortDeleteView(PermissionRequiredMixin, ObjectDeleteView): def post(self, request, *args, **kwargs): service_port = self.get_object(kwargs) - self.redirect_url = reverse('dcim:device', kwargs={'pk': service_port.ip_address.device.pk}) + self.redirect_url = reverse('dcim:device', kwargs={'pk': service_port.device.pk}) return super(ServicePortDeleteView, self).post(request, *args, **kwargs) diff --git a/netbox/templates/dcim/serviceport_assign.html b/netbox/templates/dcim/serviceport_assign.html index 6f3786df9..409c05022 100644 --- a/netbox/templates/dcim/serviceport_assign.html +++ b/netbox/templates/dcim/serviceport_assign.html @@ -21,6 +21,12 @@ Add a Service Port
{{ device }}
+{{ obj.device }}
+- {% if obj.ip_address.device %} - {{ obj.ip_address.device }} - {% else %} - None - {% endif %} -
-{{ obj.ip_address.interface }}
-