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
This commit is contained in:
Kevin Benton 2016-05-14 23:44:23 -07:00
parent d5eac3cfe0
commit 5109d16bc5
2 changed files with 16 additions and 1 deletions

View File

@ -593,7 +593,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

@ -17,6 +17,7 @@
import mock
from neutron_lib import constants
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'])