mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Converted IPAddress.interface to a GenericForeignKey
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Generated by Django 1.11.4 on 2017-08-16 21:06
|
# Generated by Django 1.11.4 on 2017-08-18 19:46
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
@ -1175,6 +1175,11 @@ class Interface(models.Model):
|
|||||||
help_text="This interface is used only for out-of-band management"
|
help_text="This interface is used only for out-of-band management"
|
||||||
)
|
)
|
||||||
description = models.CharField(max_length=100, blank=True)
|
description = models.CharField(max_length=100, blank=True)
|
||||||
|
ip_addresses = GenericRelation(
|
||||||
|
to='ipam.IPAddress',
|
||||||
|
content_type_field='interface_type',
|
||||||
|
object_id_field='interface_id'
|
||||||
|
)
|
||||||
|
|
||||||
objects = InterfaceQuerySet.as_manager()
|
objects = InterfaceQuerySet.as_manager()
|
||||||
|
|
||||||
|
@ -134,7 +134,11 @@ class PrefixViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class IPAddressViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
|
class IPAddressViewSet(WritableSerializerMixin, CustomFieldModelViewSet):
|
||||||
queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device', 'nat_inside')
|
queryset = IPAddress.objects.select_related(
|
||||||
|
'vrf__tenant', 'tenant', 'nat_inside'
|
||||||
|
).prefetch_related(
|
||||||
|
'interface__device'
|
||||||
|
)
|
||||||
serializer_class = serializers.IPAddressSerializer
|
serializer_class = serializers.IPAddressSerializer
|
||||||
write_serializer_class = serializers.WritableIPAddressSerializer
|
write_serializer_class = serializers.WritableIPAddressSerializer
|
||||||
filter_class = filters.IPAddressFilter
|
filter_class = filters.IPAddressFilter
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.0.255.1/32",
|
"address": "10.0.255.1/32",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 3,
|
"interface_id": 3,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "169.254.254.1/31",
|
"address": "169.254.254.1/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 4,
|
"interface_id": 4,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.0.255.2/32",
|
"address": "10.0.255.2/32",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 185,
|
"interface_id": 185,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -112,7 +112,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "169.254.1.1/31",
|
"address": "169.254.1.1/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 213,
|
"interface_id": 213,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -126,7 +126,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.0.254.1/24",
|
"address": "10.0.254.1/24",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 12,
|
"interface_id": 12,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.15.21.1/31",
|
"address": "10.15.21.1/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 218,
|
"interface_id": 218,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -154,7 +154,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.15.21.2/31",
|
"address": "10.15.21.2/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 9,
|
"interface_id": 9,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -168,7 +168,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.15.22.1/31",
|
"address": "10.15.22.1/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 8,
|
"interface_id": 8,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -182,7 +182,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.15.20.1/31",
|
"address": "10.15.20.1/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 7,
|
"interface_id": 7,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -196,7 +196,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.16.20.1/31",
|
"address": "10.16.20.1/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 216,
|
"interface_id": 216,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -210,7 +210,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.15.22.2/31",
|
"address": "10.15.22.2/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 206,
|
"interface_id": 206,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -224,7 +224,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.16.22.1/31",
|
"address": "10.16.22.1/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 217,
|
"interface_id": 217,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -238,7 +238,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.16.22.2/31",
|
"address": "10.16.22.2/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 205,
|
"interface_id": 205,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -252,7 +252,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.16.20.2/31",
|
"address": "10.16.20.2/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 211,
|
"interface_id": 211,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -266,7 +266,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.15.22.2/31",
|
"address": "10.15.22.2/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 212,
|
"interface_id": 212,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -280,7 +280,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "10.0.254.2/32",
|
"address": "10.0.254.2/32",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 188,
|
"interface_id": 188,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -294,7 +294,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "169.254.1.1/31",
|
"address": "169.254.1.1/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 200,
|
"interface_id": 200,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
@ -308,7 +308,7 @@
|
|||||||
"family": 4,
|
"family": 4,
|
||||||
"address": "169.254.1.2/31",
|
"address": "169.254.1.2/31",
|
||||||
"vrf": null,
|
"vrf": null,
|
||||||
"interface": 194,
|
"interface_id": 194,
|
||||||
"nat_inside": null,
|
"nat_inside": null,
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
|
44
netbox/ipam/migrations/0019_ipaddress_interface_to_gfk.py
Normal file
44
netbox/ipam/migrations/0019_ipaddress_interface_to_gfk.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.4 on 2017-08-18 19:31
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
def set_interface_type(apps, schema_editor):
|
||||||
|
"""
|
||||||
|
Set the interface_type field to 'Interface' for all IP addresses assigned to an Interface.
|
||||||
|
"""
|
||||||
|
Interface = apps.get_model('dcim', 'Interface')
|
||||||
|
interface_type = ContentType.objects.get_for_model(Interface)
|
||||||
|
IPAddress = apps.get_model('ipam', 'IPAddress')
|
||||||
|
IPAddress.objects.filter(interface__isnull=False).update(interface_type=interface_type)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contenttypes', '0002_remove_content_type_name'),
|
||||||
|
('ipam', '0018_remove_service_uniqueness_constraint'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='ipaddress',
|
||||||
|
name='interface_type',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.ContentType'),
|
||||||
|
),
|
||||||
|
migrations.RunPython(set_interface_type),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='IPAddress',
|
||||||
|
name='interface',
|
||||||
|
field=models.PositiveIntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='IPAddress',
|
||||||
|
old_name='interface',
|
||||||
|
new_name='interface_id',
|
||||||
|
)
|
||||||
|
]
|
@ -2,10 +2,12 @@ from __future__ import unicode_literals
|
|||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.fields import GenericRelation
|
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
from django.db.models.expressions import RawSQL
|
from django.db.models.expressions import RawSQL
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
@ -407,8 +409,15 @@ class IPAddress(CreatedUpdatedModel, CustomFieldModel):
|
|||||||
role = models.PositiveSmallIntegerField(
|
role = models.PositiveSmallIntegerField(
|
||||||
'Role', choices=IPADDRESS_ROLE_CHOICES, blank=True, null=True, help_text='The functional role of this IP'
|
'Role', choices=IPADDRESS_ROLE_CHOICES, blank=True, null=True, help_text='The functional role of this IP'
|
||||||
)
|
)
|
||||||
interface = models.ForeignKey(Interface, related_name='ip_addresses', on_delete=models.CASCADE, blank=True,
|
interface_type = models.ForeignKey(
|
||||||
null=True)
|
to=ContentType,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
limit_choices_to=Q(app_label='dcim', model='interface') | Q(app_label='virtualization', model='vminterface'),
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
interface_id = models.PositiveIntegerField(blank=True, null=True)
|
||||||
|
interface = GenericForeignKey('interface_type', 'interface_id')
|
||||||
nat_inside = models.OneToOneField('self', related_name='nat_outside', on_delete=models.SET_NULL, blank=True,
|
nat_inside = models.OneToOneField('self', related_name='nat_outside', on_delete=models.SET_NULL, blank=True,
|
||||||
null=True, verbose_name='NAT (Inside)',
|
null=True, verbose_name='NAT (Inside)',
|
||||||
help_text="The IP for which this address is the \"outside\" IP")
|
help_text="The IP for which this address is the \"outside\" IP")
|
||||||
|
@ -594,7 +594,11 @@ class PrefixBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class IPAddressListView(ObjectListView):
|
class IPAddressListView(ObjectListView):
|
||||||
queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device', 'nat_inside')
|
queryset = IPAddress.objects.select_related(
|
||||||
|
'vrf__tenant', 'tenant', 'nat_inside'
|
||||||
|
).prefetch_related(
|
||||||
|
'interface__device'
|
||||||
|
)
|
||||||
filter = filters.IPAddressFilter
|
filter = filters.IPAddressFilter
|
||||||
filter_form = forms.IPAddressFilterForm
|
filter_form = forms.IPAddressFilterForm
|
||||||
table = tables.IPAddressDetailTable
|
table = tables.IPAddressDetailTable
|
||||||
@ -605,7 +609,7 @@ class IPAddressView(View):
|
|||||||
|
|
||||||
def get(self, request, pk):
|
def get(self, request, pk):
|
||||||
|
|
||||||
ipaddress = get_object_or_404(IPAddress.objects.select_related('interface__device'), pk=pk)
|
ipaddress = get_object_or_404(IPAddress.objects.select_related('vrf__tenant', 'tenant'), pk=pk)
|
||||||
|
|
||||||
# Parent prefixes table
|
# Parent prefixes table
|
||||||
parent_prefixes = Prefix.objects.filter(
|
parent_prefixes = Prefix.objects.filter(
|
||||||
@ -622,12 +626,14 @@ class IPAddressView(View):
|
|||||||
).exclude(
|
).exclude(
|
||||||
pk=ipaddress.pk
|
pk=ipaddress.pk
|
||||||
).select_related(
|
).select_related(
|
||||||
'interface__device', 'nat_inside'
|
'nat_inside'
|
||||||
|
).prefetch_related(
|
||||||
|
'interface__device'
|
||||||
)
|
)
|
||||||
duplicate_ips_table = tables.IPAddressTable(list(duplicate_ips), orderable=False)
|
duplicate_ips_table = tables.IPAddressTable(list(duplicate_ips), orderable=False)
|
||||||
|
|
||||||
# Related IP table
|
# Related IP table
|
||||||
related_ips = IPAddress.objects.select_related(
|
related_ips = IPAddress.objects.prefetch_related(
|
||||||
'interface__device'
|
'interface__device'
|
||||||
).exclude(
|
).exclude(
|
||||||
address=str(ipaddress.address)
|
address=str(ipaddress.address)
|
||||||
@ -681,7 +687,7 @@ class IPAddressBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|||||||
class IPAddressBulkEditView(PermissionRequiredMixin, BulkEditView):
|
class IPAddressBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||||
permission_required = 'ipam.change_ipaddress'
|
permission_required = 'ipam.change_ipaddress'
|
||||||
cls = IPAddress
|
cls = IPAddress
|
||||||
queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device')
|
queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant').prefetch_related('interface__device')
|
||||||
filter = filters.IPAddressFilter
|
filter = filters.IPAddressFilter
|
||||||
table = tables.IPAddressTable
|
table = tables.IPAddressTable
|
||||||
form = forms.IPAddressBulkEditForm
|
form = forms.IPAddressBulkEditForm
|
||||||
@ -691,7 +697,7 @@ class IPAddressBulkEditView(PermissionRequiredMixin, BulkEditView):
|
|||||||
class IPAddressBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class IPAddressBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'ipam.delete_ipaddress'
|
permission_required = 'ipam.delete_ipaddress'
|
||||||
cls = IPAddress
|
cls = IPAddress
|
||||||
queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device')
|
queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant').prefetch_related('interface__device')
|
||||||
filter = filters.IPAddressFilter
|
filter = filters.IPAddressFilter
|
||||||
table = tables.IPAddressTable
|
table = tables.IPAddressTable
|
||||||
default_return_url = 'ipam:ipaddress_list'
|
default_return_url = 'ipam:ipaddress_list'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Generated by Django 1.11.4 on 2017-08-16 21:06
|
# Generated by Django 1.11.4 on 2017-08-18 19:46
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import dcim.fields
|
import dcim.fields
|
||||||
@ -13,9 +13,9 @@ class Migration(migrations.Migration):
|
|||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('tenancy', '0003_unicode_literals'),
|
|
||||||
('dcim', '0041_napalm_integration'),
|
('dcim', '0041_napalm_integration'),
|
||||||
('ipam', '0018_remove_service_uniqueness_constraint'),
|
('ipam', '0019_ipaddress_interface_to_gfk'),
|
||||||
|
('tenancy', '0003_unicode_literals'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
@ -89,6 +89,7 @@ class Migration(migrations.Migration):
|
|||||||
('virtual_machine', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interfaces', to='virtualization.VirtualMachine')),
|
('virtual_machine', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interfaces', to='virtualization.VirtualMachine')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
|
'verbose_name': 'VM interface',
|
||||||
'ordering': ['virtual_machine', 'name'],
|
'ordering': ['virtual_machine', 'name'],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -221,6 +221,11 @@ class VMInterface(models.Model):
|
|||||||
max_length=100,
|
max_length=100,
|
||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
|
ip_addresses = GenericRelation(
|
||||||
|
to='ipam.IPAddress',
|
||||||
|
content_type_field='interface_type',
|
||||||
|
object_id_field='interface_id'
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['virtual_machine', 'name']
|
ordering = ['virtual_machine', 'name']
|
||||||
|
Reference in New Issue
Block a user