Fix issues with rollback on quota failures

Change-Id: Icf62d1a78f2e5474fbf8a5dd68132a9ea7636698
This commit is contained in:
Sumit Naiksatam 2018-06-13 16:56:38 -07:00
parent b3b3a320c5
commit 61d738f8b6
3 changed files with 67 additions and 2 deletions

View File

@ -18,6 +18,7 @@ from gbpservice.neutron.plugins.ml2plus import driver_api
from neutron.db import api as db_api
from neutron.plugins.ml2.common import exceptions as ml2_exc
from neutron.plugins.ml2 import managers
from neutron.quota import resource_registry
from oslo_log import log
from oslo_utils import excutils
@ -29,6 +30,25 @@ class MechanismManager(managers.MechanismManager):
def __init__(self):
super(MechanismManager, self).__init__()
def _call_on_drivers(self, method_name, context,
continue_on_failure=False, raise_db_retriable=False):
super(MechanismManager, self)._call_on_drivers(
method_name, context, continue_on_failure=False,
raise_db_retriable=False)
if method_name.endswith('_precommit'):
# This does the same thing as:
# https://github.com/openstack/neutron/blob/newton-eol/neutron/
# api/v2/base.py#L489
# but from within the scope of the plugin's transaction, such
# that if it fails, everything that happened prior to this in
# precommit phase can also be rolled back.
resource_name = method_name.replace('_precommit', '').replace(
'create_', '').replace('update_', '').replace(
'delete_', '')
tracked_resource = resource_registry.get_resource(resource_name)
tracked_resource._dirty_tenants.add(context.current['tenant_id'])
resource_registry.set_resources_dirty(context._plugin_context)
def _call_on_extended_drivers(self, method_name, context,
continue_on_failure=False,
raise_db_retriable=False):

View File

@ -191,10 +191,13 @@ def undecorated(o):
else:
return o
from neutron.db import common_db_mixin as common_db_api
from neutron.db.quota import api as quota_api
from neutron.db.quota import driver # noqa
from neutron.db.quota import models as quota_models
from neutron import quota
from neutron.quota import resource_registry as res_reg
from oslo_config import cfg
f = quota_api.remove_reservation
@ -208,6 +211,37 @@ def commit_reservation(context, reservation_id):
quota.QUOTAS.get_driver().commit_reservation = commit_reservation
def patched_set_resources_dirty(context):
if not cfg.CONF.QUOTAS.track_quota_usage:
return
with context.session.begin(subtransactions=True):
for res in res_reg.get_all_resources().values():
if res_reg.is_tracked(res.name) and res.dirty:
dirty_tenants_snap = res._dirty_tenants.copy()
for tenant_id in dirty_tenants_snap:
query = common_db_api.model_query(
context, quota_models.QuotaUsage)
query = query.filter_by(resource=res.name).filter_by(
tenant_id=tenant_id)
usage_data = query.first()
# Set dirty if not set already. This effectively
# patches the inner notify method:
# https://github.com/openstack/neutron/blob/newton-eol/
# neutron/api/v2/base.py#L481
# to avoid updating the QuotaUsages table outside
# from that method (which starts a new transaction).
# The dirty marking would have been already done
# in the ml2plus manager at the end of the pre_commit
# stage (and prior to the plugin initiated transaction
# completing).
if usage_data and not usage_data.dirty:
res.mark_dirty(context)
quota.resource_registry.set_resources_dirty = patched_set_resources_dirty
from oslo_db.sqlalchemy import exc_filters

View File

@ -42,6 +42,7 @@ from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
from neutron.tests.unit.extensions import test_address_scope
from neutron.tests.unit.extensions import test_l3
from neutron.tests.unit.extensions import test_securitygroup
from neutron.tests.unit.plugins.ml2 import test_tracked_resources as tr_res
from neutron.tests.unit import testlib_api
from neutron_lib.callbacks import registry
from neutron_lib import constants as n_constants
@ -238,7 +239,8 @@ class ApicAimTestCase(test_address_scope.AddressScopeTestCase,
test_l3.L3NatTestCaseMixin, ApicAimTestMixin,
test_securitygroup.SecurityGroupsTestCase):
def setUp(self, mechanism_drivers=None, tenant_network_types=None):
def setUp(self, mechanism_drivers=None, tenant_network_types=None,
plugin=None, ext_mgr=None):
# Enable the test mechanism driver to ensure that
# we can successfully call through to all mechanism
# driver apis.
@ -3061,6 +3063,15 @@ class TestAimMapping(ApicAimTestCase):
dhcp_agt_mock.stop()
class TestTrackedResources(tr_res.TestTrackedResources, ApicAimTestCase):
def setUp(self, **kwargs):
super(TestTrackedResources, self).setUp(**kwargs)
for patch in mock.mock._patch._active_patches:
if patch.attribute == '_ensure_default_security_group':
patch.stop()
class TestSyncState(ApicAimTestCase):
@staticmethod
def _get_synced_status(self, context, resource, **kwargs):