mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 04:22:01 -06:00
Allow designating primary IPs assigned to a device's peer VC members
This commit is contained in:
parent
70d235f99e
commit
4871682dc6
@ -773,26 +773,24 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||||||
# Compile list of choices for primary IPv4 and IPv6 addresses
|
# Compile list of choices for primary IPv4 and IPv6 addresses
|
||||||
for family in [4, 6]:
|
for family in [4, 6]:
|
||||||
ip_choices = [(None, '---------')]
|
ip_choices = [(None, '---------')]
|
||||||
|
|
||||||
|
# Gather PKs of all interfaces belonging to this Device or a peer VirtualChassis member
|
||||||
|
interface_ids = self.instance.vc_interfaces.values('pk')
|
||||||
|
|
||||||
# Collect interface IPs
|
# Collect interface IPs
|
||||||
interface_ips = IPAddress.objects.select_related('interface').filter(
|
interface_ips = IPAddress.objects.select_related('interface').filter(
|
||||||
family=family, interface__device=self.instance
|
family=family, interface_id__in=interface_ids
|
||||||
)
|
)
|
||||||
if interface_ips:
|
if interface_ips:
|
||||||
ip_choices.append(
|
ip_list = [(ip.id, '{} ({})'.format(ip.address, ip.interface)) for ip in interface_ips]
|
||||||
('Interface IPs', [
|
ip_choices.append(('Interface IPs', ip_list))
|
||||||
(ip.id, '{} ({})'.format(ip.address, ip.interface)) for ip in interface_ips
|
|
||||||
])
|
|
||||||
)
|
|
||||||
# Collect NAT IPs
|
# Collect NAT IPs
|
||||||
nat_ips = IPAddress.objects.select_related('nat_inside').filter(
|
nat_ips = IPAddress.objects.select_related('nat_inside').filter(
|
||||||
family=family, nat_inside__interface__device=self.instance
|
family=family, nat_inside__interface__in=interface_ids
|
||||||
)
|
)
|
||||||
if nat_ips:
|
if nat_ips:
|
||||||
ip_choices.append(
|
ip_list = [(ip.id, '{} ({})'.format(ip.address, ip.nat_inside.address)) for ip in nat_ips]
|
||||||
('NAT IPs', [
|
ip_choices.append(('NAT IPs', ip_list))
|
||||||
(ip.id, '{} ({})'.format(ip.address, ip.nat_inside.address)) for ip in nat_ips
|
|
||||||
])
|
|
||||||
)
|
|
||||||
self.fields['primary_ip{}'.format(family)].choices = ip_choices
|
self.fields['primary_ip{}'.format(family)].choices = ip_choices
|
||||||
|
|
||||||
# If editing an existing device, exclude it from the list of occupied rack units. This ensures that a device
|
# If editing an existing device, exclude it from the list of occupied rack units. This ensures that a device
|
||||||
|
@ -923,29 +923,28 @@ class Device(CreatedUpdatedModel, CustomFieldModel):
|
|||||||
except DeviceType.DoesNotExist:
|
except DeviceType.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Validate primary IPv4 address
|
# Validate primary IP addresses
|
||||||
if self.primary_ip4 and (
|
vc_interfaces = self.vc_interfaces.all()
|
||||||
self.primary_ip4.interface is None or
|
if self.primary_ip4:
|
||||||
self.primary_ip4.interface.device != self
|
if self.primary_ip4.interface in vc_interfaces:
|
||||||
) and (
|
pass
|
||||||
self.primary_ip4.nat_inside.interface is None or
|
elif self.primary_ip4.nat_inside is not None and self.primary_ip4.nat_inside.interface in vc_interfaces:
|
||||||
self.primary_ip4.nat_inside.interface.device != self
|
pass
|
||||||
):
|
else:
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'primary_ip4': "The specified IP address ({}) is not assigned to this device.".format(self.primary_ip4),
|
'primary_ip4': "The specified IP address ({}) is not assigned to this device.".format(
|
||||||
})
|
self.primary_ip4),
|
||||||
|
})
|
||||||
# Validate primary IPv6 address
|
if self.primary_ip6:
|
||||||
if self.primary_ip6 and (
|
if self.primary_ip6.interface in vc_interfaces:
|
||||||
self.primary_ip6.interface is None or
|
pass
|
||||||
self.primary_ip6.interface.device != self
|
elif self.primary_ip6.nat_inside is not None and self.primary_ip6.nat_inside.interface in vc_interfaces:
|
||||||
) and (
|
pass
|
||||||
self.primary_ip6.nat_inside.interface is None or
|
else:
|
||||||
self.primary_ip6.nat_inside.interface.device != self
|
raise ValidationError({
|
||||||
):
|
'primary_ip6': "The specified IP address ({}) is not assigned to this device.".format(
|
||||||
raise ValidationError({
|
self.primary_ip6),
|
||||||
'primary_ip6': "The specified IP address ({}) is not assigned to this device.".format(self.primary_ip6),
|
})
|
||||||
})
|
|
||||||
|
|
||||||
# A Device can only be assigned to a Cluster in the same Site (or no Site)
|
# A Device can only be assigned to a Cluster in the same Site (or no Site)
|
||||||
if self.cluster and self.cluster.site is not None and self.cluster.site != self.site:
|
if self.cluster and self.cluster.site is not None and self.cluster.site != self.site:
|
||||||
@ -1042,6 +1041,17 @@ class Device(CreatedUpdatedModel, CustomFieldModel):
|
|||||||
except VCMembership.DoesNotExist:
|
except VCMembership.DoesNotExist:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vc_interfaces(self):
|
||||||
|
"""
|
||||||
|
Return a QuerySet matching all Interfaces assigned to this Device or, if this Device is a VC master, to another
|
||||||
|
Device belonging to the same virtual chassis.
|
||||||
|
"""
|
||||||
|
if hasattr(self, 'vc_membership') and self.vc_membership.is_master:
|
||||||
|
return Interface.objects.filter(device__vc_membership__virtual_chassis=self.vc_membership.virtual_chassis)
|
||||||
|
else:
|
||||||
|
return self.interfaces.all()
|
||||||
|
|
||||||
def get_children(self):
|
def get_children(self):
|
||||||
"""
|
"""
|
||||||
Return the set of child Devices installed in DeviceBays within this Device.
|
Return the set of child Devices installed in DeviceBays within this Device.
|
||||||
|
Loading…
Reference in New Issue
Block a user