Skip to content

Commit

Permalink
Don't try to resolve hostnames when option is disabled
Browse files Browse the repository at this point in the history
  • Loading branch information
kaklakariada committed Sep 9, 2024
1 parent e019035 commit 5ffcbb1
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 9 deletions.
25 changes: 16 additions & 9 deletions pyexasol/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
class Host(NamedTuple):
"""This represents a resolved host name with its IP address and port number."""
hostname: str
ip_address: str
ip_address: Optional[str]
port: int
fingerprint: Optional[str]

Expand Down Expand Up @@ -670,10 +670,7 @@ def _init_ws(self):
try:
self._ws = self._create_websocket_connection(hostname, ipaddr, port)
except Exception as e:
self.logger.debug(f'Failed to connect [{ipaddr}:{port}]: {e}')

failed_attempts += 1

if failed_attempts == len(dsn_items):
raise ExaConnectionFailedError(self, 'Could not connect to Exasol: ' + str(e)) from e
else:
Expand All @@ -698,11 +695,17 @@ def _create_websocket_connection(self, hostname:str, ipaddr:str, port:int) -> we

connection_string = self._get_websocket_connection_string(hostname, ipaddr, port)
self.logger.debug(f"Connection attempt {connection_string}")
return websocket.create_connection(connection_string, **ws_options)

try:
return websocket.create_connection(connection_string, **ws_options)
except Exception as e:
self.logger.debug(f'Failed to connect [{connection_string}]: {e}')
raise e

def _get_websocket_connection_string(self, hostname:str, ipaddr:str, port:int) -> str:
host = ipaddr if self.options["resolve_hostnames"] else hostname
def _get_websocket_connection_string(self, hostname:str, ipaddr:Optional[str], port:int) -> str:
host = hostname
if self.options["resolve_hostnames"]:
assert ipaddr is not None
host = ipaddr
if self.options["encryption"]:
return f"wss://{host}:{port}"
else:
Expand Down Expand Up @@ -810,7 +813,11 @@ def _process_dsn(self, dsn: str) -> list[Host]:
result.extend(self._resolve_hostname(hostname, current_port, current_fingerprint))
# Just a single hostname or single IP address
else:
result.extend(self._resolve_hostname(m.group('hostname_prefix'), current_port, current_fingerprint))
hostname = m.group('hostname_prefix')
if self.options["resolve_hostnames"]:
result.extend(self._resolve_hostname(hostname, current_port, current_fingerprint))
else:
result.append(Host(hostname, None, current_port, current_fingerprint))

random.shuffle(result)

Expand Down
12 changes: 12 additions & 0 deletions test/integration/connection_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ def test_process_empty_dsn_fails(connection_mock, empty_dsn):
with pytest.raises(ExaConnectionDsnError, match="Connection string is empty"):
connection_mock.process_dsn(empty_dsn)

def test_process_dsn_resolves_hostname_to_ip_address(connection_mock):
connection_mock.simulate_resolve_hostnames([("host1", [], ["ip1"])])
actual = connection_mock.process_dsn("host1:1234")
expected = [Host("host1", "ip1", 1234, None)]
assert expected == actual

def test_process_dsn_does_not_resolve_hostname(connection_mock):
connection_mock.connection.options["resolve_hostnames"] = False
actual = connection_mock.process_dsn("host1:1234")
expected = [Host("host1", None, 1234, None)]
assert expected == actual

def test_process_dsn_shuffles_hosts(connection_mock):
dsn = "host1:1234,host2:4321"
def resolve_hostname(con):
Expand Down

0 comments on commit 5ffcbb1

Please sign in to comment.