Fix possible DB deadlock scenario

Under certain conditions if an error occurred during an API request the
lock session could be left open. This patch corrects that by extending the
try block to include all calls with the lock open.

The test case was creating a second pool on a listener, which results in
a 409 conflict error, but the lock was left open.

Change-Id: I81e08775c515602f315aa8da32ff342f96c4a676
This commit is contained in:
Michael Johnson 2017-11-09 11:03:21 -08:00
parent 0cb21c543c
commit a332855e56
7 changed files with 74 additions and 75 deletions

View File

@ -170,17 +170,17 @@ class HealthMonitorController(base.BaseController):
constants.RBAC_POST)
lock_session = db_api.get_session(autocommit=False)
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.HealthMonitor,
health_monitor.project_id):
lock_session.rollback()
raise exceptions.QuotaException
hm_dict = db_prepare.create_health_monitor(
health_monitor.to_dict(render_unsets=True))
try:
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.HealthMonitor,
health_monitor.project_id):
raise exceptions.QuotaException
hm_dict = db_prepare.create_health_monitor(
health_monitor.to_dict(render_unsets=True))
self._test_lb_and_listener_and_pool_statuses(
lock_session, health_monitor)
db_hm = self._validate_create_hm(lock_session, hm_dict)

View File

@ -157,18 +157,18 @@ class L7PolicyController(base.BaseController):
constants.RBAC_POST)
lock_session = db_api.get_session(autocommit=False)
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.L7Policy,
l7policy.project_id):
lock_session.rollback()
raise exceptions.QuotaException
l7policy_dict = db_prepare.create_l7policy(
l7policy.to_dict(render_unsets=True),
load_balancer_id, listener_id)
try:
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.L7Policy,
l7policy.project_id):
raise exceptions.QuotaException
l7policy_dict = db_prepare.create_l7policy(
l7policy.to_dict(render_unsets=True),
load_balancer_id, listener_id)
self._test_lb_and_listener_statuses(
lock_session, lb_id=load_balancer_id,
listener_ids=[listener_id])

View File

@ -160,9 +160,10 @@ class L7RuleController(base.BaseController):
constants.RBAC_POST)
lock_session = db_api.get_session(autocommit=False)
l7rule_dict = db_prepare.create_l7rule(
l7rule.to_dict(render_unsets=True), self.l7policy_id)
try:
l7rule_dict = db_prepare.create_l7rule(
l7rule.to_dict(render_unsets=True), self.l7policy_id)
self._test_lb_listener_policy_statuses(context.session)
db_l7rule = self._validate_create_l7rule(lock_session, l7rule_dict)

View File

@ -203,22 +203,21 @@ class ListenersController(base.BaseController):
value=constants.PROTOCOL_TERMINATED_HTTPS, option='protocol')
lock_session = db_api.get_session(autocommit=False)
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.Listener,
listener.project_id):
lock_session.rollback()
raise exceptions.QuotaException
listener_dict = db_prepare.create_listener(
listener.to_dict(render_unsets=True), None)
if listener_dict['default_pool_id']:
self._validate_pool(context.session, load_balancer_id,
listener_dict['default_pool_id'])
try:
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.Listener,
listener.project_id):
raise exceptions.QuotaException
listener_dict = db_prepare.create_listener(
listener.to_dict(render_unsets=True), None)
if listener_dict['default_pool_id']:
self._validate_pool(context.session, load_balancer_id,
listener_dict['default_pool_id'])
self._test_lb_and_listener_statuses(
lock_session, lb_id=load_balancer_id)

View File

@ -231,16 +231,16 @@ class LoadBalancersController(base.BaseController):
self._validate_vip_request_object(load_balancer)
lock_session = db_api.get_session(autocommit=False)
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.LoadBalancer,
load_balancer.project_id):
lock_session.rollback()
raise exceptions.QuotaException
db_lb, db_pools, db_lists = None, None, None
try:
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.LoadBalancer,
load_balancer.project_id):
raise exceptions.QuotaException
db_lb, db_pools, db_lists = None, None, None
lb_dict = db_prepare.create_load_balancer(load_balancer.to_dict(
render_unsets=False
))

View File

@ -174,17 +174,17 @@ class MemberController(base.BaseController):
constants.RBAC_POST)
lock_session = db_api.get_session(autocommit=False)
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.Member,
member.project_id):
lock_session.rollback()
raise exceptions.QuotaException
member_dict = db_prepare.create_member(member.to_dict(
render_unsets=True), self.pool_id, bool(pool.health_monitor))
try:
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.Member,
member.project_id):
raise exceptions.QuotaException
member_dict = db_prepare.create_member(member.to_dict(
render_unsets=True), self.pool_id, bool(pool.health_monitor))
self._test_lb_and_listener_and_pool_statuses(lock_session)
db_member = self._validate_create_member(lock_session, member_dict)

View File

@ -173,25 +173,24 @@ class PoolsController(base.BaseController):
constants.RBAC_POST)
lock_session = db_api.get_session(autocommit=False)
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.Pool,
pool.project_id):
lock_session.rollback()
raise exceptions.QuotaException
listener_repo = self.repositories.listener
pool_dict = db_prepare.create_pool(
pool.to_dict(render_unsets=True))
listener_id = pool_dict.pop('listener_id', None)
if listener_id:
if listener_repo.has_default_pool(lock_session,
listener_id):
raise exceptions.DuplicatePoolEntry()
try:
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.Pool,
pool.project_id):
raise exceptions.QuotaException
listener_repo = self.repositories.listener
pool_dict = db_prepare.create_pool(
pool.to_dict(render_unsets=True))
listener_id = pool_dict.pop('listener_id', None)
if listener_id:
if listener_repo.has_default_pool(lock_session,
listener_id):
raise exceptions.DuplicatePoolEntry()
self._test_lb_and_listener_statuses(
lock_session, lb_id=pool_dict['load_balancer_id'],
listener_ids=[listener_id] if listener_id else [])