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