filtersets.py 41 KB

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