@@ -84,13 +84,17 @@ def from_instance(
84
84
region : str ,
85
85
instance : str ,
86
86
database : str ,
87
+ user : Optional [str ] = None ,
88
+ password : Optional [str ] = None ,
87
89
) -> MySQLEngine :
88
90
"""Create an instance of MySQLEngine from Cloud SQL instance
89
91
details.
90
92
91
93
This method uses the Cloud SQL Python Connector to connect to Cloud SQL
92
94
using automatic IAM database authentication with the Google ADC
93
- credentials sourced from the environment.
95
+ credentials sourced from the environment by default. If user and
96
+ password arguments are given, basic database authentication will be
97
+ used for database login.
94
98
95
99
More details can be found at https://github.com/GoogleCloudPlatform/cloud-sql-python-connector#credentials
96
100
@@ -101,42 +105,74 @@ def from_instance(
101
105
instance (str): The name of the Cloud SQL instance.
102
106
database (str): The name of the database to connect to on the
103
107
Cloud SQL instance.
108
+ user (str, optional): Database user to use for basic database
109
+ authentication and login. Defaults to None.
110
+ password (str, optional): Database password for 'user' to use for
111
+ basic database authentication and login. Defaults to None.
104
112
105
113
Returns:
106
114
(MySQLEngine): The engine configured to connect to a
107
115
Cloud SQL instance database.
108
116
"""
117
+ # error if only one of user or password is set, must be both or neither
118
+ if bool (user ) ^ bool (password ):
119
+ raise ValueError (
120
+ "Only one of 'user' or 'password' were specified. Either "
121
+ "both should be specified to use basic user/password "
122
+ "authentication or neither for IAM DB authentication."
123
+ )
109
124
engine = cls ._create_connector_engine (
110
125
instance_connection_name = f"{ project_id } :{ region } :{ instance } " ,
111
126
database = database ,
127
+ user = user ,
128
+ password = password ,
112
129
)
113
130
return cls (engine = engine )
114
131
115
132
@classmethod
116
133
def _create_connector_engine (
117
- cls , instance_connection_name : str , database : str
134
+ cls ,
135
+ instance_connection_name : str ,
136
+ database : str ,
137
+ user : Optional [str ],
138
+ password : Optional [str ],
118
139
) -> sqlalchemy .engine .Engine :
119
140
"""Create a SQLAlchemy engine using the Cloud SQL Python Connector.
120
141
121
142
Defaults to use "pymysql" driver and to connect using automatic IAM
122
143
database authentication with the IAM principal associated with the
123
- environment's Google Application Default Credentials.
144
+ environment's Google Application Default Credentials. If user and
145
+ password arguments are given, basic database authentication will be
146
+ used for database login.
124
147
125
148
Args:
126
149
instance_connection_name (str): The instance connection
127
150
name of the Cloud SQL instance to establish a connection to.
128
151
(ex. "project-id:instance-region:instance-name")
129
152
database (str): The name of the database to connect to on the
130
153
Cloud SQL instance.
154
+ user (str, optional): Database user to use for basic database
155
+ authentication and login. Defaults to None.
156
+ password (str, optional): Database password for 'user' to use for
157
+ basic database authentication and login. Defaults to None.
158
+
131
159
Returns:
132
160
(sqlalchemy.engine.Engine): Engine configured using the Cloud SQL
133
161
Python Connector.
134
162
"""
135
- # get application default credentials
136
- credentials , _ = google .auth .default (
137
- scopes = ["https://www.googleapis.com/auth/userinfo.email" ]
138
- )
139
- iam_database_user = _get_iam_principal_email (credentials )
163
+ # if user and password are given, use basic auth
164
+ if user and password :
165
+ enable_iam_auth = False
166
+ db_user = user
167
+ # otherwise use automatic IAM database authentication
168
+ else :
169
+ # get application default credentials
170
+ credentials , _ = google .auth .default (
171
+ scopes = ["https://www.googleapis.com/auth/userinfo.email" ]
172
+ )
173
+ db_user = _get_iam_principal_email (credentials )
174
+ enable_iam_auth = True
175
+
140
176
if cls ._connector is None :
141
177
cls ._connector = Connector ()
142
178
@@ -145,9 +181,10 @@ def getconn() -> pymysql.Connection:
145
181
conn = cls ._connector .connect ( # type: ignore
146
182
instance_connection_name ,
147
183
"pymysql" ,
148
- user = iam_database_user ,
184
+ user = db_user ,
185
+ password = password ,
149
186
db = database ,
150
- enable_iam_auth = True ,
187
+ enable_iam_auth = enable_iam_auth ,
151
188
)
152
189
return conn
153
190
0 commit comments