Make deepcopy of update body in API layer

This adjusts the update handler in the API layer to pass a deepcopy
of the original update body to ensure that the original is used on
any generated retry requests.

Without this update handlers that modified the body as they processed
it (e.g. the external gateway update for routers) would be missing
data on a retry request.

This adds a test case for the bug that was caused by this.

Closes-Bug: #1584920
Change-Id: I88fb9d45eb82ef48e0d865decdcc7fad1c5fb361
(cherry picked from commit 5109d16bc5)
This commit is contained in:
Kevin Benton 2016-05-14 23:44:23 -07:00
parent bff727bc19
commit 483ceec083
2 changed files with 16 additions and 1 deletions

View File

@ -580,7 +580,8 @@ class Controller(object):
@db_api.retry_db_errors
def _update(self, request, id, body, **kwargs):
body = Controller.prepare_request_body(request.context, body, False,
body = Controller.prepare_request_body(request.context,
copy.deepcopy(body), False,
self._resource, self._attr_info,
allow_bulk=self._allow_bulk)
action = self._plugin_handlers[self.UPDATE]

View File

@ -16,6 +16,7 @@
import mock
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_serialization import jsonutils
from oslo_utils import uuidutils
import testscenarios
@ -389,6 +390,19 @@ class ExtGwModeIntTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase,
expected_code=expected_code,
neutron_context=neutron_context)
def test_router_gateway_set_retry(self):
with self.router() as r, self.subnet() as s:
ext_net_id = s['subnet']['network_id']
self._set_net_external(ext_net_id)
with mock.patch.object(
l3_db.L3_NAT_dbonly_mixin, '_validate_gw_info',
side_effect=[db_exc.RetryRequest(None), ext_net_id]):
self._set_router_external_gateway(r['router']['id'],
ext_net_id)
res = self._show('routers', r['router']['id'])['router']
self.assertEqual(ext_net_id,
res['external_gateway_info']['network_id'])
def test_router_create_with_gwinfo_invalid_ext_ip(self):
with self.subnet() as s:
self._set_net_external(s['subnet']['network_id'])