filters.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. import django_filters
  2. import netaddr
  3. from django.core.exceptions import ValidationError
  4. from django.db.models import Q
  5. from netaddr.core import AddrFormatError
  6. from dcim.models import Device, Interface, Region, Site
  7. from extras.filters import CustomFieldFilterSet, CreatedUpdatedFilterSet
  8. from tenancy.filtersets import TenancyFilterSet
  9. from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter
  10. from virtualization.models import VirtualMachine
  11. from .choices import *
  12. from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
  13. __all__ = (
  14. 'AggregateFilterSet',
  15. 'IPAddressFilterSet',
  16. 'PrefixFilterSet',
  17. 'RIRFilterSet',
  18. 'RoleFilterSet',
  19. 'ServiceFilterSet',
  20. 'VLANFilterSet',
  21. 'VLANGroupFilterSet',
  22. 'VRFFilterSet',
  23. )
  24. class VRFFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
  25. id__in = NumericInFilter(
  26. field_name='id',
  27. lookup_expr='in'
  28. )
  29. q = django_filters.CharFilter(
  30. method='search',
  31. label='Search',
  32. )
  33. tag = TagFilter()
  34. def search(self, queryset, name, value):
  35. if not value.strip():
  36. return queryset
  37. return queryset.filter(
  38. Q(name__icontains=value) |
  39. Q(rd__icontains=value) |
  40. Q(description__icontains=value)
  41. )
  42. class Meta:
  43. model = VRF
  44. fields = ['name', 'rd', 'enforce_unique']
  45. class RIRFilterSet(NameSlugSearchFilterSet):
  46. id__in = NumericInFilter(
  47. field_name='id',
  48. lookup_expr='in'
  49. )
  50. class Meta:
  51. model = RIR
  52. fields = ['name', 'slug', 'is_private']
  53. class AggregateFilterSet(CustomFieldFilterSet, CreatedUpdatedFilterSet):
  54. id__in = NumericInFilter(
  55. field_name='id',
  56. lookup_expr='in'
  57. )
  58. q = django_filters.CharFilter(
  59. method='search',
  60. label='Search',
  61. )
  62. prefix = django_filters.CharFilter(
  63. method='filter_prefix',
  64. label='Prefix',
  65. )
  66. rir_id = django_filters.ModelMultipleChoiceFilter(
  67. queryset=RIR.objects.all(),
  68. label='RIR (ID)',
  69. )
  70. rir = django_filters.ModelMultipleChoiceFilter(
  71. field_name='rir__slug',
  72. queryset=RIR.objects.all(),
  73. to_field_name='slug',
  74. label='RIR (slug)',
  75. )
  76. tag = TagFilter()
  77. class Meta:
  78. model = Aggregate
  79. fields = ['family', 'date_added']
  80. def search(self, queryset, name, value):
  81. if not value.strip():
  82. return queryset
  83. qs_filter = Q(description__icontains=value)
  84. try:
  85. prefix = str(netaddr.IPNetwork(value.strip()).cidr)
  86. qs_filter |= Q(prefix__net_contains_or_equals=prefix)
  87. except (AddrFormatError, ValueError):
  88. pass
  89. return queryset.filter(qs_filter)
  90. def filter_prefix(self, queryset, name, value):
  91. if not value.strip():
  92. return queryset
  93. try:
  94. query = str(netaddr.IPNetwork(value).cidr)
  95. return queryset.filter(prefix=query)
  96. except ValidationError:
  97. return queryset.none()
  98. class RoleFilterSet(NameSlugSearchFilterSet):
  99. q = django_filters.CharFilter(
  100. method='search',
  101. label='Search',
  102. )
  103. class Meta:
  104. model = Role
  105. fields = ['id', 'name', 'slug']
  106. class PrefixFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
  107. id__in = NumericInFilter(
  108. field_name='id',
  109. lookup_expr='in'
  110. )
  111. q = django_filters.CharFilter(
  112. method='search',
  113. label='Search',
  114. )
  115. prefix = django_filters.CharFilter(
  116. method='filter_prefix',
  117. label='Prefix',
  118. )
  119. within = django_filters.CharFilter(
  120. method='search_within',
  121. label='Within prefix',
  122. )
  123. within_include = django_filters.CharFilter(
  124. method='search_within_include',
  125. label='Within and including prefix',
  126. )
  127. contains = django_filters.CharFilter(
  128. method='search_contains',
  129. label='Prefixes which contain this prefix or IP',
  130. )
  131. mask_length = django_filters.NumberFilter(
  132. method='filter_mask_length',
  133. label='Mask length',
  134. )
  135. vrf_id = django_filters.ModelMultipleChoiceFilter(
  136. queryset=VRF.objects.all(),
  137. label='VRF',
  138. )
  139. vrf = django_filters.ModelMultipleChoiceFilter(
  140. field_name='vrf__rd',
  141. queryset=VRF.objects.all(),
  142. to_field_name='rd',
  143. label='VRF (RD)',
  144. )
  145. region_id = TreeNodeMultipleChoiceFilter(
  146. queryset=Region.objects.all(),
  147. field_name='site__region__in',
  148. label='Region (ID)',
  149. )
  150. region = TreeNodeMultipleChoiceFilter(
  151. queryset=Region.objects.all(),
  152. field_name='site__region__in',
  153. to_field_name='slug',
  154. label='Region (slug)',
  155. )
  156. site_id = django_filters.ModelMultipleChoiceFilter(
  157. queryset=Site.objects.all(),
  158. label='Site (ID)',
  159. )
  160. site = django_filters.ModelMultipleChoiceFilter(
  161. field_name='site__slug',
  162. queryset=Site.objects.all(),
  163. to_field_name='slug',
  164. label='Site (slug)',
  165. )
  166. vlan_id = django_filters.ModelMultipleChoiceFilter(
  167. queryset=VLAN.objects.all(),
  168. label='VLAN (ID)',
  169. )
  170. vlan_vid = django_filters.NumberFilter(
  171. field_name='vlan__vid',
  172. label='VLAN number (1-4095)',
  173. )
  174. role_id = django_filters.ModelMultipleChoiceFilter(
  175. queryset=Role.objects.all(),
  176. label='Role (ID)',
  177. )
  178. role = django_filters.ModelMultipleChoiceFilter(
  179. field_name='role__slug',
  180. queryset=Role.objects.all(),
  181. to_field_name='slug',
  182. label='Role (slug)',
  183. )
  184. status = django_filters.MultipleChoiceFilter(
  185. choices=PrefixStatusChoices,
  186. null_value=None
  187. )
  188. tag = TagFilter()
  189. class Meta:
  190. model = Prefix
  191. fields = ['family', 'is_pool']
  192. def search(self, queryset, name, value):
  193. if not value.strip():
  194. return queryset
  195. qs_filter = Q(description__icontains=value)
  196. try:
  197. prefix = str(netaddr.IPNetwork(value.strip()).cidr)
  198. qs_filter |= Q(prefix__net_contains_or_equals=prefix)
  199. except (AddrFormatError, ValueError):
  200. pass
  201. return queryset.filter(qs_filter)
  202. def filter_prefix(self, queryset, name, value):
  203. if not value.strip():
  204. return queryset
  205. try:
  206. query = str(netaddr.IPNetwork(value).cidr)
  207. return queryset.filter(prefix=query)
  208. except ValidationError:
  209. return queryset.none()
  210. def search_within(self, queryset, name, value):
  211. value = value.strip()
  212. if not value:
  213. return queryset
  214. try:
  215. query = str(netaddr.IPNetwork(value).cidr)
  216. return queryset.filter(prefix__net_contained=query)
  217. except (AddrFormatError, ValueError):
  218. return queryset.none()
  219. def search_within_include(self, queryset, name, value):
  220. value = value.strip()
  221. if not value:
  222. return queryset
  223. try:
  224. query = str(netaddr.IPNetwork(value).cidr)
  225. return queryset.filter(prefix__net_contained_or_equal=query)
  226. except (AddrFormatError, ValueError):
  227. return queryset.none()
  228. def search_contains(self, queryset, name, value):
  229. value = value.strip()
  230. if not value:
  231. return queryset
  232. try:
  233. # Searching by prefix
  234. if '/' in value:
  235. return queryset.filter(prefix__net_contains_or_equals=str(netaddr.IPNetwork(value).cidr))
  236. # Searching by IP address
  237. else:
  238. return queryset.filter(prefix__net_contains=str(netaddr.IPAddress(value)))
  239. except (AddrFormatError, ValueError):
  240. return queryset.none()
  241. def filter_mask_length(self, queryset, name, value):
  242. if not value:
  243. return queryset
  244. return queryset.filter(prefix__net_mask_length=value)
  245. class IPAddressFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
  246. id__in = NumericInFilter(
  247. field_name='id',
  248. lookup_expr='in'
  249. )
  250. q = django_filters.CharFilter(
  251. method='search',
  252. label='Search',
  253. )
  254. parent = django_filters.CharFilter(
  255. method='search_by_parent',
  256. label='Parent prefix',
  257. )
  258. address = django_filters.CharFilter(
  259. method='filter_address',
  260. label='Address',
  261. )
  262. mask_length = django_filters.NumberFilter(
  263. method='filter_mask_length',
  264. label='Mask length',
  265. )
  266. vrf_id = django_filters.ModelMultipleChoiceFilter(
  267. queryset=VRF.objects.all(),
  268. label='VRF',
  269. )
  270. vrf = django_filters.ModelMultipleChoiceFilter(
  271. field_name='vrf__rd',
  272. queryset=VRF.objects.all(),
  273. to_field_name='rd',
  274. label='VRF (RD)',
  275. )
  276. device = django_filters.CharFilter(
  277. method='filter_device',
  278. field_name='name',
  279. label='Device',
  280. )
  281. device_id = django_filters.NumberFilter(
  282. method='filter_device',
  283. field_name='pk',
  284. label='Device (ID)',
  285. )
  286. virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
  287. field_name='interface__virtual_machine',
  288. queryset=VirtualMachine.objects.all(),
  289. label='Virtual machine (ID)',
  290. )
  291. virtual_machine = django_filters.ModelMultipleChoiceFilter(
  292. field_name='interface__virtual_machine__name',
  293. queryset=VirtualMachine.objects.all(),
  294. to_field_name='name',
  295. label='Virtual machine (name)',
  296. )
  297. interface = django_filters.ModelMultipleChoiceFilter(
  298. field_name='interface__name',
  299. queryset=Interface.objects.all(),
  300. to_field_name='name',
  301. label='Interface (ID)',
  302. )
  303. interface_id = django_filters.ModelMultipleChoiceFilter(
  304. queryset=Interface.objects.all(),
  305. label='Interface (ID)',
  306. )
  307. assigned_to_interface = django_filters.BooleanFilter(
  308. method='_assigned_to_interface',
  309. label='Is assigned to an interface',
  310. )
  311. status = django_filters.MultipleChoiceFilter(
  312. choices=IPAddressStatusChoices,
  313. null_value=None
  314. )
  315. role = django_filters.MultipleChoiceFilter(
  316. choices=IPAddressRoleChoices
  317. )
  318. tag = TagFilter()
  319. class Meta:
  320. model = IPAddress
  321. fields = ['family', 'dns_name']
  322. def search(self, queryset, name, value):
  323. if not value.strip():
  324. return queryset
  325. qs_filter = (
  326. Q(dns_name__icontains=value) |
  327. Q(description__icontains=value) |
  328. Q(address__istartswith=value)
  329. )
  330. return queryset.filter(qs_filter)
  331. def search_by_parent(self, queryset, name, value):
  332. value = value.strip()
  333. if not value:
  334. return queryset
  335. try:
  336. query = str(netaddr.IPNetwork(value.strip()).cidr)
  337. return queryset.filter(address__net_host_contained=query)
  338. except (AddrFormatError, ValueError):
  339. return queryset.none()
  340. def filter_address(self, queryset, name, value):
  341. if not value.strip():
  342. return queryset
  343. try:
  344. # Match address and subnet mask
  345. if '/' in value:
  346. return queryset.filter(address=value)
  347. return queryset.filter(address__net_host=value)
  348. except ValidationError:
  349. return queryset.none()
  350. def filter_mask_length(self, queryset, name, value):
  351. if not value:
  352. return queryset
  353. return queryset.filter(address__net_mask_length=value)
  354. def filter_device(self, queryset, name, value):
  355. try:
  356. device = Device.objects.prefetch_related('device_type').get(**{name: value})
  357. vc_interface_ids = [i['id'] for i in device.vc_interfaces.values('id')]
  358. return queryset.filter(interface_id__in=vc_interface_ids)
  359. except Device.DoesNotExist:
  360. return queryset.none()
  361. def _assigned_to_interface(self, queryset, name, value):
  362. return queryset.exclude(interface__isnull=value)
  363. class VLANGroupFilterSet(NameSlugSearchFilterSet):
  364. region_id = TreeNodeMultipleChoiceFilter(
  365. queryset=Region.objects.all(),
  366. field_name='site__region__in',
  367. label='Region (ID)',
  368. )
  369. region = TreeNodeMultipleChoiceFilter(
  370. queryset=Region.objects.all(),
  371. field_name='site__region__in',
  372. to_field_name='slug',
  373. label='Region (slug)',
  374. )
  375. site_id = django_filters.ModelMultipleChoiceFilter(
  376. queryset=Site.objects.all(),
  377. label='Site (ID)',
  378. )
  379. site = django_filters.ModelMultipleChoiceFilter(
  380. field_name='site__slug',
  381. queryset=Site.objects.all(),
  382. to_field_name='slug',
  383. label='Site (slug)',
  384. )
  385. class Meta:
  386. model = VLANGroup
  387. fields = ['id', 'name', 'slug']
  388. class VLANFilterSet(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilterSet):
  389. id__in = NumericInFilter(
  390. field_name='id',
  391. lookup_expr='in'
  392. )
  393. q = django_filters.CharFilter(
  394. method='search',
  395. label='Search',
  396. )
  397. region_id = TreeNodeMultipleChoiceFilter(
  398. queryset=Region.objects.all(),
  399. field_name='site__region__in',
  400. label='Region (ID)',
  401. )
  402. region = TreeNodeMultipleChoiceFilter(
  403. queryset=Region.objects.all(),
  404. field_name='site__region__in',
  405. to_field_name='slug',
  406. label='Region (slug)',
  407. )
  408. site_id = django_filters.ModelMultipleChoiceFilter(
  409. queryset=Site.objects.all(),
  410. label='Site (ID)',
  411. )
  412. site = django_filters.ModelMultipleChoiceFilter(
  413. field_name='site__slug',
  414. queryset=Site.objects.all(),
  415. to_field_name='slug',
  416. label='Site (slug)',
  417. )
  418. group_id = django_filters.ModelMultipleChoiceFilter(
  419. queryset=VLANGroup.objects.all(),
  420. label='Group (ID)',
  421. )
  422. group = django_filters.ModelMultipleChoiceFilter(
  423. field_name='group__slug',
  424. queryset=VLANGroup.objects.all(),
  425. to_field_name='slug',
  426. label='Group',
  427. )
  428. role_id = django_filters.ModelMultipleChoiceFilter(
  429. queryset=Role.objects.all(),
  430. label='Role (ID)',
  431. )
  432. role = django_filters.ModelMultipleChoiceFilter(
  433. field_name='role__slug',
  434. queryset=Role.objects.all(),
  435. to_field_name='slug',
  436. label='Role (slug)',
  437. )
  438. status = django_filters.MultipleChoiceFilter(
  439. choices=VLANStatusChoices,
  440. null_value=None
  441. )
  442. tag = TagFilter()
  443. class Meta:
  444. model = VLAN
  445. fields = ['vid', 'name']
  446. def search(self, queryset, name, value):
  447. if not value.strip():
  448. return queryset
  449. qs_filter = Q(name__icontains=value) | Q(description__icontains=value)
  450. try:
  451. qs_filter |= Q(vid=int(value.strip()))
  452. except ValueError:
  453. pass
  454. return queryset.filter(qs_filter)
  455. class ServiceFilterSet(CreatedUpdatedFilterSet):
  456. q = django_filters.CharFilter(
  457. method='search',
  458. label='Search',
  459. )
  460. device_id = django_filters.ModelMultipleChoiceFilter(
  461. queryset=Device.objects.all(),
  462. label='Device (ID)',
  463. )
  464. device = django_filters.ModelMultipleChoiceFilter(
  465. field_name='device__name',
  466. queryset=Device.objects.all(),
  467. to_field_name='name',
  468. label='Device (name)',
  469. )
  470. virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
  471. queryset=VirtualMachine.objects.all(),
  472. label='Virtual machine (ID)',
  473. )
  474. virtual_machine = django_filters.ModelMultipleChoiceFilter(
  475. field_name='virtual_machine__name',
  476. queryset=VirtualMachine.objects.all(),
  477. to_field_name='name',
  478. label='Virtual machine (name)',
  479. )
  480. tag = TagFilter()
  481. class Meta:
  482. model = Service
  483. fields = ['id', 'name', 'protocol', 'port']
  484. def search(self, queryset, name, value):
  485. if not value.strip():
  486. return queryset
  487. qs_filter = Q(name__icontains=value) | Q(description__icontains=value)
  488. return queryset.filter(qs_filter)