Skip to content

Commit a50b376

Browse files
committed
feat(secretmanager): adopt get_otel_channel_wrapper and apply_channel_wrappers
1 parent 2954073 commit a50b376

3 files changed

Lines changed: 68 additions & 67 deletions

File tree

packages/google-cloud-secret-manager/google/cloud/secretmanager_v1/services/secret_manager_service/client.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
import functools
1716
import json
1817
import logging as std_logging
1918
import os
@@ -44,9 +43,10 @@
4443
from google.auth.exceptions import MutualTLSChannelError # type: ignore
4544
from google.auth.transport import mtls # type: ignore
4645
from google.auth.transport.grpc import SslCredentials # type: ignore
47-
from google.cloud.secretmanager_v1 import gapic_version as package_version
4846
from google.oauth2 import service_account # type: ignore
4947

48+
from google.cloud.secretmanager_v1 import gapic_version as package_version
49+
5050
try:
5151
OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault, None]
5252
except AttributeError: # pragma: NO COVER
@@ -68,6 +68,7 @@
6868
import google.protobuf.field_mask_pb2 as field_mask_pb2 # type: ignore
6969
import google.protobuf.timestamp_pb2 as timestamp_pb2 # type: ignore
7070
from google.cloud.location import locations_pb2 # type: ignore
71+
7172
from google.cloud.secretmanager_v1.services.secret_manager_service import pagers
7273
from google.cloud.secretmanager_v1.types import resources, service
7374

@@ -757,17 +758,14 @@ def __init__(
757758
"api_audience": self._client_options.api_audience,
758759
}
759760

760-
# When OpenTelemetry tracing is enabled, bind create_channel_with_otel
761-
# using functools.partial and pass it as the channel factory.
762-
# This preserves lazy channel instantiation inside the Transport and avoids
763-
# duplicating channel initialization arguments here in the client.
761+
# When OpenTelemetry tracing is enabled, obtain the channel wrapper
762+
# and pass it to the transport.
764763
if transport_init is SecretManagerServiceGrpcTransport:
765-
if _observability.is_otel_capabilities_enabled(self._client_options):
766-
transport_kwargs["channel"] = functools.partial(
767-
_observability.create_channel_with_otel,
768-
SecretManagerServiceGrpcTransport.create_channel,
769-
client_options=self._client_options,
770-
)
764+
otel_wrapper = _observability.get_otel_channel_wrapper(
765+
self._client_options
766+
)
767+
if otel_wrapper is not None:
768+
transport_kwargs["wrappers"] = [otel_wrapper]
771769

772770
self._transport = transport_init(**transport_kwargs)
773771

packages/google-cloud-secret-manager/google/cloud/secretmanager_v1/services/secret_manager_service/transports/grpc.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@
2727
import grpc # type: ignore
2828
import proto # type: ignore
2929
from google.api_core import gapic_v1, grpc_helpers
30-
from google.api_core.grpc_helpers import ClientInterceptor
30+
from google.api_core.grpc_helpers import ChannelWrapper
3131
from google.auth import credentials as ga_credentials # type: ignore
3232
from google.auth.transport.grpc import SslCredentials # type: ignore
3333
from google.cloud.location import locations_pb2 # type: ignore
34-
from google.cloud.secretmanager_v1.types import resources, service
3534
from google.protobuf.json_format import MessageToJson
3635

36+
from google.cloud.secretmanager_v1.types import resources, service
37+
3738
from .base import DEFAULT_CLIENT_INFO, SecretManagerServiceTransport
3839

3940
try:
@@ -148,7 +149,7 @@ def __init__(
148149
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
149150
always_use_jwt_access: Optional[bool] = False,
150151
api_audience: Optional[str] = None,
151-
interceptors: Optional[Sequence[ClientInterceptor]] = None,
152+
wrappers: Optional[Sequence[ChannelWrapper]] = None,
152153
) -> None:
153154
"""Instantiate the transport.
154155
@@ -199,9 +200,9 @@ def __init__(
199200
to the service that will be set when using certain 3rd party
200201
authentication flows. Audience is typically a resource identifier.
201202
If not set, the host value will be used as a default.
202-
interceptors (Optional[Sequence[ClientInterceptor]]):
203-
Additional interceptors to be injected into the gRPC channel pipeline.
204-
These are executed in order.
203+
wrappers (Optional[Sequence[ChannelWrapper]]):
204+
Additional channel wrappers (interceptors or callables) to apply to the
205+
gRPC channel.
205206
206207
Raises:
207208
google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport
@@ -278,8 +279,8 @@ def __init__(
278279
],
279280
)
280281

281-
self._grpc_channel = grpc_helpers.apply_interceptors(
282-
self._grpc_channel, interceptors
282+
self._grpc_channel = grpc_helpers.apply_channel_wrappers(
283+
self._grpc_channel, wrappers
283284
)
284285

285286
self._interceptor = _LoggingClientInterceptor()

packages/google-cloud-secret-manager/tests/unit/gapic/secretmanager_v1/test_secret_manager_service.py

Lines changed: 49 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,15 @@
6262
from google.auth import credentials as ga_credentials
6363
from google.auth.exceptions import MutualTLSChannelError
6464
from google.cloud.location import locations_pb2
65+
from google.oauth2 import service_account
66+
6567
from google.cloud.secretmanager_v1.services.secret_manager_service import (
6668
SecretManagerServiceAsyncClient,
6769
SecretManagerServiceClient,
6870
pagers,
6971
transports,
7072
)
7173
from google.cloud.secretmanager_v1.types import resources, service
72-
from google.oauth2 import service_account
7374

7475
CRED_INFO_JSON = {
7576
"credential_source": "/path/to/file",
@@ -773,73 +774,57 @@ def test_secret_manager_service_client_client_options(
773774
def test_secret_manager_service_client_otel_channel_injection_enabled():
774775
"""Proves that when OpenTelemetry tracing is enabled:
775776

776-
1. SecretManagerServiceClient detects the feature flag via
777-
_observability.is_otel_capabilities_enabled.
778-
2. The client binds _observability.create_channel_with_otel using
779-
functools.partial with SecretManagerServiceGrpcTransport.create_channel and client_options.
780-
3. The bound channel factory callable is passed into transport kwargs under 'channel',
781-
allowing the Transport to initialize the channel lazily with its own parameters.
777+
1. SecretManagerServiceClient obtains the channel wrapper via
778+
_observability.get_otel_channel_wrapper passing client_options.
779+
2. The wrapper is passed into transport kwargs under 'wrappers',
780+
allowing the Transport to apply it via apply_channel_wrappers.
782781
"""
782+
mock_wrapper = mock.Mock()
783783
with (
784784
mock.patch(
785-
"google.cloud.secretmanager_v1.services.secret_manager_service.client._observability.is_otel_capabilities_enabled",
786-
return_value=True,
787-
) as mock_is_enabled,
785+
"google.cloud.secretmanager_v1.services.secret_manager_service.client._observability.get_otel_channel_wrapper",
786+
return_value=mock_wrapper,
787+
) as mock_get_wrapper,
788788
mock.patch.object(
789789
transports.SecretManagerServiceGrpcTransport, "__init__", return_value=None
790790
) as patched_transport_init,
791791
):
792792
client = SecretManagerServiceClient(transport="grpc")
793793

794-
mock_is_enabled.assert_called_once()
794+
mock_get_wrapper.assert_called_once_with(client._client_options)
795795
called_kwargs = patched_transport_init.call_args.kwargs
796-
assert "channel" in called_kwargs
797-
channel_factory = called_kwargs["channel"]
798-
assert isinstance(channel_factory, functools.partial)
799-
assert (
800-
channel_factory.func
801-
is google.cloud.secretmanager_v1.services.secret_manager_service.client._observability.create_channel_with_otel
802-
)
803-
assert channel_factory.args == (
804-
transports.SecretManagerServiceGrpcTransport.create_channel,
805-
)
806-
assert channel_factory.keywords == {"client_options": client._client_options}
796+
assert "wrappers" in called_kwargs
797+
assert called_kwargs["wrappers"] == [mock_wrapper]
807798

808799

809800
def test_secret_manager_service_client_otel_channel_injection_disabled():
810801
"""Proves that when OpenTelemetry tracing is disabled:
811802

812-
1. SecretManagerServiceClient checks the feature flag and finds it disabled.
813-
2. Eager channel creation via _observability.create_channel_with_otel is skipped.
814-
3. No 'channel' argument is passed to the transport constructor, preserving lazy
815-
channel initialization in the transport.
803+
1. SecretManagerServiceClient checks for an OTel wrapper and receives None.
804+
2. No 'wrappers' argument is passed to the transport constructor.
816805
"""
817806
with (
818807
mock.patch(
819-
"google.cloud.secretmanager_v1.services.secret_manager_service.client._observability.is_otel_capabilities_enabled",
820-
return_value=False,
821-
) as mock_is_enabled,
822-
mock.patch(
823-
"google.cloud.secretmanager_v1.services.secret_manager_service.client._observability.create_channel_with_otel",
824-
) as mock_create_channel_with_otel,
808+
"google.cloud.secretmanager_v1.services.secret_manager_service.client._observability.get_otel_channel_wrapper",
809+
return_value=None,
810+
) as mock_get_wrapper,
825811
mock.patch.object(
826812
transports.SecretManagerServiceGrpcTransport, "__init__", return_value=None
827813
) as patched_transport_init,
828814
):
829-
SecretManagerServiceClient(transport="grpc")
815+
client = SecretManagerServiceClient(transport="grpc")
830816

831-
mock_is_enabled.assert_called_once()
832-
mock_create_channel_with_otel.assert_not_called()
817+
mock_get_wrapper.assert_called_once_with(client._client_options)
833818
called_kwargs = patched_transport_init.call_args.kwargs
834-
assert "channel" not in called_kwargs
819+
assert "wrappers" not in called_kwargs
835820

836821

837-
def test_secret_manager_service_grpc_transport_interceptors():
838-
"""Proves that SecretManagerServiceGrpcTransport accepts custom client interceptors
839-
and invokes grpc_helpers.apply_interceptors to inject them into the underlying
840-
gRPC channel pipeline.
822+
def test_secret_manager_service_grpc_transport_wrappers():
823+
"""Proves that SecretManagerServiceGrpcTransport accepts channel wrappers
824+
and invokes grpc_helpers.apply_channel_wrappers to apply them to the underlying
825+
gRPC channel.
841826
"""
842-
mock_interceptor = mock.Mock()
827+
mock_wrapper = mock.Mock()
843828
mock_channel = mock.Mock()
844829

845830
with (
@@ -849,18 +834,35 @@ def test_secret_manager_service_grpc_transport_interceptors():
849834
return_value=mock_channel,
850835
),
851836
mock.patch(
852-
"google.api_core.grpc_helpers.apply_interceptors",
837+
"google.api_core.grpc_helpers.apply_channel_wrappers",
853838
return_value=mock_channel,
854-
) as mock_apply_interceptors,
839+
) as mock_apply_wrappers,
855840
):
856-
transport = transports.SecretManagerServiceGrpcTransport(
857-
interceptors=[mock_interceptor],
841+
transports.SecretManagerServiceGrpcTransport(
842+
wrappers=[mock_wrapper],
858843
)
859844

860-
mock_apply_interceptors.assert_called_once_with(
861-
mock_channel, [mock_interceptor]
845+
mock_apply_wrappers.assert_called_once_with(mock_channel, [mock_wrapper])
846+
847+
848+
def test_secret_manager_service_grpc_transport_custom_channel_wrappers():
849+
"""Proves that SecretManagerServiceGrpcTransport wraps explicitly passed custom channels
850+
using grpc_helpers.apply_channel_wrappers.
851+
"""
852+
mock_wrapper = mock.Mock()
853+
mock_custom_channel = mock.Mock(spec=grpc.Channel)
854+
855+
with mock.patch(
856+
"google.api_core.grpc_helpers.apply_channel_wrappers",
857+
return_value=mock_custom_channel,
858+
) as mock_apply_wrappers:
859+
transports.SecretManagerServiceGrpcTransport(
860+
channel=mock_custom_channel,
861+
wrappers=[mock_wrapper],
862862
)
863863

864+
mock_apply_wrappers.assert_called_once_with(mock_custom_channel, [mock_wrapper])
865+
864866

865867
@pytest.mark.parametrize(
866868
"client_class,transport_class,transport_name,use_client_cert_env",

0 commit comments

Comments
 (0)