From 03ce4bdfcafa92d5d1989e274abd2f8394f15dd3 Mon Sep 17 00:00:00 2001 From: dansheps Date: Thu, 24 May 2018 15:27:09 -0500 Subject: [PATCH 01/12] Added VirtualChassis Searching --- netbox/netbox/forms.py | 1 + netbox/netbox/views.py | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/netbox/netbox/forms.py b/netbox/netbox/forms.py index caa074e18..c682c353e 100644 --- a/netbox/netbox/forms.py +++ b/netbox/netbox/forms.py @@ -15,6 +15,7 @@ OBJ_TYPE_CHOICES = ( ('rack', 'Racks'), ('devicetype', 'Device types'), ('device', 'Devices'), + ('virtualchassis','Virtual Chassis'), )), ('IPAM', ( ('vrf', 'VRFs'), diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py index 0f240fff3..e3fd4d4db 100644 --- a/netbox/netbox/views.py +++ b/netbox/netbox/views.py @@ -12,9 +12,9 @@ from rest_framework.views import APIView from circuits.filters import CircuitFilter, ProviderFilter from circuits.models import Circuit, Provider from circuits.tables import CircuitTable, ProviderTable -from dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter -from dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site -from dcim.tables import DeviceDetailTable, DeviceTypeTable, RackTable, SiteTable +from dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter, VirtualChassisFilter +from dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site, VirtualChassis +from dcim.tables import DeviceDetailTable, DeviceTypeTable, RackTable, SiteTable, VirtualChassisTable from extras.models import ReportResult, TopologyMap, UserAction from ipam.filters import AggregateFilter, IPAddressFilter, PrefixFilter, VLANFilter, VRFFilter from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF @@ -72,6 +72,12 @@ SEARCH_TYPES = OrderedDict(( 'table': DeviceDetailTable, 'url': 'dcim:device_list', }), + ('virtualchassis', { + 'queryset': VirtualChassis.objects.select_related('master'), + 'filter': VirtualChassisFilter, + 'table': VirtualChassisTable, + 'url': 'dcim:virtualchassis_list', + }), # IPAM ('vrf', { 'queryset': VRF.objects.select_related('tenant'), From acc59a9da51c21da3055055451c0b7458a90e423 Mon Sep 17 00:00:00 2001 From: dansheps Date: Thu, 24 May 2018 16:03:13 -0500 Subject: [PATCH 02/12] Fix PEP8 --- netbox/netbox/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/forms.py b/netbox/netbox/forms.py index c682c353e..5611f49f9 100644 --- a/netbox/netbox/forms.py +++ b/netbox/netbox/forms.py @@ -15,7 +15,7 @@ OBJ_TYPE_CHOICES = ( ('rack', 'Racks'), ('devicetype', 'Device types'), ('device', 'Devices'), - ('virtualchassis','Virtual Chassis'), + ('virtualchassis', 'Virtual Chassis'), )), ('IPAM', ( ('vrf', 'VRFs'), From f70b7cab21c3f8e47a8cc54bad254d0e068d0db8 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Tue, 3 Jul 2018 15:53:58 -0700 Subject: [PATCH 03/12] More verbose LDAP nested groups documentation --- docs/installation/ldap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/ldap.md b/docs/installation/ldap.md index d8053da48..54419412e 100644 --- a/docs/installation/ldap.md +++ b/docs/installation/ldap.md @@ -81,7 +81,7 @@ AUTH_LDAP_USER_ATTR_MAP = { # User Groups for Permissions !!! info - When using Microsoft Active Directory, support for nested groups can be activated by using `NestedGroupOfNamesType()` instead of `GroupOfNamesType()` for `AUTH_LDAP_GROUP_TYPE`. + When using Microsoft Active Directory, support for nested groups can be activated by using `NestedGroupOfNamesType()` instead of `GroupOfNamesType()` for `AUTH_LDAP_GROUP_TYPE`. You will also need to modify the import line to use `NestedGroupOfNamesType` instead of `GroupOfNamesType` . ```python from django_auth_ldap.config import LDAPSearch, GroupOfNamesType From b19bf791a4e85c486dfa13e0f9ce0753fd80ff4c Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 5 Jul 2018 11:58:07 -0400 Subject: [PATCH 04/12] Closes #2138: Added documentation for filtering on custom fields --- docs/api/overview.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/api/overview.md b/docs/api/overview.md index ba7e11bbf..85d972008 100644 --- a/docs/api/overview.md +++ b/docs/api/overview.md @@ -206,3 +206,28 @@ The maximum number of objects that can be returned is limited by the [`MAX_PAGE_ !!! warning Disabling the page size limit introduces a potential for very resource-intensive requests, since one API request can effectively retrieve an entire table from the database. + +# Filtering + +A list of objects retrieved via the API can be filtered by passing one or more query parameters. The same parameters used by the web UI work for the API as well. For example, to return only prefixes with a status of "Active" (`1`): + +``` +GET /api/ipam/prefixes/?status=1 +``` + +The same filter can be incldued multiple times. These will effect a logical OR and return objects matching any of the given values. For example, the following will return all active and reserved prefixes: + +``` +GET /api/ipam/prefixes/?status=1&status=2 +``` + +## Custom Fields + +To filter on a custom field, prepend `cf_` to the field name. For example, the following query will return only sites where a custom field named `foo` is equal to 123: + +``` +GET /api/dcim/sites/?cf_foo=123 +``` + +!!! note + Full versus partial matching when filtering is configurable per custom field. Filtering can be toggled (or disabled) for a custom field in the admin UI. From 4bd36f0ea9f2402aa7ce121a310563ce1900f0d6 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 5 Jul 2018 12:02:32 -0400 Subject: [PATCH 05/12] Closes #2062: Added a note about parent/child device type role --- docs/data-model/dcim.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/data-model/dcim.md b/docs/data-model/dcim.md index 3cb3ed13e..5c9097569 100644 --- a/docs/data-model/dcim.md +++ b/docs/data-model/dcim.md @@ -42,6 +42,8 @@ A device type represents a particular hardware model that exists in the real wor Device types are instantiated as devices installed within racks. For example, you might define a device type to represent a Juniper EX4300-48T network switch with 48 Ethernet interfaces. You can then create multiple devices of this type named "switch1," "switch2," and so on. Each device will inherit the components (such as interfaces) of its device type. +A device type can be a parent, child, or neither. Parent devices house child devices in device bays. This relationship is used to model things like blade servers, where child devices function independently but share physical resources like rack space and power. Note that this is **not** intended to model chassis-based devices, wherein child members share a common control plane. + ### Manufacturers Each device type belongs to one manufacturer; e.g. Cisco, Opengear, or APC. The model number of a device type must be unique to its manufacturer. From 72cb1cbfff1b503722f7c98ae5bba88ce6cb919f Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 5 Jul 2018 13:20:27 -0400 Subject: [PATCH 06/12] Queryset fixes for virtual chassis --- netbox/dcim/views.py | 2 +- netbox/netbox/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 6e7aa070c..bee775773 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -2075,7 +2075,7 @@ class InventoryItemBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): # class VirtualChassisListView(ObjectListView): - queryset = VirtualChassis.objects.annotate(member_count=Count('members')) + queryset = VirtualChassis.objects.select_related('master').annotate(member_count=Count('members')) table = tables.VirtualChassisTable filter = filters.VirtualChassisFilter filter_form = forms.VirtualChassisFilterForm diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py index e3fd4d4db..f2aa30b9e 100644 --- a/netbox/netbox/views.py +++ b/netbox/netbox/views.py @@ -73,7 +73,7 @@ SEARCH_TYPES = OrderedDict(( 'url': 'dcim:device_list', }), ('virtualchassis', { - 'queryset': VirtualChassis.objects.select_related('master'), + 'queryset': VirtualChassis.objects.select_related('master').annotate(member_count=Count('members')), 'filter': VirtualChassisFilter, 'table': VirtualChassisTable, 'url': 'dcim:virtualchassis_list', From 108e9722fabd8e4f0a38a4322fc1c96d83fbe0ac Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 5 Jul 2018 13:28:26 -0400 Subject: [PATCH 07/12] Fixes #2214: Fix bug when assigning a VLAN to an interface on a VM in a cluster with no assigned site --- netbox/dcim/forms.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 593bef113..f8779dc06 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -1780,8 +1780,9 @@ class InterfaceAssignVLANsForm(BootstrapMixin, forms.ModelForm): if parent is not None: # Add site VLANs - site_vlans = VLAN.objects.filter(site=parent.site, group=None).exclude(pk__in=assigned_vlans) - vlan_choices.append((parent.site.name, [(vlan.pk, vlan) for vlan in site_vlans])) + if parent.site: + site_vlans = VLAN.objects.filter(site=parent.site, group=None).exclude(pk__in=assigned_vlans) + vlan_choices.append((parent.site.name, [(vlan.pk, vlan) for vlan in site_vlans])) # Add grouped site VLANs for group in VLANGroup.objects.filter(site=parent.site): From b6e354085ecfc4048b5e0d9a629cc0db75d4931b Mon Sep 17 00:00:00 2001 From: zmoody Date: Tue, 10 Jul 2018 20:40:48 -0500 Subject: [PATCH 08/12] Fixes #2125 - Show child status in device bay list Exposes devicebay.installed_device.status in the parent device detail view. --- netbox/templates/dcim/device.html | 1 + netbox/templates/dcim/inc/devicebay.html | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index e2253d4f4..7e36452cb 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -387,6 +387,7 @@ {% endif %} Name + Status Installed Device diff --git a/netbox/templates/dcim/inc/devicebay.html b/netbox/templates/dcim/inc/devicebay.html index 4e17e3d36..656116c89 100644 --- a/netbox/templates/dcim/inc/devicebay.html +++ b/netbox/templates/dcim/inc/devicebay.html @@ -8,6 +8,9 @@ {{ devicebay.name }} {% if devicebay.installed_device %} + + {{ devicebay.installed_device.get_status_display }} + {{ devicebay.installed_device }} @@ -15,6 +18,7 @@ {{ devicebay.installed_device.device_type.full_name }} {% else %} + Vacant From a26d1812c2e3715b7f59b90ec020c99226f84a0a Mon Sep 17 00:00:00 2001 From: mmahacek Date: Wed, 11 Jul 2018 11:52:33 -0700 Subject: [PATCH 09/12] Update sample report Reference to STATUS_ACTIVE does not work in the current version. Needs to be changed to DEVICE_STATUS_ACTIVE. --- docs/miscellaneous/reports.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/miscellaneous/reports.md b/docs/miscellaneous/reports.md index daffa72ae..234766639 100644 --- a/docs/miscellaneous/reports.md +++ b/docs/miscellaneous/reports.md @@ -32,7 +32,7 @@ class DeviceIPsReport(Report): Within each report class, we'll create a number of test methods to execute our report's logic. In DeviceConnectionsReport, for instance, we want to ensure that every live device has a console connection, an out-of-band management connection, and two power connections. ``` -from dcim.constants import CONNECTION_STATUS_PLANNED, STATUS_ACTIVE +from dcim.constants import CONNECTION_STATUS_PLANNED, DEVICE_STATUS_ACTIVE from dcim.models import ConsolePort, Device, PowerPort from extras.reports import Report @@ -43,7 +43,7 @@ class DeviceConnectionsReport(Report): def test_console_connection(self): # Check that every console port for every active device has a connection defined. - for console_port in ConsolePort.objects.select_related('device').filter(device__status=STATUS_ACTIVE): + for console_port in ConsolePort.objects.select_related('device').filter(device__status=DEVICE_STATUS_ACTIVE): if console_port.cs_port is None: self.log_failure( console_port.device, @@ -60,7 +60,7 @@ class DeviceConnectionsReport(Report): def test_power_connections(self): # Check that every active device has at least two connected power supplies. - for device in Device.objects.filter(status=STATUS_ACTIVE): + for device in Device.objects.filter(status=DEVICE_STATUS_ACTIVE): connected_ports = 0 for power_port in PowerPort.objects.filter(device=device): if power_port.power_outlet is not None: From 1fb67b791f1a91c624dae4a1cd256e4cf3ddbb77 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 16 Jul 2018 11:39:37 -0400 Subject: [PATCH 10/12] Fixes #2239: Pin django-filter to version 1.1.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5b7b3e73e..8d7e251af 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ Django>=1.11,<2.0 django-cors-headers>=2.1.0 django-debug-toolbar>=1.9.0 -django-filter>=1.1.0 +django-filter==1.1.0 django-mptt>=0.9.0 django-tables2>=1.19.0 django-timezone-field>=2.0 From 456b058462abfce4ffa213d2472599a2f016c887 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 16 Jul 2018 11:52:12 -0400 Subject: [PATCH 11/12] Release v2.3.6 --- netbox/netbox/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 71c41063c..5868af291 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -22,7 +22,7 @@ if sys.version_info[0] < 3: DeprecationWarning ) -VERSION = '2.3.6-dev' +VERSION = '2.3.6' BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) From 786f389be86fe4b649487146a467adb6b20c5d95 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 16 Jul 2018 11:56:12 -0400 Subject: [PATCH 12/12] Post-release version bump --- netbox/netbox/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 5868af291..f45024b57 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -22,7 +22,7 @@ if sys.version_info[0] < 3: DeprecationWarning ) -VERSION = '2.3.6' +VERSION = '2.3.7-dev' BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))