Fixes #4578: Prevent setting 0U height on device type with racked instances

This commit is contained in:
Jeremy Stretch 2020-05-05 13:41:23 -04:00
parent 6e2c68ef42
commit 0239be9be5
2 changed files with 22 additions and 4 deletions

View File

@ -18,6 +18,7 @@
* [#4548](https://github.com/netbox-community/netbox/issues/4548) - Fix tracing cables through a single RearPort * [#4548](https://github.com/netbox-community/netbox/issues/4548) - Fix tracing cables through a single RearPort
* [#4549](https://github.com/netbox-community/netbox/issues/4549) - Fix encoding unicode webhook body data * [#4549](https://github.com/netbox-community/netbox/issues/4549) - Fix encoding unicode webhook body data
* [#4556](https://github.com/netbox-community/netbox/issues/4556) - Update form for adding devices to clusters * [#4556](https://github.com/netbox-community/netbox/issues/4556) - Update form for adding devices to clusters
* [#4578](https://github.com/netbox-community/netbox/issues/4578) - Prevent setting 0U height on device type with racked instances
--- ---

View File

@ -12,6 +12,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models from django.db import models
from django.db.models import Count, F, ProtectedError, Sum from django.db.models import Count, F, ProtectedError, Sum
from django.urls import reverse from django.urls import reverse
from django.utils.safestring import mark_safe
from mptt.models import MPTTModel, TreeForeignKey from mptt.models import MPTTModel, TreeForeignKey
from taggit.managers import TaggableManager from taggit.managers import TaggableManager
from timezone_field import TimeZoneField from timezone_field import TimeZoneField
@ -652,7 +653,8 @@ class Rack(ChangeLoggedModel, CustomFieldModel):
pk=exclude pk=exclude
).filter( ).filter(
rack=self, rack=self,
position__gt=0 position__gt=0,
device_type__u_height__gt=0
).filter( ).filter(
Q(face=face) | Q(device_type__is_full_depth=True) Q(face=face) | Q(device_type__is_full_depth=True)
) )
@ -1089,17 +1091,32 @@ class DeviceType(ChangeLoggedModel, CustomFieldModel):
# If editing an existing DeviceType to have a larger u_height, first validate that *all* instances of it have # If editing an existing DeviceType to have a larger u_height, first validate that *all* instances of it have
# room to expand within their racks. This validation will impose a very high performance penalty when there are # room to expand within their racks. This validation will impose a very high performance penalty when there are
# many instances to check, but increasing the u_height of a DeviceType should be a very rare occurrence. # many instances to check, but increasing the u_height of a DeviceType should be a very rare occurrence.
if self.pk is not None and self.u_height > self._original_u_height: if self.pk and self.u_height > self._original_u_height:
for d in Device.objects.filter(device_type=self, position__isnull=False): for d in Device.objects.filter(device_type=self, position__isnull=False):
face_required = None if self.is_full_depth else d.face face_required = None if self.is_full_depth else d.face
u_available = d.rack.get_available_units(u_height=self.u_height, rack_face=face_required, u_available = d.rack.get_available_units(
exclude=[d.pk]) u_height=self.u_height,
rack_face=face_required,
exclude=[d.pk]
)
if d.position not in u_available: if d.position not in u_available:
raise ValidationError({ raise ValidationError({
'u_height': "Device {} in rack {} does not have sufficient space to accommodate a height of " 'u_height': "Device {} in rack {} does not have sufficient space to accommodate a height of "
"{}U".format(d, d.rack, self.u_height) "{}U".format(d, d.rack, self.u_height)
}) })
# If modifying the height of an existing DeviceType to 0U, check for any instances assigned to a rack position.
elif self.pk and self._original_u_height > 0 and self.u_height == 0:
racked_instance_count = Device.objects.filter(device_type=self, position__isnull=False).count()
if racked_instance_count:
url = f"{reverse('dcim:device_list')}?manufactuer_id={self.manufacturer_id}&device_type_id={self.pk}"
raise ValidationError({
'u_height': mark_safe(
f'Unable to set 0U height: Found <a href="{url}">{racked_instance_count} instances</a> already '
f'mounted within racks.'
)
})
if ( if (
self.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT self.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT
) and self.device_bay_templates.count(): ) and self.device_bay_templates.count():