@@ -85,11 +85,13 @@ def get_transport_class(cls, label: str = None,) -> Type[DatabaseAdminTransport]
85
85
86
86
class DatabaseAdminClient (metaclass = DatabaseAdminClientMeta ):
87
87
"""Cloud Spanner Database Admin API
88
- The Cloud Spanner Database Admin API can be used to create,
89
- drop, and list databases. It also enables updating the schema of
90
- pre-existing databases. It can be also used to create, delete
91
- and list backups for a database and to restore from an existing
92
- backup.
88
+
89
+ The Cloud Spanner Database Admin API can be used to:
90
+
91
+ - create, drop, and list databases
92
+ - update the schema of pre-existing databases
93
+ - create, delete and list backups for a database
94
+ - restore a database from an existing backup
93
95
"""
94
96
95
97
@staticmethod
@@ -325,6 +327,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
325
327
m = re .match (r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$" , path )
326
328
return m .groupdict () if m else {}
327
329
330
+ @classmethod
331
+ def get_mtls_endpoint_and_cert_source (
332
+ cls , client_options : Optional [client_options_lib .ClientOptions ] = None
333
+ ):
334
+ """Return the API endpoint and client cert source for mutual TLS.
335
+
336
+ The client cert source is determined in the following order:
337
+ (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
338
+ client cert source is None.
339
+ (2) if `client_options.client_cert_source` is provided, use the provided one; if the
340
+ default client cert source exists, use the default one; otherwise the client cert
341
+ source is None.
342
+
343
+ The API endpoint is determined in the following order:
344
+ (1) if `client_options.api_endpoint` if provided, use the provided one.
345
+ (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
346
+ default mTLS endpoint; if the environment variabel is "never", use the default API
347
+ endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
348
+ use the default API endpoint.
349
+
350
+ More details can be found at https://google.aip.dev/auth/4114.
351
+
352
+ Args:
353
+ client_options (google.api_core.client_options.ClientOptions): Custom options for the
354
+ client. Only the `api_endpoint` and `client_cert_source` properties may be used
355
+ in this method.
356
+
357
+ Returns:
358
+ Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
359
+ client cert source to use.
360
+
361
+ Raises:
362
+ google.auth.exceptions.MutualTLSChannelError: If any errors happen.
363
+ """
364
+ if client_options is None :
365
+ client_options = client_options_lib .ClientOptions ()
366
+ use_client_cert = os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" )
367
+ use_mtls_endpoint = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
368
+ if use_client_cert not in ("true" , "false" ):
369
+ raise ValueError (
370
+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
371
+ )
372
+ if use_mtls_endpoint not in ("auto" , "never" , "always" ):
373
+ raise MutualTLSChannelError (
374
+ "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
375
+ )
376
+
377
+ # Figure out the client cert source to use.
378
+ client_cert_source = None
379
+ if use_client_cert == "true" :
380
+ if client_options .client_cert_source :
381
+ client_cert_source = client_options .client_cert_source
382
+ elif mtls .has_default_client_cert_source ():
383
+ client_cert_source = mtls .default_client_cert_source ()
384
+
385
+ # Figure out which api endpoint to use.
386
+ if client_options .api_endpoint is not None :
387
+ api_endpoint = client_options .api_endpoint
388
+ elif use_mtls_endpoint == "always" or (
389
+ use_mtls_endpoint == "auto" and client_cert_source
390
+ ):
391
+ api_endpoint = cls .DEFAULT_MTLS_ENDPOINT
392
+ else :
393
+ api_endpoint = cls .DEFAULT_ENDPOINT
394
+
395
+ return api_endpoint , client_cert_source
396
+
328
397
def __init__ (
329
398
self ,
330
399
* ,
@@ -375,57 +444,22 @@ def __init__(
375
444
if client_options is None :
376
445
client_options = client_options_lib .ClientOptions ()
377
446
378
- # Create SSL credentials for mutual TLS if needed.
379
- if os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) not in (
380
- "true" ,
381
- "false" ,
382
- ):
383
- raise ValueError (
384
- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
385
- )
386
- use_client_cert = (
387
- os .getenv ("GOOGLE_API_USE_CLIENT_CERTIFICATE" , "false" ) == "true"
447
+ api_endpoint , client_cert_source_func = self .get_mtls_endpoint_and_cert_source (
448
+ client_options
388
449
)
389
450
390
- client_cert_source_func = None
391
- is_mtls = False
392
- if use_client_cert :
393
- if client_options .client_cert_source :
394
- is_mtls = True
395
- client_cert_source_func = client_options .client_cert_source
396
- else :
397
- is_mtls = mtls .has_default_client_cert_source ()
398
- if is_mtls :
399
- client_cert_source_func = mtls .default_client_cert_source ()
400
- else :
401
- client_cert_source_func = None
402
-
403
- # Figure out which api endpoint to use.
404
- if client_options .api_endpoint is not None :
405
- api_endpoint = client_options .api_endpoint
406
- else :
407
- use_mtls_env = os .getenv ("GOOGLE_API_USE_MTLS_ENDPOINT" , "auto" )
408
- if use_mtls_env == "never" :
409
- api_endpoint = self .DEFAULT_ENDPOINT
410
- elif use_mtls_env == "always" :
411
- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
412
- elif use_mtls_env == "auto" :
413
- if is_mtls :
414
- api_endpoint = self .DEFAULT_MTLS_ENDPOINT
415
- else :
416
- api_endpoint = self .DEFAULT_ENDPOINT
417
- else :
418
- raise MutualTLSChannelError (
419
- "Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
420
- "values: never, auto, always"
421
- )
451
+ api_key_value = getattr (client_options , "api_key" , None )
452
+ if api_key_value and credentials :
453
+ raise ValueError (
454
+ "client_options.api_key and credentials are mutually exclusive"
455
+ )
422
456
423
457
# Save or instantiate the transport.
424
458
# Ordinarily, we provide the transport, but allowing a custom transport
425
459
# instance provides an extensibility point for unusual situations.
426
460
if isinstance (transport , DatabaseAdminTransport ):
427
461
# transport is a DatabaseAdminTransport instance.
428
- if credentials or client_options .credentials_file :
462
+ if credentials or client_options .credentials_file or api_key_value :
429
463
raise ValueError (
430
464
"When providing a transport instance, "
431
465
"provide its credentials directly."
@@ -437,6 +471,15 @@ def __init__(
437
471
)
438
472
self ._transport = transport
439
473
else :
474
+ import google .auth ._default # type: ignore
475
+
476
+ if api_key_value and hasattr (
477
+ google .auth ._default , "get_api_key_credentials"
478
+ ):
479
+ credentials = google .auth ._default .get_api_key_credentials (
480
+ api_key_value
481
+ )
482
+
440
483
Transport = type (self ).get_transport_class (transport )
441
484
self ._transport = Transport (
442
485
credentials = credentials ,
@@ -843,7 +886,8 @@ def drop_database(
843
886
) -> None :
844
887
r"""Drops (aka deletes) a Cloud Spanner database. Completed backups
845
888
for the database will be retained according to their
846
- ``expire_time``.
889
+ ``expire_time``. Note: Cloud Spanner might continue to accept
890
+ requests for a few seconds after the database has been deleted.
847
891
848
892
Args:
849
893
request (Union[google.cloud.spanner_admin_database_v1.types.DropDatabaseRequest, dict]):
0 commit comments