views.py 97 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214
  1. from django.contrib import messages
  2. from django.contrib.contenttypes.models import ContentType
  3. from django.core.paginator import EmptyPage, PageNotAnInteger
  4. from django.db import transaction
  5. from django.db.models import Prefetch
  6. from django.forms import ModelMultipleChoiceField, MultipleHiddenInput, modelformset_factory
  7. from django.shortcuts import get_object_or_404, redirect, render
  8. from django.urls import reverse
  9. from django.utils.html import escape
  10. from django.utils.safestring import mark_safe
  11. from django.views.generic import View
  12. from circuits.models import Circuit, CircuitTermination
  13. from extras.views import ObjectConfigContextView
  14. from ipam.models import ASN, IPAddress, Prefix, Service, VLAN, VLANGroup
  15. from ipam.tables import AssignedIPAddressesTable, InterfaceVLANTable
  16. from netbox.views import generic
  17. from utilities.forms import ConfirmationForm
  18. from utilities.paginator import EnhancedPaginator, get_paginate_count
  19. from utilities.permissions import get_permission_for_model
  20. from utilities.utils import count_related
  21. from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin
  22. from virtualization.models import VirtualMachine
  23. from . import filtersets, forms, tables
  24. from .choices import DeviceFaceChoices
  25. from .constants import NONCONNECTABLE_IFACE_TYPES
  26. from .models import *
  27. CABLE_TERMINATION_TYPES = {
  28. 'dcim.consoleport': ConsolePort,
  29. 'dcim.consoleserverport': ConsoleServerPort,
  30. 'dcim.powerport': PowerPort,
  31. 'dcim.poweroutlet': PowerOutlet,
  32. 'dcim.interface': Interface,
  33. 'dcim.frontport': FrontPort,
  34. 'dcim.rearport': RearPort,
  35. 'dcim.powerfeed': PowerFeed,
  36. 'circuits.circuittermination': CircuitTermination,
  37. }
  38. class DeviceComponentsView(generic.ObjectChildrenView):
  39. queryset = Device.objects.all()
  40. def get_children(self, request, parent):
  41. return self.child_model.objects.restrict(request.user, 'view').filter(device=parent)
  42. def get_extra_context(self, request, instance):
  43. return {
  44. 'active_tab': f"{self.child_model._meta.verbose_name_plural.replace(' ', '-')}",
  45. }
  46. class DeviceTypeComponentsView(DeviceComponentsView):
  47. queryset = DeviceType.objects.all()
  48. template_name = 'dcim/devicetype/component_templates.html'
  49. viewname = None # Used for return_url resolution
  50. def get_children(self, request, parent):
  51. return self.child_model.objects.restrict(request.user, 'view').filter(device_type=parent)
  52. def get_extra_context(self, request, instance):
  53. context = super().get_extra_context(request, instance)
  54. context['return_url'] = reverse(self.viewname, kwargs={'pk': instance.pk})
  55. return context
  56. class ModuleTypeComponentsView(DeviceComponentsView):
  57. queryset = ModuleType.objects.all()
  58. template_name = 'dcim/moduletype/component_templates.html'
  59. viewname = None # Used for return_url resolution
  60. def get_children(self, request, parent):
  61. return self.child_model.objects.restrict(request.user, 'view').filter(module_type=parent)
  62. def get_extra_context(self, request, instance):
  63. context = super().get_extra_context(request, instance)
  64. context['return_url'] = reverse(self.viewname, kwargs={'pk': instance.pk})
  65. return context
  66. class BulkDisconnectView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
  67. """
  68. An extendable view for disconnection console/power/interface components in bulk.
  69. """
  70. queryset = None
  71. template_name = 'dcim/bulk_disconnect.html'
  72. def __init__(self, *args, **kwargs):
  73. super().__init__(*args, **kwargs)
  74. # Create a new Form class from ConfirmationForm
  75. class _Form(ConfirmationForm):
  76. pk = ModelMultipleChoiceField(
  77. queryset=self.queryset,
  78. widget=MultipleHiddenInput()
  79. )
  80. self.form = _Form
  81. def get_required_permission(self):
  82. return get_permission_for_model(self.queryset.model, 'change')
  83. def post(self, request):
  84. selected_objects = []
  85. return_url = self.get_return_url(request)
  86. if '_confirm' in request.POST:
  87. form = self.form(request.POST)
  88. if form.is_valid():
  89. with transaction.atomic():
  90. count = 0
  91. for obj in self.queryset.filter(pk__in=form.cleaned_data['pk']):
  92. if obj.cable is None:
  93. continue
  94. obj.cable.delete()
  95. count += 1
  96. messages.success(request, "Disconnected {} {}".format(
  97. count, self.queryset.model._meta.verbose_name_plural
  98. ))
  99. return redirect(return_url)
  100. else:
  101. form = self.form(initial={'pk': request.POST.getlist('pk')})
  102. selected_objects = self.queryset.filter(pk__in=form.initial['pk'])
  103. return render(request, self.template_name, {
  104. 'form': form,
  105. 'obj_type_plural': self.queryset.model._meta.verbose_name_plural,
  106. 'selected_objects': selected_objects,
  107. 'return_url': return_url,
  108. })
  109. #
  110. # Regions
  111. #
  112. class RegionListView(generic.ObjectListView):
  113. queryset = Region.objects.add_related_count(
  114. Region.objects.all(),
  115. Site,
  116. 'region',
  117. 'site_count',
  118. cumulative=True
  119. )
  120. filterset = filtersets.RegionFilterSet
  121. filterset_form = forms.RegionFilterForm
  122. table = tables.RegionTable
  123. class RegionView(generic.ObjectView):
  124. queryset = Region.objects.all()
  125. def get_extra_context(self, request, instance):
  126. child_regions = Region.objects.add_related_count(
  127. Region.objects.all(),
  128. Site,
  129. 'region',
  130. 'site_count',
  131. cumulative=True
  132. ).restrict(request.user, 'view').filter(
  133. parent__in=instance.get_descendants(include_self=True)
  134. )
  135. child_regions_table = tables.RegionTable(child_regions)
  136. child_regions_table.columns.hide('actions')
  137. sites = Site.objects.restrict(request.user, 'view').filter(
  138. region=instance
  139. )
  140. sites_table = tables.SiteTable(sites, user=request.user, exclude=('region',))
  141. sites_table.configure(request)
  142. return {
  143. 'child_regions_table': child_regions_table,
  144. 'sites_table': sites_table,
  145. }
  146. class RegionEditView(generic.ObjectEditView):
  147. queryset = Region.objects.all()
  148. form = forms.RegionForm
  149. class RegionDeleteView(generic.ObjectDeleteView):
  150. queryset = Region.objects.all()
  151. class RegionBulkImportView(generic.BulkImportView):
  152. queryset = Region.objects.all()
  153. model_form = forms.RegionCSVForm
  154. table = tables.RegionTable
  155. class RegionBulkEditView(generic.BulkEditView):
  156. queryset = Region.objects.add_related_count(
  157. Region.objects.all(),
  158. Site,
  159. 'region',
  160. 'site_count',
  161. cumulative=True
  162. )
  163. filterset = filtersets.RegionFilterSet
  164. table = tables.RegionTable
  165. form = forms.RegionBulkEditForm
  166. class RegionBulkDeleteView(generic.BulkDeleteView):
  167. queryset = Region.objects.add_related_count(
  168. Region.objects.all(),
  169. Site,
  170. 'region',
  171. 'site_count',
  172. cumulative=True
  173. )
  174. filterset = filtersets.RegionFilterSet
  175. table = tables.RegionTable
  176. #
  177. # Site groups
  178. #
  179. class SiteGroupListView(generic.ObjectListView):
  180. queryset = SiteGroup.objects.add_related_count(
  181. SiteGroup.objects.all(),
  182. Site,
  183. 'group',
  184. 'site_count',
  185. cumulative=True
  186. )
  187. filterset = filtersets.SiteGroupFilterSet
  188. filterset_form = forms.SiteGroupFilterForm
  189. table = tables.SiteGroupTable
  190. class SiteGroupView(generic.ObjectView):
  191. queryset = SiteGroup.objects.all()
  192. def get_extra_context(self, request, instance):
  193. child_groups = SiteGroup.objects.add_related_count(
  194. SiteGroup.objects.all(),
  195. Site,
  196. 'group',
  197. 'site_count',
  198. cumulative=True
  199. ).restrict(request.user, 'view').filter(
  200. parent__in=instance.get_descendants(include_self=True)
  201. )
  202. child_groups_table = tables.SiteGroupTable(child_groups)
  203. child_groups_table.columns.hide('actions')
  204. sites = Site.objects.restrict(request.user, 'view').filter(
  205. group=instance
  206. )
  207. sites_table = tables.SiteTable(sites, user=request.user, exclude=('group',))
  208. sites_table.configure(request)
  209. return {
  210. 'child_groups_table': child_groups_table,
  211. 'sites_table': sites_table,
  212. }
  213. class SiteGroupEditView(generic.ObjectEditView):
  214. queryset = SiteGroup.objects.all()
  215. form = forms.SiteGroupForm
  216. class SiteGroupDeleteView(generic.ObjectDeleteView):
  217. queryset = SiteGroup.objects.all()
  218. class SiteGroupBulkImportView(generic.BulkImportView):
  219. queryset = SiteGroup.objects.all()
  220. model_form = forms.SiteGroupCSVForm
  221. table = tables.SiteGroupTable
  222. class SiteGroupBulkEditView(generic.BulkEditView):
  223. queryset = SiteGroup.objects.add_related_count(
  224. SiteGroup.objects.all(),
  225. Site,
  226. 'group',
  227. 'site_count',
  228. cumulative=True
  229. )
  230. filterset = filtersets.SiteGroupFilterSet
  231. table = tables.SiteGroupTable
  232. form = forms.SiteGroupBulkEditForm
  233. class SiteGroupBulkDeleteView(generic.BulkDeleteView):
  234. queryset = SiteGroup.objects.add_related_count(
  235. SiteGroup.objects.all(),
  236. Site,
  237. 'group',
  238. 'site_count',
  239. cumulative=True
  240. )
  241. filterset = filtersets.SiteGroupFilterSet
  242. table = tables.SiteGroupTable
  243. #
  244. # Sites
  245. #
  246. class SiteListView(generic.ObjectListView):
  247. queryset = Site.objects.all()
  248. filterset = filtersets.SiteFilterSet
  249. filterset_form = forms.SiteFilterForm
  250. table = tables.SiteTable
  251. class SiteView(generic.ObjectView):
  252. queryset = Site.objects.prefetch_related('tenant__group')
  253. def get_extra_context(self, request, instance):
  254. stats = {
  255. 'location_count': Location.objects.restrict(request.user, 'view').filter(site=instance).count(),
  256. 'rack_count': Rack.objects.restrict(request.user, 'view').filter(site=instance).count(),
  257. 'device_count': Device.objects.restrict(request.user, 'view').filter(site=instance).count(),
  258. 'prefix_count': Prefix.objects.restrict(request.user, 'view').filter(site=instance).count(),
  259. 'vlangroup_count': VLANGroup.objects.restrict(request.user, 'view').filter(
  260. scope_type=ContentType.objects.get_for_model(Site),
  261. scope_id=instance.pk
  262. ).count(),
  263. 'vlan_count': VLAN.objects.restrict(request.user, 'view').filter(site=instance).count(),
  264. 'circuit_count': Circuit.objects.restrict(request.user, 'view').filter(terminations__site=instance).count(),
  265. 'vm_count': VirtualMachine.objects.restrict(request.user, 'view').filter(cluster__site=instance).count(),
  266. }
  267. locations = Location.objects.add_related_count(
  268. Location.objects.all(),
  269. Rack,
  270. 'location',
  271. 'rack_count',
  272. cumulative=True
  273. )
  274. locations = Location.objects.add_related_count(
  275. locations,
  276. Device,
  277. 'location',
  278. 'device_count',
  279. cumulative=True
  280. ).restrict(request.user, 'view').filter(site=instance)
  281. nonracked_devices = Device.objects.filter(
  282. site=instance,
  283. rack__isnull=True,
  284. parent_bay__isnull=True
  285. ).prefetch_related('device_type__manufacturer', 'parent_bay', 'device_role')
  286. asns = ASN.objects.restrict(request.user, 'view').filter(sites=instance)
  287. asn_count = asns.count()
  288. stats.update({'asn_count': asn_count})
  289. return {
  290. 'stats': stats,
  291. 'locations': locations,
  292. 'asns': asns,
  293. 'nonracked_devices': nonracked_devices.order_by('-pk')[:10],
  294. 'total_nonracked_devices_count': nonracked_devices.count(),
  295. }
  296. class SiteEditView(generic.ObjectEditView):
  297. queryset = Site.objects.all()
  298. form = forms.SiteForm
  299. class SiteDeleteView(generic.ObjectDeleteView):
  300. queryset = Site.objects.all()
  301. class SiteBulkImportView(generic.BulkImportView):
  302. queryset = Site.objects.all()
  303. model_form = forms.SiteCSVForm
  304. table = tables.SiteTable
  305. class SiteBulkEditView(generic.BulkEditView):
  306. queryset = Site.objects.all()
  307. filterset = filtersets.SiteFilterSet
  308. table = tables.SiteTable
  309. form = forms.SiteBulkEditForm
  310. class SiteBulkDeleteView(generic.BulkDeleteView):
  311. queryset = Site.objects.all()
  312. filterset = filtersets.SiteFilterSet
  313. table = tables.SiteTable
  314. #
  315. # Locations
  316. #
  317. class LocationListView(generic.ObjectListView):
  318. queryset = Location.objects.add_related_count(
  319. Location.objects.add_related_count(
  320. Location.objects.all(),
  321. Device,
  322. 'location',
  323. 'device_count',
  324. cumulative=True
  325. ),
  326. Rack,
  327. 'location',
  328. 'rack_count',
  329. cumulative=True
  330. )
  331. filterset = filtersets.LocationFilterSet
  332. filterset_form = forms.LocationFilterForm
  333. table = tables.LocationTable
  334. class LocationView(generic.ObjectView):
  335. queryset = Location.objects.all()
  336. def get_extra_context(self, request, instance):
  337. location_ids = instance.get_descendants(include_self=True).values_list('pk', flat=True)
  338. rack_count = Rack.objects.filter(location__in=location_ids).count()
  339. device_count = Device.objects.filter(location__in=location_ids).count()
  340. child_locations = Location.objects.add_related_count(
  341. Location.objects.add_related_count(
  342. Location.objects.all(),
  343. Device,
  344. 'location',
  345. 'device_count',
  346. cumulative=True
  347. ),
  348. Rack,
  349. 'location',
  350. 'rack_count',
  351. cumulative=True
  352. ).filter(pk__in=location_ids).exclude(pk=instance.pk)
  353. child_locations_table = tables.LocationTable(child_locations, user=request.user)
  354. child_locations_table.configure(request)
  355. nonracked_devices = Device.objects.filter(
  356. location=instance,
  357. rack__isnull=True,
  358. parent_bay__isnull=True
  359. ).prefetch_related('device_type__manufacturer', 'parent_bay', 'device_role')
  360. return {
  361. 'rack_count': rack_count,
  362. 'device_count': device_count,
  363. 'child_locations_table': child_locations_table,
  364. 'nonracked_devices': nonracked_devices.order_by('-pk')[:10],
  365. 'total_nonracked_devices_count': nonracked_devices.count(),
  366. }
  367. class LocationEditView(generic.ObjectEditView):
  368. queryset = Location.objects.all()
  369. form = forms.LocationForm
  370. class LocationDeleteView(generic.ObjectDeleteView):
  371. queryset = Location.objects.all()
  372. class LocationBulkImportView(generic.BulkImportView):
  373. queryset = Location.objects.all()
  374. model_form = forms.LocationCSVForm
  375. table = tables.LocationTable
  376. class LocationBulkEditView(generic.BulkEditView):
  377. queryset = Location.objects.add_related_count(
  378. Location.objects.all(),
  379. Rack,
  380. 'location',
  381. 'rack_count',
  382. cumulative=True
  383. ).prefetch_related('site')
  384. filterset = filtersets.LocationFilterSet
  385. table = tables.LocationTable
  386. form = forms.LocationBulkEditForm
  387. class LocationBulkDeleteView(generic.BulkDeleteView):
  388. queryset = Location.objects.add_related_count(
  389. Location.objects.all(),
  390. Rack,
  391. 'location',
  392. 'rack_count',
  393. cumulative=True
  394. ).prefetch_related('site')
  395. filterset = filtersets.LocationFilterSet
  396. table = tables.LocationTable
  397. #
  398. # Rack roles
  399. #
  400. class RackRoleListView(generic.ObjectListView):
  401. queryset = RackRole.objects.annotate(
  402. rack_count=count_related(Rack, 'role')
  403. )
  404. filterset = filtersets.RackRoleFilterSet
  405. filterset_form = forms.RackRoleFilterForm
  406. table = tables.RackRoleTable
  407. class RackRoleView(generic.ObjectView):
  408. queryset = RackRole.objects.all()
  409. def get_extra_context(self, request, instance):
  410. racks = Rack.objects.restrict(request.user, 'view').filter(role=instance).annotate(
  411. device_count=count_related(Device, 'rack')
  412. )
  413. racks_table = tables.RackTable(racks, user=request.user, exclude=(
  414. 'role', 'get_utilization', 'get_power_utilization',
  415. ))
  416. racks_table.configure(request)
  417. return {
  418. 'racks_table': racks_table,
  419. }
  420. class RackRoleEditView(generic.ObjectEditView):
  421. queryset = RackRole.objects.all()
  422. form = forms.RackRoleForm
  423. class RackRoleDeleteView(generic.ObjectDeleteView):
  424. queryset = RackRole.objects.all()
  425. class RackRoleBulkImportView(generic.BulkImportView):
  426. queryset = RackRole.objects.all()
  427. model_form = forms.RackRoleCSVForm
  428. table = tables.RackRoleTable
  429. class RackRoleBulkEditView(generic.BulkEditView):
  430. queryset = RackRole.objects.annotate(
  431. rack_count=count_related(Rack, 'role')
  432. )
  433. filterset = filtersets.RackRoleFilterSet
  434. table = tables.RackRoleTable
  435. form = forms.RackRoleBulkEditForm
  436. class RackRoleBulkDeleteView(generic.BulkDeleteView):
  437. queryset = RackRole.objects.annotate(
  438. rack_count=count_related(Rack, 'role')
  439. )
  440. table = tables.RackRoleTable
  441. #
  442. # Racks
  443. #
  444. class RackListView(generic.ObjectListView):
  445. queryset = Rack.objects.annotate(
  446. device_count=count_related(Device, 'rack')
  447. )
  448. filterset = filtersets.RackFilterSet
  449. filterset_form = forms.RackFilterForm
  450. table = tables.RackTable
  451. class RackElevationListView(generic.ObjectListView):
  452. """
  453. Display a set of rack elevations side-by-side.
  454. """
  455. queryset = Rack.objects.prefetch_related('role')
  456. def get(self, request):
  457. racks = filtersets.RackFilterSet(request.GET, self.queryset).qs
  458. total_count = racks.count()
  459. ORDERING_CHOICES = {
  460. 'name': 'Name (A-Z)',
  461. '-name': 'Name (Z-A)',
  462. 'facility_id': 'Facility ID (A-Z)',
  463. '-facility_id': 'Facility ID (Z-A)',
  464. }
  465. sort = request.GET.get('sort', "name")
  466. if sort not in ORDERING_CHOICES:
  467. sort = 'name'
  468. sort_choice = sort
  469. sort = sort.replace("name", "_name")
  470. racks = racks.order_by(sort)
  471. # Pagination
  472. per_page = get_paginate_count(request)
  473. page_number = request.GET.get('page', 1)
  474. paginator = EnhancedPaginator(racks, per_page)
  475. try:
  476. page = paginator.page(page_number)
  477. except PageNotAnInteger:
  478. page = paginator.page(1)
  479. except EmptyPage:
  480. page = paginator.page(paginator.num_pages)
  481. # Determine rack face
  482. rack_face = request.GET.get('face', DeviceFaceChoices.FACE_FRONT)
  483. if rack_face not in DeviceFaceChoices.values():
  484. rack_face = DeviceFaceChoices.FACE_FRONT
  485. return render(request, 'dcim/rack_elevation_list.html', {
  486. 'paginator': paginator,
  487. 'page': page,
  488. 'total_count': total_count,
  489. 'sort': sort,
  490. 'sort_display_name': ORDERING_CHOICES[sort_choice],
  491. 'sort_choices': ORDERING_CHOICES,
  492. 'rack_face': rack_face,
  493. 'filter_form': forms.RackElevationFilterForm(request.GET),
  494. })
  495. class RackView(generic.ObjectView):
  496. queryset = Rack.objects.prefetch_related('site__region', 'tenant__group', 'location', 'role')
  497. def get_extra_context(self, request, instance):
  498. # Get 0U devices located within the rack
  499. nonracked_devices = Device.objects.filter(
  500. rack=instance,
  501. position__isnull=True,
  502. parent_bay__isnull=True
  503. ).prefetch_related('device_type__manufacturer', 'parent_bay', 'device_role')
  504. peer_racks = Rack.objects.restrict(request.user, 'view').filter(site=instance.site)
  505. if instance.location:
  506. peer_racks = peer_racks.filter(location=instance.location)
  507. else:
  508. peer_racks = peer_racks.filter(location__isnull=True)
  509. next_rack = peer_racks.filter(_name__gt=instance._name).first()
  510. prev_rack = peer_racks.filter(_name__lt=instance._name).reverse().first()
  511. reservations = RackReservation.objects.restrict(request.user, 'view').filter(rack=instance)
  512. power_feeds = PowerFeed.objects.restrict(request.user, 'view').filter(rack=instance).prefetch_related(
  513. 'power_panel'
  514. )
  515. device_count = Device.objects.restrict(request.user, 'view').filter(rack=instance).count()
  516. # Determine any additional parameters to pass when embedding the rack elevations
  517. svg_extra = '&'.join([
  518. f'highlight=id:{pk}' for pk in request.GET.getlist('device')
  519. ])
  520. return {
  521. 'device_count': device_count,
  522. 'reservations': reservations,
  523. 'power_feeds': power_feeds,
  524. 'nonracked_devices': nonracked_devices,
  525. 'next_rack': next_rack,
  526. 'prev_rack': prev_rack,
  527. 'svg_extra': svg_extra,
  528. }
  529. class RackEditView(generic.ObjectEditView):
  530. queryset = Rack.objects.all()
  531. form = forms.RackForm
  532. template_name = 'dcim/rack_edit.html'
  533. class RackDeleteView(generic.ObjectDeleteView):
  534. queryset = Rack.objects.all()
  535. class RackBulkImportView(generic.BulkImportView):
  536. queryset = Rack.objects.all()
  537. model_form = forms.RackCSVForm
  538. table = tables.RackTable
  539. class RackBulkEditView(generic.BulkEditView):
  540. queryset = Rack.objects.all()
  541. filterset = filtersets.RackFilterSet
  542. table = tables.RackTable
  543. form = forms.RackBulkEditForm
  544. class RackBulkDeleteView(generic.BulkDeleteView):
  545. queryset = Rack.objects.all()
  546. filterset = filtersets.RackFilterSet
  547. table = tables.RackTable
  548. #
  549. # Rack reservations
  550. #
  551. class RackReservationListView(generic.ObjectListView):
  552. queryset = RackReservation.objects.all()
  553. filterset = filtersets.RackReservationFilterSet
  554. filterset_form = forms.RackReservationFilterForm
  555. table = tables.RackReservationTable
  556. class RackReservationView(generic.ObjectView):
  557. queryset = RackReservation.objects.all()
  558. class RackReservationEditView(generic.ObjectEditView):
  559. queryset = RackReservation.objects.all()
  560. form = forms.RackReservationForm
  561. def alter_object(self, obj, request, args, kwargs):
  562. if not obj.pk:
  563. if 'rack' in request.GET:
  564. obj.rack = get_object_or_404(Rack, pk=request.GET.get('rack'))
  565. obj.user = request.user
  566. return obj
  567. class RackReservationDeleteView(generic.ObjectDeleteView):
  568. queryset = RackReservation.objects.all()
  569. class RackReservationImportView(generic.BulkImportView):
  570. queryset = RackReservation.objects.all()
  571. model_form = forms.RackReservationCSVForm
  572. table = tables.RackReservationTable
  573. def _save_obj(self, obj_form, request):
  574. """
  575. Assign the currently authenticated user to the RackReservation.
  576. """
  577. instance = obj_form.save(commit=False)
  578. instance.user = request.user
  579. instance.save()
  580. return instance
  581. class RackReservationBulkEditView(generic.BulkEditView):
  582. queryset = RackReservation.objects.all()
  583. filterset = filtersets.RackReservationFilterSet
  584. table = tables.RackReservationTable
  585. form = forms.RackReservationBulkEditForm
  586. class RackReservationBulkDeleteView(generic.BulkDeleteView):
  587. queryset = RackReservation.objects.all()
  588. filterset = filtersets.RackReservationFilterSet
  589. table = tables.RackReservationTable
  590. #
  591. # Manufacturers
  592. #
  593. class ManufacturerListView(generic.ObjectListView):
  594. queryset = Manufacturer.objects.annotate(
  595. devicetype_count=count_related(DeviceType, 'manufacturer'),
  596. inventoryitem_count=count_related(InventoryItem, 'manufacturer'),
  597. platform_count=count_related(Platform, 'manufacturer')
  598. )
  599. filterset = filtersets.ManufacturerFilterSet
  600. filterset_form = forms.ManufacturerFilterForm
  601. table = tables.ManufacturerTable
  602. class ManufacturerView(generic.ObjectView):
  603. queryset = Manufacturer.objects.all()
  604. def get_extra_context(self, request, instance):
  605. device_types = DeviceType.objects.restrict(request.user, 'view').filter(
  606. manufacturer=instance
  607. ).annotate(
  608. instance_count=count_related(Device, 'device_type')
  609. )
  610. module_types = ModuleType.objects.restrict(request.user, 'view').filter(
  611. manufacturer=instance
  612. )
  613. inventory_items = InventoryItem.objects.restrict(request.user, 'view').filter(
  614. manufacturer=instance
  615. )
  616. devicetypes_table = tables.DeviceTypeTable(device_types, user=request.user, exclude=('manufacturer',))
  617. devicetypes_table.configure(request)
  618. return {
  619. 'devicetypes_table': devicetypes_table,
  620. 'inventory_item_count': inventory_items.count(),
  621. 'module_type_count': module_types.count(),
  622. }
  623. class ManufacturerEditView(generic.ObjectEditView):
  624. queryset = Manufacturer.objects.all()
  625. form = forms.ManufacturerForm
  626. class ManufacturerDeleteView(generic.ObjectDeleteView):
  627. queryset = Manufacturer.objects.all()
  628. class ManufacturerBulkImportView(generic.BulkImportView):
  629. queryset = Manufacturer.objects.all()
  630. model_form = forms.ManufacturerCSVForm
  631. table = tables.ManufacturerTable
  632. class ManufacturerBulkEditView(generic.BulkEditView):
  633. queryset = Manufacturer.objects.annotate(
  634. devicetype_count=count_related(DeviceType, 'manufacturer')
  635. )
  636. filterset = filtersets.ManufacturerFilterSet
  637. table = tables.ManufacturerTable
  638. form = forms.ManufacturerBulkEditForm
  639. class ManufacturerBulkDeleteView(generic.BulkDeleteView):
  640. queryset = Manufacturer.objects.annotate(
  641. devicetype_count=count_related(DeviceType, 'manufacturer')
  642. )
  643. table = tables.ManufacturerTable
  644. #
  645. # Device types
  646. #
  647. class DeviceTypeListView(generic.ObjectListView):
  648. queryset = DeviceType.objects.annotate(
  649. instance_count=count_related(Device, 'device_type')
  650. )
  651. filterset = filtersets.DeviceTypeFilterSet
  652. filterset_form = forms.DeviceTypeFilterForm
  653. table = tables.DeviceTypeTable
  654. class DeviceTypeView(generic.ObjectView):
  655. queryset = DeviceType.objects.all()
  656. def get_extra_context(self, request, instance):
  657. instance_count = Device.objects.restrict(request.user).filter(device_type=instance).count()
  658. return {
  659. 'instance_count': instance_count,
  660. }
  661. class DeviceTypeConsolePortsView(DeviceTypeComponentsView):
  662. child_model = ConsolePortTemplate
  663. table = tables.ConsolePortTemplateTable
  664. filterset = filtersets.ConsolePortTemplateFilterSet
  665. viewname = 'dcim:devicetype_consoleports'
  666. class DeviceTypeConsoleServerPortsView(DeviceTypeComponentsView):
  667. child_model = ConsoleServerPortTemplate
  668. table = tables.ConsoleServerPortTemplateTable
  669. filterset = filtersets.ConsoleServerPortTemplateFilterSet
  670. viewname = 'dcim:devicetype_consoleserverports'
  671. class DeviceTypePowerPortsView(DeviceTypeComponentsView):
  672. child_model = PowerPortTemplate
  673. table = tables.PowerPortTemplateTable
  674. filterset = filtersets.PowerPortTemplateFilterSet
  675. viewname = 'dcim:devicetype_powerports'
  676. class DeviceTypePowerOutletsView(DeviceTypeComponentsView):
  677. child_model = PowerOutletTemplate
  678. table = tables.PowerOutletTemplateTable
  679. filterset = filtersets.PowerOutletTemplateFilterSet
  680. viewname = 'dcim:devicetype_poweroutlets'
  681. class DeviceTypeInterfacesView(DeviceTypeComponentsView):
  682. child_model = InterfaceTemplate
  683. table = tables.InterfaceTemplateTable
  684. filterset = filtersets.InterfaceTemplateFilterSet
  685. viewname = 'dcim:devicetype_interfaces'
  686. class DeviceTypeFrontPortsView(DeviceTypeComponentsView):
  687. child_model = FrontPortTemplate
  688. table = tables.FrontPortTemplateTable
  689. filterset = filtersets.FrontPortTemplateFilterSet
  690. viewname = 'dcim:devicetype_frontports'
  691. class DeviceTypeRearPortsView(DeviceTypeComponentsView):
  692. child_model = RearPortTemplate
  693. table = tables.RearPortTemplateTable
  694. filterset = filtersets.RearPortTemplateFilterSet
  695. viewname = 'dcim:devicetype_rearports'
  696. class DeviceTypeModuleBaysView(DeviceTypeComponentsView):
  697. child_model = ModuleBayTemplate
  698. table = tables.ModuleBayTemplateTable
  699. filterset = filtersets.ModuleBayTemplateFilterSet
  700. viewname = 'dcim:devicetype_modulebays'
  701. class DeviceTypeDeviceBaysView(DeviceTypeComponentsView):
  702. child_model = DeviceBayTemplate
  703. table = tables.DeviceBayTemplateTable
  704. filterset = filtersets.DeviceBayTemplateFilterSet
  705. viewname = 'dcim:devicetype_devicebays'
  706. class DeviceTypeInventoryItemsView(DeviceTypeComponentsView):
  707. child_model = InventoryItemTemplate
  708. table = tables.InventoryItemTemplateTable
  709. filterset = filtersets.InventoryItemTemplateFilterSet
  710. viewname = 'dcim:devicetype_inventoryitems'
  711. class DeviceTypeEditView(generic.ObjectEditView):
  712. queryset = DeviceType.objects.all()
  713. form = forms.DeviceTypeForm
  714. class DeviceTypeDeleteView(generic.ObjectDeleteView):
  715. queryset = DeviceType.objects.all()
  716. class DeviceTypeImportView(generic.ObjectImportView):
  717. additional_permissions = [
  718. 'dcim.add_devicetype',
  719. 'dcim.add_consoleporttemplate',
  720. 'dcim.add_consoleserverporttemplate',
  721. 'dcim.add_powerporttemplate',
  722. 'dcim.add_poweroutlettemplate',
  723. 'dcim.add_interfacetemplate',
  724. 'dcim.add_frontporttemplate',
  725. 'dcim.add_rearporttemplate',
  726. 'dcim.add_modulebaytemplate',
  727. 'dcim.add_devicebaytemplate',
  728. 'dcim.add_inventoryitemtemplate',
  729. ]
  730. queryset = DeviceType.objects.all()
  731. model_form = forms.DeviceTypeImportForm
  732. related_object_forms = {
  733. 'console-ports': forms.ConsolePortTemplateImportForm,
  734. 'console-server-ports': forms.ConsoleServerPortTemplateImportForm,
  735. 'power-ports': forms.PowerPortTemplateImportForm,
  736. 'power-outlets': forms.PowerOutletTemplateImportForm,
  737. 'interfaces': forms.InterfaceTemplateImportForm,
  738. 'rear-ports': forms.RearPortTemplateImportForm,
  739. 'front-ports': forms.FrontPortTemplateImportForm,
  740. 'module-bays': forms.ModuleBayTemplateImportForm,
  741. 'device-bays': forms.DeviceBayTemplateImportForm,
  742. 'inventory-items': forms.InventoryItemTemplateImportForm,
  743. }
  744. def prep_related_object_data(self, parent, data):
  745. data.update({'device_type': parent})
  746. return data
  747. class DeviceTypeBulkEditView(generic.BulkEditView):
  748. queryset = DeviceType.objects.annotate(
  749. instance_count=count_related(Device, 'device_type')
  750. )
  751. filterset = filtersets.DeviceTypeFilterSet
  752. table = tables.DeviceTypeTable
  753. form = forms.DeviceTypeBulkEditForm
  754. class DeviceTypeBulkDeleteView(generic.BulkDeleteView):
  755. queryset = DeviceType.objects.annotate(
  756. instance_count=count_related(Device, 'device_type')
  757. )
  758. filterset = filtersets.DeviceTypeFilterSet
  759. table = tables.DeviceTypeTable
  760. #
  761. # Module types
  762. #
  763. class ModuleTypeListView(generic.ObjectListView):
  764. queryset = ModuleType.objects.annotate(
  765. instance_count=count_related(Module, 'module_type')
  766. )
  767. filterset = filtersets.ModuleTypeFilterSet
  768. filterset_form = forms.ModuleTypeFilterForm
  769. table = tables.ModuleTypeTable
  770. class ModuleTypeView(generic.ObjectView):
  771. queryset = ModuleType.objects.all()
  772. def get_extra_context(self, request, instance):
  773. instance_count = Module.objects.restrict(request.user).filter(module_type=instance).count()
  774. return {
  775. 'instance_count': instance_count,
  776. }
  777. class ModuleTypeConsolePortsView(ModuleTypeComponentsView):
  778. child_model = ConsolePortTemplate
  779. table = tables.ConsolePortTemplateTable
  780. filterset = filtersets.ConsolePortTemplateFilterSet
  781. viewname = 'dcim:moduletype_consoleports'
  782. class ModuleTypeConsoleServerPortsView(ModuleTypeComponentsView):
  783. child_model = ConsoleServerPortTemplate
  784. table = tables.ConsoleServerPortTemplateTable
  785. filterset = filtersets.ConsoleServerPortTemplateFilterSet
  786. viewname = 'dcim:moduletype_consoleserverports'
  787. class ModuleTypePowerPortsView(ModuleTypeComponentsView):
  788. child_model = PowerPortTemplate
  789. table = tables.PowerPortTemplateTable
  790. filterset = filtersets.PowerPortTemplateFilterSet
  791. viewname = 'dcim:moduletype_powerports'
  792. class ModuleTypePowerOutletsView(ModuleTypeComponentsView):
  793. child_model = PowerOutletTemplate
  794. table = tables.PowerOutletTemplateTable
  795. filterset = filtersets.PowerOutletTemplateFilterSet
  796. viewname = 'dcim:moduletype_poweroutlets'
  797. class ModuleTypeInterfacesView(ModuleTypeComponentsView):
  798. child_model = InterfaceTemplate
  799. table = tables.InterfaceTemplateTable
  800. filterset = filtersets.InterfaceTemplateFilterSet
  801. viewname = 'dcim:moduletype_interfaces'
  802. class ModuleTypeFrontPortsView(ModuleTypeComponentsView):
  803. child_model = FrontPortTemplate
  804. table = tables.FrontPortTemplateTable
  805. filterset = filtersets.FrontPortTemplateFilterSet
  806. viewname = 'dcim:moduletype_frontports'
  807. class ModuleTypeRearPortsView(ModuleTypeComponentsView):
  808. child_model = RearPortTemplate
  809. table = tables.RearPortTemplateTable
  810. filterset = filtersets.RearPortTemplateFilterSet
  811. viewname = 'dcim:moduletype_rearports'
  812. class ModuleTypeEditView(generic.ObjectEditView):
  813. queryset = ModuleType.objects.all()
  814. form = forms.ModuleTypeForm
  815. class ModuleTypeDeleteView(generic.ObjectDeleteView):
  816. queryset = ModuleType.objects.all()
  817. class ModuleTypeImportView(generic.ObjectImportView):
  818. additional_permissions = [
  819. 'dcim.add_moduletype',
  820. 'dcim.add_consoleporttemplate',
  821. 'dcim.add_consoleserverporttemplate',
  822. 'dcim.add_powerporttemplate',
  823. 'dcim.add_poweroutlettemplate',
  824. 'dcim.add_interfacetemplate',
  825. 'dcim.add_frontporttemplate',
  826. 'dcim.add_rearporttemplate',
  827. ]
  828. queryset = ModuleType.objects.all()
  829. model_form = forms.ModuleTypeImportForm
  830. related_object_forms = {
  831. 'console-ports': forms.ConsolePortTemplateImportForm,
  832. 'console-server-ports': forms.ConsoleServerPortTemplateImportForm,
  833. 'power-ports': forms.PowerPortTemplateImportForm,
  834. 'power-outlets': forms.PowerOutletTemplateImportForm,
  835. 'interfaces': forms.InterfaceTemplateImportForm,
  836. 'rear-ports': forms.RearPortTemplateImportForm,
  837. 'front-ports': forms.FrontPortTemplateImportForm,
  838. }
  839. def prep_related_object_data(self, parent, data):
  840. data.update({'module_type': parent})
  841. return data
  842. class ModuleTypeBulkEditView(generic.BulkEditView):
  843. queryset = ModuleType.objects.annotate(
  844. instance_count=count_related(Module, 'module_type')
  845. )
  846. filterset = filtersets.ModuleTypeFilterSet
  847. table = tables.ModuleTypeTable
  848. form = forms.ModuleTypeBulkEditForm
  849. class ModuleTypeBulkDeleteView(generic.BulkDeleteView):
  850. queryset = ModuleType.objects.annotate(
  851. instance_count=count_related(Module, 'module_type')
  852. )
  853. filterset = filtersets.ModuleTypeFilterSet
  854. table = tables.ModuleTypeTable
  855. #
  856. # Console port templates
  857. #
  858. class ConsolePortTemplateCreateView(generic.ComponentCreateView):
  859. queryset = ConsolePortTemplate.objects.all()
  860. form = forms.ConsolePortTemplateCreateForm
  861. model_form = forms.ConsolePortTemplateForm
  862. class ConsolePortTemplateEditView(generic.ObjectEditView):
  863. queryset = ConsolePortTemplate.objects.all()
  864. form = forms.ConsolePortTemplateForm
  865. class ConsolePortTemplateDeleteView(generic.ObjectDeleteView):
  866. queryset = ConsolePortTemplate.objects.all()
  867. class ConsolePortTemplateBulkEditView(generic.BulkEditView):
  868. queryset = ConsolePortTemplate.objects.all()
  869. table = tables.ConsolePortTemplateTable
  870. form = forms.ConsolePortTemplateBulkEditForm
  871. class ConsolePortTemplateBulkRenameView(generic.BulkRenameView):
  872. queryset = ConsolePortTemplate.objects.all()
  873. class ConsolePortTemplateBulkDeleteView(generic.BulkDeleteView):
  874. queryset = ConsolePortTemplate.objects.all()
  875. table = tables.ConsolePortTemplateTable
  876. #
  877. # Console server port templates
  878. #
  879. class ConsoleServerPortTemplateCreateView(generic.ComponentCreateView):
  880. queryset = ConsoleServerPortTemplate.objects.all()
  881. form = forms.ConsoleServerPortTemplateCreateForm
  882. model_form = forms.ConsoleServerPortTemplateForm
  883. class ConsoleServerPortTemplateEditView(generic.ObjectEditView):
  884. queryset = ConsoleServerPortTemplate.objects.all()
  885. form = forms.ConsoleServerPortTemplateForm
  886. class ConsoleServerPortTemplateDeleteView(generic.ObjectDeleteView):
  887. queryset = ConsoleServerPortTemplate.objects.all()
  888. class ConsoleServerPortTemplateBulkEditView(generic.BulkEditView):
  889. queryset = ConsoleServerPortTemplate.objects.all()
  890. table = tables.ConsoleServerPortTemplateTable
  891. form = forms.ConsoleServerPortTemplateBulkEditForm
  892. class ConsoleServerPortTemplateBulkRenameView(generic.BulkRenameView):
  893. queryset = ConsoleServerPortTemplate.objects.all()
  894. class ConsoleServerPortTemplateBulkDeleteView(generic.BulkDeleteView):
  895. queryset = ConsoleServerPortTemplate.objects.all()
  896. table = tables.ConsoleServerPortTemplateTable
  897. #
  898. # Power port templates
  899. #
  900. class PowerPortTemplateCreateView(generic.ComponentCreateView):
  901. queryset = PowerPortTemplate.objects.all()
  902. form = forms.PowerPortTemplateCreateForm
  903. model_form = forms.PowerPortTemplateForm
  904. class PowerPortTemplateEditView(generic.ObjectEditView):
  905. queryset = PowerPortTemplate.objects.all()
  906. form = forms.PowerPortTemplateForm
  907. class PowerPortTemplateDeleteView(generic.ObjectDeleteView):
  908. queryset = PowerPortTemplate.objects.all()
  909. class PowerPortTemplateBulkEditView(generic.BulkEditView):
  910. queryset = PowerPortTemplate.objects.all()
  911. table = tables.PowerPortTemplateTable
  912. form = forms.PowerPortTemplateBulkEditForm
  913. class PowerPortTemplateBulkRenameView(generic.BulkRenameView):
  914. queryset = PowerPortTemplate.objects.all()
  915. class PowerPortTemplateBulkDeleteView(generic.BulkDeleteView):
  916. queryset = PowerPortTemplate.objects.all()
  917. table = tables.PowerPortTemplateTable
  918. #
  919. # Power outlet templates
  920. #
  921. class PowerOutletTemplateCreateView(generic.ComponentCreateView):
  922. queryset = PowerOutletTemplate.objects.all()
  923. form = forms.PowerOutletTemplateCreateForm
  924. model_form = forms.PowerOutletTemplateForm
  925. class PowerOutletTemplateEditView(generic.ObjectEditView):
  926. queryset = PowerOutletTemplate.objects.all()
  927. form = forms.PowerOutletTemplateForm
  928. class PowerOutletTemplateDeleteView(generic.ObjectDeleteView):
  929. queryset = PowerOutletTemplate.objects.all()
  930. class PowerOutletTemplateBulkEditView(generic.BulkEditView):
  931. queryset = PowerOutletTemplate.objects.all()
  932. table = tables.PowerOutletTemplateTable
  933. form = forms.PowerOutletTemplateBulkEditForm
  934. class PowerOutletTemplateBulkRenameView(generic.BulkRenameView):
  935. queryset = PowerOutletTemplate.objects.all()
  936. class PowerOutletTemplateBulkDeleteView(generic.BulkDeleteView):
  937. queryset = PowerOutletTemplate.objects.all()
  938. table = tables.PowerOutletTemplateTable
  939. #
  940. # Interface templates
  941. #
  942. class InterfaceTemplateCreateView(generic.ComponentCreateView):
  943. queryset = InterfaceTemplate.objects.all()
  944. form = forms.InterfaceTemplateCreateForm
  945. model_form = forms.InterfaceTemplateForm
  946. class InterfaceTemplateEditView(generic.ObjectEditView):
  947. queryset = InterfaceTemplate.objects.all()
  948. form = forms.InterfaceTemplateForm
  949. class InterfaceTemplateDeleteView(generic.ObjectDeleteView):
  950. queryset = InterfaceTemplate.objects.all()
  951. class InterfaceTemplateBulkEditView(generic.BulkEditView):
  952. queryset = InterfaceTemplate.objects.all()
  953. table = tables.InterfaceTemplateTable
  954. form = forms.InterfaceTemplateBulkEditForm
  955. class InterfaceTemplateBulkRenameView(generic.BulkRenameView):
  956. queryset = InterfaceTemplate.objects.all()
  957. class InterfaceTemplateBulkDeleteView(generic.BulkDeleteView):
  958. queryset = InterfaceTemplate.objects.all()
  959. table = tables.InterfaceTemplateTable
  960. #
  961. # Front port templates
  962. #
  963. class FrontPortTemplateCreateView(generic.ComponentCreateView):
  964. queryset = FrontPortTemplate.objects.all()
  965. form = forms.FrontPortTemplateCreateForm
  966. model_form = forms.FrontPortTemplateForm
  967. class FrontPortTemplateEditView(generic.ObjectEditView):
  968. queryset = FrontPortTemplate.objects.all()
  969. form = forms.FrontPortTemplateForm
  970. class FrontPortTemplateDeleteView(generic.ObjectDeleteView):
  971. queryset = FrontPortTemplate.objects.all()
  972. class FrontPortTemplateBulkEditView(generic.BulkEditView):
  973. queryset = FrontPortTemplate.objects.all()
  974. table = tables.FrontPortTemplateTable
  975. form = forms.FrontPortTemplateBulkEditForm
  976. class FrontPortTemplateBulkRenameView(generic.BulkRenameView):
  977. queryset = FrontPortTemplate.objects.all()
  978. class FrontPortTemplateBulkDeleteView(generic.BulkDeleteView):
  979. queryset = FrontPortTemplate.objects.all()
  980. table = tables.FrontPortTemplateTable
  981. #
  982. # Rear port templates
  983. #
  984. class RearPortTemplateCreateView(generic.ComponentCreateView):
  985. queryset = RearPortTemplate.objects.all()
  986. form = forms.RearPortTemplateCreateForm
  987. model_form = forms.RearPortTemplateForm
  988. class RearPortTemplateEditView(generic.ObjectEditView):
  989. queryset = RearPortTemplate.objects.all()
  990. form = forms.RearPortTemplateForm
  991. class RearPortTemplateDeleteView(generic.ObjectDeleteView):
  992. queryset = RearPortTemplate.objects.all()
  993. class RearPortTemplateBulkEditView(generic.BulkEditView):
  994. queryset = RearPortTemplate.objects.all()
  995. table = tables.RearPortTemplateTable
  996. form = forms.RearPortTemplateBulkEditForm
  997. class RearPortTemplateBulkRenameView(generic.BulkRenameView):
  998. queryset = RearPortTemplate.objects.all()
  999. class RearPortTemplateBulkDeleteView(generic.BulkDeleteView):
  1000. queryset = RearPortTemplate.objects.all()
  1001. table = tables.RearPortTemplateTable
  1002. #
  1003. # Module bay templates
  1004. #
  1005. class ModuleBayTemplateCreateView(generic.ComponentCreateView):
  1006. queryset = ModuleBayTemplate.objects.all()
  1007. form = forms.ModuleBayTemplateCreateForm
  1008. model_form = forms.ModuleBayTemplateForm
  1009. class ModuleBayTemplateEditView(generic.ObjectEditView):
  1010. queryset = ModuleBayTemplate.objects.all()
  1011. form = forms.ModuleBayTemplateForm
  1012. class ModuleBayTemplateDeleteView(generic.ObjectDeleteView):
  1013. queryset = ModuleBayTemplate.objects.all()
  1014. class ModuleBayTemplateBulkEditView(generic.BulkEditView):
  1015. queryset = ModuleBayTemplate.objects.all()
  1016. table = tables.ModuleBayTemplateTable
  1017. form = forms.ModuleBayTemplateBulkEditForm
  1018. class ModuleBayTemplateBulkRenameView(generic.BulkRenameView):
  1019. queryset = ModuleBayTemplate.objects.all()
  1020. class ModuleBayTemplateBulkDeleteView(generic.BulkDeleteView):
  1021. queryset = ModuleBayTemplate.objects.all()
  1022. table = tables.ModuleBayTemplateTable
  1023. #
  1024. # Device bay templates
  1025. #
  1026. class DeviceBayTemplateCreateView(generic.ComponentCreateView):
  1027. queryset = DeviceBayTemplate.objects.all()
  1028. form = forms.DeviceBayTemplateCreateForm
  1029. model_form = forms.DeviceBayTemplateForm
  1030. class DeviceBayTemplateEditView(generic.ObjectEditView):
  1031. queryset = DeviceBayTemplate.objects.all()
  1032. form = forms.DeviceBayTemplateForm
  1033. class DeviceBayTemplateDeleteView(generic.ObjectDeleteView):
  1034. queryset = DeviceBayTemplate.objects.all()
  1035. class DeviceBayTemplateBulkEditView(generic.BulkEditView):
  1036. queryset = DeviceBayTemplate.objects.all()
  1037. table = tables.DeviceBayTemplateTable
  1038. form = forms.DeviceBayTemplateBulkEditForm
  1039. class DeviceBayTemplateBulkRenameView(generic.BulkRenameView):
  1040. queryset = DeviceBayTemplate.objects.all()
  1041. class DeviceBayTemplateBulkDeleteView(generic.BulkDeleteView):
  1042. queryset = DeviceBayTemplate.objects.all()
  1043. table = tables.DeviceBayTemplateTable
  1044. #
  1045. # Inventory item templates
  1046. #
  1047. class InventoryItemTemplateCreateView(generic.ComponentCreateView):
  1048. queryset = InventoryItemTemplate.objects.all()
  1049. form = forms.InventoryItemTemplateCreateForm
  1050. model_form = forms.InventoryItemTemplateForm
  1051. def alter_object(self, instance, request):
  1052. # Set component (if any)
  1053. component_type = request.GET.get('component_type')
  1054. component_id = request.GET.get('component_id')
  1055. if component_type and component_id:
  1056. content_type = get_object_or_404(ContentType, pk=component_type)
  1057. instance.component = get_object_or_404(content_type.model_class(), pk=component_id)
  1058. return instance
  1059. class InventoryItemTemplateEditView(generic.ObjectEditView):
  1060. queryset = InventoryItemTemplate.objects.all()
  1061. form = forms.InventoryItemTemplateForm
  1062. class InventoryItemTemplateDeleteView(generic.ObjectDeleteView):
  1063. queryset = InventoryItemTemplate.objects.all()
  1064. class InventoryItemTemplateBulkEditView(generic.BulkEditView):
  1065. queryset = InventoryItemTemplate.objects.all()
  1066. table = tables.InventoryItemTemplateTable
  1067. form = forms.InventoryItemTemplateBulkEditForm
  1068. class InventoryItemTemplateBulkRenameView(generic.BulkRenameView):
  1069. queryset = InventoryItemTemplate.objects.all()
  1070. class InventoryItemTemplateBulkDeleteView(generic.BulkDeleteView):
  1071. queryset = InventoryItemTemplate.objects.all()
  1072. table = tables.InventoryItemTemplateTable
  1073. #
  1074. # Device roles
  1075. #
  1076. class DeviceRoleListView(generic.ObjectListView):
  1077. queryset = DeviceRole.objects.annotate(
  1078. device_count=count_related(Device, 'device_role'),
  1079. vm_count=count_related(VirtualMachine, 'role')
  1080. )
  1081. filterset = filtersets.DeviceRoleFilterSet
  1082. filterset_form = forms.DeviceRoleFilterForm
  1083. table = tables.DeviceRoleTable
  1084. class DeviceRoleView(generic.ObjectView):
  1085. queryset = DeviceRole.objects.all()
  1086. def get_extra_context(self, request, instance):
  1087. devices = Device.objects.restrict(request.user, 'view').filter(
  1088. device_role=instance
  1089. )
  1090. devices_table = tables.DeviceTable(devices, user=request.user, exclude=('device_role',))
  1091. devices_table.configure(request)
  1092. return {
  1093. 'devices_table': devices_table,
  1094. 'device_count': Device.objects.filter(device_role=instance).count(),
  1095. 'virtualmachine_count': VirtualMachine.objects.filter(role=instance).count(),
  1096. }
  1097. class DeviceRoleEditView(generic.ObjectEditView):
  1098. queryset = DeviceRole.objects.all()
  1099. form = forms.DeviceRoleForm
  1100. class DeviceRoleDeleteView(generic.ObjectDeleteView):
  1101. queryset = DeviceRole.objects.all()
  1102. class DeviceRoleBulkImportView(generic.BulkImportView):
  1103. queryset = DeviceRole.objects.all()
  1104. model_form = forms.DeviceRoleCSVForm
  1105. table = tables.DeviceRoleTable
  1106. class DeviceRoleBulkEditView(generic.BulkEditView):
  1107. queryset = DeviceRole.objects.annotate(
  1108. device_count=count_related(Device, 'device_role'),
  1109. vm_count=count_related(VirtualMachine, 'role')
  1110. )
  1111. filterset = filtersets.DeviceRoleFilterSet
  1112. table = tables.DeviceRoleTable
  1113. form = forms.DeviceRoleBulkEditForm
  1114. class DeviceRoleBulkDeleteView(generic.BulkDeleteView):
  1115. queryset = DeviceRole.objects.annotate(
  1116. device_count=count_related(Device, 'device_role'),
  1117. vm_count=count_related(VirtualMachine, 'role')
  1118. )
  1119. table = tables.DeviceRoleTable
  1120. #
  1121. # Platforms
  1122. #
  1123. class PlatformListView(generic.ObjectListView):
  1124. queryset = Platform.objects.annotate(
  1125. device_count=count_related(Device, 'platform'),
  1126. vm_count=count_related(VirtualMachine, 'platform')
  1127. )
  1128. table = tables.PlatformTable
  1129. filterset = filtersets.PlatformFilterSet
  1130. filterset_form = forms.PlatformFilterForm
  1131. class PlatformView(generic.ObjectView):
  1132. queryset = Platform.objects.all()
  1133. def get_extra_context(self, request, instance):
  1134. devices = Device.objects.restrict(request.user, 'view').filter(
  1135. platform=instance
  1136. )
  1137. devices_table = tables.DeviceTable(devices, user=request.user, exclude=('platform',))
  1138. devices_table.configure(request)
  1139. return {
  1140. 'devices_table': devices_table,
  1141. 'virtualmachine_count': VirtualMachine.objects.filter(platform=instance).count()
  1142. }
  1143. class PlatformEditView(generic.ObjectEditView):
  1144. queryset = Platform.objects.all()
  1145. form = forms.PlatformForm
  1146. class PlatformDeleteView(generic.ObjectDeleteView):
  1147. queryset = Platform.objects.all()
  1148. class PlatformBulkImportView(generic.BulkImportView):
  1149. queryset = Platform.objects.all()
  1150. model_form = forms.PlatformCSVForm
  1151. table = tables.PlatformTable
  1152. class PlatformBulkEditView(generic.BulkEditView):
  1153. queryset = Platform.objects.all()
  1154. filterset = filtersets.PlatformFilterSet
  1155. table = tables.PlatformTable
  1156. form = forms.PlatformBulkEditForm
  1157. class PlatformBulkDeleteView(generic.BulkDeleteView):
  1158. queryset = Platform.objects.all()
  1159. table = tables.PlatformTable
  1160. #
  1161. # Devices
  1162. #
  1163. class DeviceListView(generic.ObjectListView):
  1164. queryset = Device.objects.all()
  1165. filterset = filtersets.DeviceFilterSet
  1166. filterset_form = forms.DeviceFilterForm
  1167. table = tables.DeviceTable
  1168. template_name = 'dcim/device_list.html'
  1169. class DeviceView(generic.ObjectView):
  1170. queryset = Device.objects.all()
  1171. def get_extra_context(self, request, instance):
  1172. # VirtualChassis members
  1173. if instance.virtual_chassis is not None:
  1174. vc_members = Device.objects.restrict(request.user, 'view').filter(
  1175. virtual_chassis=instance.virtual_chassis
  1176. ).order_by('vc_position')
  1177. else:
  1178. vc_members = []
  1179. # Services
  1180. services = Service.objects.restrict(request.user, 'view').filter(device=instance)
  1181. return {
  1182. 'services': services,
  1183. 'vc_members': vc_members,
  1184. 'svg_extra': f'highlight=id:{instance.pk}'
  1185. }
  1186. class DeviceConsolePortsView(DeviceComponentsView):
  1187. child_model = ConsolePort
  1188. table = tables.DeviceConsolePortTable
  1189. filterset = filtersets.ConsolePortFilterSet
  1190. template_name = 'dcim/device/consoleports.html'
  1191. class DeviceConsoleServerPortsView(DeviceComponentsView):
  1192. child_model = ConsoleServerPort
  1193. table = tables.DeviceConsoleServerPortTable
  1194. filterset = filtersets.ConsoleServerPortFilterSet
  1195. template_name = 'dcim/device/consoleserverports.html'
  1196. class DevicePowerPortsView(DeviceComponentsView):
  1197. child_model = PowerPort
  1198. table = tables.DevicePowerPortTable
  1199. filterset = filtersets.PowerPortFilterSet
  1200. template_name = 'dcim/device/powerports.html'
  1201. class DevicePowerOutletsView(DeviceComponentsView):
  1202. child_model = PowerOutlet
  1203. table = tables.DevicePowerOutletTable
  1204. filterset = filtersets.PowerOutletFilterSet
  1205. template_name = 'dcim/device/poweroutlets.html'
  1206. class DeviceInterfacesView(DeviceComponentsView):
  1207. child_model = Interface
  1208. table = tables.DeviceInterfaceTable
  1209. filterset = filtersets.InterfaceFilterSet
  1210. template_name = 'dcim/device/interfaces.html'
  1211. def get_children(self, request, parent):
  1212. return parent.vc_interfaces().restrict(request.user, 'view').prefetch_related(
  1213. Prefetch('ip_addresses', queryset=IPAddress.objects.restrict(request.user)),
  1214. Prefetch('member_interfaces', queryset=Interface.objects.restrict(request.user))
  1215. )
  1216. class DeviceFrontPortsView(DeviceComponentsView):
  1217. child_model = FrontPort
  1218. table = tables.DeviceFrontPortTable
  1219. filterset = filtersets.FrontPortFilterSet
  1220. template_name = 'dcim/device/frontports.html'
  1221. class DeviceRearPortsView(DeviceComponentsView):
  1222. child_model = RearPort
  1223. table = tables.DeviceRearPortTable
  1224. filterset = filtersets.RearPortFilterSet
  1225. template_name = 'dcim/device/rearports.html'
  1226. class DeviceModuleBaysView(DeviceComponentsView):
  1227. child_model = ModuleBay
  1228. table = tables.DeviceModuleBayTable
  1229. filterset = filtersets.ModuleBayFilterSet
  1230. template_name = 'dcim/device/modulebays.html'
  1231. class DeviceDeviceBaysView(DeviceComponentsView):
  1232. child_model = DeviceBay
  1233. table = tables.DeviceDeviceBayTable
  1234. filterset = filtersets.DeviceBayFilterSet
  1235. template_name = 'dcim/device/devicebays.html'
  1236. class DeviceInventoryView(DeviceComponentsView):
  1237. child_model = InventoryItem
  1238. table = tables.DeviceInventoryItemTable
  1239. filterset = filtersets.InventoryItemFilterSet
  1240. template_name = 'dcim/device/inventory.html'
  1241. class DeviceStatusView(generic.ObjectView):
  1242. additional_permissions = ['dcim.napalm_read_device']
  1243. queryset = Device.objects.all()
  1244. template_name = 'dcim/device/status.html'
  1245. def get_extra_context(self, request, instance):
  1246. return {
  1247. 'active_tab': 'status',
  1248. }
  1249. class DeviceLLDPNeighborsView(generic.ObjectView):
  1250. additional_permissions = ['dcim.napalm_read_device']
  1251. queryset = Device.objects.all()
  1252. template_name = 'dcim/device/lldp_neighbors.html'
  1253. def get_extra_context(self, request, instance):
  1254. interfaces = instance.vc_interfaces().restrict(request.user, 'view').prefetch_related(
  1255. '_path'
  1256. ).exclude(
  1257. type__in=NONCONNECTABLE_IFACE_TYPES
  1258. )
  1259. return {
  1260. 'interfaces': interfaces,
  1261. 'active_tab': 'lldp-neighbors',
  1262. }
  1263. class DeviceConfigView(generic.ObjectView):
  1264. additional_permissions = ['dcim.napalm_read_device']
  1265. queryset = Device.objects.all()
  1266. template_name = 'dcim/device/config.html'
  1267. def get_extra_context(self, request, instance):
  1268. return {
  1269. 'active_tab': 'config',
  1270. }
  1271. class DeviceConfigContextView(ObjectConfigContextView):
  1272. queryset = Device.objects.annotate_config_context_data()
  1273. base_template = 'dcim/device/base.html'
  1274. class DeviceEditView(generic.ObjectEditView):
  1275. queryset = Device.objects.all()
  1276. form = forms.DeviceForm
  1277. template_name = 'dcim/device_edit.html'
  1278. class DeviceDeleteView(generic.ObjectDeleteView):
  1279. queryset = Device.objects.all()
  1280. class DeviceBulkImportView(generic.BulkImportView):
  1281. queryset = Device.objects.all()
  1282. model_form = forms.DeviceCSVForm
  1283. table = tables.DeviceImportTable
  1284. template_name = 'dcim/device_import.html'
  1285. class ChildDeviceBulkImportView(generic.BulkImportView):
  1286. queryset = Device.objects.all()
  1287. model_form = forms.ChildDeviceCSVForm
  1288. table = tables.DeviceImportTable
  1289. template_name = 'dcim/device_import_child.html'
  1290. def _save_obj(self, obj_form, request):
  1291. obj = obj_form.save()
  1292. # Save the reverse relation to the parent device bay
  1293. device_bay = obj.parent_bay
  1294. device_bay.installed_device = obj
  1295. device_bay.save()
  1296. return obj
  1297. class DeviceBulkEditView(generic.BulkEditView):
  1298. queryset = Device.objects.prefetch_related('device_type__manufacturer')
  1299. filterset = filtersets.DeviceFilterSet
  1300. table = tables.DeviceTable
  1301. form = forms.DeviceBulkEditForm
  1302. class DeviceBulkDeleteView(generic.BulkDeleteView):
  1303. queryset = Device.objects.prefetch_related('device_type__manufacturer')
  1304. filterset = filtersets.DeviceFilterSet
  1305. table = tables.DeviceTable
  1306. class DeviceBulkRenameView(generic.BulkRenameView):
  1307. queryset = Device.objects.all()
  1308. filterset = filtersets.DeviceFilterSet
  1309. table = tables.DeviceTable
  1310. #
  1311. # Devices
  1312. #
  1313. class ModuleListView(generic.ObjectListView):
  1314. queryset = Module.objects.prefetch_related('module_type__manufacturer')
  1315. filterset = filtersets.ModuleFilterSet
  1316. filterset_form = forms.ModuleFilterForm
  1317. table = tables.ModuleTable
  1318. class ModuleView(generic.ObjectView):
  1319. queryset = Module.objects.all()
  1320. class ModuleEditView(generic.ObjectEditView):
  1321. queryset = Module.objects.all()
  1322. form = forms.ModuleForm
  1323. class ModuleDeleteView(generic.ObjectDeleteView):
  1324. queryset = Module.objects.all()
  1325. class ModuleBulkImportView(generic.BulkImportView):
  1326. queryset = Module.objects.all()
  1327. model_form = forms.ModuleCSVForm
  1328. table = tables.ModuleTable
  1329. class ModuleBulkEditView(generic.BulkEditView):
  1330. queryset = Module.objects.prefetch_related('module_type__manufacturer')
  1331. filterset = filtersets.ModuleFilterSet
  1332. table = tables.ModuleTable
  1333. form = forms.ModuleBulkEditForm
  1334. class ModuleBulkDeleteView(generic.BulkDeleteView):
  1335. queryset = Module.objects.prefetch_related('module_type__manufacturer')
  1336. filterset = filtersets.ModuleFilterSet
  1337. table = tables.ModuleTable
  1338. #
  1339. # Console ports
  1340. #
  1341. class ConsolePortListView(generic.ObjectListView):
  1342. queryset = ConsolePort.objects.all()
  1343. filterset = filtersets.ConsolePortFilterSet
  1344. filterset_form = forms.ConsolePortFilterForm
  1345. table = tables.ConsolePortTable
  1346. actions = ('import', 'export', 'bulk_edit', 'bulk_delete')
  1347. class ConsolePortView(generic.ObjectView):
  1348. queryset = ConsolePort.objects.all()
  1349. class ConsolePortCreateView(generic.ComponentCreateView):
  1350. queryset = ConsolePort.objects.all()
  1351. form = forms.ConsolePortCreateForm
  1352. model_form = forms.ConsolePortForm
  1353. class ConsolePortEditView(generic.ObjectEditView):
  1354. queryset = ConsolePort.objects.all()
  1355. form = forms.ConsolePortForm
  1356. class ConsolePortDeleteView(generic.ObjectDeleteView):
  1357. queryset = ConsolePort.objects.all()
  1358. class ConsolePortBulkImportView(generic.BulkImportView):
  1359. queryset = ConsolePort.objects.all()
  1360. model_form = forms.ConsolePortCSVForm
  1361. table = tables.ConsolePortTable
  1362. class ConsolePortBulkEditView(generic.BulkEditView):
  1363. queryset = ConsolePort.objects.all()
  1364. filterset = filtersets.ConsolePortFilterSet
  1365. table = tables.ConsolePortTable
  1366. form = forms.ConsolePortBulkEditForm
  1367. class ConsolePortBulkRenameView(generic.BulkRenameView):
  1368. queryset = ConsolePort.objects.all()
  1369. class ConsolePortBulkDisconnectView(BulkDisconnectView):
  1370. queryset = ConsolePort.objects.all()
  1371. class ConsolePortBulkDeleteView(generic.BulkDeleteView):
  1372. queryset = ConsolePort.objects.all()
  1373. filterset = filtersets.ConsolePortFilterSet
  1374. table = tables.ConsolePortTable
  1375. #
  1376. # Console server ports
  1377. #
  1378. class ConsoleServerPortListView(generic.ObjectListView):
  1379. queryset = ConsoleServerPort.objects.all()
  1380. filterset = filtersets.ConsoleServerPortFilterSet
  1381. filterset_form = forms.ConsoleServerPortFilterForm
  1382. table = tables.ConsoleServerPortTable
  1383. actions = ('import', 'export', 'bulk_edit', 'bulk_delete')
  1384. class ConsoleServerPortView(generic.ObjectView):
  1385. queryset = ConsoleServerPort.objects.all()
  1386. class ConsoleServerPortCreateView(generic.ComponentCreateView):
  1387. queryset = ConsoleServerPort.objects.all()
  1388. form = forms.ConsoleServerPortCreateForm
  1389. model_form = forms.ConsoleServerPortForm
  1390. class ConsoleServerPortEditView(generic.ObjectEditView):
  1391. queryset = ConsoleServerPort.objects.all()
  1392. form = forms.ConsoleServerPortForm
  1393. class ConsoleServerPortDeleteView(generic.ObjectDeleteView):
  1394. queryset = ConsoleServerPort.objects.all()
  1395. class ConsoleServerPortBulkImportView(generic.BulkImportView):
  1396. queryset = ConsoleServerPort.objects.all()
  1397. model_form = forms.ConsoleServerPortCSVForm
  1398. table = tables.ConsoleServerPortTable
  1399. class ConsoleServerPortBulkEditView(generic.BulkEditView):
  1400. queryset = ConsoleServerPort.objects.all()
  1401. filterset = filtersets.ConsoleServerPortFilterSet
  1402. table = tables.ConsoleServerPortTable
  1403. form = forms.ConsoleServerPortBulkEditForm
  1404. class ConsoleServerPortBulkRenameView(generic.BulkRenameView):
  1405. queryset = ConsoleServerPort.objects.all()
  1406. class ConsoleServerPortBulkDisconnectView(BulkDisconnectView):
  1407. queryset = ConsoleServerPort.objects.all()
  1408. class ConsoleServerPortBulkDeleteView(generic.BulkDeleteView):
  1409. queryset = ConsoleServerPort.objects.all()
  1410. filterset = filtersets.ConsoleServerPortFilterSet
  1411. table = tables.ConsoleServerPortTable
  1412. #
  1413. # Power ports
  1414. #
  1415. class PowerPortListView(generic.ObjectListView):
  1416. queryset = PowerPort.objects.all()
  1417. filterset = filtersets.PowerPortFilterSet
  1418. filterset_form = forms.PowerPortFilterForm
  1419. table = tables.PowerPortTable
  1420. actions = ('import', 'export', 'bulk_edit', 'bulk_delete')
  1421. class PowerPortView(generic.ObjectView):
  1422. queryset = PowerPort.objects.all()
  1423. class PowerPortCreateView(generic.ComponentCreateView):
  1424. queryset = PowerPort.objects.all()
  1425. form = forms.PowerPortCreateForm
  1426. model_form = forms.PowerPortForm
  1427. class PowerPortEditView(generic.ObjectEditView):
  1428. queryset = PowerPort.objects.all()
  1429. form = forms.PowerPortForm
  1430. class PowerPortDeleteView(generic.ObjectDeleteView):
  1431. queryset = PowerPort.objects.all()
  1432. class PowerPortBulkImportView(generic.BulkImportView):
  1433. queryset = PowerPort.objects.all()
  1434. model_form = forms.PowerPortCSVForm
  1435. table = tables.PowerPortTable
  1436. class PowerPortBulkEditView(generic.BulkEditView):
  1437. queryset = PowerPort.objects.all()
  1438. filterset = filtersets.PowerPortFilterSet
  1439. table = tables.PowerPortTable
  1440. form = forms.PowerPortBulkEditForm
  1441. class PowerPortBulkRenameView(generic.BulkRenameView):
  1442. queryset = PowerPort.objects.all()
  1443. class PowerPortBulkDisconnectView(BulkDisconnectView):
  1444. queryset = PowerPort.objects.all()
  1445. class PowerPortBulkDeleteView(generic.BulkDeleteView):
  1446. queryset = PowerPort.objects.all()
  1447. filterset = filtersets.PowerPortFilterSet
  1448. table = tables.PowerPortTable
  1449. #
  1450. # Power outlets
  1451. #
  1452. class PowerOutletListView(generic.ObjectListView):
  1453. queryset = PowerOutlet.objects.all()
  1454. filterset = filtersets.PowerOutletFilterSet
  1455. filterset_form = forms.PowerOutletFilterForm
  1456. table = tables.PowerOutletTable
  1457. actions = ('import', 'export', 'bulk_edit', 'bulk_delete')
  1458. class PowerOutletView(generic.ObjectView):
  1459. queryset = PowerOutlet.objects.all()
  1460. class PowerOutletCreateView(generic.ComponentCreateView):
  1461. queryset = PowerOutlet.objects.all()
  1462. form = forms.PowerOutletCreateForm
  1463. model_form = forms.PowerOutletForm
  1464. class PowerOutletEditView(generic.ObjectEditView):
  1465. queryset = PowerOutlet.objects.all()
  1466. form = forms.PowerOutletForm
  1467. class PowerOutletDeleteView(generic.ObjectDeleteView):
  1468. queryset = PowerOutlet.objects.all()
  1469. class PowerOutletBulkImportView(generic.BulkImportView):
  1470. queryset = PowerOutlet.objects.all()
  1471. model_form = forms.PowerOutletCSVForm
  1472. table = tables.PowerOutletTable
  1473. class PowerOutletBulkEditView(generic.BulkEditView):
  1474. queryset = PowerOutlet.objects.all()
  1475. filterset = filtersets.PowerOutletFilterSet
  1476. table = tables.PowerOutletTable
  1477. form = forms.PowerOutletBulkEditForm
  1478. class PowerOutletBulkRenameView(generic.BulkRenameView):
  1479. queryset = PowerOutlet.objects.all()
  1480. class PowerOutletBulkDisconnectView(BulkDisconnectView):
  1481. queryset = PowerOutlet.objects.all()
  1482. class PowerOutletBulkDeleteView(generic.BulkDeleteView):
  1483. queryset = PowerOutlet.objects.all()
  1484. filterset = filtersets.PowerOutletFilterSet
  1485. table = tables.PowerOutletTable
  1486. #
  1487. # Interfaces
  1488. #
  1489. class InterfaceListView(generic.ObjectListView):
  1490. queryset = Interface.objects.all()
  1491. filterset = filtersets.InterfaceFilterSet
  1492. filterset_form = forms.InterfaceFilterForm
  1493. table = tables.InterfaceTable
  1494. actions = ('import', 'export', 'bulk_edit', 'bulk_delete')
  1495. class InterfaceView(generic.ObjectView):
  1496. queryset = Interface.objects.all()
  1497. def get_extra_context(self, request, instance):
  1498. # Get assigned IP addresses
  1499. ipaddress_table = AssignedIPAddressesTable(
  1500. data=instance.ip_addresses.restrict(request.user, 'view').prefetch_related('vrf', 'tenant'),
  1501. orderable=False
  1502. )
  1503. # Get bridge interfaces
  1504. bridge_interfaces = Interface.objects.restrict(request.user, 'view').filter(bridge=instance)
  1505. bridge_interfaces_tables = tables.InterfaceTable(
  1506. bridge_interfaces,
  1507. exclude=('device', 'parent'),
  1508. orderable=False
  1509. )
  1510. # Get child interfaces
  1511. child_interfaces = Interface.objects.restrict(request.user, 'view').filter(parent=instance)
  1512. child_interfaces_tables = tables.InterfaceTable(
  1513. child_interfaces,
  1514. exclude=('device', 'parent'),
  1515. orderable=False
  1516. )
  1517. # Get assigned VLANs and annotate whether each is tagged or untagged
  1518. vlans = []
  1519. if instance.untagged_vlan is not None:
  1520. vlans.append(instance.untagged_vlan)
  1521. vlans[0].tagged = False
  1522. for vlan in instance.tagged_vlans.restrict(request.user).prefetch_related('site', 'group', 'tenant', 'role'):
  1523. vlan.tagged = True
  1524. vlans.append(vlan)
  1525. vlan_table = InterfaceVLANTable(
  1526. interface=instance,
  1527. data=vlans,
  1528. orderable=False
  1529. )
  1530. return {
  1531. 'ipaddress_table': ipaddress_table,
  1532. 'bridge_interfaces_table': bridge_interfaces_tables,
  1533. 'child_interfaces_table': child_interfaces_tables,
  1534. 'vlan_table': vlan_table,
  1535. }
  1536. class InterfaceCreateView(generic.ComponentCreateView):
  1537. queryset = Interface.objects.all()
  1538. form = forms.InterfaceCreateForm
  1539. model_form = forms.InterfaceForm
  1540. class InterfaceEditView(generic.ObjectEditView):
  1541. queryset = Interface.objects.all()
  1542. form = forms.InterfaceForm
  1543. class InterfaceDeleteView(generic.ObjectDeleteView):
  1544. queryset = Interface.objects.all()
  1545. class InterfaceBulkImportView(generic.BulkImportView):
  1546. queryset = Interface.objects.all()
  1547. model_form = forms.InterfaceCSVForm
  1548. table = tables.InterfaceTable
  1549. class InterfaceBulkEditView(generic.BulkEditView):
  1550. queryset = Interface.objects.all()
  1551. filterset = filtersets.InterfaceFilterSet
  1552. table = tables.InterfaceTable
  1553. form = forms.InterfaceBulkEditForm
  1554. class InterfaceBulkRenameView(generic.BulkRenameView):
  1555. queryset = Interface.objects.all()
  1556. class InterfaceBulkDisconnectView(BulkDisconnectView):
  1557. queryset = Interface.objects.all()
  1558. class InterfaceBulkDeleteView(generic.BulkDeleteView):
  1559. queryset = Interface.objects.all()
  1560. filterset = filtersets.InterfaceFilterSet
  1561. table = tables.InterfaceTable
  1562. #
  1563. # Front ports
  1564. #
  1565. class FrontPortListView(generic.ObjectListView):
  1566. queryset = FrontPort.objects.all()
  1567. filterset = filtersets.FrontPortFilterSet
  1568. filterset_form = forms.FrontPortFilterForm
  1569. table = tables.FrontPortTable
  1570. actions = ('import', 'export', 'bulk_edit', 'bulk_delete')
  1571. class FrontPortView(generic.ObjectView):
  1572. queryset = FrontPort.objects.all()
  1573. class FrontPortCreateView(generic.ComponentCreateView):
  1574. queryset = FrontPort.objects.all()
  1575. form = forms.FrontPortCreateForm
  1576. model_form = forms.FrontPortForm
  1577. class FrontPortEditView(generic.ObjectEditView):
  1578. queryset = FrontPort.objects.all()
  1579. form = forms.FrontPortForm
  1580. class FrontPortDeleteView(generic.ObjectDeleteView):
  1581. queryset = FrontPort.objects.all()
  1582. class FrontPortBulkImportView(generic.BulkImportView):
  1583. queryset = FrontPort.objects.all()
  1584. model_form = forms.FrontPortCSVForm
  1585. table = tables.FrontPortTable
  1586. class FrontPortBulkEditView(generic.BulkEditView):
  1587. queryset = FrontPort.objects.all()
  1588. filterset = filtersets.FrontPortFilterSet
  1589. table = tables.FrontPortTable
  1590. form = forms.FrontPortBulkEditForm
  1591. class FrontPortBulkRenameView(generic.BulkRenameView):
  1592. queryset = FrontPort.objects.all()
  1593. class FrontPortBulkDisconnectView(BulkDisconnectView):
  1594. queryset = FrontPort.objects.all()
  1595. class FrontPortBulkDeleteView(generic.BulkDeleteView):
  1596. queryset = FrontPort.objects.all()
  1597. filterset = filtersets.FrontPortFilterSet
  1598. table = tables.FrontPortTable
  1599. #
  1600. # Rear ports
  1601. #
  1602. class RearPortListView(generic.ObjectListView):
  1603. queryset = RearPort.objects.all()
  1604. filterset = filtersets.RearPortFilterSet
  1605. filterset_form = forms.RearPortFilterForm
  1606. table = tables.RearPortTable
  1607. actions = ('import', 'export', 'bulk_edit', 'bulk_delete')
  1608. class RearPortView(generic.ObjectView):
  1609. queryset = RearPort.objects.all()
  1610. class RearPortCreateView(generic.ComponentCreateView):
  1611. queryset = RearPort.objects.all()
  1612. form = forms.RearPortCreateForm
  1613. model_form = forms.RearPortForm
  1614. class RearPortEditView(generic.ObjectEditView):
  1615. queryset = RearPort.objects.all()
  1616. form = forms.RearPortForm
  1617. class RearPortDeleteView(generic.ObjectDeleteView):
  1618. queryset = RearPort.objects.all()
  1619. class RearPortBulkImportView(generic.BulkImportView):
  1620. queryset = RearPort.objects.all()
  1621. model_form = forms.RearPortCSVForm
  1622. table = tables.RearPortTable
  1623. class RearPortBulkEditView(generic.BulkEditView):
  1624. queryset = RearPort.objects.all()
  1625. filterset = filtersets.RearPortFilterSet
  1626. table = tables.RearPortTable
  1627. form = forms.RearPortBulkEditForm
  1628. class RearPortBulkRenameView(generic.BulkRenameView):
  1629. queryset = RearPort.objects.all()
  1630. class RearPortBulkDisconnectView(BulkDisconnectView):
  1631. queryset = RearPort.objects.all()
  1632. class RearPortBulkDeleteView(generic.BulkDeleteView):
  1633. queryset = RearPort.objects.all()
  1634. filterset = filtersets.RearPortFilterSet
  1635. table = tables.RearPortTable
  1636. #
  1637. # Module bays
  1638. #
  1639. class ModuleBayListView(generic.ObjectListView):
  1640. queryset = ModuleBay.objects.select_related('installed_module__module_type')
  1641. filterset = filtersets.ModuleBayFilterSet
  1642. filterset_form = forms.ModuleBayFilterForm
  1643. table = tables.ModuleBayTable
  1644. actions = ('import', 'export', 'bulk_edit', 'bulk_delete')
  1645. class ModuleBayView(generic.ObjectView):
  1646. queryset = ModuleBay.objects.all()
  1647. class ModuleBayCreateView(generic.ComponentCreateView):
  1648. queryset = ModuleBay.objects.all()
  1649. form = forms.ModuleBayCreateForm
  1650. model_form = forms.ModuleBayForm
  1651. class ModuleBayEditView(generic.ObjectEditView):
  1652. queryset = ModuleBay.objects.all()
  1653. form = forms.ModuleBayForm
  1654. class ModuleBayDeleteView(generic.ObjectDeleteView):
  1655. queryset = ModuleBay.objects.all()
  1656. class ModuleBayBulkImportView(generic.BulkImportView):
  1657. queryset = ModuleBay.objects.all()
  1658. model_form = forms.ModuleBayCSVForm
  1659. table = tables.ModuleBayTable
  1660. class ModuleBayBulkEditView(generic.BulkEditView):
  1661. queryset = ModuleBay.objects.all()
  1662. filterset = filtersets.ModuleBayFilterSet
  1663. table = tables.ModuleBayTable
  1664. form = forms.ModuleBayBulkEditForm
  1665. class ModuleBayBulkRenameView(generic.BulkRenameView):
  1666. queryset = ModuleBay.objects.all()
  1667. class ModuleBayBulkDeleteView(generic.BulkDeleteView):
  1668. queryset = ModuleBay.objects.all()
  1669. filterset = filtersets.ModuleBayFilterSet
  1670. table = tables.ModuleBayTable
  1671. #
  1672. # Device bays
  1673. #
  1674. class DeviceBayListView(generic.ObjectListView):
  1675. queryset = DeviceBay.objects.all()
  1676. filterset = filtersets.DeviceBayFilterSet
  1677. filterset_form = forms.DeviceBayFilterForm
  1678. table = tables.DeviceBayTable
  1679. actions = ('import', 'export', 'bulk_edit', 'bulk_delete')
  1680. class DeviceBayView(generic.ObjectView):
  1681. queryset = DeviceBay.objects.all()
  1682. class DeviceBayCreateView(generic.ComponentCreateView):
  1683. queryset = DeviceBay.objects.all()
  1684. form = forms.DeviceBayCreateForm
  1685. model_form = forms.DeviceBayForm
  1686. class DeviceBayEditView(generic.ObjectEditView):
  1687. queryset = DeviceBay.objects.all()
  1688. form = forms.DeviceBayForm
  1689. class DeviceBayDeleteView(generic.ObjectDeleteView):
  1690. queryset = DeviceBay.objects.all()
  1691. class DeviceBayPopulateView(generic.ObjectEditView):
  1692. queryset = DeviceBay.objects.all()
  1693. def get(self, request, pk):
  1694. device_bay = get_object_or_404(self.queryset, pk=pk)
  1695. form = forms.PopulateDeviceBayForm(device_bay)
  1696. return render(request, 'dcim/devicebay_populate.html', {
  1697. 'device_bay': device_bay,
  1698. 'form': form,
  1699. 'return_url': self.get_return_url(request, device_bay),
  1700. })
  1701. def post(self, request, pk):
  1702. device_bay = get_object_or_404(self.queryset, pk=pk)
  1703. form = forms.PopulateDeviceBayForm(device_bay, request.POST)
  1704. if form.is_valid():
  1705. device_bay.installed_device = form.cleaned_data['installed_device']
  1706. device_bay.save()
  1707. messages.success(request, "Added {} to {}.".format(device_bay.installed_device, device_bay))
  1708. return_url = self.get_return_url(request)
  1709. return redirect(return_url)
  1710. return render(request, 'dcim/devicebay_populate.html', {
  1711. 'device_bay': device_bay,
  1712. 'form': form,
  1713. 'return_url': self.get_return_url(request, device_bay),
  1714. })
  1715. class DeviceBayDepopulateView(generic.ObjectEditView):
  1716. queryset = DeviceBay.objects.all()
  1717. def get(self, request, pk):
  1718. device_bay = get_object_or_404(self.queryset, pk=pk)
  1719. form = ConfirmationForm()
  1720. return render(request, 'dcim/devicebay_depopulate.html', {
  1721. 'device_bay': device_bay,
  1722. 'form': form,
  1723. 'return_url': self.get_return_url(request, device_bay),
  1724. })
  1725. def post(self, request, pk):
  1726. device_bay = get_object_or_404(self.queryset, pk=pk)
  1727. form = ConfirmationForm(request.POST)
  1728. if form.is_valid():
  1729. removed_device = device_bay.installed_device
  1730. device_bay.installed_device = None
  1731. device_bay.save()
  1732. messages.success(request, f"{removed_device} has been removed from {device_bay}.")
  1733. return_url = self.get_return_url(request, device_bay.device)
  1734. return redirect(return_url)
  1735. return render(request, 'dcim/devicebay_depopulate.html', {
  1736. 'device_bay': device_bay,
  1737. 'form': form,
  1738. 'return_url': self.get_return_url(request, device_bay),
  1739. })
  1740. class DeviceBayBulkImportView(generic.BulkImportView):
  1741. queryset = DeviceBay.objects.all()
  1742. model_form = forms.DeviceBayCSVForm
  1743. table = tables.DeviceBayTable
  1744. class DeviceBayBulkEditView(generic.BulkEditView):
  1745. queryset = DeviceBay.objects.all()
  1746. filterset = filtersets.DeviceBayFilterSet
  1747. table = tables.DeviceBayTable
  1748. form = forms.DeviceBayBulkEditForm
  1749. class DeviceBayBulkRenameView(generic.BulkRenameView):
  1750. queryset = DeviceBay.objects.all()
  1751. class DeviceBayBulkDeleteView(generic.BulkDeleteView):
  1752. queryset = DeviceBay.objects.all()
  1753. filterset = filtersets.DeviceBayFilterSet
  1754. table = tables.DeviceBayTable
  1755. #
  1756. # Inventory items
  1757. #
  1758. class InventoryItemListView(generic.ObjectListView):
  1759. queryset = InventoryItem.objects.all()
  1760. filterset = filtersets.InventoryItemFilterSet
  1761. filterset_form = forms.InventoryItemFilterForm
  1762. table = tables.InventoryItemTable
  1763. actions = ('import', 'export', 'bulk_edit', 'bulk_delete')
  1764. class InventoryItemView(generic.ObjectView):
  1765. queryset = InventoryItem.objects.all()
  1766. class InventoryItemEditView(generic.ObjectEditView):
  1767. queryset = InventoryItem.objects.all()
  1768. form = forms.InventoryItemForm
  1769. class InventoryItemCreateView(generic.ComponentCreateView):
  1770. queryset = InventoryItem.objects.all()
  1771. form = forms.InventoryItemCreateForm
  1772. model_form = forms.InventoryItemForm
  1773. def alter_object(self, instance, request):
  1774. # Set component (if any)
  1775. component_type = request.GET.get('component_type')
  1776. component_id = request.GET.get('component_id')
  1777. if component_type and component_id:
  1778. content_type = get_object_or_404(ContentType, pk=component_type)
  1779. instance.component = get_object_or_404(content_type.model_class(), pk=component_id)
  1780. return instance
  1781. class InventoryItemDeleteView(generic.ObjectDeleteView):
  1782. queryset = InventoryItem.objects.all()
  1783. class InventoryItemBulkImportView(generic.BulkImportView):
  1784. queryset = InventoryItem.objects.all()
  1785. model_form = forms.InventoryItemCSVForm
  1786. table = tables.InventoryItemTable
  1787. class InventoryItemBulkEditView(generic.BulkEditView):
  1788. queryset = InventoryItem.objects.all()
  1789. filterset = filtersets.InventoryItemFilterSet
  1790. table = tables.InventoryItemTable
  1791. form = forms.InventoryItemBulkEditForm
  1792. class InventoryItemBulkRenameView(generic.BulkRenameView):
  1793. queryset = InventoryItem.objects.all()
  1794. class InventoryItemBulkDeleteView(generic.BulkDeleteView):
  1795. queryset = InventoryItem.objects.all()
  1796. table = tables.InventoryItemTable
  1797. template_name = 'dcim/inventoryitem_bulk_delete.html'
  1798. #
  1799. # Inventory item roles
  1800. #
  1801. class InventoryItemRoleListView(generic.ObjectListView):
  1802. queryset = InventoryItemRole.objects.annotate(
  1803. inventoryitem_count=count_related(InventoryItem, 'role'),
  1804. )
  1805. filterset = filtersets.InventoryItemRoleFilterSet
  1806. filterset_form = forms.InventoryItemRoleFilterForm
  1807. table = tables.InventoryItemRoleTable
  1808. class InventoryItemRoleView(generic.ObjectView):
  1809. queryset = InventoryItemRole.objects.all()
  1810. def get_extra_context(self, request, instance):
  1811. return {
  1812. 'inventoryitem_count': InventoryItem.objects.filter(role=instance).count(),
  1813. }
  1814. class InventoryItemRoleEditView(generic.ObjectEditView):
  1815. queryset = InventoryItemRole.objects.all()
  1816. form = forms.InventoryItemRoleForm
  1817. class InventoryItemRoleDeleteView(generic.ObjectDeleteView):
  1818. queryset = InventoryItemRole.objects.all()
  1819. class InventoryItemRoleBulkImportView(generic.BulkImportView):
  1820. queryset = InventoryItemRole.objects.all()
  1821. model_form = forms.InventoryItemRoleCSVForm
  1822. table = tables.InventoryItemRoleTable
  1823. class InventoryItemRoleBulkEditView(generic.BulkEditView):
  1824. queryset = InventoryItemRole.objects.annotate(
  1825. inventoryitem_count=count_related(InventoryItem, 'role'),
  1826. )
  1827. filterset = filtersets.InventoryItemRoleFilterSet
  1828. table = tables.InventoryItemRoleTable
  1829. form = forms.InventoryItemRoleBulkEditForm
  1830. class InventoryItemRoleBulkDeleteView(generic.BulkDeleteView):
  1831. queryset = InventoryItemRole.objects.annotate(
  1832. inventoryitem_count=count_related(InventoryItem, 'role'),
  1833. )
  1834. table = tables.InventoryItemRoleTable
  1835. #
  1836. # Bulk Device component creation
  1837. #
  1838. class DeviceBulkAddConsolePortView(generic.BulkComponentCreateView):
  1839. parent_model = Device
  1840. parent_field = 'device'
  1841. form = forms.ConsolePortBulkCreateForm
  1842. queryset = ConsolePort.objects.all()
  1843. model_form = forms.ConsolePortForm
  1844. filterset = filtersets.DeviceFilterSet
  1845. table = tables.DeviceTable
  1846. default_return_url = 'dcim:device_list'
  1847. class DeviceBulkAddConsoleServerPortView(generic.BulkComponentCreateView):
  1848. parent_model = Device
  1849. parent_field = 'device'
  1850. form = forms.ConsoleServerPortBulkCreateForm
  1851. queryset = ConsoleServerPort.objects.all()
  1852. model_form = forms.ConsoleServerPortForm
  1853. filterset = filtersets.DeviceFilterSet
  1854. table = tables.DeviceTable
  1855. default_return_url = 'dcim:device_list'
  1856. class DeviceBulkAddPowerPortView(generic.BulkComponentCreateView):
  1857. parent_model = Device
  1858. parent_field = 'device'
  1859. form = forms.PowerPortBulkCreateForm
  1860. queryset = PowerPort.objects.all()
  1861. model_form = forms.PowerPortForm
  1862. filterset = filtersets.DeviceFilterSet
  1863. table = tables.DeviceTable
  1864. default_return_url = 'dcim:device_list'
  1865. class DeviceBulkAddPowerOutletView(generic.BulkComponentCreateView):
  1866. parent_model = Device
  1867. parent_field = 'device'
  1868. form = forms.PowerOutletBulkCreateForm
  1869. queryset = PowerOutlet.objects.all()
  1870. model_form = forms.PowerOutletForm
  1871. filterset = filtersets.DeviceFilterSet
  1872. table = tables.DeviceTable
  1873. default_return_url = 'dcim:device_list'
  1874. class DeviceBulkAddInterfaceView(generic.BulkComponentCreateView):
  1875. parent_model = Device
  1876. parent_field = 'device'
  1877. form = forms.InterfaceBulkCreateForm
  1878. queryset = Interface.objects.all()
  1879. model_form = forms.InterfaceForm
  1880. filterset = filtersets.DeviceFilterSet
  1881. table = tables.DeviceTable
  1882. default_return_url = 'dcim:device_list'
  1883. # class DeviceBulkAddFrontPortView(generic.BulkComponentCreateView):
  1884. # parent_model = Device
  1885. # parent_field = 'device'
  1886. # form = forms.FrontPortBulkCreateForm
  1887. # queryset = FrontPort.objects.all()
  1888. # model_form = forms.FrontPortForm
  1889. # filterset = filtersets.DeviceFilterSet
  1890. # table = tables.DeviceTable
  1891. # default_return_url = 'dcim:device_list'
  1892. class DeviceBulkAddRearPortView(generic.BulkComponentCreateView):
  1893. parent_model = Device
  1894. parent_field = 'device'
  1895. form = forms.RearPortBulkCreateForm
  1896. queryset = RearPort.objects.all()
  1897. model_form = forms.RearPortForm
  1898. filterset = filtersets.DeviceFilterSet
  1899. table = tables.DeviceTable
  1900. default_return_url = 'dcim:device_list'
  1901. class DeviceBulkAddModuleBayView(generic.BulkComponentCreateView):
  1902. parent_model = Device
  1903. parent_field = 'device'
  1904. form = forms.ModuleBayBulkCreateForm
  1905. queryset = ModuleBay.objects.all()
  1906. model_form = forms.ModuleBayForm
  1907. filterset = filtersets.DeviceFilterSet
  1908. table = tables.DeviceTable
  1909. default_return_url = 'dcim:device_list'
  1910. class DeviceBulkAddDeviceBayView(generic.BulkComponentCreateView):
  1911. parent_model = Device
  1912. parent_field = 'device'
  1913. form = forms.DeviceBayBulkCreateForm
  1914. queryset = DeviceBay.objects.all()
  1915. model_form = forms.DeviceBayForm
  1916. filterset = filtersets.DeviceFilterSet
  1917. table = tables.DeviceTable
  1918. default_return_url = 'dcim:device_list'
  1919. class DeviceBulkAddInventoryItemView(generic.BulkComponentCreateView):
  1920. parent_model = Device
  1921. parent_field = 'device'
  1922. form = forms.InventoryItemBulkCreateForm
  1923. queryset = InventoryItem.objects.all()
  1924. model_form = forms.InventoryItemForm
  1925. filterset = filtersets.DeviceFilterSet
  1926. table = tables.DeviceTable
  1927. default_return_url = 'dcim:device_list'
  1928. #
  1929. # Cables
  1930. #
  1931. class CableListView(generic.ObjectListView):
  1932. queryset = Cable.objects.prefetch_related(
  1933. 'terminations__termination', 'terminations___device', 'terminations___rack', 'terminations___location',
  1934. 'terminations___site',
  1935. )
  1936. filterset = filtersets.CableFilterSet
  1937. filterset_form = forms.CableFilterForm
  1938. table = tables.CableTable
  1939. actions = ('import', 'export', 'bulk_edit', 'bulk_delete')
  1940. class CableView(generic.ObjectView):
  1941. queryset = Cable.objects.all()
  1942. class PathTraceView(generic.ObjectView):
  1943. """
  1944. Trace a cable path beginning from the given path endpoint (origin).
  1945. """
  1946. additional_permissions = ['dcim.view_cable']
  1947. template_name = 'dcim/cable_trace.html'
  1948. def dispatch(self, request, *args, **kwargs):
  1949. model = kwargs.pop('model')
  1950. self.queryset = model.objects.all()
  1951. return super().dispatch(request, *args, **kwargs)
  1952. def get_extra_context(self, request, instance):
  1953. related_paths = []
  1954. # If tracing a PathEndpoint, locate the CablePath (if one exists) by its origin
  1955. if isinstance(instance, PathEndpoint):
  1956. path = instance._path
  1957. # Otherwise, find all CablePaths which traverse the specified object
  1958. else:
  1959. related_paths = CablePath.objects.filter(_nodes__contains=instance)
  1960. # Check for specification of a particular path (when tracing pass-through ports)
  1961. try:
  1962. path_id = int(request.GET.get('cablepath_id'))
  1963. except TypeError:
  1964. path_id = None
  1965. if path_id in list(related_paths.values_list('pk', flat=True)):
  1966. path = CablePath.objects.get(pk=path_id)
  1967. else:
  1968. path = related_paths.first()
  1969. # No paths found
  1970. if path is None:
  1971. return {
  1972. 'path': None
  1973. }
  1974. # Get the total length of the cable and whether the length is definitive (fully defined)
  1975. total_length, is_definitive = path.get_total_length() if path else (None, False)
  1976. # Determine the path to the SVG trace image
  1977. api_viewname = f"{path.origin_type.app_label}-api:{path.origin_type.model}-trace"
  1978. svg_url = f"{reverse(api_viewname, kwargs={'pk': path.origins[0].pk})}?render=svg"
  1979. return {
  1980. 'path': path,
  1981. 'related_paths': related_paths,
  1982. 'total_length': total_length,
  1983. 'is_definitive': is_definitive,
  1984. 'svg_url': svg_url,
  1985. }
  1986. class CableEditView(generic.ObjectEditView):
  1987. queryset = Cable.objects.all()
  1988. template_name = 'dcim/cable_edit.html'
  1989. def dispatch(self, request, *args, **kwargs):
  1990. # If creating a new Cable, initialize the form class using URL query params
  1991. if 'pk' not in kwargs:
  1992. self.form = forms.get_cable_form(
  1993. a_type=CABLE_TERMINATION_TYPES.get(request.GET.get('a_terminations_type')),
  1994. b_type=CABLE_TERMINATION_TYPES.get(request.GET.get('b_terminations_type'))
  1995. )
  1996. return super().dispatch(request, *args, **kwargs)
  1997. def get_object(self, **kwargs):
  1998. """
  1999. Hack into get_object() to set the form class when editing an existing Cable, since ObjectEditView
  2000. doesn't currently provide a hook for dynamic class resolution.
  2001. """
  2002. obj = super().get_object(**kwargs)
  2003. if obj.pk:
  2004. # TODO: Optimize this logic
  2005. termination_a = obj.terminations.filter(cable_end='A').first()
  2006. a_type = termination_a.termination._meta.model if termination_a else None
  2007. termination_b = obj.terminations.filter(cable_end='B').first()
  2008. b_type = termination_b.termination._meta.model if termination_b else None
  2009. self.form = forms.get_cable_form(a_type, b_type)
  2010. return obj
  2011. class CableDeleteView(generic.ObjectDeleteView):
  2012. queryset = Cable.objects.all()
  2013. class CableBulkImportView(generic.BulkImportView):
  2014. queryset = Cable.objects.all()
  2015. model_form = forms.CableCSVForm
  2016. table = tables.CableTable
  2017. class CableBulkEditView(generic.BulkEditView):
  2018. queryset = Cable.objects.prefetch_related(
  2019. 'terminations__termination', 'terminations___device', 'terminations___rack', 'terminations___location',
  2020. 'terminations___site',
  2021. )
  2022. filterset = filtersets.CableFilterSet
  2023. table = tables.CableTable
  2024. form = forms.CableBulkEditForm
  2025. class CableBulkDeleteView(generic.BulkDeleteView):
  2026. queryset = Cable.objects.prefetch_related(
  2027. 'terminations__termination', 'terminations___device', 'terminations___rack', 'terminations___location',
  2028. 'terminations___site',
  2029. )
  2030. filterset = filtersets.CableFilterSet
  2031. table = tables.CableTable
  2032. #
  2033. # Connections
  2034. #
  2035. class ConsoleConnectionsListView(generic.ObjectListView):
  2036. queryset = ConsolePort.objects.filter(_path__is_complete=True)
  2037. filterset = filtersets.ConsoleConnectionFilterSet
  2038. filterset_form = forms.ConsoleConnectionFilterForm
  2039. table = tables.ConsoleConnectionTable
  2040. template_name = 'dcim/connections_list.html'
  2041. actions = ('export',)
  2042. def get_extra_context(self, request):
  2043. return {
  2044. 'title': 'Console Connections'
  2045. }
  2046. class PowerConnectionsListView(generic.ObjectListView):
  2047. queryset = PowerPort.objects.filter(_path__is_complete=True)
  2048. filterset = filtersets.PowerConnectionFilterSet
  2049. filterset_form = forms.PowerConnectionFilterForm
  2050. table = tables.PowerConnectionTable
  2051. template_name = 'dcim/connections_list.html'
  2052. actions = ('export',)
  2053. def get_extra_context(self, request):
  2054. return {
  2055. 'title': 'Power Connections'
  2056. }
  2057. class InterfaceConnectionsListView(generic.ObjectListView):
  2058. queryset = Interface.objects.filter(_path__is_complete=True)
  2059. filterset = filtersets.InterfaceConnectionFilterSet
  2060. filterset_form = forms.InterfaceConnectionFilterForm
  2061. table = tables.InterfaceConnectionTable
  2062. template_name = 'dcim/connections_list.html'
  2063. actions = ('export',)
  2064. def get_extra_context(self, request):
  2065. return {
  2066. 'title': 'Interface Connections'
  2067. }
  2068. #
  2069. # Virtual chassis
  2070. #
  2071. class VirtualChassisListView(generic.ObjectListView):
  2072. queryset = VirtualChassis.objects.annotate(
  2073. member_count=count_related(Device, 'virtual_chassis')
  2074. )
  2075. table = tables.VirtualChassisTable
  2076. filterset = filtersets.VirtualChassisFilterSet
  2077. filterset_form = forms.VirtualChassisFilterForm
  2078. class VirtualChassisView(generic.ObjectView):
  2079. queryset = VirtualChassis.objects.all()
  2080. def get_extra_context(self, request, instance):
  2081. members = Device.objects.restrict(request.user).filter(virtual_chassis=instance)
  2082. return {
  2083. 'members': members,
  2084. }
  2085. class VirtualChassisCreateView(generic.ObjectEditView):
  2086. queryset = VirtualChassis.objects.all()
  2087. form = forms.VirtualChassisCreateForm
  2088. template_name = 'dcim/virtualchassis_add.html'
  2089. class VirtualChassisEditView(ObjectPermissionRequiredMixin, GetReturnURLMixin, View):
  2090. queryset = VirtualChassis.objects.all()
  2091. def get_required_permission(self):
  2092. return 'dcim.change_virtualchassis'
  2093. def get(self, request, pk):
  2094. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  2095. VCMemberFormSet = modelformset_factory(
  2096. model=Device,
  2097. form=forms.DeviceVCMembershipForm,
  2098. formset=forms.BaseVCMemberFormSet,
  2099. extra=0
  2100. )
  2101. members_queryset = virtual_chassis.members.prefetch_related('rack').order_by('vc_position')
  2102. vc_form = forms.VirtualChassisForm(instance=virtual_chassis)
  2103. vc_form.fields['master'].queryset = members_queryset
  2104. formset = VCMemberFormSet(queryset=members_queryset)
  2105. return render(request, 'dcim/virtualchassis_edit.html', {
  2106. 'vc_form': vc_form,
  2107. 'formset': formset,
  2108. 'return_url': self.get_return_url(request, virtual_chassis),
  2109. })
  2110. def post(self, request, pk):
  2111. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  2112. VCMemberFormSet = modelformset_factory(
  2113. model=Device,
  2114. form=forms.DeviceVCMembershipForm,
  2115. formset=forms.BaseVCMemberFormSet,
  2116. extra=0
  2117. )
  2118. members_queryset = virtual_chassis.members.prefetch_related('rack').order_by('vc_position')
  2119. vc_form = forms.VirtualChassisForm(request.POST, instance=virtual_chassis)
  2120. vc_form.fields['master'].queryset = members_queryset
  2121. formset = VCMemberFormSet(request.POST, queryset=members_queryset)
  2122. if vc_form.is_valid() and formset.is_valid():
  2123. with transaction.atomic():
  2124. # Save the VirtualChassis
  2125. vc_form.save()
  2126. # Nullify the vc_position of each member first to allow reordering without raising an IntegrityError on
  2127. # duplicate positions. Then save each member instance.
  2128. members = formset.save(commit=False)
  2129. devices = Device.objects.filter(pk__in=[m.pk for m in members])
  2130. for device in devices:
  2131. device.vc_position = None
  2132. device.save()
  2133. for member in members:
  2134. member.save()
  2135. return redirect(virtual_chassis.get_absolute_url())
  2136. return render(request, 'dcim/virtualchassis_edit.html', {
  2137. 'vc_form': vc_form,
  2138. 'formset': formset,
  2139. 'return_url': self.get_return_url(request, virtual_chassis),
  2140. })
  2141. class VirtualChassisDeleteView(generic.ObjectDeleteView):
  2142. queryset = VirtualChassis.objects.all()
  2143. class VirtualChassisAddMemberView(ObjectPermissionRequiredMixin, GetReturnURLMixin, View):
  2144. queryset = VirtualChassis.objects.all()
  2145. def get_required_permission(self):
  2146. return 'dcim.change_virtualchassis'
  2147. def get(self, request, pk):
  2148. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  2149. initial_data = {k: request.GET[k] for k in request.GET}
  2150. member_select_form = forms.VCMemberSelectForm(initial=initial_data)
  2151. membership_form = forms.DeviceVCMembershipForm(initial=initial_data)
  2152. return render(request, 'dcim/virtualchassis_add_member.html', {
  2153. 'virtual_chassis': virtual_chassis,
  2154. 'member_select_form': member_select_form,
  2155. 'membership_form': membership_form,
  2156. 'return_url': self.get_return_url(request, virtual_chassis),
  2157. })
  2158. def post(self, request, pk):
  2159. virtual_chassis = get_object_or_404(self.queryset, pk=pk)
  2160. member_select_form = forms.VCMemberSelectForm(request.POST)
  2161. if member_select_form.is_valid():
  2162. device = member_select_form.cleaned_data['device']
  2163. device.virtual_chassis = virtual_chassis
  2164. data = {k: request.POST[k] for k in ['vc_position', 'vc_priority']}
  2165. membership_form = forms.DeviceVCMembershipForm(data=data, validate_vc_position=True, instance=device)
  2166. if membership_form.is_valid():
  2167. membership_form.save()
  2168. msg = f'Added member <a href="{device.get_absolute_url()}">{escape(device)}</a>'
  2169. messages.success(request, mark_safe(msg))
  2170. if '_addanother' in request.POST:
  2171. return redirect(request.get_full_path())
  2172. return redirect(self.get_return_url(request, device))
  2173. else:
  2174. membership_form = forms.DeviceVCMembershipForm(data=request.POST)
  2175. return render(request, 'dcim/virtualchassis_add_member.html', {
  2176. 'virtual_chassis': virtual_chassis,
  2177. 'member_select_form': member_select_form,
  2178. 'membership_form': membership_form,
  2179. 'return_url': self.get_return_url(request, virtual_chassis),
  2180. })
  2181. class VirtualChassisRemoveMemberView(ObjectPermissionRequiredMixin, GetReturnURLMixin, View):
  2182. queryset = Device.objects.all()
  2183. def get_required_permission(self):
  2184. return 'dcim.change_device'
  2185. def get(self, request, pk):
  2186. device = get_object_or_404(self.queryset, pk=pk, virtual_chassis__isnull=False)
  2187. form = ConfirmationForm(initial=request.GET)
  2188. return render(request, 'dcim/virtualchassis_remove_member.html', {
  2189. 'device': device,
  2190. 'form': form,
  2191. 'return_url': self.get_return_url(request, device),
  2192. })
  2193. def post(self, request, pk):
  2194. device = get_object_or_404(self.queryset, pk=pk, virtual_chassis__isnull=False)
  2195. form = ConfirmationForm(request.POST)
  2196. # Protect master device from being removed
  2197. virtual_chassis = VirtualChassis.objects.filter(master=device).first()
  2198. if virtual_chassis is not None:
  2199. messages.error(request, f'Unable to remove master device {device} from the virtual chassis.')
  2200. return redirect(device.get_absolute_url())
  2201. if form.is_valid():
  2202. devices = Device.objects.filter(pk=device.pk)
  2203. for device in devices:
  2204. device.virtual_chassis = None
  2205. device.vc_position = None
  2206. device.vc_priority = None
  2207. device.save()
  2208. msg = 'Removed {} from virtual chassis {}'.format(device, device.virtual_chassis)
  2209. messages.success(request, msg)
  2210. return redirect(self.get_return_url(request, device))
  2211. return render(request, 'dcim/virtualchassis_remove_member.html', {
  2212. 'device': device,
  2213. 'form': form,
  2214. 'return_url': self.get_return_url(request, device),
  2215. })
  2216. class VirtualChassisBulkImportView(generic.BulkImportView):
  2217. queryset = VirtualChassis.objects.all()
  2218. model_form = forms.VirtualChassisCSVForm
  2219. table = tables.VirtualChassisTable
  2220. class VirtualChassisBulkEditView(generic.BulkEditView):
  2221. queryset = VirtualChassis.objects.all()
  2222. filterset = filtersets.VirtualChassisFilterSet
  2223. table = tables.VirtualChassisTable
  2224. form = forms.VirtualChassisBulkEditForm
  2225. class VirtualChassisBulkDeleteView(generic.BulkDeleteView):
  2226. queryset = VirtualChassis.objects.all()
  2227. filterset = filtersets.VirtualChassisFilterSet
  2228. table = tables.VirtualChassisTable
  2229. #
  2230. # Power panels
  2231. #
  2232. class PowerPanelListView(generic.ObjectListView):
  2233. queryset = PowerPanel.objects.annotate(
  2234. powerfeed_count=count_related(PowerFeed, 'power_panel')
  2235. )
  2236. filterset = filtersets.PowerPanelFilterSet
  2237. filterset_form = forms.PowerPanelFilterForm
  2238. table = tables.PowerPanelTable
  2239. class PowerPanelView(generic.ObjectView):
  2240. queryset = PowerPanel.objects.all()
  2241. def get_extra_context(self, request, instance):
  2242. power_feeds = PowerFeed.objects.restrict(request.user).filter(power_panel=instance)
  2243. powerfeed_table = tables.PowerFeedTable(
  2244. data=power_feeds,
  2245. orderable=False
  2246. )
  2247. if request.user.has_perm('dcim.delete_cable'):
  2248. powerfeed_table.columns.show('pk')
  2249. powerfeed_table.exclude = ['power_panel']
  2250. return {
  2251. 'powerfeed_table': powerfeed_table,
  2252. }
  2253. class PowerPanelEditView(generic.ObjectEditView):
  2254. queryset = PowerPanel.objects.all()
  2255. form = forms.PowerPanelForm
  2256. class PowerPanelDeleteView(generic.ObjectDeleteView):
  2257. queryset = PowerPanel.objects.all()
  2258. class PowerPanelBulkImportView(generic.BulkImportView):
  2259. queryset = PowerPanel.objects.all()
  2260. model_form = forms.PowerPanelCSVForm
  2261. table = tables.PowerPanelTable
  2262. class PowerPanelBulkEditView(generic.BulkEditView):
  2263. queryset = PowerPanel.objects.all()
  2264. filterset = filtersets.PowerPanelFilterSet
  2265. table = tables.PowerPanelTable
  2266. form = forms.PowerPanelBulkEditForm
  2267. class PowerPanelBulkDeleteView(generic.BulkDeleteView):
  2268. queryset = PowerPanel.objects.annotate(
  2269. powerfeed_count=count_related(PowerFeed, 'power_panel')
  2270. )
  2271. filterset = filtersets.PowerPanelFilterSet
  2272. table = tables.PowerPanelTable
  2273. #
  2274. # Power feeds
  2275. #
  2276. class PowerFeedListView(generic.ObjectListView):
  2277. queryset = PowerFeed.objects.all()
  2278. filterset = filtersets.PowerFeedFilterSet
  2279. filterset_form = forms.PowerFeedFilterForm
  2280. table = tables.PowerFeedTable
  2281. class PowerFeedView(generic.ObjectView):
  2282. queryset = PowerFeed.objects.all()
  2283. class PowerFeedEditView(generic.ObjectEditView):
  2284. queryset = PowerFeed.objects.all()
  2285. form = forms.PowerFeedForm
  2286. class PowerFeedDeleteView(generic.ObjectDeleteView):
  2287. queryset = PowerFeed.objects.all()
  2288. class PowerFeedBulkImportView(generic.BulkImportView):
  2289. queryset = PowerFeed.objects.all()
  2290. model_form = forms.PowerFeedCSVForm
  2291. table = tables.PowerFeedTable
  2292. class PowerFeedBulkEditView(generic.BulkEditView):
  2293. queryset = PowerFeed.objects.all()
  2294. filterset = filtersets.PowerFeedFilterSet
  2295. table = tables.PowerFeedTable
  2296. form = forms.PowerFeedBulkEditForm
  2297. class PowerFeedBulkDisconnectView(BulkDisconnectView):
  2298. queryset = PowerFeed.objects.all()
  2299. class PowerFeedBulkDeleteView(generic.BulkDeleteView):
  2300. queryset = PowerFeed.objects.all()
  2301. filterset = filtersets.PowerFeedFilterSet
  2302. table = tables.PowerFeedTable