views.py 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477
  1. from django.contrib.contenttypes.models import ContentType
  2. from django.db.models import Prefetch
  3. from django.db.models.expressions import RawSQL
  4. from django.shortcuts import get_object_or_404, redirect, render
  5. from django.urls import reverse
  6. from django.utils.translation import gettext_lazy as _
  7. from circuits.models import Provider
  8. from dcim.filtersets import InterfaceFilterSet
  9. from dcim.forms import InterfaceFilterForm
  10. from dcim.models import Interface, Site
  11. from ipam.tables import VLANTranslationRuleTable
  12. from netbox.views import generic
  13. from tenancy.views import ObjectContactsView
  14. from utilities.query import count_related
  15. from utilities.tables import get_table_ordering
  16. from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
  17. from virtualization.filtersets import VMInterfaceFilterSet
  18. from virtualization.forms import VMInterfaceFilterForm
  19. from virtualization.models import VMInterface
  20. from . import filtersets, forms, tables
  21. from .choices import PrefixStatusChoices
  22. from .constants import *
  23. from .models import *
  24. from .utils import add_requested_prefixes, add_available_ipaddresses, add_available_vlans
  25. #
  26. # VRFs
  27. #
  28. @register_model_view(VRF, 'list', path='', detail=False)
  29. class VRFListView(generic.ObjectListView):
  30. queryset = VRF.objects.all()
  31. filterset = filtersets.VRFFilterSet
  32. filterset_form = forms.VRFFilterForm
  33. table = tables.VRFTable
  34. @register_model_view(VRF)
  35. class VRFView(GetRelatedModelsMixin, generic.ObjectView):
  36. queryset = VRF.objects.all()
  37. def get_extra_context(self, request, instance):
  38. import_targets_table = tables.RouteTargetTable(
  39. instance.import_targets.all(),
  40. orderable=False
  41. )
  42. export_targets_table = tables.RouteTargetTable(
  43. instance.export_targets.all(),
  44. orderable=False
  45. )
  46. return {
  47. 'related_models': self.get_related_models(request, instance, omit=[Interface, VMInterface]),
  48. 'import_targets_table': import_targets_table,
  49. 'export_targets_table': export_targets_table,
  50. }
  51. @register_model_view(VRF, 'add', detail=False)
  52. @register_model_view(VRF, 'edit')
  53. class VRFEditView(generic.ObjectEditView):
  54. queryset = VRF.objects.all()
  55. form = forms.VRFForm
  56. @register_model_view(VRF, 'delete')
  57. class VRFDeleteView(generic.ObjectDeleteView):
  58. queryset = VRF.objects.all()
  59. @register_model_view(VRF, 'bulk_import', detail=False)
  60. class VRFBulkImportView(generic.BulkImportView):
  61. queryset = VRF.objects.all()
  62. model_form = forms.VRFImportForm
  63. @register_model_view(VRF, 'bulk_edit', path='edit', detail=False)
  64. class VRFBulkEditView(generic.BulkEditView):
  65. queryset = VRF.objects.all()
  66. filterset = filtersets.VRFFilterSet
  67. table = tables.VRFTable
  68. form = forms.VRFBulkEditForm
  69. @register_model_view(VRF, 'bulk_delete', path='delete', detail=False)
  70. class VRFBulkDeleteView(generic.BulkDeleteView):
  71. queryset = VRF.objects.all()
  72. filterset = filtersets.VRFFilterSet
  73. table = tables.VRFTable
  74. #
  75. # Route targets
  76. #
  77. @register_model_view(RouteTarget, 'list', path='', detail=False)
  78. class RouteTargetListView(generic.ObjectListView):
  79. queryset = RouteTarget.objects.all()
  80. filterset = filtersets.RouteTargetFilterSet
  81. filterset_form = forms.RouteTargetFilterForm
  82. table = tables.RouteTargetTable
  83. @register_model_view(RouteTarget)
  84. class RouteTargetView(generic.ObjectView):
  85. queryset = RouteTarget.objects.all()
  86. @register_model_view(RouteTarget, 'add', detail=False)
  87. @register_model_view(RouteTarget, 'edit')
  88. class RouteTargetEditView(generic.ObjectEditView):
  89. queryset = RouteTarget.objects.all()
  90. form = forms.RouteTargetForm
  91. @register_model_view(RouteTarget, 'delete')
  92. class RouteTargetDeleteView(generic.ObjectDeleteView):
  93. queryset = RouteTarget.objects.all()
  94. @register_model_view(RouteTarget, 'bulk_import', detail=False)
  95. class RouteTargetBulkImportView(generic.BulkImportView):
  96. queryset = RouteTarget.objects.all()
  97. model_form = forms.RouteTargetImportForm
  98. @register_model_view(RouteTarget, 'bulk_edit', path='edit', detail=False)
  99. class RouteTargetBulkEditView(generic.BulkEditView):
  100. queryset = RouteTarget.objects.all()
  101. filterset = filtersets.RouteTargetFilterSet
  102. table = tables.RouteTargetTable
  103. form = forms.RouteTargetBulkEditForm
  104. @register_model_view(RouteTarget, 'bulk_delete', path='delete', detail=False)
  105. class RouteTargetBulkDeleteView(generic.BulkDeleteView):
  106. queryset = RouteTarget.objects.all()
  107. filterset = filtersets.RouteTargetFilterSet
  108. table = tables.RouteTargetTable
  109. #
  110. # RIRs
  111. #
  112. @register_model_view(RIR, 'list', path='', detail=False)
  113. class RIRListView(generic.ObjectListView):
  114. queryset = RIR.objects.annotate(
  115. aggregate_count=count_related(Aggregate, 'rir')
  116. )
  117. filterset = filtersets.RIRFilterSet
  118. filterset_form = forms.RIRFilterForm
  119. table = tables.RIRTable
  120. @register_model_view(RIR)
  121. class RIRView(GetRelatedModelsMixin, generic.ObjectView):
  122. queryset = RIR.objects.all()
  123. def get_extra_context(self, request, instance):
  124. return {
  125. 'related_models': self.get_related_models(request, instance),
  126. }
  127. @register_model_view(RIR, 'add', detail=False)
  128. @register_model_view(RIR, 'edit')
  129. class RIREditView(generic.ObjectEditView):
  130. queryset = RIR.objects.all()
  131. form = forms.RIRForm
  132. @register_model_view(RIR, 'delete')
  133. class RIRDeleteView(generic.ObjectDeleteView):
  134. queryset = RIR.objects.all()
  135. @register_model_view(RIR, 'bulk_import', detail=False)
  136. class RIRBulkImportView(generic.BulkImportView):
  137. queryset = RIR.objects.all()
  138. model_form = forms.RIRImportForm
  139. @register_model_view(RIR, 'bulk_edit', path='edit', detail=False)
  140. class RIRBulkEditView(generic.BulkEditView):
  141. queryset = RIR.objects.annotate(
  142. aggregate_count=count_related(Aggregate, 'rir')
  143. )
  144. filterset = filtersets.RIRFilterSet
  145. table = tables.RIRTable
  146. form = forms.RIRBulkEditForm
  147. @register_model_view(RIR, 'bulk_delete', path='delete', detail=False)
  148. class RIRBulkDeleteView(generic.BulkDeleteView):
  149. queryset = RIR.objects.annotate(
  150. aggregate_count=count_related(Aggregate, 'rir')
  151. )
  152. filterset = filtersets.RIRFilterSet
  153. table = tables.RIRTable
  154. #
  155. # ASN ranges
  156. #
  157. @register_model_view(ASNRange, 'list', path='', detail=False)
  158. class ASNRangeListView(generic.ObjectListView):
  159. queryset = ASNRange.objects.annotate_asn_counts()
  160. filterset = filtersets.ASNRangeFilterSet
  161. filterset_form = forms.ASNRangeFilterForm
  162. table = tables.ASNRangeTable
  163. @register_model_view(ASNRange)
  164. class ASNRangeView(generic.ObjectView):
  165. queryset = ASNRange.objects.all()
  166. @register_model_view(ASNRange, 'asns')
  167. class ASNRangeASNsView(generic.ObjectChildrenView):
  168. queryset = ASNRange.objects.all()
  169. child_model = ASN
  170. table = tables.ASNTable
  171. filterset = filtersets.ASNFilterSet
  172. filterset_form = forms.ASNFilterForm
  173. tab = ViewTab(
  174. label=_('ASNs'),
  175. badge=lambda x: x.get_child_asns().count(),
  176. permission='ipam.view_asn',
  177. weight=500
  178. )
  179. def get_children(self, request, parent):
  180. return parent.get_child_asns().restrict(request.user, 'view').annotate(
  181. site_count=count_related(Site, 'asns'),
  182. provider_count=count_related(Provider, 'asns')
  183. )
  184. @register_model_view(ASNRange, 'add', detail=False)
  185. @register_model_view(ASNRange, 'edit')
  186. class ASNRangeEditView(generic.ObjectEditView):
  187. queryset = ASNRange.objects.all()
  188. form = forms.ASNRangeForm
  189. @register_model_view(ASNRange, 'delete')
  190. class ASNRangeDeleteView(generic.ObjectDeleteView):
  191. queryset = ASNRange.objects.all()
  192. @register_model_view(ASNRange, 'bulk_import', detail=False)
  193. class ASNRangeBulkImportView(generic.BulkImportView):
  194. queryset = ASNRange.objects.all()
  195. model_form = forms.ASNRangeImportForm
  196. @register_model_view(ASNRange, 'bulk_edit', path='edit', detail=False)
  197. class ASNRangeBulkEditView(generic.BulkEditView):
  198. queryset = ASNRange.objects.annotate_asn_counts()
  199. filterset = filtersets.ASNRangeFilterSet
  200. table = tables.ASNRangeTable
  201. form = forms.ASNRangeBulkEditForm
  202. @register_model_view(ASNRange, 'bulk_delete', path='delete', detail=False)
  203. class ASNRangeBulkDeleteView(generic.BulkDeleteView):
  204. queryset = ASNRange.objects.annotate_asn_counts()
  205. filterset = filtersets.ASNRangeFilterSet
  206. table = tables.ASNRangeTable
  207. #
  208. # ASNs
  209. #
  210. @register_model_view(ASN, 'list', path='', detail=False)
  211. class ASNListView(generic.ObjectListView):
  212. queryset = ASN.objects.annotate(
  213. site_count=count_related(Site, 'asns'),
  214. provider_count=count_related(Provider, 'asns')
  215. )
  216. filterset = filtersets.ASNFilterSet
  217. filterset_form = forms.ASNFilterForm
  218. table = tables.ASNTable
  219. @register_model_view(ASN)
  220. class ASNView(GetRelatedModelsMixin, generic.ObjectView):
  221. queryset = ASN.objects.all()
  222. def get_extra_context(self, request, instance):
  223. return {
  224. 'related_models': self.get_related_models(
  225. request,
  226. instance,
  227. extra=(
  228. (Site.objects.restrict(request.user, 'view').filter(asns__in=[instance]), 'asn_id'),
  229. (Provider.objects.restrict(request.user, 'view').filter(asns__in=[instance]), 'asn_id'),
  230. ),
  231. ),
  232. }
  233. @register_model_view(ASN, 'add', detail=False)
  234. @register_model_view(ASN, 'edit')
  235. class ASNEditView(generic.ObjectEditView):
  236. queryset = ASN.objects.all()
  237. form = forms.ASNForm
  238. @register_model_view(ASN, 'delete')
  239. class ASNDeleteView(generic.ObjectDeleteView):
  240. queryset = ASN.objects.all()
  241. @register_model_view(ASN, 'bulk_import', detail=False)
  242. class ASNBulkImportView(generic.BulkImportView):
  243. queryset = ASN.objects.all()
  244. model_form = forms.ASNImportForm
  245. @register_model_view(ASN, 'bulk_edit', path='edit', detail=False)
  246. class ASNBulkEditView(generic.BulkEditView):
  247. queryset = ASN.objects.annotate(
  248. site_count=count_related(Site, 'asns')
  249. )
  250. filterset = filtersets.ASNFilterSet
  251. table = tables.ASNTable
  252. form = forms.ASNBulkEditForm
  253. @register_model_view(ASN, 'bulk_delete', path='delete', detail=False)
  254. class ASNBulkDeleteView(generic.BulkDeleteView):
  255. queryset = ASN.objects.annotate(
  256. site_count=count_related(Site, 'asns')
  257. )
  258. filterset = filtersets.ASNFilterSet
  259. table = tables.ASNTable
  260. #
  261. # Aggregates
  262. #
  263. @register_model_view(Aggregate, 'list', path='', detail=False)
  264. class AggregateListView(generic.ObjectListView):
  265. queryset = Aggregate.objects.annotate(
  266. child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
  267. )
  268. filterset = filtersets.AggregateFilterSet
  269. filterset_form = forms.AggregateFilterForm
  270. table = tables.AggregateTable
  271. @register_model_view(Aggregate)
  272. class AggregateView(generic.ObjectView):
  273. queryset = Aggregate.objects.all()
  274. @register_model_view(Aggregate, 'prefixes')
  275. class AggregatePrefixesView(generic.ObjectChildrenView):
  276. queryset = Aggregate.objects.all()
  277. child_model = Prefix
  278. table = tables.PrefixTable
  279. filterset = filtersets.PrefixFilterSet
  280. filterset_form = forms.PrefixFilterForm
  281. template_name = 'ipam/aggregate/prefixes.html'
  282. tab = ViewTab(
  283. label=_('Prefixes'),
  284. badge=lambda x: x.get_child_prefixes().count(),
  285. permission='ipam.view_prefix',
  286. weight=500
  287. )
  288. def get_children(self, request, parent):
  289. return Prefix.objects.restrict(request.user, 'view').filter(
  290. prefix__net_contained_or_equal=str(parent.prefix)
  291. ).prefetch_related('scope', 'role', 'tenant', 'tenant__group', 'vlan')
  292. def prep_table_data(self, request, queryset, parent):
  293. # Determine whether to show assigned prefixes, available prefixes, or both
  294. show_available = bool(request.GET.get('show_available', 'true') == 'true')
  295. show_assigned = bool(request.GET.get('show_assigned', 'true') == 'true')
  296. return add_requested_prefixes(parent.prefix, queryset, show_available, show_assigned)
  297. def get_extra_context(self, request, instance):
  298. return {
  299. 'bulk_querystring': f'within={instance.prefix}',
  300. 'first_available_prefix': instance.get_first_available_prefix(),
  301. 'show_available': bool(request.GET.get('show_available', 'true') == 'true'),
  302. 'show_assigned': bool(request.GET.get('show_assigned', 'true') == 'true'),
  303. }
  304. @register_model_view(Aggregate, 'add', detail=False)
  305. @register_model_view(Aggregate, 'edit')
  306. class AggregateEditView(generic.ObjectEditView):
  307. queryset = Aggregate.objects.all()
  308. form = forms.AggregateForm
  309. @register_model_view(Aggregate, 'delete')
  310. class AggregateDeleteView(generic.ObjectDeleteView):
  311. queryset = Aggregate.objects.all()
  312. @register_model_view(Aggregate, 'bulk_import', detail=False)
  313. class AggregateBulkImportView(generic.BulkImportView):
  314. queryset = Aggregate.objects.all()
  315. model_form = forms.AggregateImportForm
  316. @register_model_view(Aggregate, 'bulk_edit', path='edit', detail=False)
  317. class AggregateBulkEditView(generic.BulkEditView):
  318. queryset = Aggregate.objects.annotate(
  319. child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
  320. )
  321. filterset = filtersets.AggregateFilterSet
  322. table = tables.AggregateTable
  323. form = forms.AggregateBulkEditForm
  324. @register_model_view(Aggregate, 'bulk_delete', path='delete', detail=False)
  325. class AggregateBulkDeleteView(generic.BulkDeleteView):
  326. queryset = Aggregate.objects.annotate(
  327. child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
  328. )
  329. filterset = filtersets.AggregateFilterSet
  330. table = tables.AggregateTable
  331. @register_model_view(Aggregate, 'contacts')
  332. class AggregateContactsView(ObjectContactsView):
  333. queryset = Aggregate.objects.all()
  334. #
  335. # Prefix/VLAN roles
  336. #
  337. @register_model_view(Role, 'list', path='', detail=False)
  338. class RoleListView(generic.ObjectListView):
  339. queryset = Role.objects.annotate(
  340. prefix_count=count_related(Prefix, 'role'),
  341. iprange_count=count_related(IPRange, 'role'),
  342. vlan_count=count_related(VLAN, 'role')
  343. )
  344. filterset = filtersets.RoleFilterSet
  345. filterset_form = forms.RoleFilterForm
  346. table = tables.RoleTable
  347. @register_model_view(Role)
  348. class RoleView(GetRelatedModelsMixin, generic.ObjectView):
  349. queryset = Role.objects.all()
  350. def get_extra_context(self, request, instance):
  351. return {
  352. 'related_models': self.get_related_models(request, instance),
  353. }
  354. @register_model_view(Role, 'add', detail=False)
  355. @register_model_view(Role, 'edit')
  356. class RoleEditView(generic.ObjectEditView):
  357. queryset = Role.objects.all()
  358. form = forms.RoleForm
  359. @register_model_view(Role, 'delete')
  360. class RoleDeleteView(generic.ObjectDeleteView):
  361. queryset = Role.objects.all()
  362. @register_model_view(Role, 'bulk_import', detail=False)
  363. class RoleBulkImportView(generic.BulkImportView):
  364. queryset = Role.objects.all()
  365. model_form = forms.RoleImportForm
  366. @register_model_view(Role, 'bulk_edit', path='edit', detail=False)
  367. class RoleBulkEditView(generic.BulkEditView):
  368. queryset = Role.objects.all()
  369. filterset = filtersets.RoleFilterSet
  370. table = tables.RoleTable
  371. form = forms.RoleBulkEditForm
  372. @register_model_view(Role, 'bulk_delete', path='delete', detail=False)
  373. class RoleBulkDeleteView(generic.BulkDeleteView):
  374. queryset = Role.objects.all()
  375. filterset = filtersets.RoleFilterSet
  376. table = tables.RoleTable
  377. #
  378. # Prefixes
  379. #
  380. @register_model_view(Prefix, 'list', path='', detail=False)
  381. class PrefixListView(generic.ObjectListView):
  382. queryset = Prefix.objects.all()
  383. filterset = filtersets.PrefixFilterSet
  384. filterset_form = forms.PrefixFilterForm
  385. table = tables.PrefixTable
  386. template_name = 'ipam/prefix_list.html'
  387. @register_model_view(Prefix)
  388. class PrefixView(generic.ObjectView):
  389. queryset = Prefix.objects.all()
  390. def get_extra_context(self, request, instance):
  391. try:
  392. aggregate = Aggregate.objects.restrict(request.user, 'view').get(
  393. prefix__net_contains_or_equals=str(instance.prefix)
  394. )
  395. except Aggregate.DoesNotExist:
  396. aggregate = None
  397. # Parent prefixes table
  398. parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
  399. Q(vrf=instance.vrf) | Q(vrf__isnull=True, status=PrefixStatusChoices.STATUS_CONTAINER)
  400. ).filter(
  401. prefix__net_contains=str(instance.prefix)
  402. ).prefetch_related(
  403. 'scope', 'role', 'tenant', 'vlan',
  404. )
  405. parent_prefix_table = tables.PrefixTable(
  406. list(parent_prefixes),
  407. exclude=('vrf', 'utilization'),
  408. orderable=False
  409. )
  410. # Duplicate prefixes table
  411. duplicate_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
  412. vrf=instance.vrf, prefix=str(instance.prefix)
  413. ).exclude(
  414. pk=instance.pk
  415. ).prefetch_related(
  416. 'scope', 'role', 'tenant', 'vlan',
  417. )
  418. duplicate_prefix_table = tables.PrefixTable(
  419. list(duplicate_prefixes),
  420. exclude=('vrf', 'utilization'),
  421. orderable=False
  422. )
  423. return {
  424. 'aggregate': aggregate,
  425. 'parent_prefix_table': parent_prefix_table,
  426. 'duplicate_prefix_table': duplicate_prefix_table,
  427. }
  428. @register_model_view(Prefix, 'prefixes')
  429. class PrefixPrefixesView(generic.ObjectChildrenView):
  430. queryset = Prefix.objects.all()
  431. child_model = Prefix
  432. table = tables.PrefixTable
  433. filterset = filtersets.PrefixFilterSet
  434. filterset_form = forms.PrefixFilterForm
  435. template_name = 'ipam/prefix/prefixes.html'
  436. tab = ViewTab(
  437. label=_('Child Prefixes'),
  438. badge=lambda x: x.get_child_prefixes().count(),
  439. permission='ipam.view_prefix',
  440. weight=500
  441. )
  442. def get_children(self, request, parent):
  443. return parent.get_child_prefixes().restrict(request.user, 'view').prefetch_related(
  444. 'scope', 'vrf', 'vlan', 'role', 'tenant', 'tenant__group'
  445. )
  446. def prep_table_data(self, request, queryset, parent):
  447. # Determine whether to show assigned prefixes, available prefixes, or both
  448. show_available = bool(request.GET.get('show_available', 'true') == 'true')
  449. show_assigned = bool(request.GET.get('show_assigned', 'true') == 'true')
  450. return add_requested_prefixes(parent.prefix, queryset, show_available, show_assigned)
  451. def get_extra_context(self, request, instance):
  452. return {
  453. 'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&within={instance.prefix}",
  454. 'first_available_prefix': instance.get_first_available_prefix(),
  455. 'show_available': bool(request.GET.get('show_available', 'true') == 'true'),
  456. 'show_assigned': bool(request.GET.get('show_assigned', 'true') == 'true'),
  457. }
  458. @register_model_view(Prefix, 'ipranges', path='ip-ranges')
  459. class PrefixIPRangesView(generic.ObjectChildrenView):
  460. queryset = Prefix.objects.all()
  461. child_model = IPRange
  462. table = tables.IPRangeTable
  463. filterset = filtersets.IPRangeFilterSet
  464. filterset_form = forms.IPRangeFilterForm
  465. template_name = 'ipam/prefix/ip_ranges.html'
  466. tab = ViewTab(
  467. label=_('Child Ranges'),
  468. badge=lambda x: x.get_child_ranges().count(),
  469. permission='ipam.view_iprange',
  470. weight=600
  471. )
  472. def get_children(self, request, parent):
  473. return parent.get_child_ranges().restrict(request.user, 'view').prefetch_related(
  474. 'tenant__group',
  475. )
  476. def get_extra_context(self, request, instance):
  477. return {
  478. 'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&parent={instance.prefix}",
  479. 'first_available_ip': instance.get_first_available_ip(),
  480. }
  481. @register_model_view(Prefix, 'ipaddresses', path='ip-addresses')
  482. class PrefixIPAddressesView(generic.ObjectChildrenView):
  483. queryset = Prefix.objects.all()
  484. child_model = IPAddress
  485. table = tables.IPAddressTable
  486. filterset = filtersets.IPAddressFilterSet
  487. filterset_form = forms.IPAddressFilterForm
  488. template_name = 'ipam/prefix/ip_addresses.html'
  489. tab = ViewTab(
  490. label=_('IP Addresses'),
  491. badge=lambda x: x.get_child_ips().count(),
  492. permission='ipam.view_ipaddress',
  493. weight=700
  494. )
  495. def get_children(self, request, parent):
  496. return parent.get_child_ips().restrict(request.user, 'view').prefetch_related('vrf', 'tenant', 'tenant__group')
  497. def prep_table_data(self, request, queryset, parent):
  498. if not request.GET.get('q') and not get_table_ordering(request, self.table):
  499. return add_available_ipaddresses(parent.prefix, queryset, parent.is_pool)
  500. return queryset
  501. def get_extra_context(self, request, instance):
  502. return {
  503. 'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&parent={instance.prefix}",
  504. 'first_available_ip': instance.get_first_available_ip(),
  505. }
  506. @register_model_view(Prefix, 'add', detail=False)
  507. @register_model_view(Prefix, 'edit')
  508. class PrefixEditView(generic.ObjectEditView):
  509. queryset = Prefix.objects.all()
  510. form = forms.PrefixForm
  511. @register_model_view(Prefix, 'delete')
  512. class PrefixDeleteView(generic.ObjectDeleteView):
  513. queryset = Prefix.objects.all()
  514. @register_model_view(Prefix, 'bulk_import', detail=False)
  515. class PrefixBulkImportView(generic.BulkImportView):
  516. queryset = Prefix.objects.all()
  517. model_form = forms.PrefixImportForm
  518. @register_model_view(Prefix, 'bulk_edit', path='edit', detail=False)
  519. class PrefixBulkEditView(generic.BulkEditView):
  520. queryset = Prefix.objects.prefetch_related('vrf__tenant')
  521. filterset = filtersets.PrefixFilterSet
  522. table = tables.PrefixTable
  523. form = forms.PrefixBulkEditForm
  524. @register_model_view(Prefix, 'bulk_delete', path='delete', detail=False)
  525. class PrefixBulkDeleteView(generic.BulkDeleteView):
  526. queryset = Prefix.objects.prefetch_related('vrf__tenant')
  527. filterset = filtersets.PrefixFilterSet
  528. table = tables.PrefixTable
  529. @register_model_view(Prefix, 'contacts')
  530. class PrefixContactsView(ObjectContactsView):
  531. queryset = Prefix.objects.all()
  532. #
  533. # IP Ranges
  534. #
  535. @register_model_view(IPRange, 'list', path='', detail=False)
  536. class IPRangeListView(generic.ObjectListView):
  537. queryset = IPRange.objects.all()
  538. filterset = filtersets.IPRangeFilterSet
  539. filterset_form = forms.IPRangeFilterForm
  540. table = tables.IPRangeTable
  541. @register_model_view(IPRange)
  542. class IPRangeView(generic.ObjectView):
  543. queryset = IPRange.objects.all()
  544. def get_extra_context(self, request, instance):
  545. # Parent prefixes table
  546. parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
  547. Q(prefix__net_contains_or_equals=str(instance.start_address.ip)),
  548. Q(prefix__net_contains_or_equals=str(instance.end_address.ip)),
  549. vrf=instance.vrf
  550. ).prefetch_related(
  551. 'scope', 'role', 'tenant', 'vlan', 'role'
  552. )
  553. parent_prefixes_table = tables.PrefixTable(
  554. list(parent_prefixes),
  555. exclude=('vrf', 'utilization'),
  556. orderable=False
  557. )
  558. return {
  559. 'parent_prefixes_table': parent_prefixes_table,
  560. }
  561. @register_model_view(IPRange, 'ipaddresses', path='ip-addresses')
  562. class IPRangeIPAddressesView(generic.ObjectChildrenView):
  563. queryset = IPRange.objects.all()
  564. child_model = IPAddress
  565. table = tables.IPAddressTable
  566. filterset = filtersets.IPAddressFilterSet
  567. filterset_form = forms.IPRangeFilterForm
  568. template_name = 'ipam/iprange/ip_addresses.html'
  569. tab = ViewTab(
  570. label=_('IP Addresses'),
  571. badge=lambda x: x.get_child_ips().count(),
  572. permission='ipam.view_ipaddress',
  573. weight=500
  574. )
  575. def get_children(self, request, parent):
  576. return parent.get_child_ips().restrict(request.user, 'view')
  577. @register_model_view(IPRange, 'add', detail=False)
  578. @register_model_view(IPRange, 'edit')
  579. class IPRangeEditView(generic.ObjectEditView):
  580. queryset = IPRange.objects.all()
  581. form = forms.IPRangeForm
  582. @register_model_view(IPRange, 'delete')
  583. class IPRangeDeleteView(generic.ObjectDeleteView):
  584. queryset = IPRange.objects.all()
  585. @register_model_view(IPRange, 'bulk_import', detail=False)
  586. class IPRangeBulkImportView(generic.BulkImportView):
  587. queryset = IPRange.objects.all()
  588. model_form = forms.IPRangeImportForm
  589. @register_model_view(IPRange, 'bulk_edit', path='edit', detail=False)
  590. class IPRangeBulkEditView(generic.BulkEditView):
  591. queryset = IPRange.objects.all()
  592. filterset = filtersets.IPRangeFilterSet
  593. table = tables.IPRangeTable
  594. form = forms.IPRangeBulkEditForm
  595. @register_model_view(IPRange, 'bulk_delete', path='delete', detail=False)
  596. class IPRangeBulkDeleteView(generic.BulkDeleteView):
  597. queryset = IPRange.objects.all()
  598. filterset = filtersets.IPRangeFilterSet
  599. table = tables.IPRangeTable
  600. @register_model_view(IPRange, 'contacts')
  601. class IPRangeContactsView(ObjectContactsView):
  602. queryset = IPRange.objects.all()
  603. #
  604. # IP addresses
  605. #
  606. @register_model_view(IPAddress, 'list', path='', detail=False)
  607. class IPAddressListView(generic.ObjectListView):
  608. queryset = IPAddress.objects.all()
  609. filterset = filtersets.IPAddressFilterSet
  610. filterset_form = forms.IPAddressFilterForm
  611. table = tables.IPAddressTable
  612. @register_model_view(IPAddress)
  613. class IPAddressView(generic.ObjectView):
  614. queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
  615. def get_extra_context(self, request, instance):
  616. # Parent prefixes table
  617. parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
  618. vrf=instance.vrf,
  619. prefix__net_contains_or_equals=str(instance.address.ip)
  620. ).prefetch_related(
  621. 'scope', 'role'
  622. )
  623. parent_prefixes_table = tables.PrefixTable(
  624. list(parent_prefixes),
  625. exclude=('vrf', 'utilization'),
  626. orderable=False
  627. )
  628. # Duplicate IPs table
  629. duplicate_ips = IPAddress.objects.restrict(request.user, 'view').filter(
  630. vrf=instance.vrf,
  631. address=str(instance.address)
  632. ).exclude(
  633. pk=instance.pk
  634. ).prefetch_related(
  635. 'nat_inside'
  636. )
  637. # Exclude anycast IPs if this IP is anycast
  638. if instance.role == IPAddressRoleChoices.ROLE_ANYCAST:
  639. duplicate_ips = duplicate_ips.exclude(role=IPAddressRoleChoices.ROLE_ANYCAST)
  640. # Limit to a maximum of 10 duplicates displayed here
  641. duplicate_ips_table = tables.IPAddressTable(duplicate_ips[:10], orderable=False)
  642. return {
  643. 'parent_prefixes_table': parent_prefixes_table,
  644. 'duplicate_ips_table': duplicate_ips_table,
  645. }
  646. @register_model_view(IPAddress, 'add', detail=False)
  647. @register_model_view(IPAddress, 'edit')
  648. class IPAddressEditView(generic.ObjectEditView):
  649. queryset = IPAddress.objects.all()
  650. form = forms.IPAddressForm
  651. template_name = 'ipam/ipaddress_edit.html'
  652. def alter_object(self, obj, request, url_args, url_kwargs):
  653. if 'interface' in request.GET:
  654. try:
  655. obj.assigned_object = Interface.objects.get(pk=request.GET['interface'])
  656. except (ValueError, Interface.DoesNotExist):
  657. pass
  658. elif 'vminterface' in request.GET:
  659. try:
  660. obj.assigned_object = VMInterface.objects.get(pk=request.GET['vminterface'])
  661. except (ValueError, VMInterface.DoesNotExist):
  662. pass
  663. elif 'fhrpgroup' in request.GET:
  664. try:
  665. obj.assigned_object = FHRPGroup.objects.get(pk=request.GET['fhrpgroup'])
  666. except (ValueError, FHRPGroup.DoesNotExist):
  667. pass
  668. return obj
  669. # TODO: Standardize or remove this view
  670. @register_model_view(IPAddress, 'assign', path='assign', detail=False)
  671. class IPAddressAssignView(generic.ObjectView):
  672. """
  673. Search for IPAddresses to be assigned to an Interface.
  674. """
  675. queryset = IPAddress.objects.all()
  676. def dispatch(self, request, *args, **kwargs):
  677. # Redirect user if an interface has not been provided
  678. if 'interface' not in request.GET and 'vminterface' not in request.GET:
  679. return redirect('ipam:ipaddress_add')
  680. return super().dispatch(request, *args, **kwargs)
  681. def get(self, request):
  682. form = forms.IPAddressAssignForm()
  683. return render(request, 'ipam/ipaddress_assign.html', {
  684. 'form': form,
  685. 'return_url': request.GET.get('return_url', ''),
  686. })
  687. def post(self, request):
  688. form = forms.IPAddressAssignForm(request.POST)
  689. table = None
  690. if form.is_valid():
  691. addresses = self.queryset.prefetch_related('vrf', 'tenant')
  692. # Limit to 100 results
  693. addresses = filtersets.IPAddressFilterSet(request.POST, addresses).qs[:100]
  694. table = tables.IPAddressAssignTable(addresses)
  695. return render(request, 'ipam/ipaddress_assign.html', {
  696. 'form': form,
  697. 'table': table,
  698. 'return_url': request.GET.get('return_url'),
  699. })
  700. @register_model_view(IPAddress, 'delete')
  701. class IPAddressDeleteView(generic.ObjectDeleteView):
  702. queryset = IPAddress.objects.all()
  703. @register_model_view(IPAddress, 'bulk_add', path='bulk-add', detail=False)
  704. class IPAddressBulkCreateView(generic.BulkCreateView):
  705. queryset = IPAddress.objects.all()
  706. form = forms.IPAddressBulkCreateForm
  707. model_form = forms.IPAddressBulkAddForm
  708. pattern_target = 'address'
  709. template_name = 'ipam/ipaddress_bulk_add.html'
  710. @register_model_view(IPAddress, 'bulk_import', detail=False)
  711. class IPAddressBulkImportView(generic.BulkImportView):
  712. queryset = IPAddress.objects.all()
  713. model_form = forms.IPAddressImportForm
  714. @register_model_view(IPAddress, 'bulk_edit', path='edit', detail=False)
  715. class IPAddressBulkEditView(generic.BulkEditView):
  716. queryset = IPAddress.objects.prefetch_related('vrf__tenant')
  717. filterset = filtersets.IPAddressFilterSet
  718. table = tables.IPAddressTable
  719. form = forms.IPAddressBulkEditForm
  720. @register_model_view(IPAddress, 'bulk_delete', path='delete', detail=False)
  721. class IPAddressBulkDeleteView(generic.BulkDeleteView):
  722. queryset = IPAddress.objects.prefetch_related('vrf__tenant')
  723. filterset = filtersets.IPAddressFilterSet
  724. table = tables.IPAddressTable
  725. @register_model_view(IPAddress, 'related_ips', path='related-ip-addresses')
  726. class IPAddressRelatedIPsView(generic.ObjectChildrenView):
  727. queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
  728. child_model = IPAddress
  729. table = tables.IPAddressTable
  730. filterset = filtersets.IPAddressFilterSet
  731. filterset_form = forms.IPAddressFilterForm
  732. tab = ViewTab(
  733. label=_('Related IPs'),
  734. badge=lambda x: x.get_related_ips().count(),
  735. weight=500,
  736. hide_if_empty=True,
  737. )
  738. def get_children(self, request, parent):
  739. return parent.get_related_ips().restrict(request.user, 'view')
  740. @register_model_view(IPAddress, 'contacts')
  741. class IPAddressContactsView(ObjectContactsView):
  742. queryset = IPAddress.objects.all()
  743. #
  744. # VLAN groups
  745. #
  746. @register_model_view(VLANGroup, 'list', path='', detail=False)
  747. class VLANGroupListView(generic.ObjectListView):
  748. queryset = VLANGroup.objects.annotate_utilization()
  749. filterset = filtersets.VLANGroupFilterSet
  750. filterset_form = forms.VLANGroupFilterForm
  751. table = tables.VLANGroupTable
  752. @register_model_view(VLANGroup)
  753. class VLANGroupView(GetRelatedModelsMixin, generic.ObjectView):
  754. queryset = VLANGroup.objects.annotate_utilization()
  755. def get_extra_context(self, request, instance):
  756. return {
  757. 'related_models': self.get_related_models(request, instance),
  758. }
  759. @register_model_view(VLANGroup, 'add', detail=False)
  760. @register_model_view(VLANGroup, 'edit')
  761. class VLANGroupEditView(generic.ObjectEditView):
  762. queryset = VLANGroup.objects.all()
  763. form = forms.VLANGroupForm
  764. @register_model_view(VLANGroup, 'delete')
  765. class VLANGroupDeleteView(generic.ObjectDeleteView):
  766. queryset = VLANGroup.objects.all()
  767. @register_model_view(VLANGroup, 'bulk_import', detail=False)
  768. class VLANGroupBulkImportView(generic.BulkImportView):
  769. queryset = VLANGroup.objects.all()
  770. model_form = forms.VLANGroupImportForm
  771. @register_model_view(VLANGroup, 'bulk_edit', path='edit', detail=False)
  772. class VLANGroupBulkEditView(generic.BulkEditView):
  773. queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
  774. filterset = filtersets.VLANGroupFilterSet
  775. table = tables.VLANGroupTable
  776. form = forms.VLANGroupBulkEditForm
  777. @register_model_view(VLANGroup, 'bulk_delete', path='delete', detail=False)
  778. class VLANGroupBulkDeleteView(generic.BulkDeleteView):
  779. queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
  780. filterset = filtersets.VLANGroupFilterSet
  781. table = tables.VLANGroupTable
  782. @register_model_view(VLANGroup, 'vlans')
  783. class VLANGroupVLANsView(generic.ObjectChildrenView):
  784. queryset = VLANGroup.objects.all()
  785. child_model = VLAN
  786. table = tables.VLANTable
  787. filterset = filtersets.VLANFilterSet
  788. filterset_form = forms.VLANFilterForm
  789. tab = ViewTab(
  790. label=_('VLANs'),
  791. badge=lambda x: x.get_child_vlans().count(),
  792. permission='ipam.view_vlan',
  793. weight=500
  794. )
  795. def get_children(self, request, parent):
  796. return parent.get_child_vlans().restrict(request.user, 'view').prefetch_related(
  797. Prefetch('prefixes', queryset=Prefix.objects.restrict(request.user)),
  798. 'tenant', 'site', 'role',
  799. )
  800. def prep_table_data(self, request, queryset, parent):
  801. if not get_table_ordering(request, self.table):
  802. return add_available_vlans(queryset, parent)
  803. return queryset
  804. #
  805. # VLAN Translation Policies
  806. #
  807. @register_model_view(VLANTranslationPolicy, 'list', path='', detail=False)
  808. class VLANTranslationPolicyListView(generic.ObjectListView):
  809. queryset = VLANTranslationPolicy.objects.annotate(
  810. rule_count=count_related(VLANTranslationRule, 'policy'),
  811. )
  812. filterset = filtersets.VLANTranslationPolicyFilterSet
  813. filterset_form = forms.VLANTranslationPolicyFilterForm
  814. table = tables.VLANTranslationPolicyTable
  815. @register_model_view(VLANTranslationPolicy)
  816. class VLANTranslationPolicyView(GetRelatedModelsMixin, generic.ObjectView):
  817. queryset = VLANTranslationPolicy.objects.all()
  818. def get_extra_context(self, request, instance):
  819. vlan_translation_table = VLANTranslationRuleTable(
  820. data=instance.rules.all(),
  821. orderable=False
  822. )
  823. return {
  824. 'vlan_translation_table': vlan_translation_table,
  825. }
  826. @register_model_view(VLANTranslationPolicy, 'add', detail=False)
  827. @register_model_view(VLANTranslationPolicy, 'edit')
  828. class VLANTranslationPolicyEditView(generic.ObjectEditView):
  829. queryset = VLANTranslationPolicy.objects.all()
  830. form = forms.VLANTranslationPolicyForm
  831. @register_model_view(VLANTranslationPolicy, 'delete')
  832. class VLANTranslationPolicyDeleteView(generic.ObjectDeleteView):
  833. queryset = VLANTranslationPolicy.objects.all()
  834. @register_model_view(VLANTranslationPolicy, 'bulk_import', detail=False)
  835. class VLANTranslationPolicyBulkImportView(generic.BulkImportView):
  836. queryset = VLANTranslationPolicy.objects.all()
  837. model_form = forms.VLANTranslationPolicyImportForm
  838. @register_model_view(VLANTranslationPolicy, 'bulk_edit', path='edit', detail=False)
  839. class VLANTranslationPolicyBulkEditView(generic.BulkEditView):
  840. queryset = VLANTranslationPolicy.objects.all()
  841. filterset = filtersets.VLANTranslationPolicyFilterSet
  842. table = tables.VLANTranslationPolicyTable
  843. form = forms.VLANTranslationPolicyBulkEditForm
  844. @register_model_view(VLANTranslationPolicy, 'bulk_delete', path='delete', detail=False)
  845. class VLANTranslationPolicyBulkDeleteView(generic.BulkDeleteView):
  846. queryset = VLANTranslationPolicy.objects.all()
  847. filterset = filtersets.VLANTranslationPolicyFilterSet
  848. table = tables.VLANTranslationPolicyTable
  849. #
  850. # VLAN Translation Rules
  851. #
  852. @register_model_view(VLANTranslationRule, 'list', path='', detail=False)
  853. class VLANTranslationRuleListView(generic.ObjectListView):
  854. queryset = VLANTranslationRule.objects.all()
  855. filterset = filtersets.VLANTranslationRuleFilterSet
  856. filterset_form = forms.VLANTranslationRuleFilterForm
  857. table = tables.VLANTranslationRuleTable
  858. @register_model_view(VLANTranslationRule)
  859. class VLANTranslationRuleView(GetRelatedModelsMixin, generic.ObjectView):
  860. queryset = VLANTranslationRule.objects.all()
  861. def get_extra_context(self, request, instance):
  862. return {
  863. 'related_models': self.get_related_models(request, instance),
  864. }
  865. @register_model_view(VLANTranslationRule, 'add', detail=False)
  866. @register_model_view(VLANTranslationRule, 'edit')
  867. class VLANTranslationRuleEditView(generic.ObjectEditView):
  868. queryset = VLANTranslationRule.objects.all()
  869. form = forms.VLANTranslationRuleForm
  870. @register_model_view(VLANTranslationRule, 'delete')
  871. class VLANTranslationRuleDeleteView(generic.ObjectDeleteView):
  872. queryset = VLANTranslationRule.objects.all()
  873. @register_model_view(VLANTranslationRule, 'bulk_import', detail=False)
  874. class VLANTranslationRuleBulkImportView(generic.BulkImportView):
  875. queryset = VLANTranslationRule.objects.all()
  876. model_form = forms.VLANTranslationRuleImportForm
  877. @register_model_view(VLANTranslationRule, 'bulk_edit', path='edit', detail=False)
  878. class VLANTranslationRuleBulkEditView(generic.BulkEditView):
  879. queryset = VLANTranslationRule.objects.all()
  880. filterset = filtersets.VLANTranslationRuleFilterSet
  881. table = tables.VLANTranslationRuleTable
  882. form = forms.VLANTranslationRuleBulkEditForm
  883. @register_model_view(VLANTranslationRule, 'bulk_delete', path='delete', detail=False)
  884. class VLANTranslationRuleBulkDeleteView(generic.BulkDeleteView):
  885. queryset = VLANTranslationRule.objects.all()
  886. filterset = filtersets.VLANTranslationRuleFilterSet
  887. table = tables.VLANTranslationRuleTable
  888. #
  889. # FHRP groups
  890. #
  891. @register_model_view(FHRPGroup, 'list', path='', detail=False)
  892. class FHRPGroupListView(generic.ObjectListView):
  893. queryset = FHRPGroup.objects.annotate(
  894. member_count=count_related(FHRPGroupAssignment, 'group')
  895. )
  896. filterset = filtersets.FHRPGroupFilterSet
  897. filterset_form = forms.FHRPGroupFilterForm
  898. table = tables.FHRPGroupTable
  899. @register_model_view(FHRPGroup)
  900. class FHRPGroupView(generic.ObjectView):
  901. queryset = FHRPGroup.objects.all()
  902. def get_extra_context(self, request, instance):
  903. # Get assigned interfaces
  904. members_table = tables.FHRPGroupAssignmentTable(
  905. data=FHRPGroupAssignment.objects.restrict(request.user, 'view').filter(group=instance),
  906. orderable=False
  907. )
  908. members_table.columns.hide('group')
  909. return {
  910. 'members_table': members_table,
  911. 'member_count': FHRPGroupAssignment.objects.filter(group=instance).count(),
  912. }
  913. @register_model_view(FHRPGroup, 'add', detail=False)
  914. @register_model_view(FHRPGroup, 'edit')
  915. class FHRPGroupEditView(generic.ObjectEditView):
  916. queryset = FHRPGroup.objects.all()
  917. form = forms.FHRPGroupForm
  918. def get_return_url(self, request, obj=None):
  919. return_url = super().get_return_url(request, obj)
  920. # If we're redirecting the user to the FHRPGroupAssignment creation form,
  921. # initialize the group field with the FHRPGroup we just saved.
  922. if return_url.startswith(reverse('ipam:fhrpgroupassignment_add')):
  923. return_url += f'&group={obj.pk}'
  924. return return_url
  925. def alter_object(self, obj, request, url_args, url_kwargs):
  926. # Workaround to solve #10719. Capture the current user on the FHRPGroup instance so that
  927. # we can evaluate permissions during the creation of a new IPAddress within the form.
  928. obj._user = request.user
  929. return obj
  930. @register_model_view(FHRPGroup, 'delete')
  931. class FHRPGroupDeleteView(generic.ObjectDeleteView):
  932. queryset = FHRPGroup.objects.all()
  933. @register_model_view(FHRPGroup, 'bulk_import', detail=False)
  934. class FHRPGroupBulkImportView(generic.BulkImportView):
  935. queryset = FHRPGroup.objects.all()
  936. model_form = forms.FHRPGroupImportForm
  937. @register_model_view(FHRPGroup, 'bulk_edit', path='edit', detail=False)
  938. class FHRPGroupBulkEditView(generic.BulkEditView):
  939. queryset = FHRPGroup.objects.all()
  940. filterset = filtersets.FHRPGroupFilterSet
  941. table = tables.FHRPGroupTable
  942. form = forms.FHRPGroupBulkEditForm
  943. @register_model_view(FHRPGroup, 'bulk_delete', path='delete', detail=False)
  944. class FHRPGroupBulkDeleteView(generic.BulkDeleteView):
  945. queryset = FHRPGroup.objects.all()
  946. filterset = filtersets.FHRPGroupFilterSet
  947. table = tables.FHRPGroupTable
  948. #
  949. # FHRP group assignments
  950. #
  951. @register_model_view(FHRPGroupAssignment, 'add', detail=False)
  952. @register_model_view(FHRPGroupAssignment, 'edit')
  953. class FHRPGroupAssignmentEditView(generic.ObjectEditView):
  954. queryset = FHRPGroupAssignment.objects.all()
  955. form = forms.FHRPGroupAssignmentForm
  956. def alter_object(self, instance, request, args, kwargs):
  957. if not instance.pk:
  958. # Assign the interface based on URL kwargs
  959. content_type = get_object_or_404(ContentType, pk=request.GET.get('interface_type'))
  960. instance.interface = get_object_or_404(content_type.model_class(), pk=request.GET.get('interface_id'))
  961. return instance
  962. def get_extra_addanother_params(self, request):
  963. return {
  964. 'interface_type': request.GET.get('interface_type'),
  965. 'interface_id': request.GET.get('interface_id'),
  966. }
  967. @register_model_view(FHRPGroupAssignment, 'delete')
  968. class FHRPGroupAssignmentDeleteView(generic.ObjectDeleteView):
  969. queryset = FHRPGroupAssignment.objects.all()
  970. #
  971. # VLANs
  972. #
  973. @register_model_view(VLAN, 'list', path='', detail=False)
  974. class VLANListView(generic.ObjectListView):
  975. queryset = VLAN.objects.all()
  976. filterset = filtersets.VLANFilterSet
  977. filterset_form = forms.VLANFilterForm
  978. table = tables.VLANTable
  979. @register_model_view(VLAN)
  980. class VLANView(generic.ObjectView):
  981. queryset = VLAN.objects.all()
  982. def get_extra_context(self, request, instance):
  983. prefixes = Prefix.objects.restrict(request.user, 'view').filter(vlan=instance).prefetch_related(
  984. 'vrf', 'scope', 'role', 'tenant'
  985. )
  986. prefix_table = tables.PrefixTable(list(prefixes), exclude=('vlan', 'utilization'), orderable=False)
  987. return {
  988. 'prefix_table': prefix_table,
  989. }
  990. @register_model_view(VLAN, 'interfaces')
  991. class VLANInterfacesView(generic.ObjectChildrenView):
  992. queryset = VLAN.objects.all()
  993. child_model = Interface
  994. table = tables.VLANDevicesTable
  995. filterset = InterfaceFilterSet
  996. filterset_form = InterfaceFilterForm
  997. tab = ViewTab(
  998. label=_('Device Interfaces'),
  999. badge=lambda x: x.get_interfaces().count(),
  1000. permission='dcim.view_interface',
  1001. weight=500
  1002. )
  1003. def get_children(self, request, parent):
  1004. return parent.get_interfaces().restrict(request.user, 'view')
  1005. @register_model_view(VLAN, 'vminterfaces', path='vm-interfaces')
  1006. class VLANVMInterfacesView(generic.ObjectChildrenView):
  1007. queryset = VLAN.objects.all()
  1008. child_model = VMInterface
  1009. table = tables.VLANVirtualMachinesTable
  1010. filterset = VMInterfaceFilterSet
  1011. filterset_form = VMInterfaceFilterForm
  1012. tab = ViewTab(
  1013. label=_('VM Interfaces'),
  1014. badge=lambda x: x.get_vminterfaces().count(),
  1015. permission='virtualization.view_vminterface',
  1016. weight=510
  1017. )
  1018. def get_children(self, request, parent):
  1019. return parent.get_vminterfaces().restrict(request.user, 'view')
  1020. @register_model_view(VLAN, 'add', detail=False)
  1021. @register_model_view(VLAN, 'edit')
  1022. class VLANEditView(generic.ObjectEditView):
  1023. queryset = VLAN.objects.all()
  1024. form = forms.VLANForm
  1025. template_name = 'ipam/vlan_edit.html'
  1026. @register_model_view(VLAN, 'delete')
  1027. class VLANDeleteView(generic.ObjectDeleteView):
  1028. queryset = VLAN.objects.all()
  1029. @register_model_view(VLAN, 'bulk_import', detail=False)
  1030. class VLANBulkImportView(generic.BulkImportView):
  1031. queryset = VLAN.objects.all()
  1032. model_form = forms.VLANImportForm
  1033. @register_model_view(VLAN, 'bulk_edit', path='edit', detail=False)
  1034. class VLANBulkEditView(generic.BulkEditView):
  1035. queryset = VLAN.objects.all()
  1036. filterset = filtersets.VLANFilterSet
  1037. table = tables.VLANTable
  1038. form = forms.VLANBulkEditForm
  1039. @register_model_view(VLAN, 'bulk_delete', path='delete', detail=False)
  1040. class VLANBulkDeleteView(generic.BulkDeleteView):
  1041. queryset = VLAN.objects.all()
  1042. filterset = filtersets.VLANFilterSet
  1043. table = tables.VLANTable
  1044. #
  1045. # Service templates
  1046. #
  1047. @register_model_view(ServiceTemplate, 'list', path='', detail=False)
  1048. class ServiceTemplateListView(generic.ObjectListView):
  1049. queryset = ServiceTemplate.objects.all()
  1050. filterset = filtersets.ServiceTemplateFilterSet
  1051. filterset_form = forms.ServiceTemplateFilterForm
  1052. table = tables.ServiceTemplateTable
  1053. @register_model_view(ServiceTemplate)
  1054. class ServiceTemplateView(generic.ObjectView):
  1055. queryset = ServiceTemplate.objects.all()
  1056. @register_model_view(ServiceTemplate, 'add', detail=False)
  1057. @register_model_view(ServiceTemplate, 'edit')
  1058. class ServiceTemplateEditView(generic.ObjectEditView):
  1059. queryset = ServiceTemplate.objects.all()
  1060. form = forms.ServiceTemplateForm
  1061. @register_model_view(ServiceTemplate, 'delete')
  1062. class ServiceTemplateDeleteView(generic.ObjectDeleteView):
  1063. queryset = ServiceTemplate.objects.all()
  1064. @register_model_view(ServiceTemplate, 'bulk_import', detail=False)
  1065. class ServiceTemplateBulkImportView(generic.BulkImportView):
  1066. queryset = ServiceTemplate.objects.all()
  1067. model_form = forms.ServiceTemplateImportForm
  1068. @register_model_view(ServiceTemplate, 'bulk_edit', path='edit', detail=False)
  1069. class ServiceTemplateBulkEditView(generic.BulkEditView):
  1070. queryset = ServiceTemplate.objects.all()
  1071. filterset = filtersets.ServiceTemplateFilterSet
  1072. table = tables.ServiceTemplateTable
  1073. form = forms.ServiceTemplateBulkEditForm
  1074. @register_model_view(ServiceTemplate, 'bulk_delete', path='delete', detail=False)
  1075. class ServiceTemplateBulkDeleteView(generic.BulkDeleteView):
  1076. queryset = ServiceTemplate.objects.all()
  1077. filterset = filtersets.ServiceTemplateFilterSet
  1078. table = tables.ServiceTemplateTable
  1079. #
  1080. # Services
  1081. #
  1082. @register_model_view(Service, 'list', path='', detail=False)
  1083. class ServiceListView(generic.ObjectListView):
  1084. queryset = Service.objects.prefetch_related('device', 'virtual_machine')
  1085. filterset = filtersets.ServiceFilterSet
  1086. filterset_form = forms.ServiceFilterForm
  1087. table = tables.ServiceTable
  1088. @register_model_view(Service)
  1089. class ServiceView(generic.ObjectView):
  1090. queryset = Service.objects.all()
  1091. @register_model_view(Service, 'add', detail=False)
  1092. class ServiceCreateView(generic.ObjectEditView):
  1093. queryset = Service.objects.all()
  1094. form = forms.ServiceCreateForm
  1095. @register_model_view(Service, 'edit')
  1096. class ServiceEditView(generic.ObjectEditView):
  1097. queryset = Service.objects.all()
  1098. form = forms.ServiceForm
  1099. @register_model_view(Service, 'delete')
  1100. class ServiceDeleteView(generic.ObjectDeleteView):
  1101. queryset = Service.objects.all()
  1102. @register_model_view(Service, 'bulk_import', detail=False)
  1103. class ServiceBulkImportView(generic.BulkImportView):
  1104. queryset = Service.objects.all()
  1105. model_form = forms.ServiceImportForm
  1106. @register_model_view(Service, 'bulk_edit', path='edit', detail=False)
  1107. class ServiceBulkEditView(generic.BulkEditView):
  1108. queryset = Service.objects.prefetch_related('device', 'virtual_machine')
  1109. filterset = filtersets.ServiceFilterSet
  1110. table = tables.ServiceTable
  1111. form = forms.ServiceBulkEditForm
  1112. @register_model_view(Service, 'bulk_delete', path='delete', detail=False)
  1113. class ServiceBulkDeleteView(generic.BulkDeleteView):
  1114. queryset = Service.objects.prefetch_related('device', 'virtual_machine')
  1115. filterset = filtersets.ServiceFilterSet
  1116. table = tables.ServiceTable
  1117. @register_model_view(Service, 'contacts')
  1118. class ServiceContactsView(ObjectContactsView):
  1119. queryset = Service.objects.all()