test_views.py 41 KB

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