views.py 53 KB

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