diff --git a/base_requirements.txt b/base_requirements.txt index 3d1578400..cd7d9ef45 100644 --- a/base_requirements.txt +++ b/base_requirements.txt @@ -18,6 +18,14 @@ django-filter # https://github.com/django-mptt/django-mptt django-mptt +# Prometheus metrics client implementation for Django +# https://github.com/korfuri/django-prometheus +django-prometheus + +# Django caching using Redis +# https://github.com/niwinz/django-redis +django-redis + # Abstraction models for rendering and paginating HTML tables # https://github.com/jieter/django-tables2 django-tables2 diff --git a/netbox/circuits/urls.py b/netbox/circuits/urls.py index 5b818a945..8fe4f4803 100644 --- a/netbox/circuits/urls.py +++ b/netbox/circuits/urls.py @@ -2,6 +2,7 @@ from django.conf.urls import url from dcim.views import CableCreateView, CableTraceView from extras.views import ObjectChangeLogView +from utilities.urls import cached from . import views from .models import Circuit, CircuitTermination, CircuitType, Provider @@ -9,41 +10,41 @@ app_name = 'circuits' urlpatterns = [ # Providers - url(r'^providers/$', views.ProviderListView.as_view(), name='provider_list'), + url(r'^providers/$', cached(views.ProviderListView.as_view()), name='provider_list'), url(r'^providers/add/$', views.ProviderCreateView.as_view(), name='provider_add'), url(r'^providers/import/$', views.ProviderBulkImportView.as_view(), name='provider_import'), url(r'^providers/edit/$', views.ProviderBulkEditView.as_view(), name='provider_bulk_edit'), url(r'^providers/delete/$', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'), - url(r'^providers/(?P[\w-]+)/$', views.ProviderView.as_view(), name='provider'), + url(r'^providers/(?P[\w-]+)/$', cached(views.ProviderView.as_view()), name='provider'), url(r'^providers/(?P[\w-]+)/edit/$', views.ProviderEditView.as_view(), name='provider_edit'), url(r'^providers/(?P[\w-]+)/delete/$', views.ProviderDeleteView.as_view(), name='provider_delete'), - url(r'^providers/(?P[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='provider_changelog', kwargs={'model': Provider}), + url(r'^providers/(?P[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='provider_changelog', kwargs={'model': Provider}), # Circuit types - url(r'^circuit-types/$', views.CircuitTypeListView.as_view(), name='circuittype_list'), + url(r'^circuit-types/$', cached(views.CircuitTypeListView.as_view()), name='circuittype_list'), url(r'^circuit-types/add/$', views.CircuitTypeCreateView.as_view(), name='circuittype_add'), url(r'^circuit-types/import/$', views.CircuitTypeBulkImportView.as_view(), name='circuittype_import'), url(r'^circuit-types/delete/$', views.CircuitTypeBulkDeleteView.as_view(), name='circuittype_bulk_delete'), url(r'^circuit-types/(?P[\w-]+)/edit/$', views.CircuitTypeEditView.as_view(), name='circuittype_edit'), - url(r'^circuit-types/(?P[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='circuittype_changelog', kwargs={'model': CircuitType}), + url(r'^circuit-types/(?P[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='circuittype_changelog', kwargs={'model': CircuitType}), # Circuits - url(r'^circuits/$', views.CircuitListView.as_view(), name='circuit_list'), + url(r'^circuits/$', cached(views.CircuitListView.as_view()), name='circuit_list'), url(r'^circuits/add/$', views.CircuitCreateView.as_view(), name='circuit_add'), url(r'^circuits/import/$', views.CircuitBulkImportView.as_view(), name='circuit_import'), url(r'^circuits/edit/$', views.CircuitBulkEditView.as_view(), name='circuit_bulk_edit'), url(r'^circuits/delete/$', views.CircuitBulkDeleteView.as_view(), name='circuit_bulk_delete'), - url(r'^circuits/(?P\d+)/$', views.CircuitView.as_view(), name='circuit'), + url(r'^circuits/(?P\d+)/$', cached(views.CircuitView.as_view()), name='circuit'), url(r'^circuits/(?P\d+)/edit/$', views.CircuitEditView.as_view(), name='circuit_edit'), url(r'^circuits/(?P\d+)/delete/$', views.CircuitDeleteView.as_view(), name='circuit_delete'), - url(r'^circuits/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='circuit_changelog', kwargs={'model': Circuit}), - url(r'^circuits/(?P\d+)/terminations/swap/$', views.circuit_terminations_swap, name='circuit_terminations_swap'), + url(r'^circuits/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='circuit_changelog', kwargs={'model': Circuit}), + url(r'^circuits/(?P\d+)/terminations/swap/$', cached(views.circuit_terminations_swap), name='circuit_terminations_swap'), # Circuit terminations url(r'^circuits/(?P\d+)/terminations/add/$', views.CircuitTerminationCreateView.as_view(), name='circuittermination_add'), url(r'^circuit-terminations/(?P\d+)/edit/$', views.CircuitTerminationEditView.as_view(), name='circuittermination_edit'), url(r'^circuit-terminations/(?P\d+)/delete/$', views.CircuitTerminationDeleteView.as_view(), name='circuittermination_delete'), url(r'^circuit-terminations/(?P\d+)/connect/(?P[\w-]+)/$', CableCreateView.as_view(), name='circuittermination_connect', kwargs={'termination_a_type': CircuitTermination}), - url(r'^circuit-terminations/(?P\d+)/trace/$', CableTraceView.as_view(), name='circuittermination_trace', kwargs={'model': CircuitTermination}), + url(r'^circuit-terminations/(?P\d+)/trace/$', cached(CableTraceView.as_view()), name='circuittermination_trace', kwargs={'model': CircuitTermination}), ] diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index 220f4b405..95b539d8b 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -3,6 +3,7 @@ from django.conf.urls import url from extras.views import ObjectChangeLogView, ImageAttachmentEditView from ipam.views import ServiceCreateView from secrets.views import secret_add +from utilities.urls import cached from . import views from .models import ( Cable, ConsolePort, ConsoleServerPort, Device, DeviceRole, DeviceType, FrontPort, Interface, Manufacturer, Platform, @@ -14,291 +15,291 @@ app_name = 'dcim' urlpatterns = [ # Regions - url(r'^regions/$', views.RegionListView.as_view(), name='region_list'), - url(r'^regions/add/$', views.RegionCreateView.as_view(), name='region_add'), + url(r'^regions/$', cached(views.RegionListView.as_view()), name='region_list'), + url(r'^regions/add/$', cached(views.RegionCreateView.as_view()), name='region_add'), url(r'^regions/import/$', views.RegionBulkImportView.as_view(), name='region_import'), url(r'^regions/delete/$', views.RegionBulkDeleteView.as_view(), name='region_bulk_delete'), url(r'^regions/(?P\d+)/edit/$', views.RegionEditView.as_view(), name='region_edit'), - url(r'^regions/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='region_changelog', kwargs={'model': Region}), + url(r'^regions/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='region_changelog', kwargs={'model': Region}), # Sites - url(r'^sites/$', views.SiteListView.as_view(), name='site_list'), - url(r'^sites/add/$', views.SiteCreateView.as_view(), name='site_add'), + url(r'^sites/$', cached(views.SiteListView.as_view()), name='site_list'), + url(r'^sites/add/$', cached(views.SiteCreateView.as_view()), name='site_add'), url(r'^sites/import/$', views.SiteBulkImportView.as_view(), name='site_import'), url(r'^sites/edit/$', views.SiteBulkEditView.as_view(), name='site_bulk_edit'), - url(r'^sites/(?P[\w-]+)/$', views.SiteView.as_view(), name='site'), + url(r'^sites/(?P[\w-]+)/$', cached(views.SiteView.as_view()), name='site'), url(r'^sites/(?P[\w-]+)/edit/$', views.SiteEditView.as_view(), name='site_edit'), url(r'^sites/(?P[\w-]+)/delete/$', views.SiteDeleteView.as_view(), name='site_delete'), - url(r'^sites/(?P[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='site_changelog', kwargs={'model': Site}), - url(r'^sites/(?P\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='site_add_image', kwargs={'model': Site}), + url(r'^sites/(?P[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='site_changelog', kwargs={'model': Site}), + url(r'^sites/(?P\d+)/images/add/$', cached(ImageAttachmentEditView.as_view()), name='site_add_image', kwargs={'model': Site}), # Rack groups - url(r'^rack-groups/$', views.RackGroupListView.as_view(), name='rackgroup_list'), - url(r'^rack-groups/add/$', views.RackGroupCreateView.as_view(), name='rackgroup_add'), + url(r'^rack-groups/$', cached(views.RackGroupListView.as_view()), name='rackgroup_list'), + url(r'^rack-groups/add/$', cached(views.RackGroupCreateView.as_view()), name='rackgroup_add'), url(r'^rack-groups/import/$', views.RackGroupBulkImportView.as_view(), name='rackgroup_import'), url(r'^rack-groups/delete/$', views.RackGroupBulkDeleteView.as_view(), name='rackgroup_bulk_delete'), url(r'^rack-groups/(?P\d+)/edit/$', views.RackGroupEditView.as_view(), name='rackgroup_edit'), - url(r'^rack-groups/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rackgroup_changelog', kwargs={'model': RackGroup}), + url(r'^rack-groups/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='rackgroup_changelog', kwargs={'model': RackGroup}), # Rack roles - url(r'^rack-roles/$', views.RackRoleListView.as_view(), name='rackrole_list'), - url(r'^rack-roles/add/$', views.RackRoleCreateView.as_view(), name='rackrole_add'), + url(r'^rack-roles/$', cached(views.RackRoleListView.as_view()), name='rackrole_list'), + url(r'^rack-roles/add/$', cached(views.RackRoleCreateView.as_view()), name='rackrole_add'), url(r'^rack-roles/import/$', views.RackRoleBulkImportView.as_view(), name='rackrole_import'), url(r'^rack-roles/delete/$', views.RackRoleBulkDeleteView.as_view(), name='rackrole_bulk_delete'), url(r'^rack-roles/(?P\d+)/edit/$', views.RackRoleEditView.as_view(), name='rackrole_edit'), - url(r'^rack-roles/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rackrole_changelog', kwargs={'model': RackRole}), + url(r'^rack-roles/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='rackrole_changelog', kwargs={'model': RackRole}), # Rack reservations - url(r'^rack-reservations/$', views.RackReservationListView.as_view(), name='rackreservation_list'), + url(r'^rack-reservations/$', cached(views.RackReservationListView.as_view()), name='rackreservation_list'), url(r'^rack-reservations/edit/$', views.RackReservationBulkEditView.as_view(), name='rackreservation_bulk_edit'), url(r'^rack-reservations/delete/$', views.RackReservationBulkDeleteView.as_view(), name='rackreservation_bulk_delete'), url(r'^rack-reservations/(?P\d+)/edit/$', views.RackReservationEditView.as_view(), name='rackreservation_edit'), url(r'^rack-reservations/(?P\d+)/delete/$', views.RackReservationDeleteView.as_view(), name='rackreservation_delete'), - url(r'^rack-reservations/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rackreservation_changelog', kwargs={'model': RackReservation}), + url(r'^rack-reservations/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='rackreservation_changelog', kwargs={'model': RackReservation}), # Racks - url(r'^racks/$', views.RackListView.as_view(), name='rack_list'), - url(r'^rack-elevations/$', views.RackElevationListView.as_view(), name='rack_elevation_list'), - url(r'^racks/add/$', views.RackEditView.as_view(), name='rack_add'), + url(r'^racks/$', cached(views.RackListView.as_view()), name='rack_list'), + url(r'^rack-elevations/$', cached(views.RackElevationListView.as_view()), name='rack_elevation_list'), + url(r'^racks/add/$', cached(views.RackEditView.as_view()), name='rack_add'), url(r'^racks/import/$', views.RackBulkImportView.as_view(), name='rack_import'), url(r'^racks/edit/$', views.RackBulkEditView.as_view(), name='rack_bulk_edit'), url(r'^racks/delete/$', views.RackBulkDeleteView.as_view(), name='rack_bulk_delete'), - url(r'^racks/(?P\d+)/$', views.RackView.as_view(), name='rack'), + url(r'^racks/(?P\d+)/$', cached(views.RackView.as_view()), name='rack'), url(r'^racks/(?P\d+)/edit/$', views.RackEditView.as_view(), name='rack_edit'), url(r'^racks/(?P\d+)/delete/$', views.RackDeleteView.as_view(), name='rack_delete'), - url(r'^racks/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rack_changelog', kwargs={'model': Rack}), - url(r'^racks/(?P\d+)/reservations/add/$', views.RackReservationCreateView.as_view(), name='rack_add_reservation'), - url(r'^racks/(?P\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='rack_add_image', kwargs={'model': Rack}), + url(r'^racks/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='rack_changelog', kwargs={'model': Rack}), + url(r'^racks/(?P\d+)/reservations/add/$', cached(views.RackReservationCreateView.as_view()), name='rack_add_reservation'), + url(r'^racks/(?P\d+)/images/add/$', cached(ImageAttachmentEditView.as_view()), name='rack_add_image', kwargs={'model': Rack}), # Manufacturers - url(r'^manufacturers/$', views.ManufacturerListView.as_view(), name='manufacturer_list'), - url(r'^manufacturers/add/$', views.ManufacturerCreateView.as_view(), name='manufacturer_add'), + url(r'^manufacturers/$', cached(views.ManufacturerListView.as_view()), name='manufacturer_list'), + url(r'^manufacturers/add/$', cached(views.ManufacturerCreateView.as_view()), name='manufacturer_add'), url(r'^manufacturers/import/$', views.ManufacturerBulkImportView.as_view(), name='manufacturer_import'), url(r'^manufacturers/delete/$', views.ManufacturerBulkDeleteView.as_view(), name='manufacturer_bulk_delete'), url(r'^manufacturers/(?P[\w-]+)/edit/$', views.ManufacturerEditView.as_view(), name='manufacturer_edit'), - url(r'^manufacturers/(?P[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='manufacturer_changelog', kwargs={'model': Manufacturer}), + url(r'^manufacturers/(?P[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='manufacturer_changelog', kwargs={'model': Manufacturer}), # Device types - url(r'^device-types/$', views.DeviceTypeListView.as_view(), name='devicetype_list'), - url(r'^device-types/add/$', views.DeviceTypeCreateView.as_view(), name='devicetype_add'), + url(r'^device-types/$', cached(views.DeviceTypeListView.as_view()), name='devicetype_list'), + url(r'^device-types/add/$', cached(views.DeviceTypeCreateView.as_view()), name='devicetype_add'), url(r'^device-types/import/$', views.DeviceTypeBulkImportView.as_view(), name='devicetype_import'), url(r'^device-types/edit/$', views.DeviceTypeBulkEditView.as_view(), name='devicetype_bulk_edit'), url(r'^device-types/delete/$', views.DeviceTypeBulkDeleteView.as_view(), name='devicetype_bulk_delete'), - url(r'^device-types/(?P\d+)/$', views.DeviceTypeView.as_view(), name='devicetype'), + url(r'^device-types/(?P\d+)/$', cached(views.DeviceTypeView.as_view()), name='devicetype'), url(r'^device-types/(?P\d+)/edit/$', views.DeviceTypeEditView.as_view(), name='devicetype_edit'), url(r'^device-types/(?P\d+)/delete/$', views.DeviceTypeDeleteView.as_view(), name='devicetype_delete'), - url(r'^device-types/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='devicetype_changelog', kwargs={'model': DeviceType}), + url(r'^device-types/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='devicetype_changelog', kwargs={'model': DeviceType}), # Console port templates - url(r'^device-types/(?P\d+)/console-ports/add/$', views.ConsolePortTemplateCreateView.as_view(), name='devicetype_add_consoleport'), + url(r'^device-types/(?P\d+)/console-ports/add/$', cached(views.ConsolePortTemplateCreateView.as_view()), name='devicetype_add_consoleport'), url(r'^device-types/(?P\d+)/console-ports/delete/$', views.ConsolePortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleport'), # Console server port templates - url(r'^device-types/(?P\d+)/console-server-ports/add/$', views.ConsoleServerPortTemplateCreateView.as_view(), name='devicetype_add_consoleserverport'), + url(r'^device-types/(?P\d+)/console-server-ports/add/$', cached(views.ConsoleServerPortTemplateCreateView.as_view()), name='devicetype_add_consoleserverport'), url(r'^device-types/(?P\d+)/console-server-ports/delete/$', views.ConsoleServerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleserverport'), # Power port templates - url(r'^device-types/(?P\d+)/power-ports/add/$', views.PowerPortTemplateCreateView.as_view(), name='devicetype_add_powerport'), + url(r'^device-types/(?P\d+)/power-ports/add/$', cached(views.PowerPortTemplateCreateView.as_view()), name='devicetype_add_powerport'), url(r'^device-types/(?P\d+)/power-ports/delete/$', views.PowerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_powerport'), # Power outlet templates - url(r'^device-types/(?P\d+)/power-outlets/add/$', views.PowerOutletTemplateCreateView.as_view(), name='devicetype_add_poweroutlet'), + url(r'^device-types/(?P\d+)/power-outlets/add/$', cached(views.PowerOutletTemplateCreateView.as_view()), name='devicetype_add_poweroutlet'), url(r'^device-types/(?P\d+)/power-outlets/delete/$', views.PowerOutletTemplateBulkDeleteView.as_view(), name='devicetype_delete_poweroutlet'), # Interface templates - url(r'^device-types/(?P\d+)/interfaces/add/$', views.InterfaceTemplateCreateView.as_view(), name='devicetype_add_interface'), + url(r'^device-types/(?P\d+)/interfaces/add/$', cached(views.InterfaceTemplateCreateView.as_view()), name='devicetype_add_interface'), url(r'^device-types/(?P\d+)/interfaces/edit/$', views.InterfaceTemplateBulkEditView.as_view(), name='devicetype_bulkedit_interface'), url(r'^device-types/(?P\d+)/interfaces/delete/$', views.InterfaceTemplateBulkDeleteView.as_view(), name='devicetype_delete_interface'), # Front port templates - url(r'^device-types/(?P\d+)/front-ports/add/$', views.FrontPortTemplateCreateView.as_view(), name='devicetype_add_frontport'), + url(r'^device-types/(?P\d+)/front-ports/add/$', cached(views.FrontPortTemplateCreateView.as_view()), name='devicetype_add_frontport'), url(r'^device-types/(?P\d+)/front-ports/delete/$', views.FrontPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_frontport'), # Rear port templates - url(r'^device-types/(?P\d+)/rear-ports/add/$', views.RearPortTemplateCreateView.as_view(), name='devicetype_add_rearport'), + url(r'^device-types/(?P\d+)/rear-ports/add/$', cached(views.RearPortTemplateCreateView.as_view()), name='devicetype_add_rearport'), url(r'^device-types/(?P\d+)/rear-ports/delete/$', views.RearPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_rearport'), # Device bay templates - url(r'^device-types/(?P\d+)/device-bays/add/$', views.DeviceBayTemplateCreateView.as_view(), name='devicetype_add_devicebay'), + url(r'^device-types/(?P\d+)/device-bays/add/$', cached(views.DeviceBayTemplateCreateView.as_view()), name='devicetype_add_devicebay'), url(r'^device-types/(?P\d+)/device-bays/delete/$', views.DeviceBayTemplateBulkDeleteView.as_view(), name='devicetype_delete_devicebay'), # Device roles - url(r'^device-roles/$', views.DeviceRoleListView.as_view(), name='devicerole_list'), - url(r'^device-roles/add/$', views.DeviceRoleCreateView.as_view(), name='devicerole_add'), + url(r'^device-roles/$', cached(views.DeviceRoleListView.as_view()), name='devicerole_list'), + url(r'^device-roles/add/$', cached(views.DeviceRoleCreateView.as_view()), name='devicerole_add'), url(r'^device-roles/import/$', views.DeviceRoleBulkImportView.as_view(), name='devicerole_import'), url(r'^device-roles/delete/$', views.DeviceRoleBulkDeleteView.as_view(), name='devicerole_bulk_delete'), url(r'^device-roles/(?P[\w-]+)/edit/$', views.DeviceRoleEditView.as_view(), name='devicerole_edit'), - url(r'^device-roles/(?P[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='devicerole_changelog', kwargs={'model': DeviceRole}), + url(r'^device-roles/(?P[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='devicerole_changelog', kwargs={'model': DeviceRole}), # Platforms - url(r'^platforms/$', views.PlatformListView.as_view(), name='platform_list'), - url(r'^platforms/add/$', views.PlatformCreateView.as_view(), name='platform_add'), + url(r'^platforms/$', cached(views.PlatformListView.as_view()), name='platform_list'), + url(r'^platforms/add/$', cached(views.PlatformCreateView.as_view()), name='platform_add'), url(r'^platforms/import/$', views.PlatformBulkImportView.as_view(), name='platform_import'), url(r'^platforms/delete/$', views.PlatformBulkDeleteView.as_view(), name='platform_bulk_delete'), url(r'^platforms/(?P[\w-]+)/edit/$', views.PlatformEditView.as_view(), name='platform_edit'), - url(r'^platforms/(?P[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='platform_changelog', kwargs={'model': Platform}), + url(r'^platforms/(?P[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='platform_changelog', kwargs={'model': Platform}), # Devices - url(r'^devices/$', views.DeviceListView.as_view(), name='device_list'), - url(r'^devices/add/$', views.DeviceCreateView.as_view(), name='device_add'), + url(r'^devices/$', cached(views.DeviceListView.as_view()), name='device_list'), + url(r'^devices/add/$', cached(views.DeviceCreateView.as_view()), name='device_add'), url(r'^devices/import/$', views.DeviceBulkImportView.as_view(), name='device_import'), url(r'^devices/import/child-devices/$', views.ChildDeviceBulkImportView.as_view(), name='device_import_child'), url(r'^devices/edit/$', views.DeviceBulkEditView.as_view(), name='device_bulk_edit'), url(r'^devices/delete/$', views.DeviceBulkDeleteView.as_view(), name='device_bulk_delete'), - url(r'^devices/(?P\d+)/$', views.DeviceView.as_view(), name='device'), + url(r'^devices/(?P\d+)/$', cached(views.DeviceView.as_view()), name='device'), url(r'^devices/(?P\d+)/edit/$', views.DeviceEditView.as_view(), name='device_edit'), url(r'^devices/(?P\d+)/delete/$', views.DeviceDeleteView.as_view(), name='device_delete'), - url(r'^devices/(?P\d+)/config-context/$', views.DeviceConfigContextView.as_view(), name='device_configcontext'), - url(r'^devices/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='device_changelog', kwargs={'model': Device}), - url(r'^devices/(?P\d+)/inventory/$', views.DeviceInventoryView.as_view(), name='device_inventory'), + url(r'^devices/(?P\d+)/config-context/$', cached(views.DeviceConfigContextView.as_view()), name='device_configcontext'), + url(r'^devices/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='device_changelog', kwargs={'model': Device}), + url(r'^devices/(?P\d+)/inventory/$', cached(views.DeviceInventoryView.as_view()), name='device_inventory'), url(r'^devices/(?P\d+)/status/$', views.DeviceStatusView.as_view(), name='device_status'), url(r'^devices/(?P\d+)/lldp-neighbors/$', views.DeviceLLDPNeighborsView.as_view(), name='device_lldp_neighbors'), url(r'^devices/(?P\d+)/config/$', views.DeviceConfigView.as_view(), name='device_config'), url(r'^devices/(?P\d+)/add-secret/$', secret_add, name='device_addsecret'), - url(r'^devices/(?P\d+)/services/assign/$', ServiceCreateView.as_view(), name='device_service_assign'), - url(r'^devices/(?P\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='device_add_image', kwargs={'model': Device}), + url(r'^devices/(?P\d+)/services/assign/$', cached(ServiceCreateView.as_view()), name='device_service_assign'), + url(r'^devices/(?P\d+)/images/add/$', cached(ImageAttachmentEditView.as_view()), name='device_add_image', kwargs={'model': Device}), # Console ports - url(r'^devices/console-ports/add/$', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'), - url(r'^devices/(?P\d+)/console-ports/add/$', views.ConsolePortCreateView.as_view(), name='consoleport_add'), + url(r'^devices/console-ports/add/$', cached(views.DeviceBulkAddConsolePortView.as_view()), name='device_bulk_add_consoleport'), + url(r'^devices/(?P\d+)/console-ports/add/$', cached(views.ConsolePortCreateView.as_view()), name='consoleport_add'), url(r'^devices/(?P\d+)/console-ports/delete/$', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'), url(r'^console-ports/(?P\d+)/connect/(?P[\w-]+)/$', views.CableCreateView.as_view(), name='consoleport_connect', kwargs={'termination_a_type': ConsolePort}), url(r'^console-ports/(?P\d+)/edit/$', views.ConsolePortEditView.as_view(), name='consoleport_edit'), url(r'^console-ports/(?P\d+)/delete/$', views.ConsolePortDeleteView.as_view(), name='consoleport_delete'), - url(r'^console-ports/(?P\d+)/trace/$', views.CableTraceView.as_view(), name='consoleport_trace', kwargs={'model': ConsolePort}), + url(r'^console-ports/(?P\d+)/trace/$', cached(views.CableTraceView.as_view()), name='consoleport_trace', kwargs={'model': ConsolePort}), # Console server ports - url(r'^devices/console-server-ports/add/$', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'), - url(r'^devices/(?P\d+)/console-server-ports/add/$', views.ConsoleServerPortCreateView.as_view(), name='consoleserverport_add'), + url(r'^devices/console-server-ports/add/$', cached(views.DeviceBulkAddConsoleServerPortView.as_view()), name='device_bulk_add_consoleserverport'), + url(r'^devices/(?P\d+)/console-server-ports/add/$', cached(views.ConsoleServerPortCreateView.as_view()), name='consoleserverport_add'), url(r'^devices/(?P\d+)/console-server-ports/delete/$', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'), url(r'^console-server-ports/(?P\d+)/connect/(?P[\w-]+)/$', views.CableCreateView.as_view(), name='consoleserverport_connect', kwargs={'termination_a_type': ConsoleServerPort}), url(r'^console-server-ports/(?P\d+)/edit/$', views.ConsoleServerPortEditView.as_view(), name='consoleserverport_edit'), url(r'^console-server-ports/(?P\d+)/delete/$', views.ConsoleServerPortDeleteView.as_view(), name='consoleserverport_delete'), - url(r'^console-server-ports/(?P\d+)/trace/$', views.CableTraceView.as_view(), name='consoleserverport_trace', kwargs={'model': ConsoleServerPort}), - url(r'^console-server-ports/rename/$', views.ConsoleServerPortBulkRenameView.as_view(), name='consoleserverport_bulk_rename'), + url(r'^console-server-ports/(?P\d+)/trace/$', cached(views.CableTraceView.as_view()), name='consoleserverport_trace', kwargs={'model': ConsoleServerPort}), + url(r'^console-server-ports/rename/$', cached(views.ConsoleServerPortBulkRenameView.as_view()), name='consoleserverport_bulk_rename'), url(r'^console-server-ports/disconnect/$', views.ConsoleServerPortBulkDisconnectView.as_view(), name='consoleserverport_bulk_disconnect'), # Power ports - url(r'^devices/power-ports/add/$', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'), - url(r'^devices/(?P\d+)/power-ports/add/$', views.PowerPortCreateView.as_view(), name='powerport_add'), + url(r'^devices/power-ports/add/$', cached(views.DeviceBulkAddPowerPortView.as_view()), name='device_bulk_add_powerport'), + url(r'^devices/(?P\d+)/power-ports/add/$', cached(views.PowerPortCreateView.as_view()), name='powerport_add'), url(r'^devices/(?P\d+)/power-ports/delete/$', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'), url(r'^power-ports/(?P\d+)/connect/(?P[\w-]+)/$', views.CableCreateView.as_view(), name='powerport_connect', kwargs={'termination_a_type': PowerPort}), url(r'^power-ports/(?P\d+)/edit/$', views.PowerPortEditView.as_view(), name='powerport_edit'), url(r'^power-ports/(?P\d+)/delete/$', views.PowerPortDeleteView.as_view(), name='powerport_delete'), - url(r'^power-ports/(?P\d+)/trace/$', views.CableTraceView.as_view(), name='powerport_trace', kwargs={'model': PowerPort}), + url(r'^power-ports/(?P\d+)/trace/$', cached(views.CableTraceView.as_view()), name='powerport_trace', kwargs={'model': PowerPort}), # Power outlets - url(r'^devices/power-outlets/add/$', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'), - url(r'^devices/(?P\d+)/power-outlets/add/$', views.PowerOutletCreateView.as_view(), name='poweroutlet_add'), + url(r'^devices/power-outlets/add/$', cached(views.DeviceBulkAddPowerOutletView.as_view()), name='device_bulk_add_poweroutlet'), + url(r'^devices/(?P\d+)/power-outlets/add/$', cached(views.PowerOutletCreateView.as_view()), name='poweroutlet_add'), url(r'^devices/(?P\d+)/power-outlets/delete/$', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'), url(r'^power-outlets/(?P\d+)/connect/(?P[\w-]+)/$', views.CableCreateView.as_view(), name='poweroutlet_connect', kwargs={'termination_a_type': PowerOutlet}), url(r'^power-outlets/(?P\d+)/edit/$', views.PowerOutletEditView.as_view(), name='poweroutlet_edit'), url(r'^power-outlets/(?P\d+)/delete/$', views.PowerOutletDeleteView.as_view(), name='poweroutlet_delete'), - url(r'^power-outlets/(?P\d+)/trace/$', views.CableTraceView.as_view(), name='poweroutlet_trace', kwargs={'model': PowerOutlet}), - url(r'^power-outlets/rename/$', views.PowerOutletBulkRenameView.as_view(), name='poweroutlet_bulk_rename'), + url(r'^power-outlets/(?P\d+)/trace/$', cached(views.CableTraceView.as_view()), name='poweroutlet_trace', kwargs={'model': PowerOutlet}), + url(r'^power-outlets/rename/$', cached(views.PowerOutletBulkRenameView.as_view()), name='poweroutlet_bulk_rename'), url(r'^power-outlets/disconnect/$', views.PowerOutletBulkDisconnectView.as_view(), name='poweroutlet_bulk_disconnect'), # Interfaces - url(r'^devices/interfaces/add/$', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'), - url(r'^devices/(?P\d+)/interfaces/add/$', views.InterfaceCreateView.as_view(), name='interface_add'), + url(r'^devices/interfaces/add/$', cached(views.DeviceBulkAddInterfaceView.as_view()), name='device_bulk_add_interface'), + url(r'^devices/(?P\d+)/interfaces/add/$', cached(views.InterfaceCreateView.as_view()), name='interface_add'), url(r'^devices/(?P\d+)/interfaces/edit/$', views.InterfaceBulkEditView.as_view(), name='interface_bulk_edit'), url(r'^devices/(?P\d+)/interfaces/delete/$', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'), url(r'^interfaces/(?P\d+)/connect/(?P[\w-]+)/$', views.CableCreateView.as_view(), name='interface_connect', kwargs={'termination_a_type': Interface}), - url(r'^interfaces/(?P\d+)/$', views.InterfaceView.as_view(), name='interface'), + url(r'^interfaces/(?P\d+)/$', cached(views.InterfaceView.as_view()), name='interface'), url(r'^interfaces/(?P\d+)/edit/$', views.InterfaceEditView.as_view(), name='interface_edit'), - url(r'^interfaces/(?P\d+)/assign-vlans/$', views.InterfaceAssignVLANsView.as_view(), name='interface_assign_vlans'), + url(r'^interfaces/(?P\d+)/assign-vlans/$', cached(views.InterfaceAssignVLANsView.as_view()), name='interface_assign_vlans'), url(r'^interfaces/(?P\d+)/delete/$', views.InterfaceDeleteView.as_view(), name='interface_delete'), - url(r'^interfaces/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='interface_changelog', kwargs={'model': Interface}), - url(r'^interfaces/(?P\d+)/trace/$', views.CableTraceView.as_view(), name='interface_trace', kwargs={'model': Interface}), - url(r'^interfaces/rename/$', views.InterfaceBulkRenameView.as_view(), name='interface_bulk_rename'), + url(r'^interfaces/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='interface_changelog', kwargs={'model': Interface}), + url(r'^interfaces/(?P\d+)/trace/$', cached(views.CableTraceView.as_view()), name='interface_trace', kwargs={'model': Interface}), + url(r'^interfaces/rename/$', cached(views.InterfaceBulkRenameView.as_view()), name='interface_bulk_rename'), url(r'^interfaces/disconnect/$', views.InterfaceBulkDisconnectView.as_view(), name='interface_bulk_disconnect'), # Front ports # url(r'^devices/front-ports/add/$', views.DeviceBulkAddFrontPortView.as_view(), name='device_bulk_add_frontport'), - url(r'^devices/(?P\d+)/front-ports/add/$', views.FrontPortCreateView.as_view(), name='frontport_add'), + url(r'^devices/(?P\d+)/front-ports/add/$', cached(views.FrontPortCreateView.as_view()), name='frontport_add'), url(r'^devices/(?P\d+)/front-ports/edit/$', views.FrontPortBulkEditView.as_view(), name='frontport_bulk_edit'), url(r'^devices/(?P\d+)/front-ports/delete/$', views.FrontPortBulkDeleteView.as_view(), name='frontport_bulk_delete'), url(r'^front-ports/(?P\d+)/connect/(?P[\w-]+)/$', views.CableCreateView.as_view(), name='frontport_connect', kwargs={'termination_a_type': FrontPort}), url(r'^front-ports/(?P\d+)/edit/$', views.FrontPortEditView.as_view(), name='frontport_edit'), url(r'^front-ports/(?P\d+)/delete/$', views.FrontPortDeleteView.as_view(), name='frontport_delete'), - url(r'^front-ports/(?P\d+)/trace/$', views.CableTraceView.as_view(), name='frontport_trace', kwargs={'model': FrontPort}), - url(r'^front-ports/rename/$', views.FrontPortBulkRenameView.as_view(), name='frontport_bulk_rename'), + url(r'^front-ports/(?P\d+)/trace/$', cached(views.CableTraceView.as_view()), name='frontport_trace', kwargs={'model': FrontPort}), + url(r'^front-ports/rename/$', cached(views.FrontPortBulkRenameView.as_view()), name='frontport_bulk_rename'), url(r'^front-ports/disconnect/$', views.FrontPortBulkDisconnectView.as_view(), name='frontport_bulk_disconnect'), # Rear ports # url(r'^devices/rear-ports/add/$', views.DeviceBulkAddRearPortView.as_view(), name='device_bulk_add_rearport'), - url(r'^devices/(?P\d+)/rear-ports/add/$', views.RearPortCreateView.as_view(), name='rearport_add'), + url(r'^devices/(?P\d+)/rear-ports/add/$', cached(views.RearPortCreateView.as_view()), name='rearport_add'), url(r'^devices/(?P\d+)/rear-ports/edit/$', views.RearPortBulkEditView.as_view(), name='rearport_bulk_edit'), url(r'^devices/(?P\d+)/rear-ports/delete/$', views.RearPortBulkDeleteView.as_view(), name='rearport_bulk_delete'), url(r'^rear-ports/(?P\d+)/connect/(?P[\w-]+)/$', views.CableCreateView.as_view(), name='rearport_connect', kwargs={'termination_a_type': RearPort}), url(r'^rear-ports/(?P\d+)/edit/$', views.RearPortEditView.as_view(), name='rearport_edit'), url(r'^rear-ports/(?P\d+)/delete/$', views.RearPortDeleteView.as_view(), name='rearport_delete'), - url(r'^rear-ports/(?P\d+)/trace/$', views.CableTraceView.as_view(), name='rearport_trace', kwargs={'model': RearPort}), - url(r'^rear-ports/rename/$', views.RearPortBulkRenameView.as_view(), name='rearport_bulk_rename'), + url(r'^rear-ports/(?P\d+)/trace/$',cached( views.CableTraceView.as_view()), name='rearport_trace', kwargs={'model': RearPort}), + url(r'^rear-ports/rename/$', cached(views.RearPortBulkRenameView.as_view()), name='rearport_bulk_rename'), url(r'^rear-ports/disconnect/$', views.RearPortBulkDisconnectView.as_view(), name='rearport_bulk_disconnect'), # Device bays - url(r'^devices/device-bays/add/$', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'), - url(r'^devices/(?P\d+)/bays/add/$', views.DeviceBayCreateView.as_view(), name='devicebay_add'), + url(r'^devices/device-bays/add/$', cached(views.DeviceBulkAddDeviceBayView.as_view()), name='device_bulk_add_devicebay'), + url(r'^devices/(?P\d+)/bays/add/$', cached(views.DeviceBayCreateView.as_view()), name='devicebay_add'), url(r'^devices/(?P\d+)/bays/delete/$', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'), url(r'^device-bays/(?P\d+)/edit/$', views.DeviceBayEditView.as_view(), name='devicebay_edit'), url(r'^device-bays/(?P\d+)/delete/$', views.DeviceBayDeleteView.as_view(), name='devicebay_delete'), url(r'^device-bays/(?P\d+)/populate/$', views.DeviceBayPopulateView.as_view(), name='devicebay_populate'), url(r'^device-bays/(?P\d+)/depopulate/$', views.DeviceBayDepopulateView.as_view(), name='devicebay_depopulate'), - url(r'^device-bays/rename/$', views.DeviceBayBulkRenameView.as_view(), name='devicebay_bulk_rename'), + url(r'^device-bays/rename/$', cached(views.DeviceBayBulkRenameView.as_view()), name='devicebay_bulk_rename'), # Inventory items - url(r'^inventory-items/$', views.InventoryItemListView.as_view(), name='inventoryitem_list'), + url(r'^inventory-items/$', cached(views.InventoryItemListView.as_view()), name='inventoryitem_list'), url(r'^inventory-items/import/$', views.InventoryItemBulkImportView.as_view(), name='inventoryitem_import'), url(r'^inventory-items/edit/$', views.InventoryItemBulkEditView.as_view(), name='inventoryitem_bulk_edit'), url(r'^inventory-items/delete/$', views.InventoryItemBulkDeleteView.as_view(), name='inventoryitem_bulk_delete'), url(r'^inventory-items/(?P\d+)/edit/$', views.InventoryItemEditView.as_view(), name='inventoryitem_edit'), url(r'^inventory-items/(?P\d+)/delete/$', views.InventoryItemDeleteView.as_view(), name='inventoryitem_delete'), - url(r'^devices/(?P\d+)/inventory-items/add/$', views.InventoryItemEditView.as_view(), name='inventoryitem_add'), + url(r'^devices/(?P\d+)/inventory-items/add/$', cached(views.InventoryItemEditView.as_view()), name='inventoryitem_add'), # Cables - url(r'^cables/$', views.CableListView.as_view(), name='cable_list'), + url(r'^cables/$', cached(views.CableListView.as_view()), name='cable_list'), url(r'^cables/import/$', views.CableBulkImportView.as_view(), name='cable_import'), url(r'^cables/edit/$', views.CableBulkEditView.as_view(), name='cable_bulk_edit'), url(r'^cables/delete/$', views.CableBulkDeleteView.as_view(), name='cable_bulk_delete'), - url(r'^cables/(?P\d+)/$', views.CableView.as_view(), name='cable'), + url(r'^cables/(?P\d+)/$', cached(views.CableView.as_view()), name='cable'), url(r'^cables/(?P\d+)/edit/$', views.CableEditView.as_view(), name='cable_edit'), url(r'^cables/(?P\d+)/delete/$', views.CableDeleteView.as_view(), name='cable_delete'), - url(r'^cables/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='cable_changelog', kwargs={'model': Cable}), + url(r'^cables/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='cable_changelog', kwargs={'model': Cable}), # Console/power/interface connections (read-only) - url(r'^console-connections/$', views.ConsoleConnectionsListView.as_view(), name='console_connections_list'), - url(r'^power-connections/$', views.PowerConnectionsListView.as_view(), name='power_connections_list'), - url(r'^interface-connections/$', views.InterfaceConnectionsListView.as_view(), name='interface_connections_list'), + url(r'^console-connections/$', cached(views.ConsoleConnectionsListView.as_view()), name='console_connections_list'), + url(r'^power-connections/$', cached(views.PowerConnectionsListView.as_view()), name='power_connections_list'), + url(r'^interface-connections/$', cached(views.InterfaceConnectionsListView.as_view()), name='interface_connections_list'), # Virtual chassis - url(r'^virtual-chassis/$', views.VirtualChassisListView.as_view(), name='virtualchassis_list'), - url(r'^virtual-chassis/add/$', views.VirtualChassisCreateView.as_view(), name='virtualchassis_add'), + url(r'^virtual-chassis/$', cached(views.VirtualChassisListView.as_view()), name='virtualchassis_list'), + url(r'^virtual-chassis/add/$', cached(views.VirtualChassisCreateView.as_view()), name='virtualchassis_add'), url(r'^virtual-chassis/(?P\d+)/edit/$', views.VirtualChassisEditView.as_view(), name='virtualchassis_edit'), url(r'^virtual-chassis/(?P\d+)/delete/$', views.VirtualChassisDeleteView.as_view(), name='virtualchassis_delete'), - url(r'^virtual-chassis/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='virtualchassis_changelog', kwargs={'model': VirtualChassis}), + url(r'^virtual-chassis/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='virtualchassis_changelog', kwargs={'model': VirtualChassis}), url(r'^virtual-chassis/(?P\d+)/add-member/$', views.VirtualChassisAddMemberView.as_view(), name='virtualchassis_add_member'), url(r'^virtual-chassis-members/(?P\d+)/delete/$', views.VirtualChassisRemoveMemberView.as_view(), name='virtualchassis_remove_member'), # Power panels - url(r'^power-panels/$', views.PowerPanelListView.as_view(), name='powerpanel_list'), - url(r'^power-panels/add/$', views.PowerPanelCreateView.as_view(), name='powerpanel_add'), + url(r'^power-panels/$', cached(views.PowerPanelListView.as_view()), name='powerpanel_list'), + url(r'^power-panels/add/$', cached(views.PowerPanelCreateView.as_view()), name='powerpanel_add'), url(r'^power-panels/import/$', views.PowerPanelBulkImportView.as_view(), name='powerpanel_import'), url(r'^power-panels/delete/$', views.PowerPanelBulkDeleteView.as_view(), name='powerpanel_bulk_delete'), - url(r'^power-panels/(?P\d+)/$', views.PowerPanelView.as_view(), name='powerpanel'), + url(r'^power-panels/(?P\d+)/$', cached(views.PowerPanelView.as_view()), name='powerpanel'), url(r'^power-panels/(?P\d+)/edit/$', views.PowerPanelEditView.as_view(), name='powerpanel_edit'), url(r'^power-panels/(?P\d+)/delete/$', views.PowerPanelDeleteView.as_view(), name='powerpanel_delete'), - url(r'^power-panels/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='powerpanel_changelog', kwargs={'model': PowerPanel}), + url(r'^power-panels/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='powerpanel_changelog', kwargs={'model': PowerPanel}), # Power feeds - url(r'^power-feeds/$', views.PowerFeedListView.as_view(), name='powerfeed_list'), - url(r'^power-feeds/add/$', views.PowerFeedEditView.as_view(), name='powerfeed_add'), + url(r'^power-feeds/$', cached(views.PowerFeedListView.as_view()), name='powerfeed_list'), + url(r'^power-feeds/add/$', cached(views.PowerFeedEditView.as_view()), name='powerfeed_add'), url(r'^power-feeds/import/$', views.PowerFeedBulkImportView.as_view(), name='powerfeed_import'), url(r'^power-feeds/edit/$', views.PowerFeedBulkEditView.as_view(), name='powerfeed_bulk_edit'), url(r'^power-feeds/delete/$', views.PowerFeedBulkDeleteView.as_view(), name='powerfeed_bulk_delete'), - url(r'^power-feeds/(?P\d+)/$', views.PowerFeedView.as_view(), name='powerfeed'), + url(r'^power-feeds/(?P\d+)/$', cached(views.PowerFeedView.as_view()), name='powerfeed'), url(r'^power-feeds/(?P\d+)/edit/$', views.PowerFeedEditView.as_view(), name='powerfeed_edit'), url(r'^power-feeds/(?P\d+)/delete/$', views.PowerFeedDeleteView.as_view(), name='powerfeed_delete'), - url(r'^power-feeds/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='powerfeed_changelog', kwargs={'model': PowerFeed}), + url(r'^power-feeds/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='powerfeed_changelog', kwargs={'model': PowerFeed}), ] diff --git a/netbox/extras/urls.py b/netbox/extras/urls.py index d475ab5a3..63e060616 100644 --- a/netbox/extras/urls.py +++ b/netbox/extras/urls.py @@ -2,25 +2,26 @@ from django.conf.urls import url from extras import views from extras.models import Tag +from utilities.urls import cached app_name = 'extras' urlpatterns = [ # Tags - url(r'^tags/$', views.TagListView.as_view(), name='tag_list'), + url(r'^tags/$', cached(views.TagListView.as_view()), name='tag_list'), url(r'^tags/delete/$', views.TagBulkDeleteView.as_view(), name='tag_bulk_delete'), - url(r'^tags/(?P[\w-]+)/$', views.TagView.as_view(), name='tag'), + url(r'^tags/(?P[\w-]+)/$', cached(views.TagView.as_view()), name='tag'), url(r'^tags/(?P[\w-]+)/edit/$', views.TagEditView.as_view(), name='tag_edit'), url(r'^tags/(?P[\w-]+)/delete/$', views.TagDeleteView.as_view(), name='tag_delete'), - url(r'^tags/(?P[\w-]+)/changelog/$', views.ObjectChangeLogView.as_view(), name='tag_changelog', kwargs={'model': Tag}), + url(r'^tags/(?P[\w-]+)/changelog/$', cached(views.ObjectChangeLogView.as_view()), name='tag_changelog', kwargs={'model': Tag}), # Config contexts - url(r'^config-contexts/$', views.ConfigContextListView.as_view(), name='configcontext_list'), - url(r'^config-contexts/add/$', views.ConfigContextCreateView.as_view(), name='configcontext_add'), + url(r'^config-contexts/$', cached(views.ConfigContextListView.as_view()), name='configcontext_list'), + url(r'^config-contexts/add/$', cached(views.ConfigContextCreateView.as_view()), name='configcontext_add'), url(r'^config-contexts/edit/$', views.ConfigContextBulkEditView.as_view(), name='configcontext_bulk_edit'), url(r'^config-contexts/delete/$', views.ConfigContextBulkDeleteView.as_view(), name='configcontext_bulk_delete'), - url(r'^config-contexts/(?P\d+)/$', views.ConfigContextView.as_view(), name='configcontext'), + url(r'^config-contexts/(?P\d+)/$', cached(views.ConfigContextView.as_view()), name='configcontext'), url(r'^config-contexts/(?P\d+)/edit/$', views.ConfigContextEditView.as_view(), name='configcontext_edit'), url(r'^config-contexts/(?P\d+)/delete/$', views.ConfigContextDeleteView.as_view(), name='configcontext_delete'), @@ -29,12 +30,12 @@ urlpatterns = [ url(r'^image-attachments/(?P\d+)/delete/$', views.ImageAttachmentDeleteView.as_view(), name='imageattachment_delete'), # Reports - url(r'^reports/$', views.ReportListView.as_view(), name='report_list'), - url(r'^reports/(?P[^/]+\.[^/]+)/$', views.ReportView.as_view(), name='report'), + url(r'^reports/$', cached(views.ReportListView.as_view()), name='report_list'), + url(r'^reports/(?P[^/]+\.[^/]+)/$', cached(views.ReportView.as_view()), name='report'), url(r'^reports/(?P[^/]+\.[^/]+)/run/$', views.ReportRunView.as_view(), name='report_run'), # Change logging - url(r'^changelog/$', views.ObjectChangeListView.as_view(), name='objectchange_list'), - url(r'^changelog/(?P\d+)/$', views.ObjectChangeView.as_view(), name='objectchange'), + url(r'^changelog/$', cached(views.ObjectChangeListView.as_view()), name='objectchange_list'), + url(r'^changelog/(?P\d+)/$', cached(views.ObjectChangeView.as_view()), name='objectchange'), ] diff --git a/netbox/ipam/urls.py b/netbox/ipam/urls.py index c2f7badd3..563177700 100644 --- a/netbox/ipam/urls.py +++ b/netbox/ipam/urls.py @@ -1,6 +1,7 @@ from django.conf.urls import url from extras.views import ObjectChangeLogView +from utilities.urls import cached from . import views from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF @@ -8,97 +9,97 @@ app_name = 'ipam' urlpatterns = [ # VRFs - url(r'^vrfs/$', views.VRFListView.as_view(), name='vrf_list'), - url(r'^vrfs/add/$', views.VRFCreateView.as_view(), name='vrf_add'), + url(r'^vrfs/$', cached(views.VRFListView.as_view()), name='vrf_list'), + url(r'^vrfs/add/$', cached(views.VRFCreateView.as_view()), name='vrf_add'), url(r'^vrfs/import/$', views.VRFBulkImportView.as_view(), name='vrf_import'), url(r'^vrfs/edit/$', views.VRFBulkEditView.as_view(), name='vrf_bulk_edit'), url(r'^vrfs/delete/$', views.VRFBulkDeleteView.as_view(), name='vrf_bulk_delete'), - url(r'^vrfs/(?P\d+)/$', views.VRFView.as_view(), name='vrf'), + url(r'^vrfs/(?P\d+)/$', cached(views.VRFView.as_view()), name='vrf'), url(r'^vrfs/(?P\d+)/edit/$', views.VRFEditView.as_view(), name='vrf_edit'), url(r'^vrfs/(?P\d+)/delete/$', views.VRFDeleteView.as_view(), name='vrf_delete'), - url(r'^vrfs/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='vrf_changelog', kwargs={'model': VRF}), + url(r'^vrfs/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='vrf_changelog', kwargs={'model': VRF}), # RIRs - url(r'^rirs/$', views.RIRListView.as_view(), name='rir_list'), - url(r'^rirs/add/$', views.RIRCreateView.as_view(), name='rir_add'), + url(r'^rirs/$', cached(views.RIRListView.as_view()), name='rir_list'), + url(r'^rirs/add/$', cached(views.RIRCreateView.as_view()), name='rir_add'), url(r'^rirs/import/$', views.RIRBulkImportView.as_view(), name='rir_import'), url(r'^rirs/delete/$', views.RIRBulkDeleteView.as_view(), name='rir_bulk_delete'), url(r'^rirs/(?P[\w-]+)/edit/$', views.RIREditView.as_view(), name='rir_edit'), - url(r'^vrfs/(?P[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='rir_changelog', kwargs={'model': RIR}), + url(r'^vrfs/(?P[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='rir_changelog', kwargs={'model': RIR}), # Aggregates - url(r'^aggregates/$', views.AggregateListView.as_view(), name='aggregate_list'), - url(r'^aggregates/add/$', views.AggregateCreateView.as_view(), name='aggregate_add'), + url(r'^aggregates/$', cached(views.AggregateListView.as_view()), name='aggregate_list'), + url(r'^aggregates/add/$', cached(views.AggregateCreateView.as_view()), name='aggregate_add'), url(r'^aggregates/import/$', views.AggregateBulkImportView.as_view(), name='aggregate_import'), url(r'^aggregates/edit/$', views.AggregateBulkEditView.as_view(), name='aggregate_bulk_edit'), url(r'^aggregates/delete/$', views.AggregateBulkDeleteView.as_view(), name='aggregate_bulk_delete'), - url(r'^aggregates/(?P\d+)/$', views.AggregateView.as_view(), name='aggregate'), + url(r'^aggregates/(?P\d+)/$', cached(views.AggregateView.as_view()), name='aggregate'), url(r'^aggregates/(?P\d+)/edit/$', views.AggregateEditView.as_view(), name='aggregate_edit'), url(r'^aggregates/(?P\d+)/delete/$', views.AggregateDeleteView.as_view(), name='aggregate_delete'), - url(r'^aggregates/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='aggregate_changelog', kwargs={'model': Aggregate}), + url(r'^aggregates/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='aggregate_changelog', kwargs={'model': Aggregate}), # Roles - url(r'^roles/$', views.RoleListView.as_view(), name='role_list'), - url(r'^roles/add/$', views.RoleCreateView.as_view(), name='role_add'), + url(r'^roles/$', cached(views.RoleListView.as_view()), name='role_list'), + url(r'^roles/add/$', cached(views.RoleCreateView.as_view()), name='role_add'), url(r'^roles/import/$', views.RoleBulkImportView.as_view(), name='role_import'), url(r'^roles/delete/$', views.RoleBulkDeleteView.as_view(), name='role_bulk_delete'), url(r'^roles/(?P[\w-]+)/edit/$', views.RoleEditView.as_view(), name='role_edit'), - url(r'^roles/(?P[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='role_changelog', kwargs={'model': Role}), + url(r'^roles/(?P[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='role_changelog', kwargs={'model': Role}), # Prefixes - url(r'^prefixes/$', views.PrefixListView.as_view(), name='prefix_list'), - url(r'^prefixes/add/$', views.PrefixCreateView.as_view(), name='prefix_add'), + url(r'^prefixes/$', cached(views.PrefixListView.as_view()), name='prefix_list'), + url(r'^prefixes/add/$', cached(views.PrefixCreateView.as_view()), name='prefix_add'), url(r'^prefixes/import/$', views.PrefixBulkImportView.as_view(), name='prefix_import'), url(r'^prefixes/edit/$', views.PrefixBulkEditView.as_view(), name='prefix_bulk_edit'), url(r'^prefixes/delete/$', views.PrefixBulkDeleteView.as_view(), name='prefix_bulk_delete'), - url(r'^prefixes/(?P\d+)/$', views.PrefixView.as_view(), name='prefix'), + url(r'^prefixes/(?P\d+)/$', cached(views.PrefixView.as_view()), name='prefix'), url(r'^prefixes/(?P\d+)/edit/$', views.PrefixEditView.as_view(), name='prefix_edit'), url(r'^prefixes/(?P\d+)/delete/$', views.PrefixDeleteView.as_view(), name='prefix_delete'), - url(r'^prefixes/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='prefix_changelog', kwargs={'model': Prefix}), - url(r'^prefixes/(?P\d+)/prefixes/$', views.PrefixPrefixesView.as_view(), name='prefix_prefixes'), - url(r'^prefixes/(?P\d+)/ip-addresses/$', views.PrefixIPAddressesView.as_view(), name='prefix_ipaddresses'), + url(r'^prefixes/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='prefix_changelog', kwargs={'model': Prefix}), + url(r'^prefixes/(?P\d+)/prefixes/$', cached(views.PrefixPrefixesView.as_view()), name='prefix_prefixes'), + url(r'^prefixes/(?P\d+)/ip-addresses/$', cached(views.PrefixIPAddressesView.as_view()), name='prefix_ipaddresses'), # IP addresses - url(r'^ip-addresses/$', views.IPAddressListView.as_view(), name='ipaddress_list'), - url(r'^ip-addresses/add/$', views.IPAddressCreateView.as_view(), name='ipaddress_add'), - url(r'^ip-addresses/bulk-add/$', views.IPAddressBulkCreateView.as_view(), name='ipaddress_bulk_add'), + url(r'^ip-addresses/$', cached(views.IPAddressListView.as_view()), name='ipaddress_list'), + url(r'^ip-addresses/add/$', cached(views.IPAddressCreateView.as_view()), name='ipaddress_add'), + url(r'^ip-addresses/bulk-add/$', cached(views.IPAddressBulkCreateView.as_view()), name='ipaddress_bulk_add'), url(r'^ip-addresses/import/$', views.IPAddressBulkImportView.as_view(), name='ipaddress_import'), url(r'^ip-addresses/edit/$', views.IPAddressBulkEditView.as_view(), name='ipaddress_bulk_edit'), url(r'^ip-addresses/delete/$', views.IPAddressBulkDeleteView.as_view(), name='ipaddress_bulk_delete'), - url(r'^ip-addresses/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='ipaddress_changelog', kwargs={'model': IPAddress}), + url(r'^ip-addresses/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='ipaddress_changelog', kwargs={'model': IPAddress}), url(r'^ip-addresses/assign/$', views.IPAddressAssignView.as_view(), name='ipaddress_assign'), - url(r'^ip-addresses/(?P\d+)/$', views.IPAddressView.as_view(), name='ipaddress'), + url(r'^ip-addresses/(?P\d+)/$', cached(views.IPAddressView.as_view()), name='ipaddress'), url(r'^ip-addresses/(?P\d+)/edit/$', views.IPAddressEditView.as_view(), name='ipaddress_edit'), url(r'^ip-addresses/(?P\d+)/delete/$', views.IPAddressDeleteView.as_view(), name='ipaddress_delete'), # VLAN groups - url(r'^vlan-groups/$', views.VLANGroupListView.as_view(), name='vlangroup_list'), - url(r'^vlan-groups/add/$', views.VLANGroupCreateView.as_view(), name='vlangroup_add'), + url(r'^vlan-groups/$', cached(views.VLANGroupListView.as_view()), name='vlangroup_list'), + url(r'^vlan-groups/add/$', cached(views.VLANGroupCreateView.as_view()), name='vlangroup_add'), url(r'^vlan-groups/import/$', views.VLANGroupBulkImportView.as_view(), name='vlangroup_import'), url(r'^vlan-groups/delete/$', views.VLANGroupBulkDeleteView.as_view(), name='vlangroup_bulk_delete'), url(r'^vlan-groups/(?P\d+)/edit/$', views.VLANGroupEditView.as_view(), name='vlangroup_edit'), - url(r'^vlan-groups/(?P\d+)/vlans/$', views.VLANGroupVLANsView.as_view(), name='vlangroup_vlans'), - url(r'^vlan-groups/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='vlangroup_changelog', kwargs={'model': VLANGroup}), + url(r'^vlan-groups/(?P\d+)/vlans/$', cached(views.VLANGroupVLANsView.as_view()), name='vlangroup_vlans'), + url(r'^vlan-groups/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='vlangroup_changelog', kwargs={'model': VLANGroup}), # VLANs - url(r'^vlans/$', views.VLANListView.as_view(), name='vlan_list'), - url(r'^vlans/add/$', views.VLANCreateView.as_view(), name='vlan_add'), + url(r'^vlans/$', cached(views.VLANListView.as_view()), name='vlan_list'), + url(r'^vlans/add/$', cached(views.VLANCreateView.as_view()), name='vlan_add'), url(r'^vlans/import/$', views.VLANBulkImportView.as_view(), name='vlan_import'), url(r'^vlans/edit/$', views.VLANBulkEditView.as_view(), name='vlan_bulk_edit'), url(r'^vlans/delete/$', views.VLANBulkDeleteView.as_view(), name='vlan_bulk_delete'), - url(r'^vlans/(?P\d+)/$', views.VLANView.as_view(), name='vlan'), - url(r'^vlans/(?P\d+)/members/$', views.VLANMembersView.as_view(), name='vlan_members'), + url(r'^vlans/(?P\d+)/$', cached(views.VLANView.as_view()), name='vlan'), + url(r'^vlans/(?P\d+)/members/$', cached(views.VLANMembersView.as_view()), name='vlan_members'), url(r'^vlans/(?P\d+)/edit/$', views.VLANEditView.as_view(), name='vlan_edit'), url(r'^vlans/(?P\d+)/delete/$', views.VLANDeleteView.as_view(), name='vlan_delete'), - url(r'^vlans/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='vlan_changelog', kwargs={'model': VLAN}), + url(r'^vlans/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='vlan_changelog', kwargs={'model': VLAN}), # Services - url(r'^services/$', views.ServiceListView.as_view(), name='service_list'), + url(r'^services/$', cached(views.ServiceListView.as_view()), name='service_list'), url(r'^services/edit/$', views.ServiceBulkEditView.as_view(), name='service_bulk_edit'), url(r'^services/delete/$', views.ServiceBulkDeleteView.as_view(), name='service_bulk_delete'), - url(r'^services/(?P\d+)/$', views.ServiceView.as_view(), name='service'), + url(r'^services/(?P\d+)/$', cached(views.ServiceView.as_view()), name='service'), url(r'^services/(?P\d+)/edit/$', views.ServiceEditView.as_view(), name='service_edit'), url(r'^services/(?P\d+)/delete/$', views.ServiceDeleteView.as_view(), name='service_delete'), - url(r'^services/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='service_changelog', kwargs={'model': Service}), + url(r'^services/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='service_changelog', kwargs={'model': Service}), ] diff --git a/netbox/netbox/configuration.example.py b/netbox/netbox/configuration.example.py index 6efecdf35..ee55ade40 100644 --- a/netbox/netbox/configuration.example.py +++ b/netbox/netbox/configuration.example.py @@ -25,6 +25,16 @@ DATABASE = { # https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECRET_KEY SECRET_KEY = '' +# Redis database settings. The Redis database is used for caching and background processing such as webhooks +REDIS = { + 'HOST': 'localhost', + 'PORT': 6379, + 'PASSWORD': '', + 'DATABASE': 0, + 'DEFAULT_TIMEOUT': 300, + 'SSL': False, +} + ######################### # # @@ -50,6 +60,18 @@ BANNER_LOGIN = '' # BASE_PATH = 'netbox/' BASE_PATH = '' +# Cache timeout in seconds. Set to `None` to enforce an infinate timeout. Set to 0 to dissable caching by immediatly +# expiring keys. Defaults to 900 (15 minutes) +CACHE_TIMEOUT = 900 + +# Max number of entries (unique pages) to store in the cache at a time. +CACHE_MAX_ENTRIES = 300 + +# The fraction of entries that are culled when CACHE_MAX_ENTRIES is reached. The actual ratio is 1 / CACHE_CULL_FREQUENCY, +# so set CACHE_CULL_FREQUENCY to 2 to cull half the entries when CACHE_MAX_ENTRIES is reached. This setting should be an +# integer and defaults to 3 +CACHE_CULL_FREQUENCY = 3 + # Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90) CHANGELOG_RETENTION = 90 @@ -133,16 +155,6 @@ PAGINATE_COUNT = 50 # prefer IPv4 instead. PREFER_IPV4 = False -# Redis database settings (optional). A Redis database is required only if the webhooks backend is enabled. -REDIS = { - 'HOST': 'localhost', - 'PORT': 6379, - 'PASSWORD': '', - 'DATABASE': 0, - 'DEFAULT_TIMEOUT': 300, - 'SSL': False, -} - # The file path where custom reports will be stored. A trailing slash is not needed. Note that the default value of # this setting is derived from the installed location. # REPORTS_ROOT = '/opt/netbox/netbox/reports' @@ -159,6 +171,9 @@ TIME_ZONE = 'UTC' # database be configured and accessible by NetBox. WEBHOOKS_ENABLED = False +# Expose Prometheus monitoring metrics at `/metrics` +PROMETHEUS_ENABLE = False + # Date/time formatting. See the following link for supported formats: # https://docs.djangoproject.com/en/dev/ref/templates/builtins/#date DATE_FORMAT = 'N j, Y' diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 69a9c13f7..805113a1e 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -28,7 +28,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Import required configuration parameters ALLOWED_HOSTS = DATABASE = SECRET_KEY = None -for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']: +for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY', 'REDIS']: try: globals()[setting] = getattr(configuration, setting) except AttributeError: @@ -44,6 +44,9 @@ BANNER_TOP = getattr(configuration, 'BANNER_TOP', '') BASE_PATH = getattr(configuration, 'BASE_PATH', '') if BASE_PATH: BASE_PATH = BASE_PATH.strip('/') + '/' # Enforce trailing slash only +CACHE_TIMEOUT = getattr(configuration, 'CACHE_TIMEOUT', 900) +CACHE_MAX_ENTRIES = getattr(configuration, 'CACHE_MAX_ENTRIES', 300) +CACHE_CULL_FREQUENCY = getattr(configuration, 'CACHE_CULL_FREQUENCY', 3) CHANGELOG_RETENTION = getattr(configuration, 'CHANGELOG_RETENTION', 90) CORS_ORIGIN_ALLOW_ALL = getattr(configuration, 'CORS_ORIGIN_ALLOW_ALL', False) CORS_ORIGIN_REGEX_WHITELIST = getattr(configuration, 'CORS_ORIGIN_REGEX_WHITELIST', []) @@ -65,6 +68,7 @@ NAPALM_PASSWORD = getattr(configuration, 'NAPALM_PASSWORD', '') NAPALM_TIMEOUT = getattr(configuration, 'NAPALM_TIMEOUT', 30) NAPALM_ARGS = getattr(configuration, 'NAPALM_ARGS', {}) PAGINATE_COUNT = getattr(configuration, 'PAGINATE_COUNT', 50) +PROMETHEUS_ENABLE = getattr(configuration, 'PROMETHEUS_ENABLE', False) PREFER_IPV4 = getattr(configuration, 'PREFER_IPV4', False) REPORTS_ROOT = getattr(configuration, 'REPORTS_ROOT', os.path.join(BASE_DIR, 'reports')).rstrip('/') REDIS = getattr(configuration, 'REDIS', {}) @@ -157,6 +161,8 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'django.contrib.humanize', 'corsheaders', + 'django_prometheus', + 'django_redis', 'debug_toolbar', 'django_filters', 'django_tables2', @@ -184,6 +190,7 @@ if WEBHOOKS_ENABLED: # Middleware MIDDLEWARE = ( 'debug_toolbar.middleware.DebugToolbarMiddleware', + 'django_prometheus.middleware.PrometheusBeforeMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', @@ -196,6 +203,7 @@ MIDDLEWARE = ( 'utilities.middleware.LoginRequiredMiddleware', 'utilities.middleware.APIVersionMiddleware', 'extras.middleware.ObjectChangeMiddleware', + 'django_prometheus.middleware.PrometheusAfterMiddleware', ) ROOT_URLCONF = 'netbox.urls' @@ -218,6 +226,35 @@ TEMPLATES = [ }, ] +# Caching +if REDIS_SSL: + REDIS_CACHE_CON_STRING = 'rediss://' +else: + REDIS_CACHE_CON_STRING = 'redis://' + +if REDIS_PASSWORD: + REDIS_CACHE_CON_STRING = '{}@{}'.format(REDIS_PASSWORD, REDIS_CACHE_CON_STRING) + +REDIS_CACHE_CON_STRING = '{}{}:{}/{}'.format(REDIS_CACHE_CON_STRING, REDIS_HOST, REDIS_PORT, REDIS_DATABASE) + +if PROMETHEUS_ENABLE: + CACHE_BACKEND = 'django_prometheus.cache.backends.redis.RedisCache' +else: + CACHE_BACKEND = 'django_redis.cache.RedisCache' + +CACHES = { + "default": { + "BACKEND": CACHE_BACKEND, + "LOCATION": REDIS_CACHE_CON_STRING, + 'TIMEOUT': CACHE_TIMEOUT, + "OPTIONS": { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + "MAX_ENTRIES": CACHE_MAX_ENTRIES, + "CULL_FREQUENCY": CACHE_CULL_FREQUENCY + } + } +} + # WSGI WSGI_APPLICATION = 'netbox.wsgi.application' SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') diff --git a/netbox/netbox/urls.py b/netbox/netbox/urls.py index 45c99beb9..dd7aa7f8f 100644 --- a/netbox/netbox/urls.py +++ b/netbox/netbox/urls.py @@ -6,6 +6,7 @@ from drf_yasg.views import get_schema_view from netbox.views import APIRootView, HomeView, SearchView from users.views import LoginView, LogoutView +from utilities.urls import cached from .admin import admin_site schema_view = get_schema_view( @@ -24,11 +25,11 @@ schema_view = get_schema_view( _patterns = [ # Base views - url(r'^$', HomeView.as_view(), name='home'), - url(r'^search/$', SearchView.as_view(), name='search'), + url(r'^$', cached(HomeView.as_view()), name='home'), + url(r'^search/$', cached(SearchView.as_view()), name='search'), # Login/logout - url(r'^login/$', LoginView.as_view(), name='login'), + url(r'^login/$', cached(LoginView.as_view()), name='login'), url(r'^logout/$', LogoutView.as_view(), name='logout'), # Apps @@ -42,7 +43,7 @@ _patterns = [ url(r'^virtualization/', include('virtualization.urls')), # API - url(r'^api/$', APIRootView.as_view(), name='api-root'), + url(r'^api/$', cached(APIRootView.as_view()), name='api-root'), url(r'^api/circuits/', include('circuits.api.urls')), url(r'^api/dcim/', include('dcim.api.urls')), url(r'^api/extras/', include('extras.api.urls')), @@ -67,6 +68,11 @@ if settings.WEBHOOKS_ENABLED: url(r'^admin/webhook-backend-status/', include('django_rq.urls')), ] +if settings.PROMETHEUS_ENABLE: + _patterns += [ + url('', include('django_prometheus.urls')), + ] + if settings.DEBUG: import debug_toolbar _patterns += [ diff --git a/netbox/secrets/urls.py b/netbox/secrets/urls.py index e1ce2b8f2..1b73a2ca8 100644 --- a/netbox/secrets/urls.py +++ b/netbox/secrets/urls.py @@ -1,6 +1,7 @@ from django.conf.urls import url from extras.views import ObjectChangeLogView +from utilities.urls import cached from . import views from .models import Secret, SecretRole @@ -8,21 +9,21 @@ app_name = 'secrets' urlpatterns = [ # Secret roles - url(r'^secret-roles/$', views.SecretRoleListView.as_view(), name='secretrole_list'), - url(r'^secret-roles/add/$', views.SecretRoleCreateView.as_view(), name='secretrole_add'), + url(r'^secret-roles/$', cached(views.SecretRoleListView.as_view()), name='secretrole_list'), + url(r'^secret-roles/add/$', cached(views.SecretRoleCreateView.as_view()), name='secretrole_add'), url(r'^secret-roles/import/$', views.SecretRoleBulkImportView.as_view(), name='secretrole_import'), url(r'^secret-roles/delete/$', views.SecretRoleBulkDeleteView.as_view(), name='secretrole_bulk_delete'), url(r'^secret-roles/(?P[\w-]+)/edit/$', views.SecretRoleEditView.as_view(), name='secretrole_edit'), - url(r'^secret-roles/(?P[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='secretrole_changelog', kwargs={'model': SecretRole}), + url(r'^secret-roles/(?P[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='secretrole_changelog', kwargs={'model': SecretRole}), # Secrets - url(r'^secrets/$', views.SecretListView.as_view(), name='secret_list'), + url(r'^secrets/$', cached(views.SecretListView.as_view()), name='secret_list'), url(r'^secrets/import/$', views.SecretBulkImportView.as_view(), name='secret_import'), url(r'^secrets/edit/$', views.SecretBulkEditView.as_view(), name='secret_bulk_edit'), url(r'^secrets/delete/$', views.SecretBulkDeleteView.as_view(), name='secret_bulk_delete'), - url(r'^secrets/(?P\d+)/$', views.SecretView.as_view(), name='secret'), + url(r'^secrets/(?P\d+)/$', cached(views.SecretView.as_view()), name='secret'), url(r'^secrets/(?P\d+)/edit/$', views.secret_edit, name='secret_edit'), url(r'^secrets/(?P\d+)/delete/$', views.SecretDeleteView.as_view(), name='secret_delete'), - url(r'^secrets/(?P\d+)/changelog/$', ObjectChangeLogView.as_view(), name='secret_changelog', kwargs={'model': Secret}), + url(r'^secrets/(?P\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='secret_changelog', kwargs={'model': Secret}), ] diff --git a/netbox/tenancy/urls.py b/netbox/tenancy/urls.py index 19522e6c7..ab3a020e0 100644 --- a/netbox/tenancy/urls.py +++ b/netbox/tenancy/urls.py @@ -1,6 +1,7 @@ from django.conf.urls import url from extras.views import ObjectChangeLogView +from utilities.urls import cached from . import views from .models import Tenant, TenantGroup @@ -8,22 +9,22 @@ app_name = 'tenancy' urlpatterns = [ # Tenant groups - url(r'^tenant-groups/$', views.TenantGroupListView.as_view(), name='tenantgroup_list'), - url(r'^tenant-groups/add/$', views.TenantGroupCreateView.as_view(), name='tenantgroup_add'), + url(r'^tenant-groups/$', cached(views.TenantGroupListView.as_view()), name='tenantgroup_list'), + url(r'^tenant-groups/add/$', cached(views.TenantGroupCreateView.as_view()), name='tenantgroup_add'), url(r'^tenant-groups/import/$', views.TenantGroupBulkImportView.as_view(), name='tenantgroup_import'), url(r'^tenant-groups/delete/$', views.TenantGroupBulkDeleteView.as_view(), name='tenantgroup_bulk_delete'), url(r'^tenant-groups/(?P[\w-]+)/edit/$', views.TenantGroupEditView.as_view(), name='tenantgroup_edit'), - url(r'^tenant-groups/(?P[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='tenantgroup_changelog', kwargs={'model': TenantGroup}), + url(r'^tenant-groups/(?P[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='tenantgroup_changelog', kwargs={'model': TenantGroup}), # Tenants - url(r'^tenants/$', views.TenantListView.as_view(), name='tenant_list'), - url(r'^tenants/add/$', views.TenantCreateView.as_view(), name='tenant_add'), + url(r'^tenants/$', cached(views.TenantListView.as_view()), name='tenant_list'), + url(r'^tenants/add/$', cached(views.TenantCreateView.as_view()), name='tenant_add'), url(r'^tenants/import/$', views.TenantBulkImportView.as_view(), name='tenant_import'), url(r'^tenants/edit/$', views.TenantBulkEditView.as_view(), name='tenant_bulk_edit'), url(r'^tenants/delete/$', views.TenantBulkDeleteView.as_view(), name='tenant_bulk_delete'), - url(r'^tenants/(?P[\w-]+)/$', views.TenantView.as_view(), name='tenant'), + url(r'^tenants/(?P[\w-]+)/$', cached(views.TenantView.as_view()), name='tenant'), url(r'^tenants/(?P[\w-]+)/edit/$', views.TenantEditView.as_view(), name='tenant_edit'), url(r'^tenants/(?P[\w-]+)/delete/$', views.TenantDeleteView.as_view(), name='tenant_delete'), - url(r'^tenants/(?P[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='tenant_changelog', kwargs={'model': Tenant}), + url(r'^tenants/(?P[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='tenant_changelog', kwargs={'model': Tenant}), ] diff --git a/netbox/utilities/api.py b/netbox/utilities/api.py index fbebd09ff..d259343ae 100644 --- a/netbox/utilities/api.py +++ b/netbox/utilities/api.py @@ -6,6 +6,8 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.db.models import ManyToManyField from django.http import Http404 +from django.utils.decorators import method_decorator +from django.views.decorators.cache import cache_page from rest_framework.exceptions import APIException from rest_framework.permissions import BasePermission from rest_framework.relations import PrimaryKeyRelatedField, RelatedField @@ -249,6 +251,21 @@ class ModelViewSet(_ModelViewSet): return self.serializer_class + @method_decorator(cache_page(settings.CACHE_TIMEOUT)) + def list(self, *args, **kwargs): + """ + Call to super to allow for caching + """ + return super().list(*args, **kwargs) + + @method_decorator(cache_page(settings.CACHE_TIMEOUT)) + def retrieve(self, *args, **kwargs): + """ + Call to super to allow for caching + """ + return super().retrieve(*args, **kwargs) + + class FieldChoicesViewSet(ViewSet): """ Expose the built-in numeric values which represent static choices for a model's field. @@ -284,9 +301,11 @@ class FieldChoicesViewSet(ViewSet): }) self._fields[key] = choices + @method_decorator(cache_page(settings.CACHE_TIMEOUT)) def list(self, request): return Response(self._fields) + @method_decorator(cache_page(settings.CACHE_TIMEOUT)) def retrieve(self, request, pk): if pk not in self._fields: raise Http404 diff --git a/netbox/utilities/urls.py b/netbox/utilities/urls.py new file mode 100644 index 000000000..f81b02257 --- /dev/null +++ b/netbox/utilities/urls.py @@ -0,0 +1,9 @@ +from django.conf import settings +from django.views.decorators.cache import cache_page + + +def cached(view): + """ + Return a cache_page decorated view + """ + return cache_page(settings.CACHE_TIMEOUT)(view) diff --git a/requirements.txt b/requirements.txt index f65328ecd..abcd4eea7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,8 @@ django-cors-headers==2.4.0 django-debug-toolbar==1.11 django-filter==2.0.0 django-mptt==0.9.1 +django-prometheus==1.0.15 +django-redis==4.5.0 django-tables2==2.0.3 django-taggit==0.23.0 django-taggit-serializer==0.1.7