Skip to content

feat: affinity rules - #310

Merged
the-bokya merged 20 commits into
developfrom
feat/affinity-rules
Oct 1, 2026
Merged

the-bokya merged 20 commits into
developfrom
feat/affinity-rules

Conversation

@the-bokya

@the-bokya the-bokya commented Oct 1, 2026 •

Copy link
Copy Markdown
Member
  • A VM create request can carry placement_rules that limit the Metal Servers for the VM, by host tags and by the tags of other VMs on the host.
  • Metal Server has a Tags table, and the VM create request takes tags.
  • A rule reads metal_server or virtual_machine tags with has or has_not. Rules nest in any_of and all_of groups.
  • A virtual_machine rule can set within, such as rack, to read the VMs of every host with the same tag value.
  • Any tenant can set rules on its own VMs, and the VM stores its rules.
  • PlacementContext removes the hosts that fail the rules before the strategy ranks them. The placement strategies do not change.
  • Placement checks the rules again under the host lock and also locks the other hosts of a within group, so concurrent placements cannot break a rule.
  • The new Affinity Matching setting selects Enforced, which fails with affinity_unsatisfied (503), or Preferred, which places the VM on any host.
  • Migration and a resize that moves the VM apply the stored rules. An in-place resize and a migration to a named destination ignore them.
  • A rule counts only the VMs of the same tenant and ignores VMs that are being terminated. The API client and docs describe the new behavior.

The create request accepts an optional affinity map. Atlas does not apply it yet, so the field only fixes the API shape. The generated API client now includes it.
AffinityRules parses and stores the VM affinity rule tree: rules on Metal Server or VM tags with has and has_not, nested in any_of and all_of groups. It rejects unknown fields, empty tags or groups, more than 16 rules, and groups nested more than 3 deep. Placement does not apply the rules yet.
The create request takes VM tags and an affinity_rules tree that matches the AffinityRules schema. The draft VM stores both, so a later placement can read them. Only a System Manager can set rules, and only on a privileged VM. Placement does not apply the rules yet. The generated API client includes the new request types.
The tests check the affinity rule tree shape, its validation limits, the API and domain parsing of tags and rules, the System Manager and privileged VM gate, and the draft fields.
The placement handbook describes the affinity rule types, their meaning, examples, and validation. Placement does not apply the rules yet. The VM module specification names the affinity code owner and the creation invariants.
AffinityRules.filter_hosts returns the hosts that meet every rule, in the given order. AffinityHost loads the tags of each host and of the tenant VMs on it, including VMs that migrate to it. Each rule type checks its field types when it is built, and groups now nest at most 5 deep. Placement does not call the filter yet.
The tests check rule matching on host and VM tags, the type checks at construction, and the host filter on stored hosts, VMs, and migrations.
PlacementContext removes the hosts that fail the affinity rules from its snapshot when a matching host has room, and checks the rules again under the host lock. A failed check under the lock counts as contention, so the next attempt reads a fresh snapshot. The new Affinity Matching setting selects Enforced, which fails with affinity_unsatisfied, or Preferred, which uses every host. Create passes the request rules, and migration and resize pass the stored rules. An in-place resize and a migration to a named destination ignore the rules. The placement strategies do not change.
The 503 response of VM creation documents the affinity_unsatisfied code, and the affinity_rules descriptions state that placement applies the rules. The generated API client includes the new error type.
The tests check the snapshot filter, Enforced and Preferred matching, the recheck under the host lock, the setting default, and the rules that migration passes for a chosen and a named destination.
The placement handbook explains the snapshot filter, the recheck under the host lock, and the Affinity Matching setting. The tenant API lists affinity_unsatisfied, and the VM specification records the placement invariants.
A VM rule no longer counts a VM that is being terminated, on its host or on the destination of its active migration. Such a VM is about to leave the host, so it must not keep other VMs away.
A virtual_machine rule can name a host tag key in within, such as rack. The rule then reads the VMs on every host that has the same value for that key as the candidate host, and a host without the key fails the rule. Under the host lock, placement also locks each other host of the group without waiting and keeps the locks until the draft commits, so two placements cannot both pass the rule for one group.
The VM create API accepts within on an affinity rule, and the generated API client includes it.
The tests check within parsing and type checks, rules over a whole rack, a host without the key, the group locks under the host lock, and that a terminating VM does not count.
The placement handbook explains the within group, the group locks, and which VMs a rule counts. The VM specification records the group lock invariant.
The VM create API, the Virtual Machine field, the domain request, and the placement requirements use placement_rules. The rule types, the Affinity Matching setting, and the affinity_unsatisfied error keep their names. The generated API client follows the new field name.
Any tenant can set placement rules on its VMs. A System Manager and a privileged VM are no longer needed. A virtual_machine rule still reads only the VMs of the tenant that owns the new VM.
@the-bokya
the-bokya marked this pull request as ready for review October 1, 2026 19:44
@the-bokya
the-bokya merged commit 339735d into develop Oct 1, 2026
7 checks passed
@the-bokya
the-bokya deleted the feat/affinity-rules branch October 1, 2026 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant