Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
138 changes: 138 additions & 0 deletions _includes/code/howto/namespaces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# How-to: Manage namespaces — Python examples.
#
# Requires Weaviate v1.38.0+ with NAMESPACES_ENABLED=true, and the Python
# client release that adds namespace support (PR
# weaviate/weaviate-python-client#2033). Examples connect as a global
# (operator) principal; the `client.namespaces.*` endpoints are
# operator-only.

import os
import time

import weaviate
from weaviate.auth import Auth
from weaviate.rbac.models import Permissions


# ==========================================
# ===== Connect as the operator =====
# ==========================================

# START Connect
client = weaviate.connect_to_local(
auth_credentials=Auth.api_key(os.environ["OPERATOR_API_KEY"]),
)
# END Connect

# Clean up any leftovers from a previous run so the script is idempotent.
for cleanup_ns in ("customer1",):
existing = client.namespaces.get(name=cleanup_ns)
if existing is not None and existing.state != "deleting":
client.namespaces.delete(name=cleanup_ns)
# Wait for the two-phase cascade cleanup to finish.
deadline = time.time() + 60
while client.namespaces.get(name=cleanup_ns) is not None and time.time() < deadline:
time.sleep(0.5)
for cleanup_role in ("namespace_admin", "all_namespace_admin"):
try:
client.roles.delete(role_name=cleanup_role)
except Exception:
pass


# ==========================================
# ===== Create a namespace =====
# ==========================================

# START CreateNamespace
# Omit home_node to let the cluster pick automatically. To pin the
# namespace's shards to a specific node, pass home_node="<node-name>"
# where <node-name> is a current storage candidate from
# client.cluster.nodes().
ns = client.namespaces.create(name="customer1")
print(ns.name, ns.home_node, ns.state)

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This expression logs
sensitive data (private)
as clear text.
# → customer1 <pinned-node> active
# END CreateNamespace


# ==========================================
# ===== Get a single namespace =====
# ==========================================

# START GetNamespace
ns = client.namespaces.get(name="customer1")
if ns is None:
print("not found")
else:
print(ns.name, ns.home_node, ns.state)

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This expression logs
sensitive data (private)
as clear text.
# END GetNamespace


# ==========================================
# ===== List all namespaces =====
# ==========================================

# START ListNamespaces
for ns in client.namespaces.list_all():
print(ns.name, ns.state)
# END ListNamespaces


# ==========================================
# ===== Update the home node =====
# ==========================================

# START UpdateNamespace
# Updating home_node only affects future shard placements — existing
# shards are not moved. Pick a storage candidate from
# client.cluster.nodes().
target_node = client.cluster.nodes()[0].name
client.namespaces.update(name="customer1", home_node=target_node)
# END UpdateNamespace


# ==========================================
# ===== Create a namespaced DB user =====
# ==========================================

# START CreateNamespacedUser
# Bind the new DB user to a namespace. The user is stored internally as
# `customer1:api_user` and can only see resources in `customer1`.
api_key = client.users.db.create(user_id="api_user", namespace="customer1")
print(api_key)

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This expression logs
sensitive data (password)
as clear text.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
# END CreateNamespacedUser


# ==========================================
# ===== Define a role with namespace-management permissions =====
# ==========================================

# START NamespacePermissions
# `manage_namespaces` is the operator-only RBAC permission for
# /v1/namespaces CRUD. Scope it to a specific namespace or to all (`*`).
client.roles.create(
role_name="namespace_admin",
permissions=Permissions.namespaces(namespace="customer1", manage=True),
)

# Wildcard — manage any namespace
client.roles.create(
role_name="all_namespace_admin",
permissions=Permissions.namespaces(namespace="*", manage=True),
)
# END NamespacePermissions


# ==========================================
# ===== Delete a namespace =====
# ==========================================

# START DeleteNamespace
# Two-phase: the namespace flips to `state: deleting`, then a background
# cascade removes its DB users, aliases, and collections. Idempotent —
# repeated calls during cleanup return without error.
client.namespaces.delete(name="customer1")
# END DeleteNamespace


client.close()
5 changes: 5 additions & 0 deletions _includes/feature-notes/namespaces.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
:::caution Preview — added in `v1.38`

Namespaces are a preview feature. The REST shape, principal model, and operator surface may change before GA. Phase 1 (collections + aliases scoped per namespace) is in v1.38; namespace-scoped roles and DB sub-users (Phase 2) and suspend-on-idle (Phase 3) are designed but not yet shipped. Namespaces are only supported on **newly bootstrapped clusters** — they cannot be enabled on an existing cluster.

:::
3 changes: 3 additions & 0 deletions docs/deploy/configuration/env-vars/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import APITable from '@site/src/components/APITable';
| `MEMORY_READONLY_PERCENTAGE` | If memory usage is higher than the given percentage all shards on the affected node will be marked as `READONLY`, meaning all future write requests will fail. (Default: `0` - i.e. no limit) | `string - number` | `75` |
| `MEMORY_WARNING_PERCENTAGE` | If memory usage is higher than the given percentage a warning will be logged by all shards on the affected node's disk. (Default: `0` - i.e. no limit) | `string - number` | `85` |
| `MODULES_CLIENT_TIMEOUT` | Timeout for requests to Weaviate modules. Default: `50s` | `string - duration` | `5s`, `10m`, `1h` |
| `NAMESPACES_ENABLED` | If `true`, enable cluster-level [namespace](/weaviate/concepts/namespaces.md) isolation (`v1.38` Preview). Requires `DISABLE_GRAPHQL=true` and `REPLICATION_MAXIMUM_FACTOR=1`. Supported only on newly bootstrapped clusters — cannot be enabled on a cluster with pre-existing non-namespaced collections, and a cluster that has run with it `true` cannot be downgraded. Default: `false` <br/>Added in `v1.38` | `boolean` | `true` |
| `OBJECTS_TTL_BATCH_SIZE` | Number of objects deleted per batch during TTL cleanup. With the default pause settings, a pause occurs every `OBJECTS_TTL_BATCH_SIZE * OBJECTS_TTL_PAUSE_EVERY_NO_BATCHES` objects (100,000 by default). Can be modified at runtime. Default: `10000` <br/>Added in `v1.36` | `string - number` | `10000` |
| `OBJECTS_TTL_CONCURRENCY_FACTOR` | Controls the concurrency of the TTL deletion process as a multiplier. Higher values use more resources but delete faster. Must be greater than 0. Can be modified at runtime. Default: `1` <br/>Added in `v1.36` | `string - number` | `1` |
| `OBJECTS_TTL_DELETE_SCHEDULE` | Schedule for deleting expired objects. Accepts standard 5-field cron format, 6-field (with seconds), 7-field (with seconds and year), descriptors (`@yearly`, `@monthly`, `@weekly`, `@daily`, `@hourly`), or hash expressions. Default: `""` (disabled) <br/>Added in `v1.36` | `string - cron format` | `0 */6 * * *` (every 6 hours) |
Expand Down Expand Up @@ -184,6 +185,8 @@ For more information on authentication and authorization, see the [Authenticatio
| `AUTHENTICATION_OIDC_SCOPES` | OIDC scopes to request | `string - comma-separated list` | `openid,email` |
| `AUTHENTICATION_OIDC_SKIP_CLIENT_ID_CHECK` | Skip OIDC Client ID check | `boolean` | `false` |
| `AUTHENTICATION_OIDC_USERNAME_CLAIM` | OIDC Username Claim | `string` | `email` |
| `OIDC_NAMESPACE_CLAIM` | On namespace-enabled clusters (`NAMESPACES_ENABLED=true`), name of the OIDC token claim that carries the principal's namespace. See [Namespaces — OIDC classification](/weaviate/concepts/namespaces.md#oidc-classification). <br/>Added in `v1.38` | `string` | `namespace` |
| `OIDC_GLOBAL_PRINCIPAL_CLAIM` | On namespace-enabled clusters, name of the OIDC token claim that marks the principal as global (boolean). Mutually exclusive with `OIDC_NAMESPACE_CLAIM` on a per-token basis — see [Namespaces — OIDC classification](/weaviate/concepts/namespaces.md#oidc-classification). <br/>Added in `v1.38` | `string` | `is_global` |
| `AUTHORIZATION_ADMINLIST_ENABLED` | Enable AdminList authorization scheme (mutually exclusive with `AUTHORIZATION_RBAC_ENABLED`) | `boolean` | `true` |
| `AUTHORIZATION_ADMINLIST_USERS` | Users with admin permission when AdminList scheme used | `string - comma-separated list` | `jane@example.com,john@example.com` |
| `AUTHORIZATION_ADMINLIST_READONLY_USERS` | Users with read-only permission when AdminList scheme used | `string - comma-separated list` | `alice@example.com,dave@example.com` |
Expand Down
18 changes: 18 additions & 0 deletions docs/deploy/configuration/oidc.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,24 @@ Configuring the OIDC token issuer is outside the scope of Weaviate's configurati
By default, Weaviate validates that the token includes a specified client id in the audience claim. If your token issuer does not support this feature, you can turn it off as outlined in the [authentication configuration](./authentication.md#oidc-docker).
:::

## OIDC on namespace-enabled clusters

On clusters with `NAMESPACES_ENABLED=true` ([namespaces, `v1.38`+ Preview](/weaviate/concepts/namespaces.md)), every OIDC token is classified as either a **namespaced** or **global** principal. Two env vars select which claims drive the classification:

| Env var | Purpose |
|---|---|
| `OIDC_NAMESPACE_CLAIM` | Name of the claim that holds the namespace string (e.g. `namespace`). |
| `OIDC_GLOBAL_PRINCIPAL_CLAIM` | Name of the claim that holds the global-principal boolean (e.g. `is_global`). |

A token must select exactly one classification. The server **rejects** tokens that:

- Carry both a namespace claim and the global-principal claim set to `true`.
- Carry neither claim on a namespace-enabled cluster.
- Name a namespace that doesn't exist (Weaviate never auto-creates).
- Combine a namespace claim with a `root` group from `AUTHORIZATION_RBAC_ROOT_GROUPS` / `_USERS` — `root` is cluster-global and cannot coexist with a namespace.

On clusters where `NAMESPACES_ENABLED=false`, presence of either claim in the token causes the request to be rejected. See [Namespaces — OIDC classification](/weaviate/concepts/namespaces.md#oidc-classification) for the full rules.

## Questions and feedback

import DocsFeedback from '/_includes/docs-feedback.mdx';
Expand Down
6 changes: 6 additions & 0 deletions docs/weaviate/concepts/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,12 @@ For details on configuring your schema, see the [schema tutorial](../starter-gui

To separate data within a cluster, use multi-tenancy. Weaviate partitions the cluster into shards. Each shard holds data for a single tenant.

:::info Multi-tenancy is different from namespaces

[Multi-tenancy](../manage-collections/multi-tenancy.mdx) isolates **data within one collection**. [Namespaces](./namespaces.md) (`v1.38`+ Preview) isolate **collections across the cluster**. They're orthogonal — a multi-tenant collection inside a namespace works as expected.

:::

```mermaid
%%{init: {'theme': 'base', 'themeVariables': { 'background': '#f5f5f5' }}}%%
flowchart TB
Expand Down
Loading
Loading