Add router precommit events

This adds PRECOMMIT callback events to the basic router DB
operations (create/update/delete). These are leveraged by the
dependent patch for flavor and provider processing.

This also adds a small context manager to the callback manager
to make it simple to reraise the original first exception raised
during the callback processing to avoid littering the exception
unpacking logic around every 'notify' call.

Partially-Implements: bp/multi-l3-backends
Change-Id: I0479f0054f9c22f8021531c54b138179f9688de5
This commit is contained in:
Kevin Benton 2016-04-30 16:43:00 -07:00
parent 2862c261d3
commit 6bce4d5ea9
2 changed files with 74 additions and 3 deletions

View File

@ -216,14 +216,18 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
# pre-generate id so it will be available when
# configuring external gw port
status = router.get('status', n_const.ROUTER_STATUS_ACTIVE)
router_db = Router(id=(router.get('id') or
uuidutils.generate_uuid()),
tenant_id=tenant_id,
router.setdefault('id', uuidutils.generate_uuid())
router['tenant_id'] = tenant_id
router_db = Router(id=router['id'],
tenant_id=router['tenant_id'],
name=router['name'],
admin_state_up=router['admin_state_up'],
status=status,
description=router.get('description'))
context.session.add(router_db)
registry.notify(resources.ROUTER, events.PRECOMMIT_CREATE,
self, context=context, router=router,
router_id=router['id'], router_db=router_db)
return router_db
def create_router(self, context, router):
@ -245,8 +249,13 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
"""Update the DB object."""
with context.session.begin(subtransactions=True):
router_db = self._get_router(context, router_id)
old_router = self._make_router_dict(router_db)
if data:
router_db.update(data)
registry.notify(resources.ROUTER, events.PRECOMMIT_UPDATE,
self, context=context, router_id=router_id,
router=data, router_db=router_db,
old_router=old_router)
return router_db
def update_router(self, context, id, router):
@ -521,6 +530,8 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
rp.port.id,
l3_port_check=False)
with context.session.begin(subtransactions=True):
registry.notify(resources.ROUTER, events.PRECOMMIT_DELETE,
self, context=context, router_id=id)
context.session.delete(router)
def get_router(self, context, id, fields=None):

View File

@ -3030,6 +3030,66 @@ class L3AgentDbTestCaseBase(L3NatTestCaseMixin):
def test_floatingips_op_agent(self):
self._test_notify_op_agent(self._test_floatingips_op_agent)
def test_router_create_precommit_event(self):
nset = lambda *a, **k: setattr(k['router_db'], 'name', 'hello')
registry.subscribe(nset, resources.ROUTER, events.PRECOMMIT_CREATE)
with self.router() as r:
self.assertEqual('hello', r['router']['name'])
def test_router_create_event_exception_preserved(self):
# this exception should be propagated out of the callback and
# converted into its API equivalent of 404
e404 = mock.Mock(side_effect=l3.RouterNotFound(router_id='1'))
registry.subscribe(e404, resources.ROUTER, events.PRECOMMIT_CREATE)
res = self._create_router(self.fmt, 'tenid')
self.assertEqual(exc.HTTPNotFound.code, res.status_int)
# make sure nothing committed
body = self._list('routers')
self.assertFalse(body['routers'])
def test_router_update_precommit_event(self):
nset = lambda *a, **k: setattr(k['router_db'], 'name',
k['old_router']['name'] + '_ha!')
registry.subscribe(nset, resources.ROUTER, events.PRECOMMIT_UPDATE)
with self.router(name='original') as r:
update = self._update('routers', r['router']['id'],
{'router': {'name': 'hi'}})
# our rude callback should have changed the name to the original
# plus some extra
self.assertEqual('original_ha!', update['router']['name'])
def test_router_update_event_exception_preserved(self):
# this exception should be propagated out of the callback and
# converted into its API equivalent of 404
e404 = mock.Mock(side_effect=l3.RouterNotFound(router_id='1'))
registry.subscribe(e404, resources.ROUTER, events.PRECOMMIT_UPDATE)
with self.router(name='a') as r:
self._update('routers', r['router']['id'],
{'router': {'name': 'hi'}},
expected_code=exc.HTTPNotFound.code)
# ensure it stopped the commit
new = self._show('routers', r['router']['id'])
self.assertEqual('a', new['router']['name'])
def test_router_delete_precommit_event(self):
deleted = []
auditor = lambda *a, **k: deleted.append(k['router_id'])
registry.subscribe(auditor, resources.ROUTER, events.PRECOMMIT_DELETE)
with self.router() as r:
self._delete('routers', r['router']['id'])
self.assertEqual([r['router']['id']], deleted)
def test_router_delete_event_exception_preserved(self):
# this exception should be propagated out of the callback and
# converted into its API equivalent of 409
e409 = mock.Mock(side_effect=l3.RouterInUse(router_id='1'))
registry.subscribe(e409, resources.ROUTER, events.PRECOMMIT_DELETE)
with self.router() as r:
self._delete('routers', r['router']['id'],
expected_code=exc.HTTPConflict.code)
# ensure it stopped the commit
self.assertTrue(self._show('routers', r['router']['id']))
class L3BaseForIntTests(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):