Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: validate driver with database engine #1108

Merged
merged 3 commits into from
Jun 3, 2024

Conversation

jackwotherspoon
Copy link
Collaborator

@jackwotherspoon jackwotherspoon commented Jun 3, 2024

Removing ambiguous behavior if a user configures a database
driver to connect to an incompatible database engine.

i.e. pymysql (MySQL driver) -> Cloud SQL for PostgreSQL database

This behavior would timeout trying to connect and then throw
an ambiguous timeout error.

The Connector.connect already know which database engine
the Cloud SQL database is prior to attempting to connect via the
driver. So we can validate if the driver is compatible and throw an
actionable error if not.

Closes #998

@jackwotherspoon jackwotherspoon self-assigned this Jun 3, 2024
@jackwotherspoon jackwotherspoon requested a review from a team as a code owner June 3, 2024 13:16
Comment on lines +18 to +24
class DriverMapping(Enum):
"""Maps a given database driver to it's corresponding database engine."""

ASYNCPG = "POSTGRES"
PG8000 = "POSTGRES"
PYMYSQL = "MYSQL"
PYTDS = "SQLSERVER"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to have a follow-up refactor PR that moves the other shared enum types (IPTypes, RefreshStrategy) out of instance.py and into this file.

@@ -321,6 +323,14 @@ async def connect_async(
# attempt to make connection to Cloud SQL instance
try:
conn_info = await cache.connect_info()
# validate driver matches intended database engine
mapping = DriverMapping[driver.upper()]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we encapsulated more details and did something like this?

conn_info = await cache.connect_info()
if not DriverMapping.matching_engine(driver, conn_info.database_version):
    raise IncompatibleDriverError

where the DriverMapping method looks like:

class DriverMapping(Enum):
    def matching_engine(driver: str, engine: str) -> bool:
        return engine.startswith(DriverMapping[driver.upper()])

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would mean i no longer have access to the proper compatible database engine mapping.value in the error message without doing a separate call to DriverMapping[driver.upper()].value which is more work...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an idea -- feel free to handle it however you like. A good error message is most important.

mapping = DriverMapping[driver.upper()]
if not conn_info.database_version.startswith(mapping.value):
raise IncompatibleDriverError(
f"Database driver '{driver}' is incompatible with database "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a fatal configuration error. I think the message could be more clear. Something like:

"Fatal Error: the Cloud SQL Connector is configured with an incompatible database driver. Configured driver '{driver}' cannot connect to database instance '{instance_connection_string}' running version {conn_info.database_version}."

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hessjcg I don't normally see Python errors get prefixed with "Fatal Error:", its more the assumption that if an error is raised from the application it must be fatal.

I like the error message as is personally, concise and actionable. I don't have access to instance_connection_string from where the error is raised after the encapsulation refactor...

@jackwotherspoon jackwotherspoon merged commit a7c7861 into main Jun 3, 2024
15 checks passed
@jackwotherspoon jackwotherspoon deleted the validate-driver-type branch June 3, 2024 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Validate driver matches database type
3 participants