Skip to content

Commit 1d28ab9

Browse files
chore: working code path
1 parent 62e1ad4 commit 1d28ab9

File tree

6 files changed

+55
-16
lines changed

6 files changed

+55
-16
lines changed

google/cloud/sql/connector/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@
1818
from google.cloud.sql.connector.connector import create_async_connector
1919
from google.cloud.sql.connector.enums import IPTypes
2020
from google.cloud.sql.connector.enums import RefreshStrategy
21+
from google.cloud.sql.connector.resolver import DefaultResolver
22+
from google.cloud.sql.connector.resolver import DnsResolver
2123
from google.cloud.sql.connector.version import __version__
2224

2325
__all__ = [
2426
"__version__",
2527
"create_async_connector",
2628
"Connector",
29+
"DefaultResolver",
30+
"DnsResolver",
2731
"IPTypes",
2832
"RefreshStrategy",
2933
]

google/cloud/sql/connector/connection_info.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ async def create_ssl_context(self, enable_iam_auth: bool = False) -> ssl.SSLCont
5757
return self.context
5858
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
5959

60+
# update ssl.PROTOCOL_TLS_CLIENT default
61+
context.check_hostname = False
62+
6063
# TODO: remove if/else when Python 3.10 is min version. PEP 644 has been
6164
# implemented. The ssl module requires OpenSSL 1.1.1 or newer.
6265
# verify OpenSSL version supports TLSv1.3

google/cloud/sql/connector/connector.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
import google.cloud.sql.connector.pg8000 as pg8000
3838
import google.cloud.sql.connector.pymysql as pymysql
3939
import google.cloud.sql.connector.pytds as pytds
40+
from google.cloud.sql.connector.resolver import DefaultResolver
41+
from google.cloud.sql.connector.resolver import DnsResolver
4042
from google.cloud.sql.connector.utils import format_database_user
4143
from google.cloud.sql.connector.utils import generate_keys
4244

@@ -63,6 +65,7 @@ def __init__(
6365
user_agent: Optional[str] = None,
6466
universe_domain: Optional[str] = None,
6567
refresh_strategy: str | RefreshStrategy = RefreshStrategy.BACKGROUND,
68+
resolver: DefaultResolver | DnsResolver = DefaultResolver,
6669
) -> None:
6770
"""Initializes a Connector instance.
6871
@@ -104,6 +107,12 @@ def __init__(
104107
of the following: RefreshStrategy.LAZY ("LAZY") or
105108
RefreshStrategy.BACKGROUND ("BACKGROUND").
106109
Default: RefreshStrategy.BACKGROUND
110+
resolver (DefaultResolver | DnsResolver): The class name of the
111+
resolver to use for resolving the Cloud SQL instance connection
112+
name. To resolve a DNS record to an instance connection name, use
113+
DnsResolver.
114+
Default: DefaultResolver
115+
107116
"""
108117
# if refresh_strategy is str, convert to RefreshStrategy enum
109118
if isinstance(refresh_strategy, str):
@@ -157,6 +166,7 @@ def __init__(
157166
self._enable_iam_auth = enable_iam_auth
158167
self._quota_project = quota_project
159168
self._user_agent = user_agent
169+
self._resolver = resolver()
160170
# if ip_type is str, convert to IPTypes enum
161171
if isinstance(ip_type, str):
162172
ip_type = IPTypes._from_str(ip_type)
@@ -269,13 +279,14 @@ async def connect_async(
269279
if (instance_connection_string, enable_iam_auth) in self._cache:
270280
cache = self._cache[(instance_connection_string, enable_iam_auth)]
271281
else:
282+
conn_name = await self._resolver.resolve(instance_connection_string)
272283
if self._refresh_strategy == RefreshStrategy.LAZY:
273284
logger.debug(
274285
f"['{instance_connection_string}']: Refresh strategy is set"
275286
" to lazy refresh"
276287
)
277288
cache = LazyRefreshCache(
278-
instance_connection_string,
289+
conn_name,
279290
self._client,
280291
self._keys,
281292
enable_iam_auth,
@@ -286,7 +297,7 @@ async def connect_async(
286297
" to backgound refresh"
287298
)
288299
cache = RefreshAheadCache(
289-
instance_connection_string,
300+
conn_name,
290301
self._client,
291302
self._keys,
292303
enable_iam_auth,

google/cloud/sql/connector/exceptions.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,10 @@ class IncompatibleDriverError(Exception):
7070
Exception to be raised when the database driver given is for the wrong
7171
database engine. (i.e. asyncpg for a MySQL database)
7272
"""
73+
74+
75+
class DnsResolutionError(Exception):
76+
"""
77+
Exception to be raised when an instance connection name can not be resolved
78+
from a DNS record.
79+
"""

google/cloud/sql/connector/instance.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
from google.cloud.sql.connector.client import CloudSQLClient
2828
from google.cloud.sql.connector.connection_info import ConnectionInfo
29-
from google.cloud.sql.connector.connection_name import _parse_instance_connection_name
29+
from google.cloud.sql.connector.connection_name import ConnectionName
3030
from google.cloud.sql.connector.exceptions import RefreshNotValidError
3131
from google.cloud.sql.connector.rate_limiter import AsyncRateLimiter
3232
from google.cloud.sql.connector.refresh_utils import _is_valid
@@ -47,25 +47,23 @@ class RefreshAheadCache:
4747

4848
def __init__(
4949
self,
50-
instance_connection_string: str,
50+
conn_name: ConnectionName,
5151
client: CloudSQLClient,
5252
keys: asyncio.Future,
5353
enable_iam_auth: bool = False,
5454
) -> None:
5555
"""Initializes a RefreshAheadCache instance.
5656
5757
Args:
58-
instance_connection_string (str): The Cloud SQL Instance's
59-
connection string (also known as an instance connection name).
58+
conn_name (ConnectionName): The Cloud SQL Instance's
59+
connection name.
6060
client (CloudSQLClient): The Cloud SQL Client instance.
6161
keys (asyncio.Future): A future to the client's public-private key
6262
pair.
6363
enable_iam_auth (bool): Enables automatic IAM database authentication
6464
(Postgres and MySQL) as the default authentication method for all
6565
connections.
6666
"""
67-
# validate and parse instance connection name
68-
conn_name = _parse_instance_connection_name(instance_connection_string)
6967
self._project, self._region, self._instance = (
7068
conn_name.project,
7169
conn_name.region,

google/cloud/sql/connector/resolver.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@
1414

1515
from dns.asyncresolver import Resolver
1616

17-
from google.cloud.sql.connector.instance import _parse_instance_connection_name
17+
from google.cloud.sql.connector.connection_name import _parse_instance_connection_name
18+
from google.cloud.sql.connector.exceptions import DnsResolutionError
1819

1920

2021
class DefaultResolver:
2122
"""DefaultResolver simply validates and parses instance connection name."""
2223

23-
async def resolve(connection_name: str) -> str:
24-
pass
24+
async def resolve(self, connection_name: str) -> str:
25+
return _parse_instance_connection_name(connection_name)
2526

2627

2728
class DnsResolver(Resolver):
@@ -30,8 +31,23 @@ class DnsResolver(Resolver):
3031
TXT records in DNS.
3132
"""
3233

33-
pass
34-
35-
36-
async def resolve(dns: str) -> str:
37-
pass
34+
async def resolve(self, dns: str) -> str:
35+
try:
36+
conn_name = _parse_instance_connection_name(dns)
37+
except ValueError:
38+
# The connection name was not project:region:instance format.
39+
# Attempt to query a TXT record to get connection name.
40+
try:
41+
result = await super().resolve(dns, "TXT", raise_on_no_answer=True)
42+
if result is not None:
43+
rdata = result[0].to_text().strip('"')
44+
conn_name = _parse_instance_connection_name(rdata)
45+
except ValueError:
46+
raise DnsResolutionError(
47+
f"Unable to parse TXT for `{dns}` -> {result[0]}"
48+
)
49+
except Exception as e:
50+
raise DnsResolutionError(
51+
f"Unable to resolve TXT record for `{dns}`"
52+
) from e
53+
return conn_name

0 commit comments

Comments
 (0)