Add check to limit maximum value of max_rows

Currently 'glance-manage db purge' fails if given a
very large number for max_rows.

Moved and renamed validate_mysql_int() from
glance.common.utils to glance.db.sqlalchemy.api as
_validate_db_int() since it is related to database
only so that it can be used to validate max_rows
for maximum limit.

Closes-Bug: #1543937
Change-Id: Id16694807c180632c1785e9b1ebe8d1c79d885ab
This commit is contained in:
Dinesh Bhor 2016-02-16 01:36:15 -08:00 committed by dineshbhor
parent 6c7dea205e
commit 9338e5c046
4 changed files with 42 additions and 28 deletions

View File

@ -176,7 +176,10 @@ class DbCommands(object):
if max_rows < 1:
sys.exit(_("Minimal rows limit is 1."))
ctx = context.get_admin_context(show_deleted=True)
db_api.purge_deleted_rows(ctx, age_in_days, max_rows)
try:
db_api.purge_deleted_rows(ctx, age_in_days, max_rows)
except exception.Invalid as exc:
sys.exit(exc.msg)
class DbLegacyCommands(object):

View File

@ -548,31 +548,6 @@ def no_4byte_params(f):
return wrapper
def validate_mysql_int(*args, **kwargs):
"""
Make sure that all arguments are less than 2 ** 31 - 1.
This limitation is introduced because mysql stores INT in 4 bytes.
If the validation fails for some argument, exception.Invalid is raised with
appropriate information.
"""
max_int = (2 ** 31) - 1
for param in args:
if param > max_int:
msg = _("Value %(value)d out of range, "
"must not exceed %(max)d") % {"value": param,
"max": max_int}
raise exception.Invalid(msg)
for param_str in kwargs:
param = kwargs.get(param_str)
if param and param > max_int:
msg = _("'%(param)s' value out of range, "
"must not exceed %(max)d") % {"param": param_str,
"max": max_int}
raise exception.Invalid(msg)
def stash_conf_values():
"""
Make a copy of some of the current global CONF's settings.

View File

@ -105,6 +105,23 @@ def get_session(autocommit=True, expire_on_commit=False):
expire_on_commit=expire_on_commit)
def _validate_db_int(**kwargs):
"""Make sure that all arguments are less than or equal to 2 ** 31 - 1.
This limitation is introduced because databases stores INT in 4 bytes.
If the validation fails for some argument, exception.Invalid is raised with
appropriate information.
"""
max_int = (2 ** 31) - 1
for param_key, param_value in kwargs.items():
if param_value and param_value > max_int:
msg = _("'%(param)s' value out of range, "
"must not exceed %(max)d.") % {"param": param_key,
"max": max_int}
raise exception.Invalid(msg)
def clear_db_env():
"""
Unset global configuration variables for database.
@ -731,8 +748,8 @@ def _validate_image(values, mandatory_status=True):
raise exception.Invalid(msg)
# validate integer values to eliminate DBError on save
utils.validate_mysql_int(min_disk=values.get('min_disk'),
min_ram=values.get('min_ram'))
_validate_db_int(min_disk=values.get('min_disk'),
min_ram=values.get('min_ram'))
return values
@ -1273,6 +1290,9 @@ def purge_deleted_rows(context, age_in_days, max_rows, session=None):
Deletes rows of table images, table tasks and all dependent tables
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)

View File

@ -56,3 +56,19 @@ class DBCommandsTestCase(test_utils.BaseTestCase):
expected = ("Invalid int value for max_rows: "
"%(max_rows)s") % {'max_rows': max_rows}
self.assertEqual(expected, ex.code)
@mock.patch.object(db_api, 'purge_deleted_rows')
@mock.patch.object(context, 'get_admin_context')
def test_purge_max_rows(self, mock_context, mock_db_purge):
mock_context.return_value = self.context
value = (2 ** 31) - 1
self.commands.purge(age_in_days=1, max_rows=value)
mock_db_purge.assert_called_once_with(self.context, 1, value)
def test_purge_command_exceeded_maximum_rows(self):
# value(2 ** 31) is greater than max_rows(2147483647) by 1.
value = 2 ** 31
ex = self.assertRaises(SystemExit, self.commands.purge, age_in_days=1,
max_rows=value)
expected = "'max_rows' value out of range, must not exceed 2147483647."
self.assertEqual(expected, ex.code)