mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-10 13:52:17 -06:00
Merge branch 'develop' into develop-2.8
This commit is contained in:
@@ -3,8 +3,8 @@ from rest_framework import serializers
|
||||
from dcim.constants import CONNECTION_STATUS_CHOICES
|
||||
from dcim.models import (
|
||||
Cable, ConsolePort, ConsoleServerPort, Device, DeviceBay, DeviceType, DeviceRole, FrontPort, FrontPortTemplate,
|
||||
Interface, Manufacturer, Platform, PowerFeed, PowerOutlet, PowerPanel, PowerPort, Rack, RackGroup, RackRole,
|
||||
RearPort, RearPortTemplate, Region, Site, VirtualChassis,
|
||||
Interface, Manufacturer, Platform, PowerFeed, PowerOutlet, PowerPanel, PowerPort, PowerPortTemplate, Rack,
|
||||
RackGroup, RackRole, RearPort, RearPortTemplate, Region, Site, VirtualChassis,
|
||||
)
|
||||
from utilities.api import ChoiceField, WritableNestedSerializer
|
||||
|
||||
@@ -25,6 +25,7 @@ __all__ = [
|
||||
'NestedPowerOutletSerializer',
|
||||
'NestedPowerPanelSerializer',
|
||||
'NestedPowerPortSerializer',
|
||||
'NestedPowerPortTemplateSerializer',
|
||||
'NestedRackGroupSerializer',
|
||||
'NestedRackRoleSerializer',
|
||||
'NestedRackSerializer',
|
||||
@@ -111,6 +112,14 @@ class NestedDeviceTypeSerializer(WritableNestedSerializer):
|
||||
fields = ['id', 'url', 'manufacturer', 'model', 'slug', 'display_name', 'device_count']
|
||||
|
||||
|
||||
class NestedPowerPortTemplateSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerporttemplate-detail')
|
||||
|
||||
class Meta:
|
||||
model = PowerPortTemplate
|
||||
fields = ['id', 'url', 'name']
|
||||
|
||||
|
||||
class NestedRearPortTemplateSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearporttemplate-detail')
|
||||
|
||||
|
||||
@@ -172,6 +172,10 @@ class RackReservationSerializer(ValidatedModelSerializer):
|
||||
|
||||
|
||||
class RackElevationDetailFilterSerializer(serializers.Serializer):
|
||||
q = serializers.CharField(
|
||||
required=False,
|
||||
default=None
|
||||
)
|
||||
face = serializers.ChoiceField(
|
||||
choices=DeviceFaceChoices,
|
||||
default=DeviceFaceChoices.FACE_FRONT
|
||||
@@ -278,7 +282,7 @@ class PowerOutletTemplateSerializer(ValidatedModelSerializer):
|
||||
allow_blank=True,
|
||||
required=False
|
||||
)
|
||||
power_port = PowerPortTemplateSerializer(
|
||||
power_port = NestedPowerPortTemplateSerializer(
|
||||
required=False
|
||||
)
|
||||
feed_leg = ChoiceField(
|
||||
@@ -294,7 +298,7 @@ class PowerOutletTemplateSerializer(ValidatedModelSerializer):
|
||||
|
||||
class InterfaceTemplateSerializer(ValidatedModelSerializer):
|
||||
device_type = NestedDeviceTypeSerializer()
|
||||
type = ChoiceField(choices=InterfaceTypeChoices, required=False)
|
||||
type = ChoiceField(choices=InterfaceTypeChoices)
|
||||
|
||||
class Meta:
|
||||
model = InterfaceTemplate
|
||||
@@ -514,7 +518,7 @@ class PowerPortSerializer(TaggitSerializer, ConnectedEndpointSerializer):
|
||||
|
||||
class InterfaceSerializer(TaggitSerializer, ConnectedEndpointSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
type = ChoiceField(choices=InterfaceTypeChoices, required=False)
|
||||
type = ChoiceField(choices=InterfaceTypeChoices)
|
||||
lag = NestedInterfaceSerializer(required=False, allow_null=True)
|
||||
mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False)
|
||||
untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
|
||||
|
||||
@@ -210,6 +210,11 @@ class RackViewSet(CustomFieldModelViewSet):
|
||||
expand_devices=data['expand_devices']
|
||||
)
|
||||
|
||||
# Enable filtering rack units by ID
|
||||
q = data['q']
|
||||
if q:
|
||||
elevation = [u for u in elevation if q in str(u['id']) or q in str(u['name'])]
|
||||
|
||||
page = self.paginate_queryset(elevation)
|
||||
if page is not None:
|
||||
rack_units = serializers.RackUnitSerializer(page, many=True, context={'request': request})
|
||||
|
||||
@@ -55,10 +55,12 @@ class RackTypeChoices(ChoiceSet):
|
||||
|
||||
class RackWidthChoices(ChoiceSet):
|
||||
|
||||
WIDTH_10IN = 10
|
||||
WIDTH_19IN = 19
|
||||
WIDTH_23IN = 23
|
||||
|
||||
CHOICES = (
|
||||
(WIDTH_10IN, '10 inches'),
|
||||
(WIDTH_19IN, '19 inches'),
|
||||
(WIDTH_23IN, '23 inches'),
|
||||
)
|
||||
@@ -836,6 +838,7 @@ class PortTypeChoices(ChoiceSet):
|
||||
TYPE_8P8C = '8p8c'
|
||||
TYPE_110_PUNCH = '110-punch'
|
||||
TYPE_BNC = 'bnc'
|
||||
TYPE_MRJ21 = 'mrj21'
|
||||
TYPE_ST = 'st'
|
||||
TYPE_SC = 'sc'
|
||||
TYPE_SC_APC = 'sc-apc'
|
||||
@@ -854,6 +857,7 @@ class PortTypeChoices(ChoiceSet):
|
||||
(TYPE_8P8C, '8P8C'),
|
||||
(TYPE_110_PUNCH, '110 Punch'),
|
||||
(TYPE_BNC, 'BNC'),
|
||||
(TYPE_MRJ21, 'MRJ21'),
|
||||
),
|
||||
),
|
||||
(
|
||||
@@ -904,6 +908,7 @@ class CableTypeChoices(ChoiceSet):
|
||||
TYPE_CAT7 = 'cat7'
|
||||
TYPE_DAC_ACTIVE = 'dac-active'
|
||||
TYPE_DAC_PASSIVE = 'dac-passive'
|
||||
TYPE_MRJ21_TRUNK = 'mrj21-trunk'
|
||||
TYPE_COAXIAL = 'coaxial'
|
||||
TYPE_MMF = 'mmf'
|
||||
TYPE_MMF_OM1 = 'mmf-om1'
|
||||
@@ -927,6 +932,7 @@ class CableTypeChoices(ChoiceSet):
|
||||
(TYPE_CAT7, 'CAT7'),
|
||||
(TYPE_DAC_ACTIVE, 'Direct Attach Copper (Active)'),
|
||||
(TYPE_DAC_PASSIVE, 'Direct Attach Copper (Passive)'),
|
||||
(TYPE_MRJ21_TRUNK, 'MRJ21 Trunk'),
|
||||
(TYPE_COAXIAL, 'Coaxial'),
|
||||
),
|
||||
),
|
||||
@@ -973,10 +979,12 @@ class CableStatusChoices(ChoiceSet):
|
||||
|
||||
STATUS_CONNECTED = 'connected'
|
||||
STATUS_PLANNED = 'planned'
|
||||
STATUS_DECOMMISSIONING = 'decommissioning'
|
||||
|
||||
CHOICES = (
|
||||
(STATUS_CONNECTED, 'Connected'),
|
||||
(STATUS_PLANNED, 'Planned'),
|
||||
(STATUS_DECOMMISSIONING, 'Decommissioning'),
|
||||
)
|
||||
|
||||
LEGACY_MAP = {
|
||||
|
||||
@@ -61,13 +61,10 @@ POWERFEED_MAX_UTILIZATION_DEFAULT = 80 # Percentage
|
||||
# Cabling and connections
|
||||
#
|
||||
|
||||
# TODO: Replace with CableStatusChoices?
|
||||
# Console/power/interface connection statuses
|
||||
CONNECTION_STATUS_PLANNED = False
|
||||
CONNECTION_STATUS_CONNECTED = True
|
||||
CONNECTION_STATUS_CHOICES = [
|
||||
[CONNECTION_STATUS_PLANNED, 'Planned'],
|
||||
[CONNECTION_STATUS_CONNECTED, 'Connected'],
|
||||
[False, 'Not Connected'],
|
||||
[True, 'Connected'],
|
||||
]
|
||||
|
||||
# Cable endpoint types
|
||||
|
||||
@@ -20,6 +20,16 @@ class RackElevationSVG:
|
||||
self.rack = rack
|
||||
self.include_images = include_images
|
||||
|
||||
def _get_device_description(self, device):
|
||||
return '{} ({}) — {} ({}U) {} {}'.format(
|
||||
device.name,
|
||||
device.device_role,
|
||||
device.device_type.display_name,
|
||||
device.device_type.u_height,
|
||||
device.asset_tag or '',
|
||||
device.serial or ''
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _add_gradient(drawing, id_, color):
|
||||
gradient = drawing.linearGradient(
|
||||
@@ -64,10 +74,7 @@ class RackElevationSVG:
|
||||
fill='black'
|
||||
)
|
||||
)
|
||||
link.set_desc('{} — {} ({}U) {} {}'.format(
|
||||
device.device_role, device.device_type.display_name,
|
||||
device.device_type.u_height, device.asset_tag or '', device.serial or ''
|
||||
))
|
||||
link.set_desc(self._get_device_description(device))
|
||||
link.add(drawing.rect(start, end, style='fill: #{}'.format(color), class_='slot'))
|
||||
hex_color = '#{}'.format(foreground_color(color))
|
||||
link.add(drawing.text(str(name), insert=text, fill=hex_color))
|
||||
@@ -81,10 +88,7 @@ class RackElevationSVG:
|
||||
|
||||
def _draw_device_rear(self, drawing, device, start, end, text):
|
||||
rect = drawing.rect(start, end, class_="slot blocked")
|
||||
rect.set_desc('{} — {} ({}U) {} {}'.format(
|
||||
device.device_role, device.device_type.display_name,
|
||||
device.device_type.u_height, device.asset_tag or '', device.serial or ''
|
||||
))
|
||||
rect.set_desc(self._get_device_description(device))
|
||||
drawing.add(rect)
|
||||
drawing.add(drawing.text(str(device), insert=text))
|
||||
|
||||
|
||||
@@ -2344,6 +2344,11 @@ class DeviceBulkAddInterfaceForm(DeviceBulkAddComponentForm):
|
||||
|
||||
class ConsolePortFilterForm(DeviceComponentFilterForm):
|
||||
model = ConsolePort
|
||||
type = forms.MultipleChoiceField(
|
||||
choices=ConsolePortTypeChoices,
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
@@ -2429,6 +2434,11 @@ class ConsolePortCSVForm(forms.ModelForm):
|
||||
|
||||
class ConsoleServerPortFilterForm(DeviceComponentFilterForm):
|
||||
model = ConsoleServerPort
|
||||
type = forms.MultipleChoiceField(
|
||||
choices=ConsolePortTypeChoices,
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
@@ -2528,6 +2538,11 @@ class ConsoleServerPortCSVForm(forms.ModelForm):
|
||||
|
||||
class PowerPortFilterForm(DeviceComponentFilterForm):
|
||||
model = PowerPort
|
||||
type = forms.MultipleChoiceField(
|
||||
choices=PowerPortTypeChoices,
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
@@ -2633,6 +2648,11 @@ class PowerPortCSVForm(forms.ModelForm):
|
||||
|
||||
class PowerOutletFilterForm(DeviceComponentFilterForm):
|
||||
model = PowerOutlet
|
||||
type = forms.MultipleChoiceField(
|
||||
choices=PowerOutletTypeChoices,
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
@@ -2821,6 +2841,11 @@ class PowerOutletBulkDisconnectForm(ConfirmationForm):
|
||||
|
||||
class InterfaceFilterForm(DeviceComponentFilterForm):
|
||||
model = Interface
|
||||
type = forms.MultipleChoiceField(
|
||||
choices=InterfaceTypeChoices,
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
enabled = forms.NullBooleanField(
|
||||
required=False,
|
||||
widget=StaticSelect2(
|
||||
@@ -3190,6 +3215,11 @@ class InterfaceBulkDisconnectForm(ConfirmationForm):
|
||||
|
||||
class FrontPortFilterForm(DeviceComponentFilterForm):
|
||||
model = FrontPort
|
||||
type = forms.MultipleChoiceField(
|
||||
choices=PortTypeChoices,
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
@@ -3379,6 +3409,11 @@ class FrontPortBulkDisconnectForm(ConfirmationForm):
|
||||
|
||||
class RearPortFilterForm(DeviceComponentFilterForm):
|
||||
model = RearPort
|
||||
type = forms.MultipleChoiceField(
|
||||
choices=PortTypeChoices,
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
|
||||
19
netbox/dcim/migrations/0099_powerfeed_negative_voltage.py
Normal file
19
netbox/dcim/migrations/0099_powerfeed_negative_voltage.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 2.2.10 on 2020-03-03 16:59
|
||||
|
||||
from django.db import migrations, models
|
||||
import utilities.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0098_devicetype_images'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='powerfeed',
|
||||
name='voltage',
|
||||
field=models.SmallIntegerField(default=120, validators=[utilities.validators.ExclusionValidator([0])]),
|
||||
),
|
||||
]
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0098_devicetype_images'),
|
||||
('dcim', '0099_powerfeed_negative_voltage'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@@ -20,10 +20,11 @@ from dcim.choices import *
|
||||
from dcim.constants import *
|
||||
from dcim.fields import ASNField
|
||||
from dcim.elevations import RackElevationSVG
|
||||
from extras.models import ConfigContextModel, CustomFieldModel, TaggedItem
|
||||
from extras.models import ConfigContextModel, CustomFieldModel, ObjectChange, TaggedItem
|
||||
from utilities.fields import ColorField, NaturalOrderingField
|
||||
from utilities.models import ChangeLoggedModel
|
||||
from utilities.utils import to_meters
|
||||
from utilities.utils import serialize_object, to_meters
|
||||
from utilities.validators import ExclusionValidator
|
||||
from .device_component_templates import (
|
||||
ConsolePortTemplate, ConsoleServerPortTemplate, DeviceBayTemplate, FrontPortTemplate, InterfaceTemplate,
|
||||
PowerOutletTemplate, PowerPortTemplate, RearPortTemplate,
|
||||
@@ -118,6 +119,15 @@ class Region(MPTTModel, ChangeLoggedModel):
|
||||
Q(region__in=self.get_descendants())
|
||||
).count()
|
||||
|
||||
def to_objectchange(self, action):
|
||||
# Remove MPTT-internal fields
|
||||
return ObjectChange(
|
||||
changed_object=self,
|
||||
object_repr=str(self),
|
||||
action=action,
|
||||
object_data=serialize_object(self, exclude=['level', 'lft', 'rght', 'tree_id'])
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Sites
|
||||
@@ -1766,9 +1776,9 @@ class PowerFeed(ChangeLoggedModel, CableTermination, CustomFieldModel):
|
||||
choices=PowerFeedPhaseChoices,
|
||||
default=PowerFeedPhaseChoices.PHASE_SINGLE
|
||||
)
|
||||
voltage = models.PositiveSmallIntegerField(
|
||||
validators=[MinValueValidator(1)],
|
||||
default=POWERFEED_VOLTAGE_DEFAULT
|
||||
voltage = models.SmallIntegerField(
|
||||
default=POWERFEED_VOLTAGE_DEFAULT,
|
||||
validators=[ExclusionValidator([0])]
|
||||
)
|
||||
amperage = models.PositiveSmallIntegerField(
|
||||
validators=[MinValueValidator(1)],
|
||||
@@ -1850,10 +1860,16 @@ class PowerFeed(ChangeLoggedModel, CableTermination, CustomFieldModel):
|
||||
self.rack, self.rack.site, self.power_panel, self.power_panel.site
|
||||
))
|
||||
|
||||
# AC voltage cannot be negative
|
||||
if self.voltage < 0 and self.supply == PowerFeedSupplyChoices.SUPPLY_AC:
|
||||
raise ValidationError({
|
||||
"voltage": "Voltage cannot be negative for AC supply"
|
||||
})
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
|
||||
# Cache the available_power property on the instance
|
||||
kva = self.voltage * self.amperage * (self.max_utilization / 100)
|
||||
kva = abs(self.voltage) * self.amperage * (self.max_utilization / 100)
|
||||
if self.phase == PowerFeedPhaseChoices.PHASE_3PHASE:
|
||||
self.available_power = round(kva * 1.732)
|
||||
else:
|
||||
@@ -1956,6 +1972,7 @@ class Cable(ChangeLoggedModel):
|
||||
STATUS_CLASS_MAP = {
|
||||
CableStatusChoices.STATUS_CONNECTED: 'success',
|
||||
CableStatusChoices.STATUS_PLANNED: 'info',
|
||||
CableStatusChoices.STATUS_DECOMMISSIONING: 'warning',
|
||||
}
|
||||
|
||||
class Meta:
|
||||
@@ -2116,14 +2133,14 @@ class Cable(ChangeLoggedModel):
|
||||
b_path = self.termination_a.trace()
|
||||
|
||||
# Determine overall path status (connected or planned)
|
||||
if self.status == CableStatusChoices.STATUS_PLANNED:
|
||||
path_status = CONNECTION_STATUS_PLANNED
|
||||
else:
|
||||
path_status = CONNECTION_STATUS_CONNECTED
|
||||
if self.status == CableStatusChoices.STATUS_CONNECTED:
|
||||
path_status = True
|
||||
for segment in a_path[1:] + b_path[1:]:
|
||||
if segment[1] is None or segment[1].status == CableStatusChoices.STATUS_PLANNED:
|
||||
path_status = CONNECTION_STATUS_PLANNED
|
||||
if segment[1] is None or segment[1].status != CableStatusChoices.STATUS_CONNECTED:
|
||||
path_status = False
|
||||
break
|
||||
else:
|
||||
path_status = False
|
||||
|
||||
a_endpoint = a_path[-1][2]
|
||||
b_endpoint = b_path[-1][2]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db import models
|
||||
|
||||
@@ -37,11 +37,17 @@ class ComponentTemplateModel(models.Model):
|
||||
raise NotImplementedError()
|
||||
|
||||
def to_objectchange(self, action):
|
||||
# Annotate the parent DeviceType
|
||||
try:
|
||||
device_type = self.device_type
|
||||
except ObjectDoesNotExist:
|
||||
# The parent DeviceType has already been deleted
|
||||
device_type = None
|
||||
return ObjectChange(
|
||||
changed_object=self,
|
||||
object_repr=str(self),
|
||||
action=action,
|
||||
related_object=self.device_type,
|
||||
related_object=device_type,
|
||||
object_data=serialize_object(self)
|
||||
)
|
||||
|
||||
|
||||
@@ -360,9 +360,21 @@ class PowerPort(CableTermination, ComponentModel):
|
||||
|
||||
@property
|
||||
def connected_endpoint(self):
|
||||
if self._connected_poweroutlet:
|
||||
return self._connected_poweroutlet
|
||||
return self._connected_powerfeed
|
||||
"""
|
||||
Return the connected PowerOutlet, if it exists, or the connected PowerFeed, if it exists. We have to check for
|
||||
ObjectDoesNotExist in case the referenced object has been deleted from the database.
|
||||
"""
|
||||
try:
|
||||
if self._connected_poweroutlet:
|
||||
return self._connected_poweroutlet
|
||||
except ObjectDoesNotExist:
|
||||
pass
|
||||
try:
|
||||
if self._connected_powerfeed:
|
||||
return self._connected_powerfeed
|
||||
except ObjectDoesNotExist:
|
||||
pass
|
||||
return None
|
||||
|
||||
@connected_endpoint.setter
|
||||
def connected_endpoint(self, value):
|
||||
@@ -717,9 +729,21 @@ class Interface(CableTermination, ComponentModel):
|
||||
|
||||
@property
|
||||
def connected_endpoint(self):
|
||||
if self._connected_interface:
|
||||
return self._connected_interface
|
||||
return self._connected_circuittermination
|
||||
"""
|
||||
Return the connected Interface, if it exists, or the connected CircuitTermination, if it exists. We have to
|
||||
check for ObjectDoesNotExist in case the referenced object has been deleted from the database.
|
||||
"""
|
||||
try:
|
||||
if self._connected_interface:
|
||||
return self._connected_interface
|
||||
except ObjectDoesNotExist:
|
||||
pass
|
||||
try:
|
||||
if self._connected_circuittermination:
|
||||
return self._connected_circuittermination
|
||||
except ObjectDoesNotExist:
|
||||
pass
|
||||
return None
|
||||
|
||||
@connected_endpoint.setter
|
||||
def connected_endpoint(self, value):
|
||||
|
||||
@@ -4,7 +4,6 @@ from netaddr import IPNetwork
|
||||
from rest_framework import status
|
||||
|
||||
from circuits.models import Circuit, CircuitTermination, CircuitType, Provider
|
||||
from dcim.api import serializers
|
||||
from dcim.choices import *
|
||||
from dcim.constants import *
|
||||
from dcim.models import (
|
||||
@@ -589,6 +588,28 @@ class RackTest(APITestCase):
|
||||
|
||||
self.assertEqual(response.data['name'], self.rack1.name)
|
||||
|
||||
def test_get_elevation_rack_units(self):
|
||||
|
||||
url = '{}?q=3'.format(reverse('dcim-api:rack-elevation', kwargs={'pk': self.rack1.pk}))
|
||||
response = self.client.get(url, **self.header)
|
||||
|
||||
self.assertEqual(response.data['count'], 13)
|
||||
|
||||
url = '{}?q=U3'.format(reverse('dcim-api:rack-elevation', kwargs={'pk': self.rack1.pk}))
|
||||
response = self.client.get(url, **self.header)
|
||||
|
||||
self.assertEqual(response.data['count'], 11)
|
||||
|
||||
url = '{}?q=10'.format(reverse('dcim-api:rack-elevation', kwargs={'pk': self.rack1.pk}))
|
||||
response = self.client.get(url, **self.header)
|
||||
|
||||
self.assertEqual(response.data['count'], 1)
|
||||
|
||||
url = '{}?q=U20'.format(reverse('dcim-api:rack-elevation', kwargs={'pk': self.rack1.pk}))
|
||||
response = self.client.get(url, **self.header)
|
||||
|
||||
self.assertEqual(response.data['count'], 1)
|
||||
|
||||
def test_get_rack_elevation(self):
|
||||
|
||||
url = reverse('dcim-api:rack-elevation', kwargs={'pk': self.rack1.pk})
|
||||
@@ -1441,13 +1462,13 @@ class InterfaceTemplateTest(APITestCase):
|
||||
manufacturer=self.manufacturer, model='Test Device Type 1', slug='test-device-type-1'
|
||||
)
|
||||
self.interfacetemplate1 = InterfaceTemplate.objects.create(
|
||||
device_type=self.devicetype, name='Test Interface Template 1'
|
||||
device_type=self.devicetype, name='Test Interface Template 1', type='1000base-t'
|
||||
)
|
||||
self.interfacetemplate2 = InterfaceTemplate.objects.create(
|
||||
device_type=self.devicetype, name='Test Interface Template 2'
|
||||
device_type=self.devicetype, name='Test Interface Template 2', type='1000base-t'
|
||||
)
|
||||
self.interfacetemplate3 = InterfaceTemplate.objects.create(
|
||||
device_type=self.devicetype, name='Test Interface Template 3'
|
||||
device_type=self.devicetype, name='Test Interface Template 3', type='1000base-t'
|
||||
)
|
||||
|
||||
def test_get_interfacetemplate(self):
|
||||
@@ -1469,6 +1490,7 @@ class InterfaceTemplateTest(APITestCase):
|
||||
data = {
|
||||
'device_type': self.devicetype.pk,
|
||||
'name': 'Test Interface Template 4',
|
||||
'type': '1000base-t',
|
||||
}
|
||||
|
||||
url = reverse('dcim-api:interfacetemplate-list')
|
||||
@@ -1486,14 +1508,17 @@ class InterfaceTemplateTest(APITestCase):
|
||||
{
|
||||
'device_type': self.devicetype.pk,
|
||||
'name': 'Test Interface Template 4',
|
||||
'type': '1000base-t',
|
||||
},
|
||||
{
|
||||
'device_type': self.devicetype.pk,
|
||||
'name': 'Test Interface Template 5',
|
||||
'type': '1000base-t',
|
||||
},
|
||||
{
|
||||
'device_type': self.devicetype.pk,
|
||||
'name': 'Test Interface Template 6',
|
||||
'type': '1000base-t',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1511,6 +1536,7 @@ class InterfaceTemplateTest(APITestCase):
|
||||
data = {
|
||||
'device_type': self.devicetype.pk,
|
||||
'name': 'Test Interface Template X',
|
||||
'type': '1000base-x-gbic',
|
||||
}
|
||||
|
||||
url = reverse('dcim-api:interfacetemplate-detail', kwargs={'pk': self.interfacetemplate1.pk})
|
||||
@@ -2621,9 +2647,9 @@ class InterfaceTest(APITestCase):
|
||||
self.device = Device.objects.create(
|
||||
device_type=devicetype, device_role=devicerole, name='Test Device 1', site=site
|
||||
)
|
||||
self.interface1 = Interface.objects.create(device=self.device, name='Test Interface 1')
|
||||
self.interface2 = Interface.objects.create(device=self.device, name='Test Interface 2')
|
||||
self.interface3 = Interface.objects.create(device=self.device, name='Test Interface 3')
|
||||
self.interface1 = Interface.objects.create(device=self.device, name='Test Interface 1', type='1000base-t')
|
||||
self.interface2 = Interface.objects.create(device=self.device, name='Test Interface 2', type='1000base-t')
|
||||
self.interface3 = Interface.objects.create(device=self.device, name='Test Interface 3', type='1000base-t')
|
||||
|
||||
self.vlan1 = VLAN.objects.create(name="Test VLAN 1", vid=1)
|
||||
self.vlan2 = VLAN.objects.create(name="Test VLAN 2", vid=2)
|
||||
@@ -2684,6 +2710,7 @@ class InterfaceTest(APITestCase):
|
||||
data = {
|
||||
'device': self.device.pk,
|
||||
'name': 'Test Interface 4',
|
||||
'type': '1000base-t',
|
||||
}
|
||||
|
||||
url = reverse('dcim-api:interface-list')
|
||||
@@ -2700,6 +2727,7 @@ class InterfaceTest(APITestCase):
|
||||
data = {
|
||||
'device': self.device.pk,
|
||||
'name': 'Test Interface 4',
|
||||
'type': '1000base-t',
|
||||
'mode': InterfaceModeChoices.MODE_TAGGED,
|
||||
'untagged_vlan': self.vlan3.id,
|
||||
'tagged_vlans': [self.vlan1.id, self.vlan2.id],
|
||||
@@ -2721,14 +2749,17 @@ class InterfaceTest(APITestCase):
|
||||
{
|
||||
'device': self.device.pk,
|
||||
'name': 'Test Interface 4',
|
||||
'type': '1000base-t',
|
||||
},
|
||||
{
|
||||
'device': self.device.pk,
|
||||
'name': 'Test Interface 5',
|
||||
'type': '1000base-t',
|
||||
},
|
||||
{
|
||||
'device': self.device.pk,
|
||||
'name': 'Test Interface 6',
|
||||
'type': '1000base-t',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -2747,6 +2778,7 @@ class InterfaceTest(APITestCase):
|
||||
{
|
||||
'device': self.device.pk,
|
||||
'name': 'Test Interface 4',
|
||||
'type': '1000base-t',
|
||||
'mode': InterfaceModeChoices.MODE_TAGGED,
|
||||
'untagged_vlan': self.vlan2.id,
|
||||
'tagged_vlans': [self.vlan1.id],
|
||||
@@ -2754,6 +2786,7 @@ class InterfaceTest(APITestCase):
|
||||
{
|
||||
'device': self.device.pk,
|
||||
'name': 'Test Interface 5',
|
||||
'type': '1000base-t',
|
||||
'mode': InterfaceModeChoices.MODE_TAGGED,
|
||||
'untagged_vlan': self.vlan2.id,
|
||||
'tagged_vlans': [self.vlan1.id],
|
||||
@@ -2761,6 +2794,7 @@ class InterfaceTest(APITestCase):
|
||||
{
|
||||
'device': self.device.pk,
|
||||
'name': 'Test Interface 6',
|
||||
'type': '1000base-t',
|
||||
'mode': InterfaceModeChoices.MODE_TAGGED,
|
||||
'untagged_vlan': self.vlan2.id,
|
||||
'tagged_vlans': [self.vlan1.id],
|
||||
@@ -2786,6 +2820,7 @@ class InterfaceTest(APITestCase):
|
||||
data = {
|
||||
'device': self.device.pk,
|
||||
'name': 'Test Interface X',
|
||||
'type': '1000base-x-gbic',
|
||||
'lag': lag_interface.pk,
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ from dcim.models import (
|
||||
VirtualChassis,
|
||||
)
|
||||
from ipam.models import IPAddress
|
||||
from tenancy.models import Tenant
|
||||
from tenancy.models import Tenant, TenantGroup
|
||||
from virtualization.models import Cluster, ClusterType
|
||||
|
||||
|
||||
@@ -76,10 +76,24 @@ class SiteTestCase(TestCase):
|
||||
for region in regions:
|
||||
region.save()
|
||||
|
||||
tenant_groups = (
|
||||
TenantGroup(name='Tenant group 1', slug='tenant-group-1'),
|
||||
TenantGroup(name='Tenant group 2', slug='tenant-group-2'),
|
||||
TenantGroup(name='Tenant group 3', slug='tenant-group-3'),
|
||||
)
|
||||
TenantGroup.objects.bulk_create(tenant_groups)
|
||||
|
||||
tenants = (
|
||||
Tenant(name='Tenant 1', slug='tenant-1', group=tenant_groups[0]),
|
||||
Tenant(name='Tenant 2', slug='tenant-2', group=tenant_groups[1]),
|
||||
Tenant(name='Tenant 3', slug='tenant-3', group=tenant_groups[2]),
|
||||
)
|
||||
Tenant.objects.bulk_create(tenants)
|
||||
|
||||
sites = (
|
||||
Site(name='Site 1', slug='site-1', region=regions[0], status=SiteStatusChoices.STATUS_ACTIVE, facility='Facility 1', asn=65001, latitude=10, longitude=10, contact_name='Contact 1', contact_phone='123-555-0001', contact_email='contact1@example.com'),
|
||||
Site(name='Site 2', slug='site-2', region=regions[1], status=SiteStatusChoices.STATUS_PLANNED, facility='Facility 2', asn=65002, latitude=20, longitude=20, contact_name='Contact 2', contact_phone='123-555-0002', contact_email='contact2@example.com'),
|
||||
Site(name='Site 3', slug='site-3', region=regions[2], status=SiteStatusChoices.STATUS_RETIRED, facility='Facility 3', asn=65003, latitude=30, longitude=30, contact_name='Contact 3', contact_phone='123-555-0003', contact_email='contact3@example.com'),
|
||||
Site(name='Site 1', slug='site-1', region=regions[0], tenant=tenants[0], status=SiteStatusChoices.STATUS_ACTIVE, facility='Facility 1', asn=65001, latitude=10, longitude=10, contact_name='Contact 1', contact_phone='123-555-0001', contact_email='contact1@example.com'),
|
||||
Site(name='Site 2', slug='site-2', region=regions[1], tenant=tenants[1], status=SiteStatusChoices.STATUS_PLANNED, facility='Facility 2', asn=65002, latitude=20, longitude=20, contact_name='Contact 2', contact_phone='123-555-0002', contact_email='contact2@example.com'),
|
||||
Site(name='Site 3', slug='site-3', region=regions[2], tenant=tenants[2], status=SiteStatusChoices.STATUS_RETIRED, facility='Facility 3', asn=65003, latitude=30, longitude=30, contact_name='Contact 3', contact_phone='123-555-0003', contact_email='contact3@example.com'),
|
||||
)
|
||||
Site.objects.bulk_create(sites)
|
||||
|
||||
@@ -140,6 +154,20 @@ class SiteTestCase(TestCase):
|
||||
params = {'region': [regions[0].slug, regions[1].slug]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_tenant(self):
|
||||
tenants = Tenant.objects.all()[:2]
|
||||
params = {'tenant_id': [tenants[0].pk, tenants[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
params = {'tenant': [tenants[0].slug, tenants[1].slug]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_tenant_group(self):
|
||||
tenant_groups = TenantGroup.objects.all()[:2]
|
||||
params = {'tenant_group_id': [tenant_groups[0].pk, tenant_groups[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
params = {'tenant_group': [tenant_groups[0].slug, tenant_groups[1].slug]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
|
||||
class RackGroupTestCase(TestCase):
|
||||
queryset = RackGroup.objects.all()
|
||||
@@ -266,10 +294,24 @@ class RackTestCase(TestCase):
|
||||
)
|
||||
RackRole.objects.bulk_create(rack_roles)
|
||||
|
||||
tenant_groups = (
|
||||
TenantGroup(name='Tenant group 1', slug='tenant-group-1'),
|
||||
TenantGroup(name='Tenant group 2', slug='tenant-group-2'),
|
||||
TenantGroup(name='Tenant group 3', slug='tenant-group-3'),
|
||||
)
|
||||
TenantGroup.objects.bulk_create(tenant_groups)
|
||||
|
||||
tenants = (
|
||||
Tenant(name='Tenant 1', slug='tenant-1', group=tenant_groups[0]),
|
||||
Tenant(name='Tenant 2', slug='tenant-2', group=tenant_groups[1]),
|
||||
Tenant(name='Tenant 3', slug='tenant-3', group=tenant_groups[2]),
|
||||
)
|
||||
Tenant.objects.bulk_create(tenants)
|
||||
|
||||
racks = (
|
||||
Rack(name='Rack 1', facility_id='rack-1', site=sites[0], group=rack_groups[0], status=RackStatusChoices.STATUS_ACTIVE, role=rack_roles[0], serial='ABC', asset_tag='1001', type=RackTypeChoices.TYPE_2POST, width=RackWidthChoices.WIDTH_19IN, u_height=42, desc_units=False, outer_width=100, outer_depth=100, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER),
|
||||
Rack(name='Rack 2', facility_id='rack-2', site=sites[1], group=rack_groups[1], status=RackStatusChoices.STATUS_PLANNED, role=rack_roles[1], serial='DEF', asset_tag='1002', type=RackTypeChoices.TYPE_4POST, width=RackWidthChoices.WIDTH_19IN, u_height=43, desc_units=False, outer_width=200, outer_depth=200, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER),
|
||||
Rack(name='Rack 3', facility_id='rack-3', site=sites[2], group=rack_groups[2], status=RackStatusChoices.STATUS_RESERVED, role=rack_roles[2], serial='GHI', asset_tag='1003', type=RackTypeChoices.TYPE_CABINET, width=RackWidthChoices.WIDTH_23IN, u_height=44, desc_units=True, outer_width=300, outer_depth=300, outer_unit=RackDimensionUnitChoices.UNIT_INCH),
|
||||
Rack(name='Rack 1', facility_id='rack-1', site=sites[0], group=rack_groups[0], tenant=tenants[0], status=RackStatusChoices.STATUS_ACTIVE, role=rack_roles[0], serial='ABC', asset_tag='1001', type=RackTypeChoices.TYPE_2POST, width=RackWidthChoices.WIDTH_19IN, u_height=42, desc_units=False, outer_width=100, outer_depth=100, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER),
|
||||
Rack(name='Rack 2', facility_id='rack-2', site=sites[1], group=rack_groups[1], tenant=tenants[1], status=RackStatusChoices.STATUS_PLANNED, role=rack_roles[1], serial='DEF', asset_tag='1002', type=RackTypeChoices.TYPE_4POST, width=RackWidthChoices.WIDTH_19IN, u_height=43, desc_units=False, outer_width=200, outer_depth=200, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER),
|
||||
Rack(name='Rack 3', facility_id='rack-3', site=sites[2], group=rack_groups[2], tenant=tenants[2], status=RackStatusChoices.STATUS_RESERVED, role=rack_roles[2], serial='GHI', asset_tag='1003', type=RackTypeChoices.TYPE_CABINET, width=RackWidthChoices.WIDTH_23IN, u_height=44, desc_units=True, outer_width=300, outer_depth=300, outer_unit=RackDimensionUnitChoices.UNIT_INCH),
|
||||
)
|
||||
Rack.objects.bulk_create(racks)
|
||||
|
||||
@@ -366,6 +408,20 @@ class RackTestCase(TestCase):
|
||||
params = {'serial': 'abc'}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||
|
||||
def test_tenant(self):
|
||||
tenants = Tenant.objects.all()[:2]
|
||||
params = {'tenant_id': [tenants[0].pk, tenants[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
params = {'tenant': [tenants[0].slug, tenants[1].slug]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_tenant_group(self):
|
||||
tenant_groups = TenantGroup.objects.all()[:2]
|
||||
params = {'tenant_group_id': [tenant_groups[0].pk, tenant_groups[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
params = {'tenant_group': [tenant_groups[0].slug, tenant_groups[1].slug]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
|
||||
class RackReservationTestCase(TestCase):
|
||||
queryset = RackReservation.objects.all()
|
||||
@@ -402,10 +458,24 @@ class RackReservationTestCase(TestCase):
|
||||
)
|
||||
User.objects.bulk_create(users)
|
||||
|
||||
tenant_groups = (
|
||||
TenantGroup(name='Tenant group 1', slug='tenant-group-1'),
|
||||
TenantGroup(name='Tenant group 2', slug='tenant-group-2'),
|
||||
TenantGroup(name='Tenant group 3', slug='tenant-group-3'),
|
||||
)
|
||||
TenantGroup.objects.bulk_create(tenant_groups)
|
||||
|
||||
tenants = (
|
||||
Tenant(name='Tenant 1', slug='tenant-1', group=tenant_groups[0]),
|
||||
Tenant(name='Tenant 2', slug='tenant-2', group=tenant_groups[1]),
|
||||
Tenant(name='Tenant 3', slug='tenant-3', group=tenant_groups[2]),
|
||||
)
|
||||
Tenant.objects.bulk_create(tenants)
|
||||
|
||||
reservations = (
|
||||
RackReservation(rack=racks[0], units=[1, 2, 3], user=users[0]),
|
||||
RackReservation(rack=racks[1], units=[4, 5, 6], user=users[1]),
|
||||
RackReservation(rack=racks[2], units=[7, 8, 9], user=users[2]),
|
||||
RackReservation(rack=racks[0], units=[1, 2, 3], user=users[0], tenant=tenants[0]),
|
||||
RackReservation(rack=racks[1], units=[4, 5, 6], user=users[1], tenant=tenants[1]),
|
||||
RackReservation(rack=racks[2], units=[7, 8, 9], user=users[2], tenant=tenants[2]),
|
||||
)
|
||||
RackReservation.objects.bulk_create(reservations)
|
||||
|
||||
@@ -436,6 +506,20 @@ class RackReservationTestCase(TestCase):
|
||||
# params = {'user': [users[0].username, users[1].username]}
|
||||
# self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_tenant(self):
|
||||
tenants = Tenant.objects.all()[:2]
|
||||
params = {'tenant_id': [tenants[0].pk, tenants[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
params = {'tenant': [tenants[0].slug, tenants[1].slug]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_tenant_group(self):
|
||||
tenant_groups = TenantGroup.objects.all()[:2]
|
||||
params = {'tenant_group_id': [tenant_groups[0].pk, tenant_groups[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
params = {'tenant_group': [tenant_groups[0].slug, tenant_groups[1].slug]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
|
||||
class ManufacturerTestCase(TestCase):
|
||||
queryset = Manufacturer.objects.all()
|
||||
@@ -1099,10 +1183,24 @@ class DeviceTestCase(TestCase):
|
||||
)
|
||||
Cluster.objects.bulk_create(clusters)
|
||||
|
||||
tenant_groups = (
|
||||
TenantGroup(name='Tenant group 1', slug='tenant-group-1'),
|
||||
TenantGroup(name='Tenant group 2', slug='tenant-group-2'),
|
||||
TenantGroup(name='Tenant group 3', slug='tenant-group-3'),
|
||||
)
|
||||
TenantGroup.objects.bulk_create(tenant_groups)
|
||||
|
||||
tenants = (
|
||||
Tenant(name='Tenant 1', slug='tenant-1', group=tenant_groups[0]),
|
||||
Tenant(name='Tenant 2', slug='tenant-2', group=tenant_groups[1]),
|
||||
Tenant(name='Tenant 3', slug='tenant-3', group=tenant_groups[2]),
|
||||
)
|
||||
Tenant.objects.bulk_create(tenants)
|
||||
|
||||
devices = (
|
||||
Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], platform=platforms[0], serial='ABC', asset_tag='1001', site=sites[0], rack=racks[0], position=1, face=DeviceFaceChoices.FACE_FRONT, status=DeviceStatusChoices.STATUS_ACTIVE, cluster=clusters[0], local_context_data={"foo": 123}),
|
||||
Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], platform=platforms[1], serial='DEF', asset_tag='1002', site=sites[1], rack=racks[1], position=2, face=DeviceFaceChoices.FACE_FRONT, status=DeviceStatusChoices.STATUS_STAGED, cluster=clusters[1]),
|
||||
Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], platform=platforms[2], serial='GHI', asset_tag='1003', site=sites[2], rack=racks[2], position=3, face=DeviceFaceChoices.FACE_REAR, status=DeviceStatusChoices.STATUS_FAILED, cluster=clusters[2]),
|
||||
Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], platform=platforms[0], tenant=tenants[0], serial='ABC', asset_tag='1001', site=sites[0], rack=racks[0], position=1, face=DeviceFaceChoices.FACE_FRONT, status=DeviceStatusChoices.STATUS_ACTIVE, cluster=clusters[0], local_context_data={"foo": 123}),
|
||||
Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], platform=platforms[1], tenant=tenants[1], serial='DEF', asset_tag='1002', site=sites[1], rack=racks[1], position=2, face=DeviceFaceChoices.FACE_FRONT, status=DeviceStatusChoices.STATUS_STAGED, cluster=clusters[1]),
|
||||
Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], platform=platforms[2], tenant=tenants[2], serial='GHI', asset_tag='1003', site=sites[2], rack=racks[2], position=3, face=DeviceFaceChoices.FACE_REAR, status=DeviceStatusChoices.STATUS_FAILED, cluster=clusters[2]),
|
||||
)
|
||||
Device.objects.bulk_create(devices)
|
||||
|
||||
@@ -1333,6 +1431,20 @@ class DeviceTestCase(TestCase):
|
||||
params = {'local_context_data': 'false'}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_tenant(self):
|
||||
tenants = Tenant.objects.all()[:2]
|
||||
params = {'tenant_id': [tenants[0].pk, tenants[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
params = {'tenant': [tenants[0].slug, tenants[1].slug]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_tenant_group(self):
|
||||
tenant_groups = TenantGroup.objects.all()[:2]
|
||||
params = {'tenant_group_id': [tenant_groups[0].pk, tenant_groups[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
params = {'tenant_group': [tenant_groups[0].slug, tenant_groups[1].slug]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
|
||||
class ConsolePortTestCase(TestCase):
|
||||
queryset = ConsolePort.objects.all()
|
||||
|
||||
@@ -2,7 +2,6 @@ from django.core.exceptions import ValidationError
|
||||
from django.test import TestCase
|
||||
|
||||
from dcim.choices import *
|
||||
from dcim.constants import CONNECTION_STATUS_CONNECTED, CONNECTION_STATUS_PLANNED
|
||||
from dcim.models import *
|
||||
from tenancy.models import Tenant
|
||||
|
||||
@@ -522,14 +521,14 @@ class CablePathTestCase(TestCase):
|
||||
cable3.save()
|
||||
interface1 = Interface.objects.get(pk=self.interface1.pk)
|
||||
self.assertEqual(interface1.connected_endpoint, self.interface2)
|
||||
self.assertEqual(interface1.connection_status, CONNECTION_STATUS_PLANNED)
|
||||
self.assertFalse(interface1.connection_status)
|
||||
|
||||
# Switch third segment from planned to connected
|
||||
cable3.status = CableStatusChoices.STATUS_CONNECTED
|
||||
cable3.save()
|
||||
interface1 = Interface.objects.get(pk=self.interface1.pk)
|
||||
self.assertEqual(interface1.connected_endpoint, self.interface2)
|
||||
self.assertEqual(interface1.connection_status, CONNECTION_STATUS_CONNECTED)
|
||||
self.assertTrue(interface1.connection_status)
|
||||
|
||||
def test_path_teardown(self):
|
||||
|
||||
@@ -542,7 +541,7 @@ class CablePathTestCase(TestCase):
|
||||
cable3.save()
|
||||
interface1 = Interface.objects.get(pk=self.interface1.pk)
|
||||
self.assertEqual(interface1.connected_endpoint, self.interface2)
|
||||
self.assertEqual(interface1.connection_status, CONNECTION_STATUS_CONNECTED)
|
||||
self.assertTrue(interface1.connection_status)
|
||||
|
||||
# Remove a cable
|
||||
cable2.delete()
|
||||
|
||||
@@ -357,7 +357,7 @@ class RackElevationListView(PermissionRequiredMixin, View):
|
||||
|
||||
def get(self, request):
|
||||
|
||||
racks = Rack.objects.prefetch_related('site', 'group', 'tenant', 'role', 'devices__device_type')
|
||||
racks = Rack.objects.prefetch_related('role')
|
||||
racks = filters.RackFilterSet(request.GET, racks).qs
|
||||
total_count = racks.count()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user