Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/gapic-generator/gapic/generator/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def get_response(self, api_schema: api.API, opts: Options) -> CodeGeneratorRespo
for template_name in client_templates:
# Quick check: Skip "private" templates.
filename = template_name.split("/")[-1]
if filename.startswith("_") and filename != "__init__.py.j2":
if filename.startswith("_") and filename not in ("__init__.py.j2", "_compat.py.j2"):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels a little strange that we need to have a special case for this. Maybe if anything, we should have a constant list of private templates to include?

continue

# Append to the output files dictionary.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# {% include '_license.j2' %}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does _compat need to be in this directory? It seems like it can live in the services directory


import os

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like this _compat file is being generated

from typing import Optional, Callable, Tuple, Union
from google.auth.exceptions import MutualTLSChannelError

try:
from google.api_core.gapic_v1.client_utils import (
use_client_cert_effective,
get_client_cert_source,
read_environment_variables,
)
except ImportError:
from google.auth.transport import mtls # type: ignore

# TODO: Remove these fallbacks when google-api-core >= 2.18.0 is the minimum required version.

def use_client_cert_effective() -> bool:
"""Returns whether client certificate should be used for mTLS."""
if hasattr(mtls, "should_use_client_cert"):
return mtls.should_use_client_cert()
else:
use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower()
if use_client_cert_str not in ("true", "false"):
raise ValueError(
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be"
" either `true` or `false`"
)
return use_client_cert_str == "true"

def get_client_cert_source(
provided_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]],
use_cert_flag: bool,
) -> Optional[Callable[[], Tuple[bytes, bytes]]]:
"""Return the client cert source to be used by the client."""
client_cert_source = None
if use_cert_flag:
if provided_cert_source:
client_cert_source = provided_cert_source
elif (
hasattr(mtls, "has_default_client_cert_source")
and mtls.has_default_client_cert_source()
):
client_cert_source = mtls.default_client_cert_source()
else:
raise ValueError(
"Client certificate is required for mTLS, but no client certificate source was provided or found."
)
return client_cert_source

def read_environment_variables() -> Tuple[bool, str, Optional[str]]:
"""Returns the environment variables used by the client."""
use_client_cert = use_client_cert_effective()
use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower()
universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN")
if use_mtls_endpoint not in ("auto", "never", "always"):
raise MutualTLSChannelError(
"Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` "
"must be `never`, `auto` or `always`"
)
return use_client_cert, use_mtls_endpoint, universe_domain_env
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ from google.api_core import exceptions as core_exceptions
from google.api_core import extended_operation
{% endif %}
from google.api_core import gapic_v1
from {{package_path}} import _compat as client_utils
from google.api_core import retry as retries
from google.auth import credentials as ga_credentials # type: ignore
from google.auth.transport import mtls # type: ignore
Expand Down Expand Up @@ -189,30 +190,9 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta):
_DEFAULT_UNIVERSE = "googleapis.com"

@staticmethod
def _use_client_cert_effective():
"""Returns whether client certificate should be used for mTLS if the
google-auth version supports should_use_client_cert automatic mTLS enablement.

Alternatively, read from the GOOGLE_API_USE_CLIENT_CERTIFICATE env var.

Returns:
bool: whether client certificate should be used for mTLS
Raises:
ValueError: (If using a version of google-auth without should_use_client_cert and
GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.)
"""
# check if google-auth version supports should_use_client_cert for automatic mTLS enablement
if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER
return mtls.should_use_client_cert()
else: # pragma: NO COVER
# if unsupported, fallback to reading from env var
use_client_cert_str = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false").lower()
if use_client_cert_str not in ("true", "false"):
raise ValueError(
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be"
" either `true` or `false`"
)
return use_client_cert_str == "true"
def _use_client_cert_effective() -> bool:
"""Returns whether client certificate should be used for mTLS."""
return client_utils.use_client_cert_effective()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to keep the helper wrapper?

It feels confusing to have so many aliases in so many places


@classmethod
def from_service_account_info(cls, info: dict, *args, **kwargs):
Expand Down Expand Up @@ -352,44 +332,12 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta):
return api_endpoint, client_cert_source

@staticmethod
def _read_environment_variables():
"""Returns the environment variables used by the client.

Returns:
Tuple[bool, str, str]: returns the GOOGLE_API_USE_CLIENT_CERTIFICATE,
GOOGLE_API_USE_MTLS_ENDPOINT, and GOOGLE_CLOUD_UNIVERSE_DOMAIN environment variables.

Raises:
ValueError: If GOOGLE_API_USE_CLIENT_CERTIFICATE is not
any of ["true", "false"].
google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT
is not any of ["auto", "never", "always"].
"""
use_client_cert = {{ service.client_name }}._use_client_cert_effective()
use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower()
universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN")
if use_mtls_endpoint not in ("auto", "never", "always"):
raise MutualTLSChannelError("Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`")
return use_client_cert, use_mtls_endpoint, universe_domain_env

@staticmethod
def _get_client_cert_source(provided_cert_source, use_cert_flag):
"""Return the client cert source to be used by the client.

Args:
provided_cert_source (bytes): The client certificate source provided.
use_cert_flag (bool): A flag indicating whether to use the client certificate.

Returns:
bytes or None: The client cert source to be used by the client.
"""
client_cert_source = None
if use_cert_flag:
if provided_cert_source:
client_cert_source = provided_cert_source
elif mtls.has_default_client_cert_source():
client_cert_source = mtls.default_client_cert_source()
return client_cert_source
def _get_client_cert_source(
provided_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]],
use_cert_flag: bool,
) -> Optional[Callable[[], Tuple[bytes, bytes]]]:
"""Return the client cert source to be used by the client."""
return client_utils.get_client_cert_source(provided_cert_source, use_cert_flag)

@staticmethod
def _get_api_endpoint(api_override, client_cert_source, universe_domain, use_mtls_endpoint) -> str:
Expand Down Expand Up @@ -597,7 +545,7 @@ class {{ service.client_name }}(metaclass={{ service.client_name }}Meta):

universe_domain_opt = getattr(self._client_options, 'universe_domain', None)

self._use_client_cert, self._use_mtls_endpoint, self._universe_domain_env = {{ service.client_name }}._read_environment_variables()
self._use_client_cert, self._use_mtls_endpoint, self._universe_domain_env = client_utils.read_environment_variables()
self._client_cert_source = {{ service.client_name }}._get_client_cert_source(self._client_options.client_cert_source, self._use_client_cert)
self._universe_domain = {{ service.client_name }}._get_universe_domain(universe_domain_opt, self._universe_domain_env)
self._api_endpoint: str = "" # updated below, depending on `transport`
Expand Down
Loading
Loading