Fix db purge for volume_types FK constraint

db purge command raises FK constraint while purging volume_types
and volume_type_projects deleted rows.
Delete volume_type_projects records before deleting volume_types
to solve this issue.

Change-Id: I46d3c7559c58e979e6227825ed0b2e21158415c2
Closes-Bug: #1589806
This commit is contained in:
Ravi Jethani 2016-06-06 15:15:58 +05:30
parent 1bc0da2034
commit e9b928d669
2 changed files with 68 additions and 19 deletions

View File

@ -4453,9 +4453,12 @@ def purge_deleted_rows(context, age_in_days):
and hasattr(model_class, "deleted"):
tables.append(model_class.__tablename__)
# Reorder the list so the volumes table is last to avoid FK constraints
tables.remove("volumes")
tables.append("volumes")
# Reorder the list so the volumes and volume_types tables are last
# to avoid FK constraints
for table in ("volume_types", "volumes"):
tables.remove(table)
tables.append(table)
for table in tables:
t = Table(table, metadata, autoload=True)
LOG.info(_LI('Purging deleted rows older than age=%(age)d days '

View File

@ -44,6 +44,13 @@ class PurgeDeletedTest(test.TestCase):
# The volume_metadata table has a FK of volume_id
self.vm = sqlalchemyutils.get_table(
self.engine, "volume_metadata")
self.vol_types = sqlalchemyutils.get_table(
self.engine, "volume_types")
# The volume_type_projects table has a FK of volume_type_id
self.vol_type_proj = sqlalchemyutils.get_table(
self.engine, "volume_type_projects")
self.uuidstrs = []
for unused in range(6):
self.uuidstrs.append(uuid.uuid4().hex)
@ -53,43 +60,82 @@ class PurgeDeletedTest(test.TestCase):
self.conn.execute(ins_stmt)
ins_stmt = self.vm.insert().values(volume_id=uuidstr)
self.conn.execute(ins_stmt)
ins_stmt = self.vol_types.insert().values(id=uuidstr)
self.conn.execute(ins_stmt)
ins_stmt = self.vol_type_proj.insert().\
values(volume_type_id=uuidstr)
self.conn.execute(ins_stmt)
# Set 4 of them deleted, 2 are 60 days ago, 2 are 20 days ago
old = timeutils.utcnow() - datetime.timedelta(days=20)
older = timeutils.utcnow() - datetime.timedelta(days=60)
make_old = self.volumes.update().\
make_vol_old = self.volumes.update().\
where(self.volumes.c.id.in_(self.uuidstrs[1:3]))\
.values(deleted_at=old)
make_older = self.volumes.update().\
make_vol_older = self.volumes.update().\
where(self.volumes.c.id.in_(self.uuidstrs[4:6]))\
.values(deleted_at=older)
make_meta_old = self.vm.update().\
make_vol_meta_old = self.vm.update().\
where(self.vm.c.volume_id.in_(self.uuidstrs[1:3]))\
.values(deleted_at=old)
make_meta_older = self.vm.update().\
make_vol_meta_older = self.vm.update().\
where(self.vm.c.volume_id.in_(self.uuidstrs[4:6]))\
.values(deleted_at=older)
self.conn.execute(make_old)
self.conn.execute(make_older)
self.conn.execute(make_meta_old)
self.conn.execute(make_meta_older)
make_vol_types_old = self.vol_types.update().\
where(self.vol_types.c.id.in_(self.uuidstrs[1:3]))\
.values(deleted_at=old)
make_vol_types_older = self.vol_types.update().\
where(self.vol_types.c.id.in_(self.uuidstrs[4:6]))\
.values(deleted_at=older)
make_vol_type_proj_old = self.vol_type_proj.update().\
where(self.vol_type_proj.c.volume_type_id.in_(self.uuidstrs[1:3]))\
.values(deleted_at=old)
make_vol_type_proj_older = self.vol_type_proj.update().\
where(self.vol_type_proj.c.volume_type_id.in_(self.uuidstrs[4:6]))\
.values(deleted_at=older)
self.conn.execute(make_vol_old)
self.conn.execute(make_vol_older)
self.conn.execute(make_vol_meta_old)
self.conn.execute(make_vol_meta_older)
self.conn.execute(make_vol_types_old)
self.conn.execute(make_vol_types_older)
self.conn.execute(make_vol_type_proj_old)
self.conn.execute(make_vol_type_proj_older)
def test_purge_deleted_rows_old(self):
# Purge at 30 days old, should only delete 2 rows
db.purge_deleted_rows(self.context, age_in_days=30)
rows = self.session.query(self.volumes).count()
meta_rows = self.session.query(self.vm).count()
vol_rows = self.session.query(self.volumes).count()
vol_meta_rows = self.session.query(self.vm).count()
vol_type_rows = self.session.query(self.vol_types).count()
vol_type_proj_rows = self.session.query(self.vol_type_proj).count()
# Verify that we only deleted 2
self.assertEqual(4, rows)
self.assertEqual(4, meta_rows)
self.assertEqual(4, vol_rows)
self.assertEqual(4, vol_meta_rows)
self.assertEqual(4, vol_type_rows)
self.assertEqual(4, vol_type_proj_rows)
def test_purge_deleted_rows_older(self):
# Purge at 10 days old now, should delete 2 more rows
db.purge_deleted_rows(self.context, age_in_days=10)
rows = self.session.query(self.volumes).count()
meta_rows = self.session.query(self.vm).count()
vol_rows = self.session.query(self.volumes).count()
vol_meta_rows = self.session.query(self.vm).count()
vol_type_rows = self.session.query(self.vol_types).count()
vol_type_proj_rows = self.session.query(self.vol_type_proj).count()
# Verify that we only have 2 rows now
self.assertEqual(2, rows)
self.assertEqual(2, meta_rows)
self.assertEqual(2, vol_rows)
self.assertEqual(2, vol_meta_rows)
self.assertEqual(2, vol_type_rows)
self.assertEqual(2, vol_type_proj_rows)
def test_purge_deleted_rows_bad_args(self):
# Test with no age argument