filtersets.py 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082
  1. import django_filters
  2. import netaddr
  3. from django.contrib.contenttypes.models import ContentType
  4. from django.core.exceptions import ValidationError
  5. from django.db.models import Q
  6. from django.utils.translation import gettext as _
  7. from drf_spectacular.types import OpenApiTypes
  8. from drf_spectacular.utils import extend_schema_field
  9. from netaddr.core import AddrFormatError
  10. from dcim.models import Device, Interface, Region, Site, SiteGroup
  11. from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet
  12. from tenancy.filtersets import TenancyFilterSet
  13. from utilities.filters import (
  14. ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NumericArrayFilter, TreeNodeMultipleChoiceFilter,
  15. )
  16. from virtualization.models import VirtualMachine, VMInterface
  17. from vpn.models import L2VPN
  18. from .choices import *
  19. from .models import *
  20. __all__ = (
  21. 'AggregateFilterSet',
  22. 'ASNFilterSet',
  23. 'ASNRangeFilterSet',
  24. 'FHRPGroupAssignmentFilterSet',
  25. 'FHRPGroupFilterSet',
  26. 'IPAddressFilterSet',
  27. 'IPRangeFilterSet',
  28. 'PrefixFilterSet',
  29. 'PrimaryIPFilterSet',
  30. 'RIRFilterSet',
  31. 'RoleFilterSet',
  32. 'RouteTargetFilterSet',
  33. 'ServiceFilterSet',
  34. 'ServiceTemplateFilterSet',
  35. 'VLANFilterSet',
  36. 'VLANGroupFilterSet',
  37. 'VRFFilterSet',
  38. )
  39. class VRFFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
  40. import_target_id = django_filters.ModelMultipleChoiceFilter(
  41. field_name='import_targets',
  42. queryset=RouteTarget.objects.all(),
  43. label=_('Import target'),
  44. )
  45. import_target = django_filters.ModelMultipleChoiceFilter(
  46. field_name='import_targets__name',
  47. queryset=RouteTarget.objects.all(),
  48. to_field_name='name',
  49. label=_('Import target (name)'),
  50. )
  51. export_target_id = django_filters.ModelMultipleChoiceFilter(
  52. field_name='export_targets',
  53. queryset=RouteTarget.objects.all(),
  54. label=_('Export target'),
  55. )
  56. export_target = django_filters.ModelMultipleChoiceFilter(
  57. field_name='export_targets__name',
  58. queryset=RouteTarget.objects.all(),
  59. to_field_name='name',
  60. label=_('Export target (name)'),
  61. )
  62. def search(self, queryset, name, value):
  63. if not value.strip():
  64. return queryset
  65. return queryset.filter(
  66. Q(name__icontains=value) |
  67. Q(rd__icontains=value) |
  68. Q(description__icontains=value)
  69. )
  70. class Meta:
  71. model = VRF
  72. fields = ['id', 'name', 'rd', 'enforce_unique', 'description']
  73. class RouteTargetFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
  74. importing_vrf_id = django_filters.ModelMultipleChoiceFilter(
  75. field_name='importing_vrfs',
  76. queryset=VRF.objects.all(),
  77. label=_('Importing VRF'),
  78. )
  79. importing_vrf = django_filters.ModelMultipleChoiceFilter(
  80. field_name='importing_vrfs__rd',
  81. queryset=VRF.objects.all(),
  82. to_field_name='rd',
  83. label=_('Import VRF (RD)'),
  84. )
  85. exporting_vrf_id = django_filters.ModelMultipleChoiceFilter(
  86. field_name='exporting_vrfs',
  87. queryset=VRF.objects.all(),
  88. label=_('Exporting VRF'),
  89. )
  90. exporting_vrf = django_filters.ModelMultipleChoiceFilter(
  91. field_name='exporting_vrfs__rd',
  92. queryset=VRF.objects.all(),
  93. to_field_name='rd',
  94. label=_('Export VRF (RD)'),
  95. )
  96. def search(self, queryset, name, value):
  97. if not value.strip():
  98. return queryset
  99. return queryset.filter(
  100. Q(name__icontains=value) |
  101. Q(description__icontains=value)
  102. )
  103. class Meta:
  104. model = RouteTarget
  105. fields = ['id', 'name', 'description']
  106. class RIRFilterSet(OrganizationalModelFilterSet):
  107. class Meta:
  108. model = RIR
  109. fields = ['id', 'name', 'slug', 'is_private', 'description']
  110. class AggregateFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
  111. family = django_filters.NumberFilter(
  112. field_name='prefix',
  113. lookup_expr='family'
  114. )
  115. prefix = django_filters.CharFilter(
  116. method='filter_prefix',
  117. label=_('Prefix'),
  118. )
  119. rir_id = django_filters.ModelMultipleChoiceFilter(
  120. queryset=RIR.objects.all(),
  121. label=_('RIR (ID)'),
  122. )
  123. rir = django_filters.ModelMultipleChoiceFilter(
  124. field_name='rir__slug',
  125. queryset=RIR.objects.all(),
  126. to_field_name='slug',
  127. label=_('RIR (slug)'),
  128. )
  129. class Meta:
  130. model = Aggregate
  131. fields = ['id', 'date_added', 'description']
  132. def search(self, queryset, name, value):
  133. if not value.strip():
  134. return queryset
  135. qs_filter = Q(description__icontains=value)
  136. qs_filter |= Q(prefix__contains=value.strip())
  137. try:
  138. prefix = str(netaddr.IPNetwork(value.strip()).cidr)
  139. qs_filter |= Q(prefix__net_contains_or_equals=prefix)
  140. qs_filter |= Q(prefix__contains=value.strip())
  141. except (AddrFormatError, ValueError):
  142. pass
  143. return queryset.filter(qs_filter)
  144. def filter_prefix(self, queryset, name, value):
  145. if not value.strip():
  146. return queryset
  147. try:
  148. query = str(netaddr.IPNetwork(value).cidr)
  149. return queryset.filter(prefix=query)
  150. except (AddrFormatError, ValueError):
  151. return queryset.none()
  152. class ASNRangeFilterSet(OrganizationalModelFilterSet, TenancyFilterSet):
  153. rir_id = django_filters.ModelMultipleChoiceFilter(
  154. queryset=RIR.objects.all(),
  155. label=_('RIR (ID)'),
  156. )
  157. rir = django_filters.ModelMultipleChoiceFilter(
  158. field_name='rir__slug',
  159. queryset=RIR.objects.all(),
  160. to_field_name='slug',
  161. label=_('RIR (slug)'),
  162. )
  163. class Meta:
  164. model = ASNRange
  165. fields = ['id', 'name', 'start', 'end', 'description']
  166. def search(self, queryset, name, value):
  167. if not value.strip():
  168. return queryset
  169. qs_filter = Q(description__icontains=value)
  170. return queryset.filter(qs_filter)
  171. class ASNFilterSet(OrganizationalModelFilterSet, TenancyFilterSet):
  172. rir_id = django_filters.ModelMultipleChoiceFilter(
  173. queryset=RIR.objects.all(),
  174. label=_('RIR (ID)'),
  175. )
  176. rir = django_filters.ModelMultipleChoiceFilter(
  177. field_name='rir__slug',
  178. queryset=RIR.objects.all(),
  179. to_field_name='slug',
  180. label=_('RIR (slug)'),
  181. )
  182. site_id = django_filters.ModelMultipleChoiceFilter(
  183. field_name='sites',
  184. queryset=Site.objects.all(),
  185. label=_('Site (ID)'),
  186. )
  187. site = django_filters.ModelMultipleChoiceFilter(
  188. field_name='sites__slug',
  189. queryset=Site.objects.all(),
  190. to_field_name='slug',
  191. label=_('Site (slug)'),
  192. )
  193. class Meta:
  194. model = ASN
  195. fields = ['id', 'asn', 'description']
  196. def search(self, queryset, name, value):
  197. if not value.strip():
  198. return queryset
  199. qs_filter = Q(description__icontains=value)
  200. try:
  201. qs_filter |= Q(asn=int(value))
  202. except ValueError:
  203. pass
  204. return queryset.filter(qs_filter)
  205. class RoleFilterSet(OrganizationalModelFilterSet):
  206. class Meta:
  207. model = Role
  208. fields = ['id', 'name', 'slug', 'description']
  209. class PrefixFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
  210. family = django_filters.NumberFilter(
  211. field_name='prefix',
  212. lookup_expr='family'
  213. )
  214. prefix = MultiValueCharFilter(
  215. method='filter_prefix',
  216. label=_('Prefix'),
  217. )
  218. within = django_filters.CharFilter(
  219. method='search_within',
  220. label=_('Within prefix'),
  221. )
  222. within_include = django_filters.CharFilter(
  223. method='search_within_include',
  224. label=_('Within and including prefix'),
  225. )
  226. contains = django_filters.CharFilter(
  227. method='search_contains',
  228. label=_('Prefixes which contain this prefix or IP'),
  229. )
  230. depth = MultiValueNumberFilter(
  231. field_name='_depth'
  232. )
  233. children = MultiValueNumberFilter(
  234. field_name='_children'
  235. )
  236. mask_length = MultiValueNumberFilter(
  237. field_name='prefix',
  238. lookup_expr='net_mask_length',
  239. label=_('Mask length')
  240. )
  241. mask_length__gte = django_filters.NumberFilter(
  242. field_name='prefix',
  243. lookup_expr='net_mask_length__gte'
  244. )
  245. mask_length__lte = django_filters.NumberFilter(
  246. field_name='prefix',
  247. lookup_expr='net_mask_length__lte'
  248. )
  249. vrf_id = django_filters.ModelMultipleChoiceFilter(
  250. queryset=VRF.objects.all(),
  251. label=_('VRF'),
  252. )
  253. vrf = django_filters.ModelMultipleChoiceFilter(
  254. field_name='vrf__rd',
  255. queryset=VRF.objects.all(),
  256. to_field_name='rd',
  257. label=_('VRF (RD)'),
  258. )
  259. present_in_vrf_id = django_filters.ModelChoiceFilter(
  260. queryset=VRF.objects.all(),
  261. method='filter_present_in_vrf',
  262. label=_('VRF')
  263. )
  264. present_in_vrf = django_filters.ModelChoiceFilter(
  265. queryset=VRF.objects.all(),
  266. method='filter_present_in_vrf',
  267. to_field_name='rd',
  268. label=_('VRF (RD)'),
  269. )
  270. region_id = TreeNodeMultipleChoiceFilter(
  271. queryset=Region.objects.all(),
  272. field_name='site__region',
  273. lookup_expr='in',
  274. label=_('Region (ID)'),
  275. )
  276. region = TreeNodeMultipleChoiceFilter(
  277. queryset=Region.objects.all(),
  278. field_name='site__region',
  279. lookup_expr='in',
  280. to_field_name='slug',
  281. label=_('Region (slug)'),
  282. )
  283. site_group_id = TreeNodeMultipleChoiceFilter(
  284. queryset=SiteGroup.objects.all(),
  285. field_name='site__group',
  286. lookup_expr='in',
  287. label=_('Site group (ID)'),
  288. )
  289. site_group = TreeNodeMultipleChoiceFilter(
  290. queryset=SiteGroup.objects.all(),
  291. field_name='site__group',
  292. lookup_expr='in',
  293. to_field_name='slug',
  294. label=_('Site group (slug)'),
  295. )
  296. site_id = django_filters.ModelMultipleChoiceFilter(
  297. queryset=Site.objects.all(),
  298. label=_('Site (ID)'),
  299. )
  300. site = django_filters.ModelMultipleChoiceFilter(
  301. field_name='site__slug',
  302. queryset=Site.objects.all(),
  303. to_field_name='slug',
  304. label=_('Site (slug)'),
  305. )
  306. vlan_id = django_filters.ModelMultipleChoiceFilter(
  307. queryset=VLAN.objects.all(),
  308. label=_('VLAN (ID)'),
  309. )
  310. vlan_vid = django_filters.NumberFilter(
  311. field_name='vlan__vid',
  312. label=_('VLAN number (1-4094)'),
  313. )
  314. role_id = django_filters.ModelMultipleChoiceFilter(
  315. queryset=Role.objects.all(),
  316. label=_('Role (ID)'),
  317. )
  318. role = django_filters.ModelMultipleChoiceFilter(
  319. field_name='role__slug',
  320. queryset=Role.objects.all(),
  321. to_field_name='slug',
  322. label=_('Role (slug)'),
  323. )
  324. status = django_filters.MultipleChoiceFilter(
  325. choices=PrefixStatusChoices,
  326. null_value=None
  327. )
  328. class Meta:
  329. model = Prefix
  330. fields = ['id', 'is_pool', 'mark_utilized', 'description']
  331. def search(self, queryset, name, value):
  332. if not value.strip():
  333. return queryset
  334. qs_filter = Q(description__icontains=value)
  335. qs_filter |= Q(prefix__contains=value.strip())
  336. try:
  337. prefix = str(netaddr.IPNetwork(value.strip()).cidr)
  338. qs_filter |= Q(prefix__net_contains_or_equals=prefix)
  339. qs_filter |= Q(prefix__contains=value.strip())
  340. except (AddrFormatError, ValueError):
  341. pass
  342. return queryset.filter(qs_filter)
  343. def filter_prefix(self, queryset, name, value):
  344. query_values = []
  345. for v in value:
  346. try:
  347. query_values.append(netaddr.IPNetwork(v))
  348. except (AddrFormatError, ValueError):
  349. pass
  350. return queryset.filter(prefix__in=query_values)
  351. def search_within(self, queryset, name, value):
  352. value = value.strip()
  353. if not value:
  354. return queryset
  355. try:
  356. query = str(netaddr.IPNetwork(value).cidr)
  357. return queryset.filter(prefix__net_contained=query)
  358. except (AddrFormatError, ValueError):
  359. return queryset.none()
  360. def search_within_include(self, queryset, name, value):
  361. value = value.strip()
  362. if not value:
  363. return queryset
  364. try:
  365. query = str(netaddr.IPNetwork(value).cidr)
  366. return queryset.filter(prefix__net_contained_or_equal=query)
  367. except (AddrFormatError, ValueError):
  368. return queryset.none()
  369. def search_contains(self, queryset, name, value):
  370. value = value.strip()
  371. if not value:
  372. return queryset
  373. try:
  374. # Searching by prefix
  375. if '/' in value:
  376. return queryset.filter(prefix__net_contains_or_equals=str(netaddr.IPNetwork(value).cidr))
  377. # Searching by IP address
  378. else:
  379. return queryset.filter(prefix__net_contains=str(netaddr.IPAddress(value)))
  380. except (AddrFormatError, ValueError):
  381. return queryset.none()
  382. @extend_schema_field(OpenApiTypes.STR)
  383. def filter_present_in_vrf(self, queryset, name, vrf):
  384. if vrf is None:
  385. return queryset.none
  386. return queryset.filter(
  387. Q(vrf=vrf) |
  388. Q(vrf__export_targets__in=vrf.import_targets.all())
  389. )
  390. class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
  391. family = django_filters.NumberFilter(
  392. field_name='start_address',
  393. lookup_expr='family'
  394. )
  395. start_address = MultiValueCharFilter(
  396. method='filter_address',
  397. label=_('Address'),
  398. )
  399. end_address = MultiValueCharFilter(
  400. method='filter_address',
  401. label=_('Address'),
  402. )
  403. contains = django_filters.CharFilter(
  404. method='search_contains',
  405. label=_('Ranges which contain this prefix or IP'),
  406. )
  407. vrf_id = django_filters.ModelMultipleChoiceFilter(
  408. queryset=VRF.objects.all(),
  409. label=_('VRF'),
  410. )
  411. vrf = django_filters.ModelMultipleChoiceFilter(
  412. field_name='vrf__rd',
  413. queryset=VRF.objects.all(),
  414. to_field_name='rd',
  415. label=_('VRF (RD)'),
  416. )
  417. role_id = django_filters.ModelMultipleChoiceFilter(
  418. queryset=Role.objects.all(),
  419. label=_('Role (ID)'),
  420. )
  421. role = django_filters.ModelMultipleChoiceFilter(
  422. field_name='role__slug',
  423. queryset=Role.objects.all(),
  424. to_field_name='slug',
  425. label=_('Role (slug)'),
  426. )
  427. status = django_filters.MultipleChoiceFilter(
  428. choices=IPRangeStatusChoices,
  429. null_value=None
  430. )
  431. parent = MultiValueCharFilter(
  432. method='search_by_parent',
  433. label=_('Parent prefix'),
  434. )
  435. class Meta:
  436. model = IPRange
  437. fields = ['id', 'mark_utilized', 'description']
  438. def search(self, queryset, name, value):
  439. if not value.strip():
  440. return queryset
  441. qs_filter = Q(description__icontains=value) | Q(start_address__contains=value) | Q(end_address__contains=value)
  442. try:
  443. ipaddress = str(netaddr.IPNetwork(value.strip()))
  444. qs_filter |= Q(start_address=ipaddress)
  445. qs_filter |= Q(end_address=ipaddress)
  446. except (AddrFormatError, ValueError):
  447. pass
  448. return queryset.filter(qs_filter)
  449. def search_contains(self, queryset, name, value):
  450. value = value.strip()
  451. if not value:
  452. return queryset
  453. try:
  454. # Strip mask
  455. ipaddress = netaddr.IPNetwork(value)
  456. return queryset.filter(start_address__lte=ipaddress, end_address__gte=ipaddress)
  457. except (AddrFormatError, ValueError):
  458. return queryset.none()
  459. def filter_address(self, queryset, name, value):
  460. try:
  461. return queryset.filter(**{f'{name}__net_in': value})
  462. except ValidationError:
  463. return queryset.none()
  464. def search_by_parent(self, queryset, name, value):
  465. if not value:
  466. return queryset
  467. q = Q()
  468. for prefix in value:
  469. try:
  470. query = str(netaddr.IPNetwork(prefix.strip()).cidr)
  471. q |= Q(start_address__net_host_contained=query, end_address__net_host_contained=query)
  472. except (AddrFormatError, ValueError):
  473. return queryset.none()
  474. return queryset.filter(q)
  475. class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
  476. family = django_filters.NumberFilter(
  477. field_name='address',
  478. lookup_expr='family'
  479. )
  480. parent = MultiValueCharFilter(
  481. method='search_by_parent',
  482. label=_('Parent prefix'),
  483. )
  484. address = MultiValueCharFilter(
  485. method='filter_address',
  486. label=_('Address'),
  487. )
  488. mask_length = MultiValueNumberFilter(
  489. field_name='address',
  490. lookup_expr='net_mask_length',
  491. label=_('Mask length')
  492. )
  493. mask_length__gte = django_filters.NumberFilter(
  494. field_name='address',
  495. lookup_expr='net_mask_length__gte'
  496. )
  497. mask_length__lte = django_filters.NumberFilter(
  498. field_name='address',
  499. lookup_expr='net_mask_length__lte'
  500. )
  501. vrf_id = django_filters.ModelMultipleChoiceFilter(
  502. queryset=VRF.objects.all(),
  503. label=_('VRF'),
  504. )
  505. vrf = django_filters.ModelMultipleChoiceFilter(
  506. field_name='vrf__rd',
  507. queryset=VRF.objects.all(),
  508. to_field_name='rd',
  509. label=_('VRF (RD)'),
  510. )
  511. present_in_vrf_id = django_filters.ModelChoiceFilter(
  512. queryset=VRF.objects.all(),
  513. method='filter_present_in_vrf',
  514. label=_('VRF')
  515. )
  516. present_in_vrf = django_filters.ModelChoiceFilter(
  517. queryset=VRF.objects.all(),
  518. method='filter_present_in_vrf',
  519. to_field_name='rd',
  520. label=_('VRF (RD)'),
  521. )
  522. device = MultiValueCharFilter(
  523. method='filter_device',
  524. field_name='name',
  525. label=_('Device (name)'),
  526. )
  527. device_id = MultiValueNumberFilter(
  528. method='filter_device',
  529. field_name='pk',
  530. label=_('Device (ID)'),
  531. )
  532. virtual_machine = MultiValueCharFilter(
  533. method='filter_virtual_machine',
  534. field_name='name',
  535. label=_('Virtual machine (name)'),
  536. )
  537. virtual_machine_id = MultiValueNumberFilter(
  538. method='filter_virtual_machine',
  539. field_name='pk',
  540. label=_('Virtual machine (ID)'),
  541. )
  542. interface = django_filters.ModelMultipleChoiceFilter(
  543. field_name='interface__name',
  544. queryset=Interface.objects.all(),
  545. to_field_name='name',
  546. label=_('Interface (name)'),
  547. )
  548. interface_id = django_filters.ModelMultipleChoiceFilter(
  549. field_name='interface',
  550. queryset=Interface.objects.all(),
  551. label=_('Interface (ID)'),
  552. )
  553. vminterface = django_filters.ModelMultipleChoiceFilter(
  554. field_name='vminterface__name',
  555. queryset=VMInterface.objects.all(),
  556. to_field_name='name',
  557. label=_('VM interface (name)'),
  558. )
  559. vminterface_id = django_filters.ModelMultipleChoiceFilter(
  560. field_name='vminterface',
  561. queryset=VMInterface.objects.all(),
  562. label=_('VM interface (ID)'),
  563. )
  564. fhrpgroup_id = django_filters.ModelMultipleChoiceFilter(
  565. field_name='fhrpgroup',
  566. queryset=FHRPGroup.objects.all(),
  567. label=_('FHRP group (ID)'),
  568. )
  569. assigned_to_interface = django_filters.BooleanFilter(
  570. method='_assigned_to_interface',
  571. label=_('Is assigned to an interface'),
  572. )
  573. assigned = django_filters.BooleanFilter(
  574. method='_assigned',
  575. label=_('Is assigned'),
  576. )
  577. status = django_filters.MultipleChoiceFilter(
  578. choices=IPAddressStatusChoices,
  579. null_value=None
  580. )
  581. role = django_filters.MultipleChoiceFilter(
  582. choices=IPAddressRoleChoices
  583. )
  584. class Meta:
  585. model = IPAddress
  586. fields = ['id', 'dns_name', 'description']
  587. def search(self, queryset, name, value):
  588. if not value.strip():
  589. return queryset
  590. qs_filter = (
  591. Q(dns_name__icontains=value) |
  592. Q(description__icontains=value) |
  593. Q(address__istartswith=value)
  594. )
  595. return queryset.filter(qs_filter)
  596. def search_by_parent(self, queryset, name, value):
  597. if not value:
  598. return queryset
  599. q = Q()
  600. for prefix in value:
  601. try:
  602. query = str(netaddr.IPNetwork(prefix.strip()).cidr)
  603. q |= Q(address__net_host_contained=query)
  604. except (AddrFormatError, ValueError):
  605. return queryset.none()
  606. return queryset.filter(q)
  607. def parse_inet_addresses(self, value):
  608. '''
  609. Parse networks or IP addresses and cast to a format
  610. acceptable by the Postgres inet type.
  611. Skips invalid values.
  612. '''
  613. parsed = []
  614. for addr in value:
  615. if netaddr.valid_ipv4(addr) or netaddr.valid_ipv6(addr):
  616. parsed.append(addr)
  617. continue
  618. try:
  619. network = netaddr.IPNetwork(addr)
  620. parsed.append(str(network))
  621. except (AddrFormatError, ValueError):
  622. continue
  623. return parsed
  624. def filter_address(self, queryset, name, value):
  625. # Let's first parse the addresses passed
  626. # as argument. If they are all invalid,
  627. # we return an empty queryset
  628. value = self.parse_inet_addresses(value)
  629. if (len(value) == 0):
  630. return queryset.none()
  631. try:
  632. return queryset.filter(address__net_in=value)
  633. except ValidationError:
  634. return queryset.none()
  635. @extend_schema_field(OpenApiTypes.STR)
  636. def filter_present_in_vrf(self, queryset, name, vrf):
  637. if vrf is None:
  638. return queryset.none
  639. return queryset.filter(
  640. Q(vrf=vrf) |
  641. Q(vrf__export_targets__in=vrf.import_targets.all())
  642. )
  643. def filter_device(self, queryset, name, value):
  644. devices = Device.objects.filter(**{'{}__in'.format(name): value})
  645. if not devices.exists():
  646. return queryset.none()
  647. interface_ids = []
  648. for device in devices:
  649. interface_ids.extend(device.vc_interfaces().values_list('id', flat=True))
  650. return queryset.filter(
  651. interface__in=interface_ids
  652. )
  653. def filter_virtual_machine(self, queryset, name, value):
  654. virtual_machines = VirtualMachine.objects.filter(**{'{}__in'.format(name): value})
  655. if not virtual_machines.exists():
  656. return queryset.none()
  657. interface_ids = []
  658. for vm in virtual_machines:
  659. interface_ids.extend(vm.interfaces.values_list('id', flat=True))
  660. return queryset.filter(
  661. vminterface__in=interface_ids
  662. )
  663. def _assigned_to_interface(self, queryset, name, value):
  664. content_types = ContentType.objects.get_for_models(Interface, VMInterface).values()
  665. if value:
  666. return queryset.filter(
  667. assigned_object_type__in=content_types,
  668. assigned_object_id__isnull=False
  669. )
  670. else:
  671. return queryset.exclude(
  672. assigned_object_type__in=content_types,
  673. assigned_object_id__isnull=False
  674. )
  675. def _assigned(self, queryset, name, value):
  676. if value:
  677. return queryset.exclude(
  678. assigned_object_type__isnull=True,
  679. assigned_object_id__isnull=True
  680. )
  681. else:
  682. return queryset.filter(
  683. assigned_object_type__isnull=True,
  684. assigned_object_id__isnull=True
  685. )
  686. class FHRPGroupFilterSet(NetBoxModelFilterSet):
  687. protocol = django_filters.MultipleChoiceFilter(
  688. choices=FHRPGroupProtocolChoices
  689. )
  690. auth_type = django_filters.MultipleChoiceFilter(
  691. choices=FHRPGroupAuthTypeChoices
  692. )
  693. related_ip = django_filters.ModelMultipleChoiceFilter(
  694. queryset=IPAddress.objects.all(),
  695. method='filter_related_ip'
  696. )
  697. class Meta:
  698. model = FHRPGroup
  699. fields = ['id', 'group_id', 'name', 'auth_key']
  700. def search(self, queryset, name, value):
  701. if not value.strip():
  702. return queryset
  703. return queryset.filter(
  704. Q(description__icontains=value) |
  705. Q(name__icontains=value)
  706. )
  707. @extend_schema_field(OpenApiTypes.STR)
  708. def filter_related_ip(self, queryset, name, value):
  709. """
  710. Filter by VRF & prefix of assigned IP addresses.
  711. """
  712. ip_filter = Q()
  713. for ipaddress in value:
  714. if ipaddress.vrf:
  715. q = Q(
  716. ip_addresses__address__net_contained_or_equal=ipaddress.address,
  717. ip_addresses__vrf=ipaddress.vrf
  718. )
  719. else:
  720. q = Q(
  721. ip_addresses__address__net_contained_or_equal=ipaddress.address,
  722. ip_addresses__vrf__isnull=True
  723. )
  724. ip_filter |= q
  725. return queryset.filter(ip_filter)
  726. class FHRPGroupAssignmentFilterSet(ChangeLoggedModelFilterSet):
  727. interface_type = ContentTypeFilter()
  728. group_id = django_filters.ModelMultipleChoiceFilter(
  729. queryset=FHRPGroup.objects.all(),
  730. label=_('Group (ID)'),
  731. )
  732. device = MultiValueCharFilter(
  733. method='filter_device',
  734. field_name='name',
  735. label=_('Device (name)'),
  736. )
  737. device_id = MultiValueNumberFilter(
  738. method='filter_device',
  739. field_name='pk',
  740. label=_('Device (ID)'),
  741. )
  742. virtual_machine = MultiValueCharFilter(
  743. method='filter_virtual_machine',
  744. field_name='name',
  745. label=_('Virtual machine (name)'),
  746. )
  747. virtual_machine_id = MultiValueNumberFilter(
  748. method='filter_virtual_machine',
  749. field_name='pk',
  750. label=_('Virtual machine (ID)'),
  751. )
  752. class Meta:
  753. model = FHRPGroupAssignment
  754. fields = ['id', 'group_id', 'interface_type', 'interface_id', 'priority']
  755. def filter_device(self, queryset, name, value):
  756. devices = Device.objects.filter(**{f'{name}__in': value})
  757. if not devices.exists():
  758. return queryset.none()
  759. interface_ids = []
  760. for device in devices:
  761. interface_ids.extend(device.vc_interfaces().values_list('id', flat=True))
  762. return queryset.filter(
  763. Q(interface_type=ContentType.objects.get_for_model(Interface), interface_id__in=interface_ids)
  764. )
  765. def filter_virtual_machine(self, queryset, name, value):
  766. virtual_machines = VirtualMachine.objects.filter(**{f'{name}__in': value})
  767. if not virtual_machines.exists():
  768. return queryset.none()
  769. interface_ids = []
  770. for vm in virtual_machines:
  771. interface_ids.extend(vm.interfaces.values_list('id', flat=True))
  772. return queryset.filter(
  773. Q(interface_type=ContentType.objects.get_for_model(VMInterface), interface_id__in=interface_ids)
  774. )
  775. class VLANGroupFilterSet(OrganizationalModelFilterSet):
  776. scope_type = ContentTypeFilter()
  777. region = django_filters.NumberFilter(
  778. method='filter_scope'
  779. )
  780. sitegroup = django_filters.NumberFilter(
  781. method='filter_scope'
  782. )
  783. site = django_filters.NumberFilter(
  784. method='filter_scope'
  785. )
  786. location = django_filters.NumberFilter(
  787. method='filter_scope'
  788. )
  789. rack = django_filters.NumberFilter(
  790. method='filter_scope'
  791. )
  792. clustergroup = django_filters.NumberFilter(
  793. method='filter_scope'
  794. )
  795. cluster = django_filters.NumberFilter(
  796. method='filter_scope'
  797. )
  798. class Meta:
  799. model = VLANGroup
  800. fields = ['id', 'name', 'slug', 'min_vid', 'max_vid', 'description', 'scope_id']
  801. def search(self, queryset, name, value):
  802. if not value.strip():
  803. return queryset
  804. qs_filter = (
  805. Q(name__icontains=value) |
  806. Q(description__icontains=value)
  807. )
  808. return queryset.filter(qs_filter)
  809. def filter_scope(self, queryset, name, value):
  810. return queryset.filter(
  811. scope_type=ContentType.objects.get(model=name),
  812. scope_id=value
  813. )
  814. class VLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
  815. region_id = TreeNodeMultipleChoiceFilter(
  816. queryset=Region.objects.all(),
  817. field_name='site__region',
  818. lookup_expr='in',
  819. label=_('Region (ID)'),
  820. )
  821. region = TreeNodeMultipleChoiceFilter(
  822. queryset=Region.objects.all(),
  823. field_name='site__region',
  824. lookup_expr='in',
  825. to_field_name='slug',
  826. label=_('Region (slug)'),
  827. )
  828. site_group_id = TreeNodeMultipleChoiceFilter(
  829. queryset=SiteGroup.objects.all(),
  830. field_name='site__group',
  831. lookup_expr='in',
  832. label=_('Site group (ID)'),
  833. )
  834. site_group = TreeNodeMultipleChoiceFilter(
  835. queryset=SiteGroup.objects.all(),
  836. field_name='site__group',
  837. lookup_expr='in',
  838. to_field_name='slug',
  839. label=_('Site group (slug)'),
  840. )
  841. site_id = django_filters.ModelMultipleChoiceFilter(
  842. queryset=Site.objects.all(),
  843. label=_('Site (ID)'),
  844. )
  845. site = django_filters.ModelMultipleChoiceFilter(
  846. field_name='site__slug',
  847. queryset=Site.objects.all(),
  848. to_field_name='slug',
  849. label=_('Site (slug)'),
  850. )
  851. group_id = django_filters.ModelMultipleChoiceFilter(
  852. queryset=VLANGroup.objects.all(),
  853. label=_('Group (ID)'),
  854. )
  855. group = django_filters.ModelMultipleChoiceFilter(
  856. field_name='group__slug',
  857. queryset=VLANGroup.objects.all(),
  858. to_field_name='slug',
  859. label=_('Group'),
  860. )
  861. role_id = django_filters.ModelMultipleChoiceFilter(
  862. queryset=Role.objects.all(),
  863. label=_('Role (ID)'),
  864. )
  865. role = django_filters.ModelMultipleChoiceFilter(
  866. field_name='role__slug',
  867. queryset=Role.objects.all(),
  868. to_field_name='slug',
  869. label=_('Role (slug)'),
  870. )
  871. status = django_filters.MultipleChoiceFilter(
  872. choices=VLANStatusChoices,
  873. null_value=None
  874. )
  875. available_at_site = django_filters.ModelChoiceFilter(
  876. queryset=Site.objects.all(),
  877. method='get_for_site'
  878. )
  879. available_on_device = django_filters.ModelChoiceFilter(
  880. queryset=Device.objects.all(),
  881. method='get_for_device'
  882. )
  883. available_on_virtualmachine = django_filters.ModelChoiceFilter(
  884. queryset=VirtualMachine.objects.all(),
  885. method='get_for_virtualmachine'
  886. )
  887. l2vpn_id = django_filters.ModelMultipleChoiceFilter(
  888. field_name='l2vpn_terminations__l2vpn',
  889. queryset=L2VPN.objects.all(),
  890. label=_('L2VPN (ID)'),
  891. )
  892. l2vpn = django_filters.ModelMultipleChoiceFilter(
  893. field_name='l2vpn_terminations__l2vpn__identifier',
  894. queryset=L2VPN.objects.all(),
  895. to_field_name='identifier',
  896. label=_('L2VPN'),
  897. )
  898. class Meta:
  899. model = VLAN
  900. fields = ['id', 'vid', 'name', 'description']
  901. def search(self, queryset, name, value):
  902. if not value.strip():
  903. return queryset
  904. qs_filter = Q(name__icontains=value) | Q(description__icontains=value)
  905. try:
  906. qs_filter |= Q(vid=int(value.strip()))
  907. except ValueError:
  908. pass
  909. return queryset.filter(qs_filter)
  910. @extend_schema_field(OpenApiTypes.STR)
  911. def get_for_site(self, queryset, name, value):
  912. return queryset.get_for_site(value)
  913. @extend_schema_field(OpenApiTypes.STR)
  914. def get_for_device(self, queryset, name, value):
  915. return queryset.get_for_device(value)
  916. @extend_schema_field(OpenApiTypes.STR)
  917. def get_for_virtualmachine(self, queryset, name, value):
  918. return queryset.get_for_virtualmachine(value)
  919. class ServiceTemplateFilterSet(NetBoxModelFilterSet):
  920. port = NumericArrayFilter(
  921. field_name='ports',
  922. lookup_expr='contains'
  923. )
  924. class Meta:
  925. model = ServiceTemplate
  926. fields = ['id', 'name', 'protocol']
  927. def search(self, queryset, name, value):
  928. if not value.strip():
  929. return queryset
  930. qs_filter = Q(name__icontains=value) | Q(description__icontains=value)
  931. return queryset.filter(qs_filter)
  932. class ServiceFilterSet(NetBoxModelFilterSet):
  933. device_id = django_filters.ModelMultipleChoiceFilter(
  934. queryset=Device.objects.all(),
  935. label=_('Device (ID)'),
  936. )
  937. device = django_filters.ModelMultipleChoiceFilter(
  938. field_name='device__name',
  939. queryset=Device.objects.all(),
  940. to_field_name='name',
  941. label=_('Device (name)'),
  942. )
  943. virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
  944. queryset=VirtualMachine.objects.all(),
  945. label=_('Virtual machine (ID)'),
  946. )
  947. virtual_machine = django_filters.ModelMultipleChoiceFilter(
  948. field_name='virtual_machine__name',
  949. queryset=VirtualMachine.objects.all(),
  950. to_field_name='name',
  951. label=_('Virtual machine (name)'),
  952. )
  953. ipaddress_id = django_filters.ModelMultipleChoiceFilter(
  954. field_name='ipaddresses',
  955. queryset=IPAddress.objects.all(),
  956. label=_('IP address (ID)'),
  957. )
  958. ipaddress = django_filters.ModelMultipleChoiceFilter(
  959. field_name='ipaddresses__address',
  960. queryset=IPAddress.objects.all(),
  961. to_field_name='address',
  962. label=_('IP address'),
  963. )
  964. port = NumericArrayFilter(
  965. field_name='ports',
  966. lookup_expr='contains'
  967. )
  968. class Meta:
  969. model = Service
  970. fields = ['id', 'name', 'protocol', 'description']
  971. def search(self, queryset, name, value):
  972. if not value.strip():
  973. return queryset
  974. qs_filter = Q(name__icontains=value) | Q(description__icontains=value)
  975. return queryset.filter(qs_filter)
  976. class PrimaryIPFilterSet(django_filters.FilterSet):
  977. """
  978. An inheritable FilterSet for models which support primary IP assignment.
  979. """
  980. primary_ip4_id = django_filters.ModelMultipleChoiceFilter(
  981. field_name='primary_ip4',
  982. queryset=IPAddress.objects.all(),
  983. label=_('Primary IPv4 (ID)'),
  984. )
  985. primary_ip6_id = django_filters.ModelMultipleChoiceFilter(
  986. field_name='primary_ip6',
  987. queryset=IPAddress.objects.all(),
  988. label=_('Primary IPv6 (ID)'),
  989. )