Coverage for virtualization/filtersets.py: 70%

132 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-10 18:35 +0000

1import django_filters 

2import netaddr 

3from django.db.models import Q 

4from django.utils.translation import gettext as _ 

5from netaddr.core import AddrFormatError 

6 

7from dcim.base_filtersets import ScopedFilterSet 

8from dcim.filtersets import CommonInterfaceFilterSet 

9from dcim.models import Device, DeviceRole, MACAddress, Platform, Region, Site, SiteGroup 

10from extras.filtersets import LocalConfigContextFilterSet 

11from extras.models import ConfigTemplate 

12from ipam.filtersets import PrimaryIPFilterSet 

13from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet 

14from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet 

15from users.filterset_mixins import OwnerFilterMixin 

16from utilities.filters import MultiValueCharFilter, MultiValueMACAddressFilter, TreeNodeMultipleChoiceFilter 

17from utilities.filtersets import register_filterset 

18 

19from .choices import * 

20from .models import * 

21 

22__all__ = ( 

23 'ClusterFilterSet', 

24 'ClusterGroupFilterSet', 

25 'ClusterTypeFilterSet', 

26 'VMInterfaceFilterSet', 

27 'VirtualDiskFilterSet', 

28 'VirtualMachineFilterSet', 

29 'VirtualMachineTypeFilterSet', 

30) 

31 

32 

33@register_filterset 

34class ClusterTypeFilterSet(OrganizationalModelFilterSet): 

35 

36 class Meta: 

37 model = ClusterType 

38 fields = ('id', 'name', 'slug', 'description') 

39 

40 

41@register_filterset 

42class ClusterGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet): 

43 

44 class Meta: 

45 model = ClusterGroup 

46 fields = ('id', 'name', 'slug', 'description') 

47 

48 

49@register_filterset 

50class ClusterFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ScopedFilterSet, ContactModelFilterSet): 

51 group_id = django_filters.ModelMultipleChoiceFilter( 

52 queryset=ClusterGroup.objects.all(), 

53 distinct=False, 

54 label=_('Parent group (ID)'), 

55 ) 

56 group = django_filters.ModelMultipleChoiceFilter( 

57 field_name='group__slug', 

58 queryset=ClusterGroup.objects.all(), 

59 distinct=False, 

60 to_field_name='slug', 

61 label=_('Parent group (slug)'), 

62 ) 

63 type_id = django_filters.ModelMultipleChoiceFilter( 

64 queryset=ClusterType.objects.all(), 

65 distinct=False, 

66 label=_('Cluster type (ID)'), 

67 ) 

68 type = django_filters.ModelMultipleChoiceFilter( 

69 field_name='type__slug', 

70 queryset=ClusterType.objects.all(), 

71 distinct=False, 

72 to_field_name='slug', 

73 label=_('Cluster type (slug)'), 

74 ) 

75 status = django_filters.MultipleChoiceFilter( 

76 choices=ClusterStatusChoices, 

77 distinct=False, 

78 null_value=None 

79 ) 

80 

81 class Meta: 

82 model = Cluster 

83 fields = ('id', 'name', 'description', 'scope_id') 

84 

85 def search(self, queryset, name, value): 

86 if not value.strip(): 

87 return queryset 

88 return queryset.filter( 

89 Q(name__icontains=value) | 

90 Q(description__icontains=value) | 

91 Q(comments__icontains=value) 

92 ) 

93 

94 

95@register_filterset 

96class VirtualMachineTypeFilterSet(PrimaryModelFilterSet): 

97 default_platform_id = TreeNodeMultipleChoiceFilter( 

98 queryset=Platform.objects.all(), 

99 field_name='default_platform', 

100 lookup_expr='in', 

101 label=_('Default platform (ID)'), 

102 ) 

103 default_platform = TreeNodeMultipleChoiceFilter( 

104 queryset=Platform.objects.all(), 

105 field_name='default_platform', 

106 to_field_name='slug', 

107 lookup_expr='in', 

108 label=_('Default platform (slug)'), 

109 ) 

110 

111 class Meta: 

112 model = VirtualMachineType 

113 fields = ( 

114 'id', 

115 'name', 

116 'slug', 

117 'default_vcpus', 

118 'default_memory', 

119 'description', 

120 'virtual_machine_count', 

121 ) 

122 

123 def search(self, queryset, name, value): 

124 if not value.strip(): 

125 return queryset 

126 

127 return queryset.filter( 

128 Q(name__icontains=value) | 

129 Q(description__icontains=value) | 

130 Q(comments__icontains=value) 

131 ) 

132 

133 

134@register_filterset 

135class VirtualMachineFilterSet( 

136 PrimaryModelFilterSet, 

137 TenancyFilterSet, 

138 ContactModelFilterSet, 

139 LocalConfigContextFilterSet, 

140 PrimaryIPFilterSet, 

141): 

142 virtual_machine_type_id = django_filters.ModelMultipleChoiceFilter( 

143 queryset=VirtualMachineType.objects.all(), 

144 distinct=False, 

145 label=_('Virtual machine type (ID)'), 

146 ) 

147 virtual_machine_type = django_filters.ModelMultipleChoiceFilter( 

148 field_name='virtual_machine_type__slug', 

149 queryset=VirtualMachineType.objects.all(), 

150 distinct=False, 

151 to_field_name='slug', 

152 label=_('Virtual machine type (slug)'), 

153 ) 

154 status = django_filters.MultipleChoiceFilter( 

155 choices=VirtualMachineStatusChoices, 

156 distinct=False, 

157 null_value=None 

158 ) 

159 start_on_boot = django_filters.MultipleChoiceFilter( 

160 choices=VirtualMachineStartOnBootChoices, 

161 distinct=False, 

162 null_value=None 

163 ) 

164 cluster_group_id = django_filters.ModelMultipleChoiceFilter( 

165 field_name='cluster__group', 

166 queryset=ClusterGroup.objects.all(), 

167 distinct=False, 

168 label=_('Cluster group (ID)'), 

169 ) 

170 cluster_group = django_filters.ModelMultipleChoiceFilter( 

171 field_name='cluster__group__slug', 

172 queryset=ClusterGroup.objects.all(), 

173 distinct=False, 

174 to_field_name='slug', 

175 label=_('Cluster group (slug)'), 

176 ) 

177 cluster_type_id = django_filters.ModelMultipleChoiceFilter( 

178 field_name='cluster__type', 

179 queryset=ClusterType.objects.all(), 

180 distinct=False, 

181 label=_('Cluster type (ID)'), 

182 ) 

183 cluster_type = django_filters.ModelMultipleChoiceFilter( 

184 field_name='cluster__type__slug', 

185 queryset=ClusterType.objects.all(), 

186 distinct=False, 

187 to_field_name='slug', 

188 label=_('Cluster type (slug)'), 

189 ) 

190 cluster_id = django_filters.ModelMultipleChoiceFilter( 

191 queryset=Cluster.objects.all(), 

192 distinct=False, 

193 label=_('Cluster (ID)'), 

194 ) 

195 cluster = django_filters.ModelMultipleChoiceFilter( 

196 field_name='cluster__name', 

197 queryset=Cluster.objects.all(), 

198 distinct=False, 

199 to_field_name='name', 

200 label=_('Cluster'), 

201 ) 

202 device_id = django_filters.ModelMultipleChoiceFilter( 

203 queryset=Device.objects.all(), 

204 distinct=False, 

205 label=_('Device (ID)'), 

206 ) 

207 device = django_filters.ModelMultipleChoiceFilter( 

208 field_name='device__name', 

209 queryset=Device.objects.all(), 

210 distinct=False, 

211 to_field_name='name', 

212 label=_('Device'), 

213 ) 

214 region_id = TreeNodeMultipleChoiceFilter( 

215 queryset=Region.objects.all(), 

216 field_name='site__region', 

217 lookup_expr='in', 

218 label=_('Region (ID)'), 

219 ) 

220 region = TreeNodeMultipleChoiceFilter( 

221 queryset=Region.objects.all(), 

222 field_name='site__region', 

223 lookup_expr='in', 

224 to_field_name='slug', 

225 label=_('Region (slug)'), 

226 ) 

227 site_group_id = TreeNodeMultipleChoiceFilter( 

228 queryset=SiteGroup.objects.all(), 

229 field_name='site__group', 

230 lookup_expr='in', 

231 label=_('Site group (ID)'), 

232 ) 

233 site_group = TreeNodeMultipleChoiceFilter( 

234 queryset=SiteGroup.objects.all(), 

235 field_name='site__group', 

236 lookup_expr='in', 

237 to_field_name='slug', 

238 label=_('Site group (slug)'), 

239 ) 

240 site_id = django_filters.ModelMultipleChoiceFilter( 

241 queryset=Site.objects.all(), 

242 distinct=False, 

243 label=_('Site (ID)'), 

244 ) 

245 site = django_filters.ModelMultipleChoiceFilter( 

246 field_name='site__slug', 

247 queryset=Site.objects.all(), 

248 distinct=False, 

249 to_field_name='slug', 

250 label=_('Site (slug)'), 

251 ) 

252 name = MultiValueCharFilter( 

253 lookup_expr='iexact' 

254 ) 

255 role_id = TreeNodeMultipleChoiceFilter( 

256 queryset=DeviceRole.objects.all(), 

257 lookup_expr='in', 

258 label=_('Role (ID)'), 

259 ) 

260 role = TreeNodeMultipleChoiceFilter( 

261 field_name='role', 

262 queryset=DeviceRole.objects.all(), 

263 lookup_expr='in', 

264 to_field_name='slug', 

265 label=_('Role (slug)'), 

266 ) 

267 platform_id = TreeNodeMultipleChoiceFilter( 

268 queryset=Platform.objects.all(), 

269 field_name='platform', 

270 lookup_expr='in', 

271 label=_('Platform (ID)'), 

272 ) 

273 platform = TreeNodeMultipleChoiceFilter( 

274 queryset=Platform.objects.all(), 

275 field_name='platform', 

276 lookup_expr='in', 

277 to_field_name='slug', 

278 label=_('Platform (slug)'), 

279 ) 

280 mac_address = MultiValueMACAddressFilter( 

281 field_name='interfaces__mac_addresses__mac_address', 

282 label=_('MAC address'), 

283 ) 

284 has_primary_ip = django_filters.BooleanFilter( 

285 method='_has_primary_ip', 

286 label=_('Has a primary IP'), 

287 ) 

288 config_template_id = django_filters.ModelMultipleChoiceFilter( 

289 queryset=ConfigTemplate.objects.all(), 

290 distinct=False, 

291 label=_('Config template (ID)'), 

292 ) 

293 

294 class Meta: 

295 model = VirtualMachine 

296 fields = ( 

297 'id', 'cluster', 'vcpus', 'memory', 'disk', 'description', 'interface_count', 'virtual_disk_count', 

298 'serial' 

299 ) 

300 

301 def search(self, queryset, name, value): 

302 if not value.strip(): 

303 return queryset 

304 qs_filter = Q( 

305 Q(name__icontains=value) | 

306 Q(description__icontains=value) | 

307 Q(comments__icontains=value) | 

308 Q(serial__icontains=value) 

309 ) 

310 # If the given value looks like an IP address, look for primary IPv4/IPv6 assignments 

311 try: 

312 ipaddress = netaddr.IPNetwork(value) 

313 if ipaddress.version == 4: 

314 qs_filter |= Q(primary_ip4__address__host__inet=ipaddress.ip) 

315 elif ipaddress.version == 6: 

316 qs_filter |= Q(primary_ip6__address__host__inet=ipaddress.ip) 

317 except (AddrFormatError, ValueError): 

318 pass 

319 return queryset.filter(qs_filter) 

320 

321 def _has_primary_ip(self, queryset, name, value): 

322 params = Q(primary_ip4__isnull=False) | Q(primary_ip6__isnull=False) 

323 if value: 

324 return queryset.filter(params) 

325 return queryset.exclude(params) 

326 

327 

328@register_filterset 

329class VMInterfaceFilterSet(CommonInterfaceFilterSet, OwnerFilterMixin, NetBoxModelFilterSet): 

330 cluster_id = django_filters.ModelMultipleChoiceFilter( 

331 field_name='virtual_machine__cluster', 

332 queryset=Cluster.objects.all(), 

333 distinct=False, 

334 label=_('Cluster (ID)'), 

335 ) 

336 cluster = django_filters.ModelMultipleChoiceFilter( 

337 field_name='virtual_machine__cluster__name', 

338 queryset=Cluster.objects.all(), 

339 distinct=False, 

340 to_field_name='name', 

341 label=_('Cluster'), 

342 ) 

343 virtual_machine_id = django_filters.ModelMultipleChoiceFilter( 

344 field_name='virtual_machine', 

345 queryset=VirtualMachine.objects.all(), 

346 distinct=False, 

347 label=_('Virtual machine (ID)'), 

348 ) 

349 virtual_machine = django_filters.ModelMultipleChoiceFilter( 

350 field_name='virtual_machine__name', 

351 queryset=VirtualMachine.objects.all(), 

352 distinct=False, 

353 to_field_name='name', 

354 label=_('Virtual machine'), 

355 ) 

356 parent_id = django_filters.ModelMultipleChoiceFilter( 

357 field_name='parent', 

358 queryset=VMInterface.objects.all(), 

359 distinct=False, 

360 label=_('Parent interface (ID)'), 

361 ) 

362 bridge_id = django_filters.ModelMultipleChoiceFilter( 

363 field_name='bridge', 

364 queryset=VMInterface.objects.all(), 

365 distinct=False, 

366 label=_('Bridged interface (ID)'), 

367 ) 

368 mac_address = MultiValueMACAddressFilter( 

369 field_name='mac_addresses__mac_address', 

370 label=_('MAC address'), 

371 ) 

372 primary_mac_address_id = django_filters.ModelMultipleChoiceFilter( 

373 field_name='primary_mac_address', 

374 queryset=MACAddress.objects.all(), 

375 distinct=False, 

376 label=_('Primary MAC address (ID)'), 

377 ) 

378 primary_mac_address = django_filters.ModelMultipleChoiceFilter( 

379 field_name='primary_mac_address__mac_address', 

380 queryset=MACAddress.objects.all(), 

381 distinct=False, 

382 to_field_name='mac_address', 

383 label=_('Primary MAC address'), 

384 ) 

385 

386 class Meta: 

387 model = VMInterface 

388 fields = ('id', 'name', 'enabled', 'mtu', 'mode', 'description') 

389 

390 def search(self, queryset, name, value): 

391 if not value.strip(): 

392 return queryset 

393 return queryset.filter( 

394 Q(name__icontains=value) | 

395 Q(description__icontains=value) 

396 ) 

397 

398 

399@register_filterset 

400class VirtualDiskFilterSet(OwnerFilterMixin, NetBoxModelFilterSet): 

401 virtual_machine_id = django_filters.ModelMultipleChoiceFilter( 

402 field_name='virtual_machine', 

403 queryset=VirtualMachine.objects.all(), 

404 distinct=False, 

405 label=_('Virtual machine (ID)'), 

406 ) 

407 virtual_machine = django_filters.ModelMultipleChoiceFilter( 

408 field_name='virtual_machine__name', 

409 queryset=VirtualMachine.objects.all(), 

410 distinct=False, 

411 to_field_name='name', 

412 label=_('Virtual machine'), 

413 ) 

414 

415 class Meta: 

416 model = VirtualDisk 

417 fields = ('id', 'name', 'size', 'description') 

418 

419 def search(self, queryset, name, value): 

420 if not value.strip(): 

421 return queryset 

422 return queryset.filter( 

423 Q(name__icontains=value) | 

424 Q(description__icontains=value) 

425 )