views.py 41 KB

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