Skip to content

COH-30144 Implement NSLookup resolution for Python Client #193

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

Merged
merged 15 commits into from
Jan 9, 2025
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
84 changes: 84 additions & 0 deletions .github/workflows/validate-nslookup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Copyright 2022, 2025, Oracle Corporation and/or its affiliates.
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl.

name: CI nslookup Build
on:
workflow_dispatch:
schedule:
- cron: "0 5 * * *"
push:
branches:
- '*'
pull_request:
branches: [ main ]
jobs:
ci-nslookup:
strategy:
fail-fast: false
matrix:
python-version: ["3.9.x"]
poetry-version: ["1.8.4"]
os: [ubuntu-latest]
coherenceVersion:
- 24.09
- 22.06.10
base-image:
- gcr.io/distroless/java17-debian11
runs-on: ${{ matrix.os }}
steps:
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'zulu'

- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Cache Maven packages
uses: actions/cache@v4
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2

- name: Install Poetry
shell: bash
run: |
pip install poetry==${{ matrix.poetry-version }}

- name: Install Dependencies
run: python -m poetry install

- name: Configure Validation
run: python -m poetry run make validate-setup

- name: Validate Sources
run: python -m poetry run make validate

- name: Run Coherence Server
shell: bash
run: |
export COHERENCE_VERSION=${{ matrix.coherenceVersion }}
curl -sL https://raw.githubusercontent.com/oracle/coherence-cli/main/scripts/install.sh | bash
cohctl version
cohctl create cluster grpc-cluster -v ${{ matrix.coherenceVersion }} -y -a coherence-grpc-proxy
sleep 20
cohctl monitor health -n localhost:7574 -T 40 -w

- name: Run test
shell: bash
run: |
export COHERENCE_SERVER_ADDRESS=coherence:///localhost:7574
python -m poetry run make test-nslookup

- name: Archive server logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: server-logs-${{matrix.python-version}}-${{ matrix.coherenceVersion }}
path: ./tests/utils/*.txt
retention-days: 10
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,29 @@ exclude: \w*(_pb2)\w*

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # frozen: v5.0.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files

- repo: https://github.com/PyCQA/flake8
rev: e43806be3607110919eff72939fda031776e885a # frozen: 7.1.1
rev: 7.1.1
hooks:
- id: flake8

- repo: https://github.com/psf/black
rev: 1b2427a2b785cc4aac97c19bb4b9a0de063f9547 # frozen: 24.10.0
rev: 24.10.0
hooks:
- id: black

- repo: https://github.com/pre-commit/mirrors-mypy
rev: f56614daa94d5cd733d3b7004c5df9caad267b4a # frozen: v1.13.0
rev: v1.13.0
hooks:
- id: mypy

- repo: https://github.com/PyCQA/isort
rev: c235f5e450b4b84e58d114ed4c589cbf454175a3 # frozen: 5.13.2
rev: 5.13.2
hooks:
- id: isort
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# ----------------------------------------------------------------------------------------------------------------------
# Copyright (c) 2022, 2023, Oracle and/or its affiliates.
# Copyright (c) 2022, 2025, Oracle and/or its affiliates.
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl.
#
Expand Down Expand Up @@ -171,6 +171,17 @@ generate-proto: ## Generate Proto Files
test: ##
pytest -W error --cov src/coherence --cov-report=term --cov-report=html $(UNIT_TESTS) $(E2E_TESTS)

# ----------------------------------------------------------------------------------------------------------------------
# Run nslookup tests with code coverage
# ----------------------------------------------------------------------------------------------------------------------
.PHONY: test-nslookup
test-nslookup: ##
pytest -W error \
--deselect tests/e2e/test_session.py::test_basics \
--deselect tests/e2e/test_session.py::test_session_lifecycle \
--deselect tests/e2e/test_session.py::test_fail_fast \
$(UNIT_TESTS) $(E2E_TESTS)

# ----------------------------------------------------------------------------------------------------------------------
# Run unit tests with code coverage
# ----------------------------------------------------------------------------------------------------------------------
Expand Down
24 changes: 20 additions & 4 deletions src/coherence/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
from .filter import Filter
from .local_cache import CacheStats, LocalCache, NearCacheOptions
from .messages_pb2 import PageRequest
from .nslookup import AsyncNSLookup
from .processor import EntryProcessor
from .proxy_service_messages_v1_pb2 import ProxyRequest, ProxyResponse
from .proxy_service_v1_pb2_grpc import ProxyServiceStub
Expand Down Expand Up @@ -1574,7 +1575,9 @@ class Options:
"""
Environment variable to specify the Coherence gRPC server address for the client to connect to. The
environment variable is used if address is not passed as an argument in the constructor. If the environment
variable is not set and address is not passed as an argument then `DEFAULT_ADDRESS` is used
variable is not set and address is not passed as an argument then `DEFAULT_ADDRESS` is used. One can also
use the 'coherence' gRPC resolver address of "coherence:///host:port" to connect to the Coherence Name
Service, running on the cluster port, and automatically discover the gRPC endpoints.
"""
ENV_REQUEST_TIMEOUT = "COHERENCE_CLIENT_REQUEST_TIMEOUT"
"""
Expand Down Expand Up @@ -1627,9 +1630,11 @@ def __init__(
"""
Construct a new :func:`coherence.client.Options`

:param address: Address of the target Coherence cluster. If not explicitly set, this defaults
to :func:`coherence.client.Options.DEFAULT_ADDRESS`. See
also :func:`coherence.client.Options.ENV_SERVER_ADDRESS`
:param address: Address of the target Coherence cluster gRPC endpoint of the form "host:port" to connect to.
If not explicitly set, this defaults to :func:`coherence.client.Options.DEFAULT_ADDRESS`. See
also :func:`coherence.client.Options.ENV_SERVER_ADDRESS`. One can also use the 'coherence' gRPC resolver
address of "coherence:///host:port" to connect to the Coherence Name Service, running on the
cluster port, and automatically discover the gRPC endpoints.
:param scope: scope name used to link this :func:`coherence.client.Options` to the
corresponding `ConfigurableCacheFactory` on the server.
:param request_timeout_seconds: Defines the request timeout, in `seconds`, that will be applied to each
Expand Down Expand Up @@ -1667,6 +1672,14 @@ def __init__(
if tls_options is not None:
self._tls_options = tls_options

async def _resolve_ns_address(self) -> None:
if self.address.startswith("coherence:///"):
# Remove the prefix and split into host and port
_, ns_addr = self._address.split("coherence:///", 1)

# Resolve to grpc address from nameservice address
self._address = await AsyncNSLookup._resolve_nslookup_address(ns_addr)

@property
def tls_options(self) -> Optional[TlsOptions]:
"""
Expand Down Expand Up @@ -1908,6 +1921,9 @@ def __init__(self, session_options: Optional[Options] = None):

@staticmethod
async def create(session_options: Optional[Options] = None) -> Session:
if session_options is None:
session_options = Options()
await session_options._resolve_ns_address()
session: Session = Session(session_options)
await session._set_ready(False)
await session._handshake.handshake()
Expand Down
4 changes: 4 additions & 0 deletions src/coherence/entry.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Copyright (c) 2022, 2024, Oracle and/or its affiliates.
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl.

from __future__ import annotations

from typing import Generic, TypeVar
Expand Down
Loading
Loading