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

View File

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

View File

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

View File

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

View File

@ -31,7 +31,7 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='ipaddress', model_name='ipaddress',
name='assigned_object_type', 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, preserve_default=False,
), ),
migrations.RunPython( migrations.RunPython(

View File

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

View File

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

View File

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

View File

@ -256,10 +256,6 @@ class BaseFilterSet(django_filters.FilterSet):
except django_filters.exceptions.FieldLookupError: except django_filters.exceptions.FieldLookupError:
# The filter could not be created because the lookup expression is not supported on the field # The filter could not be created because the lookup expression is not supported on the field
continue 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'): if lookup_name.startswith('n'):
# This is a negation filter which requires a queryset.exclude() clause # This is a negation filter which requires a queryset.exclude() clause

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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