0075. adopt skips unapproved machines and names the v1.14 documents it cannot capture
Status: Accepted · Date: 2026-10-26 · Design section: Bootstrap (ichor adopt), Patch layers
Decided: adopt reads approved machines only; for the v1.14 documents Ichor cannot yet express it says which document and why. Whether those documents become patch kinds or spec fields is left open (below).
Context
A real-cluster test on Talos v1.14.3 could not reach zero drift. Two findings.
ichor adoptreportedKubeNetworkConfig,UnattendedInstallConfigandKubeFlannelCNIConfig(in another run: pod subnets, service subnets, cert SANs,UnattendedInstallConfig) as fields it "cannot patch automatically", and the tester fell back toversionContractv1.13, where the default pod subnet 10.244/16 then collided with the outer network.adoptdialed everyTalosMachineof the cluster, including a pending machine in maintenance mode, and failed with a TLS error. The tester had to disable discovery, delete the machine, adopt, and re-enable discovery.
What is true (Talos machinery v1.14.3, Ichor at this commit)
pkg/render.baseConfigcallsgenerate.NewInputwith only the secrets bundle, the version contract and the control-plane scheduling option. It passes no pod or service subnet, no install disk or image, no certificate SANs and no CNI choice. Nothing inTalosCluster.specorTalosMachine.speccarries those values either (there are no such fields).- At contract v1.14 the generator therefore emits its defaults:
KubeNetworkConfigwith 10.244.0.0/16 and 10.96.0.0/12,KubeFlannelCNIConfig(vxlan), an emptymachine.certSANs, and noUnattendedInstallConfigat all (generate/init.goonly emits it when an install disk was passed). Below v1.14 the same values live in the legacycluster.network,machine.installandmachine.certSANs. - The
TalosConfigPatchdocument kinds areSysctlConfig,KernelModuleConfig,Config,VolumeConfig,UserVolumeConfigandRawVolumeConfig.KubeNetworkConfig,UnattendedInstallConfig,KubeFlannelCNIConfigandKubeAPIServerConfig(cert SANs) are not among them. - The only route left is the legacy
Configdocument, and Talos rejects it next to the v1.14 documents:KubeNetworkConfigandKubeFlannelCNIConfigconflict withcluster.network,UnattendedInstallConfigconflicts withmachine.install(V1Alpha1ConflictValidatein machinery).ichor initwritesmachine.installandmachine.certSANsthrough such a patch, which works only because the base render has no install document. - So at v1.14 an Ichor-rendered cluster can have neither non-default subnets, nor a chosen install disk (other than the
legacy form), nor "no flannel". A node generated by
talosctl gen config(or by a harness that drops the flannel document) differs from the render in exactly those documents, andadoptcannot capture them because it only capturesSysctlConfigandKernelModuleConfig.
Decision
Done here:
adoptonly reads machines withapprovalState: approved. Pending and rejected machines are not dialed, and the report saysmachine "x": skipped, approval state is pending (...). An unapproved machine has no credentials in the bundle and, in maintenance mode, its Talos API accepts no client certificate, so a failure there is certain.- When the paths adopt leaves alone belong to
KubeNetworkConfig,UnattendedInstallConfigorKubeFlannelCNIConfig, the report names the document, what it holds, and that no patch kind exists for it. The old advice to "write a TalosConfigPatch by hand" is kept only for the legacyConfigpaths, where it is true.
Open: how a v1.14 cluster gets these values
Decided by ADR 0077 (option C, with the per-node half as a spec field).
Not decided here, because the design document does not settle it and each option reaches beyond pkg/render.
A. Extend the patch allow-list (design: "Kinds outside the allow-list are listed, and the user chooses between
extending the list and dropping them"). Add KubeNetworkConfig, UnattendedInstallConfig and KubeAPIServerConfig
as mirrorgen roots; then adopt can capture them and subnets/disk/SANs are patch values at the right layer
(cluster for subnets, machine for disk and SANs). Cost: CRD size, the proto and generated TS, the UI kind list,
fieldmeta rules, conversion in DocumentFromPatch. A patch cannot delete a document, so "no flannel" cannot be a
patch.
B. Spec fields. TalosCluster.spec.network.{podSubnets,serviceSubnets}, TalosMachine.spec.install.{disk,image} and
cert SANs, rendered by the system layer into whichever form the contract allows (the pattern injectKubeProxy
already uses). "No flannel" falls out of the system layer: drop KubeFlannelCNIConfig when spec.cni.preset is not
flannel (design: the system layer generates "CNI settings"). Cost: CRD changes, webhook rules (subnets immutable
after creation), adopt would map drift to those fields.
C. A mix: B for the cluster-wide, install-time values (subnets, CNI), A for per-node documents.
Dropping the flannel document for non-flannel presets changes the rendered hash of existing v1.14 Cilium clusters, so that step needs its own review of what the drift check does to them.