Merge "Mitigate OSSN-0075"
This commit is contained in:
commit
0a82f98084
@ -329,24 +329,17 @@ class DbCommands(object):
|
||||
metadata.db_export_metadefs(db_api.get_engine(),
|
||||
path)
|
||||
|
||||
@args('--age_in_days', type=int,
|
||||
help='Purge deleted rows older than age in days')
|
||||
@args('--max_rows', type=int,
|
||||
help='Limit number of records to delete')
|
||||
def purge(self, age_in_days=30, max_rows=100):
|
||||
"""Purge deleted rows older than a given age from glance tables."""
|
||||
def _purge(self, age_in_days, max_rows, purge_images_only=False):
|
||||
try:
|
||||
age_in_days = int(age_in_days)
|
||||
except ValueError:
|
||||
sys.exit(_("Invalid int value for age_in_days: "
|
||||
"%(age_in_days)s") % {'age_in_days': age_in_days})
|
||||
|
||||
try:
|
||||
max_rows = int(max_rows)
|
||||
except ValueError:
|
||||
sys.exit(_("Invalid int value for max_rows: "
|
||||
"%(max_rows)s") % {'max_rows': max_rows})
|
||||
|
||||
if age_in_days < 0:
|
||||
sys.exit(_("Must supply a non-negative value for age."))
|
||||
if age_in_days >= (int(time.time()) / 86400):
|
||||
@ -354,15 +347,34 @@ class DbCommands(object):
|
||||
if max_rows < 1:
|
||||
sys.exit(_("Minimal rows limit is 1."))
|
||||
ctx = context.get_admin_context(show_deleted=True)
|
||||
|
||||
try:
|
||||
db_api.purge_deleted_rows(ctx, age_in_days, max_rows)
|
||||
if purge_images_only:
|
||||
db_api.purge_deleted_rows_from_images(ctx, age_in_days,
|
||||
max_rows)
|
||||
else:
|
||||
db_api.purge_deleted_rows(ctx, age_in_days, max_rows)
|
||||
except exception.Invalid as exc:
|
||||
sys.exit(exc.msg)
|
||||
except db_exc.DBReferenceError:
|
||||
sys.exit(_("Purge command failed, check glance-manage"
|
||||
" logs for more details."))
|
||||
|
||||
@args('--age_in_days', type=int,
|
||||
help='Purge deleted rows older than age in days')
|
||||
@args('--max_rows', type=int,
|
||||
help='Limit number of records to delete')
|
||||
def purge(self, age_in_days=30, max_rows=100):
|
||||
"""Purge deleted rows older than a given age from glance tables."""
|
||||
self._purge(age_in_days, max_rows)
|
||||
|
||||
@args('--age_in_days', type=int,
|
||||
help='Purge deleted rows older than age in days')
|
||||
@args('--max_rows', type=int,
|
||||
help='Limit number of records to delete')
|
||||
def purge_images_table(self, age_in_days=30, max_rows=100):
|
||||
"""Purge deleted rows older than a given age from images table."""
|
||||
self._purge(age_in_days, max_rows, purge_images_only=True)
|
||||
|
||||
|
||||
class DbLegacyCommands(object):
|
||||
"""Class for managing the db using legacy commands"""
|
||||
|
@ -1322,6 +1322,11 @@ def purge_deleted_rows(context, age_in_days, max_rows, session=None):
|
||||
LOG.warning(_LW('Expected table %(tbl)s was not found in DB.'),
|
||||
{'tbl': tbl})
|
||||
else:
|
||||
# NOTE(abhishekk): To mitigate OSSN-0075 images records should be
|
||||
# purged with new ``purge-images-table`` command.
|
||||
if tbl == 'images':
|
||||
continue
|
||||
|
||||
tables.append(tbl)
|
||||
|
||||
for tbl in tables:
|
||||
@ -1354,6 +1359,50 @@ def purge_deleted_rows(context, age_in_days, max_rows, session=None):
|
||||
{'rows': rows, 'tbl': tbl})
|
||||
|
||||
|
||||
def purge_deleted_rows_from_images(context, age_in_days, max_rows,
|
||||
session=None):
|
||||
"""Purges soft deleted rows
|
||||
|
||||
Deletes rows of table images table according to given age for
|
||||
relevant models.
|
||||
"""
|
||||
# check max_rows for its maximum limit
|
||||
_validate_db_int(max_rows=max_rows)
|
||||
|
||||
session = session or get_session()
|
||||
metadata = MetaData(get_engine())
|
||||
deleted_age = timeutils.utcnow() - datetime.timedelta(days=age_in_days)
|
||||
|
||||
tbl = 'images'
|
||||
tab = Table(tbl, metadata, autoload=True)
|
||||
LOG.info(
|
||||
_LI('Purging deleted rows older than %(age_in_days)d day(s) '
|
||||
'from table %(tbl)s'),
|
||||
{'age_in_days': age_in_days, 'tbl': tbl})
|
||||
|
||||
column = tab.c.id
|
||||
deleted_at_column = tab.c.deleted_at
|
||||
|
||||
query_delete = sql.select(
|
||||
[column], deleted_at_column < deleted_age).order_by(
|
||||
deleted_at_column).limit(max_rows)
|
||||
|
||||
delete_statement = DeleteFromSelect(tab, query_delete, column)
|
||||
|
||||
try:
|
||||
with session.begin():
|
||||
result = session.execute(delete_statement)
|
||||
except db_exception.DBReferenceError as ex:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE('DBError detected when purging from '
|
||||
"%(tablename)s: %(error)s"),
|
||||
{'tablename': tbl, 'error': six.text_type(ex)})
|
||||
|
||||
rows = result.rowcount
|
||||
LOG.info(_LI('Deleted %(rows)d row(s) from table %(tbl)s'),
|
||||
{'rows': rows, 'tbl': tbl})
|
||||
|
||||
|
||||
def user_get_storage_usage(context, owner_id, image_id=None, session=None):
|
||||
_check_image_id(image_id)
|
||||
session = session or get_session()
|
||||
|
@ -1990,11 +1990,27 @@ class DBPurgeTests(test_utils.BaseTestCase):
|
||||
def test_db_purge(self):
|
||||
self.db_api.purge_deleted_rows(self.adm_context, 1, 5)
|
||||
images = self.db_api.image_get_all(self.adm_context)
|
||||
|
||||
# Verify that no records from images have been deleted
|
||||
# as images table will be purged using 'purge_images_table'
|
||||
# command.
|
||||
self.assertEqual(len(images), 3)
|
||||
tasks = self.db_api.task_get_all(self.adm_context)
|
||||
self.assertEqual(len(tasks), 2)
|
||||
|
||||
def test_db_purge_images_table(self):
|
||||
# purge records from images_tags table
|
||||
self.db_api.purge_deleted_rows(self.adm_context, 1, 5)
|
||||
|
||||
# purge records from images table
|
||||
self.db_api.purge_deleted_rows_from_images(self.adm_context, 1, 5)
|
||||
images = self.db_api.image_get_all(self.adm_context)
|
||||
|
||||
self.assertEqual(len(images), 2)
|
||||
tasks = self.db_api.task_get_all(self.adm_context)
|
||||
self.assertEqual(len(tasks), 2)
|
||||
|
||||
def test_purge_fk_constraint_failure(self):
|
||||
def test_purge_images_table_fk_constraint_failure(self):
|
||||
"""Test foreign key constraint failure
|
||||
|
||||
Test whether foreign key constraint failure during purge
|
||||
@ -2053,7 +2069,7 @@ class DBPurgeTests(test_utils.BaseTestCase):
|
||||
|
||||
# Purge all records deleted at least 10 days ago
|
||||
self.assertRaises(db_exception.DBReferenceError,
|
||||
db_api.purge_deleted_rows,
|
||||
db_api.purge_deleted_rows_from_images,
|
||||
self.adm_context,
|
||||
age_in_days=10,
|
||||
max_rows=50)
|
||||
|
Loading…
x
Reference in New Issue
Block a user