0092. Approval sets the primary NIC, its addressing and extra disk roles as typed spec fields
Status: Accepted · Date: 2026-10-27 · Design section: Nodes (approval, disk roles)
Decided: TalosMachine.spec.network (one primary link chosen by permanent MAC, DHCP or static addressing, optional VLAN, DNS servers) and TalosMachine.spec.disks (roles ephemeral and userVolume on disks identified like spec.install.disk) are written at approval by the UI form and ichor machine approve flags; pkg/render emits a LinkAliasConfig alias net0 with a CEL selector on the permanent MAC and refers to the alias from DHCPv4Config, LinkConfig, VLANConfig and ResolverConfig, a VolumeConfig for EPHEMERAL and a UserVolumeConfig per volume, and the legacy machine.network.interfaces before the multi-document contract; link addressing documents are classified live in pkg/fieldmeta, aliases and everything else keep the reboot-required default; bonds, the storage role and unused are not done
Context
ADR 0077 gave approval the system disk and left the rest of the design's approval step ("role, labels, disk roles and basic networking") without a field to carry it, so the form could not say which NIC to use or how to address it, and a node with a second disk could not put EPHEMERAL or a data volume on it.
Decision
spec.network {mac, addressing, addresses, gateway, dnsServers, vlanID}.macis the link's permanent address (pattern in the CRD).addressingisdhcp(default) orstatic; static needs at least one address (isCIDR) and dhcp takes no addresses or gateway (CEL on the struct).gatewayand each DNS server areisIP.vlanIDis 1 to 4094. Unset leaves Talos's default. The field is mutable in the CRD; what a change costs is the fieldmeta classification below, not an admission rule.spec.disks[] {role, disk, name, maxSize}.roleisephemeraloruserVolume;diskis the same one-of selector asspec.install.disk. A user volume needs aname(letters, digits, hyphen, at most 32, mounted at/var/mnt/<name>) and may carrymaxSize(200GiB, MiB/GiB/TiB). At most eight entries, oneephemeral, unique names (CEL). Whether the system disk and anephemeraldisk differ is not expressible in CEL (the two selectors can name one disk differently), so the UI checks it and Talos decides otherwise.- Network rendering, from the multi-document contract (
MultidocNetworkConfigSupported, Talos above 1.11, so both v1.13 and v1.14):LinkAliasConfignet0, selectormac(link.permanent_addr) == "<lower-case mac>", parsed againstcelenv.LinkLocator()so a wrong expression fails at render. This is the fix for interface names changing.- DHCP:
DHCPv4Confignamed by the alias (IPv4 only; DHCPv6 is not requested). - Static:
LinkConfigfornet0withup: true, the addresses, and a default route when a gateway is set. - VLAN: the alias gets a
LinkConfigwithup: trueand nothing else, and aVLANConfignet0.<id>withparent: net0carries the addresses and routes, or has aDHCPv4Configof its own. - DNS servers: a
ResolverConfignameserverslist, merged into the generator's ownResolverConfig. Contract 1.11 and older render onemachine.network.interfacesentry withdeviceSelector.permanentAddr, the VLAN under it, andmachine.network.nameservers; the legacy default route is0.0.0.0/0or::/0by gateway family.
- Disk rendering: a
VolumeConfignamedEPHEMERALwhoseprovisioning.diskSelector.matchis the same CEL expressionspec.installuses (diskExpression), which replaces the generator's own EPHEMERAL document by merge; aUserVolumeConfigper volume with that selector,grow: true,maxSizeif given, otherwiseminSize: 1GiBbecause Talos refuses a user volume with neither. These are emitted for every contract, as the documents exist well before 1.12. - fieldmeta (
pkg/fieldmeta), read against the Talos v1.14.3 controllers ininternal/app/machined/pkg/controllers/network:LinkConfig,VLANConfigandDHCPv4Configare safe (link_config.go,address_config.go,route_config.go,operator_config.gotake the activeMachineConfigas a weak input and rewrite their specs on every change, andlink_spec.go,address_spec.go,route_spec.go,operator_spec.goprogram the kernel);ResolverConfig.nameserversis safe on the same grounds as the existingmachine.network.nameserversrule (resolver_config.go).LinkAliasConfigis left at the reboot-required default althoughlink_alias_config.goalso reacts live, because it renames the handle every other document uses.ResolverConfig.hostDNSand the volume kinds are unchanged:VolumeConfig.provisioningis already install-time-only andUserVolumeConfigkeeps the default, as the design says a new user volume on an unused disk needs no reset. "Safe" is about the reboot, not about reachability: an address change on the link the controller dials moves the node (ADR 0086 covers re-finding it). - Approval.
ApproveMachineRequest.networkand.disks, mirrored onMachine;TalosLink.permanent_macis new on the wire (the details RPC showed the current MAC, which differs for a bond member or a spoofed address). The backend re-checks everything the CRD checks and requires the MAC to be one of the machine's discovered identity MACs, so a typo isInvalidArgumentwith the reason. CLI:--nic MAC,--address CIDR(repeatable; any address makes it static),--gateway,--dns(repeatable),--vlan,--ephemeral-disk DISK,--user-volume NAME=DISK[,size=200GiB](repeatable), with DISK in the--install-disksyntax. UI: a card picker listing physical links as name, MAC and speed (a typed MAC if the node reports none), address fields, and disk pickers from the disksGetNodereads. - Layer. Network and disk documents are system layer, applied with the install document and below every patch, so a
TalosConfigPatchcan still override them.
Not done
- Bonds. The design says a bond takes members by name or alias and a MAC form emits one alias per member; that needs a
second link, a mode and a
BondConfig, and is its own change. - The
storagerole (needs aTalosStoragepreset, ADR 0050),unused(no document to render) andRawVolumeConfig. - Whether Talos still runs its default DHCP on a link that has a
LinkConfigbut noDHCPv4Configwas not traced inoperator_config.go; static addressing is rendered as written and not checked against a node. - No end-to-end run on a real node. The documents are validated by Talos's own machinery at render time and the golden tests check their content at v1.14, v1.13 and v1.11.
- The "accepted, no effect" report for an edited EPHEMERAL selector on an installed node (design, Nodes) is not part
of this change;
VolumeConfig.provisioningis already classified install-time-only. - The details RPC only reports links of a maintenance-mode node through the insecure API, so a node whose Talos API is unreachable gets a typed MAC.