From ded92d0acdcde4295d0e5df05fda0d83783a3991 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Thu, 18 Jun 2020 16:27:38 -0700 Subject: feat: allow credentials files to be passed for channel creation (#50) Co-authored-by: Dov Shlachter --- google/api_core/exceptions.py | 6 ++++++ google/api_core/grpc_helpers.py | 37 +++++++++++++++++++++++++++-------- google/api_core/grpc_helpers_async.py | 14 +++++++++++-- 3 files changed, 47 insertions(+), 10 deletions(-) (limited to 'google') diff --git a/google/api_core/exceptions.py b/google/api_core/exceptions.py index d1459ab..b9c46ca 100644 --- a/google/api_core/exceptions.py +++ b/google/api_core/exceptions.py @@ -41,6 +41,12 @@ class GoogleAPIError(Exception): pass +class DuplicateCredentialArgs(GoogleAPIError): + """Raised when multiple credentials are passed.""" + + pass + + @six.python_2_unicode_compatible class RetryError(GoogleAPIError): """Raised when a function has exhausted all of its available retries. diff --git a/google/api_core/grpc_helpers.py b/google/api_core/grpc_helpers.py index b617ddf..2203968 100644 --- a/google/api_core/grpc_helpers.py +++ b/google/api_core/grpc_helpers.py @@ -176,13 +176,16 @@ def wrap_errors(callable_): return _wrap_unary_errors(callable_) -def _create_composite_credentials(credentials=None, scopes=None, ssl_credentials=None): +def _create_composite_credentials(credentials=None, credentials_file=None, scopes=None, ssl_credentials=None): """Create the composite credentials for secure channels. Args: credentials (google.auth.credentials.Credentials): The credentials. If not specified, then this function will attempt to ascertain the credentials from the environment using :func:`google.auth.default`. + credentials_file (str): A file with credentials that can be loaded with + :func:`google.auth.load_credentials_from_file`. This argument is + mutually exclusive with credentials. scopes (Sequence[str]): A optional list of scopes needed for this service. These are only used when credentials are not specified and are passed to :func:`google.auth.default`. @@ -191,14 +194,22 @@ def _create_composite_credentials(credentials=None, scopes=None, ssl_credentials Returns: grpc.ChannelCredentials: The composed channel credentials object. + + Raises: + google.api_core.DuplicateCredentialArgs: If both a credentials object and credentials_file are passed. """ - if credentials is None: - credentials, _ = google.auth.default(scopes=scopes) - else: - credentials = google.auth.credentials.with_scopes_if_required( - credentials, scopes + if credentials and credentials_file: + raise exceptions.DuplicateCredentialArgs( + "'credentials' and 'credentials_file' are mutually exclusive." ) + if credentials_file: + credentials, _ = google.auth.load_credentials_from_file(credentials_file, scopes=scopes) + elif credentials: + credentials = google.auth.credentials.with_scopes_if_required(credentials, scopes) + else: + credentials, _ = google.auth.default(scopes=scopes) + request = google.auth.transport.requests.Request() # Create the metadata plugin for inserting the authorization header. @@ -218,7 +229,7 @@ def _create_composite_credentials(credentials=None, scopes=None, ssl_credentials ) -def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, **kwargs): +def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, credentials_file=None, **kwargs): """Create a secure channel with credentials. Args: @@ -231,14 +242,24 @@ def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, are passed to :func:`google.auth.default`. ssl_credentials (grpc.ChannelCredentials): Optional SSL channel credentials. This can be used to specify different certificates. + credentials_file (str): A file with credentials that can be loaded with + :func:`google.auth.load_credentials_from_file`. This argument is + mutually exclusive with credentials. kwargs: Additional key-word args passed to :func:`grpc_gcp.secure_channel` or :func:`grpc.secure_channel`. Returns: grpc.Channel: The created channel. + + Raises: + google.api_core.DuplicateCredentialArgs: If both a credentials object and credentials_file are passed. """ + composite_credentials = _create_composite_credentials( - credentials, scopes, ssl_credentials + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + ssl_credentials=ssl_credentials ) if HAS_GRPC_GCP: diff --git a/google/api_core/grpc_helpers_async.py b/google/api_core/grpc_helpers_async.py index 9ded803..1dfe8b9 100644 --- a/google/api_core/grpc_helpers_async.py +++ b/google/api_core/grpc_helpers_async.py @@ -206,7 +206,7 @@ def wrap_errors(callable_): return _wrap_stream_errors(callable_) -def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, **kwargs): +def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, credentials_file=None, **kwargs): """Create an AsyncIO secure channel with credentials. Args: @@ -219,13 +219,23 @@ def create_channel(target, credentials=None, scopes=None, ssl_credentials=None, are passed to :func:`google.auth.default`. ssl_credentials (grpc.ChannelCredentials): Optional SSL channel credentials. This can be used to specify different certificates. + credentials_file (str): A file with credentials that can be loaded with + :func:`google.auth.load_credentials_from_file`. This argument is + mutually exclusive with credentials. kwargs: Additional key-word args passed to :func:`aio.secure_channel`. Returns: aio.Channel: The created channel. + + Raises: + google.api_core.DuplicateCredentialArgs: If both a credentials object and credentials_file are passed. """ + composite_credentials = grpc_helpers._create_composite_credentials( - credentials, scopes, ssl_credentials + credentials=credentials, + credentials_file=credentials_file, + scopes=scopes, + ssl_credentials=ssl_credentials ) return aio.secure_channel(target, composite_credentials, **kwargs) -- cgit v1.2.3