diff --git a/vmware_nsxlib/tests/unit/v3/test_policy_api.py b/vmware_nsxlib/tests/unit/v3/test_policy_api.py index 35cd5b8a..a881974d 100644 --- a/vmware_nsxlib/tests/unit/v3/test_policy_api.py +++ b/vmware_nsxlib/tests/unit/v3/test_policy_api.py @@ -18,14 +18,14 @@ from vmware_nsxlib.v3 import client from vmware_nsxlib.v3 import policy_constants from vmware_nsxlib.v3 import policy_defs as policy -BASE_POLICY_URI = "https://1.2.3.4/api/v1/" +BASE_POLICY_URI = "https://1.2.3.4/policy/api/v1/" class TestPolicyApi(nsxlib_testcase.NsxClientTestCase): def setUp(self): self.client = self.new_mocked_client(client.NSX3Client, - url_prefix='api/v1/') + url_prefix='policy/api/v1/') self.policy_api = policy.NsxPolicyApi(self.client) super(TestPolicyApi, self).setUp() @@ -43,8 +43,8 @@ class TestPolicyDomain(TestPolicyApi): 'archaea', 'prokaryotic cells', 'typically characterized by membrane lipids') - self.policy_api.create(domain_def) - self.assert_json_call('PUT', self.client, + self.policy_api.create_or_update(domain_def) + self.assert_json_call('POST', self.client, 'infra/domains/archaea', data=domain_def.get_obj_dict()) @@ -73,8 +73,8 @@ class TestPolicyGroup(TestPolicyApi): 'eukarya', 'cats', 'felis catus') - self.policy_api.create(group_def) - self.assert_json_call('PUT', self.client, + self.policy_api.create_or_update(group_def) + self.assert_json_call('POST', self.client, 'infra/domains/eukarya/groups/cats', data=group_def.get_obj_dict()) @@ -89,7 +89,7 @@ class TestPolicyGroup(TestPolicyApi): self.policy_api.create_with_parent(domain_def, group_def) data = domain_def.get_obj_dict() data['groups'] = [group_def.get_obj_dict()] - self.assert_json_call('PUT', self.client, + self.assert_json_call('POST', self.client, 'infra/domains/eukarya', data=data) @@ -110,14 +110,12 @@ class TestPolicyGroup(TestPolicyApi): expected_group = {'id': 'dogs', 'display_name': None, 'description': None, - 'expression': [expected_condition], - '_revision': 0} + 'expression': [expected_condition]} expected_data = {'id': 'eukarya', 'display_name': None, 'description': None, - 'groups': [expected_group], - '_revision': 0} - self.assert_json_call('PUT', self.client, + 'groups': [expected_group]} + self.assert_json_call('POST', self.client, 'infra/domains/eukarya', data=expected_data) @@ -134,7 +132,7 @@ class TestPolicyGroup(TestPolicyApi): self.policy_api.create_with_parent(domain_def, group_def) data = domain_def.get_obj_dict() data['groups'] = [group_def.get_obj_dict()] - self.assert_json_call('PUT', self.client, + self.assert_json_call('POST', self.client, 'infra/domains/eukarya', data=data) @@ -149,8 +147,8 @@ class TestPolicyService(TestPolicyApi): def test_create(self): service_def = policy.ServiceDef('roomservice') - self.policy_api.create(service_def) - self.assert_json_call('PUT', self.client, + self.policy_api.create_or_update(service_def) + self.assert_json_call('POST', self.client, 'infra/services/roomservice', data=service_def.get_obj_dict()) @@ -167,14 +165,12 @@ class TestPolicyService(TestPolicyApi): 'display_name': 'room http', 'description': None, 'l4_protocol': 'TCP', - 'destination_ports': [80, 8080], - '_revision': 0} + 'destination_ports': [80, 8080]} expected_data = {'id': 'roomservice', 'display_name': None, 'description': None, - 'service_entries': [expected_entry], - '_revision': 0} - self.assert_json_call('PUT', self.client, + 'service_entries': [expected_entry]} + self.assert_json_call('POST', self.client, 'infra/services/roomservice', data=expected_data) @@ -183,8 +179,8 @@ class TestPolicyCommunicationProfile(TestPolicyApi): def test_create(self): profile_def = policy.CommunicationProfileDef('rental') - self.policy_api.create(profile_def) - self.assert_json_call('PUT', self.client, + self.policy_api.create_or_update(profile_def) + self.assert_json_call('POST', self.client, 'infra/communication-profiles/rental', data=profile_def.get_obj_dict()) @@ -201,14 +197,12 @@ class TestPolicyCommunicationProfile(TestPolicyApi): 'display_name': None, 'description': 'includes roomservice', 'services': ["roomservice"], - 'action': 'ALLOW', - '_revision': 0} + 'action': 'ALLOW'} expected_data = {'id': 'rental', 'display_name': None, 'description': None, - 'communication_profile_entries': [expected_entry], - '_revision': 0} - self.assert_json_call('PUT', self.client, + 'communication_profile_entries': [expected_entry]} + self.assert_json_call('POST', self.client, 'infra/communication-profiles/rental', data=expected_data) @@ -233,8 +227,7 @@ class TestPolicyCommunicationMap(TestPolicyApi): dest_groups=["group3"], profile_id="profile2") - self.expected_data1 = {'_revision': 0, - 'id': 'cm1', + self.expected_data1 = {'id': 'cm1', 'display_name': None, 'description': None, 'sequence_number': 12, @@ -246,8 +239,7 @@ class TestPolicyCommunicationMap(TestPolicyApi): 'communication_profile_path': '/infra/communication-profiles/profile1'} - self.expected_data2 = {'_revision': 0, - 'id': 'cm2', + self.expected_data2 = {'id': 'cm2', 'display_name': None, 'description': None, 'sequence_number': 13, @@ -265,7 +257,7 @@ class TestPolicyCommunicationMap(TestPolicyApi): self.policy_api.create_with_parent(map_def, self.entry1) expected_data = map_def.get_obj_dict() expected_data['communication_entries'] = [self.expected_data1] - self.assert_json_call('PUT', self.client, + self.assert_json_call('POST', self.client, 'infra/domains/d1/communication-map', data=expected_data) @@ -277,14 +269,14 @@ class TestPolicyCommunicationMap(TestPolicyApi): expected_data = map_def.get_obj_dict() expected_data['communication_entries'] = [self.expected_data1, self.expected_data2] - self.assert_json_call('PUT', self.client, + self.assert_json_call('POST', self.client, 'infra/domains/d1/communication-map', data=expected_data) def test_update_entry(self): - self.policy_api.create(self.entry1) + self.policy_api.create_or_update(self.entry1) - self.assert_json_call('PUT', self.client, + self.assert_json_call('POST', self.client, 'infra/domains/d1/communication-map/' 'communication-entries/cm1', data=self.expected_data1) @@ -305,9 +297,9 @@ class TestPolicyEnforcementPoint(TestPolicyApi): username='admin', password='a') - self.policy_api.create(ep_def) + self.policy_api.create_or_update(ep_def) ep_path = policy.EnforcementPointDef('ep1').get_resource_path() - self.assert_json_call('PUT', self.client, + self.assert_json_call('POST', self.client, ep_path, data=ep_def.get_obj_dict()) @@ -317,15 +309,14 @@ class TestPolicyDeploymentMap(TestPolicyApi): def test_create(self): map_def = policy.DeploymentMapDef('dm1', domain_id='d1', ep_id='ep1') - self.policy_api.create(map_def) + self.policy_api.create_or_update(map_def) ep_path = policy.EnforcementPointDef('ep1').get_resource_full_path() - expected_data = {'_revision': 0, - 'id': 'dm1', + expected_data = {'id': 'dm1', 'display_name': None, 'description': None, 'domain_path': '/infra/domains/d1', 'enforcement_point_paths': [ep_path]} - self.assert_json_call('PUT', self.client, + self.assert_json_call('POST', self.client, 'infra/domaindeploymentmap/dm1', data=expected_data) diff --git a/vmware_nsxlib/tests/unit/v3/test_policy_resources.py b/vmware_nsxlib/tests/unit/v3/test_policy_resources.py index e4f1ea25..d0148ba8 100644 --- a/vmware_nsxlib/tests/unit/v3/test_policy_resources.py +++ b/vmware_nsxlib/tests/unit/v3/test_policy_resources.py @@ -82,11 +82,12 @@ class TestPolicyDomain(NsxPolicyLibTestCase): name = 'd1' description = 'desc' id = '111' - with mock.patch.object(self.policy_api, "create") as api_call: - self.resourceApi.create(name, - domain_id=id, - description=description, - tenant=TEST_TENANT) + with mock.patch.object(self.policy_api, + "create_or_update") as api_call: + self.resourceApi.create_or_overwrite(name, + domain_id=id, + description=description, + tenant=TEST_TENANT) expected_def = policy_defs.DomainDef(domain_id=id, name=name, description=description, @@ -96,9 +97,10 @@ class TestPolicyDomain(NsxPolicyLibTestCase): def test_create_without_id(self): name = 'd1' description = 'desc' - with mock.patch.object(self.policy_api, "create") as api_call: - self.resourceApi.create(name, description=description, - tenant=TEST_TENANT) + with mock.patch.object(self.policy_api, + "create_or_update") as api_call: + self.resourceApi.create_or_overwrite(name, description=description, + tenant=TEST_TENANT) expected_def = policy_defs.DomainDef(domain_id=mock.ANY, name=name, description=description, @@ -141,9 +143,8 @@ class TestPolicyDomain(NsxPolicyLibTestCase): id = '111' name = 'new name' description = 'new desc' - with mock.patch.object(self.policy_api, "get", - return_value={}) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + with mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update(id, name=name, description=description, @@ -152,7 +153,6 @@ class TestPolicyDomain(NsxPolicyLibTestCase): tenant=TEST_TENANT) expected_dict = {'display_name': name, 'description': description} - self.assert_called_with_def(get_call, expected_def) self.assert_called_with_def_and_dict( update_call, expected_def, expected_dict) @@ -168,12 +168,13 @@ class TestPolicyGroup(NsxPolicyLibTestCase): name = 'g1' description = 'desc' id = '222' - with mock.patch.object(self.policy_api, "create") as api_call: - self.resourceApi.create(name, - domain_id, - group_id=id, - description=description, - tenant=TEST_TENANT) + with mock.patch.object(self.policy_api, + "create_or_update") as api_call: + self.resourceApi.create_or_overwrite(name, + domain_id, + group_id=id, + description=description, + tenant=TEST_TENANT) expected_def = policy_defs.GroupDef(domain_id=domain_id, group_id=id, name=name, @@ -186,9 +187,11 @@ class TestPolicyGroup(NsxPolicyLibTestCase): domain_id = '111' name = 'g1' description = 'desc' - with mock.patch.object(self.policy_api, "create") as api_call: - self.resourceApi.create(name, domain_id, description=description, - tenant=TEST_TENANT) + with mock.patch.object(self.policy_api, + "create_or_update") as api_call: + self.resourceApi.create_or_overwrite(name, domain_id, + description=description, + tenant=TEST_TENANT) expected_def = policy_defs.GroupDef(domain_id=domain_id, group_id=mock.ANY, name=name, @@ -205,8 +208,9 @@ class TestPolicyGroup(NsxPolicyLibTestCase): cond_op = policy_constants.CONDITION_OP_EQUALS cond_member_type = policy_constants.CONDITION_MEMBER_NET cond_key = policy_constants.CONDITION_KEY_TAG - with mock.patch.object(self.policy_api, "create") as api_call: - self.resourceApi.create( + with mock.patch.object(self.policy_api, + "create_or_update") as api_call: + self.resourceApi.create_or_overwrite( name, domain_id, description=description, cond_val=cond_val, cond_op=cond_op, @@ -270,9 +274,8 @@ class TestPolicyGroup(NsxPolicyLibTestCase): id = '222' name = 'new name' description = 'new desc' - with mock.patch.object(self.policy_api, "get", - return_value={}) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + with mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update(domain_id, id, name=name, description=description, @@ -282,7 +285,6 @@ class TestPolicyGroup(NsxPolicyLibTestCase): tenant=TEST_TENANT) expected_dict = {'display_name': name, 'description': description} - self.assert_called_with_def(get_call, expected_def) self.assert_called_with_def_and_dict( update_call, expected_def, expected_dict) @@ -292,7 +294,8 @@ class TestPolicyGroup(NsxPolicyLibTestCase): cond_val = '123' with mock.patch.object(self.policy_api, "get", return_value={}) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update_condition(domain_id, id, cond_val=cond_val, tenant=TEST_TENANT) @@ -319,7 +322,8 @@ class TestPolicyGroup(NsxPolicyLibTestCase): 'operator': policy_constants.CONDITION_OP_EQUALS} with mock.patch.object(self.policy_api, "get", return_value={'expression': [old_cond]}) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update_condition(domain_id, id, cond_val=None, tenant=TEST_TENANT) @@ -345,9 +349,11 @@ class TestPolicyService(NsxPolicyLibTestCase): dest_ports = [81, 82] with mock.patch.object(self.policy_api, "create_with_parent") as api_call: - self.resourceApi.create(name, description=description, - protocol=protocol, dest_ports=dest_ports, - tenant=TEST_TENANT) + self.resourceApi.create_or_overwrite(name, + description=description, + protocol=protocol, + dest_ports=dest_ports, + tenant=TEST_TENANT) exp_srv_def = policy_defs.ServiceDef(service_id=mock.ANY, name=name, description=description, @@ -400,7 +406,8 @@ class TestPolicyService(NsxPolicyLibTestCase): description = 'new desc' with mock.patch.object(self.policy_api, "get", return_value={}) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update(id, name=name, description=description, @@ -424,7 +431,8 @@ class TestPolicyService(NsxPolicyLibTestCase): with mock.patch.object( self.policy_api, "get", return_value={'service_entries': [service_entry]}) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update(id, protocol=protocol, dest_ports=dest_ports, @@ -457,7 +465,8 @@ class TestPolicyService(NsxPolicyLibTestCase): with mock.patch.object( self.policy_api, "get", return_value={'service_entries': [service_entry]}) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call,\ + mock.patch.object(self.policy_api, + "create_or_update") as update_call,\ mock.patch.object(self.policy_api, "list", return_value={'results': []}): self.resourceApi.update(id, @@ -474,7 +483,7 @@ class TestPolicyService(NsxPolicyLibTestCase): # update will be called for the service and entry (2 calls) expected_dict = {'display_name': name, 'description': description, - 'service_entries': [service_entry]} + 'service_entries': []} self.assert_called_with_def_and_dict( update_call, expected_def, expected_dict) @@ -505,9 +514,10 @@ class TestPolicyCommunicationProfile(NsxPolicyLibTestCase): action = 'DENY' with mock.patch.object(self.policy_api, "create_with_parent") as api_call: - self.resourceApi.create(name, description=description, - services=[service_id], action=action, - tenant=TEST_TENANT) + self.resourceApi.create_or_overwrite(name, description=description, + services=[service_id], + action=action, + tenant=TEST_TENANT) exp_srv_def = policy_defs.CommunicationProfileDef( profile_id=mock.ANY, name=name, @@ -563,7 +573,8 @@ class TestPolicyCommunicationProfile(NsxPolicyLibTestCase): description = 'new desc' with mock.patch.object(self.policy_api, "get", return_value={}) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update(id, name=name, description=description, @@ -587,7 +598,8 @@ class TestPolicyCommunicationProfile(NsxPolicyLibTestCase): with mock.patch.object( self.policy_api, "get", return_value=entries_dict) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update(id, services=[service_id], action=action, @@ -620,7 +632,8 @@ class TestPolicyCommunicationProfile(NsxPolicyLibTestCase): with mock.patch.object( self.policy_api, "get", return_value=entries_dict) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update(id, name=name, description=description, @@ -635,7 +648,7 @@ class TestPolicyCommunicationProfile(NsxPolicyLibTestCase): # update will be called for the service and entry (2 calls) expected_dict = {'display_name': name, 'description': description, - 'communication_profile_entries': [profile_entry]} + 'communication_profile_entries': []} self.assert_called_with_def_and_dict( update_call, expected_def, expected_dict) @@ -668,15 +681,17 @@ class TestPolicyCommunicationMap(NsxPolicyLibTestCase): seq_num = 7 profile_id = 'c1' list_return_value = {'results': [{'sequence_number': 1}]} - with mock.patch.object(self.policy_api, "create") as api_call,\ + with mock.patch.object(self.policy_api, + "create_or_update") as api_call,\ mock.patch.object(self.policy_api, "list", return_value=list_return_value): - self.resourceApi.create(name, domain_id, description=description, - sequence_number=seq_num, - profile_id=profile_id, - source_groups=[source_group], - dest_groups=[dest_group], - tenant=TEST_TENANT) + self.resourceApi.create_or_overwrite(name, domain_id, + description=description, + sequence_number=seq_num, + profile_id=profile_id, + source_groups=[source_group], + dest_groups=[dest_group], + tenant=TEST_TENANT) expected_def = policy_defs.CommunicationMapEntryDef( domain_id=domain_id, map_id=mock.ANY, @@ -689,6 +704,36 @@ class TestPolicyCommunicationMap(NsxPolicyLibTestCase): tenant=TEST_TENANT) self.assert_called_with_def(api_call, expected_def) + def test_create_first_seqnum(self): + domain_id = '111' + name = 'cm1' + description = 'desc' + source_group = 'g1' + dest_group = 'g2' + profile_id = 'c1' + with mock.patch.object(self.policy_api, + "create_or_update") as api_call, \ + mock.patch.object(self.resourceApi, "list", return_value=[]): + self.resourceApi.create_or_overwrite(name, domain_id, + description=description, + profile_id=profile_id, + source_groups=[source_group], + dest_groups=[dest_group], + tenant=TEST_TENANT) + + expected_def = policy_defs.CommunicationMapEntryDef( + domain_id=domain_id, + map_id=mock.ANY, + name=name, + description=description, + sequence_number=1, + profile_id=profile_id, + source_groups=[source_group], + dest_groups=[dest_group], + tenant=TEST_TENANT) + + self.assert_called_with_def(api_call, expected_def) + def test_create_without_seqnum(self): domain_id = '111' name = 'cm1' @@ -698,12 +743,14 @@ class TestPolicyCommunicationMap(NsxPolicyLibTestCase): profile_id = 'c1' with mock.patch.object(self.policy_api, "create_with_parent") as api_call, \ - mock.patch.object(self.resourceApi, "list", return_value=[]): - self.resourceApi.create(name, domain_id, description=description, - profile_id=profile_id, - source_groups=[source_group], - dest_groups=[dest_group], - tenant=TEST_TENANT) + mock.patch.object(self.resourceApi, "_get_last_seq_num", + return_value=-1): + self.resourceApi.create_or_overwrite(name, domain_id, + description=description, + profile_id=profile_id, + source_groups=[source_group], + dest_groups=[dest_group], + tenant=TEST_TENANT) expected_map_def = policy_defs.CommunicationMapDef( domain_id=domain_id, @@ -755,16 +802,18 @@ class TestPolicyCommunicationMap(NsxPolicyLibTestCase): obj = self.resourceApi.get_by_name(domain_id, name, tenant=TEST_TENANT) self.assertIsNotNone(obj) - expected_def = policy_defs.CommunicationMapDef(domain_id, - tenant=TEST_TENANT) + expected_def = policy_defs.CommunicationMapEntryDef( + domain_id, + tenant=TEST_TENANT) self.assert_called_with_def(api_call, expected_def) def test_list(self): domain_id = '111' with mock.patch.object(self.policy_api, "list") as api_call: self.resourceApi.list(domain_id, tenant=TEST_TENANT) - expected_def = policy_defs.CommunicationMapDef(domain_id=domain_id, - tenant=TEST_TENANT) + expected_def = policy_defs.CommunicationMapEntryDef( + domain_id=domain_id, + tenant=TEST_TENANT) self.assert_called_with_def(api_call, expected_def) def test_update(self): @@ -777,7 +826,8 @@ class TestPolicyCommunicationMap(NsxPolicyLibTestCase): profile_id = 'nc1' with mock.patch.object(self.policy_api, "get", return_value={}) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update(domain_id, id, name=name, description=description, @@ -817,12 +867,15 @@ class TestPolicyEnforcementPoint(NsxPolicyLibTestCase): ip_address = '1.1.1.1' username = 'admin' password = 'zzz' - with mock.patch.object(self.policy_api, "create") as api_call: - self.resourceApi.create(name, description=description, - ip_address=ip_address, - username=username, - password=password, - tenant=TEST_TENANT) + with mock.patch.object(self.policy_api, + "create_or_update") as api_call: + self.resourceApi.create_or_overwrite( + name, description=description, + ip_address=ip_address, + username=username, + password=password, + tenant=TEST_TENANT) + expected_def = policy_defs.EnforcementPointDef( ep_id=mock.ANY, name=name, @@ -870,9 +923,8 @@ class TestPolicyEnforcementPoint(NsxPolicyLibTestCase): name = 'new name' username = 'admin' password = 'zzz' - with mock.patch.object(self.policy_api, "get", - return_value={}) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + with mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update(id, name=name, username=username, @@ -883,7 +935,6 @@ class TestPolicyEnforcementPoint(NsxPolicyLibTestCase): expected_dict = {'display_name': name, 'username': username, 'password': password} - self.assert_called_with_def(get_call, expected_def) self.assert_called_with_def_and_dict( update_call, expected_def, expected_dict) @@ -899,11 +950,13 @@ class TestPolicyDeploymentMap(NsxPolicyLibTestCase): description = 'desc' domain_id = 'domain1' ep_id = 'ep1' - with mock.patch.object(self.policy_api, "create") as api_call: - self.resourceApi.create(name, description=description, - ep_id=ep_id, - domain_id=domain_id, - tenant=TEST_TENANT) + with mock.patch.object(self.policy_api, + "create_or_update") as api_call: + self.resourceApi.create_or_overwrite(name, + description=description, + ep_id=ep_id, + domain_id=domain_id, + tenant=TEST_TENANT) expected_def = policy_defs.DeploymentMapDef( map_id=mock.ANY, name=name, @@ -950,9 +1003,8 @@ class TestPolicyDeploymentMap(NsxPolicyLibTestCase): name = 'new name' domain_id = 'domain2' ep_id = 'ep2' - with mock.patch.object(self.policy_api, "get", - return_value={}) as get_call,\ - mock.patch.object(self.policy_api, "update") as update_call: + with mock.patch.object(self.policy_api, + "create_or_update") as update_call: self.resourceApi.update(id, name=name, ep_id=ep_id, @@ -966,6 +1018,5 @@ class TestPolicyDeploymentMap(NsxPolicyLibTestCase): expected_dict = {'display_name': name, 'enforcement_point_paths': [ep_path], 'domain_path': domain_path} - self.assert_called_with_def(get_call, expected_def) self.assert_called_with_def_and_dict( update_call, expected_def, expected_dict) diff --git a/vmware_nsxlib/v3/__init__.py b/vmware_nsxlib/v3/__init__.py index faf06d71..2b0b4865 100644 --- a/vmware_nsxlib/v3/__init__.py +++ b/vmware_nsxlib/v3/__init__.py @@ -49,7 +49,8 @@ class NsxLibBase(object): self.client = client.NSX3Client( self.cluster, nsx_api_managers=self.nsxlib_config.nsx_api_managers, - max_attempts=self.nsxlib_config.max_attempts) + max_attempts=self.nsxlib_config.max_attempts, + url_path_base=self.client_url_prefix) self.general_apis = utils.NsxLibApiBase( self.client, self.nsxlib_config) @@ -63,7 +64,12 @@ class NsxLibBase(object): def set_config(self, nsxlib_config): """Set config user provided and extend it according to application""" self.nsxlib_config = nsxlib_config - self.nsxlib_config.extend(keepalive_section=self.keepalive_section) + self.nsxlib_config.extend(keepalive_section=self.keepalive_section, + url_base=self.client_url_prefix) + + @abc.abstractproperty + def client_url_prefix(self): + pass @abc.abstractproperty def keepalive_section(self): @@ -202,6 +208,10 @@ class NsxLib(NsxLibBase): return False + @property + def client_url_prefix(self): + return client.NSX3Client.NSX_V1_API_PREFIX + class NsxPolicyLib(NsxLibBase): @@ -231,3 +241,7 @@ class NsxPolicyLib(NsxLibBase): return True return False + + @property + def client_url_prefix(self): + return client.NSX3Client.NSX_POLICY_V1_API_PREFIX diff --git a/vmware_nsxlib/v3/client.py b/vmware_nsxlib/v3/client.py index 69122fa1..51339559 100644 --- a/vmware_nsxlib/v3/client.py +++ b/vmware_nsxlib/v3/client.py @@ -226,13 +226,15 @@ class JSONRESTClient(RESTClient): class NSX3Client(JSONRESTClient): - _NSX_V1_API_PREFIX = 'api/v1/' + NSX_V1_API_PREFIX = 'api/v1/' + NSX_POLICY_V1_API_PREFIX = 'policy/api/v1/' def __init__(self, connection, url_prefix=None, default_headers=None, nsx_api_managers=None, max_attempts=utils.DEFAULT_MAX_ATTEMPTS, - client_obj=None): + client_obj=None, + url_path_base=NSX_V1_API_PREFIX): # If the client obj is defined - copy configuration from it if client_obj: @@ -242,12 +244,12 @@ class NSX3Client(JSONRESTClient): self.nsx_api_managers = nsx_api_managers or [] self.max_attempts = max_attempts - url_prefix = url_prefix or NSX3Client._NSX_V1_API_PREFIX - if url_prefix and NSX3Client._NSX_V1_API_PREFIX not in url_prefix: + url_prefix = url_prefix or url_path_base + if url_prefix and url_path_base not in url_prefix: if url_prefix.startswith('http'): - url_prefix += '/' + NSX3Client._NSX_V1_API_PREFIX + url_prefix += '/' + url_path_base else: - url_prefix = "%s/%s" % (NSX3Client._NSX_V1_API_PREFIX, + url_prefix = "%s/%s" % (url_path_base, url_prefix or '') self.max_attempts = max_attempts diff --git a/vmware_nsxlib/v3/cluster.py b/vmware_nsxlib/v3/cluster.py index 4cdc0463..1aac871d 100644 --- a/vmware_nsxlib/v3/cluster.py +++ b/vmware_nsxlib/v3/cluster.py @@ -150,7 +150,9 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider): return "%s-%s" % (requests.__title__, requests.__version__) def validate_connection(self, cluster_api, endpoint, conn): - client = nsx_client.NSX3Client(conn, url_prefix=endpoint.provider.url) + client = nsx_client.NSX3Client( + conn, url_prefix=endpoint.provider.url, + url_path_base=cluster_api.nsxlib_config.url_base) keepalive_section = cluster_api.nsxlib_config.keepalive_section result = client.get(keepalive_section, silent=True) # If keeplive section returns a list, it is assumed to be non-empty diff --git a/vmware_nsxlib/v3/config.py b/vmware_nsxlib/v3/config.py index 9fa1d417..47a754ec 100644 --- a/vmware_nsxlib/v3/config.py +++ b/vmware_nsxlib/v3/config.py @@ -118,9 +118,10 @@ class NsxLibConfig(object): 'dhcp_profile_uuid is not used by the nsxlib, and will ' 'be removed from its configuration in the future.') - def extend(self, keepalive_section): + def extend(self, keepalive_section, url_base=None): """Called by library code to initialize application-specific data""" self.keepalive_section = keepalive_section + self.url_base = url_base def _attribute_by_index(self, scalar_or_list, index): if isinstance(scalar_or_list, list): diff --git a/vmware_nsxlib/v3/policy_defs.py b/vmware_nsxlib/v3/policy_defs.py index b5e4482f..d1379b78 100644 --- a/vmware_nsxlib/v3/policy_defs.py +++ b/vmware_nsxlib/v3/policy_defs.py @@ -36,8 +36,7 @@ class ResourceDef(object): self.body = {} def get_obj_dict(self): - body = {'_revision': 0, - 'display_name': self.name, + body = {'display_name': self.name, 'description': self.description} if self.id: body['id'] = self.id @@ -67,9 +66,20 @@ class ResourceDef(object): def sub_entries_path(): pass - def update_attributes_in_body(self, body, **kwargs): - self.body = body + def _get_body_from_kwargs(self, **kwargs): + if 'body' in kwargs: + body = kwargs['body'] + else: + body = {} + return body + + def update_attributes_in_body(self, **kwargs): + self.body = self._get_body_from_kwargs(**kwargs) + if 'body' in kwargs: + del kwargs['body'] for key, value in six.iteritems(kwargs): + if key == 'body': + continue if value is not None: if key == 'name': self.body['display_name'] = value @@ -164,13 +174,16 @@ class GroupDef(ResourceDef): for condition in self.conditions] return body - def update_attributes_in_body(self, body, **kwargs): + def update_attributes_in_body(self, **kwargs): + body = self._get_body_from_kwargs(**kwargs) + if 'body' in kwargs: + del kwargs['body'] # Fix params that need special conversions if kwargs.get('conditions') is not None: body['expression'] = [cond.get_obj_dict() for cond in kwargs['conditions']] del kwargs['conditions'] - super(GroupDef, self).update_attributes_in_body(body, **kwargs) + super(GroupDef, self).update_attributes_in_body(body=body, **kwargs) class ServiceDef(ResourceDef): @@ -231,8 +244,12 @@ class L4ServiceEntryDef(ResourceDef): body['destination_ports'] = self.dest_ports return body - def update_attributes_in_body(self, body, **kwargs): + def update_attributes_in_body(self, **kwargs): # Fix params that need special conversions + body = self._get_body_from_kwargs(**kwargs) + if 'body' in kwargs: + del kwargs['body'] + if kwargs.get('protocol') is not None: body['l4_protocol'] = kwargs['protocol'].upper() del kwargs['protocol'] @@ -240,7 +257,7 @@ class L4ServiceEntryDef(ResourceDef): body['destination_ports'] = kwargs['dest_ports'] del kwargs['dest_ports'] super(L4ServiceEntryDef, self).update_attributes_in_body( - body, **kwargs) + body=body, **kwargs) class CommunicationProfileDef(ResourceDef): @@ -270,9 +287,9 @@ class CommunicationProfileDef(ResourceDef): entryDef = CommunicationProfileEntryDef() return entryDef.get_last_section_dict_key - def update_attributes_in_body(self, body, **kwargs): + def update_attributes_in_body(self, **kwargs): super(CommunicationProfileDef, self).update_attributes_in_body( - body, **kwargs) + **kwargs) # make sure entries are there entries_path = self.sub_entries_path() if entries_path not in self.body: @@ -307,12 +324,15 @@ class CommunicationProfileEntryDef(ResourceDef): body['action'] = self.action return body - def update_attributes_in_body(self, body, **kwargs): + def update_attributes_in_body(self, **kwargs): + body = self._get_body_from_kwargs(**kwargs) + if 'body' in kwargs: + del kwargs['body'] if kwargs.get('action') is not None: body['action'] = kwargs['action'].upper() del kwargs['action'] super(CommunicationProfileEntryDef, self).update_attributes_in_body( - body, **kwargs) + body=body, **kwargs) class CommunicationMapDef(ResourceDef): @@ -380,7 +400,10 @@ class CommunicationMapEntryDef(ResourceDef): body['communication_profile_path'] = self.profile_path return body - def update_attributes_in_body(self, body, **kwargs): + def update_attributes_in_body(self, **kwargs): + body = self._get_body_from_kwargs(**kwargs) + if 'body' in kwargs: + del kwargs['body'] # Fix params that need special conversions if kwargs.get('profile_id') is not None: profile_path = self.get_profile_path(kwargs['profile_id']) @@ -400,7 +423,7 @@ class CommunicationMapEntryDef(ResourceDef): del kwargs['source_groups'] super(CommunicationMapEntryDef, self).update_attributes_in_body( - body, **kwargs) + body=body, **kwargs) class EnforcementPointDef(ResourceDef): @@ -411,6 +434,7 @@ class EnforcementPointDef(ResourceDef): ip_address=None, username=None, password=None, + thumbprint=None, ep_type='NSXT', tenant=policy_constants.POLICY_INFRA_TENANT): super(EnforcementPointDef, self).__init__() @@ -422,6 +446,7 @@ class EnforcementPointDef(ResourceDef): self.username = username self.password = password self.ip_address = ip_address + self.thumbprint = thumbprint self.parent_ids = (tenant) @property @@ -433,8 +458,7 @@ class EnforcementPointDef(ResourceDef): body = super(EnforcementPointDef, self).get_obj_dict() body['id'] = self.id body['connection_info'] = [{'fqdn': 'abc', - 'thumbprint': - policy_constants.DEFAULT_THUMBPRINT, + 'thumbprint': self.thumbprint, 'username': self.username, 'password': self.password, 'ip_address': self.ip_address, @@ -443,24 +467,21 @@ class EnforcementPointDef(ResourceDef): body['resource_type'] = 'EnforcementPoint' return body - def update_attributes_in_body(self, body, **kwargs): + def update_attributes_in_body(self, **kwargs): + body = self._get_body_from_kwargs(**kwargs) + if 'body' in kwargs: + del kwargs['body'] # Fix params that need special conversions if body.get('connection_info'): body['connection_info'][0]['resource_type'] = 'NSXTConnectionInfo' - if kwargs.get('username') is not None: - body['connection_info'][0]['username'] = kwargs['username'] - del kwargs['username'] - if kwargs.get('password') is not None: - body['connection_info'][0]['password'] = kwargs['password'] - del kwargs['password'] - - if kwargs.get('ip_address') is not None: - body['connection_info'][0]['ip_address'] = kwargs['ip_address'] - del kwargs['ip_address'] + for attr in ('username', 'password', 'ip_address', 'thumbprint'): + if kwargs.get(attr) is not None: + body['connection_info'][0][attr] = kwargs[attr] + del kwargs[attr] super(EnforcementPointDef, self).update_attributes_in_body( - body, **kwargs) + body=body, **kwargs) # Currently assumes one deployment point per id @@ -497,7 +518,10 @@ class DeploymentMapDef(ResourceDef): body['enforcement_point_paths'] = [self.ep_path] return body - def update_attributes_in_body(self, body, **kwargs): + def update_attributes_in_body(self, **kwargs): + body = self._get_body_from_kwargs(**kwargs) + if 'body' in kwargs: + del kwargs['body'] # Fix params that need special conversions if kwargs.get('domain_id') is not None: domain_id = kwargs.get('domain_id') @@ -514,7 +538,7 @@ class DeploymentMapDef(ResourceDef): del kwargs['ep_id'] super(DeploymentMapDef, self).update_attributes_in_body( - body, **kwargs) + body=body, **kwargs) class NsxPolicyApi(object): @@ -522,9 +546,18 @@ class NsxPolicyApi(object): def __init__(self, client): self.client = client - def create(self, resource_def): + def create_or_update(self, resource_def): + """Create or update a policy object. + + This api will update an existing object, or create a new one if it + doesn't exist. + The policy API supports POST for update too + """ path = resource_def.get_resource_path() - return self.client.update(path, resource_def.get_obj_dict()) + body = resource_def.body + if not body: + body = resource_def.get_obj_dict() + return self.client.create(path, body) def create_with_parent(self, parent_def, resource_def): path = parent_def.get_resource_path() @@ -535,7 +568,7 @@ class NsxPolicyApi(object): else: child_dict_key = resource_def.get_last_section_dict_key body[child_dict_key] = [resource_def.get_obj_dict()] - return self.client.update(path, body) + return self.client.create(path, body) def delete(self, resource_def): path = resource_def.get_resource_path() @@ -548,8 +581,3 @@ class NsxPolicyApi(object): def list(self, resource_def): path = resource_def.get_section_path() return self.client.list(path) - - def update(self, resource_def): - path = resource_def.get_resource_path() - body = resource_def.body - return self.client.update(path, body) diff --git a/vmware_nsxlib/v3/policy_resources.py b/vmware_nsxlib/v3/policy_resources.py index 7f1443aa..5510db46 100644 --- a/vmware_nsxlib/v3/policy_resources.py +++ b/vmware_nsxlib/v3/policy_resources.py @@ -54,7 +54,7 @@ class NsxPolicyResourceBase(object): pass @abc.abstractmethod - def create(self, *args, **kwargs): + def create_or_overwrite(self, *args, **kwargs): pass @abc.abstractmethod @@ -78,14 +78,14 @@ class NsxPolicyResourceBase(object): class NsxPolicyDomainApi(NsxPolicyResourceBase): """NSX Policy Domain.""" - def create(self, name, domain_id=None, description=None, - tenant=policy_constants.POLICY_INFRA_TENANT): + def create_or_overwrite(self, name, domain_id=None, description=None, + tenant=policy_constants.POLICY_INFRA_TENANT): domain_id = self._init_obj_uuid(domain_id) domain_def = policy_defs.DomainDef(domain_id=domain_id, name=name, description=description, tenant=tenant) - return self.policy_api.create(domain_def) + return self.policy_api.create_or_update(domain_def) def delete(self, domain_id, tenant=policy_constants.POLICY_INFRA_TENANT): domain_def = policy_defs.DomainDef(domain_id, tenant=tenant) @@ -103,24 +103,22 @@ class NsxPolicyDomainApi(NsxPolicyResourceBase): tenant=policy_constants.POLICY_INFRA_TENANT): domain_def = policy_defs.DomainDef(domain_id=domain_id, tenant=tenant) - # Get the current data, and update it with the new values - domain = self.get(domain_id, tenant=tenant) - domain_def.update_attributes_in_body(domain, - name=name, + domain_def.update_attributes_in_body(name=name, description=description) # update the backend - return self.policy_api.update(domain_def) + return self.policy_api.create_or_update(domain_def) class NsxPolicyGroupApi(NsxPolicyResourceBase): """NSX Policy Group (under a Domain) with a single condition.""" - def create(self, name, domain_id, group_id=None, - description=None, - cond_val=None, - cond_key=policy_constants.CONDITION_KEY_TAG, - cond_op=policy_constants.CONDITION_OP_EQUALS, - cond_member_type=policy_constants.CONDITION_MEMBER_PORT, - tenant=policy_constants.POLICY_INFRA_TENANT): + def create_or_overwrite( + self, name, domain_id, group_id=None, + description=None, + cond_val=None, + cond_key=policy_constants.CONDITION_KEY_TAG, + cond_op=policy_constants.CONDITION_OP_EQUALS, + cond_member_type=policy_constants.CONDITION_MEMBER_PORT, + tenant=policy_constants.POLICY_INFRA_TENANT): """Create a group with/without a condition. Empty condition value will result a group with no condition. @@ -142,7 +140,7 @@ class NsxPolicyGroupApi(NsxPolicyResourceBase): description=description, conditions=conditions, tenant=tenant) - return self.policy_api.create(group_def) + return self.policy_api.create_or_update(group_def) def delete(self, domain_id, group_id, tenant=policy_constants.POLICY_INFRA_TENANT): @@ -180,12 +178,10 @@ class NsxPolicyGroupApi(NsxPolicyResourceBase): group_def = policy_defs.GroupDef(domain_id=domain_id, group_id=group_id, tenant=tenant) - # Get the current data, and update it with the new values - group = self.get(domain_id, group_id, tenant=tenant) - group_def.update_attributes_in_body(group, name=name, + group_def.update_attributes_in_body(name=name, description=description) # update the backend - return self.policy_api.update(group_def) + return self.policy_api.create_or_update(group_def) def update_condition( self, domain_id, group_id, @@ -212,10 +208,11 @@ class NsxPolicyGroupApi(NsxPolicyResourceBase): else: conditions = [] # Get the current data, and update it with the new values + # We need to do that here because of the conditions data group = self.get(domain_id, group_id, tenant=tenant) - group_def.update_attributes_in_body(group, conditions=conditions) + group_def.update_attributes_in_body(body=group, conditions=conditions) # update the backend - return self.policy_api.update(group_def) + return self.policy_api.create_or_update(group_def) class NsxPolicyL4ServiceApi(NsxPolicyResourceBase): @@ -225,9 +222,9 @@ class NsxPolicyL4ServiceApi(NsxPolicyResourceBase): and multiple service entries per service. At this point this is not supported here. """ - def create(self, name, service_id=None, description=None, - protocol=policy_constants.TCP, dest_ports=None, - tenant=policy_constants.POLICY_INFRA_TENANT): + def create_or_overwrite(self, name, service_id=None, description=None, + protocol=policy_constants.TCP, dest_ports=None, + tenant=policy_constants.POLICY_INFRA_TENANT): service_id = self._init_obj_uuid(service_id) service_def = policy_defs.ServiceDef(service_id=service_id, name=name, @@ -266,16 +263,17 @@ class NsxPolicyL4ServiceApi(NsxPolicyResourceBase): name=None, description=None, protocol=None, dest_ports=None, tenant=policy_constants.POLICY_INFRA_TENANT): + # TODO(asarfaty): This action fails on backend entry_id = srv_entry['id'] entry_def = policy_defs.L4ServiceEntryDef(service_id=service_id, service_entry_id=entry_id, tenant=tenant) - entry_def.update_attributes_in_body(srv_entry, name=name, + entry_def.update_attributes_in_body(body=srv_entry, name=name, description=description, protocol=protocol, dest_ports=dest_ports) - self.policy_api.update(entry_def) + self.policy_api.create_or_update(entry_def) def update(self, service_id, name=None, description=None, protocol=None, dest_ports=None, @@ -288,11 +286,11 @@ class NsxPolicyL4ServiceApi(NsxPolicyResourceBase): # update the service itself service_def = policy_defs.ServiceDef(service_id=service_id, tenant=tenant) - service_def.update_attributes_in_body(service, name=name, + service_def.update_attributes_in_body(name=name, description=description) # update the backend - updated_service = self.policy_api.update(service_def) + updated_service = self.policy_api.create_or_update(service_def) else: updated_service = service @@ -320,9 +318,10 @@ class NsxPolicyCommunicationProfileApi(NsxPolicyResourceBase): profile. At this point this is not supported here. """ - def create(self, name, profile_id=None, description=None, - services=None, action=policy_constants.ACTION_ALLOW, - tenant=policy_constants.POLICY_INFRA_TENANT): + def create_or_overwrite(self, name, profile_id=None, description=None, + services=None, + action=policy_constants.ACTION_ALLOW, + tenant=policy_constants.POLICY_INFRA_TENANT): """Create a Communication profile with a single entry. Services should be a list of service ids @@ -371,12 +370,13 @@ class NsxPolicyCommunicationProfileApi(NsxPolicyResourceBase): profile_id=profile_id, profile_entry_id=entry_id, tenant=tenant) - entry_def.update_attributes_in_body(profile_entry, name=name, + entry_def.update_attributes_in_body(body=profile_entry, + name=name, description=description, services=services, action=action) - self.policy_api.update(entry_def) + self.policy_api.create_or_update(entry_def) def update(self, profile_id, name=None, description=None, services=None, action=None, @@ -388,11 +388,11 @@ class NsxPolicyCommunicationProfileApi(NsxPolicyResourceBase): # update the profile itself profile_def = policy_defs.CommunicationProfileDef( profile_id=profile_id, tenant=tenant) - profile_def.update_attributes_in_body(profile, name=name, + profile_def.update_attributes_in_body(name=name, description=description) # update the backend - updated_profile = self.policy_api.update(profile_def) + updated_profile = self.policy_api.create_or_update(profile_def) else: updated_profile = profile @@ -419,22 +419,28 @@ class NsxPolicyCommunicationMapApi(NsxPolicyResourceBase): def _get_last_seq_num(self, domain_id, tenant=policy_constants.POLICY_INFRA_TENANT): # get the current entries, and choose the next unused sequence number - communication_maps = self.list(domain_id, tenant=tenant) - if not len(communication_maps): + try: + com_entries = self.list(domain_id, tenant=tenant) + except exceptions.ResourceNotFound: + return -1 + if not com_entries: return 0 - - seq_nums = [int(cm['sequence_number']) for cm in communication_maps] + seq_nums = [int(cm['sequence_number']) for cm in com_entries] seq_nums.sort() return seq_nums[-1] - def create(self, name, domain_id, map_id=None, - description=None, sequence_number=None, profile_id=None, - source_groups=None, dest_groups=None, - tenant=policy_constants.POLICY_INFRA_TENANT): - """Create a CommunicationtMap. + def create_or_overwrite(self, name, domain_id, map_id=None, + description=None, sequence_number=None, + profile_id=None, + source_groups=None, dest_groups=None, + tenant=policy_constants.POLICY_INFRA_TENANT): + """Create CommunicationMapEntry. source_groups/dest_groups should be a list of group ids belonging to the domain. + NOTE: In multi-connection environment, it is recommended to execute + this call under lock to prevent race condition where two entries + end up with same sequence number. """ # Validate and convert inputs map_id = self._init_obj_uuid(map_id) @@ -447,7 +453,10 @@ class NsxPolicyCommunicationMapApi(NsxPolicyResourceBase): # get the next available sequence number last_sequence = self._get_last_seq_num(domain_id, tenant=tenant) if not sequence_number: - sequence_number = last_sequence + 1 + if last_sequence < 0: + sequence_number = 1 + else: + sequence_number = last_sequence + 1 entry_def = policy_defs.CommunicationMapEntryDef( domain_id=domain_id, @@ -460,12 +469,14 @@ class NsxPolicyCommunicationMapApi(NsxPolicyResourceBase): profile_id=profile_id, tenant=tenant) - if last_sequence == 0: + if last_sequence < 0: # if communication map is absent, we need to create it map_def = policy_defs.CommunicationMapDef(domain_id, tenant) - return self.policy_api.create_with_parent(map_def, entry_def) + map_result = self.policy_api.create_with_parent(map_def, entry_def) + # return the created entry + return map_result['communication_entries'][0] - return self.policy_api.create(entry_def) + return self.policy_api.create_or_update(entry_def) def delete(self, domain_id, map_id, tenant=policy_constants.POLICY_INFRA_TENANT): @@ -485,14 +496,14 @@ class NsxPolicyCommunicationMapApi(NsxPolicyResourceBase): def get_by_name(self, domain_id, name, tenant=policy_constants.POLICY_INFRA_TENANT): - """Return first communication map matched by name of this domain""" + """Return first communication map entry matched by name""" return super(NsxPolicyCommunicationMapApi, self).get_by_name( name, domain_id, tenant=tenant) def list(self, domain_id, tenant=policy_constants.POLICY_INFRA_TENANT): """List all the map entries of a specific domain.""" - map_def = policy_defs.CommunicationMapDef( + map_def = policy_defs.CommunicationMapEntryDef( domain_id=domain_id, tenant=tenant) return self.policy_api.list(map_def)['results'] @@ -505,10 +516,18 @@ class NsxPolicyCommunicationMapApi(NsxPolicyResourceBase): domain_id=domain_id, map_id=map_id, tenant=tenant) + # Get the current data, and update it with the new values - comm_map = self.get(domain_id, map_id, tenant=tenant) + try: + comm_map = self.get(domain_id, map_id, tenant=tenant) + except exceptions.ResourceNotFound: + return self.create_or_overwrite(name, domain_id, map_id, + description, sequence_number, + profile_id, source_groups, + dest_groups, tenant) + map_def.update_attributes_in_body( - comm_map, + body=comm_map, name=name, description=description, sequence_number=sequence_number, @@ -517,16 +536,16 @@ class NsxPolicyCommunicationMapApi(NsxPolicyResourceBase): dest_groups=dest_groups) # update the backend - return self.policy_api.update(map_def) + return self.policy_api.create_or_update(map_def) class NsxPolicyEnforcementPointApi(NsxPolicyResourceBase): """NSX Policy Enforcement Point.""" - def create(self, name, ep_id=None, description=None, - ip_address=None, username=None, - password=None, - tenant=policy_constants.POLICY_INFRA_TENANT): + def create_or_overwrite(self, name, ep_id=None, description=None, + ip_address=None, username=None, + password=None, thumbprint=None, + tenant=policy_constants.POLICY_INFRA_TENANT): if not ip_address or not username or password is None: err_msg = (_("Cannot create an enforcement point without " "ip_address, username and password")) @@ -539,8 +558,9 @@ class NsxPolicyEnforcementPointApi(NsxPolicyResourceBase): ip_address=ip_address, username=username, password=password, + thumbprint=thumbprint, tenant=tenant) - return self.policy_api.create(ep_def) + return self.policy_api.create_or_update(ep_def) def delete(self, ep_id, tenant=policy_constants.POLICY_INFRA_TENANT): @@ -559,7 +579,8 @@ class NsxPolicyEnforcementPointApi(NsxPolicyResourceBase): return self.policy_api.list(ep_def)['results'] def update(self, ep_id, name=None, description=None, - ip_address=None, username=None, password=None, + ip_address=None, username=None, + password=None, thumbprint=None, tenant=policy_constants.POLICY_INFRA_TENANT): """Update the enforcement point. @@ -572,24 +593,22 @@ class NsxPolicyEnforcementPointApi(NsxPolicyResourceBase): raise exceptions.ManagerError(details=err_msg) ep_def = policy_defs.EnforcementPointDef(ep_id=ep_id, tenant=tenant) - # Get the current data, and update it with the new values - ep = self.get(ep_id, tenant=tenant) - ep_def.update_attributes_in_body(ep, - name=name, + ep_def.update_attributes_in_body(name=name, description=description, ip_address=ip_address, username=username, - password=password) + password=password, + thumbprint=thumbprint) # update the backend - return self.policy_api.update(ep_def) + return self.policy_api.create_or_update(ep_def) class NsxPolicyDeploymentMapApi(NsxPolicyResourceBase): """NSX Policy Deployment Map.""" - def create(self, name, map_id=None, description=None, - ep_id=None, domain_id=None, - tenant=policy_constants.POLICY_INFRA_TENANT): + def create_or_overwrite(self, name, map_id=None, description=None, + ep_id=None, domain_id=None, + tenant=policy_constants.POLICY_INFRA_TENANT): map_id = self._init_obj_uuid(map_id) map_def = policy_defs.DeploymentMapDef( map_id=map_id, @@ -598,7 +617,7 @@ class NsxPolicyDeploymentMapApi(NsxPolicyResourceBase): ep_id=ep_id, domain_id=domain_id, tenant=tenant) - return self.policy_api.create(map_def) + return self.policy_api.create_or_update(map_def) def delete(self, map_id, tenant=policy_constants.POLICY_INFRA_TENANT): @@ -621,12 +640,9 @@ class NsxPolicyDeploymentMapApi(NsxPolicyResourceBase): tenant=policy_constants.POLICY_INFRA_TENANT): map_def = policy_defs.DeploymentMapDef( map_id=map_id, tenant=tenant) - # Get the current data, and update it with the new values - map_obj = self.get(map_id, tenant=tenant) - map_def.update_attributes_in_body(map_obj, - name=name, + map_def.update_attributes_in_body(name=name, description=description, ep_id=ep_id, domain_id=domain_id) # update the backend - return self.policy_api.update(map_def) + return self.policy_api.create_or_update(map_def)