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.capabilitiesmaps 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 applyof a Provider CR:banlieue-operatorcreates 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
tpmEnabledclass must pair with aninstallMode: Deferredimage, 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
VirtualMachineClaimand 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
VMImageis 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: 6over aVSphereClusterthat 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.MachinewithinfrastructureRef.kind: VSphereMachinedrives 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 |