Misc cleanup, renaming

This commit is contained in:
Jeremy Stretch 2020-06-23 16:39:43 -04:00
parent 459e485555
commit e3820e93b7
18 changed files with 82 additions and 92 deletions

View File

@ -622,8 +622,7 @@ class BaseInterface(models.Model):
@extras_features('graphs', 'export_templates', 'webhooks')
class Interface(CableTermination, ComponentModel, BaseInterface):
"""
A network interface within a Device. A physical Interface can connect to exactly one other
Interface.
A network interface within a Device. A physical Interface can connect to exactly one other Interface.
"""
device = models.ForeignKey(
to='Device',
@ -695,8 +694,7 @@ class Interface(CableTermination, ComponentModel, BaseInterface):
tags = TaggableManager(through=TaggedItem)
csv_headers = [
'device', 'name', 'lag', 'type', 'enabled', 'mac_address', 'mtu', 'mgmt_only',
'description', 'mode',
'device', 'name', 'lag', 'type', 'enabled', 'mac_address', 'mtu', 'mgmt_only', 'description', 'mode',
]
class Meta:

View File

@ -33,7 +33,7 @@ PREFIX_LENGTH_MAX = 127 # IPv6
IPADDRESS_ASSIGNMENT_MODELS = Q(
Q(app_label='dcim', model='interface') |
Q(app_label='virtualization', model='interface')
Q(app_label='virtualization', model='vminterface')
)
IPADDRESS_MASK_LENGTH_MIN = 1

View File

@ -319,6 +319,7 @@ class IPAddressFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet,
field_name='pk',
label='Virtual machine (ID)',
)
# TODO: Restore filtering by assigned interface
# interface = django_filters.ModelMultipleChoiceFilter(
# field_name='interface__name',
# queryset=Interface.objects.unrestricted(),

View File

@ -522,6 +522,7 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm)
#
class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModelForm):
# TODO: Restore ability to select assigned object when editing IPAddress
# interface = forms.ModelChoiceField(
# queryset=Interface.objects.all(),
# required=False

View File

@ -31,7 +31,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='ipaddress',
name='assigned_object_type',
field=models.ForeignKey(limit_choices_to=models.Q(models.Q(models.Q(('app_label', 'dcim'), ('model', 'interface')), models.Q(('app_label', 'virtualization'), ('model', 'interface')), _connector='OR')), on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.ContentType', blank=True, null=True),
field=models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(models.Q(('app_label', 'dcim'), ('model', 'interface')), models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), _connector='OR')), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.ContentType'),
preserve_default=False,
),
migrations.RunPython(

View File

@ -753,6 +753,7 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
super().save(*args, **kwargs)
def to_objectchange(self, action):
# Annotate the assigned object, if any
return ObjectChange(
changed_object=self,
object_repr=str(self),
@ -764,12 +765,15 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
def to_csv(self):
# Determine if this IP is primary for a Device
is_primary = False
if self.address.version == 4 and getattr(self, 'primary_ip4_for', False):
is_primary = True
elif self.address.version == 6 and getattr(self, 'primary_ip6_for', False):
is_primary = True
else:
is_primary = False
obj_type = None
if self.assigned_object_type:
obj_type = f'{self.assigned_object_type.app_label}.{self.assigned_object_type.model}'
return (
self.address,
@ -777,7 +781,7 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
self.tenant.name if self.tenant else None,
self.get_status_display(),
self.get_role_display(),
'{}.{}'.format(self.assigned_object_type.app_label, self.assigned_object_type.model) if self.assigned_object_type else None,
obj_type,
self.assigned_object_id,
is_primary,
self.dns_name,

View File

@ -92,14 +92,6 @@ IPADDRESS_ASSIGN_LINK = """
{% endif %}
"""
IPADDRESS_PARENT = """
{% if record.interface %}
<a href="{{ record.interface.parent.get_absolute_url }}">{{ record.interface.parent }}</a>
{% else %}
&mdash;
{% endif %}
"""
VRF_LINK = """
{% if record.vrf %}
<a href="{{ record.vrf.get_absolute_url }}">{{ record.vrf }}</a>
@ -477,17 +469,13 @@ class IPAddressAssignTable(BaseTable):
status = tables.TemplateColumn(
template_code=STATUS_LABEL
)
parent = tables.TemplateColumn(
template_code=IPADDRESS_PARENT,
orderable=False
)
assigned_object = tables.Column(
orderable=False
)
class Meta(BaseTable.Meta):
model = IPAddress
fields = ('address', 'dns_name', 'vrf', 'status', 'role', 'tenant', 'parent', 'assigned_object', 'description')
fields = ('address', 'dns_name', 'vrf', 'status', 'role', 'tenant', 'assigned_object', 'description')
orderable = False

View File

@ -607,47 +607,47 @@ class IPAddressView(ObjectView):
ipaddress = get_object_or_404(self.queryset, pk=pk)
# # Parent prefixes table
# parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
# vrf=ipaddress.vrf, prefix__net_contains=str(ipaddress.address.ip)
# ).prefetch_related(
# 'site', 'role'
# )
# parent_prefixes_table = tables.PrefixTable(list(parent_prefixes), orderable=False)
# parent_prefixes_table.exclude = ('vrf',)
#
# # Duplicate IPs table
# duplicate_ips = IPAddress.objects.restrict(request.user, 'view').filter(
# vrf=ipaddress.vrf, address=str(ipaddress.address)
# ).exclude(
# pk=ipaddress.pk
# ).prefetch_related(
# 'nat_inside'
# )
# # Exclude anycast IPs if this IP is 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
# related_ips = IPAddress.objects.restrict(request.user, 'view').exclude(
# address=str(ipaddress.address)
# ).filter(
# vrf=ipaddress.vrf, address__net_contained_or_equal=str(ipaddress.address)
# )
# related_ips_table = tables.IPAddressTable(related_ips, orderable=False)
#
# paginate = {
# 'paginator_class': EnhancedPaginator,
# 'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
# }
# RequestConfig(request, paginate).configure(related_ips_table)
# Parent prefixes table
parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
vrf=ipaddress.vrf, prefix__net_contains=str(ipaddress.address.ip)
).prefetch_related(
'site', 'role'
)
parent_prefixes_table = tables.PrefixTable(list(parent_prefixes), orderable=False)
parent_prefixes_table.exclude = ('vrf',)
# Duplicate IPs table
duplicate_ips = IPAddress.objects.restrict(request.user, 'view').filter(
vrf=ipaddress.vrf, address=str(ipaddress.address)
).exclude(
pk=ipaddress.pk
).prefetch_related(
'nat_inside'
)
# Exclude anycast IPs if this IP is 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
related_ips = IPAddress.objects.restrict(request.user, 'view').exclude(
address=str(ipaddress.address)
).filter(
vrf=ipaddress.vrf, address__net_contained_or_equal=str(ipaddress.address)
)
related_ips_table = tables.IPAddressTable(related_ips, orderable=False)
paginate = {
'paginator_class': EnhancedPaginator,
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
}
RequestConfig(request, paginate).configure(related_ips_table)
return render(request, 'ipam/ipaddress.html', {
'ipaddress': ipaddress,
# 'parent_prefixes_table': parent_prefixes_table,
# 'duplicate_ips_table': duplicate_ips_table,
# 'related_ips_table': related_ips_table,
'parent_prefixes_table': parent_prefixes_table,
'duplicate_ips_table': duplicate_ips_table,
'related_ips_table': related_ips_table,
})

View File

@ -256,10 +256,6 @@ class BaseFilterSet(django_filters.FilterSet):
except django_filters.exceptions.FieldLookupError:
# The filter could not be created because the lookup expression is not supported on the field
continue
except Exception as e:
print(existing_filter_name, existing_filter)
print(f'field: {field}, lookup_expr: {lookup_expr}')
raise e
if lookup_name.startswith('n'):
# This is a negation filter which requires a queryset.exclude() clause

View File

@ -78,4 +78,4 @@ class InterfaceViewSet(ModelViewSet):
'virtual_machine', 'tags'
)
serializer_class = serializers.VMInterfaceSerializer
filterset_class = filters.InterfaceFilterSet
filterset_class = filters.VMInterfaceFilterSet

View File

@ -15,8 +15,8 @@ __all__ = (
'ClusterFilterSet',
'ClusterGroupFilterSet',
'ClusterTypeFilterSet',
'InterfaceFilterSet',
'VirtualMachineFilterSet',
'VMInterfaceFilterSet',
)
@ -201,7 +201,7 @@ class VirtualMachineFilterSet(
)
class InterfaceFilterSet(BaseFilterSet):
class VMInterfaceFilterSet(BaseFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',

View File

@ -571,7 +571,7 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFil
# VM interfaces
#
class InterfaceForm(BootstrapMixin, forms.ModelForm):
class VMInterfaceForm(BootstrapMixin, forms.ModelForm):
untagged_vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(),
required=False,
@ -643,7 +643,7 @@ class InterfaceForm(BootstrapMixin, forms.ModelForm):
self.cleaned_data['tagged_vlans'] = []
class InterfaceCreateForm(BootstrapMixin, forms.Form):
class VMInterfaceCreateForm(BootstrapMixin, forms.Form):
virtual_machine = forms.ModelChoiceField(
queryset=VirtualMachine.objects.all(),
widget=forms.HiddenInput()
@ -715,7 +715,7 @@ class InterfaceCreateForm(BootstrapMixin, forms.Form):
self.fields['tagged_vlans'].widget.add_additional_query_param('site_id', site.pk)
class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm):
class VMInterfaceBulkEditForm(BootstrapMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=VMInterface.objects.all(),
widget=forms.MultipleHiddenInput()
@ -785,7 +785,7 @@ class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm):
self.fields['tagged_vlans'].widget.add_additional_query_param('site_id', site.pk)
class InterfaceFilterForm(forms.Form):
class VMInterfaceFilterForm(forms.Form):
model = VMInterface
enabled = forms.NullBooleanField(
required=False,
@ -815,7 +815,7 @@ class VirtualMachineBulkAddComponentForm(BootstrapMixin, forms.Form):
return ','.join(self.cleaned_data.get('tags'))
class InterfaceBulkCreateForm(
class VMInterfaceBulkCreateForm(
form_from_model(VMInterface, ['enabled', 'mtu', 'description', 'tags']),
VirtualMachineBulkAddComponentForm
):

View File

@ -475,6 +475,10 @@ class VMInterface(BaseInterface):
object_data=serialize_object(self)
)
@property
def parent(self):
return self.virtual_machine
@property
def count_ipaddresses(self):
return self.ip_addresses.count()

View File

@ -172,7 +172,7 @@ class VirtualMachineDetailTable(VirtualMachineTable):
# VM components
#
class InterfaceTable(BaseTable):
class VMInterfaceTable(BaseTable):
class Meta(BaseTable.Meta):
model = VMInterface

View File

@ -194,7 +194,7 @@ class VirtualMachineTest(APIViewTestCases.APIViewTestCase):
# TODO: Standardize InterfaceTest (pending #4721)
class InterfaceTest(APITestCase):
class VMInterfaceTest(APITestCase):
def setUp(self):

View File

@ -367,7 +367,7 @@ class VirtualMachineTestCase(TestCase):
class InterfaceTestCase(TestCase):
queryset = VMInterface.objects.all()
filterset = InterfaceFilterSet
filterset = VMInterfaceFilterSet
@classmethod
def setUpTestData(cls):

View File

@ -191,11 +191,11 @@ class VirtualMachineTestCase(ViewTestCases.PrimaryObjectViewTestCase):
# TODO: Update base class to DeviceComponentViewTestCase
# Blocked by #4721
class InterfaceTestCase(
class VMInterfaceTestCase(
ViewTestCases.GetObjectViewTestCase,
ViewTestCases.EditObjectViewTestCase,
ViewTestCases.DeleteObjectViewTestCase,
# ViewTestCases.BulkCreateObjectsViewTestCase,
ViewTestCases.BulkCreateObjectsViewTestCase,
ViewTestCases.BulkEditObjectsViewTestCase,
ViewTestCases.BulkDeleteObjectsViewTestCase,
):
@ -234,7 +234,6 @@ class InterfaceTestCase(
'virtual_machine': virtualmachines[1].pk,
'name': 'Interface X',
'enabled': False,
'mgmt_only': False,
'mac_address': EUI('01-02-03-04-05-06'),
'mtu': 2000,
'description': 'New description',
@ -248,7 +247,6 @@ class InterfaceTestCase(
'virtual_machine': virtualmachines[1].pk,
'name_pattern': 'Interface [4-6]',
'enabled': False,
'mgmt_only': False,
'mac_address': EUI('01-02-03-04-05-06'),
'mtu': 2000,
'description': 'New description',
@ -264,6 +262,6 @@ class InterfaceTestCase(
'mtu': 2000,
'description': 'New description',
'mode': InterfaceModeChoices.MODE_TAGGED,
# 'untagged_vlan': vlans[0].pk,
# 'tagged_vlans': [v.pk for v in vlans[1:4]],
'untagged_vlan': vlans[0].pk,
'tagged_vlans': [v.pk for v in vlans[1:4]],
}

View File

@ -291,9 +291,9 @@ class VirtualMachineBulkDeleteView(BulkDeleteView):
class InterfaceListView(ObjectListView):
queryset = VMInterface.objects.prefetch_related('virtual_machine', 'virtual_machine__tenant', 'cable')
filterset = filters.InterfaceFilterSet
filterset_form = forms.InterfaceFilterForm
table = tables.InterfaceTable
filterset = filters.VMInterfaceFilterSet
filterset_form = forms.VMInterfaceFilterForm
table = tables.VMInterfaceTable
action_buttons = ('import', 'export')
@ -334,14 +334,14 @@ class InterfaceView(ObjectView):
# TODO: This should not use ComponentCreateView
class InterfaceCreateView(ComponentCreateView):
queryset = VMInterface.objects.all()
form = forms.InterfaceCreateForm
model_form = forms.InterfaceForm
form = forms.VMInterfaceCreateForm
model_form = forms.VMInterfaceForm
template_name = 'virtualization/virtualmachine_component_add.html'
class InterfaceEditView(ObjectEditView):
queryset = VMInterface.objects.all()
model_form = forms.InterfaceForm
model_form = forms.VMInterfaceForm
template_name = 'virtualization/vminterface_edit.html'
@ -351,13 +351,13 @@ class InterfaceDeleteView(ObjectDeleteView):
class InterfaceBulkEditView(BulkEditView):
queryset = VMInterface.objects.all()
table = tables.InterfaceTable
form = forms.InterfaceBulkEditForm
table = tables.VMInterfaceTable
form = forms.VMInterfaceBulkEditForm
class InterfaceBulkDeleteView(BulkDeleteView):
queryset = VMInterface.objects.all()
table = tables.InterfaceTable
table = tables.VMInterfaceTable
#
@ -367,9 +367,9 @@ class InterfaceBulkDeleteView(BulkDeleteView):
class VirtualMachineBulkAddInterfaceView(BulkComponentCreateView):
parent_model = VirtualMachine
parent_field = 'virtual_machine'
form = forms.InterfaceBulkCreateForm
form = forms.VMInterfaceBulkCreateForm
queryset = VMInterface.objects.all()
model_form = forms.InterfaceForm
model_form = forms.VMInterfaceForm
filterset = filters.VirtualMachineFilterSet
table = tables.VirtualMachineTable
default_return_url = 'virtualization:virtualmachine_list'