Tenant API
Overview
Tenants provide isolation in the Nomad PaaS controlplane. Each tenant gets its own Nomad namespace, Consul namespace, Vault namespace, and Traefik routing prefix.
Tenant Resource
Schema
id: string # Unique tenant ID (UUID)
name: string # Tenant name (unique, alphanumeric)
displayName: string # Display name for UI
domain: string # Tenant domain for L7 routing
quotas:
maxJobs: int # Maximum number of jobs
maxCPUMHz: int # CPU limit in MHz
maxMemoryMB: int # Memory limit in MB
maxDeployments: int # Max concurrent deployments
createdAt: time # Creation timestamp
updatedAt: time # Last update timestamp
active: bool # Tenant status
API Endpoints
List Tenants
Response:
{
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "acme",
"displayName": "ACME Corp",
"domain": "acme.example.com",
"quotas": {
"maxJobs": 50,
"maxCPUMHz": 8000,
"maxMemoryMB": 16384,
"maxDeployments": 20
},
"createdAt": "2024-01-15T10:00:00Z",
"updatedAt": "2024-01-15T10:00:00Z",
"active": true
}
],
"count": 1
}
Create Tenant
POST /api/v1/tenants
Content-Type: application/json
{
"name": "acme",
"displayName": "ACME Corp",
"domain": "acme.example.com",
"quotas": {
"maxJobs": 50,
"maxCPUMHz": 8000,
"maxMemoryMB": 16384,
"maxDeployments": 20
}
}
Response: 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "acme",
"displayName": "ACME Corp",
"domain": "acme.example.com",
"quotas": {
"maxJobs": 50,
"maxCPUMHz": 8000,
"maxMemoryMB": 16384,
"maxDeployments": 20
},
"createdAt": "2024-01-15T10:00:00Z",
"updatedAt": "2024-01-15T10:00:00Z",
"active": true
}
Validation:
| Field | Rules |
|---|---|
name |
Required, alphanumeric, 2-32 characters |
displayName |
Required, max 64 characters |
domain |
Optional, valid domain |
quotas |
Optional, defaults applied |
Get Tenant
Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "acme",
"displayName": "ACME Corp",
"domain": "acme.example.com",
"quotas": {
"maxJobs": 50,
"maxCPUMHz": 8000,
"maxMemoryMB": 16384,
"maxDeployments": 20
},
"createdAt": "2024-01-15T10:00:00Z",
"updatedAt": "2024-01-15T10:00:00Z",
"active": true
}
Delete Tenant
Response: 204 No Content
Destructive Operation
Deleting a tenant will: - Remove all applications in the tenant - Delete the Nomad namespace and all jobs - Remove Consul services and namespace - Delete Traefik routing configuration
Tenant-Scoped Endpoints
All endpoints below require a tenantID in the path and are scoped to that tenant.
List Applications
Deploy Application
POST /api/v1/tenants/{tenantID}/apps
Content-Type: application/json
{
"apiVersion": "core.oam.dev/v1alpha2",
"kind": "Application",
"metadata": {
"name": "webapp"
},
"spec": {
"components": [
{
"name": "frontend",
"type": "webservice",
"properties": {
"image": "nginx:latest",
"cpu": "500m",
"memory": "256Mi"
}
}
]
}
}
Get Application
Update Application
Delete Application
Get Application Status
Restart Application
Scale Application
POST /api/v1/tenants/{tenantID}/apps/{appName}/scale
Content-Type: application/json
{
"component": "frontend",
"replicas": 3
}
List Application Allocations
List Services
List Events
Authentication
All tenant-scoped endpoints require authentication via:
- API Key:
X-API-Key: <tenant-api-key> - OIDC Token:
Authorization: Bearer <jwt-token>
The tenant ID is extracted from the authentication context, not the URL path.
Quotas
Default quotas applied if not specified:
| Quota | Default |
|---|---|
maxJobs |
50 |
maxCPUMHz |
8000 |
maxMemoryMB |
16384 |
maxDeployments |
20 |
Tenant Isolation
Each tenant gets isolated resources:
graph TD
Tenant[Tenant: acme] --> NS[Nomad Namespace<br/>namespace-acme]
Tenant --> CS[Consul Namespace<br/>namespace-acme]
Tenant --> VS[Vault Namespace<br/>namespace-acme]
Tenant --> TP[Traefik Prefix<br/>/acme/*]
NS --> Job1[Job 1]
NS --> Job2[Job 2]
CS --> Svc1[Service 1]
CS --> Svc2[Service 2]