A common library that interfaces with VMware NSX.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

526 lines
22KB

  1. # Copyright 2018 VMware, Inc.
  2. # All Rights Reserved
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. #
  16. import copy
  17. import mock
  18. from vmware_nsxlib.tests.unit.v3 import nsxlib_testcase
  19. from vmware_nsxlib.tests.unit.v3.policy import policy_testcase
  20. from vmware_nsxlib.v3 import policy
  21. from vmware_nsxlib.v3.policy import constants
  22. from vmware_nsxlib.v3.policy import transaction as trans
  23. class TestPolicyTransaction(policy_testcase.TestPolicyApi):
  24. def setUp(self):
  25. super(TestPolicyTransaction, self).setUp()
  26. nsxlib_config = nsxlib_testcase.get_default_nsxlib_config()
  27. # Mock the nsx-lib for the passthrough api
  28. with mock.patch('vmware_nsxlib.v3.NsxLib.get_version',
  29. return_value='2.5.0'):
  30. self.policy_lib = policy.NsxPolicyLib(nsxlib_config)
  31. self.policy_api = self.policy_lib.policy_api
  32. self.policy_api.client = self.client
  33. def assert_infra_patch_call(self, body):
  34. self.assert_json_call('PATCH', self.client, 'infra',
  35. data=body, headers=mock.ANY)
  36. def test_domains_only(self):
  37. tags = [{'scope': 'color', 'tag': 'green'}]
  38. d1 = {'resource_type': 'Domain', 'id': 'domain1',
  39. 'display_name': 'd1', 'description': 'first domain',
  40. 'tags': tags}
  41. d2 = {'resource_type': 'Domain', 'id': 'domain2',
  42. 'display_name': 'd2', 'description': 'no tags',
  43. 'tags': None}
  44. with trans.NsxPolicyTransaction():
  45. for d in (d1, d2):
  46. self.policy_lib.domain.create_or_overwrite(
  47. d['display_name'],
  48. d['id'],
  49. d['description'],
  50. tags=d['tags'] if 'tags' in d else None)
  51. expected_body = {'resource_type': 'Infra',
  52. 'children': [{'resource_type': 'ChildDomain',
  53. 'Domain': d1},
  54. {'resource_type': 'ChildDomain',
  55. 'Domain': d2}]}
  56. self.assert_infra_patch_call(expected_body)
  57. def test_domains_and_groups(self):
  58. tags = [{'scope': 'color', 'tag': 'green'}]
  59. g1 = {'resource_type': 'Group', 'id': 'group1',
  60. 'display_name': 'g1',
  61. 'description': 'first group',
  62. 'tags': None}
  63. g2 = {'resource_type': 'Group', 'id': 'group2',
  64. 'description': 'second group',
  65. 'display_name': 'g2',
  66. 'tags': tags}
  67. g3 = {'resource_type': 'Group', 'id': 'group3',
  68. 'display_name': 'g3',
  69. 'description': 'third group',
  70. 'tags': None}
  71. d1 = {'resource_type': 'Domain', 'id': 'domain1',
  72. 'display_name': 'd1', 'description': 'first domain',
  73. 'tags': tags}
  74. d2 = {'resource_type': 'Domain', 'id': 'domain2',
  75. 'display_name': 'd2', 'description': 'no tags',
  76. 'tags': None}
  77. with trans.NsxPolicyTransaction():
  78. for d in (d1, d2):
  79. self.policy_lib.domain.create_or_overwrite(
  80. d['display_name'],
  81. d['id'],
  82. d['description'],
  83. tags=d['tags'] if 'tags' in d else None)
  84. d['children'] = []
  85. for g in (g1, g2, g3):
  86. self.policy_lib.group.create_or_overwrite(
  87. g['display_name'],
  88. d['id'],
  89. g['id'],
  90. g['description'],
  91. tags=g['tags'] if 'tags' in g else None)
  92. d['children'].append({'resource_type': 'ChildGroup',
  93. 'Group': g})
  94. expected_body = {'resource_type': 'Infra',
  95. 'children': [{'resource_type': 'ChildDomain',
  96. 'Domain': d1},
  97. {'resource_type': 'ChildDomain',
  98. 'Domain': d2}]}
  99. self.assert_infra_patch_call(expected_body)
  100. def test_ip_address_pool_and_block_subnets(self):
  101. pool = {'id': 'pool1',
  102. 'resource_type': 'IpAddressPool',
  103. 'display_name': 'pool1',
  104. 'children': []}
  105. ip_block_id = 'block1'
  106. subnet1 = {'id': 'subnet1',
  107. 'resource_type': 'IpAddressPoolBlockSubnet',
  108. 'ip_block_path': '/infra/ip-blocks/%s' % ip_block_id,
  109. 'size': 8}
  110. subnet2 = {'id': 'subnet2',
  111. 'resource_type': 'IpAddressPoolBlockSubnet',
  112. 'ip_block_path': '/infra/ip-blocks/%s' % ip_block_id,
  113. 'size': 4}
  114. with trans.NsxPolicyTransaction():
  115. self.policy_lib.ip_pool.create_or_overwrite(
  116. pool['display_name'],
  117. ip_pool_id=pool['id'])
  118. for s in (subnet1, subnet2):
  119. self.policy_lib.ip_pool.allocate_block_subnet(
  120. ip_pool_id=pool['id'],
  121. ip_block_id=ip_block_id,
  122. ip_subnet_id=s['id'],
  123. size=s['size'])
  124. pool['children'].append(
  125. {'resource_type': 'ChildIpAddressPoolSubnet',
  126. 'IpAddressPoolSubnet': s})
  127. expected_body = {'resource_type': 'Infra',
  128. 'children': [{'resource_type': 'ChildIpAddressPool',
  129. 'IpAddressPool': pool}]}
  130. self.assert_infra_patch_call(expected_body)
  131. def test_groups_only(self):
  132. g1 = {'resource_type': 'Group', 'id': 'group1',
  133. 'display_name': 'g1',
  134. 'description': 'first group'}
  135. g2 = {'resource_type': 'Group', 'id': 'group2',
  136. 'description': 'second group',
  137. 'display_name': 'g2'}
  138. d1 = {'resource_type': 'Domain', 'id': 'domain1'}
  139. d2 = {'resource_type': 'Domain', 'id': 'domain2'}
  140. with trans.NsxPolicyTransaction():
  141. for d in (d1, d2):
  142. d['children'] = []
  143. for g in (g1, g2):
  144. self.policy_lib.group.create_or_overwrite(
  145. g['display_name'],
  146. d['id'],
  147. g['id'],
  148. g['description'])
  149. d['children'].append({'resource_type': 'ChildGroup',
  150. 'Group': g})
  151. expected_body = {'resource_type': 'Infra',
  152. 'children': [{'resource_type': 'ChildDomain',
  153. 'Domain': d1},
  154. {'resource_type': 'ChildDomain',
  155. 'Domain': d2}]}
  156. self.assert_infra_patch_call(expected_body)
  157. def test_segment_ports(self):
  158. port1 = {'id': 'port_on_seg1',
  159. 'resource_type': 'SegmentPort',
  160. 'display_name': 'port_on_seg1',
  161. 'attachment': {'type': 'VIF',
  162. 'app_id': 'app1',
  163. 'traffic_tag': 5}
  164. }
  165. port2 = {'id': 'port1_on_seg2',
  166. 'resource_type': 'SegmentPort',
  167. 'display_name': 'port_on_seg2',
  168. 'attachment': {'type': 'CHILD',
  169. 'app_id': 'app2',
  170. 'traffic_tag': None}
  171. }
  172. seg1 = {'id': 'seg1',
  173. 'resource_type': 'Segment',
  174. 'children': [{'resource_type': 'ChildSegmentPort',
  175. 'SegmentPort': port1}]}
  176. seg2 = {'id': 'seg2',
  177. 'resource_type': 'Segment',
  178. 'children': [{'resource_type': 'ChildSegmentPort',
  179. 'SegmentPort': port2}]}
  180. with trans.NsxPolicyTransaction():
  181. self.policy_lib.segment_port.create_or_overwrite(
  182. port1['display_name'],
  183. seg1['id'],
  184. port1['id'],
  185. attachment_type=port1['attachment']['type'],
  186. app_id=port1['attachment']['app_id'],
  187. traffic_tag=port1['attachment']['traffic_tag'])
  188. self.policy_lib.segment_port.create_or_overwrite(
  189. port2['display_name'],
  190. seg2['id'],
  191. port2['id'],
  192. attachment_type=port2['attachment']['type'],
  193. app_id=port2['attachment']['app_id'],
  194. traffic_tag=port2['attachment']['traffic_tag'])
  195. expected_body = {'resource_type': 'Infra',
  196. 'children': [{'resource_type': 'ChildSegment',
  197. 'Segment': seg1},
  198. {'resource_type': 'ChildSegment',
  199. 'Segment': seg2}]}
  200. self.assert_infra_patch_call(expected_body)
  201. def test_tier1_nat_rules_create(self):
  202. tier1_id = 'tier1-1'
  203. nat_rule_id1 = 'nat1'
  204. nat_rule_id2 = 'nat2'
  205. nat_rule1 = {"action": constants.NAT_ACTION_SNAT,
  206. "display_name": "snat rule",
  207. "id": nat_rule_id1,
  208. "resource_type": "PolicyNatRule"}
  209. nat_rule2 = {"action": constants.NAT_ACTION_DNAT,
  210. "display_name": "dnat rule",
  211. "id": nat_rule_id2,
  212. "resource_type": "PolicyNatRule"}
  213. policy_nat = {"id": "USER",
  214. "resource_type": "PolicyNat",
  215. "children": [
  216. {"PolicyNatRule": nat_rule1,
  217. "resource_type": "ChildPolicyNatRule"},
  218. {"PolicyNatRule": nat_rule2,
  219. "resource_type": "ChildPolicyNatRule"}]}
  220. tier1_dict = {"id": tier1_id,
  221. "resource_type": "Tier1",
  222. "children": [{"PolicyNat": policy_nat,
  223. "resource_type": "ChildPolicyNat"}]}
  224. with trans.NsxPolicyTransaction():
  225. self.policy_lib.tier1_nat_rule.create_or_overwrite(
  226. 'snat rule',
  227. tier1_id,
  228. nat_rule_id=nat_rule_id1,
  229. action=constants.NAT_ACTION_SNAT)
  230. self.policy_lib.tier1_nat_rule.create_or_overwrite(
  231. 'dnat rule',
  232. tier1_id,
  233. nat_rule_id=nat_rule_id2,
  234. action=constants.NAT_ACTION_DNAT)
  235. expected_body = {"resource_type": "Infra",
  236. "children": [{"Tier1": tier1_dict,
  237. "resource_type": "ChildTier1"}]}
  238. self.assert_infra_patch_call(expected_body)
  239. def test_tier1_nat_rules_delete(self):
  240. tier1_id = 'tier1-1'
  241. nat_rule_id1 = 'nat1'
  242. nat_rule_id2 = 'nat2'
  243. nat_rule1 = {"action": constants.NAT_ACTION_DNAT,
  244. "id": nat_rule_id1,
  245. "resource_type": "PolicyNatRule"}
  246. nat_rule2 = {"action": constants.NAT_ACTION_DNAT,
  247. "id": nat_rule_id2,
  248. "resource_type": "PolicyNatRule"}
  249. policy_nat = {"id": "USER",
  250. "resource_type": "PolicyNat",
  251. "children": [
  252. {"PolicyNatRule": nat_rule1,
  253. "marked_for_delete": True,
  254. "resource_type": "ChildPolicyNatRule"},
  255. {"PolicyNatRule": nat_rule2,
  256. "marked_for_delete": True,
  257. "resource_type": "ChildPolicyNatRule"}]}
  258. tier1_dict = {"id": tier1_id,
  259. "resource_type": "Tier1",
  260. "children": [{"PolicyNat": policy_nat,
  261. "resource_type": "ChildPolicyNat"}]}
  262. with trans.NsxPolicyTransaction():
  263. self.policy_lib.tier1_nat_rule.delete(
  264. tier1_id,
  265. nat_rule_id=nat_rule_id1)
  266. self.policy_lib.tier1_nat_rule.delete(
  267. tier1_id,
  268. nat_rule_id=nat_rule_id2)
  269. expected_body = {"resource_type": "Infra",
  270. "children": [{"Tier1": tier1_dict,
  271. "resource_type": "ChildTier1"}]}
  272. self.assert_infra_patch_call(expected_body)
  273. def test_creating_security_policy_and_dfw_rules(self):
  274. dfw_rule = {'id': 'rule_id1', 'action': 'ALLOW',
  275. 'display_name': 'rule1', 'description': None,
  276. 'direction': 'IN_OUT', 'ip_protocol': 'IPV4_IPV6',
  277. 'logged': False, 'destination_groups': ['destination_url'],
  278. 'source_groups': ['src_url'], 'resource_type': 'Rule',
  279. 'scope': None, 'sequence_number': None, 'tag': None,
  280. 'services': ['ANY']}
  281. security_policy = {'id': 'security_policy_id1',
  282. 'display_name': 'security_policy',
  283. 'category': 'Application',
  284. 'resource_type': 'SecurityPolicy'}
  285. domain = {'resource_type': 'Domain', 'id': 'domain1'}
  286. domain_id = domain['id']
  287. map_id = security_policy['id']
  288. dfw_rule_entries = [self.policy_lib.comm_map.build_entry(
  289. name=dfw_rule['display_name'],
  290. domain_id=domain_id,
  291. map_id=map_id,
  292. entry_id=dfw_rule['id'],
  293. source_groups=dfw_rule['source_groups'],
  294. dest_groups=dfw_rule['destination_groups']
  295. )]
  296. with trans.NsxPolicyTransaction():
  297. self.policy_lib.comm_map.create_with_entries(
  298. name=security_policy['display_name'],
  299. domain_id=domain_id,
  300. map_id=map_id,
  301. entries=dfw_rule_entries
  302. )
  303. def get_group_path(group_id, domain_id):
  304. return '/infra/domains/' + domain_id + '/groups/' + group_id
  305. dfw_rule['destination_groups'] = [get_group_path(group_id, domain_id)
  306. for group_id in
  307. dfw_rule['destination_groups']]
  308. dfw_rule['source_groups'] = [get_group_path(group_id, domain_id) for
  309. group_id in dfw_rule['source_groups']]
  310. child_rules = [{'resource_type': 'ChildRule', 'Rule': dfw_rule}]
  311. security_policy.update({'children': child_rules})
  312. child_security_policies = [{
  313. 'resource_type': 'ChildSecurityPolicy',
  314. 'SecurityPolicy': security_policy
  315. }]
  316. domain.update({'children': child_security_policies})
  317. child_domains = [{'resource_type': 'ChildDomain',
  318. 'Domain': domain}]
  319. expected_body = {'resource_type': 'Infra',
  320. 'children': child_domains}
  321. self.assert_infra_patch_call(expected_body)
  322. @mock.patch('vmware_nsxlib.v3.policy.core_defs.NsxPolicyApi.get')
  323. def test_updating_security_policy_and_dfw_rules(self, mock_get_api):
  324. dfw_rule1 = {'id': 'rule_id1', 'action': 'ALLOW',
  325. 'display_name': 'rule1', 'description': None,
  326. 'direction': 'IN_OUT', 'ip_protocol': 'IPV4_IPV6',
  327. 'logged': False,
  328. 'destination_groups': ['destination_url'],
  329. 'source_groups': ['src_url'], 'resource_type': 'Rule',
  330. 'scope': None, 'sequence_number': None, 'tag': None,
  331. 'services': ['ANY'], "_create_time": 1}
  332. dfw_rule2 = {'id': 'rule_id2', 'action': 'DROP',
  333. 'display_name': 'rule2', 'description': None,
  334. 'direction': 'IN_OUT', 'ip_protocol': 'IPV4_IPV6',
  335. 'logged': False,
  336. 'destination_groups': ['destination_url'],
  337. 'source_groups': ['src_url'], 'resource_type': 'Rule',
  338. 'scope': None, 'sequence_number': None, 'tag': None,
  339. 'services': ['ANY'], "_create_time": 1}
  340. security_policy = {'id': 'security_policy_id1',
  341. 'display_name': 'security_policy',
  342. 'category': 'Application',
  343. 'resource_type': 'SecurityPolicy'}
  344. domain = {'resource_type': 'Domain', 'id': 'domain1'}
  345. domain_id = domain['id']
  346. map_id = security_policy['id']
  347. new_rule_name = 'new_rule1'
  348. new_direction = 'IN'
  349. dfw_rule_entries = [self.policy_lib.comm_map.build_entry(
  350. name=new_rule_name,
  351. domain_id=domain_id,
  352. map_id=map_id,
  353. entry_id=dfw_rule1['id'],
  354. source_groups=dfw_rule1['source_groups'],
  355. dest_groups=dfw_rule1['destination_groups'],
  356. direction=new_direction
  357. )]
  358. def get_group_path(group_id, domain_id):
  359. return '/infra/domains/' + domain_id + '/groups/' + group_id
  360. for dfw_rule in [dfw_rule1, dfw_rule2]:
  361. dfw_rule['destination_groups'] = [get_group_path(group_id,
  362. domain_id)
  363. for group_id in
  364. dfw_rule['destination_groups']]
  365. dfw_rule['source_groups'] = [get_group_path(group_id, domain_id)
  366. for group_id in
  367. dfw_rule['source_groups']]
  368. security_policy_values = copy.deepcopy(security_policy)
  369. security_policy_values.update({'rules':
  370. copy.deepcopy([dfw_rule1, dfw_rule2])})
  371. mock_get_api.return_value = security_policy_values
  372. with trans.NsxPolicyTransaction():
  373. self.policy_lib.comm_map.update_with_entries(
  374. name=security_policy['display_name'],
  375. domain_id=domain_id,
  376. map_id=map_id,
  377. entries=dfw_rule_entries
  378. )
  379. dfw_rule1['display_name'] = new_rule_name
  380. dfw_rule1['direction'] = new_direction
  381. child_rules = [{'resource_type': 'ChildRule', 'Rule': dfw_rule1},
  382. {'resource_type': 'ChildRule', 'Rule': dfw_rule2,
  383. 'marked_for_delete': True}]
  384. security_policy.update({'children': child_rules})
  385. child_security_policies = [{
  386. 'resource_type': 'ChildSecurityPolicy',
  387. 'SecurityPolicy': security_policy
  388. }]
  389. domain.update({'children': child_security_policies})
  390. child_domains = [{
  391. 'resource_type': 'ChildDomain',
  392. 'Domain': domain
  393. }]
  394. expected_body = {'resource_type': 'Infra',
  395. 'children': child_domains}
  396. self.assert_infra_patch_call(expected_body)
  397. @mock.patch('vmware_nsxlib.v3.policy.core_defs.NsxPolicyApi.get')
  398. def test_updating_security_policy_with_no_entries_set(self, mock_get_api):
  399. dfw_rule1 = {'id': 'rule_id1', 'action': 'ALLOW',
  400. 'display_name': 'rule1', 'description': None,
  401. 'direction': 'IN_OUT', 'ip_protocol': 'IPV4_IPV6',
  402. 'logged': False,
  403. 'destination_groups': ['destination_url'],
  404. 'source_groups': ['src_url'], 'resource_type': 'Rule',
  405. 'scope': None, 'sequence_number': None, 'tag': None,
  406. 'services': ['ANY'], "_create_time": 1}
  407. security_policy = {'id': 'security_policy_id1',
  408. 'display_name': 'security_policy',
  409. 'category': 'Application',
  410. 'resource_type': 'SecurityPolicy'}
  411. domain = {'resource_type': 'Domain', 'id': 'domain1'}
  412. domain_id = domain['id']
  413. map_id = security_policy['id']
  414. def get_group_path(group_id, domain_id):
  415. return '/infra/domains/' + domain_id + '/groups/' + group_id
  416. for dfw_rule in [dfw_rule1]:
  417. dfw_rule['destination_groups'] = [get_group_path(group_id,
  418. domain_id)
  419. for group_id in
  420. dfw_rule['destination_groups']]
  421. dfw_rule['source_groups'] = [get_group_path(group_id, domain_id)
  422. for group_id in
  423. dfw_rule['source_groups']]
  424. security_policy.update({'rules': [dfw_rule1]})
  425. mock_get_api.return_value = security_policy
  426. with trans.NsxPolicyTransaction():
  427. self.policy_lib.comm_map.update_with_entries(
  428. name=security_policy['display_name'],
  429. domain_id=domain_id,
  430. map_id=map_id
  431. )
  432. child_security_policies = [{
  433. 'resource_type': 'ChildSecurityPolicy',
  434. 'SecurityPolicy': security_policy
  435. }]
  436. domain.update({'children': child_security_policies})
  437. child_domains = [{
  438. 'resource_type': 'ChildDomain',
  439. 'Domain': domain
  440. }]
  441. expected_body = {'resource_type': 'Infra',
  442. 'children': child_domains}
  443. self.assert_infra_patch_call(expected_body)