Skip to content

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

GET /api/v1/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

GET /api/v1/tenants/{tenantID}

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

DELETE /api/v1/tenants/{tenantID}

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

GET /api/v1/tenants/{tenantID}/apps

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

GET /api/v1/tenants/{tenantID}/apps/{appName}

Update Application

PUT /api/v1/tenants/{tenantID}/apps/{appName}
Content-Type: application/json

<application yaml>

Delete Application

DELETE /api/v1/tenants/{tenantID}/apps/{appName}

Get Application Status

GET /api/v1/tenants/{tenantID}/apps/{appName}/status

Restart Application

POST /api/v1/tenants/{tenantID}/apps/{appName}/restart

Scale Application

POST /api/v1/tenants/{tenantID}/apps/{appName}/scale
Content-Type: application/json

{
  "component": "frontend",
  "replicas": 3
}

List Application Allocations

GET /api/v1/tenants/{tenantID}/apps/{appName}/allocations

List Services

GET /api/v1/tenants/{tenantID}/services

List Events

GET /api/v1/tenants/{tenantID}/events?limit=100

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]