2
0

views.py 40 KB

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