Support PATCH partial updates

Change-Id: I4bb34bccc0c95e985ab10190fc11ed21d0664be8
(cherry picked from commit e93309ff86)
This commit is contained in:
Adit Sarfaty 2019-08-01 12:29:54 +03:00
parent b4cd5825be
commit 1cbb8d815c
7 changed files with 37 additions and 26 deletions

View File

@ -29,7 +29,7 @@ class TestPolicyApi(nsxlib_testcase.NsxClientTestCase):
super(TestPolicyApi, self).setUp() super(TestPolicyApi, self).setUp()
def assert_json_call(self, method, client, url, data=None): def assert_json_call(self, method, client, url, data=None, headers=None):
url = BASE_POLICY_URI + url url = BASE_POLICY_URI + url
return super(TestPolicyApi, self).assert_json_call( return super(TestPolicyApi, self).assert_json_call(
method, client, url, data=data) method, client, url, data=data, headers=headers)

View File

@ -852,7 +852,6 @@ class TestPolicyLBVirtualServer(test_resources.NsxPolicyLibTestCase):
expected_def = lb_defs.LBVirtualServerDef( expected_def = lb_defs.LBVirtualServerDef(
virtual_server_id=vs_obj_id, virtual_server_id=vs_obj_id,
name=vs_name,
rules=[lb_rule]) rules=[lb_rule])
self.assert_called_with_def(update_call, expected_def) self.assert_called_with_def(update_call, expected_def)
@ -880,7 +879,6 @@ class TestPolicyLBVirtualServer(test_resources.NsxPolicyLibTestCase):
expected_def = lb_defs.LBVirtualServerDef( expected_def = lb_defs.LBVirtualServerDef(
virtual_server_id=vs_obj_id, virtual_server_id=vs_obj_id,
name=vs_name,
rules=[lb_rule, rules=[lb_rule,
{'display_name': 'xx'}, {'display_name': 'xx'},
{'display_name': 'yy'}]) {'display_name': 'yy'}])
@ -908,7 +906,6 @@ class TestPolicyLBVirtualServer(test_resources.NsxPolicyLibTestCase):
expected_def = lb_defs.LBVirtualServerDef( expected_def = lb_defs.LBVirtualServerDef(
virtual_server_id=vs_obj_id, virtual_server_id=vs_obj_id,
name=vs_name,
rules=[{'display_name': 'xx'}, rules=[{'display_name': 'xx'},
{'display_name': 'yy'}, {'display_name': 'yy'},
lb_rule]) lb_rule])
@ -937,7 +934,7 @@ class TestPolicyLBVirtualServer(test_resources.NsxPolicyLibTestCase):
rule_match_strategy, rule_phase) rule_match_strategy, rule_phase)
expected_def = lb_defs.LBVirtualServerDef( expected_def = lb_defs.LBVirtualServerDef(
virtual_server_id=vs_obj_id, name=vs_name, virtual_server_id=vs_obj_id,
rules=[{'display_name': 'xx'}, rules=[{'display_name': 'xx'},
{'display_name': 'yy'}, {'display_name': 'yy'},
lb_rule]) lb_rule])
@ -965,7 +962,6 @@ class TestPolicyLBVirtualServer(test_resources.NsxPolicyLibTestCase):
rule_match_strategy, rule_phase) rule_match_strategy, rule_phase)
expected_def = lb_defs.LBVirtualServerDef( expected_def = lb_defs.LBVirtualServerDef(
name=vs_name,
virtual_server_id=vs_obj_id, virtual_server_id=vs_obj_id,
rules=[{'display_name': 'xx'}, rules=[{'display_name': 'xx'},
lb_rule, lb_rule,
@ -983,7 +979,6 @@ class TestPolicyLBVirtualServer(test_resources.NsxPolicyLibTestCase):
self.resourceApi.update_lb_rule(vs_obj_id, 'xx', actions='22') self.resourceApi.update_lb_rule(vs_obj_id, 'xx', actions='22')
expected_def = lb_defs.LBVirtualServerDef( expected_def = lb_defs.LBVirtualServerDef(
name=vs_name,
virtual_server_id=vs_obj_id, virtual_server_id=vs_obj_id,
rules=[{'display_name': 'xx', 'actions': '22'}, rules=[{'display_name': 'xx', 'actions': '22'},
{'display_name': 'yy'}]) {'display_name': 'yy'}])
@ -1002,7 +997,6 @@ class TestPolicyLBVirtualServer(test_resources.NsxPolicyLibTestCase):
expected_def = lb_defs.LBVirtualServerDef( expected_def = lb_defs.LBVirtualServerDef(
virtual_server_id=vs_obj_id, virtual_server_id=vs_obj_id,
name=vs_name,
rules=[{'display_name': 'yy'}, rules=[{'display_name': 'yy'},
{'display_name': 'xx', 'actions': '22'}]) {'display_name': 'xx', 'actions': '22'}])
self.assert_called_with_def(update_call, expected_def) self.assert_called_with_def(update_call, expected_def)
@ -1018,7 +1012,6 @@ class TestPolicyLBVirtualServer(test_resources.NsxPolicyLibTestCase):
expected_def = lb_defs.LBVirtualServerDef( expected_def = lb_defs.LBVirtualServerDef(
virtual_server_id=vs_obj_id, virtual_server_id=vs_obj_id,
name=vs_name,
rules=[{'display_name': 'yy'}]) rules=[{'display_name': 'yy'}])
self.assert_called_with_def(update_call, expected_def) self.assert_called_with_def(update_call, expected_def)

View File

@ -18,6 +18,7 @@ import mock
from vmware_nsxlib.tests.unit.v3 import nsxlib_testcase from vmware_nsxlib.tests.unit.v3 import nsxlib_testcase
from vmware_nsxlib.tests.unit.v3.policy import policy_testcase from vmware_nsxlib.tests.unit.v3.policy import policy_testcase
from vmware_nsxlib.tests.unit.v3 import test_client
from vmware_nsxlib.v3 import exceptions as nsxlib_exc from vmware_nsxlib.v3 import exceptions as nsxlib_exc
from vmware_nsxlib.v3 import nsx_constants from vmware_nsxlib.v3 import nsx_constants
from vmware_nsxlib.v3 import policy from vmware_nsxlib.v3 import policy
@ -39,7 +40,7 @@ class NsxPolicyLibTestCase(policy_testcase.TestPolicyApi):
# Mock the nsx-lib for the passthrough api # Mock the nsx-lib for the passthrough api
# TODO(annak): move version forward with backend releases # TODO(annak): move version forward with backend releases
with mock.patch("vmware_nsxlib.v3.NsxLib") as mock_lib: with mock.patch("vmware_nsxlib.v3.NsxLib") as mock_lib:
mock_lib.return_value.get_version.return_value = "2.5.0" mock_lib.return_value.get_version.return_value = "3.0.0"
self.policy_lib = policy.NsxPolicyLib(nsxlib_config) self.policy_lib = policy.NsxPolicyLib(nsxlib_config)
self.policy_api = self.policy_lib.policy_api self.policy_api = self.policy_lib.policy_api
@ -216,7 +217,8 @@ class TestPolicyDomain(NsxPolicyLibTestCase):
self.assert_json_call('PATCH', self.client, self.assert_json_call('PATCH', self.client,
'%s/domains/%s' % (TEST_TENANT, domain_id), '%s/domains/%s' % (TEST_TENANT, domain_id),
data=expected_body) data=expected_body,
headers=test_client.PARTIAL_UPDATE_HEADERS)
class TestPolicyGroup(NsxPolicyLibTestCase): class TestPolicyGroup(NsxPolicyLibTestCase):
@ -595,7 +597,8 @@ class TestPolicyGroup(NsxPolicyLibTestCase):
'%s/domains/%s/groups/%s' % (TEST_TENANT, '%s/domains/%s/groups/%s' % (TEST_TENANT,
domain_id, domain_id,
group_id), group_id),
data=expected_body) data=expected_body,
headers=test_client.PARTIAL_UPDATE_HEADERS)
def test_get_realized(self): def test_get_realized(self):
domain_id = 'd1' domain_id = 'd1'
@ -2385,6 +2388,7 @@ class TestPolicyTier1(NsxPolicyLibTestCase):
def setUp(self, *args, **kwargs): def setUp(self, *args, **kwargs):
super(TestPolicyTier1, self).setUp(*args, **kwargs) super(TestPolicyTier1, self).setUp(*args, **kwargs)
self.resourceApi = self.policy_lib.tier1 self.resourceApi = self.policy_lib.tier1
self.partial_updates = True
def test_create(self): def test_create(self):
name = 'test' name = 'test'
@ -2551,9 +2555,10 @@ class TestPolicyTier1(NsxPolicyLibTestCase):
expected_def = core_defs.Tier1Def( expected_def = core_defs.Tier1Def(
tier1_id=obj_id, tier1_id=obj_id,
name=rtr_name,
route_advertisement=new_adv, route_advertisement=new_adv,
tenant=TEST_TENANT) tenant=TEST_TENANT)
if not self.partial_updates:
expected_def.attrs['name'] = rtr_name
self.assert_called_with_def( self.assert_called_with_def(
update_call, expected_def) update_call, expected_def)
@ -2583,10 +2588,11 @@ class TestPolicyTier1(NsxPolicyLibTestCase):
expected_def = core_defs.Tier1Def( expected_def = core_defs.Tier1Def(
tier1_id=obj_id, tier1_id=obj_id,
name=rtr_name,
route_advertisement=new_adv, route_advertisement=new_adv,
tier0=tier0, tier0=tier0,
tenant=TEST_TENANT) tenant=TEST_TENANT)
if not self.partial_updates:
expected_def.attrs['name'] = rtr_name
self.assert_called_with_def( self.assert_called_with_def(
update_call, expected_def) update_call, expected_def)
@ -2902,6 +2908,8 @@ class TestPolicyTier1NoPassthrough(TestPolicyTier1):
def setUp(self, *args, **kwargs): def setUp(self, *args, **kwargs):
super(TestPolicyTier1NoPassthrough, self).setUp( super(TestPolicyTier1NoPassthrough, self).setUp(
allow_passthrough=False) allow_passthrough=False)
# No passthrough also means no partial updates
self.partial_updates = False
def test_update_transport_zone(self): def test_update_transport_zone(self):
# Will not work without passthrough api # Will not work without passthrough api

View File

@ -39,6 +39,13 @@ JSON_DFT_ACCEPT_HEADERS = {
'Cookie': 'JSESSIONID=%s;' % nsxlib_testcase.JSESSIONID 'Cookie': 'JSESSIONID=%s;' % nsxlib_testcase.JSESSIONID
} }
PARTIAL_UPDATE_HEADERS = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Cookie': 'JSESSIONID=%s;' % nsxlib_testcase.JSESSIONID,
'nsx-enable-partial-patch': 'true'
}
def _headers(**kwargs): def _headers(**kwargs):
headers = copy.copy(DFT_ACCEPT_HEADERS) headers = copy.copy(DFT_ACCEPT_HEADERS)

View File

@ -156,11 +156,10 @@ class NsxPolicyLib(lib.NsxLibBase):
if (feature == nsx_constants.FEATURE_ENS_WITH_QOS): if (feature == nsx_constants.FEATURE_ENS_WITH_QOS):
return True return True
# TODO(asarfaty): Uncomment this once partial updates are supported if (version.LooseVersion(self.get_version()) >=
# if (version.LooseVersion(self.get_version()) >= version.LooseVersion(nsx_constants.NSX_VERSION_3_0_0)):
# version.LooseVersion(nsx_constants.NSX_VERSION_3_0_0)): if feature == nsx_constants.FEATURE_PARTIAL_UPDATES:
# if feature == nsx_constants.FEATURE_PARTIAL_UPDATES: return True
# return True
return (feature == nsx_constants.FEATURE_NSX_POLICY) return (feature == nsx_constants.FEATURE_NSX_POLICY)

View File

@ -1764,7 +1764,7 @@ class NsxPolicyApi(object):
def partial_updates_supported(self): def partial_updates_supported(self):
return self.partial_updates return self.partial_updates
def create_or_update(self, resource_def): def create_or_update(self, resource_def, partial_updates=False):
"""Create or update a policy object. """Create or update a policy object.
This api will update an existing object, or create a new one if it This api will update an existing object, or create a new one if it
@ -1776,7 +1776,10 @@ class NsxPolicyApi(object):
self.cache.remove(path) self.cache.remove(path)
body = resource_def.get_obj_dict() body = resource_def.get_obj_dict()
self.client.patch(path, body) headers = None
if partial_updates:
headers = {'nsx-enable-partial-patch': 'true'}
self.client.patch(path, body, headers=headers)
def create_with_parent(self, parent_def, resource_def): def create_with_parent(self, parent_def, resource_def):
path = parent_def.get_resource_path() path = parent_def.get_resource_path()

View File

@ -147,14 +147,16 @@ class NsxPolicyResourceBase(object):
if self.policy_api.partial_updates_supported(): if self.policy_api.partial_updates_supported():
policy_def = self._init_def(**kwargs) policy_def = self._init_def(**kwargs)
partial_updates = True
else: else:
policy_def = self._get_and_update_def(**kwargs) policy_def = self._get_and_update_def(**kwargs)
partial_updates = False
if policy_def.bodyless(): if policy_def.bodyless():
# Nothing to update - only keys provided in kwargs # Nothing to update - only keys provided in kwargs
return return
self.policy_api.create_or_update(
self.policy_api.create_or_update(policy_def) policy_def, partial_updates=partial_updates)
@staticmethod @staticmethod
def _init_obj_uuid(obj_uuid): def _init_obj_uuid(obj_uuid):
@ -994,8 +996,7 @@ class NsxPolicyTier1Api(NsxPolicyResourceBase):
self.update(tier1_id, self.update(tier1_id,
route_advertisement=route_adv, route_advertisement=route_adv,
tier0=tier0, tier0=tier0,
tenant=tenant, tenant=tenant)
current_body=tier1_dict)
def add_advertisement_rule( def add_advertisement_rule(
self, tier1_id, name, action=None, prefix_operator=None, self, tier1_id, name, action=None, prefix_operator=None,