ip.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. import django_tables2 as tables
  2. from django.utils.safestring import mark_safe
  3. from django_tables2.utils import Accessor
  4. from ipam.models import *
  5. from netbox.tables import NetBoxTable, columns
  6. from tenancy.tables import TenancyColumnsMixin, TenantColumn
  7. __all__ = (
  8. 'AggregateTable',
  9. 'ASNTable',
  10. 'AssignedIPAddressesTable',
  11. 'IPAddressAssignTable',
  12. 'IPAddressTable',
  13. 'IPRangeTable',
  14. 'PrefixTable',
  15. 'RIRTable',
  16. 'RoleTable',
  17. )
  18. AVAILABLE_LABEL = mark_safe('<span class="badge bg-success">Available</span>')
  19. PREFIX_LINK = """
  20. {% if record.pk %}
  21. <a href="{{ record.get_absolute_url }}">{{ record.prefix }}</a>
  22. {% else %}
  23. <a href="{% url 'ipam:prefix_add' %}?prefix={{ record }}{% if object.vrf %}&vrf={{ object.vrf.pk }}{% endif %}{% if object.site %}&site={{ object.site.pk }}{% endif %}{% if object.tenant %}&tenant_group={{ object.tenant.group.pk }}&tenant={{ object.tenant.pk }}{% endif %}">{{ record.prefix }}</a>
  24. {% endif %}
  25. """
  26. PREFIX_LINK_WITH_DEPTH = """
  27. {% load helpers %}
  28. {% if record.depth %}
  29. <div class="record-depth">
  30. {% for i in record.depth|as_range %}
  31. <span>•</span>
  32. {% endfor %}
  33. </div>
  34. {% endif %}
  35. """ + PREFIX_LINK
  36. IPADDRESS_LINK = """
  37. {% if record.pk %}
  38. <a href="{{ record.get_absolute_url }}">{{ record.address }}</a>
  39. {% elif perms.ipam.add_ipaddress %}
  40. <a href="{% url 'ipam:ipaddress_add' %}?address={{ record.1 }}{% if object.vrf %}&vrf={{ object.vrf.pk }}{% endif %}{% if object.tenant %}&tenant={{ object.tenant.pk }}{% endif %}" class="btn btn-sm btn-success">{% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available</a>
  41. {% else %}
  42. {% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available
  43. {% endif %}
  44. """
  45. IPADDRESS_ASSIGN_LINK = """
  46. <a href="{% url 'ipam:ipaddress_edit' pk=record.pk %}?{% if request.GET.interface %}interface={{ request.GET.interface }}{% elif request.GET.vminterface %}vminterface={{ request.GET.vminterface }}{% endif %}&return_url={{ request.GET.return_url }}">{{ record }}</a>
  47. """
  48. VRF_LINK = """
  49. {% if value %}
  50. <a href="{{ record.vrf.get_absolute_url }}">{{ record.vrf }}</a>
  51. {% elif object.vrf %}
  52. <a href="{{ object.vrf.get_absolute_url }}">{{ object.vrf }}</a>
  53. {% else %}
  54. Global
  55. {% endif %}
  56. """
  57. #
  58. # RIRs
  59. #
  60. class RIRTable(NetBoxTable):
  61. name = tables.Column(
  62. linkify=True
  63. )
  64. is_private = columns.BooleanColumn(
  65. verbose_name='Private'
  66. )
  67. aggregate_count = columns.LinkedCountColumn(
  68. viewname='ipam:aggregate_list',
  69. url_params={'rir_id': 'pk'},
  70. verbose_name='Aggregates'
  71. )
  72. tags = columns.TagColumn(
  73. url_name='ipam:rir_list'
  74. )
  75. class Meta(NetBoxTable.Meta):
  76. model = RIR
  77. fields = (
  78. 'pk', 'id', 'name', 'slug', 'is_private', 'aggregate_count', 'description', 'tags', 'created',
  79. 'last_updated', 'actions',
  80. )
  81. default_columns = ('pk', 'name', 'is_private', 'aggregate_count', 'description')
  82. #
  83. # ASNs
  84. #
  85. class ASNTable(TenancyColumnsMixin, NetBoxTable):
  86. asn = tables.Column(
  87. linkify=True
  88. )
  89. asn_asdot = tables.Column(
  90. accessor=tables.A('asn_asdot'),
  91. linkify=True,
  92. verbose_name='ASDOT'
  93. )
  94. site_count = columns.LinkedCountColumn(
  95. viewname='dcim:site_list',
  96. url_params={'asn_id': 'pk'},
  97. verbose_name='Site Count'
  98. )
  99. provider_count = columns.LinkedCountColumn(
  100. viewname='circuits:provider_list',
  101. url_params={'asn_id': 'pk'},
  102. verbose_name='Provider Count'
  103. )
  104. sites = columns.ManyToManyColumn(
  105. linkify_item=True,
  106. verbose_name='Sites'
  107. )
  108. tags = columns.TagColumn(
  109. url_name='ipam:asn_list'
  110. )
  111. class Meta(NetBoxTable.Meta):
  112. model = ASN
  113. fields = (
  114. 'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'provider_count', 'tenant', 'tenant_group', 'description', 'sites', 'tags',
  115. 'created', 'last_updated', 'actions',
  116. )
  117. default_columns = ('pk', 'asn', 'rir', 'site_count', 'provider_count', 'sites', 'description', 'tenant')
  118. #
  119. # Aggregates
  120. #
  121. class AggregateTable(TenancyColumnsMixin, NetBoxTable):
  122. prefix = tables.Column(
  123. linkify=True,
  124. verbose_name='Aggregate'
  125. )
  126. date_added = tables.DateColumn(
  127. format="Y-m-d",
  128. verbose_name='Added'
  129. )
  130. child_count = tables.Column(
  131. verbose_name='Prefixes'
  132. )
  133. utilization = columns.UtilizationColumn(
  134. accessor='get_utilization',
  135. orderable=False
  136. )
  137. tags = columns.TagColumn(
  138. url_name='ipam:aggregate_list'
  139. )
  140. class Meta(NetBoxTable.Meta):
  141. model = Aggregate
  142. fields = (
  143. 'pk', 'id', 'prefix', 'rir', 'tenant', 'tenant_group', 'child_count', 'utilization', 'date_added', 'description', 'tags',
  144. 'created', 'last_updated',
  145. )
  146. default_columns = ('pk', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description')
  147. #
  148. # Roles
  149. #
  150. class RoleTable(NetBoxTable):
  151. name = tables.Column(
  152. linkify=True
  153. )
  154. prefix_count = columns.LinkedCountColumn(
  155. viewname='ipam:prefix_list',
  156. url_params={'role_id': 'pk'},
  157. verbose_name='Prefixes'
  158. )
  159. iprange_count = columns.LinkedCountColumn(
  160. viewname='ipam:iprange_list',
  161. url_params={'role_id': 'pk'},
  162. verbose_name='IP Ranges'
  163. )
  164. vlan_count = columns.LinkedCountColumn(
  165. viewname='ipam:vlan_list',
  166. url_params={'role_id': 'pk'},
  167. verbose_name='VLANs'
  168. )
  169. tags = columns.TagColumn(
  170. url_name='ipam:role_list'
  171. )
  172. class Meta(NetBoxTable.Meta):
  173. model = Role
  174. fields = (
  175. 'pk', 'id', 'name', 'slug', 'prefix_count', 'iprange_count', 'vlan_count', 'description', 'weight', 'tags',
  176. 'created', 'last_updated', 'actions',
  177. )
  178. default_columns = ('pk', 'name', 'prefix_count', 'iprange_count', 'vlan_count', 'description')
  179. #
  180. # Prefixes
  181. #
  182. class PrefixUtilizationColumn(columns.UtilizationColumn):
  183. """
  184. Extend UtilizationColumn to allow disabling the warning & danger thresholds for prefixes
  185. marked as fully utilized.
  186. """
  187. template_code = """
  188. {% load helpers %}
  189. {% if record.pk and record.mark_utilized %}
  190. {% utilization_graph value warning_threshold=0 danger_threshold=0 %}
  191. {% elif record.pk %}
  192. {% utilization_graph value %}
  193. {% endif %}
  194. """
  195. class PrefixTable(TenancyColumnsMixin, NetBoxTable):
  196. prefix = columns.TemplateColumn(
  197. template_code=PREFIX_LINK_WITH_DEPTH,
  198. export_raw=True,
  199. attrs={'td': {'class': 'text-nowrap'}}
  200. )
  201. prefix_flat = columns.TemplateColumn(
  202. accessor=Accessor('prefix'),
  203. template_code=PREFIX_LINK,
  204. export_raw=True,
  205. verbose_name='Prefix (Flat)'
  206. )
  207. depth = tables.Column(
  208. accessor=Accessor('_depth'),
  209. verbose_name='Depth'
  210. )
  211. children = columns.LinkedCountColumn(
  212. accessor=Accessor('_children'),
  213. viewname='ipam:prefix_list',
  214. url_params={
  215. 'vrf_id': 'vrf_id',
  216. 'within': 'prefix',
  217. },
  218. verbose_name='Children'
  219. )
  220. status = columns.ChoiceFieldColumn(
  221. default=AVAILABLE_LABEL
  222. )
  223. vrf = tables.TemplateColumn(
  224. template_code=VRF_LINK,
  225. verbose_name='VRF'
  226. )
  227. site = tables.Column(
  228. linkify=True
  229. )
  230. vlan_group = tables.Column(
  231. accessor='vlan__group',
  232. linkify=True,
  233. verbose_name='VLAN Group'
  234. )
  235. vlan = tables.Column(
  236. linkify=True,
  237. verbose_name='VLAN'
  238. )
  239. role = tables.Column(
  240. linkify=True
  241. )
  242. is_pool = columns.BooleanColumn(
  243. verbose_name='Pool'
  244. )
  245. mark_utilized = columns.BooleanColumn(
  246. verbose_name='Marked Utilized'
  247. )
  248. utilization = PrefixUtilizationColumn(
  249. accessor='get_utilization',
  250. orderable=False
  251. )
  252. tags = columns.TagColumn(
  253. url_name='ipam:prefix_list'
  254. )
  255. class Meta(NetBoxTable.Meta):
  256. model = Prefix
  257. fields = (
  258. 'pk', 'id', 'prefix', 'prefix_flat', 'status', 'children', 'vrf', 'utilization', 'tenant', 'tenant_group', 'site',
  259. 'vlan_group', 'vlan', 'role', 'is_pool', 'mark_utilized', 'description', 'tags', 'created', 'last_updated',
  260. )
  261. default_columns = (
  262. 'pk', 'prefix', 'status', 'children', 'vrf', 'utilization', 'tenant', 'site', 'vlan', 'role', 'description',
  263. )
  264. row_attrs = {
  265. 'class': lambda record: 'success' if not record.pk else '',
  266. }
  267. #
  268. # IP ranges
  269. #
  270. class IPRangeTable(TenancyColumnsMixin, NetBoxTable):
  271. start_address = tables.Column(
  272. linkify=True
  273. )
  274. vrf = tables.TemplateColumn(
  275. template_code=VRF_LINK,
  276. verbose_name='VRF'
  277. )
  278. status = columns.ChoiceFieldColumn(
  279. default=AVAILABLE_LABEL
  280. )
  281. role = tables.Column(
  282. linkify=True
  283. )
  284. utilization = columns.UtilizationColumn(
  285. accessor='utilization',
  286. orderable=False
  287. )
  288. tags = columns.TagColumn(
  289. url_name='ipam:iprange_list'
  290. )
  291. class Meta(NetBoxTable.Meta):
  292. model = IPRange
  293. fields = (
  294. 'pk', 'id', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'description',
  295. 'utilization', 'tags', 'created', 'last_updated',
  296. )
  297. default_columns = (
  298. 'pk', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'description',
  299. )
  300. row_attrs = {
  301. 'class': lambda record: 'success' if not record.pk else '',
  302. }
  303. #
  304. # IPAddresses
  305. #
  306. class IPAddressTable(TenancyColumnsMixin, NetBoxTable):
  307. address = tables.TemplateColumn(
  308. template_code=IPADDRESS_LINK,
  309. verbose_name='IP Address'
  310. )
  311. vrf = tables.TemplateColumn(
  312. template_code=VRF_LINK,
  313. verbose_name='VRF'
  314. )
  315. status = columns.ChoiceFieldColumn(
  316. default=AVAILABLE_LABEL
  317. )
  318. role = columns.ChoiceFieldColumn()
  319. assigned_object = tables.Column(
  320. linkify=True,
  321. orderable=False,
  322. verbose_name='Interface'
  323. )
  324. assigned_object_parent = tables.Column(
  325. accessor='assigned_object__parent_object',
  326. linkify=True,
  327. orderable=False,
  328. verbose_name='Device/VM'
  329. )
  330. nat_inside = tables.Column(
  331. linkify=True,
  332. orderable=False,
  333. verbose_name='NAT (Inside)'
  334. )
  335. nat_outside = tables.ManyToManyColumn(
  336. linkify_item=True,
  337. orderable=False,
  338. verbose_name='NAT (Outside)'
  339. )
  340. assigned = columns.BooleanColumn(
  341. accessor='assigned_object_id',
  342. linkify=lambda record: record.assigned_object.get_absolute_url(),
  343. verbose_name='Assigned'
  344. )
  345. tags = columns.TagColumn(
  346. url_name='ipam:ipaddress_list'
  347. )
  348. class Meta(NetBoxTable.Meta):
  349. model = IPAddress
  350. fields = (
  351. 'pk', 'id', 'address', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'nat_inside', 'nat_outside', 'assigned', 'dns_name', 'description',
  352. 'tags', 'created', 'last_updated',
  353. )
  354. default_columns = (
  355. 'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'assigned', 'dns_name', 'description',
  356. )
  357. row_attrs = {
  358. 'class': lambda record: 'success' if not isinstance(record, IPAddress) else '',
  359. }
  360. class IPAddressAssignTable(NetBoxTable):
  361. address = tables.TemplateColumn(
  362. template_code=IPADDRESS_ASSIGN_LINK,
  363. verbose_name='IP Address'
  364. )
  365. status = columns.ChoiceFieldColumn()
  366. assigned_object = tables.Column(
  367. orderable=False
  368. )
  369. class Meta(NetBoxTable.Meta):
  370. model = IPAddress
  371. fields = ('address', 'dns_name', 'vrf', 'status', 'role', 'tenant', 'assigned_object', 'description')
  372. exclude = ('id', )
  373. orderable = False
  374. class AssignedIPAddressesTable(NetBoxTable):
  375. """
  376. List IP addresses assigned to an object.
  377. """
  378. address = tables.Column(
  379. linkify=True,
  380. verbose_name='IP Address'
  381. )
  382. vrf = tables.TemplateColumn(
  383. template_code=VRF_LINK,
  384. verbose_name='VRF'
  385. )
  386. status = columns.ChoiceFieldColumn()
  387. tenant = TenantColumn()
  388. class Meta(NetBoxTable.Meta):
  389. model = IPAddress
  390. fields = ('address', 'vrf', 'status', 'role', 'tenant', 'description')
  391. exclude = ('id', )