mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Merge develop into develop-2.10
This commit is contained in:
@@ -88,7 +88,7 @@ class PrefixViewSet(CustomFieldModelViewSet):
|
||||
return super().get_serializer_class()
|
||||
|
||||
@swagger_auto_schema(method='get', responses={200: serializers.AvailablePrefixSerializer(many=True)})
|
||||
@swagger_auto_schema(method='post', responses={201: serializers.AvailablePrefixSerializer(many=True)})
|
||||
@swagger_auto_schema(method='post', responses={201: serializers.PrefixSerializer(many=False)})
|
||||
@action(detail=True, url_path='available-prefixes', methods=['get', 'post'])
|
||||
@advisory_lock(ADVISORY_LOCK_KEYS['available-prefixes'])
|
||||
def available_prefixes(self, request, pk=None):
|
||||
@@ -247,7 +247,7 @@ class PrefixViewSet(CustomFieldModelViewSet):
|
||||
|
||||
class IPAddressViewSet(CustomFieldModelViewSet):
|
||||
queryset = IPAddress.objects.prefetch_related(
|
||||
'vrf__tenant', 'tenant', 'nat_inside', 'nat_outside', 'tags',
|
||||
'vrf__tenant', 'tenant', 'nat_inside', 'nat_outside', 'tags', 'assigned_object'
|
||||
)
|
||||
serializer_class = serializers.IPAddressSerializer
|
||||
filterset_class = filters.IPAddressFilterSet
|
||||
|
@@ -41,12 +41,14 @@ class IPAddressStatusChoices(ChoiceSet):
|
||||
STATUS_RESERVED = 'reserved'
|
||||
STATUS_DEPRECATED = 'deprecated'
|
||||
STATUS_DHCP = 'dhcp'
|
||||
STATUS_SLAAC = 'slaac'
|
||||
|
||||
CHOICES = (
|
||||
(STATUS_ACTIVE, 'Active'),
|
||||
(STATUS_RESERVED, 'Reserved'),
|
||||
(STATUS_DEPRECATED, 'Deprecated'),
|
||||
(STATUS_DHCP, 'DHCP'),
|
||||
(STATUS_SLAAC, 'SLAAC'),
|
||||
)
|
||||
|
||||
|
||||
|
@@ -669,6 +669,7 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
|
||||
'reserved': 'info',
|
||||
'deprecated': 'danger',
|
||||
'dhcp': 'success',
|
||||
'slaac': 'success',
|
||||
}
|
||||
|
||||
ROLE_CLASS_MAP = {
|
||||
@@ -745,12 +746,18 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel):
|
||||
'vminterface': f"IP address is primary for virtual machine {vm} but not assigned to an "
|
||||
f"interface"
|
||||
})
|
||||
elif self.interface.virtual_machine != vm:
|
||||
elif self.assigned_object.virtual_machine != vm:
|
||||
raise ValidationError({
|
||||
'vminterface': f"IP address is primary for virtual machine {vm} but assigned to "
|
||||
f"{self.assigned_object.virtual_machine} ({self.assigned_object})"
|
||||
})
|
||||
|
||||
# Validate IP status selection
|
||||
if self.status == IPAddressStatusChoices.STATUS_SLAAC and self.family != 6:
|
||||
raise ValidationError({
|
||||
'status': "Only IPv6 addresses can be assigned SLAAC status"
|
||||
})
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
|
||||
# Force dns_name to lowercase
|
||||
|
@@ -67,11 +67,7 @@ IPADDRESS_LINK = """
|
||||
"""
|
||||
|
||||
IPADDRESS_ASSIGN_LINK = """
|
||||
{% if request.GET %}
|
||||
<a href="{% url 'ipam:ipaddress_edit' pk=record.pk %}?interface={{ request.GET.interface }}&return_url={{ request.GET.return_url }}">{{ record }}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'ipam:ipaddress_edit' pk=record.pk %}?interface={{ record.interface.pk }}&return_url={{ request.path }}">{{ record }}</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'ipam:ipaddress_edit' pk=record.pk %}?{% if request.GET.interface %}interface={{ request.GET.interface }}{% elif request.GET.vminterface %}vminterface={{ request.GET.vminterface }}{% endif %}&return_url={{ request.GET.return_url }}">{{ record }}</a>
|
||||
"""
|
||||
|
||||
VRF_LINK = """
|
||||
@@ -103,7 +99,7 @@ VLAN_LINK = """
|
||||
"""
|
||||
|
||||
VLAN_PREFIXES = """
|
||||
{% for prefix in record.prefixes.unrestricted %}
|
||||
{% for prefix in record.prefixes.all %}
|
||||
<a href="{% url 'ipam:prefix' pk=prefix.pk %}">{{ prefix }}</a>{% if not forloop.last %}<br />{% endif %}
|
||||
{% empty %}
|
||||
—
|
||||
@@ -387,15 +383,23 @@ class IPAddressTable(BaseTable):
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=TENANT_LINK
|
||||
)
|
||||
assigned = tables.BooleanColumn(
|
||||
accessor='assigned_object_id',
|
||||
verbose_name='Assigned'
|
||||
assigned_object = tables.Column(
|
||||
linkify=True,
|
||||
orderable=False,
|
||||
verbose_name='Interface'
|
||||
)
|
||||
assigned_object_parent = tables.Column(
|
||||
accessor='assigned_object__parent',
|
||||
linkify=True,
|
||||
orderable=False,
|
||||
verbose_name='Interface Parent'
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
model = IPAddress
|
||||
fields = (
|
||||
'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'assigned', 'dns_name', 'description',
|
||||
'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'assigned_object', 'assigned_object_parent', 'dns_name',
|
||||
'description',
|
||||
)
|
||||
row_attrs = {
|
||||
'class': lambda record: 'success' if not isinstance(record, IPAddress) else '',
|
||||
@@ -411,6 +415,10 @@ class IPAddressDetailTable(IPAddressTable):
|
||||
tenant = tables.TemplateColumn(
|
||||
template_code=COL_TENANT
|
||||
)
|
||||
assigned = tables.BooleanColumn(
|
||||
accessor='assigned_object_id',
|
||||
verbose_name='Assigned'
|
||||
)
|
||||
tags = TagColumn(
|
||||
url_name='ipam:ipaddress_list'
|
||||
)
|
||||
|
@@ -493,7 +493,7 @@ class PrefixBulkDeleteView(BulkDeleteView):
|
||||
|
||||
class IPAddressListView(ObjectListView):
|
||||
queryset = IPAddress.objects.prefetch_related(
|
||||
'vrf__tenant', 'tenant', 'nat_inside'
|
||||
'vrf__tenant', 'tenant', 'nat_inside', 'assigned_object'
|
||||
)
|
||||
filterset = filters.IPAddressFilterSet
|
||||
filterset_form = forms.IPAddressFilterForm
|
||||
@@ -582,7 +582,7 @@ class IPAddressAssignView(ObjectView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
|
||||
# Redirect user if an interface has not been provided
|
||||
if 'interface' not in request.GET:
|
||||
if 'interface' not in request.GET and 'vminterface' not in request.GET:
|
||||
return redirect('ipam:ipaddress_add')
|
||||
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
@@ -609,7 +609,7 @@ class IPAddressAssignView(ObjectView):
|
||||
return render(request, 'ipam/ipaddress_assign.html', {
|
||||
'form': form,
|
||||
'table': table,
|
||||
'return_url': request.GET.get('return_url', ''),
|
||||
'return_url': request.GET.get('return_url'),
|
||||
})
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user