test_views.py 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. import datetime
  2. from django.contrib.contenttypes.models import ContentType
  3. from django.test import override_settings
  4. from django.urls import reverse
  5. from netaddr import IPNetwork
  6. from dcim.constants import InterfaceTypeChoices
  7. from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site, Interface
  8. from ipam.choices import *
  9. from ipam.models import *
  10. from tenancy.models import Tenant
  11. from utilities.testing import ViewTestCases, create_tags
  12. class ASNRangeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  13. model = ASNRange
  14. @classmethod
  15. def setUpTestData(cls):
  16. rirs = [
  17. RIR(name='RIR 1', slug='rir-1', is_private=True),
  18. RIR(name='RIR 2', slug='rir-2', is_private=True),
  19. ]
  20. RIR.objects.bulk_create(rirs)
  21. tenants = [
  22. Tenant(name='Tenant 1', slug='tenant-1'),
  23. Tenant(name='Tenant 2', slug='tenant-2'),
  24. ]
  25. Tenant.objects.bulk_create(tenants)
  26. asn_ranges = (
  27. ASNRange(name='ASN Range 1', slug='asn-range-1', rir=rirs[0], tenant=tenants[0], start=100, end=199),
  28. ASNRange(name='ASN Range 2', slug='asn-range-2', rir=rirs[0], tenant=tenants[0], start=200, end=299),
  29. ASNRange(name='ASN Range 3', slug='asn-range-3', rir=rirs[0], tenant=tenants[0], start=300, end=399),
  30. )
  31. ASNRange.objects.bulk_create(asn_ranges)
  32. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  33. cls.form_data = {
  34. 'name': 'ASN Range X',
  35. 'slug': 'asn-range-x',
  36. 'rir': rirs[1].pk,
  37. 'tenant': tenants[1].pk,
  38. 'start': 1000,
  39. 'end': 1099,
  40. 'description': 'A new ASN range',
  41. 'tags': [t.pk for t in tags],
  42. }
  43. cls.csv_data = (
  44. "name,slug,rir,tenant,start,end,description",
  45. f"ASN Range 4,asn-range-4,{rirs[1].name},{tenants[1].name},400,499,Fourth range",
  46. f"ASN Range 5,asn-range-5,{rirs[1].name},{tenants[1].name},500,599,Fifth range",
  47. f"ASN Range 6,asn-range-6,{rirs[1].name},{tenants[1].name},600,699,Sixth range",
  48. )
  49. cls.csv_update_data = (
  50. "id,description",
  51. f"{asn_ranges[0].pk},New description 1",
  52. f"{asn_ranges[1].pk},New description 2",
  53. f"{asn_ranges[2].pk},New description 3",
  54. )
  55. cls.bulk_edit_data = {
  56. 'rir': rirs[1].pk,
  57. 'description': 'Next description',
  58. }
  59. class ASNTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  60. model = ASN
  61. @classmethod
  62. def setUpTestData(cls):
  63. rirs = [
  64. RIR(name='RIR 1', slug='rir-1', is_private=True),
  65. RIR(name='RIR 2', slug='rir-2', is_private=True),
  66. ]
  67. RIR.objects.bulk_create(rirs)
  68. sites = (
  69. Site(name='Site 1', slug='site-1'),
  70. Site(name='Site 2', slug='site-2')
  71. )
  72. Site.objects.bulk_create(sites)
  73. tenants = (
  74. Tenant(name='Tenant 1', slug='tenant-1'),
  75. Tenant(name='Tenant 2', slug='tenant-2'),
  76. )
  77. Tenant.objects.bulk_create(tenants)
  78. asns = (
  79. ASN(asn=65001, rir=rirs[0], tenant=tenants[0]),
  80. ASN(asn=65002, rir=rirs[1], tenant=tenants[1]),
  81. ASN(asn=4200000001, rir=rirs[0], tenant=tenants[0]),
  82. ASN(asn=4200000002, rir=rirs[1], tenant=tenants[1]),
  83. )
  84. ASN.objects.bulk_create(asns)
  85. asns[0].sites.set([sites[0]])
  86. asns[1].sites.set([sites[1]])
  87. asns[2].sites.set([sites[0]])
  88. asns[3].sites.set([sites[1]])
  89. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  90. cls.form_data = {
  91. 'asn': 65000,
  92. 'rir': rirs[0].pk,
  93. 'tenant': tenants[0].pk,
  94. 'site': sites[0].pk,
  95. 'description': 'A new ASN',
  96. 'tags': [t.pk for t in tags],
  97. }
  98. cls.csv_data = (
  99. "asn,rir",
  100. "65003,RIR 1",
  101. "65004,RIR 2",
  102. "4200000003,RIR 1",
  103. "4200000004,RIR 2",
  104. )
  105. cls.csv_update_data = (
  106. "id,description",
  107. f"{asns[0].pk},New description1",
  108. f"{asns[1].pk},New description2",
  109. f"{asns[2].pk},New description3",
  110. )
  111. cls.bulk_edit_data = {
  112. 'rir': rirs[1].pk,
  113. 'description': 'Next description',
  114. }
  115. class VRFTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  116. model = VRF
  117. @classmethod
  118. def setUpTestData(cls):
  119. tenants = (
  120. Tenant(name='Tenant A', slug='tenant-a'),
  121. Tenant(name='Tenant B', slug='tenant-b'),
  122. )
  123. Tenant.objects.bulk_create(tenants)
  124. vrfs = (
  125. VRF(name='VRF 1', rd='65000:1'),
  126. VRF(name='VRF 2', rd='65000:2'),
  127. VRF(name='VRF 3', rd='65000:3'),
  128. )
  129. VRF.objects.bulk_create(vrfs)
  130. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  131. cls.form_data = {
  132. 'name': 'VRF X',
  133. 'rd': '65000:999',
  134. 'tenant': tenants[0].pk,
  135. 'enforce_unique': True,
  136. 'description': 'A new VRF',
  137. 'tags': [t.pk for t in tags],
  138. }
  139. cls.csv_data = (
  140. "name",
  141. "VRF 4",
  142. "VRF 5",
  143. "VRF 6",
  144. )
  145. cls.csv_update_data = (
  146. "id,name",
  147. f"{vrfs[0].pk},VRF 7",
  148. f"{vrfs[1].pk},VRF 8",
  149. f"{vrfs[2].pk},VRF 9",
  150. )
  151. cls.bulk_edit_data = {
  152. 'tenant': tenants[1].pk,
  153. 'enforce_unique': False,
  154. 'description': 'New description',
  155. }
  156. class RouteTargetTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  157. model = RouteTarget
  158. @classmethod
  159. def setUpTestData(cls):
  160. tenants = (
  161. Tenant(name='Tenant A', slug='tenant-a'),
  162. Tenant(name='Tenant B', slug='tenant-b'),
  163. )
  164. Tenant.objects.bulk_create(tenants)
  165. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  166. route_targets = (
  167. RouteTarget(name='65000:1001', tenant=tenants[0]),
  168. RouteTarget(name='65000:1002', tenant=tenants[1]),
  169. RouteTarget(name='65000:1003'),
  170. )
  171. RouteTarget.objects.bulk_create(route_targets)
  172. cls.form_data = {
  173. 'name': '65000:100',
  174. 'description': 'A new route target',
  175. 'tags': [t.pk for t in tags],
  176. }
  177. cls.csv_data = (
  178. "name,tenant,description",
  179. "65000:1004,Tenant A,Foo",
  180. "65000:1005,Tenant B,Bar",
  181. "65000:1006,,No tenant",
  182. )
  183. cls.csv_update_data = (
  184. "id,name,description",
  185. f"{route_targets[0].pk},65000:1007,New description1",
  186. f"{route_targets[1].pk},65000:1008,New description2",
  187. f"{route_targets[2].pk},65000:1009,New description3",
  188. )
  189. cls.bulk_edit_data = {
  190. 'tenant': tenants[1].pk,
  191. 'description': 'New description',
  192. }
  193. class RIRTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  194. model = RIR
  195. @classmethod
  196. def setUpTestData(cls):
  197. rirs = (
  198. RIR(name='RIR 1', slug='rir-1'),
  199. RIR(name='RIR 2', slug='rir-2'),
  200. RIR(name='RIR 3', slug='rir-3'),
  201. )
  202. RIR.objects.bulk_create(rirs)
  203. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  204. cls.form_data = {
  205. 'name': 'RIR X',
  206. 'slug': 'rir-x',
  207. 'is_private': True,
  208. 'description': 'A new RIR',
  209. 'tags': [t.pk for t in tags],
  210. }
  211. cls.csv_data = (
  212. "name,slug,description",
  213. "RIR 4,rir-4,Fourth RIR",
  214. "RIR 5,rir-5,Fifth RIR",
  215. "RIR 6,rir-6,Sixth RIR",
  216. )
  217. cls.csv_update_data = (
  218. "id,name,description",
  219. f"{rirs[0].pk},RIR 7,Fourth RIR7",
  220. f"{rirs[1].pk},RIR 8,Fifth RIR8",
  221. f"{rirs[2].pk},RIR 9,Sixth RIR9",
  222. )
  223. cls.bulk_edit_data = {
  224. 'description': 'New description',
  225. }
  226. class AggregateTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  227. model = Aggregate
  228. @classmethod
  229. def setUpTestData(cls):
  230. rirs = (
  231. RIR(name='RIR 1', slug='rir-1'),
  232. RIR(name='RIR 2', slug='rir-2'),
  233. )
  234. RIR.objects.bulk_create(rirs)
  235. aggregates = (
  236. Aggregate(prefix=IPNetwork('10.1.0.0/16'), rir=rirs[0]),
  237. Aggregate(prefix=IPNetwork('10.2.0.0/16'), rir=rirs[0]),
  238. Aggregate(prefix=IPNetwork('10.3.0.0/16'), rir=rirs[0]),
  239. )
  240. Aggregate.objects.bulk_create(aggregates)
  241. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  242. cls.form_data = {
  243. 'prefix': IPNetwork('10.99.0.0/16'),
  244. 'rir': rirs[1].pk,
  245. 'date_added': datetime.date(2020, 1, 1),
  246. 'description': 'A new aggregate',
  247. 'tags': [t.pk for t in tags],
  248. }
  249. cls.csv_data = (
  250. "prefix,rir",
  251. "10.4.0.0/16,RIR 1",
  252. "10.5.0.0/16,RIR 1",
  253. "10.6.0.0/16,RIR 1",
  254. )
  255. cls.csv_update_data = (
  256. "id,description",
  257. f"{aggregates[0].pk},New description1",
  258. f"{aggregates[1].pk},New description2",
  259. f"{aggregates[2].pk},New description3",
  260. )
  261. cls.bulk_edit_data = {
  262. 'rir': rirs[1].pk,
  263. 'date_added': datetime.date(2020, 1, 1),
  264. 'description': 'New description',
  265. }
  266. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  267. def test_aggregate_prefixes(self):
  268. rir = RIR.objects.first()
  269. aggregate = Aggregate.objects.create(prefix=IPNetwork('192.168.0.0/16'), rir=rir)
  270. prefixes = (
  271. Prefix(prefix=IPNetwork('192.168.1.0/24')),
  272. Prefix(prefix=IPNetwork('192.168.2.0/24')),
  273. Prefix(prefix=IPNetwork('192.168.3.0/24')),
  274. )
  275. Prefix.objects.bulk_create(prefixes)
  276. self.assertEqual(aggregate.get_child_prefixes().count(), 3)
  277. url = reverse('ipam:aggregate_prefixes', kwargs={'pk': aggregate.pk})
  278. self.assertHttpStatus(self.client.get(url), 200)
  279. class RoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  280. model = Role
  281. @classmethod
  282. def setUpTestData(cls):
  283. roles = (
  284. Role(name='Role 1', slug='role-1'),
  285. Role(name='Role 2', slug='role-2'),
  286. Role(name='Role 3', slug='role-3'),
  287. )
  288. Role.objects.bulk_create(roles)
  289. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  290. cls.form_data = {
  291. 'name': 'Role X',
  292. 'slug': 'role-x',
  293. 'weight': 200,
  294. 'description': 'A new role',
  295. 'tags': [t.pk for t in tags],
  296. }
  297. cls.csv_data = (
  298. "name,slug,weight",
  299. "Role 4,role-4,1000",
  300. "Role 5,role-5,1000",
  301. "Role 6,role-6,1000",
  302. )
  303. cls.csv_update_data = (
  304. "id,name,description",
  305. f"{roles[0].pk},Role 7,New description7",
  306. f"{roles[1].pk},Role 8,New description8",
  307. f"{roles[2].pk},Role 9,New description9",
  308. )
  309. cls.bulk_edit_data = {
  310. 'description': 'New description',
  311. }
  312. class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  313. model = Prefix
  314. @classmethod
  315. def setUpTestData(cls):
  316. sites = (
  317. Site(name='Site 1', slug='site-1'),
  318. Site(name='Site 2', slug='site-2'),
  319. )
  320. Site.objects.bulk_create(sites)
  321. vrfs = (
  322. VRF(name='VRF 1', rd='65000:1'),
  323. VRF(name='VRF 2', rd='65000:2'),
  324. )
  325. VRF.objects.bulk_create(vrfs)
  326. roles = (
  327. Role(name='Role 1', slug='role-1'),
  328. Role(name='Role 2', slug='role-2'),
  329. )
  330. Role.objects.bulk_create(roles)
  331. prefixes = (
  332. Prefix(prefix=IPNetwork('10.1.0.0/16'), vrf=vrfs[0], scope=sites[0], role=roles[0]),
  333. Prefix(prefix=IPNetwork('10.2.0.0/16'), vrf=vrfs[0], scope=sites[0], role=roles[0]),
  334. Prefix(prefix=IPNetwork('10.3.0.0/16'), vrf=vrfs[0], scope=sites[0], role=roles[0]),
  335. )
  336. Prefix.objects.bulk_create(prefixes)
  337. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  338. cls.form_data = {
  339. 'prefix': IPNetwork('192.0.2.0/24'),
  340. 'scope_type': ContentType.objects.get_for_model(Site).pk,
  341. 'scope': sites[1].pk,
  342. 'vrf': vrfs[1].pk,
  343. 'tenant': None,
  344. 'vlan': None,
  345. 'status': PrefixStatusChoices.STATUS_RESERVED,
  346. 'role': roles[1].pk,
  347. 'is_pool': True,
  348. 'description': 'A new prefix',
  349. 'tags': [t.pk for t in tags],
  350. }
  351. site = sites[0].pk
  352. cls.csv_data = (
  353. "vrf,prefix,status,scope_type,scope_id",
  354. f"VRF 1,10.4.0.0/16,active,dcim.site,{site}",
  355. f"VRF 1,10.5.0.0/16,active,dcim.site,{site}",
  356. f"VRF 1,10.6.0.0/16,active,dcim.site,{site}",
  357. )
  358. cls.csv_update_data = (
  359. "id,description,status",
  360. f"{prefixes[0].pk},New description 7,{PrefixStatusChoices.STATUS_RESERVED}",
  361. f"{prefixes[1].pk},New description 8,{PrefixStatusChoices.STATUS_RESERVED}",
  362. f"{prefixes[2].pk},New description 9,{PrefixStatusChoices.STATUS_RESERVED}",
  363. )
  364. cls.bulk_edit_data = {
  365. 'vrf': vrfs[1].pk,
  366. 'tenant': None,
  367. 'status': PrefixStatusChoices.STATUS_RESERVED,
  368. 'role': roles[1].pk,
  369. 'is_pool': False,
  370. 'description': 'New description',
  371. }
  372. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  373. def test_prefix_prefixes(self):
  374. prefixes = (
  375. Prefix(prefix=IPNetwork('192.168.0.0/16')),
  376. Prefix(prefix=IPNetwork('192.168.1.0/24')),
  377. Prefix(prefix=IPNetwork('192.168.2.0/24')),
  378. Prefix(prefix=IPNetwork('192.168.3.0/24')),
  379. )
  380. Prefix.objects.bulk_create(prefixes)
  381. self.assertEqual(prefixes[0].get_child_prefixes().count(), 3)
  382. url = reverse('ipam:prefix_prefixes', kwargs={'pk': prefixes[0].pk})
  383. self.assertHttpStatus(self.client.get(url), 200)
  384. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  385. def test_prefix_ipranges(self):
  386. prefix = Prefix.objects.create(prefix=IPNetwork('192.168.0.0/16'))
  387. ip_ranges = (
  388. IPRange(start_address='192.168.0.1/24', end_address='192.168.0.100/24', size=99),
  389. IPRange(start_address='192.168.1.1/24', end_address='192.168.1.100/24', size=99),
  390. IPRange(start_address='192.168.2.1/24', end_address='192.168.2.100/24', size=99),
  391. )
  392. IPRange.objects.bulk_create(ip_ranges)
  393. self.assertEqual(prefix.get_child_ranges().count(), 3)
  394. url = reverse('ipam:prefix_ipranges', kwargs={'pk': prefix.pk})
  395. self.assertHttpStatus(self.client.get(url), 200)
  396. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  397. def test_prefix_ipaddresses(self):
  398. prefix = Prefix.objects.create(prefix=IPNetwork('192.168.0.0/16'))
  399. ip_addresses = (
  400. IPAddress(address=IPNetwork('192.168.0.1/16')),
  401. IPAddress(address=IPNetwork('192.168.0.2/16')),
  402. IPAddress(address=IPNetwork('192.168.0.3/16')),
  403. )
  404. IPAddress.objects.bulk_create(ip_addresses)
  405. self.assertEqual(prefix.get_child_ips().count(), 3)
  406. url = reverse('ipam:prefix_ipaddresses', kwargs={'pk': prefix.pk})
  407. self.assertHttpStatus(self.client.get(url), 200)
  408. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  409. def test_prefix_import(self):
  410. """
  411. Custom import test for YAML-based imports (versus CSV)
  412. """
  413. site = Site.objects.get(name='Site 1')
  414. IMPORT_DATA = f"""
  415. prefix: 10.1.1.0/24
  416. status: active
  417. vlan: 101
  418. scope_type: dcim.site
  419. scope_id: {site.pk}
  420. """
  421. # Note, a site is not tied to the VLAN to verify the fix for #12622
  422. VLAN.objects.create(vid=101, name='VLAN101')
  423. # Add all required permissions to the test user
  424. self.add_permissions('ipam.view_prefix', 'ipam.add_prefix')
  425. form_data = {
  426. 'data': IMPORT_DATA,
  427. 'format': 'yaml'
  428. }
  429. response = self.client.post(reverse('ipam:prefix_bulk_import'), data=form_data, follow=True)
  430. self.assertHttpStatus(response, 200)
  431. prefix = Prefix.objects.get(prefix='10.1.1.0/24')
  432. self.assertEqual(prefix.status, PrefixStatusChoices.STATUS_ACTIVE)
  433. self.assertEqual(prefix.vlan.vid, 101)
  434. self.assertEqual(prefix.scope, site)
  435. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  436. def test_prefix_import_with_vlan_group(self):
  437. """
  438. This test covers a unique import edge case where VLAN group is specified during the import.
  439. """
  440. site = Site.objects.get(name='Site 1')
  441. IMPORT_DATA = f"""
  442. prefix: 10.1.2.0/24
  443. status: active
  444. scope_type: dcim.site
  445. scope_id: {site.pk}
  446. vlan_group: Group 1
  447. vlan: 102
  448. """
  449. vlan_group = VLANGroup.objects.create(name='Group 1', slug='group-1', scope=Site.objects.get(name="Site 1"))
  450. VLAN.objects.create(vid=102, name='VLAN102', group=vlan_group)
  451. # Add all required permissions to the test user
  452. self.add_permissions('ipam.view_prefix', 'ipam.add_prefix')
  453. form_data = {
  454. 'data': IMPORT_DATA,
  455. 'format': 'yaml'
  456. }
  457. response = self.client.post(reverse('ipam:prefix_bulk_import'), data=form_data, follow=True)
  458. self.assertHttpStatus(response, 200)
  459. prefix = Prefix.objects.get(prefix='10.1.2.0/24')
  460. self.assertEqual(prefix.status, PrefixStatusChoices.STATUS_ACTIVE)
  461. self.assertEqual(prefix.vlan.vid, 102)
  462. self.assertEqual(prefix.scope, site)
  463. class IPRangeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  464. model = IPRange
  465. @classmethod
  466. def setUpTestData(cls):
  467. vrfs = (
  468. VRF(name='VRF 1', rd='65000:1'),
  469. VRF(name='VRF 2', rd='65000:2'),
  470. )
  471. VRF.objects.bulk_create(vrfs)
  472. roles = (
  473. Role(name='Role 1', slug='role-1'),
  474. Role(name='Role 2', slug='role-2'),
  475. )
  476. Role.objects.bulk_create(roles)
  477. ip_ranges = (
  478. IPRange(start_address='192.168.0.10/24', end_address='192.168.0.100/24', size=91),
  479. IPRange(start_address='192.168.1.10/24', end_address='192.168.1.100/24', size=91),
  480. IPRange(start_address='192.168.2.10/24', end_address='192.168.2.100/24', size=91),
  481. IPRange(start_address='192.168.3.10/24', end_address='192.168.3.100/24', size=91),
  482. IPRange(start_address='192.168.4.10/24', end_address='192.168.4.100/24', size=91),
  483. )
  484. IPRange.objects.bulk_create(ip_ranges)
  485. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  486. cls.form_data = {
  487. 'start_address': IPNetwork('192.0.5.10/24'),
  488. 'end_address': IPNetwork('192.0.5.100/24'),
  489. 'vrf': vrfs[1].pk,
  490. 'tenant': None,
  491. 'vlan': None,
  492. 'status': IPRangeStatusChoices.STATUS_RESERVED,
  493. 'role': roles[1].pk,
  494. 'is_pool': True,
  495. 'description': 'A new IP range',
  496. 'tags': [t.pk for t in tags],
  497. }
  498. cls.csv_data = (
  499. "vrf,start_address,end_address,status",
  500. "VRF 1,10.1.0.1/16,10.1.9.254/16,active",
  501. "VRF 1,10.2.0.1/16,10.2.9.254/16,active",
  502. "VRF 1,10.3.0.1/16,10.3.9.254/16,active",
  503. )
  504. cls.csv_update_data = (
  505. "id,description,status",
  506. f"{ip_ranges[0].pk},New description 7,{IPRangeStatusChoices.STATUS_RESERVED}",
  507. f"{ip_ranges[1].pk},New description 8,{IPRangeStatusChoices.STATUS_RESERVED}",
  508. f"{ip_ranges[2].pk},New description 9,{IPRangeStatusChoices.STATUS_RESERVED}",
  509. )
  510. cls.bulk_edit_data = {
  511. 'vrf': vrfs[1].pk,
  512. 'tenant': None,
  513. 'status': IPRangeStatusChoices.STATUS_RESERVED,
  514. 'role': roles[1].pk,
  515. 'description': 'New description',
  516. }
  517. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  518. def test_iprange_ipaddresses(self):
  519. iprange = IPRange.objects.create(
  520. start_address=IPNetwork('192.168.0.1/24'),
  521. end_address=IPNetwork('192.168.0.100/24'),
  522. size=99
  523. )
  524. ip_addresses = (
  525. IPAddress(address=IPNetwork('192.168.0.1/24')),
  526. IPAddress(address=IPNetwork('192.168.0.2/24')),
  527. IPAddress(address=IPNetwork('192.168.0.3/24')),
  528. )
  529. IPAddress.objects.bulk_create(ip_addresses)
  530. self.assertEqual(iprange.get_child_ips().count(), 3)
  531. url = reverse('ipam:iprange_ipaddresses', kwargs={'pk': iprange.pk})
  532. self.assertHttpStatus(self.client.get(url), 200)
  533. class IPAddressTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  534. model = IPAddress
  535. @classmethod
  536. def setUpTestData(cls):
  537. vrfs = (
  538. VRF(name='VRF 1', rd='65000:1'),
  539. VRF(name='VRF 2', rd='65000:2'),
  540. )
  541. VRF.objects.bulk_create(vrfs)
  542. ipaddresses = (
  543. IPAddress(address=IPNetwork('192.0.2.1/24'), vrf=vrfs[0]),
  544. IPAddress(address=IPNetwork('192.0.2.2/24'), vrf=vrfs[0]),
  545. IPAddress(address=IPNetwork('192.0.2.3/24'), vrf=vrfs[0]),
  546. )
  547. IPAddress.objects.bulk_create(ipaddresses)
  548. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  549. fhrp_groups = (
  550. FHRPGroup(
  551. name='FHRP Group 1',
  552. protocol=FHRPGroupProtocolChoices.PROTOCOL_HSRP,
  553. group_id=10
  554. ),
  555. FHRPGroup(
  556. name='FHRP Group 2',
  557. protocol=FHRPGroupProtocolChoices.PROTOCOL_HSRP,
  558. group_id=20
  559. ),
  560. FHRPGroup(
  561. name='FHRP Group 3',
  562. protocol=FHRPGroupProtocolChoices.PROTOCOL_HSRP,
  563. group_id=30
  564. ),
  565. )
  566. FHRPGroup.objects.bulk_create(fhrp_groups)
  567. cls.form_data = {
  568. 'vrf': vrfs[1].pk,
  569. 'address': IPNetwork('192.0.2.99/24'),
  570. 'tenant': None,
  571. 'status': IPAddressStatusChoices.STATUS_RESERVED,
  572. 'role': IPAddressRoleChoices.ROLE_ANYCAST,
  573. 'nat_inside': None,
  574. 'dns_name': 'example',
  575. 'description': 'A new IP address',
  576. 'tags': [t.pk for t in tags],
  577. }
  578. cls.csv_data = (
  579. "vrf,address,status,fhrp_group",
  580. "VRF 1,192.0.2.4/24,active,FHRP Group 1",
  581. "VRF 1,192.0.2.5/24,active,FHRP Group 2",
  582. "VRF 1,192.0.2.6/24,active,FHRP Group 3",
  583. )
  584. cls.csv_update_data = (
  585. "id,description,status",
  586. f"{ipaddresses[0].pk},New description 7,{IPAddressStatusChoices.STATUS_RESERVED}",
  587. f"{ipaddresses[1].pk},New description 8,{IPAddressStatusChoices.STATUS_RESERVED}",
  588. f"{ipaddresses[2].pk},New description 9,{IPAddressStatusChoices.STATUS_RESERVED}",
  589. )
  590. cls.bulk_edit_data = {
  591. 'vrf': vrfs[1].pk,
  592. 'tenant': None,
  593. 'status': IPAddressStatusChoices.STATUS_RESERVED,
  594. 'role': IPAddressRoleChoices.ROLE_ANYCAST,
  595. 'dns_name': 'example',
  596. 'description': 'New description',
  597. }
  598. class FHRPGroupTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  599. model = FHRPGroup
  600. @classmethod
  601. def setUpTestData(cls):
  602. fhrp_groups = (
  603. FHRPGroup(
  604. protocol=FHRPGroupProtocolChoices.PROTOCOL_VRRP2,
  605. group_id=10,
  606. auth_type=FHRPGroupAuthTypeChoices.AUTHENTICATION_PLAINTEXT,
  607. auth_key='foobar123',
  608. ),
  609. FHRPGroup(
  610. protocol=FHRPGroupProtocolChoices.PROTOCOL_VRRP3,
  611. group_id=20,
  612. auth_type=FHRPGroupAuthTypeChoices.AUTHENTICATION_MD5,
  613. auth_key='foobar123',
  614. ),
  615. FHRPGroup(
  616. protocol=FHRPGroupProtocolChoices.PROTOCOL_HSRP,
  617. group_id=30
  618. ),
  619. )
  620. FHRPGroup.objects.bulk_create(fhrp_groups)
  621. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  622. cls.form_data = {
  623. 'protocol': FHRPGroupProtocolChoices.PROTOCOL_VRRP2,
  624. 'group_id': 99,
  625. 'auth_type': FHRPGroupAuthTypeChoices.AUTHENTICATION_MD5,
  626. 'auth_key': 'abc123def456',
  627. 'description': 'Blah blah blah',
  628. 'name': 'test123 name',
  629. 'tags': [t.pk for t in tags],
  630. }
  631. cls.csv_data = (
  632. "protocol,group_id,auth_type,auth_key,description",
  633. "vrrp2,40,plaintext,foobar123,Foo",
  634. "vrrp3,50,md5,foobar123,Bar",
  635. "hsrp,60,,,",
  636. )
  637. cls.csv_update_data = (
  638. "id,name,description",
  639. f"{fhrp_groups[0].pk},FHRP Group 1,New description 1",
  640. f"{fhrp_groups[1].pk},FHRP Group 2,New description 2",
  641. f"{fhrp_groups[2].pk},FHRP Group 3,New description 3",
  642. )
  643. cls.bulk_edit_data = {
  644. 'protocol': FHRPGroupProtocolChoices.PROTOCOL_CARP,
  645. }
  646. class VLANGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  647. model = VLANGroup
  648. @classmethod
  649. def setUpTestData(cls):
  650. sites = (
  651. Site(name='Site 1', slug='site-1'),
  652. Site(name='Site 2', slug='site-2'),
  653. )
  654. Site.objects.bulk_create(sites)
  655. vlan_groups = (
  656. VLANGroup(name='VLAN Group 1', slug='vlan-group-1', scope=sites[0]),
  657. VLANGroup(name='VLAN Group 2', slug='vlan-group-2', scope=sites[0]),
  658. VLANGroup(name='VLAN Group 3', slug='vlan-group-3', scope=sites[0]),
  659. )
  660. VLANGroup.objects.bulk_create(vlan_groups)
  661. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  662. cls.form_data = {
  663. 'name': 'VLAN Group X',
  664. 'slug': 'vlan-group-x',
  665. 'description': 'A new VLAN group',
  666. 'vid_ranges': '100-199,300-399',
  667. 'tags': [t.pk for t in tags],
  668. }
  669. cls.csv_data = (
  670. "name,slug,scope_type,scope_id,description",
  671. "VLAN Group 4,vlan-group-4,,,Fourth VLAN group",
  672. f"VLAN Group 5,vlan-group-5,dcim.site,{sites[0].pk},Fifth VLAN group",
  673. f"VLAN Group 6,vlan-group-6,dcim.site,{sites[1].pk},Sixth VLAN group",
  674. )
  675. cls.csv_update_data = (
  676. "id,name,description",
  677. f"{vlan_groups[0].pk},VLAN Group 7,Fourth VLAN group7",
  678. f"{vlan_groups[1].pk},VLAN Group 8,Fifth VLAN group8",
  679. f"{vlan_groups[2].pk},VLAN Group 9,Sixth VLAN group9",
  680. )
  681. cls.bulk_edit_data = {
  682. 'description': 'New description',
  683. }
  684. class VLANTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  685. model = VLAN
  686. @classmethod
  687. def setUpTestData(cls):
  688. sites = (
  689. Site(name='Site 1', slug='site-1'),
  690. Site(name='Site 2', slug='site-2'),
  691. )
  692. Site.objects.bulk_create(sites)
  693. vlangroups = (
  694. VLANGroup(name='VLAN Group 1', slug='vlan-group-1', scope=sites[0]),
  695. VLANGroup(name='VLAN Group 2', slug='vlan-group-2', scope=sites[1]),
  696. )
  697. VLANGroup.objects.bulk_create(vlangroups)
  698. roles = (
  699. Role(name='Role 1', slug='role-1'),
  700. Role(name='Role 2', slug='role-2'),
  701. )
  702. Role.objects.bulk_create(roles)
  703. vlans = (
  704. VLAN(group=vlangroups[0], vid=101, name='VLAN101', site=sites[0], role=roles[0]),
  705. VLAN(group=vlangroups[0], vid=102, name='VLAN102', site=sites[0], role=roles[0]),
  706. VLAN(group=vlangroups[0], vid=103, name='VLAN103', site=sites[0], role=roles[0]),
  707. )
  708. VLAN.objects.bulk_create(vlans)
  709. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  710. cls.form_data = {
  711. 'site': sites[1].pk,
  712. 'group': vlangroups[1].pk,
  713. 'vid': 999,
  714. 'name': 'VLAN999',
  715. 'tenant': None,
  716. 'status': VLANStatusChoices.STATUS_RESERVED,
  717. 'role': roles[1].pk,
  718. 'description': 'A new VLAN',
  719. 'tags': [t.pk for t in tags],
  720. }
  721. cls.csv_data = (
  722. "vid,name,status",
  723. "104,VLAN104,active",
  724. "105,VLAN105,active",
  725. "106,VLAN106,active",
  726. )
  727. cls.csv_update_data = (
  728. "id,name,description",
  729. f"{vlans[0].pk},VLAN107,New description 7",
  730. f"{vlans[1].pk},VLAN108,New description 8",
  731. f"{vlans[2].pk},VLAN109,New description 9",
  732. )
  733. cls.bulk_edit_data = {
  734. 'site': sites[1].pk,
  735. 'group': vlangroups[1].pk,
  736. 'tenant': None,
  737. 'status': VLANStatusChoices.STATUS_RESERVED,
  738. 'role': roles[1].pk,
  739. 'description': 'New description',
  740. }
  741. class VLANTranslationPolicyTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  742. model = VLANTranslationPolicy
  743. @classmethod
  744. def setUpTestData(cls):
  745. vlan_translation_policies = (
  746. VLANTranslationPolicy(
  747. name='Policy 1',
  748. description='foobar1',
  749. ),
  750. VLANTranslationPolicy(
  751. name='Policy 2',
  752. description='foobar2',
  753. ),
  754. VLANTranslationPolicy(
  755. name='Policy 3',
  756. description='foobar3',
  757. ),
  758. )
  759. VLANTranslationPolicy.objects.bulk_create(vlan_translation_policies)
  760. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  761. cls.form_data = {
  762. 'name': 'Policy999',
  763. 'description': 'A new VLAN Translation Policy',
  764. 'tags': [t.pk for t in tags],
  765. }
  766. cls.csv_data = (
  767. "name,description",
  768. "Policy101,foobar1",
  769. "Policy102,foobar2",
  770. "Policy103,foobar3",
  771. )
  772. cls.csv_update_data = (
  773. "id,name,description",
  774. f"{vlan_translation_policies[0].pk},Policy101,New description 1",
  775. f"{vlan_translation_policies[1].pk},Policy102,New description 2",
  776. f"{vlan_translation_policies[2].pk},Policy103,New description 3",
  777. )
  778. cls.bulk_edit_data = {
  779. 'description': 'New description',
  780. }
  781. class VLANTranslationRuleTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  782. model = VLANTranslationRule
  783. @classmethod
  784. def setUpTestData(cls):
  785. vlan_translation_policies = (
  786. VLANTranslationPolicy(
  787. name='Policy 1',
  788. description='foobar1',
  789. ),
  790. VLANTranslationPolicy(
  791. name='Policy 2',
  792. description='foobar2',
  793. ),
  794. VLANTranslationPolicy(
  795. name='Policy 3',
  796. description='foobar3',
  797. ),
  798. )
  799. VLANTranslationPolicy.objects.bulk_create(vlan_translation_policies)
  800. vlan_translation_rules = (
  801. VLANTranslationRule(
  802. policy=vlan_translation_policies[0],
  803. local_vid=100,
  804. remote_vid=200,
  805. ),
  806. VLANTranslationRule(
  807. policy=vlan_translation_policies[0],
  808. local_vid=101,
  809. remote_vid=201,
  810. ),
  811. VLANTranslationRule(
  812. policy=vlan_translation_policies[1],
  813. local_vid=102,
  814. remote_vid=202,
  815. ),
  816. )
  817. VLANTranslationRule.objects.bulk_create(vlan_translation_rules)
  818. cls.form_data = {
  819. 'policy': vlan_translation_policies[0].pk,
  820. 'local_vid': 300,
  821. 'remote_vid': 400,
  822. }
  823. cls.csv_data = (
  824. "policy,local_vid,remote_vid",
  825. f"{vlan_translation_policies[0].name},103,203",
  826. f"{vlan_translation_policies[0].name},104,204",
  827. f"{vlan_translation_policies[1].name},105,205",
  828. )
  829. cls.csv_update_data = (
  830. "id,local_vid,remote_vid",
  831. f"{vlan_translation_rules[0].pk},105,205",
  832. f"{vlan_translation_rules[1].pk},106,206",
  833. f"{vlan_translation_rules[2].pk},107,207",
  834. )
  835. cls.bulk_edit_data = {
  836. 'policy': vlan_translation_policies[2].pk,
  837. }
  838. class ServiceTemplateTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  839. model = ServiceTemplate
  840. @classmethod
  841. def setUpTestData(cls):
  842. service_templates = (
  843. ServiceTemplate(name='Service Template 1', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[101]),
  844. ServiceTemplate(name='Service Template 2', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[102]),
  845. ServiceTemplate(name='Service Template 3', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[103]),
  846. )
  847. ServiceTemplate.objects.bulk_create(service_templates)
  848. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  849. cls.form_data = {
  850. 'name': 'Service Template X',
  851. 'protocol': ServiceProtocolChoices.PROTOCOL_UDP,
  852. 'ports': '104,105',
  853. 'description': 'A new service template',
  854. 'tags': [t.pk for t in tags],
  855. }
  856. cls.csv_data = (
  857. "name,protocol,ports,description",
  858. "Service Template 4,tcp,1,First service template",
  859. "Service Template 5,tcp,2,Second service template",
  860. "Service Template 6,tcp,3,Third service template",
  861. )
  862. cls.csv_update_data = (
  863. "id,name,description",
  864. f"{service_templates[0].pk},Service Template 7,First service template7",
  865. f"{service_templates[1].pk},Service Template 8,Second service template8",
  866. f"{service_templates[2].pk},Service Template 9,Third service template9",
  867. )
  868. cls.bulk_edit_data = {
  869. 'protocol': ServiceProtocolChoices.PROTOCOL_UDP,
  870. 'ports': '106,107',
  871. 'description': 'New description',
  872. }
  873. class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  874. model = Service
  875. @classmethod
  876. def setUpTestData(cls):
  877. site = Site.objects.create(name='Site 1', slug='site-1')
  878. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  879. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1')
  880. role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
  881. device = Device.objects.create(name='Device 1', site=site, device_type=devicetype, role=role)
  882. interface = Interface.objects.create(device=device, name='Interface 1', type=InterfaceTypeChoices.TYPE_VIRTUAL)
  883. services = (
  884. Service(device=device, name='Service 1', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[101]),
  885. Service(device=device, name='Service 2', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[102]),
  886. Service(device=device, name='Service 3', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[103]),
  887. )
  888. Service.objects.bulk_create(services)
  889. ip_addresses = (
  890. IPAddress(assigned_object=interface, address='192.0.2.1/24'),
  891. IPAddress(assigned_object=interface, address='192.0.2.2/24'),
  892. )
  893. IPAddress.objects.bulk_create(ip_addresses)
  894. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  895. cls.form_data = {
  896. 'device': device.pk,
  897. 'virtual_machine': None,
  898. 'name': 'Service X',
  899. 'protocol': ServiceProtocolChoices.PROTOCOL_TCP,
  900. 'ports': '104,105',
  901. 'ipaddresses': [],
  902. 'description': 'A new service',
  903. 'tags': [t.pk for t in tags],
  904. }
  905. cls.csv_data = (
  906. "device,name,protocol,ports,ipaddresses,description",
  907. "Device 1,Service 1,tcp,1,192.0.2.1/24,First service",
  908. "Device 1,Service 2,tcp,2,192.0.2.2/24,Second service",
  909. "Device 1,Service 3,udp,3,,Third service",
  910. )
  911. cls.csv_update_data = (
  912. "id,name,description",
  913. f"{services[0].pk},Service 7,First service7",
  914. f"{services[1].pk},Service 8,Second service8",
  915. f"{services[2].pk},Service 9,Third service9",
  916. )
  917. cls.bulk_edit_data = {
  918. 'protocol': ServiceProtocolChoices.PROTOCOL_UDP,
  919. 'ports': '106,107',
  920. 'description': 'New description',
  921. }
  922. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  923. def test_create_from_template(self):
  924. self.add_permissions('ipam.add_service')
  925. device = Device.objects.first()
  926. service_template = ServiceTemplate.objects.create(
  927. name='HTTP',
  928. protocol=ServiceProtocolChoices.PROTOCOL_TCP,
  929. ports=[80],
  930. description='Hypertext transfer protocol'
  931. )
  932. request = {
  933. 'path': self._get_url('add'),
  934. 'data': {
  935. 'device': device.pk,
  936. 'service_template': service_template.pk,
  937. },
  938. }
  939. self.assertHttpStatus(self.client.post(**request), 302)
  940. instance = self._get_queryset().order_by('pk').last()
  941. self.assertEqual(instance.device, device)
  942. self.assertEqual(instance.name, service_template.name)
  943. self.assertEqual(instance.protocol, service_template.protocol)
  944. self.assertEqual(instance.ports, service_template.ports)
  945. self.assertEqual(instance.description, service_template.description)