Device/VM unique constraints ignore case for name field

This commit is contained in:
jeremystretch
2022-09-27 16:19:39 -04:00
parent c349e06346
commit 1d4f828b93
6 changed files with 56 additions and 13 deletions

View File

@@ -1,4 +1,5 @@
from django.db import migrations, models
import django.db.models.functions.text
class Migration(migrations.Migration):
@@ -30,11 +31,11 @@ class Migration(migrations.Migration):
),
migrations.AddConstraint(
model_name='virtualmachine',
constraint=models.UniqueConstraint(fields=('name', 'cluster', 'tenant'), name='virtualization_virtualmachine_unique_name_cluster_tenant'),
constraint=models.UniqueConstraint(django.db.models.functions.text.Lower('name'), models.F('cluster'), models.F('tenant'), name='virtualization_virtualmachine_unique_name_cluster_tenant'),
),
migrations.AddConstraint(
model_name='virtualmachine',
constraint=models.UniqueConstraint(condition=models.Q(('tenant__isnull', True)), fields=('name', 'cluster'), name='virtualization_virtualmachine_unique_name_cluster', violation_error_message='Virtual machine name must be unique per site.'),
constraint=models.UniqueConstraint(django.db.models.functions.text.Lower('name'), models.F('cluster'), condition=models.Q(('tenant__isnull', True)), name='virtualization_virtualmachine_unique_name_cluster', violation_error_message='Virtual machine name must be unique per cluster.'),
),
migrations.AddConstraint(
model_name='vminterface',

View File

@@ -3,6 +3,7 @@ from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator
from django.db import models
from django.db.models import Q
from django.db.models.functions import Lower
from django.urls import reverse
from dcim.models import BaseInterface, Device
@@ -318,14 +319,14 @@ class VirtualMachine(NetBoxModel, ConfigContextModel):
ordering = ('_name', 'pk') # Name may be non-unique
constraints = (
models.UniqueConstraint(
fields=('name', 'cluster', 'tenant'),
Lower('name'), 'cluster', 'tenant',
name='%(app_label)s_%(class)s_unique_name_cluster_tenant'
),
models.UniqueConstraint(
fields=('name', 'cluster'),
Lower('name'), 'cluster',
name='%(app_label)s_%(class)s_unique_name_cluster',
condition=Q(tenant__isnull=True),
violation_error_message="Virtual machine name must be unique per site."
violation_error_message="Virtual machine name must be unique per cluster."
),
)

View File

@@ -8,12 +8,14 @@ from tenancy.models import Tenant
class VirtualMachineTestCase(TestCase):
def test_vm_duplicate_name_per_cluster(self):
@classmethod
def setUpTestData(cls):
cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
cluster = Cluster.objects.create(name='Cluster 1', type=cluster_type)
Cluster.objects.create(name='Cluster 1', type=cluster_type)
def test_vm_duplicate_name_per_cluster(self):
vm1 = VirtualMachine(
cluster=cluster,
cluster=Cluster.objects.first(),
name='Test VM 1'
)
vm1.save()
@@ -43,7 +45,7 @@ class VirtualMachineTestCase(TestCase):
vm2.save()
def test_vm_mismatched_site_cluster(self):
cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
cluster_type = ClusterType.objects.first()
sites = (
Site(name='Site 1', slug='site-1'),
@@ -71,3 +73,19 @@ class VirtualMachineTestCase(TestCase):
# VM with cluster site but no direct site should fail
with self.assertRaises(ValidationError):
VirtualMachine(name='vm1', site=None, cluster=clusters[0]).full_clean()
def test_vm_name_case_sensitivity(self):
vm1 = VirtualMachine(
cluster=Cluster.objects.first(),
name='virtual machine 1'
)
vm1.save()
vm2 = VirtualMachine(
cluster=vm1.cluster,
name='VIRTUAL MACHINE 1'
)
# Uniqueness validation for name should ignore case
with self.assertRaises(ValidationError):
vm2.full_clean()