Skip to content

Commit

Permalink
SNOW-799381: improve error message when hitting ssl related error (#2074
Browse files Browse the repository at this point in the history
)
  • Loading branch information
sfc-gh-aling authored Oct 22, 2024
1 parent 8e2b757 commit 7ddbf31
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 4 deletions.
1 change: 1 addition & 0 deletions DESCRIPTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Source code is also available at: https://github.com/snowflakedb/snowflake-conne
# Release Notes

- v3.12.3(TBD)
- Improved the error message for SSL-related issues to provide clearer guidance when an SSL error occurs.
- Improved error message for SQL execution cancellations caused by timeout.

- v3.12.2(September 11,2024)
Expand Down
3 changes: 3 additions & 0 deletions src/snowflake/connector/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
from .config_manager import CONFIG_MANAGER, _get_default_connection_params
from .connection_diagnostic import ConnectionDiagnostic
from .constants import (
_CONNECTIVITY_ERR_MSG,
_DOMAIN_NAME_MAP,
ENV_VAR_PARTNER,
PARAMETER_AUTOCOMMIT,
Expand Down Expand Up @@ -1455,6 +1456,8 @@ def _authenticate(self, auth_instance: AuthByPlugin):
)
except OperationalError as auth_op:
if auth_op.errno == ER_FAILED_TO_CONNECT_TO_DB:
if _CONNECTIVITY_ERR_MSG in e.msg:
auth_op.msg += f"\n{_CONNECTIVITY_ERR_MSG}"
raise auth_op from e
logger.debug("Continuing authenticator specific timeout handling")
continue
Expand Down
6 changes: 6 additions & 0 deletions src/snowflake/connector/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,3 +428,9 @@ class IterUnit(Enum):


_DOMAIN_NAME_MAP = {_DEFAULT_HOSTNAME_TLD: "GLOBAL", _CHINA_HOSTNAME_TLD: "CHINA"}

_CONNECTIVITY_ERR_MSG = (
"Verify that the hostnames and port numbers in SYSTEM$ALLOWLIST are added to your firewall's allowed list."
"\nTo further troubleshoot your connection you may reference the following article: "
"https://docs.snowflake.com/en/user-guide/client-connectivity-troubleshooting/overview."
)
16 changes: 14 additions & 2 deletions src/snowflake/connector/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
urlparse,
)
from .constants import (
_CONNECTIVITY_ERR_MSG,
_SNOWFLAKE_HOST_SUFFIX_REGEX,
HTTP_HEADER_ACCEPT,
HTTP_HEADER_CONTENT_TYPE,
Expand Down Expand Up @@ -1134,8 +1135,19 @@ def _request_exec(
finally:
raw_ret.close() # ensure response is closed
except SSLError as se:
logger.debug("Hit non-retryable SSL error, %s", str(se))

msg = f"Hit non-retryable SSL error, {str(se)}.\n{_CONNECTIVITY_ERR_MSG}"
logger.debug(msg)
# the following code is for backward compatibility with old versions of python connector which calls
# self._handle_unknown_error to process SSLError
Error.errorhandler_wrapper(
self._connection,
None,
OperationalError,
{
"msg": msg,
"errno": ER_FAILED_TO_REQUEST,
},
)
except (
BadStatusLine,
ConnectionError,
Expand Down
23 changes: 22 additions & 1 deletion test/unit/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from __future__ import annotations

import json
import logging
import os
import stat
import sys
Expand Down Expand Up @@ -41,7 +42,11 @@
try: # pragma: no cover
from snowflake.connector.auth import AuthByUsrPwdMfa
from snowflake.connector.config_manager import CONFIG_MANAGER
from snowflake.connector.constants import ENV_VAR_PARTNER, QueryStatus
from snowflake.connector.constants import (
_CONNECTIVITY_ERR_MSG,
ENV_VAR_PARTNER,
QueryStatus,
)
except ImportError:
ENV_VAR_PARTNER = "SF_PARTNER"
QueryStatus = CONFIG_MANAGER = None
Expand Down Expand Up @@ -546,3 +551,19 @@ def test_request_guid():
and SnowflakeRestful.add_request_guid("https://test.abc.cn?a=b")
== "https://test.abc.cn?a=b"
)


@pytest.mark.skipolddriver
def test_ssl_error_hint(caplog):
from snowflake.connector.vendored.requests.exceptions import SSLError

with mock.patch(
"snowflake.connector.vendored.requests.sessions.Session.request",
side_effect=SSLError("SSL error"),
), caplog.at_level(logging.DEBUG):
with pytest.raises(OperationalError) as exc:
fake_connector()
assert _CONNECTIVITY_ERR_MSG in exc.value.msg and isinstance(
exc.value, OperationalError
)
assert "SSL error" in caplog.text and _CONNECTIVITY_ERR_MSG in caplog.text
8 changes: 7 additions & 1 deletion test/unit/test_util.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#
# Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved.
#
import pytest

from snowflake.connector._utils import _TrackedQueryCancellationTimer
try:
from snowflake.connector._utils import _TrackedQueryCancellationTimer
except ImportError:
pass

pytestmark = pytest.mark.skipolddriver


def test_timer():
Expand Down

0 comments on commit 7ddbf31

Please sign in to comment.