views.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  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 circuits.models import Provider, Circuit
  7. from circuits.tables import ProviderTable
  8. from dcim.filtersets import InterfaceFilterSet
  9. from dcim.models import Interface, Site
  10. from dcim.tables import SiteTable
  11. from netbox.views import generic
  12. from utilities.utils import count_related
  13. from virtualization.filtersets import VMInterfaceFilterSet
  14. from virtualization.models import VMInterface
  15. from . import filtersets, forms, tables
  16. from .constants import *
  17. from .models import *
  18. from .models import ASN
  19. from .utils import add_requested_prefixes, add_available_ipaddresses, add_available_vlans
  20. #
  21. # VRFs
  22. #
  23. class VRFListView(generic.ObjectListView):
  24. queryset = VRF.objects.all()
  25. filterset = filtersets.VRFFilterSet
  26. filterset_form = forms.VRFFilterForm
  27. table = tables.VRFTable
  28. class VRFView(generic.ObjectView):
  29. queryset = VRF.objects.all()
  30. def get_extra_context(self, request, instance):
  31. prefix_count = Prefix.objects.restrict(request.user, 'view').filter(vrf=instance).count()
  32. ipaddress_count = IPAddress.objects.restrict(request.user, 'view').filter(vrf=instance).count()
  33. import_targets_table = tables.RouteTargetTable(
  34. instance.import_targets.prefetch_related('tenant'),
  35. orderable=False
  36. )
  37. export_targets_table = tables.RouteTargetTable(
  38. instance.export_targets.prefetch_related('tenant'),
  39. orderable=False
  40. )
  41. return {
  42. 'prefix_count': prefix_count,
  43. 'ipaddress_count': ipaddress_count,
  44. 'import_targets_table': import_targets_table,
  45. 'export_targets_table': export_targets_table,
  46. }
  47. class VRFEditView(generic.ObjectEditView):
  48. queryset = VRF.objects.all()
  49. form = forms.VRFForm
  50. class VRFDeleteView(generic.ObjectDeleteView):
  51. queryset = VRF.objects.all()
  52. class VRFBulkImportView(generic.BulkImportView):
  53. queryset = VRF.objects.all()
  54. model_form = forms.VRFCSVForm
  55. table = tables.VRFTable
  56. class VRFBulkEditView(generic.BulkEditView):
  57. queryset = VRF.objects.prefetch_related('tenant')
  58. filterset = filtersets.VRFFilterSet
  59. table = tables.VRFTable
  60. form = forms.VRFBulkEditForm
  61. class VRFBulkDeleteView(generic.BulkDeleteView):
  62. queryset = VRF.objects.prefetch_related('tenant')
  63. filterset = filtersets.VRFFilterSet
  64. table = tables.VRFTable
  65. #
  66. # Route targets
  67. #
  68. class RouteTargetListView(generic.ObjectListView):
  69. queryset = RouteTarget.objects.all()
  70. filterset = filtersets.RouteTargetFilterSet
  71. filterset_form = forms.RouteTargetFilterForm
  72. table = tables.RouteTargetTable
  73. class RouteTargetView(generic.ObjectView):
  74. queryset = RouteTarget.objects.all()
  75. def get_extra_context(self, request, instance):
  76. importing_vrfs_table = tables.VRFTable(
  77. instance.importing_vrfs.prefetch_related('tenant'),
  78. orderable=False
  79. )
  80. exporting_vrfs_table = tables.VRFTable(
  81. instance.exporting_vrfs.prefetch_related('tenant'),
  82. orderable=False
  83. )
  84. return {
  85. 'importing_vrfs_table': importing_vrfs_table,
  86. 'exporting_vrfs_table': exporting_vrfs_table,
  87. }
  88. class RouteTargetEditView(generic.ObjectEditView):
  89. queryset = RouteTarget.objects.all()
  90. form = forms.RouteTargetForm
  91. class RouteTargetDeleteView(generic.ObjectDeleteView):
  92. queryset = RouteTarget.objects.all()
  93. class RouteTargetBulkImportView(generic.BulkImportView):
  94. queryset = RouteTarget.objects.all()
  95. model_form = forms.RouteTargetCSVForm
  96. table = tables.RouteTargetTable
  97. class RouteTargetBulkEditView(generic.BulkEditView):
  98. queryset = RouteTarget.objects.prefetch_related('tenant')
  99. filterset = filtersets.RouteTargetFilterSet
  100. table = tables.RouteTargetTable
  101. form = forms.RouteTargetBulkEditForm
  102. class RouteTargetBulkDeleteView(generic.BulkDeleteView):
  103. queryset = RouteTarget.objects.prefetch_related('tenant')
  104. filterset = filtersets.RouteTargetFilterSet
  105. table = tables.RouteTargetTable
  106. #
  107. # RIRs
  108. #
  109. class RIRListView(generic.ObjectListView):
  110. queryset = RIR.objects.annotate(
  111. aggregate_count=count_related(Aggregate, 'rir')
  112. )
  113. filterset = filtersets.RIRFilterSet
  114. filterset_form = forms.RIRFilterForm
  115. table = tables.RIRTable
  116. class RIRView(generic.ObjectView):
  117. queryset = RIR.objects.all()
  118. def get_extra_context(self, request, instance):
  119. aggregates = Aggregate.objects.restrict(request.user, 'view').filter(rir=instance).annotate(
  120. child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
  121. )
  122. aggregates_table = tables.AggregateTable(aggregates, user=request.user, exclude=('rir', 'utilization'))
  123. aggregates_table.configure(request)
  124. return {
  125. 'aggregates_table': aggregates_table,
  126. }
  127. class RIREditView(generic.ObjectEditView):
  128. queryset = RIR.objects.all()
  129. form = forms.RIRForm
  130. class RIRDeleteView(generic.ObjectDeleteView):
  131. queryset = RIR.objects.all()
  132. class RIRBulkImportView(generic.BulkImportView):
  133. queryset = RIR.objects.all()
  134. model_form = forms.RIRCSVForm
  135. table = tables.RIRTable
  136. class RIRBulkEditView(generic.BulkEditView):
  137. queryset = RIR.objects.annotate(
  138. aggregate_count=count_related(Aggregate, 'rir')
  139. )
  140. filterset = filtersets.RIRFilterSet
  141. table = tables.RIRTable
  142. form = forms.RIRBulkEditForm
  143. class RIRBulkDeleteView(generic.BulkDeleteView):
  144. queryset = RIR.objects.annotate(
  145. aggregate_count=count_related(Aggregate, 'rir')
  146. )
  147. filterset = filtersets.RIRFilterSet
  148. table = tables.RIRTable
  149. #
  150. # ASNs
  151. #
  152. class ASNListView(generic.ObjectListView):
  153. queryset = ASN.objects.annotate(
  154. site_count=count_related(Site, 'asns'),
  155. provider_count=count_related(Provider, 'asns')
  156. )
  157. filterset = filtersets.ASNFilterSet
  158. filterset_form = forms.ASNFilterForm
  159. table = tables.ASNTable
  160. class ASNView(generic.ObjectView):
  161. queryset = ASN.objects.all()
  162. def get_extra_context(self, request, instance):
  163. # Gather assigned Sites
  164. sites = instance.sites.restrict(request.user, 'view')
  165. sites_table = SiteTable(sites, user=request.user)
  166. sites_table.configure(request)
  167. # Gather assigned Providers
  168. providers = instance.providers.restrict(request.user, 'view').annotate(
  169. count_circuits=count_related(Circuit, 'provider')
  170. )
  171. providers_table = ProviderTable(providers, user=request.user)
  172. providers_table.configure(request)
  173. return {
  174. 'sites_table': sites_table,
  175. 'sites_count': sites.count(),
  176. 'providers_table': providers_table,
  177. 'providers_count': providers.count(),
  178. }
  179. class ASNEditView(generic.ObjectEditView):
  180. queryset = ASN.objects.all()
  181. form = forms.ASNForm
  182. class ASNDeleteView(generic.ObjectDeleteView):
  183. queryset = ASN.objects.all()
  184. class ASNBulkImportView(generic.BulkImportView):
  185. queryset = ASN.objects.all()
  186. model_form = forms.ASNCSVForm
  187. table = tables.ASNTable
  188. class ASNBulkEditView(generic.BulkEditView):
  189. queryset = ASN.objects.annotate(
  190. site_count=count_related(Site, 'asns')
  191. )
  192. filterset = filtersets.ASNFilterSet
  193. table = tables.ASNTable
  194. form = forms.ASNBulkEditForm
  195. class ASNBulkDeleteView(generic.BulkDeleteView):
  196. queryset = ASN.objects.annotate(
  197. site_count=count_related(Site, 'asns')
  198. )
  199. filterset = filtersets.ASNFilterSet
  200. table = tables.ASNTable
  201. #
  202. # Aggregates
  203. #
  204. class AggregateListView(generic.ObjectListView):
  205. queryset = Aggregate.objects.annotate(
  206. child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
  207. )
  208. filterset = filtersets.AggregateFilterSet
  209. filterset_form = forms.AggregateFilterForm
  210. table = tables.AggregateTable
  211. class AggregateView(generic.ObjectView):
  212. queryset = Aggregate.objects.all()
  213. class AggregatePrefixesView(generic.ObjectChildrenView):
  214. queryset = Aggregate.objects.all()
  215. child_model = Prefix
  216. table = tables.PrefixTable
  217. filterset = filtersets.PrefixFilterSet
  218. template_name = 'ipam/aggregate/prefixes.html'
  219. def get_children(self, request, parent):
  220. return Prefix.objects.restrict(request.user, 'view').filter(
  221. prefix__net_contained_or_equal=str(parent.prefix)
  222. ).prefetch_related('site', 'role', 'tenant', 'vlan')
  223. def prep_table_data(self, request, queryset, parent):
  224. # Determine whether to show assigned prefixes, available prefixes, or both
  225. show_available = bool(request.GET.get('show_available', 'true') == 'true')
  226. show_assigned = bool(request.GET.get('show_assigned', 'true') == 'true')
  227. return add_requested_prefixes(parent.prefix, queryset, show_available, show_assigned)
  228. def get_extra_context(self, request, instance):
  229. return {
  230. 'bulk_querystring': f'within={instance.prefix}',
  231. 'active_tab': 'prefixes',
  232. 'first_available_prefix': instance.get_first_available_prefix(),
  233. 'show_available': bool(request.GET.get('show_available', 'true') == 'true'),
  234. 'show_assigned': bool(request.GET.get('show_assigned', 'true') == 'true'),
  235. }
  236. class AggregateEditView(generic.ObjectEditView):
  237. queryset = Aggregate.objects.all()
  238. form = forms.AggregateForm
  239. class AggregateDeleteView(generic.ObjectDeleteView):
  240. queryset = Aggregate.objects.all()
  241. class AggregateBulkImportView(generic.BulkImportView):
  242. queryset = Aggregate.objects.all()
  243. model_form = forms.AggregateCSVForm
  244. table = tables.AggregateTable
  245. class AggregateBulkEditView(generic.BulkEditView):
  246. queryset = Aggregate.objects.prefetch_related('rir')
  247. filterset = filtersets.AggregateFilterSet
  248. table = tables.AggregateTable
  249. form = forms.AggregateBulkEditForm
  250. class AggregateBulkDeleteView(generic.BulkDeleteView):
  251. queryset = Aggregate.objects.prefetch_related('rir')
  252. filterset = filtersets.AggregateFilterSet
  253. table = tables.AggregateTable
  254. #
  255. # Prefix/VLAN roles
  256. #
  257. class RoleListView(generic.ObjectListView):
  258. queryset = Role.objects.annotate(
  259. prefix_count=count_related(Prefix, 'role'),
  260. iprange_count=count_related(IPRange, 'role'),
  261. vlan_count=count_related(VLAN, 'role')
  262. )
  263. filterset = filtersets.RoleFilterSet
  264. filterset_form = forms.RoleFilterForm
  265. table = tables.RoleTable
  266. class RoleView(generic.ObjectView):
  267. queryset = Role.objects.all()
  268. def get_extra_context(self, request, instance):
  269. prefixes = Prefix.objects.restrict(request.user, 'view').filter(
  270. role=instance
  271. )
  272. prefixes_table = tables.PrefixTable(prefixes, user=request.user, exclude=('role', 'utilization'))
  273. prefixes_table.configure(request)
  274. return {
  275. 'prefixes_table': prefixes_table,
  276. }
  277. class RoleEditView(generic.ObjectEditView):
  278. queryset = Role.objects.all()
  279. form = forms.RoleForm
  280. class RoleDeleteView(generic.ObjectDeleteView):
  281. queryset = Role.objects.all()
  282. class RoleBulkImportView(generic.BulkImportView):
  283. queryset = Role.objects.all()
  284. model_form = forms.RoleCSVForm
  285. table = tables.RoleTable
  286. class RoleBulkEditView(generic.BulkEditView):
  287. queryset = Role.objects.all()
  288. filterset = filtersets.RoleFilterSet
  289. table = tables.RoleTable
  290. form = forms.RoleBulkEditForm
  291. class RoleBulkDeleteView(generic.BulkDeleteView):
  292. queryset = Role.objects.all()
  293. table = tables.RoleTable
  294. #
  295. # Prefixes
  296. #
  297. class PrefixListView(generic.ObjectListView):
  298. queryset = Prefix.objects.all()
  299. filterset = filtersets.PrefixFilterSet
  300. filterset_form = forms.PrefixFilterForm
  301. table = tables.PrefixTable
  302. template_name = 'ipam/prefix_list.html'
  303. class PrefixView(generic.ObjectView):
  304. queryset = Prefix.objects.prefetch_related('vrf', 'site__region', 'tenant__group', 'vlan__group', 'role')
  305. def get_extra_context(self, request, instance):
  306. try:
  307. aggregate = Aggregate.objects.restrict(request.user, 'view').get(
  308. prefix__net_contains_or_equals=str(instance.prefix)
  309. )
  310. except Aggregate.DoesNotExist:
  311. aggregate = None
  312. # Parent prefixes table
  313. parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
  314. Q(vrf=instance.vrf) | Q(vrf__isnull=True)
  315. ).filter(
  316. prefix__net_contains=str(instance.prefix)
  317. ).prefetch_related(
  318. 'site', 'role', 'tenant'
  319. )
  320. parent_prefix_table = tables.PrefixTable(
  321. list(parent_prefixes),
  322. exclude=('vrf', 'utilization'),
  323. orderable=False
  324. )
  325. # Duplicate prefixes table
  326. duplicate_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
  327. vrf=instance.vrf, prefix=str(instance.prefix)
  328. ).exclude(
  329. pk=instance.pk
  330. ).prefetch_related(
  331. 'site', 'role'
  332. )
  333. duplicate_prefix_table = tables.PrefixTable(
  334. list(duplicate_prefixes),
  335. exclude=('vrf', 'utilization'),
  336. orderable=False
  337. )
  338. return {
  339. 'aggregate': aggregate,
  340. 'parent_prefix_table': parent_prefix_table,
  341. 'duplicate_prefix_table': duplicate_prefix_table,
  342. }
  343. class PrefixPrefixesView(generic.ObjectChildrenView):
  344. queryset = Prefix.objects.all()
  345. child_model = Prefix
  346. table = tables.PrefixTable
  347. filterset = filtersets.PrefixFilterSet
  348. template_name = 'ipam/prefix/prefixes.html'
  349. def get_children(self, request, parent):
  350. return parent.get_child_prefixes().restrict(request.user, 'view').prefetch_related(
  351. 'site', 'vrf', 'vlan', 'role', 'tenant',
  352. )
  353. def prep_table_data(self, request, queryset, parent):
  354. # Determine whether to show assigned prefixes, available prefixes, or both
  355. show_available = bool(request.GET.get('show_available', 'true') == 'true')
  356. show_assigned = bool(request.GET.get('show_assigned', 'true') == 'true')
  357. return add_requested_prefixes(parent.prefix, queryset, show_available, show_assigned)
  358. def get_extra_context(self, request, instance):
  359. return {
  360. 'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&within={instance.prefix}",
  361. 'active_tab': 'prefixes',
  362. 'first_available_prefix': instance.get_first_available_prefix(),
  363. 'show_available': bool(request.GET.get('show_available', 'true') == 'true'),
  364. 'show_assigned': bool(request.GET.get('show_assigned', 'true') == 'true'),
  365. }
  366. class PrefixIPRangesView(generic.ObjectChildrenView):
  367. queryset = Prefix.objects.all()
  368. child_model = IPRange
  369. table = tables.IPRangeTable
  370. filterset = filtersets.IPRangeFilterSet
  371. template_name = 'ipam/prefix/ip_ranges.html'
  372. def get_children(self, request, parent):
  373. return parent.get_child_ranges().restrict(request.user, 'view').prefetch_related(
  374. 'vrf', 'role', 'tenant',
  375. )
  376. def get_extra_context(self, request, instance):
  377. return {
  378. 'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&parent={instance.prefix}",
  379. 'active_tab': 'ip-ranges',
  380. 'first_available_ip': instance.get_first_available_ip(),
  381. }
  382. class PrefixIPAddressesView(generic.ObjectChildrenView):
  383. queryset = Prefix.objects.all()
  384. child_model = IPAddress
  385. table = tables.IPAddressTable
  386. filterset = filtersets.IPAddressFilterSet
  387. template_name = 'ipam/prefix/ip_addresses.html'
  388. def get_children(self, request, parent):
  389. return parent.get_child_ips().restrict(request.user, 'view').prefetch_related('vrf', 'tenant')
  390. def prep_table_data(self, request, queryset, parent):
  391. show_available = bool(request.GET.get('show_available', 'true') == 'true')
  392. if show_available:
  393. return add_available_ipaddresses(parent.prefix, queryset, parent.is_pool)
  394. return queryset
  395. def get_extra_context(self, request, instance):
  396. return {
  397. 'bulk_querystring': f"vrf_id={instance.vrf.pk if instance.vrf else '0'}&parent={instance.prefix}",
  398. 'active_tab': 'ip-addresses',
  399. 'first_available_ip': instance.get_first_available_ip(),
  400. }
  401. class PrefixEditView(generic.ObjectEditView):
  402. queryset = Prefix.objects.all()
  403. form = forms.PrefixForm
  404. class PrefixDeleteView(generic.ObjectDeleteView):
  405. queryset = Prefix.objects.all()
  406. class PrefixBulkImportView(generic.BulkImportView):
  407. queryset = Prefix.objects.all()
  408. model_form = forms.PrefixCSVForm
  409. table = tables.PrefixTable
  410. class PrefixBulkEditView(generic.BulkEditView):
  411. queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
  412. filterset = filtersets.PrefixFilterSet
  413. table = tables.PrefixTable
  414. form = forms.PrefixBulkEditForm
  415. class PrefixBulkDeleteView(generic.BulkDeleteView):
  416. queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
  417. filterset = filtersets.PrefixFilterSet
  418. table = tables.PrefixTable
  419. #
  420. # IP Ranges
  421. #
  422. class IPRangeListView(generic.ObjectListView):
  423. queryset = IPRange.objects.all()
  424. filterset = filtersets.IPRangeFilterSet
  425. filterset_form = forms.IPRangeFilterForm
  426. table = tables.IPRangeTable
  427. class IPRangeView(generic.ObjectView):
  428. queryset = IPRange.objects.all()
  429. class IPRangeIPAddressesView(generic.ObjectChildrenView):
  430. queryset = IPRange.objects.all()
  431. child_model = IPAddress
  432. table = tables.IPAddressTable
  433. filterset = filtersets.IPAddressFilterSet
  434. template_name = 'ipam/iprange/ip_addresses.html'
  435. def get_children(self, request, parent):
  436. return parent.get_child_ips().restrict(request.user, 'view').prefetch_related(
  437. 'vrf', 'role', 'tenant',
  438. )
  439. def get_extra_context(self, request, instance):
  440. return {
  441. 'active_tab': 'ip-addresses',
  442. }
  443. class IPRangeEditView(generic.ObjectEditView):
  444. queryset = IPRange.objects.all()
  445. form = forms.IPRangeForm
  446. class IPRangeDeleteView(generic.ObjectDeleteView):
  447. queryset = IPRange.objects.all()
  448. class IPRangeBulkImportView(generic.BulkImportView):
  449. queryset = IPRange.objects.all()
  450. model_form = forms.IPRangeCSVForm
  451. table = tables.IPRangeTable
  452. class IPRangeBulkEditView(generic.BulkEditView):
  453. queryset = IPRange.objects.prefetch_related('vrf', 'tenant')
  454. filterset = filtersets.IPRangeFilterSet
  455. table = tables.IPRangeTable
  456. form = forms.IPRangeBulkEditForm
  457. class IPRangeBulkDeleteView(generic.BulkDeleteView):
  458. queryset = IPRange.objects.prefetch_related('vrf', 'tenant')
  459. filterset = filtersets.IPRangeFilterSet
  460. table = tables.IPRangeTable
  461. #
  462. # IP addresses
  463. #
  464. class IPAddressListView(generic.ObjectListView):
  465. queryset = IPAddress.objects.all()
  466. filterset = filtersets.IPAddressFilterSet
  467. filterset_form = forms.IPAddressFilterForm
  468. table = tables.IPAddressTable
  469. class IPAddressView(generic.ObjectView):
  470. queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
  471. def get_extra_context(self, request, instance):
  472. # Parent prefixes table
  473. parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
  474. vrf=instance.vrf,
  475. prefix__net_contains_or_equals=str(instance.address.ip)
  476. ).prefetch_related(
  477. 'site', 'role'
  478. )
  479. parent_prefixes_table = tables.PrefixTable(
  480. list(parent_prefixes),
  481. exclude=('vrf', 'utilization'),
  482. orderable=False
  483. )
  484. # Duplicate IPs table
  485. duplicate_ips = IPAddress.objects.restrict(request.user, 'view').filter(
  486. vrf=instance.vrf,
  487. address=str(instance.address)
  488. ).exclude(
  489. pk=instance.pk
  490. ).prefetch_related(
  491. 'nat_inside'
  492. )
  493. # Exclude anycast IPs if this IP is anycast
  494. if instance.role == IPAddressRoleChoices.ROLE_ANYCAST:
  495. duplicate_ips = duplicate_ips.exclude(role=IPAddressRoleChoices.ROLE_ANYCAST)
  496. # Limit to a maximum of 10 duplicates displayed here
  497. duplicate_ips_table = tables.IPAddressTable(duplicate_ips[:10], orderable=False)
  498. # Related IP table
  499. related_ips = IPAddress.objects.restrict(request.user, 'view').exclude(
  500. address=str(instance.address)
  501. ).filter(
  502. vrf=instance.vrf, address__net_contained_or_equal=str(instance.address)
  503. )
  504. related_ips_table = tables.IPAddressTable(related_ips, orderable=False)
  505. related_ips_table.configure(request)
  506. services = Service.objects.restrict(request.user, 'view').filter(ipaddresses=instance)
  507. return {
  508. 'parent_prefixes_table': parent_prefixes_table,
  509. 'duplicate_ips_table': duplicate_ips_table,
  510. 'more_duplicate_ips': duplicate_ips.count() > 10,
  511. 'related_ips_table': related_ips_table,
  512. 'services': services,
  513. }
  514. class IPAddressEditView(generic.ObjectEditView):
  515. queryset = IPAddress.objects.all()
  516. form = forms.IPAddressForm
  517. template_name = 'ipam/ipaddress_edit.html'
  518. def alter_object(self, obj, request, url_args, url_kwargs):
  519. if 'interface' in request.GET:
  520. try:
  521. obj.assigned_object = Interface.objects.get(pk=request.GET['interface'])
  522. except (ValueError, Interface.DoesNotExist):
  523. pass
  524. elif 'vminterface' in request.GET:
  525. try:
  526. obj.assigned_object = VMInterface.objects.get(pk=request.GET['vminterface'])
  527. except (ValueError, VMInterface.DoesNotExist):
  528. pass
  529. elif 'fhrpgroup' in request.GET:
  530. try:
  531. obj.assigned_object = FHRPGroup.objects.get(pk=request.GET['fhrpgroup'])
  532. except (ValueError, FHRPGroup.DoesNotExist):
  533. pass
  534. return obj
  535. # TODO: Standardize or remove this view
  536. class IPAddressAssignView(generic.ObjectView):
  537. """
  538. Search for IPAddresses to be assigned to an Interface.
  539. """
  540. queryset = IPAddress.objects.all()
  541. def dispatch(self, request, *args, **kwargs):
  542. # Redirect user if an interface has not been provided
  543. if 'interface' not in request.GET and 'vminterface' not in request.GET:
  544. return redirect('ipam:ipaddress_add')
  545. return super().dispatch(request, *args, **kwargs)
  546. def get(self, request):
  547. form = forms.IPAddressAssignForm()
  548. return render(request, 'ipam/ipaddress_assign.html', {
  549. 'form': form,
  550. 'return_url': request.GET.get('return_url', ''),
  551. })
  552. def post(self, request):
  553. form = forms.IPAddressAssignForm(request.POST)
  554. table = None
  555. if form.is_valid():
  556. addresses = self.queryset.prefetch_related('vrf', 'tenant')
  557. # Limit to 100 results
  558. addresses = filtersets.IPAddressFilterSet(request.POST, addresses).qs[:100]
  559. table = tables.IPAddressAssignTable(addresses)
  560. return render(request, 'ipam/ipaddress_assign.html', {
  561. 'form': form,
  562. 'table': table,
  563. 'return_url': request.GET.get('return_url'),
  564. })
  565. class IPAddressDeleteView(generic.ObjectDeleteView):
  566. queryset = IPAddress.objects.all()
  567. class IPAddressBulkCreateView(generic.BulkCreateView):
  568. queryset = IPAddress.objects.all()
  569. form = forms.IPAddressBulkCreateForm
  570. model_form = forms.IPAddressBulkAddForm
  571. pattern_target = 'address'
  572. template_name = 'ipam/ipaddress_bulk_add.html'
  573. class IPAddressBulkImportView(generic.BulkImportView):
  574. queryset = IPAddress.objects.all()
  575. model_form = forms.IPAddressCSVForm
  576. table = tables.IPAddressTable
  577. class IPAddressBulkEditView(generic.BulkEditView):
  578. queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
  579. filterset = filtersets.IPAddressFilterSet
  580. table = tables.IPAddressTable
  581. form = forms.IPAddressBulkEditForm
  582. class IPAddressBulkDeleteView(generic.BulkDeleteView):
  583. queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
  584. filterset = filtersets.IPAddressFilterSet
  585. table = tables.IPAddressTable
  586. #
  587. # VLAN groups
  588. #
  589. class VLANGroupListView(generic.ObjectListView):
  590. queryset = VLANGroup.objects.annotate(
  591. vlan_count=count_related(VLAN, 'group')
  592. )
  593. filterset = filtersets.VLANGroupFilterSet
  594. filterset_form = forms.VLANGroupFilterForm
  595. table = tables.VLANGroupTable
  596. class VLANGroupView(generic.ObjectView):
  597. queryset = VLANGroup.objects.all()
  598. def get_extra_context(self, request, instance):
  599. vlans = VLAN.objects.restrict(request.user, 'view').filter(group=instance).prefetch_related(
  600. Prefetch('prefixes', queryset=Prefix.objects.restrict(request.user))
  601. ).order_by('vid')
  602. vlans_count = vlans.count()
  603. vlans = add_available_vlans(vlans, vlan_group=instance)
  604. vlans_table = tables.VLANTable(vlans, user=request.user, exclude=('group',))
  605. if request.user.has_perm('ipam.change_vlan') or request.user.has_perm('ipam.delete_vlan'):
  606. vlans_table.columns.show('pk')
  607. vlans_table.configure(request)
  608. # Compile permissions list for rendering the object table
  609. permissions = {
  610. 'add': request.user.has_perm('ipam.add_vlan'),
  611. 'change': request.user.has_perm('ipam.change_vlan'),
  612. 'delete': request.user.has_perm('ipam.delete_vlan'),
  613. }
  614. return {
  615. 'vlans_count': vlans_count,
  616. 'vlans_table': vlans_table,
  617. 'permissions': permissions,
  618. }
  619. class VLANGroupEditView(generic.ObjectEditView):
  620. queryset = VLANGroup.objects.all()
  621. form = forms.VLANGroupForm
  622. class VLANGroupDeleteView(generic.ObjectDeleteView):
  623. queryset = VLANGroup.objects.all()
  624. class VLANGroupBulkImportView(generic.BulkImportView):
  625. queryset = VLANGroup.objects.all()
  626. model_form = forms.VLANGroupCSVForm
  627. table = tables.VLANGroupTable
  628. class VLANGroupBulkEditView(generic.BulkEditView):
  629. queryset = VLANGroup.objects.annotate(
  630. vlan_count=count_related(VLAN, 'group')
  631. )
  632. filterset = filtersets.VLANGroupFilterSet
  633. table = tables.VLANGroupTable
  634. form = forms.VLANGroupBulkEditForm
  635. class VLANGroupBulkDeleteView(generic.BulkDeleteView):
  636. queryset = VLANGroup.objects.annotate(
  637. vlan_count=count_related(VLAN, 'group')
  638. )
  639. filterset = filtersets.VLANGroupFilterSet
  640. table = tables.VLANGroupTable
  641. #
  642. # FHRP groups
  643. #
  644. class FHRPGroupListView(generic.ObjectListView):
  645. queryset = FHRPGroup.objects.annotate(
  646. member_count=count_related(FHRPGroupAssignment, 'group')
  647. )
  648. filterset = filtersets.FHRPGroupFilterSet
  649. filterset_form = forms.FHRPGroupFilterForm
  650. table = tables.FHRPGroupTable
  651. class FHRPGroupView(generic.ObjectView):
  652. queryset = FHRPGroup.objects.all()
  653. def get_extra_context(self, request, instance):
  654. # Get assigned IP addresses
  655. ipaddress_table = tables.AssignedIPAddressesTable(
  656. data=instance.ip_addresses.restrict(request.user, 'view').prefetch_related('vrf', 'tenant'),
  657. orderable=False
  658. )
  659. # Get assigned interfaces
  660. members_table = tables.FHRPGroupAssignmentTable(
  661. data=FHRPGroupAssignment.objects.restrict(request.user, 'view').filter(group=instance),
  662. orderable=False
  663. )
  664. members_table.columns.hide('group')
  665. return {
  666. 'ipaddress_table': ipaddress_table,
  667. 'members_table': members_table,
  668. 'member_count': FHRPGroupAssignment.objects.filter(group=instance).count(),
  669. }
  670. class FHRPGroupEditView(generic.ObjectEditView):
  671. queryset = FHRPGroup.objects.all()
  672. form = forms.FHRPGroupForm
  673. template_name = 'ipam/fhrpgroup_edit.html'
  674. def get_return_url(self, request, obj=None):
  675. return_url = super().get_return_url(request, obj)
  676. # If we're redirecting the user to the FHRPGroupAssignment creation form,
  677. # initialize the group field with the FHRPGroup we just saved.
  678. if return_url.startswith(reverse('ipam:fhrpgroupassignment_add')):
  679. return_url += f'&group={obj.pk}'
  680. return return_url
  681. class FHRPGroupDeleteView(generic.ObjectDeleteView):
  682. queryset = FHRPGroup.objects.all()
  683. class FHRPGroupBulkImportView(generic.BulkImportView):
  684. queryset = FHRPGroup.objects.all()
  685. model_form = forms.FHRPGroupCSVForm
  686. table = tables.FHRPGroupTable
  687. class FHRPGroupBulkEditView(generic.BulkEditView):
  688. queryset = FHRPGroup.objects.all()
  689. filterset = filtersets.FHRPGroupFilterSet
  690. table = tables.FHRPGroupTable
  691. form = forms.FHRPGroupBulkEditForm
  692. class FHRPGroupBulkDeleteView(generic.BulkDeleteView):
  693. queryset = FHRPGroup.objects.all()
  694. filterset = filtersets.FHRPGroupFilterSet
  695. table = tables.FHRPGroupTable
  696. #
  697. # FHRP group assignments
  698. #
  699. class FHRPGroupAssignmentEditView(generic.ObjectEditView):
  700. queryset = FHRPGroupAssignment.objects.all()
  701. form = forms.FHRPGroupAssignmentForm
  702. template_name = 'ipam/fhrpgroupassignment_edit.html'
  703. def alter_object(self, instance, request, args, kwargs):
  704. if not instance.pk:
  705. # Assign the interface based on URL kwargs
  706. content_type = get_object_or_404(ContentType, pk=request.GET.get('interface_type'))
  707. instance.interface = get_object_or_404(content_type.model_class(), pk=request.GET.get('interface_id'))
  708. return instance
  709. class FHRPGroupAssignmentDeleteView(generic.ObjectDeleteView):
  710. queryset = FHRPGroupAssignment.objects.all()
  711. #
  712. # VLANs
  713. #
  714. class VLANListView(generic.ObjectListView):
  715. queryset = VLAN.objects.all()
  716. filterset = filtersets.VLANFilterSet
  717. filterset_form = forms.VLANFilterForm
  718. table = tables.VLANTable
  719. class VLANView(generic.ObjectView):
  720. queryset = VLAN.objects.prefetch_related('site__region', 'tenant__group', 'role')
  721. def get_extra_context(self, request, instance):
  722. prefixes = Prefix.objects.restrict(request.user, 'view').filter(vlan=instance).prefetch_related(
  723. 'vrf', 'site', 'role'
  724. )
  725. prefix_table = tables.PrefixTable(list(prefixes), exclude=('vlan', 'utilization'), orderable=False)
  726. return {
  727. 'prefix_table': prefix_table,
  728. }
  729. class VLANInterfacesView(generic.ObjectChildrenView):
  730. queryset = VLAN.objects.all()
  731. child_model = Interface
  732. table = tables.VLANDevicesTable
  733. filterset = InterfaceFilterSet
  734. template_name = 'ipam/vlan/interfaces.html'
  735. def get_children(self, request, parent):
  736. return parent.get_interfaces().restrict(request.user, 'view')
  737. def get_extra_context(self, request, instance):
  738. return {
  739. 'active_tab': 'interfaces',
  740. }
  741. class VLANVMInterfacesView(generic.ObjectChildrenView):
  742. queryset = VLAN.objects.all()
  743. child_model = VMInterface
  744. table = tables.VLANVirtualMachinesTable
  745. filterset = VMInterfaceFilterSet
  746. template_name = 'ipam/vlan/vminterfaces.html'
  747. def get_children(self, request, parent):
  748. return parent.get_vminterfaces().restrict(request.user, 'view')
  749. def get_extra_context(self, request, instance):
  750. return {
  751. 'active_tab': 'vminterfaces',
  752. }
  753. class VLANEditView(generic.ObjectEditView):
  754. queryset = VLAN.objects.all()
  755. form = forms.VLANForm
  756. template_name = 'ipam/vlan_edit.html'
  757. class VLANDeleteView(generic.ObjectDeleteView):
  758. queryset = VLAN.objects.all()
  759. class VLANBulkImportView(generic.BulkImportView):
  760. queryset = VLAN.objects.all()
  761. model_form = forms.VLANCSVForm
  762. table = tables.VLANTable
  763. class VLANBulkEditView(generic.BulkEditView):
  764. queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role')
  765. filterset = filtersets.VLANFilterSet
  766. table = tables.VLANTable
  767. form = forms.VLANBulkEditForm
  768. class VLANBulkDeleteView(generic.BulkDeleteView):
  769. queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role')
  770. filterset = filtersets.VLANFilterSet
  771. table = tables.VLANTable
  772. #
  773. # Service templates
  774. #
  775. class ServiceTemplateListView(generic.ObjectListView):
  776. queryset = ServiceTemplate.objects.all()
  777. filterset = filtersets.ServiceTemplateFilterSet
  778. filterset_form = forms.ServiceTemplateFilterForm
  779. table = tables.ServiceTemplateTable
  780. class ServiceTemplateView(generic.ObjectView):
  781. queryset = ServiceTemplate.objects.all()
  782. class ServiceTemplateEditView(generic.ObjectEditView):
  783. queryset = ServiceTemplate.objects.all()
  784. form = forms.ServiceTemplateForm
  785. class ServiceTemplateDeleteView(generic.ObjectDeleteView):
  786. queryset = ServiceTemplate.objects.all()
  787. class ServiceTemplateBulkImportView(generic.BulkImportView):
  788. queryset = ServiceTemplate.objects.all()
  789. model_form = forms.ServiceTemplateCSVForm
  790. table = tables.ServiceTemplateTable
  791. class ServiceTemplateBulkEditView(generic.BulkEditView):
  792. queryset = ServiceTemplate.objects.all()
  793. filterset = filtersets.ServiceTemplateFilterSet
  794. table = tables.ServiceTemplateTable
  795. form = forms.ServiceTemplateBulkEditForm
  796. class ServiceTemplateBulkDeleteView(generic.BulkDeleteView):
  797. queryset = ServiceTemplate.objects.all()
  798. filterset = filtersets.ServiceTemplateFilterSet
  799. table = tables.ServiceTemplateTable
  800. #
  801. # Services
  802. #
  803. class ServiceListView(generic.ObjectListView):
  804. queryset = Service.objects.all()
  805. filterset = filtersets.ServiceFilterSet
  806. filterset_form = forms.ServiceFilterForm
  807. table = tables.ServiceTable
  808. class ServiceView(generic.ObjectView):
  809. queryset = Service.objects.prefetch_related('ipaddresses')
  810. class ServiceCreateView(generic.ObjectEditView):
  811. queryset = Service.objects.all()
  812. form = forms.ServiceCreateForm
  813. template_name = 'ipam/service_create.html'
  814. class ServiceEditView(generic.ObjectEditView):
  815. queryset = Service.objects.prefetch_related('ipaddresses')
  816. form = forms.ServiceForm
  817. template_name = 'ipam/service_edit.html'
  818. class ServiceDeleteView(generic.ObjectDeleteView):
  819. queryset = Service.objects.all()
  820. class ServiceBulkImportView(generic.BulkImportView):
  821. queryset = Service.objects.all()
  822. model_form = forms.ServiceCSVForm
  823. table = tables.ServiceTable
  824. class ServiceBulkEditView(generic.BulkEditView):
  825. queryset = Service.objects.prefetch_related('device', 'virtual_machine')
  826. filterset = filtersets.ServiceFilterSet
  827. table = tables.ServiceTable
  828. form = forms.ServiceBulkEditForm
  829. class ServiceBulkDeleteView(generic.BulkDeleteView):
  830. queryset = Service.objects.prefetch_related('device', 'virtual_machine')
  831. filterset = filtersets.ServiceFilterSet
  832. table = tables.ServiceTable