@@ -258,6 +258,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
258258 m = re .match (r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$" , path )
259259 return m .groupdict () if m else {}
260260
261+ @classmethod
262+ def get_mtls_endpoint_and_cert_source (
263+ cls , client_options : Optional [client_options_lib .ClientOptions ] = None
264+ ):
265+ """Return the API endpoint and client cert source for mutual TLS.
266+
267+ The client cert source is determined in the following order:
268+ (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
269+ client cert source is None.
270+ (2) if `client_options.client_cert_source` is provided, use the provided one; if the
271+ default client cert source exists, use the default one; otherwise the client cert
272+ source is None.
273+
274+ The API endpoint is determined in the following order:
275+ (1) if `client_options.api_endpoint` if provided, use the provided one.
276+ (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
277+ default mTLS endpoint; if the environment variabel is "never", use the default API
278+ endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
279+ use the default API endpoint.
280+
281+ More details can be found at https://google.aip.dev/auth/4114.
282+
283+ Args:
284+ client_options (google.api_core.client_options.ClientOptions): Custom options for the
285+ client. Only the `api_endpoint` and `client_cert_source` properties may be used
286+ in this method.
287+
288+ Returns:
289+ Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
290+ client cert source to use.
291+
292+ Raises:
293+ google.auth.exceptions.MutualTLSChannelError: If any errors happen.
294+ """
295+ if client_options is None :
296+ client_options = client_options_lib .ClientOptions ()
297+ use_client_cert = os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" )
298+ use_mtls_endpoint = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
299+ if use_client_cert not in ("true" , "false" ):
300+ raise ValueError (
301+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
302+ )
303+ if use_mtls_endpoint not in ("auto" , "never" , "always" ):
304+ raise MutualTLSChannelError (
305+ "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
306+ )
307+
308+ # Figure out the client cert source to use.
309+ client_cert_source = None
310+ if use_client_cert == "true" :
311+ if client_options .client_cert_source :
312+ client_cert_source = client_options .client_cert_source
313+ elif mtls .has_default_client_cert_source ():
314+ client_cert_source = mtls .default_client_cert_source ()
315+
316+ # Figure out which api endpoint to use.
317+ if client_options .api_endpoint is not None :
318+ api_endpoint = client_options .api_endpoint
319+ elif use_mtls_endpoint == "always" or (
320+ use_mtls_endpoint == "auto" and client_cert_source
321+ ):
322+ api_endpoint = cls .DEFAULT_MTLS_ENDPOINT
323+ else :
324+ api_endpoint = cls .DEFAULT_ENDPOINT
325+
326+ return api_endpoint , client_cert_source
327+
261328 def __init__ (
262329 self ,
263330 * ,
@@ -308,57 +375,22 @@ def __init__(
308375 if client_options is None :
309376 client_options = client_options_lib .ClientOptions ()
310377
311- # Create SSL credentials for mutual TLS if needed.
312- if os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) not in (
313- "true" ,
314- "false" ,
315- ):
316- raise ValueError (
317- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
318- )
319- use_client_cert = (
320- os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) == "true"
378+ api_endpoint , client_cert_source_func = self .get_mtls_endpoint_and_cert_source (
379+ client_options
321380 )
322381
323- client_cert_source_func = None
324- is_mtls = False
325- if use_client_cert :
326- if client_options .client_cert_source :
327- is_mtls = True
328- client_cert_source_func = client_options .client_cert_source
329- else :
330- is_mtls = mtls .has_default_client_cert_source ()
331- if is_mtls :
332- client_cert_source_func = mtls .default_client_cert_source ()
333- else :
334- client_cert_source_func = None
335-
336- # Figure out which api endpoint to use.
337- if client_options .api_endpoint is not None :
338- api_endpoint = client_options .api_endpoint
339- else :
340- use_mtls_env = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
341- if use_mtls_env == "never" :
342- api_endpoint = self .DEFAULT_ENDPOINT
343- elif use_mtls_env == "always" :
344- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
345- elif use_mtls_env == "auto" :
346- if is_mtls :
347- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
348- else :
349- api_endpoint = self .DEFAULT_ENDPOINT
350- else :
351- raise MutualTLSChannelError (
352- "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
353- "values: never, auto, always"
354- )
382+ api_key_value = getattr (client_options , "api_key" , None )
383+ if api_key_value and credentials :
384+ raise ValueError (
385+ "client_options.api_key and credentials are mutually exclusive"
386+ )
355387
356388 # Save or instantiate the transport.
357389 # Ordinarily, we provide the transport, but allowing a custom transport
358390 # instance provides an extensibility point for unusual situations.
359391 if isinstance (transport , CloudRedisTransport ):
360392 # transport is a CloudRedisTransport instance.
361- if credentials or client_options .credentials_file :
393+ if credentials or client_options .credentials_file or api_key_value :
362394 raise ValueError (
363395 "When providing a transport instance, "
364396 "provide its credentials directly."
@@ -370,6 +402,15 @@ def __init__(
370402 )
371403 self ._transport = transport
372404 else :
405+ import google .auth ._default # type: ignore
406+
407+ if api_key_value and hasattr (
408+ google .auth ._default , "get_api_key_credentials"
409+ ):
410+ credentials = google .auth ._default .get_api_key_credentials (
411+ api_key_value
412+ )
413+
373414 Transport = type (self ).get_transport_class (transport )
374415 self ._transport = Transport (
375416 credentials = credentials ,
0 commit comments