Skip to content
This repository was archived by the owner on Sep 5, 2023. It is now read-only.

Commit 1560ad8

Browse files
feat: add mtls support (#7)
1 parent 6b7cf38 commit 1560ad8

7 files changed

Lines changed: 321 additions & 39 deletions

File tree

docs/conf.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"sphinx.ext.napoleon",
3939
"sphinx.ext.todo",
4040
"sphinx.ext.viewcode",
41+
"recommonmark",
4142
]
4243

4344
# autodoc/autosummary flags
@@ -49,10 +50,6 @@
4950
# Add any paths that contain templates here, relative to this directory.
5051
templates_path = ["_templates"]
5152

52-
# Allow markdown includes (so releases.md can include CHANGLEOG.md)
53-
# http://www.sphinx-doc.org/en/master/markdown.html
54-
source_parsers = {".md": "recommonmark.parser.CommonMarkParser"}
55-
5653
# The suffix(es) of source filenames.
5754
# You can specify multiple suffix as a list of string:
5855
# source_suffix = ['.rst', '.md']

google/cloud/mediatranslation_v1beta1/services/speech_translation_service/client.py

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
#
1717

1818
from collections import OrderedDict
19-
from typing import Dict, Iterable, Iterator, Sequence, Tuple, Type, Union
19+
import re
20+
from typing import Callable, Dict, Iterable, Iterator, Sequence, Tuple, Type, Union
2021
import pkg_resources
2122

2223
import google.api_core.client_options as ClientOptions # type: ignore
@@ -70,8 +71,38 @@ def get_transport_class(
7071
class SpeechTranslationServiceClient(metaclass=SpeechTranslationServiceClientMeta):
7172
"""Provides translation from/to media types."""
7273

73-
DEFAULT_OPTIONS = ClientOptions.ClientOptions(
74-
api_endpoint="mediatranslation.googleapis.com"
74+
@staticmethod
75+
def _get_default_mtls_endpoint(api_endpoint):
76+
"""Convert api endpoint to mTLS endpoint.
77+
Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to
78+
"*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively.
79+
Args:
80+
api_endpoint (Optional[str]): the api endpoint to convert.
81+
Returns:
82+
str: converted mTLS api endpoint.
83+
"""
84+
if not api_endpoint:
85+
return api_endpoint
86+
87+
mtls_endpoint_re = re.compile(
88+
r"(?P<name>[^.]+)(?P<mtls>\.mtls)?(?P<sandbox>\.sandbox)?(?P<googledomain>\.googleapis\.com)?"
89+
)
90+
91+
m = mtls_endpoint_re.match(api_endpoint)
92+
name, mtls, sandbox, googledomain = m.groups()
93+
if mtls or not googledomain:
94+
return api_endpoint
95+
96+
if sandbox:
97+
return api_endpoint.replace(
98+
"sandbox.googleapis.com", "mtls.sandbox.googleapis.com"
99+
)
100+
101+
return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com")
102+
103+
DEFAULT_ENDPOINT = "mediatranslation.googleapis.com"
104+
DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore
105+
DEFAULT_ENDPOINT
75106
)
76107

77108
@classmethod
@@ -99,7 +130,7 @@ def __init__(
99130
*,
100131
credentials: credentials.Credentials = None,
101132
transport: Union[str, SpeechTranslationServiceTransport] = None,
102-
client_options: ClientOptions = DEFAULT_OPTIONS,
133+
client_options: ClientOptions = None,
103134
) -> None:
104135
"""Instantiate the speech translation service client.
105136
@@ -113,6 +144,17 @@ def __init__(
113144
transport to use. If set to None, a transport is chosen
114145
automatically.
115146
client_options (ClientOptions): Custom options for the client.
147+
(1) The ``api_endpoint`` property can be used to override the
148+
default endpoint provided by the client.
149+
(2) If ``transport`` argument is None, ``client_options`` can be
150+
used to create a mutual TLS transport. If ``client_cert_source``
151+
is provided, mutual TLS transport will be created with the given
152+
``api_endpoint`` or the default mTLS endpoint, and the client
153+
SSL credentials obtained from ``client_cert_source``.
154+
155+
Raises:
156+
google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport
157+
creation failed for any reason.
116158
"""
117159
if isinstance(client_options, dict):
118160
client_options = ClientOptions.from_dict(client_options)
@@ -121,17 +163,46 @@ def __init__(
121163
# Ordinarily, we provide the transport, but allowing a custom transport
122164
# instance provides an extensibility point for unusual situations.
123165
if isinstance(transport, SpeechTranslationServiceTransport):
166+
# transport is a SpeechTranslationServiceTransport instance.
124167
if credentials:
125168
raise ValueError(
126169
"When providing a transport instance, "
127170
"provide its credentials directly."
128171
)
129172
self._transport = transport
130-
else:
173+
elif client_options is None or (
174+
client_options.api_endpoint is None
175+
and client_options.client_cert_source is None
176+
):
177+
# Don't trigger mTLS if we get an empty ClientOptions.
131178
Transport = type(self).get_transport_class(transport)
132179
self._transport = Transport(
180+
credentials=credentials, host=self.DEFAULT_ENDPOINT
181+
)
182+
else:
183+
# We have a non-empty ClientOptions. If client_cert_source is
184+
# provided, trigger mTLS with user provided endpoint or the default
185+
# mTLS endpoint.
186+
if client_options.client_cert_source:
187+
api_mtls_endpoint = (
188+
client_options.api_endpoint
189+
if client_options.api_endpoint
190+
else self.DEFAULT_MTLS_ENDPOINT
191+
)
192+
else:
193+
api_mtls_endpoint = None
194+
195+
api_endpoint = (
196+
client_options.api_endpoint
197+
if client_options.api_endpoint
198+
else self.DEFAULT_ENDPOINT
199+
)
200+
201+
self._transport = SpeechTranslationServiceGrpcTransport(
133202
credentials=credentials,
134-
host=client_options.api_endpoint or "mediatranslation.googleapis.com",
203+
host=api_endpoint,
204+
api_mtls_endpoint=api_mtls_endpoint,
205+
client_cert_source=client_options.client_cert_source,
135206
)
136207

137208
def streaming_translate_speech(

google/cloud/mediatranslation_v1beta1/services/speech_translation_service/transports/grpc.py

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
# limitations under the License.
1616
#
1717

18-
from typing import Callable, Dict
18+
from typing import Callable, Dict, Tuple
1919

2020
from google.api_core import grpc_helpers # type: ignore
2121
from google.auth import credentials # type: ignore
22+
from google.auth.transport.grpc import SslCredentials # type: ignore
23+
2224

2325
import grpc # type: ignore
2426

@@ -45,7 +47,9 @@ def __init__(
4547
*,
4648
host: str = "mediatranslation.googleapis.com",
4749
credentials: credentials.Credentials = None,
48-
channel: grpc.Channel = None
50+
channel: grpc.Channel = None,
51+
api_mtls_endpoint: str = None,
52+
client_cert_source: Callable[[], Tuple[bytes, bytes]] = None
4953
) -> None:
5054
"""Instantiate the transport.
5155
@@ -59,20 +63,55 @@ def __init__(
5963
This argument is ignored if ``channel`` is provided.
6064
channel (Optional[grpc.Channel]): A ``Channel`` instance through
6165
which to make calls.
66+
api_mtls_endpoint (Optional[str]): The mutual TLS endpoint. If
67+
provided, it overrides the ``host`` argument and tries to create
68+
a mutual TLS channel with client SSL credentials from
69+
``client_cert_source`` or applicatin default SSL credentials.
70+
client_cert_source (Optional[Callable[[], Tuple[bytes, bytes]]]): A
71+
callback to provide client SSL certificate bytes and private key
72+
bytes, both in PEM format. It is ignored if ``api_mtls_endpoint``
73+
is None.
74+
75+
Raises:
76+
google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport
77+
creation failed for any reason.
6278
"""
63-
# Sanity check: Ensure that channel and credentials are not both
64-
# provided.
6579
if channel:
80+
# Sanity check: Ensure that channel and credentials are not both
81+
# provided.
6682
credentials = False
6783

84+
# If a channel was explicitly provided, set it.
85+
self._grpc_channel = channel
86+
elif api_mtls_endpoint:
87+
host = (
88+
api_mtls_endpoint
89+
if ":" in api_mtls_endpoint
90+
else api_mtls_endpoint + ":443"
91+
)
92+
93+
# Create SSL credentials with client_cert_source or application
94+
# default SSL credentials.
95+
if client_cert_source:
96+
cert, key = client_cert_source()
97+
ssl_credentials = grpc.ssl_channel_credentials(
98+
certificate_chain=cert, private_key=key
99+
)
100+
else:
101+
ssl_credentials = SslCredentials().ssl_credentials
102+
103+
# create a new channel. The provided one is ignored.
104+
self._grpc_channel = grpc_helpers.create_channel(
105+
host,
106+
credentials=credentials,
107+
ssl_credentials=ssl_credentials,
108+
scopes=self.AUTH_SCOPES,
109+
)
110+
68111
# Run the base constructor.
69112
super().__init__(host=host, credentials=credentials)
70113
self._stubs = {} # type: Dict[str, Callable]
71114

72-
# If a channel was explicitly provided, set it.
73-
if channel:
74-
self._grpc_channel = channel
75-
76115
@classmethod
77116
def create_channel(
78117
cls,

mypy.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[mypy]
2-
python_version = 3.5
2+
python_version = 3.6
33
namespace_packages = True

setup.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@
3939
platforms="Posix; MacOS X; Windows",
4040
include_package_data=True,
4141
install_requires=(
42-
"google-api-core >= 1.8.0, < 2.0.0dev",
43-
"googleapis-common-protos >= 1.5.8",
44-
"grpcio >= 1.10.0",
42+
"google-api-core[grpc] >= 1.17.0, < 2.0.0dev",
4543
"proto-plus >= 0.4.0",
4644
),
4745
python_requires=">=3.6",

synth.metadata

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
{
2-
"updateTime": "2020-03-25T12:13:59.097589Z",
32
"sources": [
3+
{
4+
"git": {
5+
"name": ".",
6+
"remote": "https://github.com/googleapis/python-media-translation.git",
7+
"sha": "6b7cf38268b8b42373db97d2f70d2089e4c57462"
8+
}
9+
},
410
{
511
"git": {
612
"name": "googleapis",
713
"remote": "https://github.com/googleapis/googleapis.git",
814
"sha": "551cf1e6e3addcc63740427c4f9b40dedd3dac27",
9-
"internalRef": "302792195",
10-
"log": "551cf1e6e3addcc63740427c4f9b40dedd3dac27\nfeat: Add OS Config AgentEndpointService v1 PatchJobs and Tasks APIs.\n\nPiperOrigin-RevId: 302792195\n\n1df117114c73299b614dfd3ba3632bf246669336\nSynchronize new proto/yaml changes.\n\nPiperOrigin-RevId: 302753982\n\n71d6c56a14bb433beb1237dccb48dabcd9597924\nRefresh monitoring client libraries.\nRename to Cloud Monitoring API.\nAdded support for TimeSeriesQueryLanguageCondition condition type in alert policies.\n\nPiperOrigin-RevId: 302735422\n\n25a1781c096974df99d556cc5888fefa82bc6425\nbazel: migrate all go_gapic_library targets to microgenerator implementation\n\n* update rules_go and gazelle bazel dependencies\n* update gapic-generator bazel dependency (with build file generator changes)\n\nPiperOrigin-RevId: 302730217\n\n36c0febd0fa7267ab66d14408eec2afd1b6bec4e\nUpdate GAPIC configurations to v2 .yaml.\n\nPiperOrigin-RevId: 302639621\n\n078f222366ed344509a48f2f084944ef61476613\nFix containeranalysis v1beta1 assembly target name\n\nPiperOrigin-RevId: 302529186\n\n0be7105dc52590fa9a24e784052298ae37ce53aa\nAdd BUILD.bazel file to asset/v1p1beta1\n\nPiperOrigin-RevId: 302154871\n\n6c248fd13e8543f8d22cbf118d978301a9fbe2a8\nAdd missing resource annotations and additional_bindings to dialogflow v2 API.\n\nPiperOrigin-RevId: 302063117\n\n9a3a7f33be9eeacf7b3e98435816b7022d206bd7\nChange the service name from \"chromeos-moblab.googleapis.com\" to \"chromeosmoblab.googleapis.com\"\n\nPiperOrigin-RevId: 302060989\n\n98a339237577e3de26cb4921f75fb5c57cc7a19f\nfeat: devtools/build/v1 publish client library config annotations\n\n* add details field to some of the BuildEvents\n* add final_invocation_id and build_tool_exit_code fields to BuildStatus\n\nPiperOrigin-RevId: 302044087\n\ncfabc98c6bbbb22d1aeaf7612179c0be193b3a13\nfeat: home/graph/v1 publish client library config annotations & comment updates\n\nThis change includes adding the client library configuration annotations, updated proto comments, and some client library configuration files.\n\nPiperOrigin-RevId: 302042647\n\nc8c8c0bd15d082db9546253dbaad1087c7a9782c\nchore: use latest gapic-generator in bazel WORKSPACE.\nincluding the following commits from gapic-generator:\n- feat: take source protos in all sub-packages (#3144)\n\nPiperOrigin-RevId: 301843591\n\ne4daf5202ea31cb2cb6916fdbfa9d6bd771aeb4c\nAdd bazel file for v1 client lib generation\n\nPiperOrigin-RevId: 301802926\n\n275fbcce2c900278d487c33293a3c7e1fbcd3a34\nfeat: pubsub/v1 add an experimental filter field to Subscription\n\nPiperOrigin-RevId: 301661567\n\nf2b18cec51d27c999ad30011dba17f3965677e9c\nFix: UpdateBackupRequest.backup is a resource, not a resource reference - remove annotation.\n\nPiperOrigin-RevId: 301636171\n\n800384063ac93a0cac3a510d41726fa4b2cd4a83\nCloud Billing Budget API v1beta1\nModified api documentation to include warnings about the new filter field.\n\nPiperOrigin-RevId: 301634389\n\n0cc6c146b660db21f04056c3d58a4b752ee445e3\nCloud Billing Budget API v1alpha1\nModified api documentation to include warnings about the new filter field.\n\nPiperOrigin-RevId: 301630018\n\nff2ea00f69065585c3ac0993c8b582af3b6fc215\nFix: Add resource definition for a parent of InspectTemplate which was otherwise missing.\n\nPiperOrigin-RevId: 301623052\n\n55fa441c9daf03173910760191646399338f2b7c\nAdd proto definition for AccessLevel, AccessPolicy, and ServicePerimeter.\n\nPiperOrigin-RevId: 301620844\n\ne7b10591c5408a67cf14ffafa267556f3290e262\nCloud Bigtable Managed Backup service and message proto files.\n\nPiperOrigin-RevId: 301585144\n\nd8e226f702f8ddf92915128c9f4693b63fb8685d\nfeat: Add time-to-live in a queue for builds\n\nPiperOrigin-RevId: 301579876\n\n430375af011f8c7a5174884f0d0e539c6ffa7675\ndocs: add missing closing backtick\n\nPiperOrigin-RevId: 301538851\n\n"
15+
"internalRef": "302792195"
1116
}
1217
},
1318
{

0 commit comments

Comments
 (0)