@@ -231,6 +231,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
231231 m = re .match (r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$" , path )
232232 return m .groupdict () if m else {}
233233
234+ @classmethod
235+ def get_mtls_endpoint_and_cert_source (
236+ cls , client_options : Optional [client_options_lib .ClientOptions ] = None
237+ ):
238+ """Return the API endpoint and client cert source for mutual TLS.
239+
240+ The client cert source is determined in the following order:
241+ (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
242+ client cert source is None.
243+ (2) if `client_options.client_cert_source` is provided, use the provided one; if the
244+ default client cert source exists, use the default one; otherwise the client cert
245+ source is None.
246+
247+ The API endpoint is determined in the following order:
248+ (1) if `client_options.api_endpoint` if provided, use the provided one.
249+ (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
250+ default mTLS endpoint; if the environment variabel is "never", use the default API
251+ endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
252+ use the default API endpoint.
253+
254+ More details can be found at https://google.aip.dev/auth/4114.
255+
256+ Args:
257+ client_options (google.api_core.client_options.ClientOptions): Custom options for the
258+ client. Only the `api_endpoint` and `client_cert_source` properties may be used
259+ in this method.
260+
261+ Returns:
262+ Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
263+ client cert source to use.
264+
265+ Raises:
266+ google.auth.exceptions.MutualTLSChannelError: If any errors happen.
267+ """
268+ if client_options is None :
269+ client_options = client_options_lib .ClientOptions ()
270+ use_client_cert = os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" )
271+ use_mtls_endpoint = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
272+ if use_client_cert not in ("true" , "false" ):
273+ raise ValueError (
274+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
275+ )
276+ if use_mtls_endpoint not in ("auto" , "never" , "always" ):
277+ raise MutualTLSChannelError (
278+ "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
279+ )
280+
281+ # Figure out the client cert source to use.
282+ client_cert_source = None
283+ if use_client_cert == "true" :
284+ if client_options .client_cert_source :
285+ client_cert_source = client_options .client_cert_source
286+ elif mtls .has_default_client_cert_source ():
287+ client_cert_source = mtls .default_client_cert_source ()
288+
289+ # Figure out which api endpoint to use.
290+ if client_options .api_endpoint is not None :
291+ api_endpoint = client_options .api_endpoint
292+ elif use_mtls_endpoint == "always" or (
293+ use_mtls_endpoint == "auto" and client_cert_source
294+ ):
295+ api_endpoint = cls .DEFAULT_MTLS_ENDPOINT
296+ else :
297+ api_endpoint = cls .DEFAULT_ENDPOINT
298+
299+ return api_endpoint , client_cert_source
300+
234301 def __init__ (
235302 self ,
236303 * ,
@@ -281,57 +348,22 @@ def __init__(
281348 if client_options is None :
282349 client_options = client_options_lib .ClientOptions ()
283350
284- # Create SSL credentials for mutual TLS if needed.
285- if os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) not in (
286- "true" ,
287- "false" ,
288- ):
289- raise ValueError (
290- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
291- )
292- use_client_cert = (
293- os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) == "true"
351+ api_endpoint , client_cert_source_func = self .get_mtls_endpoint_and_cert_source (
352+ client_options
294353 )
295354
296- client_cert_source_func = None
297- is_mtls = False
298- if use_client_cert :
299- if client_options .client_cert_source :
300- is_mtls = True
301- client_cert_source_func = client_options .client_cert_source
302- else :
303- is_mtls = mtls .has_default_client_cert_source ()
304- if is_mtls :
305- client_cert_source_func = mtls .default_client_cert_source ()
306- else :
307- client_cert_source_func = None
308-
309- # Figure out which api endpoint to use.
310- if client_options .api_endpoint is not None :
311- api_endpoint = client_options .api_endpoint
312- else :
313- use_mtls_env = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
314- if use_mtls_env == "never" :
315- api_endpoint = self .DEFAULT_ENDPOINT
316- elif use_mtls_env == "always" :
317- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
318- elif use_mtls_env == "auto" :
319- if is_mtls :
320- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
321- else :
322- api_endpoint = self .DEFAULT_ENDPOINT
323- else :
324- raise MutualTLSChannelError (
325- "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
326- "values: never, auto, always"
327- )
355+ api_key_value = getattr (client_options , "api_key" , None )
356+ if api_key_value and credentials :
357+ raise ValueError (
358+ "client_options.api_key and credentials are mutually exclusive"
359+ )
328360
329361 # Save or instantiate the transport.
330362 # Ordinarily, we provide the transport, but allowing a custom transport
331363 # instance provides an extensibility point for unusual situations.
332364 if isinstance (transport , ErrorGroupServiceTransport ):
333365 # transport is a ErrorGroupServiceTransport instance.
334- if credentials or client_options .credentials_file :
366+ if credentials or client_options .credentials_file or api_key_value :
335367 raise ValueError (
336368 "When providing a transport instance, "
337369 "provide its credentials directly."
@@ -343,6 +375,15 @@ def __init__(
343375 )
344376 self ._transport = transport
345377 else :
378+ import google .auth ._default # type: ignore
379+
380+ if api_key_value and hasattr (
381+ google .auth ._default , "get_api_key_credentials"
382+ ):
383+ credentials = google .auth ._default .get_api_key_credentials (
384+ api_key_value
385+ )
386+
346387 Transport = type (self ).get_transport_class (transport )
347388 self ._transport = Transport (
348389 credentials = credentials ,
0 commit comments