summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Finucane <stephenfin@redhat.com>2023-03-22 12:05:06 +0000
committerStephen Finucane <stephenfin@redhat.com>2023-04-17 10:17:44 +0100
commit7d62b3664e4acad9161d849a111bdb8b4d707f61 (patch)
tree4ea11f3b3e7cc419c009d2457fac5d85be9f4b52
parent04acea8cbbf7a989e07dad66fd40ac1d3ba4e0d2 (diff)
downloadoslo-db-7d62b3664e4acad9161d849a111bdb8b4d707f61.tar.gz
Match exceptions with multiple lines
We were creating regexes without the DOTALL flag, which meant '.' wasn't matching newlines. This meant exceptions that contained multiple lines would not be caught. For example, in my environment where Kerberos is used, I see the following otherwise harmless message: (psycopg2.OperationalError) connection to server at "localhost" (::1), port 5432 failed: could not initiate GSSAPI security context: No credentials were supplied, or the credentials were unavailable or inaccessible: Configuration file does not specify default realm connection to server at "localhost" (::1), port 5432 failed: FATAL: database "non_existent_database" does not exist The presence of that newline causes our matchers to fail and the exception is not wrapped. Correct this. In the meanwhile, we reformat the function that does the wrapping to make it a little flatter. This was difficult to modify (for debugging purposes) due to the level of indentation. Change-Id: I5396a5a3272e6984954d819cfc71507283c775db Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
-rw-r--r--oslo_db/sqlalchemy/exc_filters.py89
1 files changed, 45 insertions, 44 deletions
diff --git a/oslo_db/sqlalchemy/exc_filters.py b/oslo_db/sqlalchemy/exc_filters.py
index 420b5c7..4ad7721 100644
--- a/oslo_db/sqlalchemy/exc_filters.py
+++ b/oslo_db/sqlalchemy/exc_filters.py
@@ -44,7 +44,7 @@ def filters(dbname, exception_type, regex):
"""
def _receive(fn):
_registry[dbname][exception_type].extend(
- (fn, re.compile(reg))
+ (fn, re.compile(reg, re.DOTALL))
for reg in
((regex,) if not isinstance(regex, tuple) else regex)
)
@@ -432,50 +432,51 @@ def handler(context):
dialect = compat.dialect_from_exception_context(context)
for per_dialect in _dialect_registries(dialect):
- for exc in (
- context.sqlalchemy_exception,
- context.original_exception):
+ for exc in (context.sqlalchemy_exception, context.original_exception):
for super_ in exc.__class__.__mro__:
- if super_ in per_dialect:
- regexp_reg = per_dialect[super_]
- for fn, regexp in regexp_reg:
- match = regexp.match(exc.args[0])
- if match:
- try:
- fn(
- exc,
- match,
- dialect.name,
- context.is_disconnect)
- except exception.DBError as dbe:
- if (
- context.connection is not None and
- not context.connection.closed and
- not context.connection.invalidated and
- ROLLBACK_CAUSE_KEY
- in context.connection.info
- ):
- dbe.cause = \
- context.connection.info.pop(
- ROLLBACK_CAUSE_KEY)
-
- if isinstance(
- dbe, exception.DBConnectionError):
- context.is_disconnect = True
-
- # new in 2.0.5
- if (
- hasattr(context, "is_pre_ping") and
- context.is_pre_ping
- ):
- # if this is a pre-ping, need to
- # integrate with the built
- # in pre-ping handler that doesnt know
- # about DBConnectionError, just needs
- # the updated status
- return None
-
- return dbe
+ if super_ not in per_dialect:
+ continue
+
+ regexp_reg = per_dialect[super_]
+ for fn, regexp in regexp_reg:
+ match = regexp.match(exc.args[0])
+ if not match:
+ continue
+
+ try:
+ fn(
+ exc,
+ match,
+ dialect.name,
+ context.is_disconnect,
+ )
+ except exception.DBError as dbe:
+ if (
+ context.connection is not None and
+ not context.connection.closed and
+ not context.connection.invalidated and
+ ROLLBACK_CAUSE_KEY in context.connection.info
+ ):
+ dbe.cause = context.connection.info.pop(
+ ROLLBACK_CAUSE_KEY,
+ )
+
+ if isinstance(dbe, exception.DBConnectionError):
+ context.is_disconnect = True
+
+ # new in 2.0.5
+ if (
+ hasattr(context, "is_pre_ping") and
+ context.is_pre_ping
+ ):
+ # if this is a pre-ping, need to
+ # integrate with the built
+ # in pre-ping handler that doesnt know
+ # about DBConnectionError, just needs
+ # the updated status
+ return None
+
+ return dbe
def register_engine(engine):