diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index c01fd330b..114b8283a 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -226,8 +226,7 @@ class DeviceTypeSerializer(TaggitSerializer, CustomFieldModelSerializer): model = DeviceType fields = [ 'id', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'interface_ordering', - 'is_console_server', 'is_pdu', 'is_network_device', 'subdevice_role', 'comments', 'tags', - 'custom_fields', 'created', 'last_updated', 'instance_count', + 'subdevice_role', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'instance_count', ] diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index f0ce0cfea..20f9cba1c 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -1,6 +1,6 @@ import django_filters from django.contrib.auth.models import User -from django.db.models import Q +from django.db.models import Count, Q from netaddr import EUI from netaddr.core import AddrFormatError @@ -310,8 +310,7 @@ class DeviceTypeFilter(CustomFieldFilterSet, django_filters.FilterSet): class Meta: model = DeviceType fields = [ - 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'is_console_server', 'is_pdu', - 'is_network_device', 'subdevice_role', + 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', ] def search(self, queryset, name, value): @@ -506,18 +505,19 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet): name='device_type__is_full_depth', label='Is full depth', ) - is_console_server = django_filters.BooleanFilter( - name='device_type__is_console_server', - label='Is a console server', - ) - is_pdu = django_filters.BooleanFilter( - name='device_type__is_pdu', - label='Is a PDU', - ) - is_network_device = django_filters.BooleanFilter( - name='device_type__is_network_device', - label='Is a network device', - ) + # TODO: Replace these filters + # is_console_server = django_filters.BooleanFilter( + # name='device_type__is_console_server', + # label='Is a console server', + # ) + # is_pdu = django_filters.BooleanFilter( + # name='device_type__is_pdu', + # label='Is a PDU', + # ) + # is_network_device = django_filters.BooleanFilter( + # name='device_type__is_network_device', + # label='Is a network device', + # ) mac_address = django_filters.CharFilter( method='_mac_address', label='MAC address', diff --git a/netbox/dcim/fixtures/dcim.json b/netbox/dcim/fixtures/dcim.json index 9ebe9d4c7..215fbb702 100644 --- a/netbox/dcim/fixtures/dcim.json +++ b/netbox/dcim/fixtures/dcim.json @@ -76,10 +76,7 @@ "model": "MX960", "slug": "mx960", "u_height": 16, - "is_full_depth": true, - "is_console_server": false, - "is_pdu": false, - "is_network_device": true + "is_full_depth": true } }, { @@ -92,10 +89,7 @@ "model": "EX9214", "slug": "ex9214", "u_height": 16, - "is_full_depth": true, - "is_console_server": false, - "is_pdu": false, - "is_network_device": true + "is_full_depth": true } }, { @@ -108,10 +102,7 @@ "model": "QFX5100-24Q", "slug": "qfx5100-24q", "u_height": 1, - "is_full_depth": true, - "is_console_server": false, - "is_pdu": false, - "is_network_device": true + "is_full_depth": true } }, { @@ -124,10 +115,7 @@ "model": "QFX5100-48S", "slug": "qfx5100-48s", "u_height": 1, - "is_full_depth": true, - "is_console_server": false, - "is_pdu": false, - "is_network_device": true + "is_full_depth": true } }, { @@ -140,10 +128,7 @@ "model": "CM4148", "slug": "cm4148", "u_height": 1, - "is_full_depth": true, - "is_console_server": true, - "is_pdu": false, - "is_network_device": false + "is_full_depth": true } }, { @@ -156,10 +141,7 @@ "model": "CWG-24VYM415C9", "slug": "cwg-24vym415c9", "u_height": 0, - "is_full_depth": false, - "is_console_server": false, - "is_pdu": true, - "is_network_device": false + "is_full_depth": false } }, { diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index a09ee7161..8db4ceb4f 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -531,8 +531,8 @@ class DeviceTypeForm(BootstrapMixin, CustomFieldForm): class Meta: model = DeviceType fields = [ - 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'is_console_server', 'is_pdu', - 'is_network_device', 'subdevice_role', 'interface_ordering', 'comments', 'tags', + 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', + 'interface_ordering', 'comments', 'tags', ] labels = { 'interface_ordering': 'Order interfaces by', @@ -575,13 +575,6 @@ class DeviceTypeBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkE u_height = forms.IntegerField(min_value=1, required=False) is_full_depth = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label='Is full depth') interface_ordering = forms.ChoiceField(choices=add_blank_choice(IFACE_ORDERING_CHOICES), required=False) - is_console_server = forms.NullBooleanField( - required=False, widget=BulkEditNullBooleanSelect, label='Is a console server' - ) - is_pdu = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label='Is a PDU') - is_network_device = forms.NullBooleanField( - required=False, widget=BulkEditNullBooleanSelect, label='Is a network device' - ) class Meta: nullable_fields = [] @@ -594,14 +587,6 @@ class DeviceTypeFilterForm(BootstrapMixin, CustomFieldFilterForm): queryset=Manufacturer.objects.annotate(filter_count=Count('device_types')), to_field_name='slug' ) - is_console_server = forms.BooleanField( - required=False, label='Is a console server', widget=forms.CheckboxInput(attrs={'value': 'True'})) - is_pdu = forms.BooleanField( - required=False, label='Is a PDU', widget=forms.CheckboxInput(attrs={'value': 'True'}) - ) - is_network_device = forms.BooleanField( - required=False, label='Is a network device', widget=forms.CheckboxInput(attrs={'value': 'True'}) - ) subdevice_role = forms.NullBooleanField( required=False, label='Subdevice role', widget=forms.Select(choices=( ('', '---------'), @@ -1288,7 +1273,7 @@ class ConsolePortCreateForm(ComponentForm): class ConsoleConnectionCSVForm(forms.ModelForm): console_server = FlexibleModelChoiceField( - queryset=Device.objects.filter(device_type__is_console_server=True), + queryset=Device.objects.all(), to_field_name='name', help_text='Console server name or ID', error_messages={ @@ -1387,7 +1372,7 @@ class ConsolePortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelF ) ) console_server = ChainedModelChoiceField( - queryset=Device.objects.filter(device_type__is_console_server=True), + queryset=Device.objects.all(), chains=( ('site', 'site'), ('rack', 'rack'), @@ -1395,7 +1380,7 @@ class ConsolePortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelF label='Console Server', required=False, widget=APISelect( - api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}&is_console_server=True', + api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}', display_field='display_name', attrs={'filter-for': 'connected_endpoint'} ) @@ -1557,7 +1542,7 @@ class PowerPortCreateForm(ComponentForm): class PowerConnectionCSVForm(forms.ModelForm): pdu = FlexibleModelChoiceField( - queryset=Device.objects.filter(device_type__is_pdu=True), + queryset=Device.objects.all(), to_field_name='name', help_text='PDU name or ID', error_messages={ @@ -1664,7 +1649,7 @@ class PowerPortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor label='PDU', required=False, widget=APISelect( - api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}&is_pdu=True', + api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}', display_field='display_name', attrs={'filter-for': 'connected_endpoint'} ) diff --git a/netbox/dcim/migrations/0067_device_type_remove_qualifiers.py b/netbox/dcim/migrations/0067_device_type_remove_qualifiers.py new file mode 100644 index 000000000..883f863fc --- /dev/null +++ b/netbox/dcim/migrations/0067_device_type_remove_qualifiers.py @@ -0,0 +1,25 @@ +# Generated by Django 2.0.8 on 2018-10-26 17:49 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0066_cables'), + ] + + operations = [ + migrations.RemoveField( + model_name='devicetype', + name='is_console_server', + ), + migrations.RemoveField( + model_name='devicetype', + name='is_network_device', + ), + migrations.RemoveField( + model_name='devicetype', + name='is_pdu', + ), + ] diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index bc2dbc88b..bb5c13fd8 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -770,21 +770,6 @@ class DeviceType(ChangeLoggedModel, CustomFieldModel): choices=IFACE_ORDERING_CHOICES, default=IFACE_ORDERING_POSITION ) - is_console_server = models.BooleanField( - default=False, - verbose_name='Is a console server', - help_text='This type of device has console server ports' - ) - is_pdu = models.BooleanField( - default=False, - verbose_name='Is a PDU', - help_text='This type of device has power outlets' - ) - is_network_device = models.BooleanField( - default=True, - verbose_name='Is a network device', - help_text='This type of device has network interfaces' - ) subdevice_role = models.NullBooleanField( default=None, verbose_name='Parent/child status', @@ -804,8 +789,8 @@ class DeviceType(ChangeLoggedModel, CustomFieldModel): tags = TaggableManager() csv_headers = [ - 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'is_console_server', 'is_pdu', - 'is_network_device', 'subdevice_role', 'interface_ordering', 'comments', + 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', + 'interface_ordering', 'comments', ] class Meta: @@ -835,9 +820,6 @@ class DeviceType(ChangeLoggedModel, CustomFieldModel): self.part_number, self.u_height, self.is_full_depth, - self.is_console_server, - self.is_pdu, - self.is_network_device, self.get_subdevice_role_display() if self.subdevice_role else None, self.get_interface_ordering_display(), self.comments, @@ -859,24 +841,6 @@ class DeviceType(ChangeLoggedModel, CustomFieldModel): "{}U".format(d, d.rack, self.u_height) }) - if not self.is_console_server and self.cs_port_templates.count(): - raise ValidationError({ - 'is_console_server': "Must delete all console server port templates associated with this device before " - "declassifying it as a console server." - }) - - if not self.is_pdu and self.power_outlet_templates.count(): - raise ValidationError({ - 'is_pdu': "Must delete all power outlet templates associated with this device before declassifying it " - "as a PDU." - }) - - if not self.is_network_device and self.interface_templates.filter(mgmt_only=False).count(): - raise ValidationError({ - 'is_network_device': "Must delete all non-management-only interface templates associated with this " - "device before declassifying it as a network device." - }) - if self.subdevice_role != SUBDEVICE_ROLE_PARENT and self.device_bay_templates.count(): raise ValidationError({ 'subdevice_role': "Must delete all device bay templates associated with this device before " @@ -1705,17 +1669,6 @@ class ConsoleServerPort(CableTermination, ComponentModel): def get_absolute_url(self): return self.device.get_absolute_url() - def clean(self): - - # Check that the parent device's DeviceType is a console server - if self.device is None: - raise ValidationError("Console server ports must be assigned to devices.") - device_type = self.device.device_type - if not device_type.is_console_server: - raise ValidationError("The {} {} device type does not support assignment of console server ports.".format( - device_type.manufacturer, device_type - )) - # # Power ports @@ -1808,17 +1761,6 @@ class PowerOutlet(CableTermination, ComponentModel): def get_absolute_url(self): return self.device.get_absolute_url() - def clean(self): - - # Check that the parent device's DeviceType is a PDU - if self.device is None: - raise ValidationError("Power outlets must be assigned to devices.") - device_type = self.device.device_type - if not device_type.is_pdu: - raise ValidationError("The {} {} device type does not support assignment of power outlets.".format( - device_type.manufacturer, device_type - )) - # # Interfaces @@ -1927,14 +1869,6 @@ class Interface(CableTermination, ComponentModel): def clean(self): - # Check that the parent device's DeviceType is a network device - if self.device is not None: - device_type = self.device.device_type - if not device_type.is_network_device: - raise ValidationError("The {} {} device type does not support assignment of network interfaces.".format( - device_type.manufacturer, device_type - )) - # An Interface must belong to a Device *or* to a VirtualMachine if self.device and self.virtual_machine: raise ValidationError("An interface cannot belong to both a device and a virtual machine.") diff --git a/netbox/dcim/tables.py b/netbox/dcim/tables.py index 412b1224c..39085cc45 100644 --- a/netbox/dcim/tables.py +++ b/netbox/dcim/tables.py @@ -349,9 +349,6 @@ class DeviceTypeTable(BaseTable): verbose_name='Device Type' ) is_full_depth = BooleanColumn(verbose_name='Full Depth') - is_console_server = BooleanColumn(verbose_name='CS') - is_pdu = BooleanColumn(verbose_name='PDU') - is_network_device = BooleanColumn(verbose_name='Net') subdevice_role = tables.TemplateColumn( template_code=SUBDEVICE_ROLE_TEMPLATE, verbose_name='Subdevice Role' @@ -364,8 +361,8 @@ class DeviceTypeTable(BaseTable): class Meta(BaseTable.Meta): model = DeviceType fields = ( - 'pk', 'model', 'manufacturer', 'part_number', 'u_height', 'is_full_depth', 'is_console_server', 'is_pdu', - 'is_network_device', 'subdevice_role', 'instance_count', + 'pk', 'model', 'manufacturer', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', + 'instance_count', ) diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index 774725725..389797a09 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -2035,7 +2035,7 @@ class ConsoleServerPortTest(APITestCase): site = Site.objects.create(name='Test Site 1', slug='test-site-1') manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1') devicetype = DeviceType.objects.create( - manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1', is_console_server=True + manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1' ) devicerole = DeviceRole.objects.create( name='Test Device Role 1', slug='test-device-role-1', color='ff0000' @@ -2261,7 +2261,7 @@ class PowerOutletTest(APITestCase): site = Site.objects.create(name='Test Site 1', slug='test-site-1') manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1') devicetype = DeviceType.objects.create( - manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1', is_pdu=True + manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1' ) devicerole = DeviceRole.objects.create( name='Test Device Role 1', slug='test-device-role-1', color='ff0000' @@ -2372,7 +2372,7 @@ class InterfaceTest(APITestCase): site = Site.objects.create(name='Test Site 1', slug='test-site-1') manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1') devicetype = DeviceType.objects.create( - manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1', is_network_device=True + manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1' ) devicerole = DeviceRole.objects.create( name='Test Device Role 1', slug='test-device-role-1', color='ff0000' diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index e2ae02bff..29f187825 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -35,6 +35,21 @@
- {% if devicetype.is_console_server %} - - {% else %} - - {% endif %} - | -
- Console Server - This device {% if devicetype.is_console_server %}has{% else %}does not have{% endif %} console server ports - |
-
- {% if devicetype.is_pdu %} - - {% else %} - - {% endif %} - | -
- PDU - This device {% if devicetype.is_pdu %}has{% else %}does not have{% endif %} power outlets - |
-
- {% if devicetype.is_network_device %} - - {% else %} - - {% endif %} - | -
- Network Device - This device {% if devicetype.is_network_device %}has{% else %}does not have{% endif %} network interfaces - |
-
- {% if devicetype.subdevice_role == True %} - - {% elif devicetype.subdevice_role == False %} - - {% else %} - - {% endif %} - | -
- Parent/Child - {% if devicetype.subdevice_role == True %} - This device has device bays for mounting child devices - {% elif devicetype.subdevice_role == False %} - This device can only be mounted in a parent device - {% else %} - This device does not have device bays - {% endif %} - |
-