cloud-sql-python-connector 1.23.0__tar.gz → 1.24.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.
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/PKG-INFO +80 -1
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/README.md +78 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/cloud_sql_python_connector.egg-info/PKG-INFO +80 -1
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/cloud_sql_python_connector.egg-info/SOURCES.txt +1 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/connection_info.py +4 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/connector.py +128 -32
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/instance.py +236 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/lazy.py +45 -1
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/monitored_cache.py +6 -1
- cloud_sql_python_connector-1.24.0/google/cloud/sql/connector/postgres_connection.py +235 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/sqldata_client.py +1 -1
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/utils.py +1 -1
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/version.py +1 -1
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/pyproject.toml +1 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/LICENSE +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/cloud_sql_python_connector.egg-info/dependency_links.txt +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/cloud_sql_python_connector.egg-info/requires.txt +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/cloud_sql_python_connector.egg-info/top_level.txt +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/__init__.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/asyncpg.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/client.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/connection_name.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/enums.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/exceptions.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/pg8000.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/psycopg.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/py.typed +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/pymysql.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/pytds.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/rate_limiter.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/refresh_utils.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.0}/google/cloud/sql/connector/resolver.py +0 -0
- {cloud_sql_python_connector-1.23.0 → cloud_sql_python_connector-1.24.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.
|
|
3
|
+
Version: 1.24.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
|
|
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
19
20
|
Classifier: Operating System :: OS Independent
|
|
20
21
|
Requires-Python: >=3.11
|
|
21
22
|
Description-Content-Type: text/markdown
|
|
@@ -789,6 +790,84 @@ async def main():
|
|
|
789
790
|
await pool.dispose()
|
|
790
791
|
```
|
|
791
792
|
|
|
793
|
+
### Post-Quantum Cryptography (PQC)
|
|
794
|
+
|
|
795
|
+
The Cloud SQL Python Connector establishes mTLS connections over TLS 1.3 using
|
|
796
|
+
Python's standard `ssl` module without restricting key-exchange groups. When
|
|
797
|
+
Python's `ssl` module is linked against **OpenSSL 3.5 or later**, TLS 1.3
|
|
798
|
+
connections automatically offer and negotiate the hybrid post-quantum key
|
|
799
|
+
exchange group **`X25519MLKEM768`** (ML-KEM-768 combined with X25519) whenever
|
|
800
|
+
the Cloud SQL instance supports it. No code changes or connector configuration
|
|
801
|
+
are required.
|
|
802
|
+
|
|
803
|
+
#### Checking your OpenSSL version
|
|
804
|
+
|
|
805
|
+
Post-quantum TLS key exchange depends on the OpenSSL library linked into your
|
|
806
|
+
Python runtime's `ssl` module (not the Python language version or the
|
|
807
|
+
`cryptography` package version alone). Run the following command to check which
|
|
808
|
+
OpenSSL version your Python interpreter uses:
|
|
809
|
+
|
|
810
|
+
```sh
|
|
811
|
+
python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
- **OpenSSL 3.5.0 or higher** (for example, `python:3.13-trixie` / Debian 13
|
|
815
|
+
"Trixie" container images; check your runtime with the one-liner above):
|
|
816
|
+
`X25519MLKEM768` is enabled by default on TLS 1.3 connections.
|
|
817
|
+
- **OpenSSL earlier than 3.5.0** (for example, Ubuntu 24.04 LTS, which ships
|
|
818
|
+
system OpenSSL 3.0.x): TLS 1.3 connections continue to use classical elliptic
|
|
819
|
+
curve Diffie-Hellman (such as `X25519` or `P-256`).
|
|
820
|
+
|
|
821
|
+
> [!NOTE]
|
|
822
|
+
>
|
|
823
|
+
> Connections configured with `ip_type="sql_data"` (`IPTypes.SQL_DATA`) stream
|
|
824
|
+
> over gRPC (`grpcio`), which uses its bundled BoringSSL (supporting
|
|
825
|
+
> `X25519MLKEM768` independently of Python's `ssl` module and `OPENSSL_CONF`),
|
|
826
|
+
> whereas its direct-TLS fallback path uses `create_ssl_context()` and Python's
|
|
827
|
+
> linked OpenSSL library as described above.
|
|
828
|
+
|
|
829
|
+
#### Backwards compatibility
|
|
830
|
+
|
|
831
|
+
Hybrid post-quantum key exchange is backwards-compatible. On OpenSSL 3.5+,
|
|
832
|
+
Python's `ssl` module advertises both hybrid (`X25519MLKEM768`) and classical
|
|
833
|
+
(`X25519`, `secp256r1`, etc.) groups in the TLS 1.3 `ClientHello`. If either the
|
|
834
|
+
client runtime (OpenSSL `< 3.5`) or the Cloud SQL instance only supports
|
|
835
|
+
classical groups, the TLS 1.3 handshake automatically falls back to classical
|
|
836
|
+
ECDHE without error.
|
|
837
|
+
|
|
838
|
+
#### Opting out
|
|
839
|
+
|
|
840
|
+
If you need to disable post-quantum key exchange on an OpenSSL 3.5+ client (for
|
|
841
|
+
example, to troubleshoot a network middlebox sensitive to larger TLS
|
|
842
|
+
`ClientHello` records), configure OpenSSL's `Groups` list via an OpenSSL
|
|
843
|
+
configuration file (`OPENSSL_CONF`) to advertise only classical curves.
|
|
844
|
+
|
|
845
|
+
> [!WARNING]
|
|
846
|
+
>
|
|
847
|
+
> Setting `OPENSSL_CONF` replaces the system default OpenSSL configuration for
|
|
848
|
+
> the entire Python process. It affects **all** TLS connections made by the
|
|
849
|
+
> process (not just Cloud SQL connections), and starting from a minimal file
|
|
850
|
+
> omits distribution defaults (such as Debian's `MinProtocol` or
|
|
851
|
+
> `CipherString`). Copy your system's `openssl.cnf` (check `openssl version -d`,
|
|
852
|
+
> typically `/etc/ssl/openssl.cnf`) and add `Groups = X25519:P-256:P-384` under
|
|
853
|
+
> its `[system_default_sect]` section rather than using a bare file from
|
|
854
|
+
> scratch.
|
|
855
|
+
|
|
856
|
+
For example, after copying `/etc/ssl/openssl.cnf`, ensure its
|
|
857
|
+
`[system_default_sect]` (referenced via `ssl_conf` -> `system_default`) sets
|
|
858
|
+
`Groups`:
|
|
859
|
+
|
|
860
|
+
```ini
|
|
861
|
+
[system_default_sect]
|
|
862
|
+
Groups = X25519:P-256:P-384
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
Then point `OPENSSL_CONF` to your modified copy when starting your application:
|
|
866
|
+
|
|
867
|
+
```sh
|
|
868
|
+
OPENSSL_CONF=/path/to/openssl.cnf python3 app.py
|
|
869
|
+
```
|
|
870
|
+
|
|
792
871
|
### Debug Logging
|
|
793
872
|
|
|
794
873
|
The Cloud SQL Python Connector uses the standard [Python logging module][python-logging]
|
|
@@ -749,6 +749,84 @@ async def main():
|
|
|
749
749
|
await pool.dispose()
|
|
750
750
|
```
|
|
751
751
|
|
|
752
|
+
### Post-Quantum Cryptography (PQC)
|
|
753
|
+
|
|
754
|
+
The Cloud SQL Python Connector establishes mTLS connections over TLS 1.3 using
|
|
755
|
+
Python's standard `ssl` module without restricting key-exchange groups. When
|
|
756
|
+
Python's `ssl` module is linked against **OpenSSL 3.5 or later**, TLS 1.3
|
|
757
|
+
connections automatically offer and negotiate the hybrid post-quantum key
|
|
758
|
+
exchange group **`X25519MLKEM768`** (ML-KEM-768 combined with X25519) whenever
|
|
759
|
+
the Cloud SQL instance supports it. No code changes or connector configuration
|
|
760
|
+
are required.
|
|
761
|
+
|
|
762
|
+
#### Checking your OpenSSL version
|
|
763
|
+
|
|
764
|
+
Post-quantum TLS key exchange depends on the OpenSSL library linked into your
|
|
765
|
+
Python runtime's `ssl` module (not the Python language version or the
|
|
766
|
+
`cryptography` package version alone). Run the following command to check which
|
|
767
|
+
OpenSSL version your Python interpreter uses:
|
|
768
|
+
|
|
769
|
+
```sh
|
|
770
|
+
python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
- **OpenSSL 3.5.0 or higher** (for example, `python:3.13-trixie` / Debian 13
|
|
774
|
+
"Trixie" container images; check your runtime with the one-liner above):
|
|
775
|
+
`X25519MLKEM768` is enabled by default on TLS 1.3 connections.
|
|
776
|
+
- **OpenSSL earlier than 3.5.0** (for example, Ubuntu 24.04 LTS, which ships
|
|
777
|
+
system OpenSSL 3.0.x): TLS 1.3 connections continue to use classical elliptic
|
|
778
|
+
curve Diffie-Hellman (such as `X25519` or `P-256`).
|
|
779
|
+
|
|
780
|
+
> [!NOTE]
|
|
781
|
+
>
|
|
782
|
+
> Connections configured with `ip_type="sql_data"` (`IPTypes.SQL_DATA`) stream
|
|
783
|
+
> over gRPC (`grpcio`), which uses its bundled BoringSSL (supporting
|
|
784
|
+
> `X25519MLKEM768` independently of Python's `ssl` module and `OPENSSL_CONF`),
|
|
785
|
+
> whereas its direct-TLS fallback path uses `create_ssl_context()` and Python's
|
|
786
|
+
> linked OpenSSL library as described above.
|
|
787
|
+
|
|
788
|
+
#### Backwards compatibility
|
|
789
|
+
|
|
790
|
+
Hybrid post-quantum key exchange is backwards-compatible. On OpenSSL 3.5+,
|
|
791
|
+
Python's `ssl` module advertises both hybrid (`X25519MLKEM768`) and classical
|
|
792
|
+
(`X25519`, `secp256r1`, etc.) groups in the TLS 1.3 `ClientHello`. If either the
|
|
793
|
+
client runtime (OpenSSL `< 3.5`) or the Cloud SQL instance only supports
|
|
794
|
+
classical groups, the TLS 1.3 handshake automatically falls back to classical
|
|
795
|
+
ECDHE without error.
|
|
796
|
+
|
|
797
|
+
#### Opting out
|
|
798
|
+
|
|
799
|
+
If you need to disable post-quantum key exchange on an OpenSSL 3.5+ client (for
|
|
800
|
+
example, to troubleshoot a network middlebox sensitive to larger TLS
|
|
801
|
+
`ClientHello` records), configure OpenSSL's `Groups` list via an OpenSSL
|
|
802
|
+
configuration file (`OPENSSL_CONF`) to advertise only classical curves.
|
|
803
|
+
|
|
804
|
+
> [!WARNING]
|
|
805
|
+
>
|
|
806
|
+
> Setting `OPENSSL_CONF` replaces the system default OpenSSL configuration for
|
|
807
|
+
> the entire Python process. It affects **all** TLS connections made by the
|
|
808
|
+
> process (not just Cloud SQL connections), and starting from a minimal file
|
|
809
|
+
> omits distribution defaults (such as Debian's `MinProtocol` or
|
|
810
|
+
> `CipherString`). Copy your system's `openssl.cnf` (check `openssl version -d`,
|
|
811
|
+
> typically `/etc/ssl/openssl.cnf`) and add `Groups = X25519:P-256:P-384` under
|
|
812
|
+
> its `[system_default_sect]` section rather than using a bare file from
|
|
813
|
+
> scratch.
|
|
814
|
+
|
|
815
|
+
For example, after copying `/etc/ssl/openssl.cnf`, ensure its
|
|
816
|
+
`[system_default_sect]` (referenced via `ssl_conf` -> `system_default`) sets
|
|
817
|
+
`Groups`:
|
|
818
|
+
|
|
819
|
+
```ini
|
|
820
|
+
[system_default_sect]
|
|
821
|
+
Groups = X25519:P-256:P-384
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
Then point `OPENSSL_CONF` to your modified copy when starting your application:
|
|
825
|
+
|
|
826
|
+
```sh
|
|
827
|
+
OPENSSL_CONF=/path/to/openssl.cnf python3 app.py
|
|
828
|
+
```
|
|
829
|
+
|
|
752
830
|
### Debug Logging
|
|
753
831
|
|
|
754
832
|
The Cloud SQL Python Connector uses the standard [Python logging module][python-logging]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cloud-sql-python-connector
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.24.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
|
|
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
19
20
|
Classifier: Operating System :: OS Independent
|
|
20
21
|
Requires-Python: >=3.11
|
|
21
22
|
Description-Content-Type: text/markdown
|
|
@@ -789,6 +790,84 @@ async def main():
|
|
|
789
790
|
await pool.dispose()
|
|
790
791
|
```
|
|
791
792
|
|
|
793
|
+
### Post-Quantum Cryptography (PQC)
|
|
794
|
+
|
|
795
|
+
The Cloud SQL Python Connector establishes mTLS connections over TLS 1.3 using
|
|
796
|
+
Python's standard `ssl` module without restricting key-exchange groups. When
|
|
797
|
+
Python's `ssl` module is linked against **OpenSSL 3.5 or later**, TLS 1.3
|
|
798
|
+
connections automatically offer and negotiate the hybrid post-quantum key
|
|
799
|
+
exchange group **`X25519MLKEM768`** (ML-KEM-768 combined with X25519) whenever
|
|
800
|
+
the Cloud SQL instance supports it. No code changes or connector configuration
|
|
801
|
+
are required.
|
|
802
|
+
|
|
803
|
+
#### Checking your OpenSSL version
|
|
804
|
+
|
|
805
|
+
Post-quantum TLS key exchange depends on the OpenSSL library linked into your
|
|
806
|
+
Python runtime's `ssl` module (not the Python language version or the
|
|
807
|
+
`cryptography` package version alone). Run the following command to check which
|
|
808
|
+
OpenSSL version your Python interpreter uses:
|
|
809
|
+
|
|
810
|
+
```sh
|
|
811
|
+
python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
- **OpenSSL 3.5.0 or higher** (for example, `python:3.13-trixie` / Debian 13
|
|
815
|
+
"Trixie" container images; check your runtime with the one-liner above):
|
|
816
|
+
`X25519MLKEM768` is enabled by default on TLS 1.3 connections.
|
|
817
|
+
- **OpenSSL earlier than 3.5.0** (for example, Ubuntu 24.04 LTS, which ships
|
|
818
|
+
system OpenSSL 3.0.x): TLS 1.3 connections continue to use classical elliptic
|
|
819
|
+
curve Diffie-Hellman (such as `X25519` or `P-256`).
|
|
820
|
+
|
|
821
|
+
> [!NOTE]
|
|
822
|
+
>
|
|
823
|
+
> Connections configured with `ip_type="sql_data"` (`IPTypes.SQL_DATA`) stream
|
|
824
|
+
> over gRPC (`grpcio`), which uses its bundled BoringSSL (supporting
|
|
825
|
+
> `X25519MLKEM768` independently of Python's `ssl` module and `OPENSSL_CONF`),
|
|
826
|
+
> whereas its direct-TLS fallback path uses `create_ssl_context()` and Python's
|
|
827
|
+
> linked OpenSSL library as described above.
|
|
828
|
+
|
|
829
|
+
#### Backwards compatibility
|
|
830
|
+
|
|
831
|
+
Hybrid post-quantum key exchange is backwards-compatible. On OpenSSL 3.5+,
|
|
832
|
+
Python's `ssl` module advertises both hybrid (`X25519MLKEM768`) and classical
|
|
833
|
+
(`X25519`, `secp256r1`, etc.) groups in the TLS 1.3 `ClientHello`. If either the
|
|
834
|
+
client runtime (OpenSSL `< 3.5`) or the Cloud SQL instance only supports
|
|
835
|
+
classical groups, the TLS 1.3 handshake automatically falls back to classical
|
|
836
|
+
ECDHE without error.
|
|
837
|
+
|
|
838
|
+
#### Opting out
|
|
839
|
+
|
|
840
|
+
If you need to disable post-quantum key exchange on an OpenSSL 3.5+ client (for
|
|
841
|
+
example, to troubleshoot a network middlebox sensitive to larger TLS
|
|
842
|
+
`ClientHello` records), configure OpenSSL's `Groups` list via an OpenSSL
|
|
843
|
+
configuration file (`OPENSSL_CONF`) to advertise only classical curves.
|
|
844
|
+
|
|
845
|
+
> [!WARNING]
|
|
846
|
+
>
|
|
847
|
+
> Setting `OPENSSL_CONF` replaces the system default OpenSSL configuration for
|
|
848
|
+
> the entire Python process. It affects **all** TLS connections made by the
|
|
849
|
+
> process (not just Cloud SQL connections), and starting from a minimal file
|
|
850
|
+
> omits distribution defaults (such as Debian's `MinProtocol` or
|
|
851
|
+
> `CipherString`). Copy your system's `openssl.cnf` (check `openssl version -d`,
|
|
852
|
+
> typically `/etc/ssl/openssl.cnf`) and add `Groups = X25519:P-256:P-384` under
|
|
853
|
+
> its `[system_default_sect]` section rather than using a bare file from
|
|
854
|
+
> scratch.
|
|
855
|
+
|
|
856
|
+
For example, after copying `/etc/ssl/openssl.cnf`, ensure its
|
|
857
|
+
`[system_default_sect]` (referenced via `ssl_conf` -> `system_default`) sets
|
|
858
|
+
`Groups`:
|
|
859
|
+
|
|
860
|
+
```ini
|
|
861
|
+
[system_default_sect]
|
|
862
|
+
Groups = X25519:P-256:P-384
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
Then point `OPENSSL_CONF` to your modified copy when starting your application:
|
|
866
|
+
|
|
867
|
+
```sh
|
|
868
|
+
OPENSSL_CONF=/path/to/openssl.cnf python3 app.py
|
|
869
|
+
```
|
|
870
|
+
|
|
792
871
|
### Debug Logging
|
|
793
872
|
|
|
794
873
|
The Cloud SQL Python Connector uses the standard [Python logging module][python-logging]
|
|
@@ -18,6 +18,7 @@ google/cloud/sql/connector/instance.py
|
|
|
18
18
|
google/cloud/sql/connector/lazy.py
|
|
19
19
|
google/cloud/sql/connector/monitored_cache.py
|
|
20
20
|
google/cloud/sql/connector/pg8000.py
|
|
21
|
+
google/cloud/sql/connector/postgres_connection.py
|
|
21
22
|
google/cloud/sql/connector/psycopg.py
|
|
22
23
|
google/cloud/sql/connector/py.typed
|
|
23
24
|
google/cloud/sql/connector/pymysql.py
|
|
@@ -23,6 +23,7 @@ import logging
|
|
|
23
23
|
import os
|
|
24
24
|
import random
|
|
25
25
|
import socket
|
|
26
|
+
import ssl
|
|
26
27
|
from threading import Thread
|
|
27
28
|
import time
|
|
28
29
|
from types import TracebackType
|
|
@@ -38,6 +39,7 @@ from google.cloud.sql.connector import psycopg
|
|
|
38
39
|
from google.cloud.sql.connector import pymysql
|
|
39
40
|
from google.cloud.sql.connector import pytds
|
|
40
41
|
from google.cloud.sql.connector.client import CloudSQLClient
|
|
42
|
+
from google.cloud.sql.connector.connection_info import ConnectionInfo
|
|
41
43
|
from google.cloud.sql.connector.connection_name import ConnectionName
|
|
42
44
|
from google.cloud.sql.connector.enums import DriverMapping
|
|
43
45
|
from google.cloud.sql.connector.enums import IPTypes
|
|
@@ -49,6 +51,7 @@ from google.cloud.sql.connector.exceptions import ResourceExhaustedError
|
|
|
49
51
|
from google.cloud.sql.connector.instance import RefreshAheadCache
|
|
50
52
|
from google.cloud.sql.connector.lazy import LazyRefreshCache
|
|
51
53
|
from google.cloud.sql.connector.monitored_cache import MonitoredCache
|
|
54
|
+
from google.cloud.sql.connector.postgres_connection import PostgresConnection
|
|
52
55
|
from google.cloud.sql.connector.resolver import DefaultResolver
|
|
53
56
|
from google.cloud.sql.connector.resolver import DnsResolver
|
|
54
57
|
from google.cloud.sql.connector.sqldata_client import SqlDataClient
|
|
@@ -346,6 +349,7 @@ class Connector:
|
|
|
346
349
|
self,
|
|
347
350
|
conn_name: ConnectionName,
|
|
348
351
|
enable_iam_auth: bool,
|
|
352
|
+
ip_type: IPTypes | None = None,
|
|
349
353
|
) -> MonitoredCache:
|
|
350
354
|
assert self._client is not None, "client must be initialized before creating cache"
|
|
351
355
|
assert self._keys is not None, "keys must be initialized before creating cache"
|
|
@@ -355,6 +359,13 @@ class Connector:
|
|
|
355
359
|
].closed:
|
|
356
360
|
return self._cache[(str(conn_name), enable_iam_auth)]
|
|
357
361
|
|
|
362
|
+
effective_ip_type = ip_type if ip_type is not None else self._ip_type
|
|
363
|
+
dial_func = partial(
|
|
364
|
+
self._dial_probe_connection,
|
|
365
|
+
enable_iam_auth=enable_iam_auth,
|
|
366
|
+
ip_type=effective_ip_type,
|
|
367
|
+
)
|
|
368
|
+
|
|
358
369
|
if self._refresh_strategy == RefreshStrategy.LAZY:
|
|
359
370
|
logger.debug(
|
|
360
371
|
f"['{conn_name}']: Refresh strategy is set to lazy refresh"
|
|
@@ -364,6 +375,9 @@ class Connector:
|
|
|
364
375
|
self._client,
|
|
365
376
|
self._keys,
|
|
366
377
|
enable_iam_auth,
|
|
378
|
+
ip_type=effective_ip_type,
|
|
379
|
+
timeout=self._timeout,
|
|
380
|
+
dial_func=dial_func,
|
|
367
381
|
)
|
|
368
382
|
else:
|
|
369
383
|
logger.debug(
|
|
@@ -374,6 +388,9 @@ class Connector:
|
|
|
374
388
|
self._client,
|
|
375
389
|
self._keys,
|
|
376
390
|
enable_iam_auth,
|
|
391
|
+
ip_type=effective_ip_type,
|
|
392
|
+
timeout=self._timeout,
|
|
393
|
+
dial_func=dial_func,
|
|
377
394
|
)
|
|
378
395
|
# wrap cache as a MonitoredCache
|
|
379
396
|
monitored_cache = MonitoredCache(
|
|
@@ -452,7 +469,9 @@ class Connector:
|
|
|
452
469
|
|
|
453
470
|
conn_name = await self._resolver.resolve(instance_connection_string)
|
|
454
471
|
if ip_type != IPTypes.SQL_DATA:
|
|
455
|
-
monitored_cache = self._get_or_create_cache(
|
|
472
|
+
monitored_cache = self._get_or_create_cache(
|
|
473
|
+
conn_name, enable_iam_auth, ip_type
|
|
474
|
+
)
|
|
456
475
|
|
|
457
476
|
connect_func = {
|
|
458
477
|
"pymysql": pymysql.connect,
|
|
@@ -587,33 +606,7 @@ class Connector:
|
|
|
587
606
|
await self._remove_cached(str(conn_name), enable_iam_auth)
|
|
588
607
|
raise
|
|
589
608
|
|
|
590
|
-
targets =
|
|
591
|
-
if conn_info.conn_name.domain_name and isinstance(self._resolver, DnsResolver):
|
|
592
|
-
try:
|
|
593
|
-
ips = await self._resolver.resolve_a_record(conn_info.conn_name.domain_name)
|
|
594
|
-
if ips:
|
|
595
|
-
targets.extend(ips)
|
|
596
|
-
logger.debug(
|
|
597
|
-
f"['{instance_connection_string}']: Custom DNS name "
|
|
598
|
-
f"'{conn_info.conn_name.domain_name}' resolved to '{ips}', "
|
|
599
|
-
"using it to connect"
|
|
600
|
-
)
|
|
601
|
-
else:
|
|
602
|
-
logger.debug(
|
|
603
|
-
f"['{instance_connection_string}']: Custom DNS name "
|
|
604
|
-
f"'{conn_info.conn_name.domain_name}' resolved but returned no "
|
|
605
|
-
f"entries, using '{preferred_ips}' from instance metadata"
|
|
606
|
-
)
|
|
607
|
-
targets.extend(preferred_ips)
|
|
608
|
-
except Exception as e: # noqa: BLE001
|
|
609
|
-
logger.debug(
|
|
610
|
-
f"['{instance_connection_string}']: Custom DNS name "
|
|
611
|
-
f"'{conn_info.conn_name.domain_name}' did not resolve to an IP "
|
|
612
|
-
f"address: {e}, using '{preferred_ips}' from instance metadata"
|
|
613
|
-
)
|
|
614
|
-
targets.extend(preferred_ips)
|
|
615
|
-
else:
|
|
616
|
-
targets.extend(preferred_ips)
|
|
609
|
+
targets = await self._resolve_targets(conn_info, preferred_ips)
|
|
617
610
|
# format `user` param for automatic IAM database authn
|
|
618
611
|
if enable_iam_auth:
|
|
619
612
|
formatted_user = format_database_user(
|
|
@@ -636,14 +629,28 @@ class Connector:
|
|
|
636
629
|
await conn_info.create_ssl_context(enable_iam_auth),
|
|
637
630
|
**kwargs,
|
|
638
631
|
)
|
|
632
|
+
if (
|
|
633
|
+
enable_iam_auth
|
|
634
|
+
and conn_info.database_version.startswith("POSTGRES")
|
|
635
|
+
):
|
|
636
|
+
db_name = kwargs.get("database")
|
|
637
|
+
if db_name is None:
|
|
638
|
+
db_name = kwargs.get("db")
|
|
639
|
+
user = kwargs.get("user")
|
|
640
|
+
if user:
|
|
641
|
+
monitored_cache.record_principal(
|
|
642
|
+
str(user),
|
|
643
|
+
str(db_name) if db_name else str(user),
|
|
644
|
+
)
|
|
639
645
|
last_ex = None
|
|
640
646
|
return conn
|
|
641
647
|
|
|
642
648
|
# Create socket with SSLContext for sync drivers
|
|
643
649
|
ctx = await conn_info.create_ssl_context(enable_iam_auth)
|
|
644
650
|
raw_sock = socket.create_connection((target_ip, SERVER_PROXY_PORT))
|
|
651
|
+
sync_sock: socket.socket | ssl.SSLSocket | PostgresConnection
|
|
645
652
|
try:
|
|
646
|
-
|
|
653
|
+
sync_sock = ctx.wrap_socket(
|
|
647
654
|
raw_sock,
|
|
648
655
|
server_hostname=target_ip,
|
|
649
656
|
)
|
|
@@ -651,15 +658,24 @@ class Connector:
|
|
|
651
658
|
raw_sock.close()
|
|
652
659
|
raise
|
|
653
660
|
|
|
661
|
+
if (
|
|
662
|
+
enable_iam_auth
|
|
663
|
+
and conn_info.database_version.startswith("POSTGRES")
|
|
664
|
+
):
|
|
665
|
+
sync_sock = PostgresConnection(
|
|
666
|
+
sync_sock,
|
|
667
|
+
on_startup=monitored_cache.record_principal,
|
|
668
|
+
)
|
|
669
|
+
|
|
654
670
|
# If this connection was opened using a domain name, then store it
|
|
655
671
|
# for later in case we need to forcibly close it on failover.
|
|
656
672
|
if conn_info.conn_name.domain_name:
|
|
657
|
-
monitored_cache.sockets.append(
|
|
673
|
+
monitored_cache.sockets.append(sync_sock)
|
|
658
674
|
# Synchronous drivers are blocking and run using executor
|
|
659
675
|
connect_partial = partial(
|
|
660
676
|
connector,
|
|
661
677
|
target_ip,
|
|
662
|
-
|
|
678
|
+
sync_sock,
|
|
663
679
|
**kwargs,
|
|
664
680
|
)
|
|
665
681
|
conn = await self._loop.run_in_executor(None, connect_partial)
|
|
@@ -670,7 +686,6 @@ class Connector:
|
|
|
670
686
|
f"['{conn_info.conn_name}']: Connection to {target_ip} failed: {e}"
|
|
671
687
|
)
|
|
672
688
|
last_ex = e
|
|
673
|
-
|
|
674
689
|
if last_ex:
|
|
675
690
|
raise last_ex
|
|
676
691
|
|
|
@@ -694,6 +709,87 @@ class Connector:
|
|
|
694
709
|
cache = self._cache.pop((instance_connection_string, enable_iam_auth))
|
|
695
710
|
await cache.close()
|
|
696
711
|
|
|
712
|
+
async def _resolve_targets(
|
|
713
|
+
self,
|
|
714
|
+
conn_info: ConnectionInfo,
|
|
715
|
+
preferred_ips: list[str],
|
|
716
|
+
) -> list[str]:
|
|
717
|
+
"""Resolves target IP addresses for a Cloud SQL instance, with DNS fallback."""
|
|
718
|
+
targets: list[str] = []
|
|
719
|
+
if conn_info.conn_name.domain_name and isinstance(self._resolver, DnsResolver):
|
|
720
|
+
try:
|
|
721
|
+
ips = await self._resolver.resolve_a_record(
|
|
722
|
+
conn_info.conn_name.domain_name
|
|
723
|
+
)
|
|
724
|
+
if ips:
|
|
725
|
+
targets.extend(ips)
|
|
726
|
+
logger.debug(
|
|
727
|
+
f"['{conn_info.conn_name}']: Custom DNS name "
|
|
728
|
+
f"'{conn_info.conn_name.domain_name}' resolved to '{ips}', "
|
|
729
|
+
"using it to connect"
|
|
730
|
+
)
|
|
731
|
+
else:
|
|
732
|
+
logger.debug(
|
|
733
|
+
f"['{conn_info.conn_name}']: Custom DNS name "
|
|
734
|
+
f"'{conn_info.conn_name.domain_name}' resolved but returned no "
|
|
735
|
+
f"entries, using '{preferred_ips}' from instance metadata"
|
|
736
|
+
)
|
|
737
|
+
targets.extend(preferred_ips)
|
|
738
|
+
except Exception as e: # noqa: BLE001
|
|
739
|
+
logger.debug(
|
|
740
|
+
f"['{conn_info.conn_name}']: Custom DNS name "
|
|
741
|
+
f"'{conn_info.conn_name.domain_name}' did not resolve to an IP "
|
|
742
|
+
f"address: {e}, using '{preferred_ips}' from instance metadata"
|
|
743
|
+
)
|
|
744
|
+
targets.extend(preferred_ips)
|
|
745
|
+
else:
|
|
746
|
+
targets.extend(preferred_ips)
|
|
747
|
+
return targets
|
|
748
|
+
|
|
749
|
+
async def _dial_probe_connection(
|
|
750
|
+
self,
|
|
751
|
+
conn_info: ConnectionInfo,
|
|
752
|
+
enable_iam_auth: bool,
|
|
753
|
+
ip_type: IPTypes | None = None,
|
|
754
|
+
) -> tuple[asyncio.StreamReader, asyncio.StreamWriter]:
|
|
755
|
+
"""Dials a TLS probe connection using the connector's IP resolution and SSLContext."""
|
|
756
|
+
effective_ip_type = ip_type if ip_type is not None else self._ip_type
|
|
757
|
+
preferred_ips = conn_info.get_preferred_ips(effective_ip_type)
|
|
758
|
+
targets = await self._resolve_targets(conn_info, preferred_ips)
|
|
759
|
+
|
|
760
|
+
if not targets:
|
|
761
|
+
raise ConnectionError(
|
|
762
|
+
f"No target IP addresses found for {conn_info.conn_name}"
|
|
763
|
+
)
|
|
764
|
+
|
|
765
|
+
ssl_context = await conn_info.create_ssl_context(enable_iam_auth)
|
|
766
|
+
server_hostname = (
|
|
767
|
+
conn_info.conn_name.domain_name
|
|
768
|
+
if conn_info.conn_name.domain_name
|
|
769
|
+
else None
|
|
770
|
+
)
|
|
771
|
+
|
|
772
|
+
last_err: Exception | None = None
|
|
773
|
+
for target in targets:
|
|
774
|
+
try:
|
|
775
|
+
reader, writer = await asyncio.wait_for(
|
|
776
|
+
asyncio.open_connection(
|
|
777
|
+
host=target,
|
|
778
|
+
port=SERVER_PROXY_PORT,
|
|
779
|
+
ssl=ssl_context,
|
|
780
|
+
server_hostname=server_hostname,
|
|
781
|
+
),
|
|
782
|
+
timeout=float(max(1, self._timeout)),
|
|
783
|
+
)
|
|
784
|
+
return reader, writer
|
|
785
|
+
except Exception as e: # noqa: BLE001
|
|
786
|
+
last_err = e
|
|
787
|
+
if last_err:
|
|
788
|
+
raise last_err
|
|
789
|
+
raise ConnectionError(
|
|
790
|
+
f"Failed to connect to any target for {conn_info.conn_name}"
|
|
791
|
+
)
|
|
792
|
+
|
|
697
793
|
def __enter__(self) -> Any:
|
|
698
794
|
"""Enter context manager by returning Connector object"""
|
|
699
795
|
return self
|