Raise RetryRequest on policy parent not found

During a port list operation, a port and its parent network
may be concurrently deleted from the database after they have
been retrieved from the DB but before policy is enforced.
Then when the policy engine tries to do a get_network to check
network ownership for a port on a network that no longer exists,
it will encounter a NetworkNotFound exception from the core plugin.

This exception was being propagated all of the way up to the whole
API operation as a 404, which made no sense in the context of a
port list.

This patch adjusts the logic to catch any NotFound exceptions during
this processing and convert them into a RetryRequest to trigger the
API to restart the operation. At this point the objects will be gone
from the database so the problematic items will not be passed to the
policy engine for enforcement.

Closes-Bug: #1528031
Change-Id: I89d12fe0767e1c7ecb68138b5f6f17aa68a68769
This commit is contained in:
Kevin Benton 2016-01-27 05:18:13 -08:00
parent 44571236ca
commit 77de9653fd
2 changed files with 21 additions and 0 deletions

View File

@ -17,6 +17,7 @@ import collections
import re
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_log import log as logging
from oslo_policy import policy
from oslo_utils import excutils
@ -257,6 +258,13 @@ class OwnerCheck(policy.Check):
target[parent_foreign_key],
fields=[parent_field])
target[self.target_field] = data[parent_field]
except exceptions.NotFound as e:
# NOTE(kevinbenton): a NotFound exception can occur if a
# list operation is happening at the same time as one of
# the parents and its children being deleted. So we issue
# a RetryRequest so the API will redo the lookup and the
# problem items will be gone.
raise db_exc.RetryRequest(e)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE('Policy check error while calling %s!'),

View File

@ -16,6 +16,7 @@
"""Test of Policy Engine For Neutron"""
import mock
from oslo_db import exception as db_exc
from oslo_policy import fixture as op_fixture
from oslo_policy import policy as oslo_policy
from oslo_serialization import jsonutils
@ -537,6 +538,18 @@ class NeutronPolicyTestCase(base.BaseTestCase):
action,
target)
def test_retryrequest_on_notfound(self):
failure = exceptions.NetworkNotFound(net_id='whatever')
action = "create_port:mac"
with mock.patch.object(manager.NeutronManager.get_instance().plugin,
'get_network', side_effect=failure):
target = {'network_id': 'whatever'}
try:
policy.enforce(self.context, action, target)
self.fail("Did not raise RetryRequest")
except db_exc.RetryRequest as e:
self.assertEqual(failure, e.inner_exc)
def test_enforce_tenant_id_check_parent_resource_bw_compatibility(self):
def fakegetnetwork(*args, **kwargs):