Machine currently carries two different things in one object:
- Physical identity / inventory —
bmc.address, bootMACAddress, networkSite
- Deployment intent —
imageRef, dataImages, postHookRefs, params, afterDeploy, ezio tuning
That works for the naming-a-specific-machine workflow ("install this image on these three hosts"), which is the current use case. It does not express the fleet workflow: "deploy this image to 20 machines at site A, I do not care which 20."
The state machine already anticipates the split
Enrolling -> Inspecting -> Available -> Provisioning -> Provisioned already has an Available state, whose meaning is "inspected, idle, ready to be given work" — a purely inventory notion. What actually moves a Machine out of it today is a user editing spec.imageRef (the spec-vs-status diff that triggers provisioning). So the inventory semantics are half-built: the state exists, but nothing allocates into it.
Shape and name
A MachineClaim holding the intent plus a count and a selector, matched against Available Machines by a binding controller. The closest in-tree analogue is PersistentVolume / PersistentVolumeClaim: admin-provided inventory, a claim describing what is wanted, and a controller that binds them.
Named MachineClaim, not MachineRequest. "Claim" is the term Kubernetes already uses for this exact relationship — a PersistentVolumeClaim holds a volume until released, and DRA's ResourceClaim is the current core API for "allocate devices matching criteria". "Request" reads as a one-shot imperative ask; "claim" carries the binding-and-holding semantics that are actually wanted here, so the lifecycle (bound, released, re-bindable) is legible from the name alone. Metal3 (BareMetalHost consumed by a CAPI Machine) and Ironic (its Allocation resource with resource_class / traits) are the same pattern in this problem domain, so the operator's mental model transfers.
On a split, imageRef, dataImages, postHookRefs, params, afterDeploy and the ezio tuning move to the claim; Machine keeps physical identity, status, and a binding reference recording which claim holds it.
Selection: labels only, at least initially
Match on Machine labels with a standard label selector, and let users apply the labels themselves. Hardware-fact matching is explicitly not the starting point: status.hardware only exists after the agent registers (the machine must boot and be inspected first), and today it carries just disks, NICs and a CPU count — too thin to select on usefully. Operator-applied labels (site=a, role=worker, ram=64g) need no new fact model and no inspection dependency, and they let the user encode whatever distinctions actually matter in their environment. Richer fact-based selection can come later if labels prove insufficient.
Semantics to settle before building
- Binding under contention — two claims wanting the same Machine. Needs a claim reference on the Machine written with optimistic concurrency, in the PV/PVC style.
- Release — after a deploy completes, does the Machine return to
Available, or stay held by the claim until it is deleted?
- Insufficient capacity — fewer matching Machines than claimed: wait, fail, or partially satisfy and keep trying?
- Re-provisioning — under the current model this is editing
spec.imageRef; with a claim layer, what does changing a bound request's image mean for machines already provisioned by it?
Scope note
Not planned for now. The current named-machine flow covers the immediate use case, and this adds a controller with real allocation semantics. It is recorded because the split point is already clear and because the existing state machine was built in a way that leaves room for it.
Machinecurrently carries two different things in one object:bmc.address,bootMACAddress,networkSiteimageRef,dataImages,postHookRefs,params,afterDeploy, ezio tuningThat works for the naming-a-specific-machine workflow ("install this image on these three hosts"), which is the current use case. It does not express the fleet workflow: "deploy this image to 20 machines at site A, I do not care which 20."
The state machine already anticipates the split
Enrolling -> Inspecting -> Available -> Provisioning -> Provisionedalready has anAvailablestate, whose meaning is "inspected, idle, ready to be given work" — a purely inventory notion. What actually moves a Machine out of it today is a user editingspec.imageRef(the spec-vs-status diff that triggers provisioning). So the inventory semantics are half-built: the state exists, but nothing allocates into it.Shape and name
A
MachineClaimholding the intent plus a count and a selector, matched againstAvailableMachines by a binding controller. The closest in-tree analogue is PersistentVolume / PersistentVolumeClaim: admin-provided inventory, a claim describing what is wanted, and a controller that binds them.Named
MachineClaim, notMachineRequest. "Claim" is the term Kubernetes already uses for this exact relationship — a PersistentVolumeClaim holds a volume until released, and DRA'sResourceClaimis the current core API for "allocate devices matching criteria". "Request" reads as a one-shot imperative ask; "claim" carries the binding-and-holding semantics that are actually wanted here, so the lifecycle (bound, released, re-bindable) is legible from the name alone. Metal3 (BareMetalHostconsumed by a CAPIMachine) and Ironic (itsAllocationresource withresource_class/traits) are the same pattern in this problem domain, so the operator's mental model transfers.On a split,
imageRef,dataImages,postHookRefs,params,afterDeployand the ezio tuning move to the claim;Machinekeeps physical identity, status, and a binding reference recording which claim holds it.Selection: labels only, at least initially
Match on Machine labels with a standard label selector, and let users apply the labels themselves. Hardware-fact matching is explicitly not the starting point:
status.hardwareonly exists after the agent registers (the machine must boot and be inspected first), and today it carries just disks, NICs and a CPU count — too thin to select on usefully. Operator-applied labels (site=a,role=worker,ram=64g) need no new fact model and no inspection dependency, and they let the user encode whatever distinctions actually matter in their environment. Richer fact-based selection can come later if labels prove insufficient.Semantics to settle before building
Available, or stay held by the claim until it is deleted?spec.imageRef; with a claim layer, what does changing a bound request's image mean for machines already provisioned by it?Scope note
Not planned for now. The current named-machine flow covers the immediate use case, and this adds a controller with real allocation semantics. It is recorded because the split point is already clear and because the existing state machine was built in a way that leaves room for it.