GeezerVison is showing github.com — feat(gapic): support mTLS certificates when available (#1249) · googleapis/python-bigtable@ca20219
This repository was archived by the owner on Aug 30, 2026. It is now read-only.
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: .librarian/generator-input/setup.py -4Lines changed: 0 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 94 | 94 | packages=packages, | 95 | 95 | install_requires=dependencies, | 96 | 96 | extras_require=extras, | 97 | | - scripts=[ | 98 | | - "scripts/fixup_bigtable_v2_keywords.py", | 99 | | - "scripts/fixup_admin_v2_keywords.py", | 100 | | - ], | 101 | 97 | python_requires=">=3.7", | 102 | 98 | include_package_data=True, | 103 | 99 | zip_safe=False, | |
Collapse file Copy file name to clipboardExpand all lines: .librarian/state.yaml +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
| 1 | | -image: us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator@sha256:8e2c32496077054105bd06c54a59d6a6694287bc053588e24debe6da6920ad91 | | 1 | +image: us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator@sha256:b8058df4c45e9a6e07f6b4d65b458d0d059241dd34c814f151c8bf6b89211209 | 2 | 2 | libraries: | 3 | 3 | - id: google-cloud-bigtable | 4 | 4 | version: 2.34.0 | |
Collapse file Copy file name to clipboardExpand all lines: google/cloud/bigtable_admin_v2/__init__.py +104Lines changed: 104 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 15 | 15 | # | 16 | 16 | from google.cloud.bigtable_admin_v2 import gapic_version as package_version | 17 | 17 |
| | 18 | +import google.api_core as api_core | | 19 | +import sys | | 20 | + | 18 | 21 | __version__ = package_version.__version__ | 19 | 22 |
| | 23 | +if sys.version_info >= (3, 8): # pragma: NO COVER | | 24 | + from importlib import metadata | | 25 | +else: # pragma: NO COVER | | 26 | + # TODO(https://github.com/googleapis/python-api-core/issues/835): Remove | | 27 | + # this code path once we drop support for Python 3.7 | | 28 | + import importlib_metadata as metadata | | 29 | + | 20 | 30 |
| 21 | 31 | from .services.bigtable_instance_admin import BigtableInstanceAdminClient | 22 | 32 | from .services.bigtable_instance_admin import BigtableInstanceAdminAsyncClient | | 143 | 153 | from .types.table import RestoreSourceType | 144 | 154 | from .types.types import Type | 145 | 155 |
| | 156 | +if hasattr(api_core, "check_python_version") and hasattr( | | 157 | + api_core, "check_dependency_versions" | | 158 | +): # pragma: NO COVER | | 159 | + api_core.check_python_version("google.cloud.bigtable_admin_v2") # type: ignore | | 160 | + api_core.check_dependency_versions("google.cloud.bigtable_admin_v2") # type: ignore | | 161 | +else: # pragma: NO COVER | | 162 | + # An older version of api_core is installed which does not define the | | 163 | + # functions above. We do equivalent checks manually. | | 164 | + try: | | 165 | + import warnings | | 166 | + import sys | | 167 | + | | 168 | + _py_version_str = sys.version.split()[0] | | 169 | + _package_label = "google.cloud.bigtable_admin_v2" | | 170 | + if sys.version_info < (3, 9): | | 171 | + warnings.warn( | | 172 | + "You are using a non-supported Python version " | | 173 | + + f"({_py_version_str}). Google will not post any further " | | 174 | + + f"updates to {_package_label} supporting this Python version. " | | 175 | + + "Please upgrade to the latest Python version, or at " | | 176 | + + f"least to Python 3.9, and then update {_package_label}.", | | 177 | + FutureWarning, | | 178 | + ) | | 179 | + if sys.version_info[:2] == (3, 9): | | 180 | + warnings.warn( | | 181 | + f"You are using a Python version ({_py_version_str}) " | | 182 | + + f"which Google will stop supporting in {_package_label} in " | | 183 | + + "January 2026. Please " | | 184 | + + "upgrade to the latest Python version, or at " | | 185 | + + "least to Python 3.10, before then, and " | | 186 | + + f"then update {_package_label}.", | | 187 | + FutureWarning, | | 188 | + ) | | 189 | + | | 190 | + def parse_version_to_tuple(version_string: str): | | 191 | + """Safely converts a semantic version string to a comparable tuple of integers. | | 192 | + Example: "4.25.8" -> (4, 25, 8) | | 193 | + Ignores non-numeric parts and handles common version formats. | | 194 | + Args: | | 195 | + version_string: Version string in the format "x.y.z" or "x.y.z<suffix>" | | 196 | + Returns: | | 197 | + Tuple of integers for the parsed version string. | | 198 | + """ | | 199 | + parts = [] | | 200 | + for part in version_string.split("."): | | 201 | + try: | | 202 | + parts.append(int(part)) | | 203 | + except ValueError: | | 204 | + # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here. | | 205 | + # This is a simplification compared to 'packaging.parse_version', but sufficient | | 206 | + # for comparing strictly numeric semantic versions. | | 207 | + break | | 208 | + return tuple(parts) | | 209 | + | | 210 | + def _get_version(dependency_name): | | 211 | + try: | | 212 | + version_string: str = metadata.version(dependency_name) | | 213 | + parsed_version = parse_version_to_tuple(version_string) | | 214 | + return (parsed_version, version_string) | | 215 | + except Exception: | | 216 | + # Catch exceptions from metadata.version() (e.g., PackageNotFoundError) | | 217 | + # or errors during parse_version_to_tuple | | 218 | + return (None, "--") | | 219 | + | | 220 | + _dependency_package = "google.protobuf" | | 221 | + _next_supported_version = "4.25.8" | | 222 | + _next_supported_version_tuple = (4, 25, 8) | | 223 | + _recommendation = " (we recommend 6.x)" | | 224 | + (_version_used, _version_used_string) = _get_version(_dependency_package) | | 225 | + if _version_used and _version_used < _next_supported_version_tuple: | | 226 | + warnings.warn( | | 227 | + f"Package {_package_label} depends on " | | 228 | + + f"{_dependency_package}, currently installed at version " | | 229 | + + f"{_version_used_string}. Future updates to " | | 230 | + + f"{_package_label} will require {_dependency_package} at " | | 231 | + + f"version {_next_supported_version} or higher{_recommendation}." | | 232 | + + " Please ensure " | | 233 | + + "that either (a) your Python environment doesn't pin the " | | 234 | + + f"version of {_dependency_package}, so that updates to " | | 235 | + + f"{_package_label} can require the higher version, or " | | 236 | + + "(b) you manually update your Python environment to use at " | | 237 | + + f"least version {_next_supported_version} of " | | 238 | + + f"{_dependency_package}.", | | 239 | + FutureWarning, | | 240 | + ) | | 241 | + except Exception: | | 242 | + warnings.warn( | | 243 | + "Could not determine the version of Python " | | 244 | + + "currently being used. To continue receiving " | | 245 | + + "updates for {_package_label}, ensure you are " | | 246 | + + "using a supported version of Python; see " | | 247 | + + "https://devguide.python.org/versions/" | | 248 | + ) | | 249 | + | 146 | 250 | __all__ = ( | 147 | 251 | "BaseBigtableTableAdminAsyncClient", | 148 | 252 | "BigtableInstanceAdminAsyncClient", | |
Collapse file Copy file name to clipboardExpand all lines: google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/client.py +32-14Lines changed: 32 additions & 14 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -161,6 +161,34 @@ def _get_default_mtls_endpoint(api_endpoint): | 161 | 161 | _DEFAULT_ENDPOINT_TEMPLATE = "bigtableadmin.{UNIVERSE_DOMAIN}" | 162 | 162 | _DEFAULT_UNIVERSE = "googleapis.com" | 163 | 163 |
| | 164 | + @staticmethod | | 165 | + def _use_client_cert_effective(): | | 166 | + """Returns whether client certificate should be used for mTLS if the | | 167 | + google-auth version supports should_use_client_cert automatic mTLS enablement. | | 168 | +
| | 169 | + Alternatively, read from the GOOGLE_API_USE_CLIENT_CERTIFICATE env var. | | 170 | +
| | 171 | + Returns: | | 172 | + bool: whether client certificate should be used for mTLS | | 173 | + Raises: | | 174 | + ValueError: (If using a version of google-auth without should_use_client_cert and | | 175 | + GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) | | 176 | + """ | | 177 | + # check if google-auth version supports should_use_client_cert for automatic mTLS enablement | | 178 | + if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER | | 179 | + return mtls.should_use_client_cert() | | 180 | + else: # pragma: NO COVER | | 181 | + # if unsupported, fallback to reading from env var | | 182 | + use_client_cert_str = os.getenv( | | 183 | + "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false" | | 184 | + ).lower() | | 185 | + if use_client_cert_str not in ("true", "false"): | | 186 | + raise ValueError( | | 187 | + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" | | 188 | + " either `true` or `false`" | | 189 | + ) | | 190 | + return use_client_cert_str == "true" | | 191 | + | 164 | 192 | @classmethod | 165 | 193 | def from_service_account_info(cls, info: dict, *args, **kwargs): | 166 | 194 | """Creates an instance of this client using the provided credentials | @@ -503,20 +531,16 @@ def get_mtls_endpoint_and_cert_source( | 503 | 531 | ) | 504 | 532 | if client_options is None: | 505 | 533 | client_options = client_options_lib.ClientOptions() | 506 | | - use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") | | 534 | + use_client_cert = BigtableInstanceAdminClient._use_client_cert_effective() | 507 | 535 | use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") | 508 | | - if use_client_cert not in ("true", "false"): | 509 | | - raise ValueError( | 510 | | - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" | 511 | | - ) | 512 | 536 | if use_mtls_endpoint not in ("auto", "never", "always"): | 513 | 537 | raise MutualTLSChannelError( | 514 | 538 | "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" | 515 | 539 | ) | 516 | 540 |
| 517 | 541 | # Figure out the client cert source to use. | 518 | 542 | client_cert_source = None | 519 | | - if use_client_cert == "true": | | 543 | + if use_client_cert: | 520 | 544 | if client_options.client_cert_source: | 521 | 545 | client_cert_source = client_options.client_cert_source | 522 | 546 | elif mtls.has_default_client_cert_source(): | @@ -548,20 +572,14 @@ def _read_environment_variables(): | 548 | 572 | google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT | 549 | 573 | is not any of ["auto", "never", "always"]. | 550 | 574 | """ | 551 | | - use_client_cert = os.getenv( | 552 | | - "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false" | 553 | | - ).lower() | | 575 | + use_client_cert = BigtableInstanceAdminClient._use_client_cert_effective() | 554 | 576 | use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() | 555 | 577 | universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") | 556 | | - if use_client_cert not in ("true", "false"): | 557 | | - raise ValueError( | 558 | | - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" | 559 | | - ) | 560 | 578 | if use_mtls_endpoint not in ("auto", "never", "always"): | 561 | 579 | raise MutualTLSChannelError( | 562 | 580 | "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" | 563 | 581 | ) | 564 | | - return use_client_cert == "true", use_mtls_endpoint, universe_domain_env | | 582 | + return use_client_cert, use_mtls_endpoint, universe_domain_env | 565 | 583 |
| 566 | 584 | @staticmethod | 567 | 585 | def _get_client_cert_source(provided_cert_source, use_cert_flag): | |
Collapse file Copy file name to clipboardExpand all lines: google/cloud/bigtable_admin_v2/services/bigtable_table_admin/client.py +32-14Lines changed: 32 additions & 14 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -162,6 +162,34 @@ def _get_default_mtls_endpoint(api_endpoint): | 162 | 162 | _DEFAULT_ENDPOINT_TEMPLATE = "bigtableadmin.{UNIVERSE_DOMAIN}" | 163 | 163 | _DEFAULT_UNIVERSE = "googleapis.com" | 164 | 164 |
| | 165 | + @staticmethod | | 166 | + def _use_client_cert_effective(): | | 167 | + """Returns whether client certificate should be used for mTLS if the | | 168 | + google-auth version supports should_use_client_cert automatic mTLS enablement. | | 169 | +
| | 170 | + Alternatively, read from the GOOGLE_API_USE_CLIENT_CERTIFICATE env var. | | 171 | +
| | 172 | + Returns: | | 173 | + bool: whether client certificate should be used for mTLS | | 174 | + Raises: | | 175 | + ValueError: (If using a version of google-auth without should_use_client_cert and | | 176 | + GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.) | | 177 | + """ | | 178 | + # check if google-auth version supports should_use_client_cert for automatic mTLS enablement | | 179 | + if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER | | 180 | + return mtls.should_use_client_cert() | | 181 | + else: # pragma: NO COVER | | 182 | + # if unsupported, fallback to reading from env var | | 183 | + use_client_cert_str = os.getenv( | | 184 | + "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false" | | 185 | + ).lower() | | 186 | + if use_client_cert_str not in ("true", "false"): | | 187 | + raise ValueError( | | 188 | + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" | | 189 | + " either `true` or `false`" | | 190 | + ) | | 191 | + return use_client_cert_str == "true" | | 192 | + | 165 | 193 | @classmethod | 166 | 194 | def from_service_account_info(cls, info: dict, *args, **kwargs): | 167 | 195 | """Creates an instance of this client using the provided credentials | @@ -510,20 +538,16 @@ def get_mtls_endpoint_and_cert_source( | 510 | 538 | ) | 511 | 539 | if client_options is None: | 512 | 540 | client_options = client_options_lib.ClientOptions() | 513 | | - use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") | | 541 | + use_client_cert = BaseBigtableTableAdminClient._use_client_cert_effective() | 514 | 542 | use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto") | 515 | | - if use_client_cert not in ("true", "false"): | 516 | | - raise ValueError( | 517 | | - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" | 518 | | - ) | 519 | 543 | if use_mtls_endpoint not in ("auto", "never", "always"): | 520 | 544 | raise MutualTLSChannelError( | 521 | 545 | "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" | 522 | 546 | ) | 523 | 547 |
| 524 | 548 | # Figure out the client cert source to use. | 525 | 549 | client_cert_source = None | 526 | | - if use_client_cert == "true": | | 550 | + if use_client_cert: | 527 | 551 | if client_options.client_cert_source: | 528 | 552 | client_cert_source = client_options.client_cert_source | 529 | 553 | elif mtls.has_default_client_cert_source(): | @@ -555,20 +579,14 @@ def _read_environment_variables(): | 555 | 579 | google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT | 556 | 580 | is not any of ["auto", "never", "always"]. | 557 | 581 | """ | 558 | | - use_client_cert = os.getenv( | 559 | | - "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false" | 560 | | - ).lower() | | 582 | + use_client_cert = BaseBigtableTableAdminClient._use_client_cert_effective() | 561 | 583 | use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() | 562 | 584 | universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") | 563 | | - if use_client_cert not in ("true", "false"): | 564 | | - raise ValueError( | 565 | | - "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`" | 566 | | - ) | 567 | 585 | if use_mtls_endpoint not in ("auto", "never", "always"): | 568 | 586 | raise MutualTLSChannelError( | 569 | 587 | "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`" | 570 | 588 | ) | 571 | | - return use_client_cert == "true", use_mtls_endpoint, universe_domain_env | | 589 | + return use_client_cert, use_mtls_endpoint, universe_domain_env | 572 | 590 |
| 573 | 591 | @staticmethod | 574 | 592 | def _get_client_cert_source(provided_cert_source, use_cert_flag): | |
|