diff --git a/src/api-lib/vnc_api.py b/src/api-lib/vnc_api.py index 35b344a3a6b..e0b41585bce 100644 --- a/src/api-lib/vnc_api.py +++ b/src/api-lib/vnc_api.py @@ -376,13 +376,17 @@ def _object_update(self, res_type, obj): if not obj.uuid: obj.uuid = self.fq_name_to_id(res_type, obj.get_fq_name()) - # Ignore fields with None value in json representation - json_param = json.dumps(obj, default=self._obj_serializer) - json_body = '{"%s":%s}' %(res_type, json_param) + # Generate PUT on object only if some attr was modified + content = None + if obj.get_pending_updates(): + # Ignore fields with None value in json representation + json_param = json.dumps(obj, default=self._obj_serializer) + json_body = '{"%s":%s}' %(res_type, json_param) + + id = obj.uuid + uri = obj_cls.resource_uri_base[res_type] + '/' + id + content = self._request_server(rest.OP_PUT, uri, data=json_body) - id = obj.uuid - uri = obj_cls.resource_uri_base[res_type] + '/' + id - content = self._request_server(rest.OP_PUT, uri, data=json_body) for ref_name in obj._pending_ref_updates: ref_orig = set([(x.get('uuid'), tuple(x.get('to', [])), x.get('attr')) diff --git a/src/config/api-server/tests/test_crud_basic.py b/src/config/api-server/tests/test_crud_basic.py index a382e949edc..89d2de51c5f 100644 --- a/src/config/api-server/tests/test_crud_basic.py +++ b/src/config/api-server/tests/test_crud_basic.py @@ -1614,6 +1614,26 @@ def test_vmi_links_to_native_ri(self): logger.info("...link to Native RI done.") # end test_vmi_links_to_native_ri + def test_nop_on_empty_body_update(self): + # library api test + vn_fq_name = VirtualNetwork().fq_name + vn_obj = self._vnc_lib.virtual_network_read(fq_name=vn_fq_name) + mod_time = vn_obj.id_perms.last_modified + resp = self._vnc_lib.virtual_network_update(vn_obj) + self.assertIsNone(resp) + vn_obj = self._vnc_lib.virtual_network_read(fq_name=vn_fq_name) + self.assertEqual(mod_time, vn_obj.id_perms.last_modified) + + # rest api test + listen_ip = self._api_server_ip + listen_port = self._api_server._args.listen_port + url = 'http://%s:%s/virtual-network/%s' %( + listen_ip, listen_port, vn_obj.uuid) + resp = requests.put(url) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.text, '') + # end test_nop_on_empty_body_update + # end class TestVncCfgApiServer class TestVncCfgApiServerRequests(test_case.ApiServerTestCase): diff --git a/src/config/api-server/vnc_cfg_api_server.py b/src/config/api-server/vnc_cfg_api_server.py index 58c5fa4a94e..159b728e709 100644 --- a/src/config/api-server/vnc_cfg_api_server.py +++ b/src/config/api-server/vnc_cfg_api_server.py @@ -556,6 +556,13 @@ def http_resource_read(self, resource_type, id): def http_resource_update(self, resource_type, id): r_class = self.get_resource_class(resource_type) obj_type = resource_type.replace('-', '_') + # Early return if there is no body or an empty body + request = get_request() + if (not hasattr(request, 'json') or + not request.json or + not request.json[resource_type]): + return + obj_dict = get_request().json[resource_type] try: self._extension_mgrs['resourceApi'].map_method(