Browse Source

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
changes/72/322372/1
Kevin Benton 5 years ago
parent
commit
5109d16bc5
  1. 3
      neutron/api/v2/base.py
  2. 14
      neutron/tests/unit/extensions/test_l3_ext_gw_mode.py

3
neutron/api/v2/base.py

@ -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]

14
neutron/tests/unit/extensions/test_l3_ext_gw_mode.py

@ -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'])

Loading…
Cancel
Save