Simplify delete_health_monitor() using cascades

Currently delete_health_monitor() emulates behaviour of
cascade deletion: when a HealthMonitor instance is deleted,
all corresponding PoolMonitorAssociations are queried and
deleted one by one. This can be done automatically by means
of SQLAlchemy if we set proper cascade flags on the relationship
between HealthMonitor and PoolMonitorAssociations models.

Fixes bug 1169107.

Change-Id: I674c381192719a56433f67be53a32203c36ebe2b
This commit is contained in:
Roman Podolyaka
2013-04-15 18:10:07 +03:00
parent 765baf8532
commit ee50162b27
3 changed files with 47 additions and 15 deletions

View File

@@ -127,6 +127,12 @@ class HealthMonitor(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
status = sa.Column(sa.String(16), nullable=False) status = sa.Column(sa.String(16), nullable=False)
admin_state_up = sa.Column(sa.Boolean(), nullable=False) admin_state_up = sa.Column(sa.Boolean(), nullable=False)
pools = orm.relationship(
"PoolMonitorAssociation",
backref="healthmonitor",
cascade="all"
)
class PoolMonitorAssociation(model_base.BASEV2): class PoolMonitorAssociation(model_base.BASEV2):
""" """
@@ -139,8 +145,6 @@ class PoolMonitorAssociation(model_base.BASEV2):
monitor_id = sa.Column(sa.String(36), monitor_id = sa.Column(sa.String(36),
sa.ForeignKey("healthmonitors.id"), sa.ForeignKey("healthmonitors.id"),
primary_key=True) primary_key=True)
monitor = orm.relationship("HealthMonitor",
backref="pools_poolmonitorassociations")
class LoadBalancerPluginDb(LoadBalancerPluginBase): class LoadBalancerPluginDb(LoadBalancerPluginBase):
@@ -605,7 +609,7 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase):
assoc = PoolMonitorAssociation(pool_id=pool_id, assoc = PoolMonitorAssociation(pool_id=pool_id,
monitor_id=monitor_id) monitor_id=monitor_id)
assoc.monitor = monitor assoc.healthmonitor = monitor
pool.monitors.append(assoc) pool.monitors.append(assoc)
monitors = [] monitors = []
@@ -746,14 +750,6 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase):
def delete_health_monitor(self, context, id): def delete_health_monitor(self, context, id):
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
assoc_qry = context.session.query(PoolMonitorAssociation)
pool_qry = context.session.query(Pool)
for assoc in assoc_qry.filter_by(monitor_id=id).all():
try:
pool = pool_qry.filter_by(id=assoc['pool_id']).one()
except exc.NoResultFound:
raise loadbalancer.PoolNotFound(pool_id=pool['id'])
pool.monitors.remove(assoc)
monitor_db = self._get_resource(context, HealthMonitor, id) monitor_db = self._get_resource(context, HealthMonitor, id)
context.session.delete(monitor_db) context.session.delete(monitor_db)

View File

@@ -79,8 +79,8 @@ class LoadBalancerCallbacks(object):
m.status = constants.ACTIVE m.status = constants.ACTIVE
for hm in pool.monitors: for hm in pool.monitors:
if hm.monitor.status in ACTIVE_PENDING: if hm.healthmonitor.status in ACTIVE_PENDING:
hm.monitor.status = constants.ACTIVE hm.healthmonitor.status = constants.ACTIVE
if (pool.status != constants.ACTIVE if (pool.status != constants.ACTIVE
or pool.vip.status != constants.ACTIVE): or pool.vip.status != constants.ACTIVE):
@@ -104,9 +104,9 @@ class LoadBalancerCallbacks(object):
for m in pool.members if m.status == constants.ACTIVE for m in pool.members if m.status == constants.ACTIVE
] ]
retval['healthmonitors'] = [ retval['healthmonitors'] = [
self.plugin._make_health_monitor_dict(hm.monitor) self.plugin._make_health_monitor_dict(hm.healthmonitor)
for hm in pool.monitors for hm in pool.monitors
if hm.monitor.status == constants.ACTIVE if hm.healthmonitor.status == constants.ACTIVE
] ]
return retval return retval

View File

@@ -836,6 +836,42 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
res = req.get_response(self.ext_api) res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, 204) self.assertEqual(res.status_int, 204)
def test_delete_healthmonitor_cascade_deletion_of_associations(self):
with self.health_monitor(type='HTTP', no_delete=True) as monitor:
with self.pool() as pool:
data = {
'health_monitor': {
'id': monitor['health_monitor']['id'],
'tenant_id': self._tenant_id
}
}
req = self.new_create_request(
'pools',
data,
fmt=self.fmt,
id=pool['pool']['id'],
subresource='health_monitors')
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, 201)
ctx = context.get_admin_context()
# check if we actually have corresponding Pool associations
qry = ctx.session.query(ldb.PoolMonitorAssociation)
qry = qry.filter_by(monitor_id=monitor['health_monitor']['id'])
self.assertTrue(qry.all())
# delete the HealthMonitor instance
req = self.new_delete_request(
'health_monitors',
monitor['health_monitor']['id']
)
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, 204)
# check if all corresponding Pool associations are deleted
qry = ctx.session.query(ldb.PoolMonitorAssociation)
qry = qry.filter_by(monitor_id=monitor['health_monitor']['id'])
self.assertFalse(qry.all())
def test_show_healthmonitor(self): def test_show_healthmonitor(self):
with self.health_monitor() as monitor: with self.health_monitor() as monitor:
keys = [('type', "TCP"), keys = [('type', "TCP"),