Skip to content

Commit 8e43bb3

Browse files
authored
feat: Support Developer Edition connections (GoogleCloudPlatform#1433)
1 parent d3eef24 commit 8e43bb3

23 files changed

Lines changed: 2971 additions & 162 deletions

‎.coveragerc‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[report]
2+
exclude_lines =
3+
pragma: no cover
4+
def __repr__
5+
raise AssertionError
6+
raise NotImplementedError
7+
if __name__ == .__main__.:
8+
@abc.abstractmethod
9+
if TYPE_CHECKING:
10+

‎.github/workflows/tests.yml‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ jobs:
8686
POSTGRES_CUSTOMER_CAS_PASS_VALID_DOMAIN_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_CUSTOMER_CAS_PASS_VALID_DOMAIN_NAME
8787
POSTGRES_MCP_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_MCP_CONNECTION_NAME
8888
POSTGRES_MCP_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_MCP_PASS
89+
POSTGRES_AIDE_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_AIDE_CONNECTION_NAME
90+
POSTGRES_AIDE_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_AIDE_USER
91+
POSTGRES_AIDE_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_AIDE_PASS
92+
POSTGRES_AIDE_DB:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_AIDE_DB
93+
POSTGRES_FALLBACK_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_FALLBACK_CONNECTION_NAME
94+
POSTGRES_FALLBACK_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_FALLBACK_USER
95+
POSTGRES_FALLBACK_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_FALLBACK_PASS
96+
POSTGRES_FALLBACK_DB:${{ vars.GOOGLE_CLOUD_PROJECT }}/POSTGRES_FALLBACK_DB
8997
SQLSERVER_CONNECTION_NAME:${{ vars.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_CONNECTION_NAME
9098
SQLSERVER_USER:${{ vars.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_USER
9199
SQLSERVER_PASS:${{ vars.GOOGLE_CLOUD_PROJECT }}/SQLSERVER_PASS
@@ -112,6 +120,14 @@ jobs:
112120
POSTGRES_CUSTOMER_CAS_PASS_VALID_DOMAIN_NAME: "${{ steps.secrets.outputs.POSTGRES_CUSTOMER_CAS_PASS_VALID_DOMAIN_NAME }}"
113121
POSTGRES_MCP_CONNECTION_NAME: "${{ steps.secrets.outputs.POSTGRES_MCP_CONNECTION_NAME }}"
114122
POSTGRES_MCP_PASS: "${{ steps.secrets.outputs.POSTGRES_MCP_PASS }}"
123+
POSTGRES_AIDE_CONNECTION_NAME: "${{ steps.secrets.outputs.POSTGRES_AIDE_CONNECTION_NAME }}"
124+
POSTGRES_AIDE_USER: "${{ steps.secrets.outputs.POSTGRES_AIDE_USER }}"
125+
POSTGRES_AIDE_PASS: "${{ steps.secrets.outputs.POSTGRES_AIDE_PASS }}"
126+
POSTGRES_AIDE_DB: "${{ steps.secrets.outputs.POSTGRES_AIDE_DB }}"
127+
POSTGRES_FALLBACK_CONNECTION_NAME: "${{ steps.secrets.outputs.POSTGRES_FALLBACK_CONNECTION_NAME }}"
128+
POSTGRES_FALLBACK_USER: "${{ steps.secrets.outputs.POSTGRES_FALLBACK_USER }}"
129+
POSTGRES_FALLBACK_PASS: "${{ steps.secrets.outputs.POSTGRES_FALLBACK_PASS }}"
130+
POSTGRES_FALLBACK_DB: "${{ steps.secrets.outputs.POSTGRES_FALLBACK_DB }}"
115131
SQLSERVER_CONNECTION_NAME: "${{ steps.secrets.outputs.SQLSERVER_CONNECTION_NAME }}"
116132
SQLSERVER_USER: "${{ steps.secrets.outputs.SQLSERVER_USER }}"
117133
SQLSERVER_PASS: "${{ steps.secrets.outputs.SQLSERVER_PASS }}"

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dist/
1010
sponge_log.xml
1111
.envrc
1212
*.iml
13+
build/
1314
.mypy_cache/
1415
.nox/
1516
.pytest_cache/

‎README.md‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ from google.cloud.sql.connector import Connector
201201

202202
# Note: all parameters below are optional
203203
connector = Connector(
204-
ip_type="public", # can also be "private" or "psc"
204+
ip_type="public", # can also be "private", "psc", or "sql_data"
205205
enable_iam_auth=False,
206206
timeout=30,
207207
credentials=custom_creds, # google.auth.credentials.Credentials
@@ -279,7 +279,11 @@ with, set the `ip_type` keyword argument when initializing a `Connector()` or wh
279279
calling `connector.connect()`.
280280

281281
Possible values for `ip_type` are `"public"` (default value),
282-
`"private"`, and `"psc"`.
282+
`"private"`, `"psc"`, and `"sql_data"`.
283+
284+
> [!NOTE]
285+
>
286+
> Usage of the `asyncpg` driver does not currently support `ip_type="sql_data"` (`IPTypes.SQL_DATA`).
283287
284288
Example:
285289

‎build.sh‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,14 @@ function write_e2e_env(){
120120
POSTGRES_CUSTOMER_CAS_INVALID_DOMAIN_NAME=POSTGRES_CUSTOMER_CAS_INVALID_DOMAIN_NAME
121121
POSTGRES_MCP_CONNECTION_NAME=POSTGRES_MCP_CONNECTION_NAME
122122
POSTGRES_MCP_PASS=POSTGRES_MCP_PASS
123+
POSTGRES_AIDE_CONNECTION_NAME=POSTGRES_AIDE_CONNECTION_NAME
124+
POSTGRES_AIDE_USER=POSTGRES_AIDE_USER
125+
POSTGRES_AIDE_PASS=POSTGRES_AIDE_PASS
126+
POSTGRES_AIDE_DB=POSTGRES_AIDE_DB
127+
POSTGRES_FALLBACK_CONNECTION_NAME=POSTGRES_FALLBACK_CONNECTION_NAME
128+
POSTGRES_FALLBACK_USER=POSTGRES_FALLBACK_USER
129+
POSTGRES_FALLBACK_PASS=POSTGRES_FALLBACK_PASS
130+
POSTGRES_FALLBACK_DB=POSTGRES_FALLBACK_DB
123131
SQLSERVER_CONNECTION_NAME=SQLSERVER_CONNECTION_NAME
124132
SQLSERVER_USER=SQLSERVER_USER
125133
SQLSERVER_PASS=SQLSERVER_PASS

‎google/cloud/sql/connector/client.py‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,13 @@ async def _get_metadata(
173173
if psc_dns_names:
174174
ip_addresses["PSC"] = psc_dns_names
175175

176+
server_ca_cert = None
177+
if "serverCaCert" in ret_dict and "cert" in ret_dict["serverCaCert"]:
178+
server_ca_cert = ret_dict["serverCaCert"]["cert"]
179+
176180
return {
177181
"ip_addresses": ip_addresses,
178-
"server_ca_cert": ret_dict["serverCaCert"]["cert"],
182+
"server_ca_cert": server_ca_cert,
179183
"database_version": ret_dict["databaseVersion"],
180184
}
181185

@@ -271,7 +275,15 @@ async def _get_ephemeral(
271275
finally:
272276
resp.raise_for_status()
273277

274-
ephemeral_cert: str = ret_dict["ephemeralCert"]["cert"]
278+
try:
279+
ephemeral_cert: str = ret_dict["ephemeralCert"]["cert"]
280+
except KeyError as e:
281+
logger.error(
282+
"KeyError in _get_ephemeral parsing generateEphemeralCert: %s. Response dict: %s",
283+
e,
284+
ret_dict,
285+
)
286+
raise
275287

276288
# decode cert to read expiration
277289
x509 = load_pem_x509_certificate(

‎google/cloud/sql/connector/connection_info.py‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from typing import Any, TYPE_CHECKING
2222

2323
from google.cloud.sql.connector.connection_name import ConnectionName
24+
from google.cloud.sql.connector.exceptions import CloudSQLConnectionError
2425
from google.cloud.sql.connector.exceptions import CloudSQLIPTypeError
2526
from google.cloud.sql.connector.exceptions import TLSVersionError
2627
from google.cloud.sql.connector.utils import AsyncTemporaryDirectory
@@ -62,7 +63,7 @@ class ConnectionInfo:
6263

6364
conn_name: ConnectionName
6465
client_cert: str
65-
server_ca_cert: str
66+
server_ca_cert: str | None
6667
private_key: bytes
6768
ip_addrs: dict[str, Any]
6869
database_version: str
@@ -78,6 +79,12 @@ async def create_ssl_context(self, enable_iam_auth: bool = False) -> ssl.SSLCont
7879
# if SSL context is cached, use it
7980
if self.context is not None:
8081
return self.context
82+
83+
if self.server_ca_cert is None:
84+
raise CloudSQLConnectionError(
85+
"Cannot create SSL context: server CA certificate is missing."
86+
)
87+
8188
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
8289

8390
# update ssl.PROTOCOL_TLS_CLIENT default

0 commit comments

Comments
 (0)