# Service classification — the prior that derives a component's compute envelope, # QoS intent, stateful-ness, and preferred node placement. A component declares # `class` and optionally overrides `resources`/`placement`; consumers (render # pipeline, placement simulator) resolve effective values via `effective`. { # Coarse service taxonomy. Drives the default resource envelope and node affinity. # 'gateway is the non-compute case: a declarative resource (e.g. a Cilium Gateway # API object) with no pods — no resource envelope, no placement. ServiceClass = [| 'controller, 'web, 'app_server, 'cache, 'datastore, 'storage_engine, 'edge, 'gateway |], # Node role taxonomy. A component's class maps to the node classes it may run on. NodeClass = [| 'control_plane, 'general, 'storage, 'edge |], # Effective compute envelope — the complete output shape of `effective`. ResourceSpec = { cpu | { request | String, limit | String }, memory | { request | String, limit | String }, }, # Partial override a component may declare under `resources`. Any omitted field # falls back to the class default during resolution. ResourceOverride = { cpu | { request | String, limit | String } | optional, memory | { request | String, limit | String } | optional, }, # Runtime health probe. `type` selects the k8s probe handler; `port` defaults to # the component's first declared port when omitted by the renderer. ProbeSpec = { type | [| 'http, 'tcp, 'exec |] | doc "k8s probe handler" | default = 'http, path | String | doc "httpGet path (http type)" | default = "/", port | Number | optional, command | Array String | doc "exec command (exec type)" | default = [], initial_delay | Number | doc "initialDelaySeconds" | default = 30, period | Number | doc "periodSeconds" | default = 15, timeout | Number | doc "timeoutSeconds" | default = 5, failure_threshold | Number | doc "failureThreshold" | default = 3, }, # Placement policy. `mode` 'prefer = soft affinity (respects cost co-location); # 'require = hard nodeSelector. `spread` = anti-affinity across nodes. Placement = { node_class | Array NodeClass | optional, mode | [| 'prefer, 'require |] | doc "soft (prefer) vs hard (require) placement" | default = 'prefer, spread | Bool | doc "anti-affinity across nodes" | default = true, }, # Per-class default envelope. cpu/memory are k8s quantity strings; `qos` is the # intended QoS class (k8s derives actual QoS from request==limit); `stateful` # marks PVC-backed services; `node_class` is the preferred placement. class_default = fun class => class |> match { 'controller => { cpu = { request = "50m", limit = "200m" }, memory = { request = "64Mi", limit = "128Mi" }, qos = 'burstable, stateful = false, node_class = ['control_plane, 'general], }, 'web => { cpu = { request = "50m", limit = "500m" }, memory = { request = "128Mi", limit = "256Mi" }, qos = 'burstable, stateful = false, node_class = ['general], }, 'app_server => { cpu = { request = "100m", limit = "1000m" }, memory = { request = "384Mi", limit = "768Mi" }, qos = 'burstable, stateful = false, node_class = ['general], }, 'cache => { cpu = { request = "50m", limit = "500m" }, memory = { request = "64Mi", limit = "256Mi" }, qos = 'burstable, stateful = false, node_class = ['general, 'storage], }, 'datastore => { cpu = { request = "200m", limit = "1000m" }, memory = { request = "512Mi", limit = "1Gi" }, qos = 'burstable, stateful = true, node_class = ['storage], }, 'storage_engine => { cpu = { request = "100m", limit = "500m" }, memory = { request = "256Mi", limit = "512Mi" }, qos = 'guaranteed, stateful = true, node_class = ['storage], }, 'edge => { cpu = { request = "50m", limit = "500m" }, memory = { request = "64Mi", limit = "256Mi" }, qos = 'burstable, stateful = false, node_class = ['edge, 'general], }, 'gateway => { # Non-compute declarative resource (Gateway CR) — no pods, no footprint. cpu = { request = "0", limit = "0" }, memory = { request = "0", limit = "0" }, qos = 'besteffort, stateful = false, node_class = [], }, }, # Resolve effective resources + placement for a class with optional partial # overrides ({cpu?, memory?, node_class?}). Override fields win; the rest fall # back to the class default. Output conforms to ResourceSpec plus placement hints. effective = fun class override => let d = class_default class in { cpu = if std.record.has_field "cpu" override then override.cpu else d.cpu, memory = if std.record.has_field "memory" override then override.memory else d.memory, qos = d.qos, stateful = d.stateful, node_class = if std.record.has_field "node_class" override then override.node_class else d.node_class, }, }