Skip to content

Commit

Permalink
Support GRPC user-agent in SDK
Browse files Browse the repository at this point in the history
* Prepend User-Agent set by grpc library with `yandex-cloud-python-sdk/$VERSION` entry. Version is taken from pkg_resources
* Allow SDK clients to add their own User-Agent entry, which will be prepended to previous result.
  • Loading branch information
Petr Reznikov committed Dec 9, 2021
1 parent 35f39f0 commit 12d5666
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 9 deletions.
6 changes: 4 additions & 2 deletions examples/dataproc/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@

import yandexcloud

USER_AGENT = 'ycloud-python-sdk:dataproc.example.main'


def main():
logging.basicConfig(level=logging.INFO)
arguments = parse_cmd()
if arguments.token:
sdk = yandexcloud.SDK(token=arguments.token)
sdk = yandexcloud.SDK(token=arguments.token, user_agent=USER_AGENT)
else:
with open(arguments.sa_json_path) as infile:
sdk = yandexcloud.SDK(service_account_key=json.load(infile))
sdk = yandexcloud.SDK(service_account_key=json.load(infile), user_agent=USER_AGENT)

fill_missing_arguments(sdk, arguments)

Expand Down
6 changes: 4 additions & 2 deletions examples/dataproc/using_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@
import yandexcloud
from yandexcloud.operations import OperationError

USER_AGENT = 'ycloud-python-sdk:dataproc.example.using_wrapper'


def main():
logging.basicConfig(level=logging.INFO)
arguments = parse_cmd()
if arguments.token:
sdk = yandexcloud.SDK(token=arguments.token)
sdk = yandexcloud.SDK(token=arguments.token, user_agent=USER_AGENT)
else:
with open(arguments.sa_json_path) as infile:
sdk = yandexcloud.SDK(service_account_key=json.load(infile))
sdk = yandexcloud.SDK(service_account_key=json.load(infile), user_agent=USER_AGENT)
fill_missing_arguments(sdk, arguments)

dataproc = sdk.wrappers.Dataproc(
Expand Down
22 changes: 19 additions & 3 deletions yandexcloud/_channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@
from yandexcloud import _auth_plugin
from yandexcloud._auth_fabric import get_auth_token_requester

import pkg_resources
try:
VERSION = pkg_resources.get_distribution('yandexcloud').version
except pkg_resources.DistributionNotFound:
VERSION = '0.0.0'

SDK_USER_AGENT = 'yandex-cloud-python-sdk/{version}'.format(version=VERSION)


class Channels(object):
def __init__(self, **kwargs):
def __init__(self, client_user_agent=None, **kwargs):
self._channel_creds = grpc.ssl_channel_credentials(
root_certificates=kwargs.get('root_certificates'),
private_key=kwargs.get('private_key'),
Expand All @@ -20,11 +28,19 @@ def __init__(self, **kwargs):

self._unauthenticated_channel = None
self._channels = None
self._client_user_agent = client_user_agent

def channel_options(self):
return tuple(
('grpc.primary_user_agent', user_agent)
for user_agent in [self._client_user_agent, SDK_USER_AGENT]
if user_agent is not None
)

def channel(self, endpoint):
if not self._channels:
self._unauthenticated_channel = grpc.secure_channel(
self._endpoint, self._channel_creds)
self._endpoint, self._channel_creds, options=self.channel_options())
endpoint_service = ApiEndpointServiceStub(
self._unauthenticated_channel)
resp = endpoint_service.List(ListApiEndpointsRequest())
Expand All @@ -37,7 +53,7 @@ def channel(self, endpoint):
self._channel_creds, call_creds)

self._channels = {
ep.id: grpc.secure_channel(ep.address, creds)
ep.id: grpc.secure_channel(ep.address, creds, options=self.channel_options())
for ep in endpoints
}

Expand Down
17 changes: 15 additions & 2 deletions yandexcloud/_sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,21 @@


class SDK(object):
def __init__(self, interceptor=None, **kwargs):
self._channels = _channels.Channels(**kwargs)
def __init__(self, interceptor=None, user_agent=None, **kwargs):
"""
API entry-point object.
:param interceptor: GRPC interceptor to be used instead of default RetryInterceptor
:type interceptor: Union[
UnaryUnaryClientInterceptor,
UnaryStreamClientInterceptor,
StreamUnaryClientInterceptor,
StreamStreamClientInterceptor
]
:param user_agent: String to prepend User-Agent metadata header for all GRPC requests made via SDK object
:type user_agent: Optional[str]
"""
self._channels = _channels.Channels(client_user_agent=user_agent, **kwargs)
if interceptor is None:
interceptor = RetryInterceptor(
max_retry_count=5,
Expand Down

0 comments on commit 12d5666

Please sign in to comment.