Skip to content

API Reference

Every banlieue Custom Resource Definition, generated from the Rust types that are the schema's source of truth. Field descriptions are the rustdoc comments on those types.

banlieue.io

infrastructure.banlieue.io


Provider

API: banlieue.io/v1alpha1 · Kind: Provider · Scope: Namespaced · Short names: prov

Provider — one backend instance registered with banlieue.

A Provider represents a single place VMs can run: one vCenter, one Proxmox cluster, or one libvirt host. It carries the connection details and an admin-curated declaration of the storage classes, network classes, and features that backend exposes. Its controller logs in, verifies those capabilities, and publishes the reachable status.failureDomains[].

Why create one

  • Make a backend schedulable. A VirtualMachine can only be placed on a Provider — no Provider, nowhere to run.
  • Declare capabilities explicitly. spec.capabilities maps abstract class names (the ones VMClass / VMImage request) to concrete backend targets (a datastore, a port group). That mapping is the contract the scheduler matches against — capabilities are declared, not guessed.
  • Model many backends, including duplicates. A cluster can hold many Providers of the same class (prod-vsphere, dr-vsphere) and mix classes freely.

The provider's controller talks to the backend; banlieue's main controller never does. Communication between them is CRD-only.

Printer columns (kubectl get):

Name Type JSON path Priority
Class string .spec.providerClassRef.name 0
Endpoint string .spec.connection.endpoint 1
Ready string .status.conditions[?(@.type=='Ready')].status 0
Age date .metadata.creationTimestamp 0

.spec

Field Type Required Description
capabilities object Admin-defined capability mappings. Every storage / network class that VMClass and VMImage may request MUST be listed here for this provider to be considered by the scheduler.
connection object Yes Connection details for the backend.
failureDomainNameOverrides object[] Explicit overrides for individual discovered failure domains' generated name. The auto-computed, collision-safe name (<provider>-<datacenter>-<cluster>, hashed when too long) is always the fallback for any (datacenter, cluster) pair with no matching entry here — this is opt-in, never required. See ADR-0023.
paused boolean Suspend reconciliation. Equivalent to setting the cluster.x-k8s.io/paused annotation but in-band.
providerClassRef object Yes Reference to a ProviderClass that identifies the backend type.
useContentLibrary boolean vSphere only: import Url-kind VMImages through a vCenter Content Library rather than the default datastore-upload + MarkAsTemplate path. Defaults to false (no Content Library required), matching environments where CL is not enabled. Ignored by non-vSphere classes. See ADR-0020.

.spec.capabilities

Admin-defined capability mappings. Every storage / network class that VMClass and VMImage may request MUST be listed here for this provider to be considered by the scheduler.

Field Type Required Description
features string[] Feature flags admin asserts are available. Provider's controller may downgrade these in status if introspection finds otherwise. Well-known values: hotAddCPU, hotAddMemory, efiSecureBoot, nestedVirtualization, gpuPassthrough.
networkClasses object[] Network classes the admin asserts are available on this backend.
storageClasses object[] Storage classes the admin asserts are available on this backend. Each entry maps an abstract class name to a provider-interpreted concrete target.
.spec.capabilities.networkClasses[]

Network classes the admin asserts are available on this backend.

Field Type Required Description
name string Yes Abstract name referenced by VMClass.network.interfaces[].networkClass.
perZone object[] Per-(datacenter, cluster) overrides of target (ADR-0030).
perZoneSubnet object[] Per-(datacenter, cluster) overrides of subnet (ADR-0032).
subnet object Default subnet shape (gateway/nameservers/domain) for this network class, used in any zone per_zone_subnet does not cover. A port group implies a subnet, so this lives alongside target/per_zone rather than on VMClass — it lets a static-addressing VirtualMachine omit gateway/nameservers/domain entirely and have them resolved from whichever zone the scheduler picked (ADR-0032).
target map[string]string Default concrete target, used in any zone per_zone does not cover. None means this class resolves ONLY in the zones per_zone lists. Free-form per provider class. Examples: vsphere: { portGroup: "vmnet-prod" } { distributedPortGroup: "dvs-prod-vlan100" } proxmox: { bridge: "vmbr0", vlan: "100" } libvirt: { network: "br-prod" }
.spec.capabilities.networkClasses[].perZone[]

Per-(datacenter, cluster) overrides of target (ADR-0030).

Field Type Required Description
cluster string Yes Cluster name as vCenter reports it.
datacenter string Yes Datacenter name as vCenter reports it.
target map[string]string Yes Concrete backend target for this zone, same shape as [StorageClassMapping::target] / [NetworkClassMapping::target].
.spec.capabilities.networkClasses[].perZoneSubnet[]

Per-(datacenter, cluster) overrides of subnet (ADR-0032).

Field Type Required Description
cluster string Yes Cluster name as vCenter reports it.
datacenter string Yes Datacenter name as vCenter reports it.
subnet object Yes Subnet shape for this zone.
# .spec.capabilities.networkClasses[].perZoneSubnet[].subnet

Subnet shape for this zone.

Field Type Required Description
domain string
gateway string
nameservers string[]
.spec.capabilities.networkClasses[].subnet

Default subnet shape (gateway/nameservers/domain) for this network class, used in any zone per_zone_subnet does not cover. A port group implies a subnet, so this lives alongside target/per_zone rather than on VMClass — it lets a static-addressing VirtualMachine omit gateway/nameservers/domain entirely and have them resolved from whichever zone the scheduler picked (ADR-0032).

Field Type Required Description
domain string
gateway string
nameservers string[]
.spec.capabilities.storageClasses[]

Storage classes the admin asserts are available on this backend. Each entry maps an abstract class name to a provider-interpreted concrete target.

Field Type Required Description
name string Yes Abstract name referenced by VMClass.hardware.disks[].storageClass.
perZone object[] Per-(datacenter, cluster) overrides of target (ADR-0030).
target map[string]string Default concrete target, used in any zone per_zone does not cover. None means this class resolves ONLY in the zones per_zone lists. Free-form per provider class; the provider's controller interprets it. Examples by provider class: vsphere: { datastore: "ds-fast-01" } { datastoreCluster: "dsc-gold" } { tagCategory: "tier", tag: "gold" } proxmox: { storage: "ceph-pool-1" } libvirt: { pool: "nvme-pool" }
.spec.capabilities.storageClasses[].perZone[]

Per-(datacenter, cluster) overrides of target (ADR-0030).

Field Type Required Description
cluster string Yes Cluster name as vCenter reports it.
datacenter string Yes Datacenter name as vCenter reports it.
target map[string]string Yes Concrete backend target for this zone, same shape as [StorageClassMapping::target] / [NetworkClassMapping::target].

.spec.connection

Connection details for the backend.

Field Type Required Description
caBundle object Optional CA bundle to validate the endpoint's TLS certificate.
credentialsRef object Yes Reference to a Secret in the Provider's namespace containing the credentials. Required keys depend on provider class: vsphere: username, password proxmox: username (root@pam!token-id), tokenValue OR username, password libvirt: optional sshPrivateKey for SSH transports
endpoint string Yes Endpoint URL or URI. Format depends on provider class: vsphere: https://vcenter.example.com/sdk proxmox: https://pve.example.com:8006 libvirt: qemu+ssh://kvm-host.example.com/system
insecureSkipTLSVerify boolean Skip TLS verification. Applies to vsphere and proxmox.
.spec.connection.caBundle

Optional CA bundle to validate the endpoint's TLS certificate.

A value-or-source: inline PEM, or a configMapRef / secretRef naming a key (default ca.crt) in the Provider's namespace. Exactly one source must be set; see [CABundleSource]. Resolved by the provider controller and injected into the HTTP client (ADR-0008, BYOC). When unset, the system trust roots are used.

Field Type Required Description
configMapRef object Key in a ConfigMap in the referrer's namespace (key defaults to ca.crt).
inline string Inline PEM (one or more concatenated certificates).
secretRef object Key in a Secret in the referrer's namespace (key defaults to ca.crt).
.spec.connection.caBundle.configMapRef

Key in a ConfigMap in the referrer's namespace (key defaults to ca.crt).

Field Type Required Description
key string Key within the object's data. Defaults are caller-defined.
name string Yes Name of the ConfigMap / Secret in the referrer's namespace.
.spec.connection.caBundle.secretRef

Key in a Secret in the referrer's namespace (key defaults to ca.crt).

Field Type Required Description
key string Key within the object's data. Defaults are caller-defined.
name string Yes Name of the ConfigMap / Secret in the referrer's namespace.
.spec.connection.credentialsRef

Reference to a Secret in the Provider's namespace containing the credentials. Required keys depend on provider class: vsphere: username, password proxmox: username (root@pam!token-id), tokenValue OR username, password libvirt: optional sshPrivateKey for SSH transports

Field Type Required Description
name string Yes

.spec.failureDomainNameOverrides[]

Explicit overrides for individual discovered failure domains' generated name. The auto-computed, collision-safe name (<provider>-<datacenter>-<cluster>, hashed when too long) is always the fallback for any (datacenter, cluster) pair with no matching entry here — this is opt-in, never required. See ADR-0023.

Field Type Required Description
cluster string Yes Cluster name as vCenter reports it.
datacenter string Yes Datacenter name as vCenter reports it (matches discover_inventory's walk, not an operator-chosen alias).
name string Yes The name to use instead of the auto-computed one, e.g. cluster-01. Slugified the same way auto-computed names are, so Cluster 01 still produces a valid Kubernetes name.

.spec.providerClassRef

Reference to a ProviderClass that identifies the backend type.

For v1alpha1 the ProviderClass CRD is deferred; treat this as a name drawn from a well-known set: vsphere, proxmox, libvirt. A future ProviderClass CRD will provide install metadata (image, RBAC) without changing this reference.

Field Type Required Description
name string Yes

.status

Observed state of a Provider: the failure domains its controller discovered and the health / reachability conditions.

Field Type Required Description
conditions object[] Standard Kubernetes conditions. The Ready condition reflects overall provider health. The ProviderReachable condition reflects connection state to the backend.
failureDomains object[] Failure domains ("availability zones" — the terms are synonyms; failureDomain was kept to align with CAPI v1beta2's own vocabulary) discovered by the provider's controller within this backend. The scheduler matches against labels and filters by attributes.availableStorageClasses / availableNetworkClasses.
observedGeneration integer The generation of the spec that the controller has reconciled.
workload object The provider workload banlieue-operator created for this Provider.

.status.conditions[]

Standard Kubernetes conditions. The Ready condition reflects overall provider health. The ProviderReachable condition reflects connection state to the backend.

Field Type Required Description
lastTransitionTime string Yes lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string Yes message is a human readable message indicating details about the transition. This may be an empty string.
observedGeneration integer observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
reason string Yes reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string Yes status of the condition, one of True, False, Unknown.
type string Yes type of condition in CamelCase or in foo.example.com/CamelCase.

.status.failureDomains[]

Failure domains ("availability zones" — the terms are synonyms; failureDomain was kept to align with CAPI v1beta2's own vocabulary) discovered by the provider's controller within this backend. The scheduler matches against labels and filters by attributes.availableStorageClasses / availableNetworkClasses.

Field Type Required Description
attributes object Attributes the provider's controller resolved for this domain, including the subset of admin-listed classes that are actually reachable from here.
labels map[string]string Labels used by the scheduler's failureDomainSelector and by VirtualMachine anti-affinity topologyKey matching. Recommended keys: datacenter, cluster, rack, env. Every provider also sets name to this failure domain's own resolved name above (auto-computed, or an ADR-0023 override) — name above is a top-level field a LabelSelector cannot match directly, so without this mirror, targeting a specific zone by its friendly override name (rather than a raw backend-reported label like cluster) would be impossible.
name string Yes Stable name. Conventionally <provider>-<cluster-or-zone>.
.status.failureDomains[].attributes

Attributes the provider's controller resolved for this domain, including the subset of admin-listed classes that are actually reachable from here.

Field Type Required Description
availableNetworkClasses string[] Subset of spec.capabilities.networkClasses[].name reachable here.
availableStorageClasses string[] Subset of spec.capabilities.storageClasses[].name reachable here.
features string[] Feature flags actually present here. Always a subset of spec.capabilities.features.
raw map[string]string Provider-specific resolved attributes; for vSphere this typically includes datacenter, cluster, resourcePool. Used by the provider's controller when filling in the infrastructure CR.

.status.workload

The provider workload banlieue-operator created for this Provider.

Written only by the operator's field manager (banlieue.io/operator); the provider's own controller never touches it. This split is deliberate: conditions is a plain list with no x-kubernetes-list-type: map marker, so two field managers writing into it would contend over the whole array rather than merging per entry. Giving the operator a disjoint field keeps server-side apply conflict-free (ADR-0012).

Field Type Required Description
deploymentName string Yes Name of the Deployment running this Provider's controller. Conventionally banlieue-provider-<class>-<provider-name>.
namespace string Yes Namespace the Deployment was created in — the ProviderClass's workloadNamespace, or the operator's own namespace when unset.
observedGeneration integer The Provider generation the operator had observed when it last applied this workload.
readyReplicas integer Yes Ready replicas reported by that Deployment. Zero means the backend's controller is not currently running, whatever the Provider's other conditions say.

ProviderClass

API: banlieue.io/v1alpha1 · Kind: ProviderClass · Scope: Cluster · Short names: pc

ProviderClass — what banlieue runs for a class of backends.

A ProviderClass carries the install metadata for one backend type: which banlieue provider <backend> role to run, from which image, with what pod shape and extra permissions. It names no endpoint and holds no credentials — that is a Provider's job.

Why create one

  • Make backends self-provisioning. With a ProviderClass in place, registering a backend is kubectl apply of a Provider CR: banlieue-operator creates that Provider's Deployment, ServiceAccount, Role and RoleBinding for you. No manifest editing, no helm values.
  • Decide the image once. Every Provider of this class runs the image pinned here, so upgrading a fleet of backends is a one-object edit instead of one edit per backend.
  • Separate the two jobs. Deciding what banlieue runs (a platform owner, cluster-scoped) is not the same as registering a vCenter (a backend admin, namespaced) — different people, different privileges.

How it is used

Provider.spec.providerClassRef.name points at a ProviderClass by name. The operator resolves it, then applies one workload set per Provider, each owned by its Provider CR so deleting the Provider garbage-collects the workload. Each spawned pod runs a server-side filtered watch scoped to its own Provider, so one hung backend cannot stall another (ADR-0003).

Cluster-scoped: one ProviderClass serves Providers in any namespace.

Printer columns (kubectl get):

Name Type JSON path Priority
Backend string .spec.backend 0
Image string .spec.image.tag 0
Providers integer .status.providers 0
Ready string .status.conditions[?(@.type=='Ready')].status 0
Age date .metadata.creationTimestamp 0

.spec

Field Type Required Description
additionalRules object[] Extra RBAC rules appended to the per-instance Role the operator generates for each Provider of this class.
backend string Yes Which provider backend this class instantiates — the banlieue provider <backend> subcommand spawned Deployments run.
image object Yes Container image every provider workload of this class runs.
logging object Log level and format passed to spawned workloads.
nodeSelector map[string]string Node selector applied to provider pods. Useful when backend access is only routable from particular nodes.
paused boolean Suspend lifecycle reconciliation for every Provider of this class. Existing workloads are left running untouched.
replicas integer Replicas for each provider Deployment. Defaults to [DEFAULT_PROVIDER_REPLICAS]. Provider controllers are leader-elected, so values above one provide failover, not parallelism.
resources object Resource requests and limits for the provider container. When unset the operator applies its own conservative defaults.
tolerations object[] Tolerations applied to provider pods.
workloadNamespace string Namespace to create provider workloads in.

.spec.additionalRules[]

Extra RBAC rules appended to the per-instance Role the operator generates for each Provider of this class.

Note that Kubernetes forbids granting permissions the grantor does not itself hold: a rule listed here also has to be present in the operator's own ClusterRole, or the RoleBinding is rejected (ADR-0012).

Field Type Required Description
apiGroups string[] APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups.
nonResourceURLs string[] NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both.
resourceNames string[] ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.
resources string[] Resources is a list of resources this rule applies to. '*' represents all resources.
verbs string[] Yes Verbs is a list of Verbs that apply to ALL the ResourceKinds contained in this rule. '*' represents all verbs.

.spec.image

Container image every provider workload of this class runs.

Field Type Required Description
digest string Image digest, e.g. sha256:0f756fa0…. When set it is what actually gets pulled, and any tag becomes documentation of intent.
pullPolicy string Image pull policy, spelled exactly as Kubernetes spells it. Allowed: Always, IfNotPresent, Never.
pullSecrets object[] Secrets used to pull the image, for private or mirrored registries.
repository string Yes Image repository without a tag, e.g. ghcr.io/firestoned/banlieue.
tag string Yes Image tag, e.g. v0.1.0. Never use latest in production — a mutable tag makes the running version unknowable and defeats rollback.
.spec.image.pullSecrets[]

Secrets used to pull the image, for private or mirrored registries.

Field Type Required Description
name string Yes

.spec.logging

Log level and format passed to spawned workloads.

Field Type Required Description
format string Log format: json for SIEM-friendly structured output, anything else for the human-readable text formatter.
level string Log level, e.g. info or debug,kube=warn. Passed through as the workload's log-level flag.

.spec.resources

Resource requests and limits for the provider container. When unset the operator applies its own conservative defaults.

Field Type Required Description
claims object[] Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container.
limits map[string]object Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
requests map[string]object Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
.spec.resources.claims[]

Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container.

This field depends on the DynamicResourceAllocation feature gate.

This field is immutable. It can only be set for containers.

Field Type Required Description
name string Yes Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container.
request string Request is the name chosen for a request in the referenced claim. If empty, everything from the claim is made available, otherwise only the result of this request.

.spec.tolerations[]

Tolerations applied to provider pods.

Field Type Required Description
effect string Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
key string Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys.
operator string Operator represents a key's relationship to the value. Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
tolerationSeconds integer TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system.
value string Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string.

.status

Observed state of a ProviderClass.

Field Type Required Description
conditions object[] Standard Kubernetes conditions. Ready reflects whether the class is usable: its backend is compiled into the running operator and its image reference is well-formed.
observedGeneration integer The generation of the spec the operator has reconciled.
providers integer Number of Provider CRs currently referencing this class.

.status.conditions[]

Standard Kubernetes conditions. Ready reflects whether the class is usable: its backend is compiled into the running operator and its image reference is well-formed.

Field Type Required Description
lastTransitionTime string Yes lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string Yes message is a human readable message indicating details about the transition. This may be an empty string.
observedGeneration integer observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
reason string Yes reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string Yes status of the condition, one of True, False, Unknown.
type string Yes type of condition in CamelCase or in foo.example.com/CamelCase.

VirtualMachine

API: banlieue.io/v1alpha1 · Kind: VirtualMachine · Scope: Namespaced · Short names: vm

VirtualMachine — the user-facing request for a running VM.

This is the one resource end users create. It expresses intent: which VMClass (shape) and VMImage (OS) to use, optional placement constraints, the desired power state, and optional guest user-data. banlieue's controller schedules it onto a Provider + failure domain, creates the matching provider infrastructure CR (e.g. VSphereMachine), and mirrors that CR's status back here.

Why create one

  • Declare a VM the Kubernetes way. Describe the VM you want; the controller reconciles reality toward it, including power state.
  • Stay backend-agnostic. You reference a class and an image by name, not a datastore or a port group. Where it lands is the scheduler's job.
  • Compose with policy. Label / anti-affinity selectors and a migration policy steer placement and drift handling without coupling to a specific Provider.

Independent of Cluster API: a VirtualMachine is not a clusterv1. Machine. It can coexist with CAPI but does not depend on it.

Namespaced: candidate Providers are drawn from the VM's own namespace.

Printer columns (kubectl get):

Name Type JSON path Priority
Class string .spec.classRef.name 0
Image string .spec.imageRef.name 0
Provider string .status.scheduled.providerName 0
FailureDomain string .status.scheduled.failureDomain 1
Power string .status.observedPowerState 0
Ready string .status.conditions[?(@.type=='Ready')].status 0
Age date .metadata.creationTimestamp 0

.spec

Field Type Required Description
classRef object Yes Reference to a (cluster-scoped) VMClass.
desiredPowerState string Desired power state. Defaults to PoweredOn. Allowed: PoweredOn, PoweredOff, Suspended.
folder string Destination folder for the provisioned VM (e.g. apps/prod on vSphere). When unset, the provider defaults to organizing the VM the same way it organizes its source template — on vSphere, the same per-zone folder the template lives in (ADR-0020 Decision #5).
hardwareOverride object Per-VM override for the VMClass's hardware shape — CPUs, memory, and disk sizes.
imageRef object Yes Reference to a (cluster-scoped) VMImage.
migrationPolicy string What to do when current placement no longer satisfies the spec. Allowed: automatic, manual, never.
networkOverrides object[] Per-VM overrides for specific VMClass-declared network interfaces (ADR-0024). Keyed by NetworkInterfaceSpec.name; an interface with no entry here uses its VMClass's own ipam verbatim (commonly dhcp). Lets many VMs share one VMClass while each still gets its own static address — a VMClass-level ipam.static cannot express that, since a class is shared by design.
paused boolean Suspend reconciliation in-band.
placement object Placement intent. If unset, the scheduler considers every Provider in the VM's namespace and every failure domain.
userData object Optional user-data delivered to the guest via the image's guestAgent (cloud-init / ignition / sysprep).

.spec.classRef

Reference to a (cluster-scoped) VMClass.

Field Type Required Description
name string Yes

.spec.hardwareOverride

Per-VM override for the VMClass's hardware shape — CPUs, memory, and disk sizes.

This is a delta, not the primary definition. The VMClass is the authoritative source for a VM's hardware shape: its spec.hardware is fixed and shared by every VM that references the class. This field applies on top of the class — only the fields you set here replace the class value; everything else is inherited verbatim.

Use this sparingly. Its primary purpose is to accommodate the rare VM that genuinely needs a different CPU, memory, or disk budget than its class defines — for example, a database primary bumped to 16 CPUs while all other replicas use the 4-CPU class shape, or one VM that needs a larger data disk. If you find yourself setting the same override on every VM of a given class, create a new VMClass instead.

Field Type Required Description
cpus integer Override the VMClass's spec.hardware.cpus. If absent, the class value is used unchanged.
diskOverrides object[] Per-disk size overrides, keyed by DiskSpec.name. Only sizeGiB can be overridden per VM; the disk's storageClass and provisioning are class-level concerns.
memoryMiB integer Override the VMClass's spec.hardware.memoryMiB. If absent, the class value is used unchanged.
.spec.hardwareOverride.diskOverrides[]

Per-disk size overrides, keyed by DiskSpec.name. Only sizeGiB can be overridden per VM; the disk's storageClass and provisioning are class-level concerns.

This is a delta, not the primary definition. A disk with no entry here inherits the VMClass's size verbatim.

Field Type Required Description
name string Yes Matches a VMClass.spec.hardware.disks[].name.
sizeGiB integer Yes Override the disk's sizeGiB. Must be ≥ the class value (the provider will reject a shrink). If absent, the class size is used.

.spec.imageRef

Reference to a (cluster-scoped) VMImage.

Field Type Required Description
name string Yes

.spec.networkOverrides[]

Per-VM overrides for specific VMClass-declared network interfaces (ADR-0024). Keyed by NetworkInterfaceSpec.name; an interface with no entry here uses its VMClass's own ipam verbatim (commonly dhcp). Lets many VMs share one VMClass while each still gets its own static address — a VMClass-level ipam.static cannot express that, since a class is shared by design.

This is a delta, not the primary definition. The VMClass is the authoritative source for the VM's network shape. Entries here are layered on top: only the named interface's ipam is replaced; every other interface is inherited from the class unchanged.

Field Type Required Description
name string Yes Matches a VMClass.spec.network.interfaces[].name.
static object Yes The static address to use for this interface, overriding whatever the VMClass's own ipam declares.
.spec.networkOverrides[].static

The static address to use for this interface, overriding whatever the VMClass's own ipam declares.

Field Type Required Description
address string Yes
domain string DNS domain, used both as a DNS search domain and (by a VirtualMachine.spec.networkOverrides consumer, ADR-0024) to build an FQDN as <vm-name>.<domain>.
gateway string
nameservers string[]
prefix integer Yes

.spec.placement

Placement intent. If unset, the scheduler considers every Provider in the VM's namespace and every failure domain.

Field Type Required Description
antiAffinity object[] Anti-affinity rules against other VirtualMachines in the same namespace. Evaluated at scheduling time.
failureDomainSelector object Match failure domains by their status.failureDomains[].labels. Across all candidate Providers, only failure domains whose labels match are considered.
providerSelector object Match Providers by their metadata.labels. A Provider is a candidate only if its labels match this selector.
.spec.placement.antiAffinity[]

Anti-affinity rules against other VirtualMachines in the same namespace. Evaluated at scheduling time.

Field Type Required Description
labelSelector object Yes Other VMs (by their own metadata.labels) to spread away from.
mode string Strictness. required filters candidates; preferred is best-effort. Allowed: required, preferred.
topologyKey string Yes A label key from the failure domain's labels. Spreading is required across distinct values of this key. Common keys: cluster, rack, host, dc.
.spec.placement.antiAffinity[].labelSelector

Other VMs (by their own metadata.labels) to spread away from.

Field Type Required Description
matchExpressions object[]
matchLabels map[string]string
# .spec.placement.antiAffinity[].labelSelector.matchExpressions[]
Field Type Required Description
key string Yes
operator string Yes Allowed: In, NotIn, Exists, DoesNotExist.
values string[]
.spec.placement.failureDomainSelector

Match failure domains by their status.failureDomains[].labels. Across all candidate Providers, only failure domains whose labels match are considered.

Field Type Required Description
matchExpressions object[]
matchLabels map[string]string
.spec.placement.failureDomainSelector.matchExpressions[]
Field Type Required Description
key string Yes
operator string Yes Allowed: In, NotIn, Exists, DoesNotExist.
values string[]
.spec.placement.providerSelector

Match Providers by their metadata.labels. A Provider is a candidate only if its labels match this selector.

Field Type Required Description
matchExpressions object[]
matchLabels map[string]string
.spec.placement.providerSelector.matchExpressions[]
Field Type Required Description
key string Yes
operator string Yes Allowed: In, NotIn, Exists, DoesNotExist.
values string[]

.spec.userData

Optional user-data delivered to the guest via the image's guestAgent (cloud-init / ignition / sysprep).

Field Type Required Description
configMapRef object Key in a ConfigMap in the VirtualMachine's namespace (key defaults to [DEFAULT_USER_DATA_KEY]).
secretRef object Key in a Secret in the VirtualMachine's namespace (key defaults to [DEFAULT_USER_DATA_KEY]).
.spec.userData.configMapRef

Key in a ConfigMap in the VirtualMachine's namespace (key defaults to [DEFAULT_USER_DATA_KEY]).

Field Type Required Description
key string Key within the object's data. Defaults are caller-defined.
name string Yes Name of the ConfigMap / Secret in the referrer's namespace.
.spec.userData.secretRef

Key in a Secret in the VirtualMachine's namespace (key defaults to [DEFAULT_USER_DATA_KEY]).

Field Type Required Description
key string Key within the object's data. Defaults are caller-defined.
name string Yes Name of the ConfigMap / Secret in the referrer's namespace.

.status

Observed state of a VirtualMachine: the scheduling decision, the infra CR it owns, mirrored provisioning / address / power state, and conditions.

Field Type Required Description
addresses object[] Mirrored from the infra CR's status.addresses.
conditions object[] Standard Kubernetes conditions. Required types: Ready — overall readiness Scheduled — placement decision exists and is current PlacementValid — current placement satisfies the spec InfrastructureReady — mirrors the infra CR's Ready condition Optional: Migrating — true while a migration is in progress
infrastructureRef object Reference to the provider-specific infrastructure CR (e.g. infrastructure.banlieue.io/v1alpha1/VSphereMachine). Set after scheduling, owned by this VirtualMachine.
initialization object Mirrored from the infra CR's status.initialization.
observedGeneration integer
observedPowerState string Observed power state from the provider. Allowed: PoweredOn, PoweredOff, Suspended, null.
scheduled object Current scheduling decision. Absent until first successful schedule.

.status.addresses[]

Mirrored from the infra CR's status.addresses.

Field Type Required Description
address string Yes The address itself.
type string Yes Address type. Accepted: Hostname, ExternalIP, InternalIP, ExternalDNS, InternalDNS. Allowed: Hostname, ExternalIP, InternalIP, ExternalDNS, InternalDNS.

.status.conditions[]

Standard Kubernetes conditions. Required types: Ready — overall readiness Scheduled — placement decision exists and is current PlacementValid — current placement satisfies the spec InfrastructureReady — mirrors the infra CR's Ready condition Optional: Migrating — true while a migration is in progress

Field Type Required Description
lastTransitionTime string Yes lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string Yes message is a human readable message indicating details about the transition. This may be an empty string.
observedGeneration integer observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
reason string Yes reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string Yes status of the condition, one of True, False, Unknown.
type string Yes type of condition in CamelCase or in foo.example.com/CamelCase.

.status.infrastructureRef

Reference to the provider-specific infrastructure CR (e.g. infrastructure.banlieue.io/v1alpha1/VSphereMachine). Set after scheduling, owned by this VirtualMachine.

Field Type Required Description
apiGroup string Yes
kind string Yes
name string Yes
namespace string

.status.initialization

Mirrored from the infra CR's status.initialization.

Field Type Required Description
provisioned boolean True when the infrastructure provider reports that the resource's infrastructure is fully provisioned.

.status.scheduled

Current scheduling decision. Absent until first successful schedule.

Field Type Required Description
failureDomain string Yes Failure domain name (one of the Provider's status.failureDomains[].name).
providerClass string Yes Provider's ProviderClass (denormalized for convenience in printer columns).
providerName string Yes Provider name (in the VM's namespace).
resolvedNetworks object[] Resolved network class → concrete backend identifier mappings.
resolvedStorage object[] Resolved storage class → concrete backend identifier mappings.
scheduledAt string Time the placement decision was made.
.status.scheduled.resolvedNetworks[]

Resolved network class → concrete backend identifier mappings.

Field Type Required Description
backendId string Yes Backend identifier the provider resolved to (e.g. "ds-fast-01", "vmnet-prod").
className string Yes Class name as referenced in the VMClass (e.g. "gold", "prod").
.status.scheduled.resolvedStorage[]

Resolved storage class → concrete backend identifier mappings.

Field Type Required Description
backendId string Yes Backend identifier the provider resolved to (e.g. "ds-fast-01", "vmnet-prod").
className string Yes Class name as referenced in the VMClass (e.g. "gold", "prod").

VirtualMachinePool

API: banlieue.io/v1alpha1 · Kind: VirtualMachinePool · Scope: Namespaced · Short names: vmpool

VirtualMachinePool: a self-refilling set of warm, single-use VMs.

Why create one

  • Hide install latency. A tpmEnabled class must pair with an installMode: Deferred image, so every VM pays a full install on first boot. The pool pays that ahead of time.
  • Single use by construction. Members are handed out through VirtualMachineClaim and destroyed when the claim ends. There is no code path that returns a used member to the warm set.
  • Follow the image. When the referenced VMImage is rebuilt, warm members from the old build are replaced surge-style without dropping claimable capacity.

Namespaced: members are created in the pool's own namespace, which is also where the scheduler looks for candidate Providers.

Printer columns (kubectl get):

Name Type JSON path Priority
Warm integer .spec.warmReplicas 0
Available integer .status.available 0
Provisioning integer .status.provisioning 0
Claimed integer .status.claimed 0
Age date .metadata.creationTimestamp 0

.spec

Field Type Required Description
addressing object Per-member static addressing. Omit for DHCP or class-level IPAM. Interim until the CAPI IPAM contract lands (ADR-0033); at that point this gains a poolRef alternative and the inline range stays as the zero-dependency option.
maxIdleSeconds integer Replace a Ready member that has sat unclaimed this long. Bounds how stale an unpatched warm VM can get between image rebuilds.
maxReplicas integer Yes Hard ceiling on members of any phase, claimed ones included. Leave headroom above warmReplicas plus expected concurrent claims, or image rollouts have to trade warm capacity for replacements.
maxSurge integer Most members allowed to be provisioning at once. Bounds the install load a refill puts on the hosts that claimed members are running on.
provisioningTimeoutSeconds integer A member still provisioning after this long is treated as poisoned and deleted, never repaired.
readiness string Yes Which member condition makes it claimable. See [PoolReadiness]. Allowed: GuestReady, InfrastructureReady.
recycleOnImageChange boolean Replace warm members when the referenced VMImage's build changes.
template object Yes Template for each member. spec.networkOverrides entries for the interface named in addressing are replaced per member; everything else is copied verbatim.
warmReplicas integer Yes How many Ready, unclaimed members to keep available.

.spec.addressing

Per-member static addressing. Omit for DHCP or class-level IPAM. Interim until the CAPI IPAM contract lands (ADR-0033); at that point this gains a poolRef alternative and the inline range stays as the zero-dependency option.

Field Type Required Description
domain string
gateway string
interface string Yes Name of the VMClass network interface to stamp, matching NetworkInterfaceOverride.name.
nameservers string[]
prefix integer Yes
rangeEnd string Yes Last address of the inclusive range. Size it at maxReplicas plus a few spares: an address stays held until a deleted member's backend VM is actually gone.
rangeStart string Yes First address of the inclusive range.

.spec.template

Template for each member. spec.networkOverrides entries for the interface named in addressing are replaced per member; everything else is copied verbatim.

Field Type Required Description
annotations map[string]string Extra annotations stamped on each member.
labels map[string]string Extra labels stamped on each member, in addition to the pool's own.
spec object Yes VirtualMachine — the user-facing request for a running VM.
.spec.template.spec

VirtualMachine — the user-facing request for a running VM.

This is the one resource end users create. It expresses intent: which VMClass (shape) and VMImage (OS) to use, optional placement constraints, the desired power state, and optional guest user-data. banlieue's controller schedules it onto a Provider + failure domain, creates the matching provider infrastructure CR (e.g. VSphereMachine), and mirrors that CR's status back here.

Why create one

  • Declare a VM the Kubernetes way. Describe the VM you want; the controller reconciles reality toward it, including power state.
  • Stay backend-agnostic. You reference a class and an image by name, not a datastore or a port group. Where it lands is the scheduler's job.
  • Compose with policy. Label / anti-affinity selectors and a migration policy steer placement and drift handling without coupling to a specific Provider.

Independent of Cluster API: a VirtualMachine is not a clusterv1. Machine. It can coexist with CAPI but does not depend on it.

Namespaced: candidate Providers are drawn from the VM's own namespace.

Field Type Required Description
classRef object Yes Reference to a (cluster-scoped) VMClass.
desiredPowerState string Desired power state. Defaults to PoweredOn. Allowed: PoweredOn, PoweredOff, Suspended.
folder string Destination folder for the provisioned VM (e.g. apps/prod on vSphere). When unset, the provider defaults to organizing the VM the same way it organizes its source template — on vSphere, the same per-zone folder the template lives in (ADR-0020 Decision #5).
hardwareOverride object Per-VM override for the VMClass's hardware shape — CPUs, memory, and disk sizes.
imageRef object Yes Reference to a (cluster-scoped) VMImage.
migrationPolicy string What to do when current placement no longer satisfies the spec. Allowed: automatic, manual, never.
networkOverrides object[] Per-VM overrides for specific VMClass-declared network interfaces (ADR-0024). Keyed by NetworkInterfaceSpec.name; an interface with no entry here uses its VMClass's own ipam verbatim (commonly dhcp). Lets many VMs share one VMClass while each still gets its own static address — a VMClass-level ipam.static cannot express that, since a class is shared by design.
paused boolean Suspend reconciliation in-band.
placement object Placement intent. If unset, the scheduler considers every Provider in the VM's namespace and every failure domain.
userData object Optional user-data delivered to the guest via the image's guestAgent (cloud-init / ignition / sysprep).
.spec.template.spec.classRef

Reference to a (cluster-scoped) VMClass.

Field Type Required Description
name string Yes
.spec.template.spec.hardwareOverride

Per-VM override for the VMClass's hardware shape — CPUs, memory, and disk sizes.

This is a delta, not the primary definition. The VMClass is the authoritative source for a VM's hardware shape: its spec.hardware is fixed and shared by every VM that references the class. This field applies on top of the class — only the fields you set here replace the class value; everything else is inherited verbatim.

Use this sparingly. Its primary purpose is to accommodate the rare VM that genuinely needs a different CPU, memory, or disk budget than its class defines — for example, a database primary bumped to 16 CPUs while all other replicas use the 4-CPU class shape, or one VM that needs a larger data disk. If you find yourself setting the same override on every VM of a given class, create a new VMClass instead.

Field Type Required Description
cpus integer Override the VMClass's spec.hardware.cpus. If absent, the class value is used unchanged.
diskOverrides object[] Per-disk size overrides, keyed by DiskSpec.name. Only sizeGiB can be overridden per VM; the disk's storageClass and provisioning are class-level concerns.
memoryMiB integer Override the VMClass's spec.hardware.memoryMiB. If absent, the class value is used unchanged.
# .spec.template.spec.hardwareOverride.diskOverrides[]

Per-disk size overrides, keyed by DiskSpec.name. Only sizeGiB can be overridden per VM; the disk's storageClass and provisioning are class-level concerns.

This is a delta, not the primary definition. A disk with no entry here inherits the VMClass's size verbatim.

Field Type Required Description
name string Yes Matches a VMClass.spec.hardware.disks[].name.
sizeGiB integer Yes Override the disk's sizeGiB. Must be ≥ the class value (the provider will reject a shrink). If absent, the class size is used.
.spec.template.spec.imageRef

Reference to a (cluster-scoped) VMImage.

Field Type Required Description
name string Yes
.spec.template.spec.networkOverrides[]

Per-VM overrides for specific VMClass-declared network interfaces (ADR-0024). Keyed by NetworkInterfaceSpec.name; an interface with no entry here uses its VMClass's own ipam verbatim (commonly dhcp). Lets many VMs share one VMClass while each still gets its own static address — a VMClass-level ipam.static cannot express that, since a class is shared by design.

This is a delta, not the primary definition. The VMClass is the authoritative source for the VM's network shape. Entries here are layered on top: only the named interface's ipam is replaced; every other interface is inherited from the class unchanged.

Field Type Required Description
name string Yes Matches a VMClass.spec.network.interfaces[].name.
static object Yes The static address to use for this interface, overriding whatever the VMClass's own ipam declares.
# .spec.template.spec.networkOverrides[].static

The static address to use for this interface, overriding whatever the VMClass's own ipam declares.

Field Type Required Description
address string Yes
domain string DNS domain, used both as a DNS search domain and (by a VirtualMachine.spec.networkOverrides consumer, ADR-0024) to build an FQDN as <vm-name>.<domain>.
gateway string
nameservers string[]
prefix integer Yes
.spec.template.spec.placement

Placement intent. If unset, the scheduler considers every Provider in the VM's namespace and every failure domain.

Field Type Required Description
antiAffinity object[] Anti-affinity rules against other VirtualMachines in the same namespace. Evaluated at scheduling time.
failureDomainSelector object Match failure domains by their status.failureDomains[].labels. Across all candidate Providers, only failure domains whose labels match are considered.
providerSelector object Match Providers by their metadata.labels. A Provider is a candidate only if its labels match this selector.
# .spec.template.spec.placement.antiAffinity[]

Anti-affinity rules against other VirtualMachines in the same namespace. Evaluated at scheduling time.

Field Type Required Description
labelSelector object Yes Other VMs (by their own metadata.labels) to spread away from.
mode string Strictness. required filters candidates; preferred is best-effort. Allowed: required, preferred.
topologyKey string Yes A label key from the failure domain's labels. Spreading is required across distinct values of this key. Common keys: cluster, rack, host, dc.
## .spec.template.spec.placement.antiAffinity[].labelSelector

Other VMs (by their own metadata.labels) to spread away from.

Field Type Required Description
matchExpressions object[]
matchLabels map[string]string
### .spec.template.spec.placement.antiAffinity[].labelSelector.matchExpressions[]
Field Type Required Description
key string Yes
operator string Yes Allowed: In, NotIn, Exists, DoesNotExist.
values string[]
# .spec.template.spec.placement.failureDomainSelector

Match failure domains by their status.failureDomains[].labels. Across all candidate Providers, only failure domains whose labels match are considered.

Field Type Required Description
matchExpressions object[]
matchLabels map[string]string
## .spec.template.spec.placement.failureDomainSelector.matchExpressions[]
Field Type Required Description
key string Yes
operator string Yes Allowed: In, NotIn, Exists, DoesNotExist.
values string[]
# .spec.template.spec.placement.providerSelector

Match Providers by their metadata.labels. A Provider is a candidate only if its labels match this selector.

Field Type Required Description
matchExpressions object[]
matchLabels map[string]string
## .spec.template.spec.placement.providerSelector.matchExpressions[]
Field Type Required Description
key string Yes
operator string Yes Allowed: In, NotIn, Exists, DoesNotExist.
values string[]
.spec.template.spec.userData

Optional user-data delivered to the guest via the image's guestAgent (cloud-init / ignition / sysprep).

Field Type Required Description
configMapRef object Key in a ConfigMap in the VirtualMachine's namespace (key defaults to [DEFAULT_USER_DATA_KEY]).
secretRef object Key in a Secret in the VirtualMachine's namespace (key defaults to [DEFAULT_USER_DATA_KEY]).
# .spec.template.spec.userData.configMapRef

Key in a ConfigMap in the VirtualMachine's namespace (key defaults to [DEFAULT_USER_DATA_KEY]).

Field Type Required Description
key string Key within the object's data. Defaults are caller-defined.
name string Yes Name of the ConfigMap / Secret in the referrer's namespace.
# .spec.template.spec.userData.secretRef

Key in a Secret in the VirtualMachine's namespace (key defaults to [DEFAULT_USER_DATA_KEY]).

Field Type Required Description
key string Key within the object's data. Defaults are caller-defined.
name string Yes Name of the ConfigMap / Secret in the referrer's namespace.

.status

Field Type Required Description
available integer Ready and unclaimed: what a claim can bind right now.
claimed integer
conditions object[]
imageRevision string Image revision new members are currently being built from.
observedGeneration integer
provisioning integer
replicas integer Members of any phase, excluding ones already being deleted.

.status.conditions[]

Field Type Required Description
lastTransitionTime string Yes lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string Yes message is a human readable message indicating details about the transition. This may be an empty string.
observedGeneration integer observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
reason string Yes reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string Yes status of the condition, one of True, False, Unknown.
type string Yes type of condition in CamelCase or in foo.example.com/CamelCase.

VMClass

API: banlieue.io/v1alpha1 · Kind: VMClass · Scope: Cluster · Short names: vmc

VMClass — a reusable, cluster-scoped catalog of VM "shapes".

A VMClass is to a VirtualMachine what a Kubernetes StorageClass is to a PersistentVolumeClaim: a named, admin-curated template that captures how much machine you get and what the backend must support, without naming any particular backend. A VirtualMachine references a VMClass by name (spec.classRef) instead of restating CPU / memory / disk / network on every VM.

Why create one

  • Standardize sizing. Define a small set of tiers (small, db-prod, gpu-trainer) once; users pick a tier instead of hand-tuning hardware.
  • Decouple intent from backend. A VMClass requests abstract storage and network classes plus feature flags (e.g. efiSecureBoot). The scheduler only places a VM on a Provider + failure domain that actually advertises those capabilities, so a class stays portable across vSphere, Proxmox, and libvirt.
  • Govern capabilities. Because requirements live on the class, cluster admins control which hardware shapes and features tenants may request.

How it is used

At schedule time the controller intersects this class's requirements with each candidate Provider's spec.capabilities and each failure domain's resolved attributes. A Provider that lacks the requested storage class, network class, firmware, or a required feature is filtered out.

Cluster-scoped: a VMClass is shared by VirtualMachines in any namespace.

Printer columns (kubectl get):

Name Type JSON path Priority
CPUs integer .spec.hardware.cpus 0
MemoryMiB integer .spec.hardware.memoryMiB 0
Firmware string .spec.firmware 0
Age date .metadata.creationTimestamp 0

.spec

Field Type Required Description
features string[] Required feature flags. The scheduler will only select a Provider + failure domain whose features is a superset of this list.
firmware string Firmware. Providers / failure domains that lack support for the requested firmware are filtered out by the scheduler. Allowed: bios, efi, efi-secure.
hardware object Yes Virtual hardware shape — CPU, memory, and disks — every VM of this class is given.
network object Yes Network shape — the ordered interfaces (and their abstract network classes) every VM of this class is given.
tpmEnabled boolean Attach a virtual TPM (vTPM) device to every VM of this class (ADR-0039). A class-level capability, like firmware — not a per-VM override (VirtualMachineSpec.hardwareOverride has no tpmEnabled counterpart, for the same reason it has none for firmware). The scheduler only selects a Provider/failure domain advertising the vtpm feature when this is true. Used by Kairos's kcrypt to seal LUKS keys to the VM's own TPM at install time; the device must exist before first boot, which the vSphere provider guarantees by attaching it between clone and power-on.

.spec.hardware

Virtual hardware shape — CPU, memory, and disks — every VM of this class is given.

Field Type Required Description
cpus integer Yes Number of virtual CPUs.
disks object[] Yes Disks in attachment order. The first disk is the OS disk and is backed by the VMImage resolved for the VirtualMachine; subsequent disks are blank and created with the requested size and storage class.
memoryMiB integer Yes Memory in MiB.
.spec.hardware.disks[]

Disks in attachment order. The first disk is the OS disk and is backed by the VMImage resolved for the VirtualMachine; subsequent disks are blank and created with the requested size and storage class.

Field Type Required Description
name string Yes Stable name within the VM; used in status to report resolved backend identifiers.
provisioning string Disk provisioning hint. Providers honor on a best-effort basis. Allowed: thin, thick, eagerZeroed.
sizeGiB integer Yes Size in GiB. For the OS disk this is the minimum size; if the image is larger, the provider grows accordingly.
storageClass string Yes Abstract storage class name. MUST be advertised in the chosen Provider's spec.capabilities.storageClasses.

.spec.network

Network shape — the ordered interfaces (and their abstract network classes) every VM of this class is given.

Field Type Required Description
interfaces object[] Yes Network interfaces in attachment order.
.spec.network.interfaces[]

Network interfaces in attachment order.

Field Type Required Description
ipam object Yes IPAM configuration. Uses [IpamShape] (not [IpamSpec]) because a VMClass is shared by many VMs — there is no per-VM address at this level. Per-VM static addresses are provided via VirtualMachine.spec.networkOverrides.
mtu integer Optional MTU override. Provider may ignore if unsupported.
name string Yes Stable name within the VM.
networkClass string Yes Abstract network class name. MUST be advertised in the chosen Provider's spec.capabilities.networkClasses.
.spec.network.interfaces[].ipam

IPAM configuration. Uses [IpamShape] (not [IpamSpec]) because a VMClass is shared by many VMs — there is no per-VM address at this level. Per-VM static addresses are provided via VirtualMachine.spec.networkOverrides.

Field Type Required Description
pool object Pool-based IPAM parameters.
static object Shared subnet parameters (prefix, gateway, nameservers, domain) — not a per-VM address.
# .spec.network.interfaces[].ipam.pool

Pool-based IPAM parameters.

Field Type Required Description
poolRef object Yes Typed reference (apiGroup + kind + name + optional namespace).
## .spec.network.interfaces[].ipam.pool.poolRef

Typed reference (apiGroup + kind + name + optional namespace).

Used wherever the referenced kind is pluggable — e.g. IPAM pools, where we want to accept either ipam.cluster.x-k8s.io/IPAddressClaim (CAPI's default) or future banlieue-native pool types.

Field Type Required Description
apiGroup string Yes
kind string Yes
name string Yes
namespace string
# .spec.network.interfaces[].ipam.static

Shared subnet parameters (prefix, gateway, nameservers, domain) — not a per-VM address.

Field Type Required Description
domain string DNS domain, used both as a DNS search domain and (by a VirtualMachine.spec.networkOverrides consumer, ADR-0024) to build an FQDN as <vm-name>.<domain>.
gateway string
nameservers string[]
prefix integer

VMImage

API: banlieue.io/v1alpha1 · Kind: VMImage · Scope: Cluster · Short names: vmi

VMImage — a cluster-scoped, backend-agnostic catalog entry for a bootable guest image.

A VMImage names an operating system (family / distribution / version / architecture) once, then lists — per provider class — where that image actually lives on each backend (spec.sources). A VirtualMachine references a VMImage by name (spec.imageRef); the scheduler and the chosen provider resolve it to a concrete template / backing file / import URL at provisioning time.

Why create one

  • One name, many backends. "ubuntu-22.04" can map to a vSphere template, a Proxmox template VMID, and a libvirt qcow2 — users reference a single VMImage regardless of where the VM lands.
  • Explicit, auditable image sourcing. Sources (and optional checksums) are declared, not auto-discovered, so what actually boots is reviewable.
  • Readiness gating. The image controller records per-Provider readiness in status; the scheduler refuses to place a VM until the image is confirmed available (or importable) on a candidate Provider.

Cluster-scoped: a VMImage is shared by VirtualMachines in any namespace.

Printer columns (kubectl get):

Name Type JSON path Priority
OS string .spec.osDistribution 0
Version string .spec.osVersion 0
Arch string .spec.architecture 0
Ready string .status.conditions[?(@.type=='Ready')].status 0
Age date .metadata.creationTimestamp 0

.spec

Field Type Required Description
architecture string Yes Guest CPU architecture. Failure domains whose hosts cannot run this architecture are filtered out by the scheduler. Allowed: amd64, arm64.
cloudConfigs object[] Layered cloud-configs baked into the built artifact for Url-kind sources (ADR-0037). banlieue-imagebuilder fetches each referenced Secret in list order, deep-merges their YAML content (maps deep-merge, lists concatenate, type-mismatch errors), SSA-applies a single merged Secret (<vmimage-name>-cloud-config-merged), and passes that to the kairos-operator OSArtifact as cloudConfigRef (auroraboot build-iso --cloud-config). Empty list = no cloud-config. Index 0 is the base; each subsequent entry layers on top. SecretRef-first; see [CloudConfigSource] and ADR-0020. Ignored for non-Url sources.
guestAgent string Guest agent contract this image is built to support; determines how VirtualMachine.spec.userData is delivered. Allowed: cloud-init, ignition, sysprep, none.
isoOverlay object Additional files overlaid onto a built ISO for Url-kind vSphere sources (e.g. a hand-verified grub.cfg). Resolved by banlieue-imagebuilder into the kairos-operator OSArtifact's spec.volumes[] + spec.artifacts.overlayISOVolume — the same auroraboot build-iso --overlay-iso mechanism a hand-run ISO-build pipeline would use. See [IsoOverlaySource] and ADR-0022. Ignored for cloudImage-kind builds and non-Url sources.
osDistribution string Yes Free-form distribution string. Examples: ubuntu, rhel, debian, fedora-coreos, windows-server.
osFamily string Yes Broad operating-system family. Coarser than osDistribution; lets providers apply high-level guest handling. Allowed: linux, windows, bsd, other.
osVersion string Yes Free-form version string. Examples: "22.04", "9.4", "2022".
sources object[] Yes Per-provider source mappings — one backend binding for this catalog entry per providerClass you intend to schedule VMs onto ("one name, many backends", see the type-level doc comment above).
template object How the backend template is built from a Url source (root folder, network, disk, CPU / memory / firmware / NIC, force knobs). Every field is optional and falls back to a built-in default. Only meaningful for Url sources; ignored for Template / BackingFile. See [VMImageTemplate] and ADR-0020.
trustedBoot object Requests a Trusted Boot (UKI) artifact instead of a classic kernel+initrd one, for Url-kind vSphere sources. Resolved by banlieue-imagebuilder into the kairos-operator OSArtifact's spec.artifacts.uki.{iso,keysVolume} (replacing the plain artifacts.iso request) — the auroraboot build-uki mechanism. See [TrustedBootSource] and ADR-0051. Ignored for cloudImage-kind builds and non-Url sources.

.spec.cloudConfigs[]

Layered cloud-configs baked into the built artifact for Url-kind sources (ADR-0037). banlieue-imagebuilder fetches each referenced Secret in list order, deep-merges their YAML content (maps deep-merge, lists concatenate, type-mismatch errors), SSA-applies a single merged Secret (<vmimage-name>-cloud-config-merged), and passes that to the kairos-operator OSArtifact as cloudConfigRef (auroraboot build-iso --cloud-config). Empty list = no cloud-config. Index 0 is the base; each subsequent entry layers on top. SecretRef-first; see [CloudConfigSource] and ADR-0020. Ignored for non-Url sources.

Field Type Required Description
secretRef object Key in a Secret in the imagebuild namespace holding the cloud-config YAML (key defaults to [DEFAULT_CLOUD_CONFIG_KEY]).
.spec.cloudConfigs[].secretRef

Key in a Secret in the imagebuild namespace holding the cloud-config YAML (key defaults to [DEFAULT_CLOUD_CONFIG_KEY]).

Field Type Required Description
key string Key within the object's data. Defaults are caller-defined.
name string Yes Name of the ConfigMap / Secret in the referrer's namespace.

.spec.isoOverlay

Additional files overlaid onto a built ISO for Url-kind vSphere sources (e.g. a hand-verified grub.cfg). Resolved by banlieue-imagebuilder into the kairos-operator OSArtifact's spec.volumes[] + spec.artifacts.overlayISOVolume — the same auroraboot build-iso --overlay-iso mechanism a hand-run ISO-build pipeline would use. See [IsoOverlaySource] and ADR-0022. Ignored for cloudImage-kind builds and non-Url sources.

Field Type Required Description
files object[] Explicit key -> ISO-relative-path mapping. At least one entry expected; an empty list is accepted but wires nothing into the OSArtifact.
secretRef object Yes Secret in the imagebuild namespace holding the overlay file contents.
.spec.isoOverlay.files[]

Explicit key -> ISO-relative-path mapping. At least one entry expected; an empty list is accepted but wires nothing into the OSArtifact.

Field Type Required Description
key string Yes Key within the overlay Secret holding this file's content.
path string Yes Destination path, relative to the ISO root (e.g. boot/grub2/grub.cfg).
.spec.isoOverlay.secretRef

Secret in the imagebuild namespace holding the overlay file contents.

Field Type Required Description
name string Yes

.spec.sources[]

Per-provider source mappings — one backend binding for this catalog entry per providerClass you intend to schedule VMs onto ("one name, many backends", see the type-level doc comment above).

x-kubernetes-list-type: map keyed on providerClass: the API server rejects a second entry for a providerClass that already has one, rather than leaving it to find_url_source / find_vsphere_source to silently pick whichever came first.

Field Type Required Description
checksum string Optional checksum for imported images. Format: <alg>:<hex>, e.g. sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b.... Supported algorithms: sha256, sha512. Provider import Jobs verify the built artifact against this value before writing it to the backend and fail closed on mismatch or an unsupported algorithm.
importFrom string Optional source URL. When set, providers that support image import will pull from here if the image isn't already present locally.
kind string Yes What kind of backend artifact ref refers to. Allowed: Template, BackingFile, Url.
providerClass string Yes Name of the ProviderClass this source applies to. Conventional values: vsphere, proxmox, libvirt.
ref string Yes Provider-interpreted reference: vsphere + Template: template name e.g. "ubuntu-22.04-cloudinit" proxmox + Template: template VMID e.g. "9000" libvirt + BackingFile: path e.g. "/var/lib/libvirt/images/ubuntu.qcow2" * + Url: ignored; uses importFrom

.spec.template

How the backend template is built from a Url source (root folder, network, disk, CPU / memory / firmware / NIC, force knobs). Every field is optional and falls back to a built-in default. Only meaningful for Url sources; ignored for Template / BackingFile. See [VMImageTemplate] and ADR-0020.

Field Type Required Description
cpus integer Virtual CPU count of the template (govc vm.create -c). When unset, defaults to 2. vSphere-only.
disk object Install disk of the template (the clone source's disk). When unset, a thin 100 GiB disk on a pvscsi controller is used.
firmware string Firmware for the template (govc vm.create -firmware). Reuses the backend-agnostic [Firmware] hint (bios / efi / efi-secure). When unset, defaults to efi. vSphere maps efi-secure to EFI with secure boot enabled. Allowed: bios, efi, efi-secure, null.
forceCreate boolean Recreate the template even if one of that name already exists, destroying the existing one first. Threaded as --force-create.
forceUpload boolean Re-upload the built ISO even if one of that name already exists on the backend, deleting the existing one first (the vСenter datastore file API does not overwrite in place). Threaded as --force-upload.
guestId string vCenter guestId for the template (govc vm.create -g, e.g. rhel9_64Guest, ubuntu64Guest). When unset, it is derived from the VMImage's osFamily / osDistribution / osVersion. vSphere-only.
installMode string How the template's install step is driven. See [InstallMode] and ADR-0021 / ADR-0040. Allowed: immediate, deferred, manual.
installTimeoutSeconds integer Bound, in seconds, on how long the import Job waits for the unattended Kairos install to finish and the VM to power itself off (install.poweroff: true in the cloud-config) before failing the Job. When unset, defaults to 1800 (30 min). See ADR-0021: the golden disk is never rebooted by the build, so this bounds only the (typically 8-12 min) unattended-install window, not a boot cycle.
memoryMib integer Memory of the template, in MiB (govc vm.create -m). When unset, defaults to 4096. vSphere-only.
network object[] The template's network interfaces. Empty means exactly one NIC, using every per-entry default below — the same behavior this field had before it became a list (ADR-0031). vSphere-only.
retainOnDelete boolean Keep the per-zone vCenter template(s) this VMImage caused to be built when the VMImage itself is deleted. When unset (the default), deleting a VMImage also destroys every per-zone template it owns — declarative deletion, matching VirtualMachine's own cascade onto its VSphereMachine (ADR-0026). Set true to opt out — e.g. the template is still referenced by another generation, or its lifecycle is managed by hand outside banlieue. vSphere-only; ignored by any other provider. See ADR-0028.
rootFolder string Root vCenter inventory folder (path under the datacenter's VM folder, e.g. templates/kairos); created if missing. When unset, the datacenter's VM-folder root is the root. vSphere-only.
.spec.template.disk

Install disk of the template (the clone source's disk). When unset, a thin 100 GiB disk on a pvscsi controller is used.

Field Type Required Description
controller string Disk controller type. Defaults to pvscsi. Allowed: pvscsi, lsiLogic, lsiLogicSas, busLogic.
size integer Disk size, in GiB. Defaults to 100 when unset.
type string Provisioning hint: thin (default), thick, or eagerZeroed. Reuses the backend-agnostic [DiskProvisioning] shared with VMClass / VSphereMachine; eager-zeroing is the eagerZeroed variant, not a separate flag. Providers honor it on a best-effort basis. Allowed: thin, thick, eagerZeroed.
.spec.template.network[]

The template's network interfaces. Empty means exactly one NIC, using every per-entry default below — the same behavior this field had before it became a list (ADR-0031). vSphere-only.

Field Type Required Description
adapter string Virtual NIC adapter type for the template (govc vm.create -net.adapter). Allowed: vmxnet3, vmxnet2, e1000, e1000e.
network string Port group this NIC attaches to. When unset, the zone's first reachable network class (ADR-0019) is used.
pciSlot integer PCI slot number for this NIC (ethernetN.pciSlotNumber). Slot 192 on the first NIC yields a stable ens192 interface name in the guest. When unset, defaults to 192 + this NIC's index in VMImageTemplate.network — so a template with several NICs and no explicit slots still gets predictable, non-colliding ens192/ens193/ens194/... naming.

.spec.trustedBoot

Requests a Trusted Boot (UKI) artifact instead of a classic kernel+initrd one, for Url-kind vSphere sources. Resolved by banlieue-imagebuilder into the kairos-operator OSArtifact's spec.artifacts.uki.{iso,keysVolume} (replacing the plain artifacts.iso request) — the auroraboot build-uki mechanism. See [TrustedBootSource] and ADR-0051. Ignored for cloudImage-kind builds and non-Url sources.

Field Type Required Description
secretRef object Yes Secret in the imagebuild namespace holding the six files auroraboot build-uki requires: PK.auth, KEK.auth, db.auth, db.key, db.pem, tpm2-pcr-private.pem. Generated out-of-band via auroraboot genkey — banlieue never generates or manages this key material.
.spec.trustedBoot.secretRef

Secret in the imagebuild namespace holding the six files auroraboot build-uki requires: PK.auth, KEK.auth, db.auth, db.key, db.pem, tpm2-pcr-private.pem. Generated out-of-band via auroraboot genkey — banlieue never generates or manages this key material.

Field Type Required Description
name string Yes

.status

Observed availability of a VMImage across the Providers that can serve it. Maintained by the image controller; read by the scheduler.

Field Type Required Description
buildArtifact object Progress of the shared, provider-agnostic image build for Url-kind sources — set exclusively by banlieue-imagebuilder (field manager banlieue.io/imagebuilder), never by a provider. Typed by kind (cloudImage for libvirt, iso for vSphere). None when no Url source exists on this VMImage or the build hasn't started. See ADR-0010 and ADR-0020.
conditions object[] Ready is True iff every per-provider entry is ready.
observedGeneration integer
perProvider object[] Per-Provider readiness. One entry per Provider that supports this image's providerClass and has reconciled at least once.

.status.buildArtifact

Progress of the shared, provider-agnostic image build for Url-kind sources — set exclusively by banlieue-imagebuilder (field manager banlieue.io/imagebuilder), never by a provider. Typed by kind (cloudImage for libvirt, iso for vSphere). None when no Url source exists on this VMImage or the build hasn't started. See ADR-0010 and ADR-0020.

Field Type Required Description
checksum string Expected checksum (<alg>:<hex>) of the built artifact, copied from the Url source the build serves. Consumers that stream the artifact to a backend MUST verify it against this value and fail closed on mismatch (security review 2026-07-31, SEC-004) — the value lives here, next to the PVC reference, so no consumer has to re-derive which source the shared build came from.
file string File name of the artifact within the artifacts PVC (kairos-operator convention: <osArtifactRef>.raw for cloudImage, <osArtifactRef>.iso for iso). Populated at phase Ready.
kind string Yes What kind of artifact was built, aligned with kairos-operator's own OSArtifactKind. Determines the file extension and which provider class consumes it. Allowed: cloudImage, iso.
message string Long human-readable detail, e.g. the OSArtifact.status.message on failure.
osArtifactRef string Yes Name of the OSArtifact CR banlieue-imagebuilder created for this VMImage (same namespace as the artifacts PVC below).
osArtifactUid string metadata.uid of the OSArtifact named by os_artifact_ref, once observed. Each provider's per-zone import Job sets this as its own ownerReference so a rebuilt (deleted-and-recreated) OSArtifact garbage-collects the stale Job — and the artifacts PVC mount it holds — instead of the Job outliving it for up to its ttlSecondsAfterFinished (ADR-0027). Absent until the OSArtifact has actually been observed once.
phase string Yes Current build phase. Allowed: Pending, Building, Ready, Failed.
pvcRef object Reference to the PVC kairos-operator created holding the built artifact, once known. Populated no earlier than phase Building.
reason string Short reason, mirroring the stable-string convention used elsewhere in this status (e.g. ImagePerProviderStatus.reason).
.status.buildArtifact.pvcRef

Reference to the PVC kairos-operator created holding the built artifact, once known. Populated no earlier than phase Building.

Field Type Required Description
name string Yes

.status.conditions[]

Ready is True iff every per-provider entry is ready.

Written only by banlieue-controller (field manager banlieue.io/controller), which is the only component with a whole-image view. A provider cannot compute "ready everywhere" from rows it does not own, so it writes its perProvider entry and nothing here (ADR-0015). Merge-keyed on type, per Kubernetes convention.

Field Type Required Description
lastTransitionTime string Yes lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string Yes message is a human readable message indicating details about the transition. This may be an empty string.
observedGeneration integer observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
reason string Yes reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string Yes status of the condition, one of True, False, Unknown.
type string Yes type of condition in CamelCase or in foo.example.com/CamelCase.

.status.perProvider[]

Per-Provider readiness. One entry per Provider that supports this image's providerClass and has reconciled at least once.

Merge-keyed, and it must stay that way (ADR-0015). Several providers write this list concurrently, each applying only its own entry. Without x-kubernetes-list-type: map server-side apply treats the array as atomic — one manager owns the whole thing and force() hands it over wholesale, silently discarding every other provider's row. That was a real, reproduced bug, not a theoretical one.

Field Type Required Description
message string Long human-readable detail.
providerName string Yes Name of the Provider.
providerNamespace string Yes Namespace of the Provider.
ready boolean Yes True when the image can be used to clone/create a VM on this provider.
reason string Short reason if not ready. Stable values from condition_reasons::IMAGE_*.
resolvedRef string Resolved concrete reference on the backend. vSphere: [datacenter] folder/template-name. Proxmox: VMID. Libvirt: path.
zones object[] Per-zone (per-Provider.status.failureDomains[]) import progress. Only populated for Url-kind sources, where "ready" on this Provider legitimately means "ready in some zones, still importing in others" — Template sources report readiness as a single vCenter-wide lookup and leave this empty.
.status.perProvider[].zones[]

Per-zone (per-Provider.status.failureDomains[]) import progress. Only populated for Url-kind sources, where "ready" on this Provider legitimately means "ready in some zones, still importing in others" — Template sources report readiness as a single vCenter-wide lookup and leave this empty.

Field Type Required Description
message string
name string Yes Name of the failure domain, matching Provider.status.failureDomains[].name.
ready boolean Yes True once the template/import is usable in this zone.
reason string
resolvedRef string The template's bare display name within this zone once ready — the value a provider passes to a name-based template lookup. NOT a decorated string (no [dc]/folder prefix): folder scoping for a per-zone (Url-kind) import lives in [Self::template_folder], kept separate so a lookup can be built from structured fields instead of parsing this one.
templateFolder string The vCenter folder path (relative to the datacenter's VM folder, e.g. templates/cluster-01) the template in [Self::resolved_ref] lives in, for a per-zone (Url-kind) import (ADR-0020 Decision #5). None for a Template-kind image, which has no per-zone folder — its resolved_ref is looked up datacenter-wide.

LibvirtMachine

API: infrastructure.banlieue.io/v1alpha1 · Kind: LibvirtMachine · Scope: Namespaced · Short names: lvm

LibvirtMachine — the concrete, scheduled VM request for a libvirt/KVM host.

You normally do not create this by hand: banlieue's controller does, owned by the VirtualMachine it was scheduled from, and the libvirt provider reconciles it into a real domain.

Printer columns (kubectl get):

Name Type JSON path Priority
Provider string .spec.providerRef.name 0
Provisioned boolean .status.initialization.provisioned 0
Power string .status.observedPowerState 0
Domain string .spec.domainName 1
ProviderID string .spec.providerID 1
Age date .metadata.creationTimestamp 0

.spec

Field Type Required Description
bootSource object Yes How this machine's OS disk comes into being.
desiredPowerState string Desired power state, resolved from the parent VirtualMachine's spec.desiredPowerState (ADR-0024). Allowed: PoweredOn, PoweredOff, Suspended.
disks object[] Yes Disks. The first is the OS disk; the rest are blank data disks.
domainName string Yes libvirt domain name. Unique per host, and the handle every domain procedure takes.
failureDomain string CAPI contract (optional): failure domain placement. The banlieue scheduler writes the chosen failure domain here.
firmware string Yes Firmware. EFI requires OVMF on the host; EfiSecure additionally requires a .secboot.fd variant and pre-enrolled keys. Allowed: bios, efi, efi-secure.
machineType string QEMU machine type (q35, pc, …). None lets libvirt pick its default for the host's architecture, which is the right answer unless an image needs a specific chipset.
memoryMiB integer Yes Memory in MiB.
network object[] Yes Network interfaces.
pool string Yes Storage pool that holds this machine's volumes, resolved from the storage class by the scheduler.
providerID string CAPI contract: Provider ID for the resulting Node, if this VM becomes a Kubernetes node. Format: libvirt://<provider-name>/<domain-uuid>. Set by the provider controller after the domain is defined.
providerRef object Yes Reference to the banlieue Provider whose connection details describe the target libvirt host.
tpmEnabled boolean Attach an emulated TPM 2.0 device (swtpm), resolved from the VM's VMClass.spec.tpmEnabled (ADR-0039).
userData string Guest bootstrap payload, already resolved from the parent VirtualMachine's spec.userData Secret or ConfigMap (ADR-0038) and placeholder-substituted by banlieue-controller (ADR-0025). The provider renders it into a NoCloud cidata volume — it never reads a Secret or ConfigMap itself.
vcpus integer Yes Number of virtual CPUs.

.spec.bootSource

How this machine's OS disk comes into being.

Field Type Required Description
kind string Yes Which of the two provisioning shapes this machine uses. Allowed: backingVolume, installMedia.
volume string Yes Volume name within [LibvirtMachineSpec::pool]: the backing image for BackingVolume, or the installer ISO for InstallMedia.

.spec.disks[]

Disks. The first is the OS disk; the rest are blank data disks.

Field Type Required Description
bus string Controller bus. Allowed: virtio, scsi, sata.
name string Yes Stable disk name; echoed in status and used to name the volume.
sizeGiB integer Yes Disk size in GiB. For an overlay OS disk this is a floor — the overlay is created at least this large.

.spec.network[]

Network interfaces.

Field Type Required Description
ipam object Yes IP address management for this interface.
macAddress string Optional MAC address (otherwise libvirt generates one).
model string Device model. None means virtio, which is what every image banlieue builds expects.
name string Yes Stable NIC name; echoed in status.
source object Yes Resolved bridge or libvirt network.
.spec.network[].ipam

IP address management for this interface.

Field Type Required Description
pool object Pool-based IPAM parameters.
static object Static IPAM parameters (address, prefix, gateway, nameservers, domain).
.spec.network[].ipam.pool

Pool-based IPAM parameters.

Field Type Required Description
poolRef object Yes Typed reference (apiGroup + kind + name + optional namespace).
# .spec.network[].ipam.pool.poolRef

Typed reference (apiGroup + kind + name + optional namespace).

Used wherever the referenced kind is pluggable — e.g. IPAM pools, where we want to accept either ipam.cluster.x-k8s.io/IPAddressClaim (CAPI's default) or future banlieue-native pool types.

Field Type Required Description
apiGroup string Yes
kind string Yes
name string Yes
namespace string
.spec.network[].ipam.static

Static IPAM parameters (address, prefix, gateway, nameservers, domain).

Field Type Required Description
address string Yes
domain string DNS domain, used both as a DNS search domain and (by a VirtualMachine.spec.networkOverrides consumer, ADR-0024) to build an FQDN as <vm-name>.<domain>.
gateway string
nameservers string[]
prefix integer Yes
.spec.network[].source

Resolved bridge or libvirt network.

Field Type Required Description
kind string Yes Whether name names a host bridge or a libvirt network. Allowed: network, bridge.
name string Yes The bridge interface (br0) or libvirt network (default).

.spec.providerRef

Reference to the banlieue Provider whose connection details describe the target libvirt host.

Field Type Required Description
name string Yes

.status

Observed state of a LibvirtMachine, shaped to the CAPI v1beta2 InfraMachine status contract (plus libvirt-specific diagnostics).

Field Type Required Description
addressSource string Which source answered when the provider looked up the guest's addresses (ADR-0050 Decision 8). Allowed: guestAgent, dhcpLease, arpTable.
addresses object[] CAPI contract field (optional): VM addresses.
conditions object[] CAPI-compatible conditions. The Ready condition is mirrored as InfrastructureReady on the parent per contract.
domainUuid string libvirt's UUID for the domain, in its 36-character textual form. The domain's real identity — stable across rename and host restart — and the source for spec.providerID. Not part of the CAPI contract.
failureDomain string CAPI contract field (optional): observed failure domain — the host the domain actually landed on.
initialization object CAPI contract field: replaces the deprecated v1beta1 status.ready.
observedGeneration integer
observedPowerState string The domain's last observed run state, mapped onto banlieue's backend-neutral [PowerState] (ADR-0034). The hypervisor's view, not a guest-OS-boot signal. Not part of the CAPI contract; mirrored onto the parent VirtualMachine's status.observedPowerState. Allowed: PoweredOn, PoweredOff, Suspended, null.
tpmAttached boolean Whether an emulated TPM was attached, when spec.tpmEnabled is set (ADR-0039). None when tpmEnabled is false or the attach has not run yet. A failed attach surfaces through the conditions rather than a dedicated VirtualMachine-level mirror.

.status.addresses[]

CAPI contract field (optional): VM addresses.

Field Type Required Description
address string Yes The address itself.
type string Yes Address type. Accepted: Hostname, ExternalIP, InternalIP, ExternalDNS, InternalDNS. Allowed: Hostname, ExternalIP, InternalIP, ExternalDNS, InternalDNS.

.status.conditions[]

CAPI-compatible conditions. The Ready condition is mirrored as InfrastructureReady on the parent per contract.

Field Type Required Description
lastTransitionTime string Yes lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string Yes message is a human readable message indicating details about the transition. This may be an empty string.
observedGeneration integer observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
reason string Yes reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string Yes status of the condition, one of True, False, Unknown.
type string Yes type of condition in CamelCase or in foo.example.com/CamelCase.

.status.initialization

CAPI contract field: replaces the deprecated v1beta1 status.ready.

Field Type Required Description
provisioned boolean True when the infrastructure provider reports that the resource's infrastructure is fully provisioned.

LibvirtMachineTemplate

API: infrastructure.banlieue.io/v1alpha1 · Kind: LibvirtMachineTemplate · Scope: Namespaced · Short names: lvmt

LibvirtMachineTemplate — a stamped-out LibvirtMachine spec.

CAPI requires an InfraMachineTemplate so higher-level controllers (a MachineSet / MachineDeployment) can mint many identical machines from one template. banlieue ships it for CAPI compatibility; standalone VirtualMachine users do not need it.

Note that a template is a spec template, not a disk template: nothing here clones a domain. That distinction matters on libvirt, because cloning a domain that carries TPM state would copy the state too, which is precisely ADR-0040's shared-vTPM problem.

.spec

Field Type Required Description
template object Yes The LibvirtMachine spec stamped into every machine created from this template.

.spec.template

The LibvirtMachine spec stamped into every machine created from this template.

Field Type Required Description
spec object Yes The LibvirtMachine spec for machines created from this template.
.spec.template.spec

The LibvirtMachine spec for machines created from this template.

Field Type Required Description
bootSource object Yes How this machine's OS disk comes into being.
desiredPowerState string Desired power state, resolved from the parent VirtualMachine's spec.desiredPowerState (ADR-0024). Allowed: PoweredOn, PoweredOff, Suspended.
disks object[] Yes Disks. The first is the OS disk; the rest are blank data disks.
domainName string Yes libvirt domain name. Unique per host, and the handle every domain procedure takes.
failureDomain string CAPI contract (optional): failure domain placement. The banlieue scheduler writes the chosen failure domain here.
firmware string Yes Firmware. EFI requires OVMF on the host; EfiSecure additionally requires a .secboot.fd variant and pre-enrolled keys. Allowed: bios, efi, efi-secure.
machineType string QEMU machine type (q35, pc, …). None lets libvirt pick its default for the host's architecture, which is the right answer unless an image needs a specific chipset.
memoryMiB integer Yes Memory in MiB.
network object[] Yes Network interfaces.
pool string Yes Storage pool that holds this machine's volumes, resolved from the storage class by the scheduler.
providerID string CAPI contract: Provider ID for the resulting Node, if this VM becomes a Kubernetes node. Format: libvirt://<provider-name>/<domain-uuid>. Set by the provider controller after the domain is defined.
providerRef object Yes Reference to the banlieue Provider whose connection details describe the target libvirt host.
tpmEnabled boolean Attach an emulated TPM 2.0 device (swtpm), resolved from the VM's VMClass.spec.tpmEnabled (ADR-0039).
userData string Guest bootstrap payload, already resolved from the parent VirtualMachine's spec.userData Secret or ConfigMap (ADR-0038) and placeholder-substituted by banlieue-controller (ADR-0025). The provider renders it into a NoCloud cidata volume — it never reads a Secret or ConfigMap itself.
vcpus integer Yes Number of virtual CPUs.
.spec.template.spec.bootSource

How this machine's OS disk comes into being.

Field Type Required Description
kind string Yes Which of the two provisioning shapes this machine uses. Allowed: backingVolume, installMedia.
volume string Yes Volume name within [LibvirtMachineSpec::pool]: the backing image for BackingVolume, or the installer ISO for InstallMedia.
.spec.template.spec.disks[]

Disks. The first is the OS disk; the rest are blank data disks.

Field Type Required Description
bus string Controller bus. Allowed: virtio, scsi, sata.
name string Yes Stable disk name; echoed in status and used to name the volume.
sizeGiB integer Yes Disk size in GiB. For an overlay OS disk this is a floor — the overlay is created at least this large.
.spec.template.spec.network[]

Network interfaces.

Field Type Required Description
ipam object Yes IP address management for this interface.
macAddress string Optional MAC address (otherwise libvirt generates one).
model string Device model. None means virtio, which is what every image banlieue builds expects.
name string Yes Stable NIC name; echoed in status.
source object Yes Resolved bridge or libvirt network.
# .spec.template.spec.network[].ipam

IP address management for this interface.

Field Type Required Description
pool object Pool-based IPAM parameters.
static object Static IPAM parameters (address, prefix, gateway, nameservers, domain).
## .spec.template.spec.network[].ipam.pool

Pool-based IPAM parameters.

Field Type Required Description
poolRef object Yes Typed reference (apiGroup + kind + name + optional namespace).
### .spec.template.spec.network[].ipam.pool.poolRef

Typed reference (apiGroup + kind + name + optional namespace).

Used wherever the referenced kind is pluggable — e.g. IPAM pools, where we want to accept either ipam.cluster.x-k8s.io/IPAddressClaim (CAPI's default) or future banlieue-native pool types.

Field Type Required Description
apiGroup string Yes
kind string Yes
name string Yes
namespace string
## .spec.template.spec.network[].ipam.static

Static IPAM parameters (address, prefix, gateway, nameservers, domain).

Field Type Required Description
address string Yes
domain string DNS domain, used both as a DNS search domain and (by a VirtualMachine.spec.networkOverrides consumer, ADR-0024) to build an FQDN as <vm-name>.<domain>.
gateway string
nameservers string[]
prefix integer Yes
# .spec.template.spec.network[].source

Resolved bridge or libvirt network.

Field Type Required Description
kind string Yes Whether name names a host bridge or a libvirt network. Allowed: network, bridge.
name string Yes The bridge interface (br0) or libvirt network (default).
.spec.template.spec.providerRef

Reference to the banlieue Provider whose connection details describe the target libvirt host.

Field Type Required Description
name string Yes

VSphereCluster

API: infrastructure.banlieue.io/v1alpha1 · Kind: VSphereCluster · Scope: Namespaced · Short names: vsc

VSphereCluster — banlieue's CAPI v1beta2 InfraCluster for vSphere backends.

It tells CAPI where a cluster's machines may be placed by aggregating the failure domains of one or more Providers (vCenters) into the CAPI-shaped status.failureDomains list. The control-plane endpoint is operator-supplied (a VIP) or filled in by the control-plane provider (e.g. k0smotron).

Why it exists

  • Cluster-side failure-domain spread. CAPI's control-plane / MachineSet controllers balance machines across the FDs published here. "Spread across all 6 domains" is simply replicas: 6 over a VSphereCluster that advertises 6 FDs.
  • Multi-vCenter clusters. One Kubernetes cluster can span several Providers — a capability beyond single-vCenter CAPV.

You do not create the resulting VMs by hand; CAPI mints VSphereMachines (the InfraMachine) from a VSphereMachineTemplate. This object only advertises where they may go.

Printer columns (kubectl get):

Name Type JSON path Priority
Provisioned boolean .status.initialization.provisioned 0
Endpoint string .status.controlPlaneEndpoint.host 1
Ready string .status.conditions[?(@.type=='Ready')].status 0
Age date .metadata.creationTimestamp 0

.spec

Field Type Required Description
controlPlaneEndpoint object CAPI contract (optional): the cluster's API-server endpoint. Operator- supplied control-plane VIP, or left unset for a control-plane provider (e.g. k0smotron) to manage. Mirrored to status.controlPlaneEndpoint.
controlPlaneFailureDomainSelector object Which aggregated failure domains are eligible to run control-plane nodes, matched against the Provider FD labels. When unset, all aggregated FDs are control-plane eligible. Use this to keep the etcd quorum to a bounded, odd set of domains while workers spread wider.
paused boolean Suspend reconciliation. Equivalent to the cluster.x-k8s.io/paused annotation but in-band.
providerRefs object[] Explicit list of Providers (in this namespace) to aggregate. Takes precedence over providerSelector when non-empty. Declaring the set explicitly is the preferred, "explicit over implicit" form.
providerSelector object Select Providers (in this namespace) to aggregate failure domains from, by matching their labels. Ignored when providerRefs is set.

.spec.controlPlaneEndpoint

CAPI contract (optional): the cluster's API-server endpoint. Operator- supplied control-plane VIP, or left unset for a control-plane provider (e.g. k0smotron) to manage. Mirrored to status.controlPlaneEndpoint.

Field Type Required Description
host string Yes Hostname or IP on which the API server is serving.
port integer Yes Port on which the API server is serving.

.spec.controlPlaneFailureDomainSelector

Which aggregated failure domains are eligible to run control-plane nodes, matched against the Provider FD labels. When unset, all aggregated FDs are control-plane eligible. Use this to keep the etcd quorum to a bounded, odd set of domains while workers spread wider.

Field Type Required Description
matchExpressions object[]
matchLabels map[string]string
.spec.controlPlaneFailureDomainSelector.matchExpressions[]
Field Type Required Description
key string Yes
operator string Yes Allowed: In, NotIn, Exists, DoesNotExist.
values string[]

.spec.providerRefs[]

Explicit list of Providers (in this namespace) to aggregate. Takes precedence over providerSelector when non-empty. Declaring the set explicitly is the preferred, "explicit over implicit" form.

Field Type Required Description
name string Yes

.spec.providerSelector

Select Providers (in this namespace) to aggregate failure domains from, by matching their labels. Ignored when providerRefs is set.

Field Type Required Description
matchExpressions object[]
matchLabels map[string]string
.spec.providerSelector.matchExpressions[]
Field Type Required Description
key string Yes
operator string Yes Allowed: In, NotIn, Exists, DoesNotExist.
values string[]

.status

Observed state of a VSphereCluster, shaped to the CAPI v1beta2 InfraCluster status contract.

Field Type Required Description
conditions object[] CAPI-compatible conditions. The Ready condition is mirrored to the parent Cluster's InfrastructureReady; Paused reflects pause state.
controlPlaneEndpoint object CAPI contract field (optional): the resolved API-server endpoint, echoed from spec.controlPlaneEndpoint or set by the control-plane provider.
failureDomains object[] CAPI contract field: the failure domains machines may be placed in, aggregated from the selected Providers. A list per v1beta2.
initialization object CAPI contract field: replaces the deprecated v1beta1 status.ready. provisioned == true once the failure domains are resolved (and the control-plane endpoint is known, when one is required).
observedGeneration integer The generation of the spec the controller has reconciled.

.status.conditions[]

CAPI-compatible conditions. The Ready condition is mirrored to the parent Cluster's InfrastructureReady; Paused reflects pause state.

Field Type Required Description
lastTransitionTime string Yes lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string Yes message is a human readable message indicating details about the transition. This may be an empty string.
observedGeneration integer observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
reason string Yes reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string Yes status of the condition, one of True, False, Unknown.
type string Yes type of condition in CamelCase or in foo.example.com/CamelCase.

.status.controlPlaneEndpoint

CAPI contract field (optional): the resolved API-server endpoint, echoed from spec.controlPlaneEndpoint or set by the control-plane provider.

Field Type Required Description
host string Yes Hostname or IP on which the API server is serving.
port integer Yes Port on which the API server is serving.

.status.failureDomains[]

CAPI contract field: the failure domains machines may be placed in, aggregated from the selected Providers. A list per v1beta2.

Field Type Required Description
attributes map[string]string Arbitrary attributes for consumers. banlieue flattens the Provider FD's attributes.raw plus dc/cluster labels into this map.
controlPlane boolean Whether this failure domain is eligible to run control-plane nodes. None is treated by CAPI as "not control-plane eligible".
name string Yes Unique failure-domain name (one of the Provider's status.failureDomains[].name).

.status.initialization

CAPI contract field: replaces the deprecated v1beta1 status.ready. provisioned == true once the failure domains are resolved (and the control-plane endpoint is known, when one is required).

Field Type Required Description
provisioned boolean True when the infrastructure provider reports that the resource's infrastructure is fully provisioned.

VSphereMachine

API: infrastructure.banlieue.io/v1alpha1 · Kind: VSphereMachine · Scope: Namespaced · Short names: vsm

VSphereMachine — the concrete, scheduled VM request for the vSphere backend.

This is banlieue's reference implementation of the CAPI v1beta2 InfraMachine contract. Where a VirtualMachine is abstract, every field here is already resolved: a real vCenter template, datacenter, cluster, datastore, and per-NIC portGroup. banlieue's main controller creates it after scheduling; the vSphere provider reconciles it into a real VM and reports CAPI-shaped status.

Why it exists

  • It is the hand-off. A VirtualMachine says "an ubuntu db-prod VM somewhere reasonable"; a VSphereMachine says "clone template X in DC0 / cluster C0 onto datastore ds-fast-01" — the thing a provider can actually execute.
  • CAPI-compatible by contract. Because it satisfies the InfraMachine contract, it doubles as a Cluster API infrastructure provider: a clusterv1.Machine with infrastructureRef.kind: VSphereMachine drives it the same way.

You normally do not create this by hand — the controller does, owned by the VirtualMachine. The CAPI contract label cluster.x-k8s.io/v1beta2: v1alpha1 is emitted onto the generated CRD by crdgen, since kube-derive cannot set CRD-level labels (ADR-0005).

Printer columns (kubectl get):

Name Type JSON path Priority
Provider string .spec.providerRef.name 0
Provisioned boolean .status.initialization.provisioned 0
Power string .status.observedPowerState 0
ProviderID string .spec.providerID 1
Cluster string .spec.cluster 1
Age date .metadata.creationTimestamp 0

.spec

Field Type Required Description
cluster string Yes Compute cluster within the datacenter.
datacenter string Yes Datacenter name.
datastore string Yes Datastore or datastore cluster name (resolved from the storage class).
desiredPowerState string Desired power state, resolved from the parent VirtualMachine's spec.desiredPowerState (ADR-0024). Defaults to PoweredOn, matching VirtualMachineSpec's own default. Allowed: PoweredOn, PoweredOff, Suspended.
disks object[] Yes Disks. The first disk is the template's OS disk (grown if needed); subsequent disks are blank.
failureDomain string CAPI contract (optional): failure domain placement. The banlieue scheduler writes the chosen failure domain here; for CAPI users the parent Machine's spec.failureDomain is what populates this.
firmware string Yes Firmware. EFI / EFI Secure require the template to be EFI-capable. Allowed: bios, efi, efi-secure.
folder string Destination vCenter folder path for the clone (not the source template — see template_folder). Optional; defaults to the datacenter VM root, or (once set by banlieue-controller) the same per-zone folder the template lives in.
memoryMiB integer Yes Memory in MiB.
network object[] Yes Network interfaces.
numCpus integer Yes Number of virtual CPUs.
providerID string CAPI contract: Provider ID for the resulting Node, if this VM becomes a Kubernetes node. Format: vsphere://<vm-instance-uuid>. Set by the provider controller after the VM is created.
providerRef object Yes Reference to the banlieue Provider whose connection details describe the target vCenter.
resourcePool string Resource pool path within the cluster. Optional; defaults to the cluster's root resource pool.
template string Yes vCenter template's bare display name (resolved from VMImage). Never a decorated string (no [dc]/folder prefix) — see template_folder for the scoping the lookup needs.
templateFolder string The per-zone vCenter folder the template in template lives in (resolved from VMImage.status, e.g. templates/cluster-01, ADR-0020 Decision #5). None for a Template-kind image, which has no per-zone folder — its lookup is datacenter-wide.
tpmEnabled boolean Attach a virtual TPM (vTPM) device to this VM, resolved from the VM's VMClass.spec.tpmEnabled (ADR-0039). Consumed by the provider controller between clone_vm (which always clones powered off) and the power-on step, so the device exists before first boot — a hard requirement for Kairos's kcrypt to seal LUKS keys to it during unattended install.
userData string Guest bootstrap payload content — already resolved from the parent VirtualMachine's spec.userData Secret or ConfigMap (ADR-0038) and placeholder-substituted (ADR-0024's ${VM_NAME}/${FQDN}/etc. set) by banlieue-controller (ADR-0025). The provider delivers this verbatim (base64 into guestinfo.userdata) — it never reads a Secret or ConfigMap itself.

.spec.disks[]

Disks. The first disk is the template's OS disk (grown if needed); subsequent disks are blank.

Field Type Required Description
name string Yes Stable disk name; echoed in status with resolved backend identifiers.
provisioning string Provisioning hint (thin / thick / eager-zeroed). Allowed: thin, thick, eagerZeroed.
sizeGiB integer Yes Disk size in GiB. For the OS disk this is a floor — the template's disk is grown to at least this size.

.spec.network[]

Network interfaces.

Field Type Required Description
ipam object Yes IP address management for this interface.
macAddress string Optional MAC address (otherwise vCenter generates one).
name string Yes Stable NIC name; echoed in status.
portGroup string Yes Resolved port group or distributed port group name.
.spec.network[].ipam

IP address management for this interface.

Field Type Required Description
pool object Pool-based IPAM parameters.
static object Static IPAM parameters (address, prefix, gateway, nameservers, domain).
.spec.network[].ipam.pool

Pool-based IPAM parameters.

Field Type Required Description
poolRef object Yes Typed reference (apiGroup + kind + name + optional namespace).
# .spec.network[].ipam.pool.poolRef

Typed reference (apiGroup + kind + name + optional namespace).

Used wherever the referenced kind is pluggable — e.g. IPAM pools, where we want to accept either ipam.cluster.x-k8s.io/IPAddressClaim (CAPI's default) or future banlieue-native pool types.

Field Type Required Description
apiGroup string Yes
kind string Yes
name string Yes
namespace string
.spec.network[].ipam.static

Static IPAM parameters (address, prefix, gateway, nameservers, domain).

Field Type Required Description
address string Yes
domain string DNS domain, used both as a DNS search domain and (by a VirtualMachine.spec.networkOverrides consumer, ADR-0024) to build an FQDN as <vm-name>.<domain>.
gateway string
nameservers string[]
prefix integer Yes

.spec.providerRef

Reference to the banlieue Provider whose connection details describe the target vCenter.

Field Type Required Description
name string Yes

.status

Observed state of a VSphereMachine, shaped to the CAPI v1beta2 InfraMachine status contract (plus a few vSphere-specific diagnostics).

Field Type Required Description
addresses object[] CAPI contract field (optional): VM addresses. Surfaced to the parent Machine's status.addresses once initialization is complete.
conditions object[] CAPI-compatible conditions (using metav1.Condition). The Ready condition is mirrored as InfrastructureReady on the parent (clusterv1.Machine or banlieue VirtualMachine) per contract.
failureDomain string CAPI contract field (optional): observed failure domain. Surfaced to the parent Machine's status.failureDomain.
initialization object CAPI contract field: replaces the deprecated v1beta1 status.ready.
instanceUuid string VM instance UUID. Stable across vCenter restarts and the source for spec.providerID. Not part of the CAPI contract.
observedGeneration integer
observedPowerState string The backend VM's actual power state, as last observed via VirtualMachine.runtime.powerState (ADR-0034) — the hypervisor's view, available immediately on power-on, not a guest-OS-boot signal. Absent until first observed. Not part of the CAPI contract; mirrored onto the parent VirtualMachine's own status.observedPowerState. Allowed: PoweredOn, PoweredOff, Suspended, null.
tpmAttached boolean Whether a vTPM device was successfully attached, when spec.tpmEnabled is set (ADR-0039). None when tpmEnabled is false (nothing was ever attempted) or the attach hasn't run yet. Not part of the CAPI contract; a failed attach surfaces through the Ready/InfrastructureReady conditions rather than a dedicated VirtualMachine-level mirror (ADR-0034's reasoning for observedPowerState applies equally here).
vmRef string VMware managed-object reference (vm-NNNN). Useful for operator diagnostics. Not part of the CAPI contract.

.status.addresses[]

CAPI contract field (optional): VM addresses. Surfaced to the parent Machine's status.addresses once initialization is complete.

Field Type Required Description
address string Yes The address itself.
type string Yes Address type. Accepted: Hostname, ExternalIP, InternalIP, ExternalDNS, InternalDNS. Allowed: Hostname, ExternalIP, InternalIP, ExternalDNS, InternalDNS.

.status.conditions[]

CAPI-compatible conditions (using metav1.Condition). The Ready condition is mirrored as InfrastructureReady on the parent (clusterv1.Machine or banlieue VirtualMachine) per contract.

Field Type Required Description
lastTransitionTime string Yes lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
message string Yes message is a human readable message indicating details about the transition. This may be an empty string.
observedGeneration integer observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
reason string Yes reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
status string Yes status of the condition, one of True, False, Unknown.
type string Yes type of condition in CamelCase or in foo.example.com/CamelCase.

.status.initialization

CAPI contract field: replaces the deprecated v1beta1 status.ready.

Field Type Required Description
provisioned boolean True when the infrastructure provider reports that the resource's infrastructure is fully provisioned.

VSphereMachineTemplate

API: infrastructure.banlieue.io/v1alpha1 · Kind: VSphereMachineTemplate · Scope: Namespaced · Short names: vsmt

VSphereMachineTemplate — a stamped-out VSphereMachine spec.

CAPI requires an InfraMachineTemplate so higher-level controllers (a MachineSet / MachineDeployment) can mint many identical machines from one template. It wraps a single template.spec that is the VSphereMachine spec used for each generated machine. banlieue ships it for CAPI compatibility; standalone VirtualMachine users do not need it.

.spec

Field Type Required Description
template object Yes The VSphereMachine spec stamped into every machine created from this template.

.spec.template

The VSphereMachine spec stamped into every machine created from this template.

Field Type Required Description
spec object Yes The VSphereMachine spec for machines created from this template.
.spec.template.spec

The VSphereMachine spec for machines created from this template.

Field Type Required Description
cluster string Yes Compute cluster within the datacenter.
datacenter string Yes Datacenter name.
datastore string Yes Datastore or datastore cluster name (resolved from the storage class).
desiredPowerState string Desired power state, resolved from the parent VirtualMachine's spec.desiredPowerState (ADR-0024). Defaults to PoweredOn, matching VirtualMachineSpec's own default. Allowed: PoweredOn, PoweredOff, Suspended.
disks object[] Yes Disks. The first disk is the template's OS disk (grown if needed); subsequent disks are blank.
failureDomain string CAPI contract (optional): failure domain placement. The banlieue scheduler writes the chosen failure domain here; for CAPI users the parent Machine's spec.failureDomain is what populates this.
firmware string Yes Firmware. EFI / EFI Secure require the template to be EFI-capable. Allowed: bios, efi, efi-secure.
folder string Destination vCenter folder path for the clone (not the source template — see template_folder). Optional; defaults to the datacenter VM root, or (once set by banlieue-controller) the same per-zone folder the template lives in.
memoryMiB integer Yes Memory in MiB.
network object[] Yes Network interfaces.
numCpus integer Yes Number of virtual CPUs.
providerID string CAPI contract: Provider ID for the resulting Node, if this VM becomes a Kubernetes node. Format: vsphere://<vm-instance-uuid>. Set by the provider controller after the VM is created.
providerRef object Yes Reference to the banlieue Provider whose connection details describe the target vCenter.
resourcePool string Resource pool path within the cluster. Optional; defaults to the cluster's root resource pool.
template string Yes vCenter template's bare display name (resolved from VMImage). Never a decorated string (no [dc]/folder prefix) — see template_folder for the scoping the lookup needs.
templateFolder string The per-zone vCenter folder the template in template lives in (resolved from VMImage.status, e.g. templates/cluster-01, ADR-0020 Decision #5). None for a Template-kind image, which has no per-zone folder — its lookup is datacenter-wide.
tpmEnabled boolean Attach a virtual TPM (vTPM) device to this VM, resolved from the VM's VMClass.spec.tpmEnabled (ADR-0039). Consumed by the provider controller between clone_vm (which always clones powered off) and the power-on step, so the device exists before first boot — a hard requirement for Kairos's kcrypt to seal LUKS keys to it during unattended install.
userData string Guest bootstrap payload content — already resolved from the parent VirtualMachine's spec.userData Secret or ConfigMap (ADR-0038) and placeholder-substituted (ADR-0024's ${VM_NAME}/${FQDN}/etc. set) by banlieue-controller (ADR-0025). The provider delivers this verbatim (base64 into guestinfo.userdata) — it never reads a Secret or ConfigMap itself.
.spec.template.spec.disks[]

Disks. The first disk is the template's OS disk (grown if needed); subsequent disks are blank.

Field Type Required Description
name string Yes Stable disk name; echoed in status with resolved backend identifiers.
provisioning string Provisioning hint (thin / thick / eager-zeroed). Allowed: thin, thick, eagerZeroed.
sizeGiB integer Yes Disk size in GiB. For the OS disk this is a floor — the template's disk is grown to at least this size.
.spec.template.spec.network[]

Network interfaces.

Field Type Required Description
ipam object Yes IP address management for this interface.
macAddress string Optional MAC address (otherwise vCenter generates one).
name string Yes Stable NIC name; echoed in status.
portGroup string Yes Resolved port group or distributed port group name.
# .spec.template.spec.network[].ipam

IP address management for this interface.

Field Type Required Description
pool object Pool-based IPAM parameters.
static object Static IPAM parameters (address, prefix, gateway, nameservers, domain).
## .spec.template.spec.network[].ipam.pool

Pool-based IPAM parameters.

Field Type Required Description
poolRef object Yes Typed reference (apiGroup + kind + name + optional namespace).
### .spec.template.spec.network[].ipam.pool.poolRef

Typed reference (apiGroup + kind + name + optional namespace).

Used wherever the referenced kind is pluggable — e.g. IPAM pools, where we want to accept either ipam.cluster.x-k8s.io/IPAddressClaim (CAPI's default) or future banlieue-native pool types.

Field Type Required Description
apiGroup string Yes
kind string Yes
name string Yes
namespace string
## .spec.template.spec.network[].ipam.static

Static IPAM parameters (address, prefix, gateway, nameservers, domain).

Field Type Required Description
address string Yes
domain string DNS domain, used both as a DNS search domain and (by a VirtualMachine.spec.networkOverrides consumer, ADR-0024) to build an FQDN as <vm-name>.<domain>.
gateway string
nameservers string[]
prefix integer Yes
.spec.template.spec.providerRef

Reference to the banlieue Provider whose connection details describe the target vCenter.

Field Type Required Description
name string Yes