|
27 | 27 | import asyncio |
28 | 28 | from collections.abc import Awaitable |
29 | 29 | import queue |
| 30 | +import os |
30 | 31 | import sys |
31 | 32 | import threading |
| 33 | +import enum |
| 34 | +from google.auth.transport import mtls |
| 35 | +from google.auth.transport import requests as requests_auth |
32 | 36 |
|
33 | 37 |
|
34 | 38 | if TYPE_CHECKING: |
|
97 | 101 |
|
98 | 102 | _DEFAULT_APP_NAME = "default-app-name" |
99 | 103 | _DEFAULT_USER_ID = "default-user-id" |
| 104 | +_DEFAULT_TELEMETRY_ENDPOINT = "https://telemetry.googleapis.com/v1/traces" |
| 105 | +_DEFAULT_MTLS_TELEMETRY_ENDPOINT = "https://telemetry.mtls.googleapis.com/v1/traces" |
| 106 | + |
| 107 | + |
| 108 | +class _MtlsEndpoint(enum.Enum): |
| 109 | + """The mTLS endpoint setting.""" |
| 110 | + |
| 111 | + AUTO = "auto" |
| 112 | + ALWAYS = "always" |
| 113 | + NEVER = "never" |
| 114 | + |
| 115 | + |
100 | 116 | _TELEMETRY_API_DISABLED_WARNING = ( |
101 | 117 | "Tracing integration for Agent Engine has migrated to a new API.\n" |
102 | 118 | "The 'telemetry.googleapis.com' has not been enabled in project %s. \n" |
@@ -250,6 +266,64 @@ def _warn(msg: str): |
250 | 266 | _warn._LOGGER.warning(msg) # pyright: ignore[reportFunctionMemberAccess] |
251 | 267 |
|
252 | 268 |
|
| 269 | +def _get_api_endpoint(client_cert_source: bytes | None = None) -> str: |
| 270 | + """Returns API endpoint based on mTLS configuration and cert availability. |
| 271 | +
|
| 272 | + Args: |
| 273 | + client_cert_source (bytes | None): The client certificate source. |
| 274 | +
|
| 275 | + Returns: |
| 276 | + str: The API endpoint to be used. |
| 277 | + """ |
| 278 | + use_mtls_endpoint_str = os.getenv( |
| 279 | + "GOOGLE_API_USE_MTLS_ENDPOINT", _MtlsEndpoint.AUTO.value |
| 280 | + ).lower() |
| 281 | + |
| 282 | + try: |
| 283 | + use_mtls_endpoint = _MtlsEndpoint(use_mtls_endpoint_str) |
| 284 | + except ValueError: |
| 285 | + _warn( |
| 286 | + f"Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be one of " |
| 287 | + f"{[e.value for e in _MtlsEndpoint]}. Defaulting to" |
| 288 | + f" {_MtlsEndpoint.AUTO.value}." |
| 289 | + ) |
| 290 | + use_mtls_endpoint = _MtlsEndpoint.AUTO |
| 291 | + |
| 292 | + if (use_mtls_endpoint == _MtlsEndpoint.ALWAYS) or ( |
| 293 | + use_mtls_endpoint == _MtlsEndpoint.AUTO and client_cert_source |
| 294 | + ): |
| 295 | + return _DEFAULT_MTLS_TELEMETRY_ENDPOINT |
| 296 | + |
| 297 | + return _DEFAULT_TELEMETRY_ENDPOINT |
| 298 | + |
| 299 | + |
| 300 | +def _use_client_cert_effective() -> bool: |
| 301 | + """Returns whether client certificate should be used for mTLS. |
| 302 | +
|
| 303 | + This checks if the google-auth version supports should_use_client_cert |
| 304 | + automatic mTLS enablement. Alternatively, it reads from the |
| 305 | + GOOGLE_API_USE_CLIENT_CERTIFICATE env var. |
| 306 | +
|
| 307 | + Returns: |
| 308 | + bool: whether client certificate should be used for mTLS. |
| 309 | + """ |
| 310 | + # check if google-auth version supports should_use_client_cert for automatic |
| 311 | + # mTLS enablement |
| 312 | + try: |
| 313 | + return mtls.should_use_client_cert() |
| 314 | + except (ImportError, AttributeError): |
| 315 | + # if unsupported, fallback to reading from env var |
| 316 | + use_client_cert_str = os.getenv( |
| 317 | + "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false" |
| 318 | + ).lower() |
| 319 | + if use_client_cert_str not in ("true", "false"): |
| 320 | + _warn( |
| 321 | + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be" |
| 322 | + " either `true` or `false`" |
| 323 | + ) |
| 324 | + return use_client_cert_str == "true" |
| 325 | + |
| 326 | + |
253 | 327 | async def _force_flush_otel(tracing_enabled: bool, logging_enabled: bool): |
254 | 328 | try: |
255 | 329 | import opentelemetry.trace |
@@ -393,12 +467,24 @@ def _detect_cloud_resource_id(project_id: str) -> Optional[str]: |
393 | 467 | otlp_http_version = opentelemetry.exporter.otlp.proto.http.version.__version__ |
394 | 468 | user_agent = f"Vertex-Agent-Engine/{vertex_sdk_version} OTel-OTLP-Exporter-Python/{otlp_http_version}" |
395 | 469 |
|
| 470 | + session = requests_auth.AuthorizedSession(credentials=credentials) |
| 471 | + |
| 472 | + use_client_cert = _use_client_cert_effective() |
| 473 | + if use_client_cert: |
| 474 | + client_cert_source = ( |
| 475 | + mtls.default_client_cert_source() |
| 476 | + if mtls.has_default_client_cert_source() |
| 477 | + else None |
| 478 | + ) |
| 479 | + session.configure_mtls_channel() |
| 480 | + endpoint = _get_api_endpoint(client_cert_source) |
| 481 | + else: |
| 482 | + endpoint = _DEFAULT_TELEMETRY_ENDPOINT |
| 483 | + |
396 | 484 | span_exporter = ( |
397 | 485 | opentelemetry.exporter.otlp.proto.http.trace_exporter.OTLPSpanExporter( |
398 | | - session=google.auth.transport.requests.AuthorizedSession( |
399 | | - credentials=credentials |
400 | | - ), |
401 | | - endpoint="https://telemetry.googleapis.com/v1/traces", |
| 486 | + session=session, |
| 487 | + endpoint=endpoint, |
402 | 488 | headers={"User-Agent": user_agent}, |
403 | 489 | ) |
404 | 490 | ) |
@@ -1620,10 +1706,20 @@ def _warn_if_telemetry_api_disabled(self): |
1620 | 1706 | except (ImportError, AttributeError): |
1621 | 1707 | return |
1622 | 1708 | credentials, project = google.auth.default() |
1623 | | - session = google.auth.transport.requests.AuthorizedSession( |
1624 | | - credentials=credentials |
1625 | | - ) |
1626 | | - r = session.post("https://telemetry.googleapis.com/v1/traces", data=None) |
| 1709 | + session = requests_auth.AuthorizedSession(credentials=credentials) |
| 1710 | + |
| 1711 | + use_client_cert = _use_client_cert_effective() |
| 1712 | + if use_client_cert: |
| 1713 | + client_cert_source = ( |
| 1714 | + mtls.default_client_cert_source() |
| 1715 | + if mtls.has_default_client_cert_source() |
| 1716 | + else None |
| 1717 | + ) |
| 1718 | + session.configure_mtls_channel() |
| 1719 | + endpoint = _get_api_endpoint(client_cert_source) |
| 1720 | + else: |
| 1721 | + endpoint = _DEFAULT_TELEMETRY_ENDPOINT |
| 1722 | + r = session.post(endpoint, data=None) |
1627 | 1723 | if "Telemetry API has not been used in project" in r.text: |
1628 | 1724 | _warn(_TELEMETRY_API_DISABLED_WARNING % (project, project)) |
1629 | 1725 |
|
|
0 commit comments