mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-25 01:48:38 -06:00
* Fixes #15717: Allow VM with Site to Cluster without Site * Fixes #15717: Allow VM with Site to Cluster without Site * Fixes #15717: Allow VM with Site to Cluster without Site * Fixes #15717: Allow VM with Site to Cluster without Site * Fixes #15717: Allow VM with Site to Cluster without Site
This commit is contained in:
parent
32e219c70a
commit
582ede8ed3
@ -465,7 +465,10 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
|
|||||||
label=_('Cluster'),
|
label=_('Cluster'),
|
||||||
queryset=Cluster.objects.all(),
|
queryset=Cluster.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
selector=True
|
selector=True,
|
||||||
|
query_params={
|
||||||
|
'site_id': ['$site', 'null']
|
||||||
|
},
|
||||||
)
|
)
|
||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
local_context_data = JSONField(
|
local_context_data = JSONField(
|
||||||
|
@ -8,6 +8,7 @@ from dcim.models import *
|
|||||||
from extras.models import CustomField
|
from extras.models import CustomField
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.data import drange
|
from utilities.data import drange
|
||||||
|
from virtualization.models import Cluster, ClusterType
|
||||||
|
|
||||||
|
|
||||||
class LocationTestCase(TestCase):
|
class LocationTestCase(TestCase):
|
||||||
@ -533,6 +534,36 @@ class DeviceTestCase(TestCase):
|
|||||||
device2.full_clean()
|
device2.full_clean()
|
||||||
device2.save()
|
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):
|
class CableTestCase(TestCase):
|
||||||
|
|
||||||
|
@ -178,8 +178,8 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
|
|||||||
required=False,
|
required=False,
|
||||||
selector=True,
|
selector=True,
|
||||||
query_params={
|
query_params={
|
||||||
'site_id': '$site',
|
'site_id': ['$site', 'null']
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
device = DynamicModelChoiceField(
|
device = DynamicModelChoiceField(
|
||||||
label=_('Device'),
|
label=_('Device'),
|
||||||
|
@ -180,7 +180,7 @@ class VirtualMachine(ContactsMixin, ImageAttachmentsMixin, RenderConfigMixin, Co
|
|||||||
})
|
})
|
||||||
|
|
||||||
# Validate site for cluster & device
|
# 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({
|
raise ValidationError({
|
||||||
'cluster': _(
|
'cluster': _(
|
||||||
'The selected cluster ({cluster}) is not assigned to this site ({site}).'
|
'The selected cluster ({cluster}) is not assigned to this site ({site}).'
|
||||||
|
@ -63,6 +63,9 @@ class VirtualMachineTestCase(TestCase):
|
|||||||
# VM with site only should pass
|
# VM with site only should pass
|
||||||
VirtualMachine(name='vm1', site=sites[0]).full_clean()
|
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
|
# VM with non-site cluster only should pass
|
||||||
VirtualMachine(name='vm1', cluster=clusters[2]).full_clean()
|
VirtualMachine(name='vm1', cluster=clusters[2]).full_clean()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user