views.py 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483
  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.ip_addresses.count(),
  492. permission='ipam.view_ipaddress',
  493. weight=700
  494. )
  495. def get_children(self, request, parent):
  496. return parent.ip_addresses.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. def get_extra_addanother_params(self, request):
  670. if 'interface' in request.GET:
  671. return {'interface': request.GET['interface']}
  672. elif 'vminterface' in request.GET:
  673. return {'vminterface': request.GET['vminterface']}
  674. # TODO: Standardize or remove this view
  675. @register_model_view(IPAddress, 'assign', path='assign', detail=False)
  676. class IPAddressAssignView(generic.ObjectView):
  677. """
  678. Search for IPAddresses to be assigned to an Interface.
  679. """
  680. queryset = IPAddress.objects.all()
  681. def dispatch(self, request, *args, **kwargs):
  682. # Redirect user if an interface has not been provided
  683. if 'interface' not in request.GET and 'vminterface' not in request.GET:
  684. return redirect('ipam:ipaddress_add')
  685. return super().dispatch(request, *args, **kwargs)
  686. def get(self, request):
  687. form = forms.IPAddressAssignForm()
  688. return render(request, 'ipam/ipaddress_assign.html', {
  689. 'form': form,
  690. 'return_url': request.GET.get('return_url', ''),
  691. })
  692. def post(self, request):
  693. form = forms.IPAddressAssignForm(request.POST)
  694. table = None
  695. if form.is_valid():
  696. addresses = self.queryset.prefetch_related('vrf', 'tenant')
  697. # Limit to 100 results
  698. addresses = filtersets.IPAddressFilterSet(request.POST, addresses).qs[:100]
  699. table = tables.IPAddressAssignTable(addresses)
  700. return render(request, 'ipam/ipaddress_assign.html', {
  701. 'form': form,
  702. 'table': table,
  703. 'return_url': request.GET.get('return_url'),
  704. })
  705. @register_model_view(IPAddress, 'delete')
  706. class IPAddressDeleteView(generic.ObjectDeleteView):
  707. queryset = IPAddress.objects.all()
  708. @register_model_view(IPAddress, 'bulk_add', path='bulk-add', detail=False)
  709. class IPAddressBulkCreateView(generic.BulkCreateView):
  710. queryset = IPAddress.objects.all()
  711. form = forms.IPAddressBulkCreateForm
  712. model_form = forms.IPAddressBulkAddForm
  713. pattern_target = 'address'
  714. template_name = 'ipam/ipaddress_bulk_add.html'
  715. @register_model_view(IPAddress, 'bulk_import', detail=False)
  716. class IPAddressBulkImportView(generic.BulkImportView):
  717. queryset = IPAddress.objects.all()
  718. model_form = forms.IPAddressImportForm
  719. @register_model_view(IPAddress, 'bulk_edit', path='edit', detail=False)
  720. class IPAddressBulkEditView(generic.BulkEditView):
  721. queryset = IPAddress.objects.prefetch_related('vrf__tenant')
  722. filterset = filtersets.IPAddressFilterSet
  723. table = tables.IPAddressTable
  724. form = forms.IPAddressBulkEditForm
  725. @register_model_view(IPAddress, 'bulk_delete', path='delete', detail=False)
  726. class IPAddressBulkDeleteView(generic.BulkDeleteView):
  727. queryset = IPAddress.objects.prefetch_related('vrf__tenant')
  728. filterset = filtersets.IPAddressFilterSet
  729. table = tables.IPAddressTable
  730. @register_model_view(IPAddress, 'related_ips', path='related-ip-addresses')
  731. class IPAddressRelatedIPsView(generic.ObjectChildrenView):
  732. queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
  733. child_model = IPAddress
  734. table = tables.IPAddressTable
  735. filterset = filtersets.IPAddressFilterSet
  736. filterset_form = forms.IPAddressFilterForm
  737. tab = ViewTab(
  738. label=_('Related IPs'),
  739. badge=lambda x: x.get_related_ips().count(),
  740. weight=500,
  741. hide_if_empty=True,
  742. )
  743. def get_children(self, request, parent):
  744. return parent.get_related_ips().restrict(request.user, 'view')
  745. @register_model_view(IPAddress, 'contacts')
  746. class IPAddressContactsView(ObjectContactsView):
  747. queryset = IPAddress.objects.all()
  748. #
  749. # VLAN groups
  750. #
  751. @register_model_view(VLANGroup, 'list', path='', detail=False)
  752. class VLANGroupListView(generic.ObjectListView):
  753. queryset = VLANGroup.objects.annotate_utilization()
  754. filterset = filtersets.VLANGroupFilterSet
  755. filterset_form = forms.VLANGroupFilterForm
  756. table = tables.VLANGroupTable
  757. @register_model_view(VLANGroup)
  758. class VLANGroupView(GetRelatedModelsMixin, generic.ObjectView):
  759. queryset = VLANGroup.objects.annotate_utilization()
  760. def get_extra_context(self, request, instance):
  761. return {
  762. 'related_models': self.get_related_models(request, instance),
  763. }
  764. @register_model_view(VLANGroup, 'add', detail=False)
  765. @register_model_view(VLANGroup, 'edit')
  766. class VLANGroupEditView(generic.ObjectEditView):
  767. queryset = VLANGroup.objects.all()
  768. form = forms.VLANGroupForm
  769. @register_model_view(VLANGroup, 'delete')
  770. class VLANGroupDeleteView(generic.ObjectDeleteView):
  771. queryset = VLANGroup.objects.all()
  772. @register_model_view(VLANGroup, 'bulk_import', detail=False)
  773. class VLANGroupBulkImportView(generic.BulkImportView):
  774. queryset = VLANGroup.objects.all()
  775. model_form = forms.VLANGroupImportForm
  776. @register_model_view(VLANGroup, 'bulk_edit', path='edit', detail=False)
  777. class VLANGroupBulkEditView(generic.BulkEditView):
  778. queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
  779. filterset = filtersets.VLANGroupFilterSet
  780. table = tables.VLANGroupTable
  781. form = forms.VLANGroupBulkEditForm
  782. @register_model_view(VLANGroup, 'bulk_delete', path='delete', detail=False)
  783. class VLANGroupBulkDeleteView(generic.BulkDeleteView):
  784. queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
  785. filterset = filtersets.VLANGroupFilterSet
  786. table = tables.VLANGroupTable
  787. @register_model_view(VLANGroup, 'vlans')
  788. class VLANGroupVLANsView(generic.ObjectChildrenView):
  789. queryset = VLANGroup.objects.all()
  790. child_model = VLAN
  791. table = tables.VLANTable
  792. filterset = filtersets.VLANFilterSet
  793. filterset_form = forms.VLANFilterForm
  794. tab = ViewTab(
  795. label=_('VLANs'),
  796. badge=lambda x: x.get_child_vlans().count(),
  797. permission='ipam.view_vlan',
  798. weight=500
  799. )
  800. def get_children(self, request, parent):
  801. return parent.get_child_vlans().restrict(request.user, 'view').prefetch_related(
  802. Prefetch('prefixes', queryset=Prefix.objects.restrict(request.user)),
  803. 'tenant', 'site', 'role',
  804. )
  805. def prep_table_data(self, request, queryset, parent):
  806. if not get_table_ordering(request, self.table):
  807. return add_available_vlans(queryset, parent)
  808. return queryset
  809. #
  810. # VLAN Translation Policies
  811. #
  812. @register_model_view(VLANTranslationPolicy, 'list', path='', detail=False)
  813. class VLANTranslationPolicyListView(generic.ObjectListView):
  814. queryset = VLANTranslationPolicy.objects.annotate(
  815. rule_count=count_related(VLANTranslationRule, 'policy'),
  816. )
  817. filterset = filtersets.VLANTranslationPolicyFilterSet
  818. filterset_form = forms.VLANTranslationPolicyFilterForm
  819. table = tables.VLANTranslationPolicyTable
  820. @register_model_view(VLANTranslationPolicy)
  821. class VLANTranslationPolicyView(GetRelatedModelsMixin, generic.ObjectView):
  822. queryset = VLANTranslationPolicy.objects.all()
  823. def get_extra_context(self, request, instance):
  824. vlan_translation_table = VLANTranslationRuleTable(
  825. data=instance.rules.all(),
  826. orderable=False
  827. )
  828. return {
  829. 'vlan_translation_table': vlan_translation_table,
  830. }
  831. @register_model_view(VLANTranslationPolicy, 'add', detail=False)
  832. @register_model_view(VLANTranslationPolicy, 'edit')
  833. class VLANTranslationPolicyEditView(generic.ObjectEditView):
  834. queryset = VLANTranslationPolicy.objects.all()
  835. form = forms.VLANTranslationPolicyForm
  836. @register_model_view(VLANTranslationPolicy, 'delete')
  837. class VLANTranslationPolicyDeleteView(generic.ObjectDeleteView):
  838. queryset = VLANTranslationPolicy.objects.all()
  839. @register_model_view(VLANTranslationPolicy, 'bulk_import', detail=False)
  840. class VLANTranslationPolicyBulkImportView(generic.BulkImportView):
  841. queryset = VLANTranslationPolicy.objects.all()
  842. model_form = forms.VLANTranslationPolicyImportForm
  843. @register_model_view(VLANTranslationPolicy, 'bulk_edit', path='edit', detail=False)
  844. class VLANTranslationPolicyBulkEditView(generic.BulkEditView):
  845. queryset = VLANTranslationPolicy.objects.all()
  846. filterset = filtersets.VLANTranslationPolicyFilterSet
  847. table = tables.VLANTranslationPolicyTable
  848. form = forms.VLANTranslationPolicyBulkEditForm
  849. @register_model_view(VLANTranslationPolicy, 'bulk_delete', path='delete', detail=False)
  850. class VLANTranslationPolicyBulkDeleteView(generic.BulkDeleteView):
  851. queryset = VLANTranslationPolicy.objects.all()
  852. filterset = filtersets.VLANTranslationPolicyFilterSet
  853. table = tables.VLANTranslationPolicyTable
  854. #
  855. # VLAN Translation Rules
  856. #
  857. @register_model_view(VLANTranslationRule, 'list', path='', detail=False)
  858. class VLANTranslationRuleListView(generic.ObjectListView):
  859. queryset = VLANTranslationRule.objects.all()
  860. filterset = filtersets.VLANTranslationRuleFilterSet
  861. filterset_form = forms.VLANTranslationRuleFilterForm
  862. table = tables.VLANTranslationRuleTable
  863. @register_model_view(VLANTranslationRule)
  864. class VLANTranslationRuleView(GetRelatedModelsMixin, generic.ObjectView):
  865. queryset = VLANTranslationRule.objects.all()
  866. def get_extra_context(self, request, instance):
  867. return {
  868. 'related_models': self.get_related_models(request, instance),
  869. }
  870. @register_model_view(VLANTranslationRule, 'add', detail=False)
  871. @register_model_view(VLANTranslationRule, 'edit')
  872. class VLANTranslationRuleEditView(generic.ObjectEditView):
  873. queryset = VLANTranslationRule.objects.all()
  874. form = forms.VLANTranslationRuleForm
  875. @register_model_view(VLANTranslationRule, 'delete')
  876. class VLANTranslationRuleDeleteView(generic.ObjectDeleteView):
  877. queryset = VLANTranslationRule.objects.all()
  878. @register_model_view(VLANTranslationRule, 'bulk_import', detail=False)
  879. class VLANTranslationRuleBulkImportView(generic.BulkImportView):
  880. queryset = VLANTranslationRule.objects.all()
  881. model_form = forms.VLANTranslationRuleImportForm
  882. @register_model_view(VLANTranslationRule, 'bulk_edit', path='edit', detail=False)
  883. class VLANTranslationRuleBulkEditView(generic.BulkEditView):
  884. queryset = VLANTranslationRule.objects.all()
  885. filterset = filtersets.VLANTranslationRuleFilterSet
  886. table = tables.VLANTranslationRuleTable
  887. form = forms.VLANTranslationRuleBulkEditForm
  888. @register_model_view(VLANTranslationRule, 'bulk_delete', path='delete', detail=False)
  889. class VLANTranslationRuleBulkDeleteView(generic.BulkDeleteView):
  890. queryset = VLANTranslationRule.objects.all()
  891. filterset = filtersets.VLANTranslationRuleFilterSet
  892. table = tables.VLANTranslationRuleTable
  893. #
  894. # FHRP groups
  895. #
  896. @register_model_view(FHRPGroup, 'list', path='', detail=False)
  897. class FHRPGroupListView(generic.ObjectListView):
  898. queryset = FHRPGroup.objects.annotate(
  899. member_count=count_related(FHRPGroupAssignment, 'group')
  900. )
  901. filterset = filtersets.FHRPGroupFilterSet
  902. filterset_form = forms.FHRPGroupFilterForm
  903. table = tables.FHRPGroupTable
  904. @register_model_view(FHRPGroup)
  905. class FHRPGroupView(generic.ObjectView):
  906. queryset = FHRPGroup.objects.all()
  907. def get_extra_context(self, request, instance):
  908. # Get assigned interfaces
  909. members_table = tables.FHRPGroupAssignmentTable(
  910. data=FHRPGroupAssignment.objects.restrict(request.user, 'view').filter(group=instance),
  911. orderable=False
  912. )
  913. members_table.columns.hide('group')
  914. return {
  915. 'members_table': members_table,
  916. 'member_count': FHRPGroupAssignment.objects.filter(group=instance).count(),
  917. }
  918. @register_model_view(FHRPGroup, 'add', detail=False)
  919. @register_model_view(FHRPGroup, 'edit')
  920. class FHRPGroupEditView(generic.ObjectEditView):
  921. queryset = FHRPGroup.objects.all()
  922. form = forms.FHRPGroupForm
  923. def get_return_url(self, request, obj=None):
  924. return_url = super().get_return_url(request, obj)
  925. # If we're redirecting the user to the FHRPGroupAssignment creation form,
  926. # initialize the group field with the FHRPGroup we just saved.
  927. if return_url.startswith(reverse('ipam:fhrpgroupassignment_add')):
  928. return_url += f'&group={obj.pk}'
  929. return return_url
  930. def alter_object(self, obj, request, url_args, url_kwargs):
  931. # Workaround to solve #10719. Capture the current user on the FHRPGroup instance so that
  932. # we can evaluate permissions during the creation of a new IPAddress within the form.
  933. obj._user = request.user
  934. return obj
  935. @register_model_view(FHRPGroup, 'delete')
  936. class FHRPGroupDeleteView(generic.ObjectDeleteView):
  937. queryset = FHRPGroup.objects.all()
  938. @register_model_view(FHRPGroup, 'bulk_import', detail=False)
  939. class FHRPGroupBulkImportView(generic.BulkImportView):
  940. queryset = FHRPGroup.objects.all()
  941. model_form = forms.FHRPGroupImportForm
  942. @register_model_view(FHRPGroup, 'bulk_edit', path='edit', detail=False)
  943. class FHRPGroupBulkEditView(generic.BulkEditView):
  944. queryset = FHRPGroup.objects.all()
  945. filterset = filtersets.FHRPGroupFilterSet
  946. table = tables.FHRPGroupTable
  947. form = forms.FHRPGroupBulkEditForm
  948. @register_model_view(FHRPGroup, 'bulk_delete', path='delete', detail=False)
  949. class FHRPGroupBulkDeleteView(generic.BulkDeleteView):
  950. queryset = FHRPGroup.objects.all()
  951. filterset = filtersets.FHRPGroupFilterSet
  952. table = tables.FHRPGroupTable
  953. #
  954. # FHRP group assignments
  955. #
  956. @register_model_view(FHRPGroupAssignment, 'add', detail=False)
  957. @register_model_view(FHRPGroupAssignment, 'edit')
  958. class FHRPGroupAssignmentEditView(generic.ObjectEditView):
  959. queryset = FHRPGroupAssignment.objects.all()
  960. form = forms.FHRPGroupAssignmentForm
  961. def alter_object(self, instance, request, args, kwargs):
  962. if not instance.pk:
  963. # Assign the interface based on URL kwargs
  964. content_type = get_object_or_404(ContentType, pk=request.GET.get('interface_type'))
  965. instance.interface = get_object_or_404(content_type.model_class(), pk=request.GET.get('interface_id'))
  966. return instance
  967. def get_extra_addanother_params(self, request):
  968. return {
  969. 'interface_type': request.GET.get('interface_type'),
  970. 'interface_id': request.GET.get('interface_id'),
  971. }
  972. @register_model_view(FHRPGroupAssignment, 'delete')
  973. class FHRPGroupAssignmentDeleteView(generic.ObjectDeleteView):
  974. queryset = FHRPGroupAssignment.objects.all()
  975. #
  976. # VLANs
  977. #
  978. @register_model_view(VLAN, 'list', path='', detail=False)
  979. class VLANListView(generic.ObjectListView):
  980. queryset = VLAN.objects.all()
  981. filterset = filtersets.VLANFilterSet
  982. filterset_form = forms.VLANFilterForm
  983. table = tables.VLANTable
  984. @register_model_view(VLAN)
  985. class VLANView(generic.ObjectView):
  986. queryset = VLAN.objects.all()
  987. def get_extra_context(self, request, instance):
  988. prefixes = Prefix.objects.restrict(request.user, 'view').filter(vlan=instance).prefetch_related(
  989. 'vrf', 'scope', 'role', 'tenant'
  990. )
  991. prefix_table = tables.PrefixTable(list(prefixes), exclude=('vlan', 'utilization'), orderable=False)
  992. return {
  993. 'prefix_table': prefix_table,
  994. }
  995. @register_model_view(VLAN, 'interfaces')
  996. class VLANInterfacesView(generic.ObjectChildrenView):
  997. queryset = VLAN.objects.all()
  998. child_model = Interface
  999. table = tables.VLANDevicesTable
  1000. filterset = InterfaceFilterSet
  1001. filterset_form = InterfaceFilterForm
  1002. tab = ViewTab(
  1003. label=_('Device Interfaces'),
  1004. badge=lambda x: x.get_interfaces().count(),
  1005. permission='dcim.view_interface',
  1006. weight=500
  1007. )
  1008. def get_children(self, request, parent):
  1009. return parent.get_interfaces().restrict(request.user, 'view')
  1010. @register_model_view(VLAN, 'vminterfaces', path='vm-interfaces')
  1011. class VLANVMInterfacesView(generic.ObjectChildrenView):
  1012. queryset = VLAN.objects.all()
  1013. child_model = VMInterface
  1014. table = tables.VLANVirtualMachinesTable
  1015. filterset = VMInterfaceFilterSet
  1016. filterset_form = VMInterfaceFilterForm
  1017. tab = ViewTab(
  1018. label=_('VM Interfaces'),
  1019. badge=lambda x: x.get_vminterfaces().count(),
  1020. permission='virtualization.view_vminterface',
  1021. weight=510
  1022. )
  1023. def get_children(self, request, parent):
  1024. return parent.get_vminterfaces().restrict(request.user, 'view')
  1025. @register_model_view(VLAN, 'add', detail=False)
  1026. @register_model_view(VLAN, 'edit')
  1027. class VLANEditView(generic.ObjectEditView):
  1028. queryset = VLAN.objects.all()
  1029. form = forms.VLANForm
  1030. template_name = 'ipam/vlan_edit.html'
  1031. @register_model_view(VLAN, 'delete')
  1032. class VLANDeleteView(generic.ObjectDeleteView):
  1033. queryset = VLAN.objects.all()
  1034. @register_model_view(VLAN, 'bulk_import', detail=False)
  1035. class VLANBulkImportView(generic.BulkImportView):
  1036. queryset = VLAN.objects.all()
  1037. model_form = forms.VLANImportForm
  1038. @register_model_view(VLAN, 'bulk_edit', path='edit', detail=False)
  1039. class VLANBulkEditView(generic.BulkEditView):
  1040. queryset = VLAN.objects.all()
  1041. filterset = filtersets.VLANFilterSet
  1042. table = tables.VLANTable
  1043. form = forms.VLANBulkEditForm
  1044. @register_model_view(VLAN, 'bulk_delete', path='delete', detail=False)
  1045. class VLANBulkDeleteView(generic.BulkDeleteView):
  1046. queryset = VLAN.objects.all()
  1047. filterset = filtersets.VLANFilterSet
  1048. table = tables.VLANTable
  1049. #
  1050. # Service templates
  1051. #
  1052. @register_model_view(ServiceTemplate, 'list', path='', detail=False)
  1053. class ServiceTemplateListView(generic.ObjectListView):
  1054. queryset = ServiceTemplate.objects.all()
  1055. filterset = filtersets.ServiceTemplateFilterSet
  1056. filterset_form = forms.ServiceTemplateFilterForm
  1057. table = tables.ServiceTemplateTable
  1058. @register_model_view(ServiceTemplate)
  1059. class ServiceTemplateView(generic.ObjectView):
  1060. queryset = ServiceTemplate.objects.all()
  1061. @register_model_view(ServiceTemplate, 'add', detail=False)
  1062. @register_model_view(ServiceTemplate, 'edit')
  1063. class ServiceTemplateEditView(generic.ObjectEditView):
  1064. queryset = ServiceTemplate.objects.all()
  1065. form = forms.ServiceTemplateForm
  1066. @register_model_view(ServiceTemplate, 'delete')
  1067. class ServiceTemplateDeleteView(generic.ObjectDeleteView):
  1068. queryset = ServiceTemplate.objects.all()
  1069. @register_model_view(ServiceTemplate, 'bulk_import', detail=False)
  1070. class ServiceTemplateBulkImportView(generic.BulkImportView):
  1071. queryset = ServiceTemplate.objects.all()
  1072. model_form = forms.ServiceTemplateImportForm
  1073. @register_model_view(ServiceTemplate, 'bulk_edit', path='edit', detail=False)
  1074. class ServiceTemplateBulkEditView(generic.BulkEditView):
  1075. queryset = ServiceTemplate.objects.all()
  1076. filterset = filtersets.ServiceTemplateFilterSet
  1077. table = tables.ServiceTemplateTable
  1078. form = forms.ServiceTemplateBulkEditForm
  1079. @register_model_view(ServiceTemplate, 'bulk_delete', path='delete', detail=False)
  1080. class ServiceTemplateBulkDeleteView(generic.BulkDeleteView):
  1081. queryset = ServiceTemplate.objects.all()
  1082. filterset = filtersets.ServiceTemplateFilterSet
  1083. table = tables.ServiceTemplateTable
  1084. #
  1085. # Services
  1086. #
  1087. @register_model_view(Service, 'list', path='', detail=False)
  1088. class ServiceListView(generic.ObjectListView):
  1089. queryset = Service.objects.prefetch_related('device', 'virtual_machine')
  1090. filterset = filtersets.ServiceFilterSet
  1091. filterset_form = forms.ServiceFilterForm
  1092. table = tables.ServiceTable
  1093. @register_model_view(Service)
  1094. class ServiceView(generic.ObjectView):
  1095. queryset = Service.objects.all()
  1096. @register_model_view(Service, 'add', detail=False)
  1097. class ServiceCreateView(generic.ObjectEditView):
  1098. queryset = Service.objects.all()
  1099. form = forms.ServiceCreateForm
  1100. @register_model_view(Service, 'edit')
  1101. class ServiceEditView(generic.ObjectEditView):
  1102. queryset = Service.objects.all()
  1103. form = forms.ServiceForm
  1104. @register_model_view(Service, 'delete')
  1105. class ServiceDeleteView(generic.ObjectDeleteView):
  1106. queryset = Service.objects.all()
  1107. @register_model_view(Service, 'bulk_import', detail=False)
  1108. class ServiceBulkImportView(generic.BulkImportView):
  1109. queryset = Service.objects.all()
  1110. model_form = forms.ServiceImportForm
  1111. @register_model_view(Service, 'bulk_edit', path='edit', detail=False)
  1112. class ServiceBulkEditView(generic.BulkEditView):
  1113. queryset = Service.objects.prefetch_related('device', 'virtual_machine')
  1114. filterset = filtersets.ServiceFilterSet
  1115. table = tables.ServiceTable
  1116. form = forms.ServiceBulkEditForm
  1117. @register_model_view(Service, 'bulk_delete', path='delete', detail=False)
  1118. class ServiceBulkDeleteView(generic.BulkDeleteView):
  1119. queryset = Service.objects.prefetch_related('device', 'virtual_machine')
  1120. filterset = filtersets.ServiceFilterSet
  1121. table = tables.ServiceTable
  1122. @register_model_view(Service, 'contacts')
  1123. class ServiceContactsView(ObjectContactsView):
  1124. queryset = Service.objects.all()