Content-Length: 1022465 | pFad | https://github.com/googleapis/python-deploy/commit/aaa957f2673db673c3a8e38275d4689323ded044

36 feat: add api key support (#35) · googleapis/python-deploy@aaa957f · GitHub
Skip to content
This repository was archived by the owner on Jul 6, 2023. It is now read-only.

Commit aaa957f

Browse files
feat: add api key support (#35)
* chore: upgrade gapic-generator-java, gax-java and gapic-generator-python PiperOrigin-RevId: 423842556 Source-Link: googleapis/googleapis@a616ca0 Source-Link: https://github.com/googleapis/googleapis-gen/commit/29b938c58c1e51d019f2ee539d55dc0a3c86a905 Copy-Tag: eyJwIjoiLmdpdGh1Yi8uT3dsQm90LnlhbWwiLCJoIjoiMjliOTM4YzU4YzFlNTFkMDE5ZjJlZTUzOWQ1NWRjMGEzYzg2YTkwNSJ9 * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent 612dba0 commit aaa957f

File tree

3 files changed

+245
-44
lines changed

3 files changed

+245
-44
lines changed

google/cloud/deploy_v1/services/cloud_deploy/async_client.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from collections import OrderedDict
1717
import functools
1818
import re
19-
from typing import Dict, Sequence, Tuple, Type, Union
19+
from typing import Dict, Optional, Sequence, Tuple, Type, Union
2020
import pkg_resources
2121

2222
from google.api_core.client_options import ClientOptions
@@ -126,6 +126,42 @@ def from_service_account_file(cls, filename: str, *args, **kwargs):
126126

127127
from_service_account_json = from_service_account_file
128128

129+
@classmethod
130+
def get_mtls_endpoint_and_cert_source(
131+
cls, client_options: Optional[ClientOptions] = None
132+
):
133+
"""Return the API endpoint and client cert source for mutual TLS.
134+
135+
The client cert source is determined in the following order:
136+
(1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
137+
client cert source is None.
138+
(2) if `client_options.client_cert_source` is provided, use the provided one; if the
139+
default client cert source exists, use the default one; otherwise the client cert
140+
source is None.
141+
142+
The API endpoint is determined in the following order:
143+
(1) if `client_options.api_endpoint` if provided, use the provided one.
144+
(2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
145+
default mTLS endpoint; if the environment variabel is "never", use the default API
146+
endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
147+
use the default API endpoint.
148+
149+
More details can be found at https://google.aip.dev/auth/4114.
150+
151+
Args:
152+
client_options (google.api_core.client_options.ClientOptions): Custom options for the
153+
client. Only the `api_endpoint` and `client_cert_source` properties may be used
154+
in this method.
155+
156+
Returns:
157+
Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
158+
client cert source to use.
159+
160+
Raises:
161+
google.auth.exceptions.MutualTLSChannelError: If any errors happen.
162+
"""
163+
return CloudDeployClient.get_mtls_endpoint_and_cert_source(client_options) # type: ignore
164+
129165
@property
130166
def transport(self) -> CloudDeployTransport:
131167
"""Returns the transport used by the client instance.

google/cloud/deploy_v1/services/cloud_deploy/client.py

Lines changed: 84 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,73 @@ def parse_common_location_path(path: str) -> Dict[str, str]:
364364
m = re.match(r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$", path)
365365
return m.groupdict() if m else {}
366366

367+
@classmethod
368+
def get_mtls_endpoint_and_cert_source(
369+
cls, client_options: Optional[client_options_lib.ClientOptions] = None
370+
):
371+
"""Return the API endpoint and client cert source for mutual TLS.
372+
373+
The client cert source is determined in the following order:
374+
(1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
375+
client cert source is None.
376+
(2) if `client_options.client_cert_source` is provided, use the provided one; if the
377+
default client cert source exists, use the default one; otherwise the client cert
378+
source is None.
379+
380+
The API endpoint is determined in the following order:
381+
(1) if `client_options.api_endpoint` if provided, use the provided one.
382+
(2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
383+
default mTLS endpoint; if the environment variabel is "never", use the default API
384+
endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
385+
use the default API endpoint.
386+
387+
More details can be found at https://google.aip.dev/auth/4114.
388+
389+
Args:
390+
client_options (google.api_core.client_options.ClientOptions): Custom options for the
391+
client. Only the `api_endpoint` and `client_cert_source` properties may be used
392+
in this method.
393+
394+
Returns:
395+
Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
396+
client cert source to use.
397+
398+
Raises:
399+
google.auth.exceptions.MutualTLSChannelError: If any errors happen.
400+
"""
401+
if client_options is None:
402+
client_options = client_options_lib.ClientOptions()
403+
use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
404+
use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
405+
if use_client_cert not in ("true", "false"):
406+
raise ValueError(
407+
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
408+
)
409+
if use_mtls_endpoint not in ("auto", "never", "always"):
410+
raise MutualTLSChannelError(
411+
"Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
412+
)
413+
414+
# Figure out the client cert source to use.
415+
client_cert_source = None
416+
if use_client_cert == "true":
417+
if client_options.client_cert_source:
418+
client_cert_source = client_options.client_cert_source
419+
elif mtls.has_default_client_cert_source():
420+
client_cert_source = mtls.default_client_cert_source()
421+
422+
# Figure out which api endpoint to use.
423+
if client_options.api_endpoint is not None:
424+
api_endpoint = client_options.api_endpoint
425+
elif use_mtls_endpoint == "always" or (
426+
use_mtls_endpoint == "auto" and client_cert_source
427+
):
428+
api_endpoint = cls.DEFAULT_MTLS_ENDPOINT
429+
else:
430+
api_endpoint = cls.DEFAULT_ENDPOINT
431+
432+
return api_endpoint, client_cert_source
433+
367434
def __init__(
368435
self,
369436
*,
@@ -414,57 +481,22 @@ def __init__(
414481
if client_options is None:
415482
client_options = client_options_lib.ClientOptions()
416483

417-
# Create SSL credentials for mutual TLS if needed.
418-
if os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") not in (
419-
"true",
420-
"false",
421-
):
422-
raise ValueError(
423-
"Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
424-
)
425-
use_client_cert = (
426-
os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true"
484+
api_endpoint, client_cert_source_func = self.get_mtls_endpoint_and_cert_source(
485+
client_options
427486
)
428487

429-
client_cert_source_func = None
430-
is_mtls = False
431-
if use_client_cert:
432-
if client_options.client_cert_source:
433-
is_mtls = True
434-
client_cert_source_func = client_options.client_cert_source
435-
else:
436-
is_mtls = mtls.has_default_client_cert_source()
437-
if is_mtls:
438-
client_cert_source_func = mtls.default_client_cert_source()
439-
else:
440-
client_cert_source_func = None
441-
442-
# Figure out which api endpoint to use.
443-
if client_options.api_endpoint is not None:
444-
api_endpoint = client_options.api_endpoint
445-
else:
446-
use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
447-
if use_mtls_env == "never":
448-
api_endpoint = self.DEFAULT_ENDPOINT
449-
elif use_mtls_env == "always":
450-
api_endpoint = self.DEFAULT_MTLS_ENDPOINT
451-
elif use_mtls_env == "auto":
452-
if is_mtls:
453-
api_endpoint = self.DEFAULT_MTLS_ENDPOINT
454-
else:
455-
api_endpoint = self.DEFAULT_ENDPOINT
456-
else:
457-
raise MutualTLSChannelError(
458-
"Unsupported GOOGLE_API_USE_MTLS_ENDPOINT value. Accepted "
459-
"values: never, auto, always"
460-
)
488+
api_key_value = getattr(client_options, "api_key", None)
489+
if api_key_value and credentials:
490+
raise ValueError(
491+
"client_options.api_key and credentials are mutually exclusive"
492+
)
461493

462494
# Save or instantiate the transport.
463495
# Ordinarily, we provide the transport, but allowing a custom transport
464496
# instance provides an extensibility point for unusual situations.
465497
if isinstance(transport, CloudDeployTransport):
466498
# transport is a CloudDeployTransport instance.
467-
if credentials or client_options.credentials_file:
499+
if credentials or client_options.credentials_file or api_key_value:
468500
raise ValueError(
469501
"When providing a transport instance, "
470502
"provide its credentials directly."
@@ -476,6 +508,15 @@ def __init__(
476508
)
477509
self._transport = transport
478510
else:
511+
import google.auth._default # type: ignore
512+
513+
if api_key_value and hasattr(
514+
google.auth._default, "get_api_key_credentials"
515+
):
516+
credentials = google.auth._default.get_api_key_credentials(
517+
api_key_value
518+
)
519+
479520
Transport = type(self).get_transport_class(transport)
480521
self._transport = Transport(
481522
credentials=credentials,

tests/unit/gapic/deploy_v1/test_cloud_deploy.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,83 @@ def test_cloud_deploy_client_mtls_env_auto(
390390
)
391391

392392

393+
@pytest.mark.parametrize("client_class", [CloudDeployClient, CloudDeployAsyncClient])
394+
@mock.patch.object(
395+
CloudDeployClient, "DEFAULT_ENDPOINT", modify_default_endpoint(CloudDeployClient)
396+
)
397+
@mock.patch.object(
398+
CloudDeployAsyncClient,
399+
"DEFAULT_ENDPOINT",
400+
modify_default_endpoint(CloudDeployAsyncClient),
401+
)
402+
def test_cloud_deploy_client_get_mtls_endpoint_and_cert_source(client_class):
403+
mock_client_cert_source = mock.Mock()
404+
405+
# Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "true".
406+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
407+
mock_api_endpoint = "foo"
408+
options = client_options.ClientOptions(
409+
client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint
410+
)
411+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source(
412+
options
413+
)
414+
assert api_endpoint == mock_api_endpoint
415+
assert cert_source == mock_client_cert_source
416+
417+
# Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "false".
418+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}):
419+
mock_client_cert_source = mock.Mock()
420+
mock_api_endpoint = "foo"
421+
options = client_options.ClientOptions(
422+
client_cert_source=mock_client_cert_source, api_endpoint=mock_api_endpoint
423+
)
424+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source(
425+
options
426+
)
427+
assert api_endpoint == mock_api_endpoint
428+
assert cert_source is None
429+
430+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "never".
431+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}):
432+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
433+
assert api_endpoint == client_class.DEFAULT_ENDPOINT
434+
assert cert_source is None
435+
436+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "always".
437+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}):
438+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
439+
assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT
440+
assert cert_source is None
441+
442+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert doesn't exist.
443+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
444+
with mock.patch(
445+
"google.auth.transport.mtls.has_default_client_cert_source",
446+
return_value=False,
447+
):
448+
api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
449+
assert api_endpoint == client_class.DEFAULT_ENDPOINT
450+
assert cert_source is None
451+
452+
# Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "auto" and default cert exists.
453+
with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
454+
with mock.patch(
455+
"google.auth.transport.mtls.has_default_client_cert_source",
456+
return_value=True,
457+
):
458+
with mock.patch(
459+
"google.auth.transport.mtls.default_client_cert_source",
460+
return_value=mock_client_cert_source,
461+
):
462+
(
463+
api_endpoint,
464+
cert_source,
465+
) = client_class.get_mtls_endpoint_and_cert_source()
466+
assert api_endpoint == client_class.DEFAULT_MTLS_ENDPOINT
467+
assert cert_source == mock_client_cert_source
468+
469+
393470
@pytest.mark.parametrize(
394471
"client_class,transport_class,transport_name",
395472
[
@@ -4949,6 +5026,23 @@ def test_credentials_transport_error():
49495026
transport=transport,
49505027
)
49515028

5029+
# It is an error to provide an api_key and a transport instance.
5030+
transport = transports.CloudDeployGrpcTransport(
5031+
credentials=ga_credentials.AnonymousCredentials(),
5032+
)
5033+
options = client_options.ClientOptions()
5034+
options.api_key = "api_key"
5035+
with pytest.raises(ValueError):
5036+
client = CloudDeployClient(client_options=options, transport=transport,)
5037+
5038+
# It is an error to provide an api_key and a credential.
5039+
options = mock.Mock()
5040+
options.api_key = "api_key"
5041+
with pytest.raises(ValueError):
5042+
client = CloudDeployClient(
5043+
client_options=options, credentials=ga_credentials.AnonymousCredentials()
5044+
)
5045+
49525046
# It is an error to provide scopes and a transport instance.
49535047
transport = transports.CloudDeployGrpcTransport(
49545048
credentials=ga_credentials.AnonymousCredentials(),
@@ -5724,3 +5818,33 @@ def test_client_ctx():
57245818
with client:
57255819
pass
57265820
close.assert_called()
5821+
5822+
5823+
@pytest.mark.parametrize(
5824+
"client_class,transport_class",
5825+
[
5826+
(CloudDeployClient, transports.CloudDeployGrpcTransport),
5827+
(CloudDeployAsyncClient, transports.CloudDeployGrpcAsyncIOTransport),
5828+
],
5829+
)
5830+
def test_api_key_credentials(client_class, transport_class):
5831+
with mock.patch.object(
5832+
google.auth._default, "get_api_key_credentials", create=True
5833+
) as get_api_key_credentials:
5834+
mock_cred = mock.Mock()
5835+
get_api_key_credentials.return_value = mock_cred
5836+
options = client_options.ClientOptions()
5837+
options.api_key = "api_key"
5838+
with mock.patch.object(transport_class, "__init__") as patched:
5839+
patched.return_value = None
5840+
client = client_class(client_options=options)
5841+
patched.assert_called_once_with(
5842+
credentials=mock_cred,
5843+
credentials_file=None,
5844+
host=client.DEFAULT_ENDPOINT,
5845+
scopes=None,
5846+
client_cert_source_for_mtls=None,
5847+
quota_project_id=None,
5848+
client_info=transports.base.DEFAULT_CLIENT_INFO,
5849+
always_use_jwt_access=True,
5850+
)

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: https://github.com/googleapis/python-deploy/commit/aaa957f2673db673c3a8e38275d4689323ded044

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy