|
|
@@ -1018,20 +1018,29 @@ class Device(
|
|
|
).format(virtual_chassis=self.vc_master_for)
|
|
|
})
|
|
|
|
|
|
- # Prevent leaving a virtual chassis while interfaces form a LAG with another member
|
|
|
+ # Validate cross-chassis LAGs only when virtual chassis membership changes
|
|
|
if self.pk:
|
|
|
- lag_members = Interface.objects.filter(device=self, lag__isnull=False).exclude(lag__device=self)
|
|
|
- lag_peers = Interface.objects.filter(lag__device=self).exclude(device=self)
|
|
|
- if self.virtual_chassis:
|
|
|
- lag_members = lag_members.exclude(lag__device__virtual_chassis=self.virtual_chassis)
|
|
|
- lag_peers = lag_peers.exclude(device__virtual_chassis=self.virtual_chassis)
|
|
|
- if lag_members.exists() or lag_peers.exists():
|
|
|
- raise ValidationError({
|
|
|
- 'virtual_chassis': _(
|
|
|
- 'Device cannot be removed from its virtual chassis because one or more of its interfaces '
|
|
|
- 'form a LAG with another member device.'
|
|
|
- )
|
|
|
- })
|
|
|
+ stored_vc_id = Device.objects.filter(pk=self.pk).values_list('virtual_chassis_id', flat=True).first()
|
|
|
+ if self.virtual_chassis_id != stored_vc_id:
|
|
|
+ self.clean_vc_lag_membership()
|
|
|
+
|
|
|
+ def clean_vc_lag_membership(self):
|
|
|
+ """
|
|
|
+ Raise ValidationError if any interface would form a LAG with a device outside this device's virtual chassis.
|
|
|
+ """
|
|
|
+ lag_members = Interface.objects.filter(device=self, lag__isnull=False).exclude(lag__device=self)
|
|
|
+ lag_peers = Interface.objects.filter(lag__device=self).exclude(device=self)
|
|
|
+ if self.virtual_chassis_id:
|
|
|
+ lag_members = lag_members.exclude(lag__device__virtual_chassis=self.virtual_chassis_id)
|
|
|
+ lag_peers = lag_peers.exclude(device__virtual_chassis=self.virtual_chassis_id)
|
|
|
+ interfaces = [*lag_members.select_related('lag__device'), *lag_peers.select_related('device', 'lag')]
|
|
|
+ if interfaces:
|
|
|
+ raise ValidationError({
|
|
|
+ 'virtual_chassis': _(
|
|
|
+ 'Virtual chassis membership cannot be changed while interfaces form a LAG with another device '
|
|
|
+ 'outside the virtual chassis: {interfaces}'
|
|
|
+ ).format(interfaces=', '.join(f'{i.device}:{i} ({i.lag.device}:{i.lag})' for i in interfaces))
|
|
|
+ })
|
|
|
|
|
|
def _check_duplicate_component_names(self, components):
|
|
|
"""
|