> ## Documentation Index
> Fetch the complete documentation index at: https://docs.internal.nscale.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Managing Tenants and Allocations

> How Fleet Manager admins define customer capacity ownership and Radar projection metadata.

Tenants and allocations are customer-impacting Fleet Manager records. They control how Fleet Manager maps physical [devices](../start-here/glossary#node) to customer-facing [Radar](../start-here/glossary#radar-api) inventory and health data.

Treat tenant and allocation changes as production changes. If they are missing or wrong, devices can disappear from Radar, appear under the wrong customer, resolve against the wrong UNI region, or fail topology and instance lookups.

## Domain Model

### Tenant

A tenant is Fleet Manager's local representation of a customer capacity owner inside a Fleet Manager organisation.

The tenant answers: who is this capacity for?

Tenant annotations map that Fleet Manager tenant to external UNI customer identity:

```json theme={null}
{
  "uni_org_id": "<UNI organization UUID>",
  "uni_org_name": "<UNI organization name>"
}
```

Some cross-environment test tenants must not be projected to Radar even when they keep valid UNI organisation annotations. Mark those tenants with both Radar-ignore annotations:

```json theme={null}
{
  "radar_ignore": "true",
  "radar_ignore_reason": "reservation-cross-env-test"
}
```

`radar_ignore` is optional, but when set it must be exactly `"true"` or `"false"`. `radar_ignore_reason` is required and must be non-empty when `radar_ignore` is `"true"`. Devices assigned to an ignored tenant are skipped by the Fleet Manager Radar ingestion agent and are not published to Radar. A newly tagged tenant is picked up by the Radar agent's poll loop, so the stop is bounded by the agent poll interval rather than being instant. This is not a retraction path: Fleet Manager does not delete `resource_stats` rows that Radar already stored before the tenant was ignored.

### Allocation

An allocation is a time-bounded assignment of specific devices at one Fleet Manager site to one tenant.

The allocation answers: for this time window, which devices are assigned to this tenant, and in which UNI region is that capacity exposed?

Allocation annotations map the assigned capacity to the UNI region used by Radar and compute-resolver:

```json theme={null}
{
  "uni_region_id": "<UNI region UUID>",
  "uni_region_name": "<UNI region name, for example no-sys2-sta1>"
}
```

### Current Tenant

A device's current tenant is derived from its active allocation at the current time.

Allocation windows are half-open intervals:

```text theme={null}
start_at <= now < end_at
```

If a device has no active allocation, it has no current tenant.

### Current UNI Region

A device's current UNI region is derived from its active allocation at the current time.

If a device has no active allocation, it has no current UNI region for Radar projection.

### Custody Is Separate

Allocation does not mean Fleet Manager has handed operational control to the customer. Custody is modelled through device operational status and workflow behaviour.

## Why This Matters

The Radar ingestion flow depends on tenant and allocation metadata.

```text theme={null}
Device -> active Allocation -> Tenant + UNI Region
Tenant annotations -> UNI organisation for Radar
Allocation annotations -> UNI region for Radar
```

Fleet Manager publishes device resource projections to Radar. Radar ingest stores resource stats that Radar Service later exposes by UNI organisation and region.

Wrong metadata has customer-visible consequences:

* Missing tenant means the device has no current customer assignment.
* Missing `uni_org_id` or `uni_org_name` means Radar cannot map the device to a UNI organisation.
* Wrong `uni_org_id` can publish or store resource stats under the wrong customer.
* Missing `uni_region_id` means Radar cannot store the correct region ID for topology and resource filters.
* Wrong `uni_region_id` means Radar Service requests scoped by Region may not find the device.
* Missing or wrong `uni_region_name` means Radar ingest cannot resolve UNI Instances in the correct region scope.

## Operating Rules

Use these rules when creating or updating tenants and allocations.

* One tenant per customer capacity owner within the relevant Fleet Manager organisation. For UNI customers the UNI agent creates it; create a tenant by hand only for capacity that is not UNI-facing.
* Put UNI organisation identity on the tenant, not on each allocation.
* Create one allocation per tenant, site, UNI region, time window, and device cohort.
* Split capacity across multiple allocations when a customer has devices in multiple UNI regions.
* Do not create one allocation that mixes devices from different UNI regions.
* Tenants and organisations cannot be deleted, through the API or through Django admin — the Delete button is absent on both. A tenant delete would strand org-service's organisation-to-tenant mapping with nothing to correct it, and an organisation delete cascades through every site, device, role, workflow and tenant beneath it. To retire a customer, end their allocations (set `end_at`) and leave the tenant in place; to move a tenant to another UNI organisation, change `uni_org_id` rather than recreating it. Do not delete allocations for operational cleanup either; preserve history and adjust future windows instead.
* Treat changes to `uni_org_id`, `uni_region_id`, or `uni_region_name` as customer-impacting changes.
* Use `radar_ignore=true` only for explicit cross-environment or operational exceptions, and always provide a clear `radar_ignore_reason`.

Fleet Manager stores annotations as generic metadata today. The API validates annotation shape, the `radar_ignore` reason invariant, and that `uni_org_id` is a UUID when set — a malformed value is rejected with a 400. It does not validate that `uni_org_id`, `uni_org_name`, `uni_region_id`, or `uni_region_name` point at live UNI records, and nothing can tell you that `uni_org_id` names the *right* organisation. Admins must verify them before relying on Radar output or on the organisation-to-tenant mapping WatchTower resolves against.

## Tenants For UNI Customers Are Created By The UNI Agent

The UNI agent lists every organisation in UNI Identity and, within five minutes of a new one appearing, creates the tenant that carries its ID as `uni_org_id` and its name as `uni_org_name`. It matches on `uni_org_id` alone, so every tenant that already carries the right ID is adopted as it is. After creation the agent never writes to a tenant again: `name`, `slug`, `tags` and every annotation, `uni_org_name` included, are yours to change. It never deletes a tenant and never touches allocations.

Agent-created tenants are named after the UNI organisation. Rename them freely; the agent will not rename them back.

### Linking A Hand-Made Tenant

A tenant created by hand for a UNI customer is in one of three states, and the agent reports each without changing it:

* **Linked**: carries the customer's `uni_org_id`. Adopted silently.
* **Unlinked**: carries no `uni_org_id`. Counted on the `unlinked` gauge. If its name or slug matches the UNI organisation, the agent refuses to create a twin and raises a blocked-create alert naming both.
* **Wrong**: carries an ID no live organisation has. Counted on the `orphaned` gauge. The agent cannot tell it from a new customer, so it creates the correct tenant alongside it.

To repair:

1. **Identify.** The blocked-create alert logs both IDs, and after every poll the agent logs the orphaned, unlinked and renamed tenants with their IDs, so a non-zero gauge always points at named records. `fleetctl api tenant list` shows every tenant's annotations, and `fleetctl api allocation list --tenant-id <id>` lists what hangs off the tenant you are about to change. Nothing about allocations moves during repair.
2. **Link.** Set `uni_org_id` and `uni_org_name` on the hand-made tenant. On its next pass the agent finds exactly one tenant for the organisation and does nothing more.
3. **Retire a twin.** If the agent created a tenant before you linked the hand-made one, both now carry the ID and the duplicate alert fires. Tenants cannot be deleted, so retire the empty twin: remove its `uni_org_id`, set `radar_ignore` to `"true"` with a reason, and tag it `retired`. The organisation resolves to one tenant again and the twin drops off every consumer's lookup and off the `unlinked` gauge.

## Before Creating A Tenant By Hand

Confirm these values before creating a tenant:

* Fleet Manager organisation ID.
* Customer-facing tenant name and slug.
* UNI organisation UUID.
* UNI organisation name.
* Whether a tenant for the same customer already exists in the Fleet Manager organisation.

Example API payload:

```json theme={null}
{
  "name": "Customer A",
  "slug": "customer-a",
  "organisation": "<fleet-manager-organisation-id>",
  "annotations": {
    "uni_org_id": "<uni-organisation-id>",
    "uni_org_name": "Customer A"
  }
}
```

API endpoint:

```text theme={null}
POST /api/v1/tenants/
```

## Before Creating An Allocation

Confirm these values before creating an allocation:

* Tenant exists and has valid `uni_org_id` and `uni_org_name` annotations.
* Fleet Manager site ID.
* UNI region UUID for this capacity.
* UNI Region Name, for example `no-sys2-sta1`.
* Start and end timestamps in UTC.
* Complete list of device UUIDs.
* All devices are in the same Fleet Manager site.
* No device is already allocated in an overlapping time window.

Example API payload:

```json theme={null}
{
  "tenant": "<tenant-id>",
  "site": "<site-id>",
  "start_at": "2026-06-01T00:00:00Z",
  "end_at": "2027-06-01T00:00:00Z",
  "device_ids": ["<device-id-1>", "<device-id-2>"],
  "annotations": {
    "uni_region_id": "<uni-region-id>",
    "uni_region_name": "no-sys2-sta1"
  }
}
```

API endpoint:

```text theme={null}
POST /api/v1/allocations/
```

## Changing Devices On An Existing Allocation

Use the API-backed `fleetctl` workflow when an allocation already exists and a
whole site, rack set, or explicit device set must be added. This does not require
shell or database access to a Fleet Manager pod.

Preview a rack-and-role selection:

```bash theme={null}
uv run fleetctl api allocation assign <allocation-id> \
  --rack-names A01,A02 \
  --device-role-slugs gpu-node \
  --dry-run true
```

Apply it by omitting `--dry-run true`:

```bash theme={null}
uv run fleetctl api allocation assign <allocation-id> \
  --rack-names A01,A02 \
  --device-role-slugs gpu-node
```

Selection rules:

* Pass `--device-ids` or `--rack-names`, but not both.
* Pass `--all-devices true` to select every device in the allocation's site; a
  request with no selector is rejected.
* `--device-role-slugs` narrows whichever selector is active.
* Existing members are left unchanged, so the operation is safe to repeat.
* Devices in another overlapping allocation are not added. Non-conflicting
  devices are still added and the response uses HTTP 409 with conflict details;
  `fleetctl` therefore exits non-zero until the overlaps are resolved.

API endpoint:

```text theme={null}
POST /api/v1/allocations/{id}/assign/
```

### Unassign Devices

Use the same selectors to preview devices that will be removed from an
allocation:

```bash theme={null}
uv run fleetctl api allocation unassign <allocation-id> \
  --rack-names A01,A02 \
  --device-role-slugs gpu-node \
  --dry-run true
```

Omit `--dry-run true` to remove the memberships. Selected devices that are not
members of the target allocation are reported as idempotent no-ops. The
operation never removes memberships from other allocations. To select the
whole site, pass `--all-devices true` explicitly; a bare unassignment request
is rejected.

API endpoint:

```text theme={null}
POST /api/v1/allocations/{id}/unassign/
```

## Troubleshooting

### Device Does Not Appear In Radar

Check the device has an active allocation at the current time.

Check the tenant has `uni_org_id` and `uni_org_name` annotations.

Check the tenant does not have `radar_ignore` set to `"true"`. If it does, the device is intentionally skipped by Fleet Manager's Radar ingestion agent; confirm `radar_ignore_reason` explains the exception.

Check the allocation has `uni_region_id` and `uni_region_name` annotations.

Check the device has a valid `infrastructure_ref`; Radar projection skips devices without it.

### Device Appears Under The Wrong Customer

Check the active allocation points to the intended tenant.

Check the tenant's `uni_org_id` annotation matches the intended UNI organisation.

Check whether a correction requires a new allocation window rather than editing historical allocation data.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.