cloud-sql-python-connector 1.18.5__tar.gz → 1.20.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/PKG-INFO +18 -5
  2. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/README.md +17 -4
  3. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/cloud_sql_python_connector.egg-info/PKG-INFO +18 -5
  4. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/connector.py +43 -1
  5. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/exceptions.py +7 -0
  6. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/resolver.py +12 -0
  7. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/version.py +1 -1
  8. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/LICENSE +0 -0
  9. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/cloud_sql_python_connector.egg-info/SOURCES.txt +0 -0
  10. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/cloud_sql_python_connector.egg-info/dependency_links.txt +0 -0
  11. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/cloud_sql_python_connector.egg-info/requires.txt +0 -0
  12. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/cloud_sql_python_connector.egg-info/top_level.txt +0 -0
  13. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/__init__.py +0 -0
  14. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/asyncpg.py +0 -0
  15. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/client.py +0 -0
  16. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/connection_info.py +0 -0
  17. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/connection_name.py +0 -0
  18. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/enums.py +0 -0
  19. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/instance.py +0 -0
  20. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/lazy.py +0 -0
  21. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/monitored_cache.py +0 -0
  22. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/pg8000.py +0 -0
  23. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/py.typed +0 -0
  24. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/pymysql.py +0 -0
  25. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/pytds.py +0 -0
  26. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/rate_limiter.py +0 -0
  27. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/refresh_utils.py +0 -0
  28. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/google/cloud/sql/connector/utils.py +0 -0
  29. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/pyproject.toml +0 -0
  30. {cloud_sql_python_connector-1.18.5 → cloud_sql_python_connector-1.20.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloud-sql-python-connector
3
- Version: 1.18.5
3
+ Version: 1.20.0
4
4
  Summary: Google Cloud SQL Python Connector library
5
5
  Author-email: Google LLC <googleapis-packages@google.com>
6
6
  License-Expression: Apache-2.0
@@ -387,14 +387,27 @@ conn = connector.connect(
387
387
  )
388
388
  ```
389
389
 
390
- ### Using DNS domain names to identify instances
390
+ ### Using Advanced Disaster Recovery and DNS domain names to identify instances
391
391
 
392
- The connector can be configured to use DNS to look up an instance. This would
393
- allow you to configure your application to connect to a database instance, and
394
- centrally configure which instance in your DNS zone.
392
+ The connector can be configured to use DNS to look up an instance.
393
+ Use a DNS name managed by Cloud SQL [Advanced Disaster Recovery](https://docs.cloud.google.com/sql/docs/mysql/use-advanced-disaster-recovery),
394
+ or a domain name that you manage.
395
+
396
+ #### Using Advanced Recovery Write Endpoint DNS Name
397
+
398
+ [Advanced Disaster Recovery](https://docs.cloud.google.com/sql/docs/mysql/use-advanced-disaster-recovery)
399
+ creates geographically distributed replicas of your Cloud SQL database instance. When you perform
400
+ switchover or failover on the database instance, the connector will gracefully disconnect from the
401
+ old primary instance and reconnect to the new primary instance.
402
+
403
+ Follow the instructions in [Connect using Write Endpoint](https://docs.cloud.google.com/sql/docs/mysql/connect-to-instance-using-write-endpoint)
404
+ to get the write endpoint DNS name for your primary instance. Then, use this write endpoint DNS
405
+ name to configure the connector.
395
406
 
396
407
  #### Configure your DNS Records
397
408
 
409
+ The connector may be configured to use DNS that you define as well.
410
+
398
411
  Add a DNS TXT record for the Cloud SQL instance to a **private** DNS server
399
412
  or a private Google Cloud DNS Zone used by your application.
400
413
 
@@ -348,14 +348,27 @@ conn = connector.connect(
348
348
  )
349
349
  ```
350
350
 
351
- ### Using DNS domain names to identify instances
351
+ ### Using Advanced Disaster Recovery and DNS domain names to identify instances
352
352
 
353
- The connector can be configured to use DNS to look up an instance. This would
354
- allow you to configure your application to connect to a database instance, and
355
- centrally configure which instance in your DNS zone.
353
+ The connector can be configured to use DNS to look up an instance.
354
+ Use a DNS name managed by Cloud SQL [Advanced Disaster Recovery](https://docs.cloud.google.com/sql/docs/mysql/use-advanced-disaster-recovery),
355
+ or a domain name that you manage.
356
+
357
+ #### Using Advanced Recovery Write Endpoint DNS Name
358
+
359
+ [Advanced Disaster Recovery](https://docs.cloud.google.com/sql/docs/mysql/use-advanced-disaster-recovery)
360
+ creates geographically distributed replicas of your Cloud SQL database instance. When you perform
361
+ switchover or failover on the database instance, the connector will gracefully disconnect from the
362
+ old primary instance and reconnect to the new primary instance.
363
+
364
+ Follow the instructions in [Connect using Write Endpoint](https://docs.cloud.google.com/sql/docs/mysql/connect-to-instance-using-write-endpoint)
365
+ to get the write endpoint DNS name for your primary instance. Then, use this write endpoint DNS
366
+ name to configure the connector.
356
367
 
357
368
  #### Configure your DNS Records
358
369
 
370
+ The connector may be configured to use DNS that you define as well.
371
+
359
372
  Add a DNS TXT record for the Cloud SQL instance to a **private** DNS server
360
373
  or a private Google Cloud DNS Zone used by your application.
361
374
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloud-sql-python-connector
3
- Version: 1.18.5
3
+ Version: 1.20.0
4
4
  Summary: Google Cloud SQL Python Connector library
5
5
  Author-email: Google LLC <googleapis-packages@google.com>
6
6
  License-Expression: Apache-2.0
@@ -387,14 +387,27 @@ conn = connector.connect(
387
387
  )
388
388
  ```
389
389
 
390
- ### Using DNS domain names to identify instances
390
+ ### Using Advanced Disaster Recovery and DNS domain names to identify instances
391
391
 
392
- The connector can be configured to use DNS to look up an instance. This would
393
- allow you to configure your application to connect to a database instance, and
394
- centrally configure which instance in your DNS zone.
392
+ The connector can be configured to use DNS to look up an instance.
393
+ Use a DNS name managed by Cloud SQL [Advanced Disaster Recovery](https://docs.cloud.google.com/sql/docs/mysql/use-advanced-disaster-recovery),
394
+ or a domain name that you manage.
395
+
396
+ #### Using Advanced Recovery Write Endpoint DNS Name
397
+
398
+ [Advanced Disaster Recovery](https://docs.cloud.google.com/sql/docs/mysql/use-advanced-disaster-recovery)
399
+ creates geographically distributed replicas of your Cloud SQL database instance. When you perform
400
+ switchover or failover on the database instance, the connector will gracefully disconnect from the
401
+ old primary instance and reconnect to the new primary instance.
402
+
403
+ Follow the instructions in [Connect using Write Endpoint](https://docs.cloud.google.com/sql/docs/mysql/connect-to-instance-using-write-endpoint)
404
+ to get the write endpoint DNS name for your primary instance. Then, use this write endpoint DNS
405
+ name to configure the connector.
395
406
 
396
407
  #### Configure your DNS Records
397
408
 
409
+ The connector may be configured to use DNS that you define as well.
410
+
398
411
  Add a DNS TXT record for the Cloud SQL instance to a **private** DNS server
399
412
  or a private Google Cloud DNS Zone used by your application.
400
413
 
@@ -34,6 +34,7 @@ from google.cloud.sql.connector.client import CloudSQLClient
34
34
  from google.cloud.sql.connector.enums import DriverMapping
35
35
  from google.cloud.sql.connector.enums import IPTypes
36
36
  from google.cloud.sql.connector.enums import RefreshStrategy
37
+ from google.cloud.sql.connector.exceptions import ClosedConnectorError
37
38
  from google.cloud.sql.connector.exceptions import ConnectorLoopError
38
39
  from google.cloud.sql.connector.instance import RefreshAheadCache
39
40
  from google.cloud.sql.connector.lazy import LazyRefreshCache
@@ -155,6 +156,7 @@ class Connector:
155
156
  # connection name string and enable_iam_auth boolean flag
156
157
  self._cache: dict[tuple[str, bool], MonitoredCache] = {}
157
158
  self._client: Optional[CloudSQLClient] = None
159
+ self._closed: bool = False
158
160
 
159
161
  # initialize credentials
160
162
  scopes = ["https://www.googleapis.com/auth/sqlservice.admin"]
@@ -244,6 +246,12 @@ class Connector:
244
246
  # connect runs sync database connections on background thread.
245
247
  # Async database connections should call 'connect_async' directly to
246
248
  # avoid hanging indefinitely.
249
+
250
+ # Check if the connector is closed before attempting to connect.
251
+ if self._closed:
252
+ raise ClosedConnectorError(
253
+ "Connection attempt failed because the connector has already been closed."
254
+ )
247
255
  connect_future = asyncio.run_coroutine_threadsafe(
248
256
  self.connect_async(instance_connection_string, driver, **kwargs),
249
257
  self._loop,
@@ -281,7 +289,13 @@ class Connector:
281
289
  and then subsequent attempt with IAM database authentication.
282
290
  KeyError: Unsupported database driver Must be one of pymysql, asyncpg,
283
291
  pg8000, and pytds.
292
+ RuntimeError: Connector has been closed. Cannot connect using a closed
293
+ Connector.
284
294
  """
295
+ if self._closed:
296
+ raise ClosedConnectorError(
297
+ "Connection attempt failed because the connector has already been closed."
298
+ )
285
299
  # check if event loop is running in current thread
286
300
  if self._loop != asyncio.get_running_loop():
287
301
  raise ConnectorLoopError(
@@ -376,6 +390,33 @@ class Connector:
376
390
  # the cache and re-raise the error
377
391
  await self._remove_cached(str(conn_name), enable_iam_auth)
378
392
  raise
393
+
394
+ # If the connector is configured with a custom DNS name, attempt to use
395
+ # that DNS name to connect to the instance. Fall back to the metadata IP
396
+ # address if the DNS name does not resolve to an IP address.
397
+ if conn_info.conn_name.domain_name and isinstance(self._resolver, DnsResolver):
398
+ try:
399
+ ips = await self._resolver.resolve_a_record(conn_info.conn_name.domain_name)
400
+ if ips:
401
+ ip_address = ips[0]
402
+ logger.debug(
403
+ f"['{instance_connection_string}']: Custom DNS name "
404
+ f"'{conn_info.conn_name.domain_name}' resolved to '{ip_address}', "
405
+ "using it to connect"
406
+ )
407
+ else:
408
+ logger.debug(
409
+ f"['{instance_connection_string}']: Custom DNS name "
410
+ f"'{conn_info.conn_name.domain_name}' resolved but returned no "
411
+ f"entries, using '{ip_address}' from instance metadata"
412
+ )
413
+ except Exception as e:
414
+ logger.debug(
415
+ f"['{instance_connection_string}']: Custom DNS name "
416
+ f"'{conn_info.conn_name.domain_name}' did not resolve to an IP "
417
+ f"address: {e}, using '{ip_address}' from instance metadata"
418
+ )
419
+
379
420
  logger.debug(f"['{conn_info.conn_name}']: Connecting to {ip_address}:3307")
380
421
  # format `user` param for automatic IAM database authn
381
422
  if enable_iam_auth:
@@ -477,9 +518,10 @@ class Connector:
477
518
  async def close_async(self) -> None:
478
519
  """Helper function to cancel the cache's tasks
479
520
  and close aiohttp.ClientSession."""
480
- await asyncio.gather(*[cache.close() for cache in self._cache.values()])
521
+ self._closed = True
481
522
  if self._client:
482
523
  await self._client.close()
524
+ await asyncio.gather(*[cache.close() for cache in self._cache.values()])
483
525
 
484
526
 
485
527
  async def create_async_connector(
@@ -84,3 +84,10 @@ class CacheClosedError(Exception):
84
84
  Exception to be raised when a ConnectionInfoCache can not be accessed after
85
85
  it is closed.
86
86
  """
87
+
88
+
89
+ class ClosedConnectorError(Exception):
90
+ """
91
+ Exception to be raised when a Connector is closed and connect method is
92
+ called on it.
93
+ """
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from typing import List
16
+
15
17
  import dns.asyncresolver
16
18
 
17
19
  from google.cloud.sql.connector.connection_name import _is_valid_domain
@@ -53,6 +55,16 @@ class DnsResolver(dns.asyncresolver.Resolver):
53
55
  )
54
56
  return conn_name
55
57
 
58
+ async def resolve_a_record(self, dns: str) -> List[str]:
59
+ try:
60
+ # Attempt to query the A records.
61
+ records = await super().resolve(dns, "A", raise_on_no_answer=True)
62
+ # return IP addresses as strings
63
+ return [record.to_text() for record in records]
64
+ except Exception:
65
+ # On any error, return empty list
66
+ return []
67
+
56
68
  async def query_dns(self, dns: str) -> ConnectionName:
57
69
  try:
58
70
  # Attempt to query the TXT records.
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- __version__ = "1.18.5"
15
+ __version__ = "1.20.0"