Xeonr Developer Docs

Create Cluster

POST
/containers.api.v1.ClusterService/CreateCluster

Registers a cluster owned by owner_team in PENDING state with PRIVATE visibility. Nothing runs on it until an operator enrols (CreateEnrolmentToken, then the operator's first connection). A platform admin's owner_team is verified against Xeonr Auth and canonicalised to the team URN.

Access: a platform admin, or an admin of the owner_team team.

Authorization

BearerAuth
AuthorizationBearer <token>

A namespace-scoped API key (cpk_…) for machines, or a Xeonr Auth OIDC token for humans. The key's namespace and role are pinned server-side.

In: header

Header Parameters

Connect-Protocol-Version?number

Define the version of the Connect protocol

Connect-Timeout-Ms?number

Define the timeout, in ms

Request Body

application/json

displayName?string
Length1 <= length <= 255
ownerTeam?string

The owning team: a URN, or for a platform admin a slug that is verified and canonicalised.

Match^(urn:xeonr:auth:team:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|[a-z0-9]([a-z0-9-]{0,38}[a-z0-9])?)$
labels?
Propertiesproperties <= 32
[key: string]?never

Response Body

application/json

application/json

curl -X POST "https://containers.xeonr.io/containers.api.v1.ClusterService/CreateCluster" \  -H "Connect-Protocol-Version: 1" \  -H "Connect-Timeout-Ms: 1000" \  -H "Content-Type: application/json" \  -d '{}'
{
  "cluster": {
    "clusterId": "string",
    "displayName": "string",
    "ownerTeam": "string",
    "visibility": "CLUSTER_VISIBILITY_UNSPECIFIED",
    "grants": [
      {
        "team": "string",
        "quotaCpuMillis": 0,
        "quotaMemoryMb": 0,
        "quotaMaxPods": 0,
        "quotaStorageMb": 0,
        "quotaMaxVolumes": 0
      }
    ],
    "default": true,
    "allowRunc": true,
    "state": "CLUSTER_STATE_UNSPECIFIED",
    "lastSeen": "2023-01-15T01:30:15.01Z",
    "operatorVersion": "string",
    "capabilities": {
      "gvisor": true,
      "cpCsi": true,
      "previewIngress": true,
      "appIngress": true,
      "previewDomain": "string",
      "appDomain": "string"
    },
    "labels": {
      "property1": "string",
      "property2": "string"
    },
    "createdAt": "2023-01-15T01:30:15.01Z",
    "capacity": {
      "observedAt": "2023-01-15T01:30:15.01Z",
      "nodes": [
        {
          "name": "string",
          "ready": true,
          "allocatableCpuMillis": "string",
          "allocatableMemoryMb": "string",
          "allocatablePods": 0,
          "requestedCpuMillis": "string",
          "requestedMemoryMb": "string",
          "pods": 0,
          "volumeDiskFreeMb": "string"
        }
      ],
      "installCap": {
        "cpuMillis": "string",
        "memoryMb": "string",
        "pods": 0,
        "storageMb": "string",
        "volumes": 0
      },
      "installRequested": {
        "cpuMillis": "string",
        "memoryMb": "string",
        "pods": 0,
        "storageMb": "string",
        "volumes": 0
      }
    },
    "conditions": [
      {
        "type": "TYPE_UNSPECIFIED",
        "message": "string",
        "since": "2023-01-15T01:30:15.01Z",
        "pods": [
          "string"
        ]
      }
    ],
    "archiveIntervalSec": 0,
    "archivedBytes": "string"
  }
}
{
  "code": "not_found",
  "message": "string",
  "details": [
    {
      "type": "string",
      "value": "string",
      "debug": {}
    }
  ]
}

containers.api.v1.ClusterService

ClusterService manages where namespaces run (BYOC, platform-docs container-platform/docs/BYOC.md §2). A cluster is one operator install: one enrolment, one credential, one owner team. Two teams installing on the same physical cluster produce two records, and the platform neither knows nor needs to know that they share hardware. The platform's own fleet is a cluster like any other, flagged GLOBAL and `default`, which is where a namespace lands when nothing names a cluster. A namespace is placed on exactly one cluster when it is created (Namespace.cluster_id) and everything beneath it — sandboxes, jobs, apps, environments, volumes, pools, keys — runs there. Placement is immutable: moving a namespace is a migration, not an update. Who may place a namespace on a cluster is its visibility: PRIVATE is the owner team only; SHARED adds the teams holding a grant; GLOBAL is every team, within the everyone-grant. A grant also caps how much of the cluster that team's namespaces may hold in total (BYOC.md §5.4): the sum of a team's namespace quotas on a cluster must fit its grant, and the owner team's grant is implicit and unbounded. GetCluster and ListClusters carry allow_api_keys: a namespace key reaches the cluster its namespace is placed on and nothing else. The mutations do not, for the reason CreateNamespace does not: each needs a team role, and no key holds one.

Create Enrolment Token POST

Mints a one-time enrolment token for a cluster, valid for 15 minutes, which an operator install exchanges for its cluster credential on first start. The secret is returned exactly once. Minting a new token does not revoke an unspent earlier one until it expires. **Access:** admin of the owner team, or a platform admin. Other callers get NotFound.