Skip to content

Commit

Permalink
Fixes netbox-community#15717 - Unable to assign a VM in Site to Clust…
Browse files Browse the repository at this point in the history
…er without Site (netbox-community#15763)

* Fixes netbox-community#15717: Allow VM with Site to Cluster without Site

* Fixes netbox-community#15717: Allow VM with Site to Cluster without Site

* Fixes netbox-community#15717: Allow VM with Site to Cluster without Site

* Fixes netbox-community#15717: Allow VM with Site to Cluster without Site

* Fixes netbox-community#15717: Allow VM with Site to Cluster without Site
  • Loading branch information
nopg authored Jun 20, 2024
1 parent 32e219c commit 582ede8
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 4 deletions.
5 changes: 4 additions & 1 deletion netbox/dcim/forms/model_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,10 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
label=_('Cluster'),
queryset=Cluster.objects.all(),
required=False,
selector=True
selector=True,
query_params={
'site_id': ['$site', 'null']
},
)
comments = CommentField()
local_context_data = JSONField(
Expand Down
31 changes: 31 additions & 0 deletions netbox/dcim/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from extras.models import CustomField
from tenancy.models import Tenant
from utilities.data import drange
from virtualization.models import Cluster, ClusterType


class LocationTestCase(TestCase):
Expand Down Expand Up @@ -533,6 +534,36 @@ def test_device_duplicate_names(self):
device2.full_clean()
device2.save()

def test_device_mismatched_site_cluster(self):
cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
Cluster.objects.create(name='Cluster 1', type=cluster_type)

sites = (
Site(name='Site 1', slug='site-1'),
Site(name='Site 2', slug='site-2'),
)
Site.objects.bulk_create(sites)

clusters = (
Cluster(name='Cluster 1', type=cluster_type, site=sites[0]),
Cluster(name='Cluster 2', type=cluster_type, site=sites[1]),
Cluster(name='Cluster 3', type=cluster_type, site=None),
)
Cluster.objects.bulk_create(clusters)

device_type = DeviceType.objects.first()
device_role = DeviceRole.objects.first()

# Device with site only should pass
Device(name='device1', site=sites[0], device_type=device_type, role=device_role).full_clean()

# Device with site, cluster non-site should pass
Device(name='device1', site=sites[0], device_type=device_type, role=device_role, cluster=clusters[2]).full_clean()

# Device with mismatched site & cluster should fail
with self.assertRaises(ValidationError):
Device(name='device1', site=sites[0], device_type=device_type, role=device_role, cluster=clusters[1]).full_clean()


class CableTestCase(TestCase):

Expand Down
4 changes: 2 additions & 2 deletions netbox/virtualization/forms/model_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
required=False,
selector=True,
query_params={
'site_id': '$site',
}
'site_id': ['$site', 'null']
},
)
device = DynamicModelChoiceField(
label=_('Device'),
Expand Down
2 changes: 1 addition & 1 deletion netbox/virtualization/models/virtualmachines.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def clean(self):
})

# Validate site for cluster & device
if self.cluster and self.site and self.cluster.site != self.site:
if self.cluster and self.cluster.site is not None and self.cluster.site != self.site:
raise ValidationError({
'cluster': _(
'The selected cluster ({cluster}) is not assigned to this site ({site}).'
Expand Down
3 changes: 3 additions & 0 deletions netbox/virtualization/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ def test_vm_mismatched_site_cluster(self):
# VM with site only should pass
VirtualMachine(name='vm1', site=sites[0]).full_clean()

# VM with site, cluster non-site should pass
VirtualMachine(name='vm1', site=sites[0], cluster=clusters[2]).full_clean()

# VM with non-site cluster only should pass
VirtualMachine(name='vm1', cluster=clusters[2]).full_clean()

Expand Down

0 comments on commit 582ede8

Please sign in to comment.