Skip to main content

Catalog Service

Overview​

The Catalog service exposes three focused clients that mirror the server-side routers:

AttributeDescription
client.catalog.datasetsDataset CRUD, schema management, and URN helpers
client.catalog.containersContainer lifecycle and dataset membership
client.catalog.secretsSecret registration/listing tied to corpuser owners

Each client accepts/returns the Pydantic models defined in kamiwaza_sdk/schemas/catalog.py, so responses are thread-safe and easy to validate.

Datasets​

from kamiwaza_sdk import KamiwazaClient
from kamiwaza_sdk.schemas.catalog import DatasetCreate, DatasetUpdate

client = KamiwazaClient("https://localhost/api", api_key="...shh...")

# Create and immediately fetch the dataset metadata
payload = DatasetCreate(
name="/var/data/visitors.parquet",
platform="s3",
environment="PROD",
description="Daily visitor export",
properties={"region": "us-east-1", "endpoint": "http://localhost:19100"},
tags=["pii", "bronze"],
)
dataset_urn = client.catalog.datasets.create(payload)
dataset = client.catalog.datasets.get(dataset_urn)

# List only datasets the receiver authorizes for this federated identity.
remote_datasets = client.catalog.datasets.list(target_cluster="receiver-name")

# Update tags/properties via URN
client.catalog.datasets.update(
dataset_urn,
DatasetUpdate(tags=["pii", "silver"], properties={"region": "us-east-1"}),
)

# Fetch or update the logical schema
schema = client.catalog.datasets.get_schema(dataset_urn)
client.catalog.datasets.update_schema(dataset_urn, schema)

# Convenience wrappers for legacy code that previously called
# `client.catalog.create_dataset(...)` still work and delegate to the dataset client.

Containers​

from kamiwaza_sdk.schemas.catalog import ContainerCreate, ContainerUpdate

containers = client.catalog.containers
container_urn = containers.create(ContainerCreate(name="rag-demo", platform="kamiwaza"))
containers.add_dataset(container_urn, dataset_urn)

# Read all members, or explicitly walk bounded pages. Cursors are opaque.
page = containers.get(container_urn, datasets_page_size=100)
members = list(page.datasets)
while page.datasets_next_cursor is not None:
page = containers.get(
container_urn,
datasets_page_size=100,
datasets_cursor=page.datasets_next_cursor,
)
members.extend(page.datasets)

# Update metadata or re-parent the container
containers.update(container_urn, ContainerUpdate(description="Demo assets"))

# Remove membership or delete the container
containers.remove_dataset(container_urn, dataset_urn)
containers.delete(container_urn)

get() without pagination arguments retains the server's default behavior. datasets_page_size accepts 1–1000. The returned datasets_next_cursor marks another page, and workroom_id identifies the container's Workroom. Removing a membership or deleting its container retains the dataset and its schema. Catalog metadata deletion does not establish physical data deletion.

All URNs can be percent-encoded for the /v2/{urn} endpoints with client.catalog.encode_urn(...) (or DatasetClient.encode_path_urn / ContainerClient.encode_path_urn).

Secrets​

from kamiwaza_sdk.schemas.catalog import SecretCreate

secrets = client.catalog.secrets
secret_urn = secrets.create(
SecretCreate(
name="minio/rag-demo",
value="{'aws_access_key_id':'minioadmin','aws_secret_access_key':'minioadmin'}",
owner="urn:li:corpuser:demo",
description="Demo MinIO credentials",
),
clobber=True, # overwrite existing entry if present
)

secret = secrets.get(secret_urn)
for visible in secrets.list():
print(visible.urn, visible.owner)

secrets.delete(secret_urn)

Secret URNs are generated by the server (often DataHub-style such as urn:li:dataHubSecret:<name>). Treat them as opaque identifiers—capture the value returned by create(...) and pass it verbatim to subsequent get/delete calls rather than constructing prefixes client-side.

The SDK now calls the /catalog/secrets/v2/{secret_urn} path with the raw URN, so you shouldn’t need to percent-encode or reshape it yourself; keep the string exactly as the server returned.

Secret reads return metadata, not the stored value. Creating a duplicate name fails unless clobber=True is explicit. Clobber replaces the existing secret while preserving its URN; applications should treat that as a credential change, not as key rotation in the underlying storage encryption scheme.

test_catalog_secret_contract_live.py exercises those contracts through uv run pytest -m integration, including the actual v2, by-URN and list HTTP responses before SDK model parsing can hide unknown fields. It uses a unique synthetic secret, checks default duplicate refusal and explicit clobber, and removes the secret. It does not inspect encrypted storage or establish key custody, cryptographic rotation, or another user's value-read permissions.

Diagnostics​

Both the catalog and auth services now expose lightweight health endpoints to simplify readiness checks:

client.auth.health() # -> {"status": "ok", ...}
client.auth.metadata() # -> {"version": "...", ...}
client.catalog.health() # -> {"status": "ok"}
client.catalog.metadata() # -> {... service banner ...}

These helpers pair with the improved VectorDBUnavailableError so SDK consumers can reason about platform readiness before kicking off ingestion or retrieval jobs.

Writable dataset content​

Set DatasetCreate(writable=True, storage=DatasetStorageRequest(backend="object")) to ask the platform for managed storage in the selected Workroom. Omit both fields to preserve the existing metadata-only create request. Dataset responses expose workroom_id, storage_binding and content_revision.

client.catalog.datasets provides create_object, list_objects, get_object, get_object_content, replace_object, delete_object and purge_object. Uploads take a (filename, bytes_or_open_binary_stream, content_type) tuple; create_object optionally takes a distinct logical_path. The SDK does not close caller-owned upload streams. Downloads return bytes and close the HTTP response. Content metadata is typed by the models in kamiwaza_sdk.schemas.dataset_content and preserves unknown response fields.

from kamiwaza_sdk.schemas.catalog import DatasetCreate
from kamiwaza_sdk.schemas.dataset_content import DatasetStorageRequest

urn = client.catalog.datasets.create(DatasetCreate(
name="notes", platform="kamiwaza", writable=True,
storage=DatasetStorageRequest(backend="object"),
))
objects = client.catalog.datasets
item = objects.create_object(urn, ("note.txt", b"first", "text/plain"))
assert objects.get_object_content(urn, item.item_id) == b"first"
replacement = objects.replace_object(
urn, item.item_id, ("note.txt", b"second", "text/plain"),
if_match=f'"{item.etag}"',
)
tombstone = objects.delete_object(
urn, replacement.item_id, if_match=f'"{replacement.etag}"',
)

POST refuses an existing live path. Replace/delete forward If-Match unchanged; Core requires a quoted ETag, *, or an RFC 9110 list and returns 412 for a missing or stale condition. Replacement may allocate a new item ID; use the returned item for later writes. Deletion leaves a tombstone and retained bytes. purge_object is a separate, explicit administrator operation; a response is not independent proof of physical removal from the backend.

The integration node tests/integration/test_writable_dataset_content_live.py::test_writable_dataset_content_lifecycle uses its own Workroom and object-backed dataset, exact bytes, precondition and revision checks, and strict cleanup. It is selected by pytest -m integration. Storage limits, non-admin/tenant permissions, file-backend variants, concurrent writers, retention/acknowledgements and independent purge/audit readback remain explicit residuals.

Writable datasets require the kamiwaza catalog platform, independently of the object/file backend choice. Byte downloads are buffered in client memory; this SDK method does not return an HTTP streaming handle or response headers.