From 1fbfea56c12c0ab9315a9c70d17e873e83eb133e Mon Sep 17 00:00:00 2001 From: Brian Tiemann Date: Thu, 9 Jan 2025 19:35:40 -0500 Subject: [PATCH 1/2] Fix validation of site in Assign Device to Cluster flow --- netbox/virtualization/forms/model_forms.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/netbox/virtualization/forms/model_forms.py b/netbox/virtualization/forms/model_forms.py index 9edda1fe011..57ed0b94ff7 100644 --- a/netbox/virtualization/forms/model_forms.py +++ b/netbox/virtualization/forms/model_forms.py @@ -1,4 +1,5 @@ from django import forms +from django.apps import apps from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ @@ -144,16 +145,27 @@ def clean(self): super().clean() # If the Cluster is assigned to a Site, all Devices must be assigned to that Site. - if self.cluster.site is not None: + # This validation currently only supports Site scoping, but can be extended to Location etc. if needed. + if self.cluster.scope is not None: for device in self.cleaned_data.get('devices', []): - if device.site != self.cluster.site: + device_scope = None + scope_type = None + if ( + self.cluster.scope_type.model_class() == apps.get_model('dcim', 'site') + and device.site != self.cluster.scope + ): + device_scope = device.site + scope_type = 'site' + if device_scope: raise ValidationError({ 'devices': _( - "{device} belongs to a different site ({device_site}) than the cluster ({cluster_site})" + "{device} belongs to a different {scope_type} ({device_scope}) than the " + "cluster ({cluster_scope})" ).format( device=device, - device_site=device.site, - cluster_site=self.cluster.site + scope_type=scope_type, + device_scope=device_scope, + cluster_scope=self.cluster.scope ) }) From 30c41755aa641e9967ea177cc4e7ac2fa7d05765 Mon Sep 17 00:00:00 2001 From: Brian Tiemann Date: Sat, 11 Jan 2025 12:46:38 -0500 Subject: [PATCH 2/2] Validate Location as well as Site scope --- netbox/virtualization/forms/model_forms.py | 40 ++++++++++------------ 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/netbox/virtualization/forms/model_forms.py b/netbox/virtualization/forms/model_forms.py index 57ed0b94ff7..9d53c938267 100644 --- a/netbox/virtualization/forms/model_forms.py +++ b/netbox/virtualization/forms/model_forms.py @@ -144,30 +144,26 @@ def __init__(self, cluster, *args, **kwargs): def clean(self): super().clean() - # If the Cluster is assigned to a Site, all Devices must be assigned to that Site. - # This validation currently only supports Site scoping, but can be extended to Location etc. if needed. + # If the Cluster is assigned to a Site or Location, all Devices must be assigned to that same scope. if self.cluster.scope is not None: for device in self.cleaned_data.get('devices', []): - device_scope = None - scope_type = None - if ( - self.cluster.scope_type.model_class() == apps.get_model('dcim', 'site') - and device.site != self.cluster.scope - ): - device_scope = device.site - scope_type = 'site' - if device_scope: - raise ValidationError({ - 'devices': _( - "{device} belongs to a different {scope_type} ({device_scope}) than the " - "cluster ({cluster_scope})" - ).format( - device=device, - scope_type=scope_type, - device_scope=device_scope, - cluster_scope=self.cluster.scope - ) - }) + for scope_field in ['site', 'location']: + device_scope = getattr(device, scope_field) + if ( + self.cluster.scope_type.model_class() == apps.get_model('dcim', scope_field) + and device_scope != self.cluster.scope + ): + raise ValidationError({ + 'devices': _( + "{device} belongs to a different {scope_field} ({device_scope}) than the " + "cluster ({cluster_scope})" + ).format( + device=device, + scope_field=scope_field, + device_scope=device_scope, + cluster_scope=self.cluster.scope + ) + }) class ClusterRemoveDevicesForm(ConfirmationForm):