Serve Nested Spec

3 min read

Nested Spec Paths

serve.fields.path

By default, serve.fields maps field names directly to top-level spec paths. Use path to map a field to a nested location in the CRD spec.

serve:
  fields:
    # Flat field — maps to spec.repository
    repository:
      label: "Repository"

    # Nested field — maps to spec.app.repository
    repository:
      path: app.repository
      label: "Repository"

    # Deeply nested — maps to spec.app.resources.cpu
    cpu:
      path: app.resources.cpu
      label: "CPU Request"

Callers submit flat field names — they don’t need to know about nesting. The gateway maps the field to the correct location in the CRD.

curl -X POST /api/v1/apply \
  -d '{
    "target": "smartapp",
    "repository": "myorg/payments-api",  # → spec.app.repository
    "cpu": "500m"                         # → spec.app.resources.cpu
  }'

Why Use path

Without pathWith path
Fields must match CRD structureFields are flat and caller-friendly
Callers must know nested pathsCallers submit simple field names
CRD evolution breaks callersGateway maps to new paths
UI fields show dot-pathsUI fields show clean names

Validation

ork validate enforces:

  • Unique paths — no two fields can map to the same spec location
  • Valid format — path segments must be valid Kubernetes names (alphanumeric, _, -, .)
  • No empty segmentsapp..repository is rejected
  • No leading/trailing dots.app.repository is rejected

Schema Validation (Not Yet Implemented)

Path existence in the CRD schema is not yet validated by ork validate. The platform team must verify that nested paths exist in the CRD spec. This will be added in a future release when OpenAPI schemas are loaded into the Katalog.

Example

CRD:

spec:
  app:
    repository: string
    image: string
    resources:
      cpu: string
      memory: string
  scaling:
    replicas: integer
    minReplicas: integer
    maxReplicas: integer

Serve Config:

serve:
  fields:
    repository:
      path: app.repository
      label: "Repository"
    image:
      path: app.image
      label: "Container Image"
    cpu:
      path: app.resources.cpu
      label: "CPU Request"
    memory:
      path: app.resources.memory
      label: "Memory Request"
    replicas:
      path: scaling.replicas
      label: "Replicas"

Caller Request:

{
  "target": "smartapp",
  "repository": "myorg/payments-api",
  "image": "ghcr.io/myorg/app:v1",
  "cpu": "500m",
  "memory": "512Mi",
  "replicas": 3
}

Generated CR:

spec:
  app:
    repository: myorg/payments-api
    image: ghcr.io/myorg/app:v1
    resources:
      cpu: 500m
      memory: 512Mi
  scaling:
    replicas: 3

serve.fields — field configuration reference

serve labels/annotations — labels and annotations as fields

Target Mode API — submitting fields instead of CRs


target.clusters

Scopes the apply fan-out for a specific named target or alias to a subset of serve.clusters. When absent, fan-out uses all of serve.clusters. Reads and lists always use the local cluster regardless of this setting.

serve:
  clusters:
    - prod
    - staging
    - eu-west
  target:
    prod-release:
      primary: true
      clusters:
        - prod              # restricts to prod only — staging and eu-west skipped
    canary:
      clusters:
        - '{{ if eq .request.region "eu" }}eu-west{{ else }}staging{{ end }}'

Every entry in target.clusters must appear in serve.clustersork validate rejects any name that is not declared there. Template expressions skip this check at validate time; the resolved name is validated against serve.clusters at apply time.

Value typeValidationResolution
Static nameChecked against gateway.clusters AND serve.clusters at ork validate timeLooked up in registry at apply time
Template expressionParse + function existence checked at ork validate timeResolved against intent fields at apply time
AbsentFan-out uses all of serve.clusters; falls back to local if that is also absent

serve.clusters — CRD-level routing whitelist and default fan-out
gateway.clusters — registering clusters
Multi-cluster routing — concept overview