Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes http endpoint being overwritten by gRPC address argument in constructor #621

Merged
merged 4 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions dapr/clients/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,7 @@ def __init__(
if http_timeout_seconds is None:
http_timeout_seconds = settings.DAPR_HTTP_TIMEOUT_SECONDS
self.invocation_client = DaprInvocationHttpClient(headers_callback=headers_callback,
timeout=http_timeout_seconds,
address=address)
timeout=http_timeout_seconds)
elif invocation_protocol == 'GRPC':
pass
else:
Expand Down
12 changes: 4 additions & 8 deletions dapr/clients/http/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ class DaprHttpClient:
def __init__(self,
message_serializer: 'Serializer',
timeout: Optional[int] = 60,
headers_callback: Optional[Callable[[], Dict[str, str]]] = None,
address: Optional[str] = None):
headers_callback: Optional[Callable[[], Dict[str, str]]] = None):
"""Invokes Dapr over HTTP.

Args:
Expand All @@ -49,16 +48,13 @@ def __init__(self,
self._timeout = aiohttp.ClientTimeout(total=timeout)
self._serializer = message_serializer
self._headers_callback = headers_callback
self._address = address

def get_api_url(self) -> str:
if self._address:
return '{}/{}'.format(self._address, settings.DAPR_API_VERSION)
if settings.DAPR_HTTP_ENDPOINT:
return '{}/{}'.format(settings.DAPR_HTTP_ENDPOINT, settings.DAPR_API_VERSION)
else:
return 'http://{}:{}/{}'.format(settings.DAPR_RUNTIME_HOST,
settings.DAPR_HTTP_PORT, settings.DAPR_API_VERSION)

return 'http://{}:{}/{}'.format(settings.DAPR_RUNTIME_HOST,
settings.DAPR_HTTP_PORT, settings.DAPR_API_VERSION)

async def send_bytes(
self, method: str, url: str,
Expand Down
5 changes: 2 additions & 3 deletions dapr/clients/http/dapr_invocation_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,14 @@ class DaprInvocationHttpClient:
def __init__(
self,
timeout: int = 60,
headers_callback: Optional[Callable[[], Dict[str, str]]] = None,
address: Optional[str] = None):
headers_callback: Optional[Callable[[], Dict[str, str]]] = None):
"""Invokes Dapr's API for method invocation over HTTP.

Args:
timeout (int, optional): Timeout in seconds, defaults to 60.
headers_callback (lambda: Dict[str, str]], optional): Generates header for each request.
"""
self._client = DaprHttpClient(DefaultJSONSerializer(), timeout, headers_callback, address)
self._client = DaprHttpClient(DefaultJSONSerializer(), timeout, headers_callback)

async def invoke_method_async(
self,
Expand Down
8 changes: 8 additions & 0 deletions daprdocs/content/en/python-sdk-docs/python-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ The Python SDK allows you to interface with all of the [Dapr building blocks]({{

### Invoke a service

The Dapr Python SDK provides a simple API for invoking services via either HTTP or gRPC (deprecated). The protocol can be selected by setting the `DAPR_API_METHOD_INVOCATION_PROTOCOL` environment variable, defaulting to HTTP when unset. GRPC service invocation in Dapr is deprecated and GRPC proxying is recommended as an alternative.

```python
from dapr.clients import DaprClient

Expand All @@ -80,6 +82,12 @@ with DaprClient() as d:
resp = d.invoke_method('service-to-invoke', 'method-to-invoke', data='{"id":"100", "FirstName":"Value", "LastName":"Value"}', http_verb='post')
```

The base endpoint for HTTP api calls is specified in the `DAPR_HTTP_ENDPOINT` environment variable.
If this variable is not set, the endpoint value is derived from the `DAPR_RUNTIME_HOST` and `DAPR_HTTP_PORT` variables, whose default values are `127.0.0.1` and `3500` accordingly.

The base endpoint for gRPC calls is the one used for the client initialisation ([explained above](#initialising-the-client)).


- For a full guide on service invocation visit [How-To: Invoke a service]({{< ref howto-invoke-discover-services.md >}}).
- Visit [Python SDK examples](https://github.com/dapr/python-sdk/tree/master/examples/invoke-simple) for code samples and instructions to try out service invocation.

Expand Down
5 changes: 3 additions & 2 deletions tests/clients/test_http_service_invocation_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ def test_get_api_url_default(self):
settings.DAPR_API_VERSION),
client.invocation_client._client.get_api_url())

def test_get_api_url_endpoint_as_argument(self):
@patch.object(settings, "DAPR_HTTP_ENDPOINT", "https://domain1.com:5000")
def test_dont_get_api_url_endpoint_as_argument(self):
client = DaprClient("http://localhost:5000")
self.assertEqual('http://localhost:5000/{}'.format(settings.DAPR_API_VERSION),
self.assertEqual('https://domain1.com:5000/{}'.format(settings.DAPR_API_VERSION),
client.invocation_client._client.get_api_url())

@patch.object(settings, "DAPR_HTTP_ENDPOINT", "https://domain1.com:5000")
Expand Down
51 changes: 10 additions & 41 deletions tests/clients/test_secure_http_service_invocation_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,13 @@
limitations under the License.
"""
import ssl
from unittest.mock import patch

from dapr.clients.http.client import DaprHttpClient
from .certs import CERTIFICATE_CHAIN_PATH
from .fake_http_server import FakeHttpServer
from dapr.conf import settings
from dapr.clients import DaprClient
from dapr.proto import common_v1
from asyncio import TimeoutError


from opencensus.trace.tracer import Tracer # type: ignore
from opencensus.trace import print_exporter, samplers

from .test_http_service_invocation_client import DaprInvocationHttpClientTests

Expand All @@ -45,7 +40,8 @@ def setUp(self):
self.server.start()
settings.DAPR_HTTP_PORT = self.server_port
settings.DAPR_API_METHOD_INVOCATION_PROTOCOL = 'http'
self.client = DaprClient("https://localhost:{}".format(self.server_port))
settings.DAPR_HTTP_ENDPOINT = "https://localhost:{}".format(self.server_port)
self.client = DaprClient()
self.app_id = 'fakeapp'
self.method_name = 'fakemethod'
self.invoke_url = f'/v1.0/invoke/{self.app_id}/method/{self.method_name}'
Expand All @@ -55,37 +51,10 @@ def tearDown(self):
settings.DAPR_API_TOKEN = None
settings.DAPR_API_METHOD_INVOCATION_PROTOCOL = 'http'

def test_global_timeout_setting_is_honored(self):
previous_timeout = settings.DAPR_HTTP_TIMEOUT_SECONDS
settings.DAPR_HTTP_TIMEOUT_SECONDS = 1
new_client = DaprClient("https://localhost:{}".format(self.server_port))
self.server.set_server_delay(1.5)
with self.assertRaises(TimeoutError):
new_client.invoke_method(self.app_id, self.method_name, "")

settings.DAPR_HTTP_TIMEOUT_SECONDS = previous_timeout

def test_invoke_method_with_tracer(self):
tracer = Tracer(sampler=samplers.AlwaysOnSampler(), exporter=print_exporter.PrintExporter())

self.client = DaprClient("https://localhost:{}".format(self.server_port),
headers_callback=lambda: tracer.propagator.to_headers(
tracer.span_context))
self.server.set_response(b"FOO")

with tracer.span(name="test"):
req = common_v1.StateItem(key='test')
resp = self.client.invoke_method(self.app_id, self.method_name, http_verb='PUT',
data=req, )

request_headers = self.server.get_request_headers()

self.assertIn('Traceparent', request_headers)
self.assertEqual(b'FOO', resp.data)

def test_timeout_exception_thrown_when_timeout_reached(self):
new_client = DaprClient("https://localhost:{}".format(self.server_port),
http_timeout_seconds=1)
self.server.set_server_delay(1.5)
with self.assertRaises(TimeoutError):
new_client.invoke_method(self.app_id, self.method_name, "")
@patch.object(settings, "DAPR_HTTP_ENDPOINT", None)
def test_get_api_url_default(self):
client = DaprClient()
self.assertEqual(
'http://{}:{}/{}'.format(settings.DAPR_RUNTIME_HOST, settings.DAPR_HTTP_PORT,
settings.DAPR_API_VERSION),
client.invocation_client._client.get_api_url())
Loading