Provide user friendly message for FK failure

'cinder-manage db purge' command fails with DBReferenceError due
to FK constraint failure and exits with stack-trace on the command
prompt.

Made changes to give user friendly message to the user as well as
log appropriate error message in cinder-manage logs instead of
stack-trace and exit with non-zero code to notify user about
the failure.

Closes-Bug: #1542169
Change-Id: I24476af70b45150b9f9e4e5d874f46fd4c07e680
This commit is contained in:
Abhishek Kekane 2016-02-11 04:30:47 -08:00
parent 092618aab8
commit dc70025072
3 changed files with 46 additions and 4 deletions

View File

@ -60,6 +60,7 @@ import os
import sys
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_db.sqlalchemy import migration
from oslo_log import log as logging
import oslo_messaging as messaging
@ -229,7 +230,13 @@ class DbCommands(object):
print(_("Must supply a positive, non-zero value for age"))
sys.exit(1)
ctxt = context.get_admin_context()
try:
db.purge_deleted_rows(ctxt, age_in_days)
except db_exc.DBReferenceError:
print(_("Purge command failed, check cinder-manage "
"logs for more details."))
sys.exit(1)
class VersionCommands(object):

View File

@ -4265,9 +4265,10 @@ def purge_deleted_rows(context, age_in_days):
result = session.execute(
t.delete()
.where(t.c.deleted_at < deleted_age))
except db_exc.DBReferenceError:
LOG.exception(_LE('DBError detected when purging from '
'table=%(table)s'), {'table': table})
except db_exc.DBReferenceError as ex:
LOG.error(_LE('DBError detected when purging from '
'%(tablename)s: %(error)s.'),
{'tablename': table, 'error': six.text_type(ex)})
raise
rows_purged = result.rowcount

View File

@ -18,7 +18,9 @@
import datetime
import uuid
from oslo_db import exception as db_exc
from oslo_utils import timeutils
from sqlalchemy.dialects import sqlite
from cinder import context
from cinder import db
@ -100,3 +102,35 @@ class PurgeDeletedTest(test.TestCase):
self.assertRaises(exception.InvalidParameterValue,
db.purge_deleted_rows, self.context,
age_in_days=-1)
def test_purge_deleted_rows_integrity_failure(self):
dialect = self.engine.url.get_dialect()
if dialect == sqlite.dialect:
# We're seeing issues with foreign key support in SQLite 3.6.20
# SQLAlchemy doesn't support it at all with < SQLite 3.6.19
# It works fine in SQLite 3.7.
# So return early to skip this test if running SQLite < 3.7
import sqlite3
tup = sqlite3.sqlite_version_info
if tup[0] < 3 or (tup[0] == 3 and tup[1] < 7):
self.skipTest(
'sqlite version too old for reliable SQLA foreign_keys')
self.conn.execute("PRAGMA foreign_keys = ON")
# add new entry in volume and volume_admin_metadata for
# integrity check
uuid_str = uuid.uuid4().hex
ins_stmt = self.volumes.insert().values(id=uuid_str)
self.conn.execute(ins_stmt)
ins_stmt = self.vm.insert().values(volume_id=uuid_str)
self.conn.execute(ins_stmt)
# set volume record to deleted 20 days ago
old = timeutils.utcnow() - datetime.timedelta(days=20)
make_old = self.volumes.update().where(
self.volumes.c.id.in_([uuid_str])).values(deleted_at=old)
self.conn.execute(make_old)
# Verify that purge_deleted_rows fails due to Foreign Key constraint
self.assertRaises(db_exc.DBReferenceError, db.purge_deleted_rows,
self.context, age_in_days=10)