Skip to content

Commit abc929a

Browse files
committed
bugfix: add tenant to destination based resolution
1 parent 5cb795f commit abc929a

2 files changed

Lines changed: 111 additions & 85 deletions

File tree

src/sap_cloud_sdk/core/auditlog_ng/__init__.py

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,28 @@
2121
client = create_client(config=config)
2222
2323
Usage:
24-
resolve from a Destination:
24+
resolve from a Destination (requires tenant):
2525
2626
from sap_cloud_sdk.core.auditlog_ng import create_client
2727
2828
client = create_client(
29+
tenant="my-tenant-subdomain",
2930
destination_name="my-audit-destination",
3031
destination_instance="my-binding-instance",
3132
fragment_name="prod-fragment", # optional
3233
)
3334
35+
Usage:
36+
explicit keyword arguments:
37+
38+
from sap_cloud_sdk.core.auditlog_ng import create_client
39+
40+
client = create_client(
41+
endpoint="audit.example.com:443",
42+
deployment_id="my-deployment",
43+
namespace="namespace-123",
44+
)
45+
3446
# Send an audit event (protobuf message)
3547
event_id = client.send(event, "DataAccess")
3648
client.close()
@@ -67,6 +79,7 @@ def _get_config_from_destination(
6779
destination_name: Optional[str],
6880
destination_instance: Optional[str],
6981
fragment_name: Optional[str] = None,
82+
tenant: Optional[str] = None,
7083
) -> dict[str, str]:
7184
"""Resolve endpoint, deployment_id and namespace from a named Destination.
7285
@@ -84,16 +97,16 @@ def _get_config_from_destination(
8497
passed as ``instance=`` to ``destination.create_client()``.
8598
fragment_name: Optional fragment name merged into the destination
8699
before resolution. Wrapped in ``ConsumptionOptions`` when provided.
100+
tenant: Tenant subdomain forwarded as ``tenant=`` to
101+
``get_destination()``.
87102
88103
Returns:
89104
dict with keys ``endpoint``, ``deployment_id``, ``namespace``
90-
when destination is found.
105+
when destination is found, or an empty dict when not found.
91106
92-
Returns:
93-
None: If destination is not found.
94-
95-
Return:
96-
ValueError: If required properties are missing.
107+
Raises:
108+
ValueError: If required properties (``deploymentId``/``deploymentRegion``
109+
or ``namespace``) are missing from the resolved destination.
97110
"""
98111
# Lazy import — keeps destination an optional dependency; importing auditlog_ng
99112
# in environments without the destination package continues to work.
@@ -113,7 +126,10 @@ def _get_config_from_destination(
113126
)
114127

115128
destination = dest_client.get_destination(
116-
name=destination_name, options=options, level=ConsumptionLevel.SUBACCOUNT
129+
name=destination_name,
130+
options=options,
131+
tenant=tenant,
132+
level=ConsumptionLevel.SUBACCOUNT,
117133
)
118134

119135
if destination is None:
@@ -153,6 +169,7 @@ def create_client(
153169
destination_name: Optional[str] = "AuditLogV3_Destination",
154170
destination_instance: Optional[str] = "default",
155171
fragment_name: Optional[str] = None,
172+
tenant: Optional[str] = None,
156173
# Explicit connection parameters
157174
endpoint: Optional[str] = None,
158175
deployment_id: Optional[str] = None,
@@ -174,28 +191,35 @@ def create_client(
174191
1. **Explicit config object** — pass a pre-built :class:`AuditLogNGConfig`
175192
via ``config``; all other keyword arguments are ignored.
176193
177-
2. **Destination-based resolution** — pass ``destination_name`` and
178-
``destination_instance`` (both required); ``fragment_name`` is optional.
179-
The Destination module resolves the named destination at subaccount level
180-
and extracts ``endpoint``, ``deployment_id`` (with fallback to
181-
``deploymentRegion``), and ``namespace`` from its properties.
194+
2. **Destination-based resolution** — pass ``tenant`` (required to activate
195+
this path). ``destination_name`` and ``destination_instance`` identify
196+
the destination; ``fragment_name`` is optional. The Destination module
197+
resolves the named destination at subaccount level and extracts
198+
``endpoint``, ``deployment_id`` (with fallback to ``deploymentRegion``),
199+
and ``namespace`` from its properties.
182200
183201
3. **Explicit keyword arguments** — pass ``endpoint``, ``deployment_id``,
184-
and ``namespace`` directly.
202+
and ``namespace`` directly (used when ``tenant`` is not provided).
185203
186204
Args:
187205
_telemetry_source: Internal parameter for telemetry. Not for external use.
188206
config: Optional explicit configuration. If provided, all other
189207
keyword arguments are ignored.
190-
destination_name: Name of the SAP Destination to resolve. Must be
191-
combined with ``destination_instance`` to enter the destination path.
208+
tenant: Tenant subdomain used for destination-based resolution.
209+
When provided, ``destination_name`` and ``destination_instance``
210+
are used to look up the destination.
211+
destination_name: Name of the SAP Destination to resolve. Only used
212+
when ``tenant`` is provided.
192213
destination_instance: Destination service binding instance name, passed
193-
as ``instance=`` to ``destination.create_client()``. Must be combined
194-
with ``destination_name`` to enter the destination path.
214+
as ``instance=`` to ``destination.create_client()``. Only used
215+
when ``tenant`` is provided.
195216
fragment_name: Optional destination fragment name merged before resolution.
196-
endpoint: OTLP gRPC endpoint (``host:port``).
197-
deployment_id: Deployment identifier.
198-
namespace: Namespace identifier.
217+
endpoint: OTLP endpoint (``host:port``). Required when ``tenant``
218+
is not provided and ``config`` is not given.
219+
deployment_id: Deployment identifier. Required when ``tenant`` is not
220+
provided and ``config`` is not given.
221+
namespace: Namespace identifier. Required when ``tenant`` is not
222+
provided and ``config`` is not given.
199223
cert_file: Path to client certificate (PEM) for mTLS.
200224
key_file: Path to client private key (PEM) for mTLS.
201225
ca_file: Path to CA certificate (PEM) for server verification.
@@ -216,26 +240,28 @@ def create_client(
216240
try:
217241
if config is None:
218242
try:
219-
resolved = _get_config_from_destination(
220-
destination_name=destination_name,
221-
destination_instance=destination_instance,
222-
fragment_name=fragment_name,
223-
)
224-
if resolved:
225-
endpoint = resolved["endpoint"]
226-
deployment_id = resolved["deployment_id"]
227-
namespace = resolved["namespace"]
243+
if tenant:
244+
resolved = _get_config_from_destination(
245+
destination_name=destination_name,
246+
destination_instance=destination_instance,
247+
fragment_name=fragment_name,
248+
tenant=tenant,
249+
)
250+
if resolved:
251+
endpoint = resolved["endpoint"]
252+
deployment_id = resolved["deployment_id"]
253+
namespace = resolved["namespace"]
228254
else:
229255
if not endpoint or not deployment_id or not namespace:
230256
raise ValueError(
231257
"endpoint, deployment_id, and namespace are required "
232-
"when config or valid destination is not provided"
258+
"when config or valid tenant subdomain is not provided"
233259
)
234260

235261
config = AuditLogNGConfig(
236-
endpoint=endpoint,
237-
deployment_id=deployment_id,
238-
namespace=namespace,
262+
endpoint=endpoint or "",
263+
deployment_id=deployment_id or "",
264+
namespace=namespace or "",
239265
cert_file=cert_file,
240266
key_file=key_file,
241267
ca_file=ca_file,

0 commit comments

Comments
 (0)