Merge branch 'develop' into 16424-allow_filtering_of_devices_by_cluster_and_cluster_group

This commit is contained in:
Julio-Oliveira-Encora 2024-06-20 14:59:03 -03:00
commit 1c162344fe
6 changed files with 42 additions and 5 deletions

View File

@ -24,7 +24,7 @@ If you believe you've uncovered a security vulnerability and wish to report it c
Please note that we **DO NOT** accept reports generated by automated tooling which merely suggest that a file or file(s) _may_ be vulnerable under certain conditions, as these are most often innocuous.
If you believe that you've found a vulnerability which meets all of these conditions, please [submit a draft security advisory](https://github.com/netbox-community/netbox/security/advisories/new) on GitHub, or email a brief description of the suspected bug and instructions for reproduction to **security@netbox.dev**. For any security concerns regarding NetBox deployed via Docker, please see the [netbox-docker](https://github.com/netbox-community/netbox-docker) project.
If you believe that you've found a vulnerability which meets all of these conditions, please [submit a draft security advisory](https://github.com/netbox-community/netbox/security/advisories/new) on GitHub. For any security concerns regarding NetBox deployed via Docker, please see the [netbox-docker](https://github.com/netbox-community/netbox-docker) project.
### Bug Bounties

View File

@ -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(

View File

@ -8,6 +8,7 @@ from dcim.models import *
from extras.models import CustomField
from tenancy.models import Tenant
from utilities.data import drange
from virtualization.models import Cluster, ClusterType
class LocationTestCase(TestCase):
@ -533,6 +534,36 @@ class DeviceTestCase(TestCase):
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):

View File

@ -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'),

View File

@ -180,7 +180,7 @@ class VirtualMachine(ContactsMixin, ImageAttachmentsMixin, RenderConfigMixin, Co
})
# 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}).'

View File

@ -63,6 +63,9 @@ class VirtualMachineTestCase(TestCase):
# 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()