NSX: Sync do not pass around model object

The NSX sync backend previously passed around a sqlalchemy model object
around which was nice because we did not need to query the database an
additional time to update the status of an object.

Unfortunately, this was add done within a db transaction which included a
call to NSX which could cause deadlock this needed to be removed. Now a
dict is passed around instead and proper transaction handling
is used when updating objects.

Change-Id: Id50abd8f2143b127d1ca81c360c1c6d400e1d74f
Closes-bug: #1281772
This commit is contained in:
Aaron Rosen 2014-02-18 12:22:42 -08:00 committed by Aaron Rosen
parent 1a6fa787bc
commit bdfc05a6b8
1 changed files with 67 additions and 26 deletions

View File

@ -15,6 +15,8 @@
import random
from sqlalchemy.orm import exc
from neutron.common import constants
from neutron.common import exceptions
from neutron import context
@ -235,17 +237,6 @@ class NsxSynchronizer():
def _get_tag_dict(self, tags):
return dict((tag.get('scope'), tag['tag']) for tag in tags)
def _update_neutron_object(self, context, neutron_data, status):
if status == neutron_data['status']:
# do nothing
return
with context.session.begin(subtransactions=True):
LOG.debug(_("Updating status for neutron resource %(q_id)s to: "
"%(status)s"), {'q_id': neutron_data['id'],
'status': status})
neutron_data['status'] = status
context.session.add(neutron_data)
def synchronize_network(self, context, neutron_network_data,
lswitches=None):
"""Synchronize a Neutron network with its NSX counterpart.
@ -286,7 +277,22 @@ class NsxSynchronizer():
if lswitches:
status = constants.NET_STATUS_ACTIVE
# Update db object
self._update_neutron_object(context, neutron_network_data, status)
if status == neutron_network_data['status']:
# do nothing
return
with context.session.begin(subtransactions=True):
try:
network = self._plugin._get_network(context,
neutron_network_data['id'])
except exc.NoResultFound:
pass
else:
network.status = status
LOG.debug(_("Updating status for neutron resource %(q_id)s to:"
" %(status)s"),
{'q_id': neutron_network_data['id'],
'status': status})
def _synchronize_lswitches(self, ctx, ls_uuids, scan_missing=False):
if not ls_uuids and not scan_missing:
@ -309,8 +315,11 @@ class NsxSynchronizer():
filters = {'router:external': [False]}
if not scan_missing:
filters['id'] = neutron_net_ids
networks = self._plugin._get_collection_query(
ctx, models_v2.Network, filters=filters)
networks = self._plugin._get_collection(
ctx, models_v2.Network, self._plugin._make_network_dict,
filters=filters)
for network in networks:
lswitches = neutron_nsx_mappings.get(network['id'], [])
lswitches = [lswitch.get('data') for lswitch in lswitches]
@ -350,7 +359,22 @@ class NsxSynchronizer():
constants.NET_STATUS_ACTIVE
or constants.NET_STATUS_DOWN)
# Update db object
self._update_neutron_object(context, neutron_router_data, status)
if status == neutron_router_data['status']:
# do nothing
return
with context.session.begin(subtransactions=True):
try:
router = self._plugin._get_router(context,
neutron_router_data['id'])
except exc.NoResultFound:
pass
else:
router.status = status
LOG.debug(_("Updating status for neutron resource %(q_id)s to:"
" %(status)s"),
{'q_id': neutron_router_data['id'],
'status': status})
def _synchronize_lrouters(self, ctx, lr_uuids, scan_missing=False):
if not lr_uuids and not scan_missing:
@ -372,8 +396,9 @@ class NsxSynchronizer():
# Fetch neutron routers from database
filters = ({} if scan_missing else
{'id': neutron_router_mappings.keys()})
routers = self._plugin._get_collection_query(
ctx, l3_db.Router, filters=filters)
routers = self._plugin._get_collection(
ctx, l3_db.Router, self._plugin._make_router_dict,
filters=filters)
for router in routers:
lrouter = neutron_router_mappings.get(router['id'])
self.synchronize_router(
@ -427,8 +452,24 @@ class NsxSynchronizer():
status = (lp_status and
constants.PORT_STATUS_ACTIVE
or constants.PORT_STATUS_DOWN)
# Update db object
self._update_neutron_object(context, neutron_port_data, status)
if status == neutron_port_data['status']:
# do nothing
return
with context.session.begin(subtransactions=True):
try:
port = self._plugin._get_port(context,
neutron_port_data['id'])
except exc.NoResultFound:
pass
else:
port.status = status
LOG.debug(_("Updating status for neutron resource %(q_id)s to:"
" %(status)s"),
{'q_id': neutron_port_data['id'],
'status': status})
def _synchronize_lswitchports(self, ctx, lp_uuids, scan_missing=False):
if not lp_uuids and not scan_missing:
@ -457,8 +498,9 @@ class NsxSynchronizer():
external_net_db.ExternalNetwork,
(models_v2.Network.id ==
external_net_db.ExternalNetwork.network_id))]
ports = self._plugin._get_collection_query(
ctx, models_v2.Port, filters=filters)
ports = self._plugin._get_collection(
ctx, models_v2.Port, self._plugin._make_port_dict,
filters=filters)
for port in ports:
lswitchport = neutron_port_mappings.get(port['id'])
self.synchronize_port(
@ -599,13 +641,12 @@ class NsxSynchronizer():
# Get an admin context
ctx = context.get_admin_context()
# Synchronize with database
with ctx.session.begin(subtransactions=True):
self._synchronize_lswitches(ctx, ls_uuids,
scan_missing=scan_missing)
self._synchronize_lrouters(ctx, lr_uuids,
self._synchronize_lswitches(ctx, ls_uuids,
scan_missing=scan_missing)
self._synchronize_lrouters(ctx, lr_uuids,
scan_missing=scan_missing)
self._synchronize_lswitchports(ctx, lp_uuids,
scan_missing=scan_missing)
self._synchronize_lswitchports(ctx, lp_uuids,
scan_missing=scan_missing)
# Increase chunk counter
LOG.info(_("Synchronization for chunk %(chunk_num)d of "
"%(total_chunks)d performed"),