Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Full documentation lives at **[talm.cozystack.io](https://talm.cozystack.io/)**.
- [Initializing a project](https://talm.cozystack.io/getting-started/init/) — `--image`, `--cluster-endpoint`, `--root`.
- [Node files](https://talm.cozystack.io/configuration/node-files/) — the modeline, discovery comments, per-node overrides.
- [Endpoints and VIPs](https://talm.cozystack.io/configuration/endpoints-and-vips/) — `endpoint`, `floatingIP`, `vipLink`.
- [Talos versions and output format](https://talm.cozystack.io/configuration/talos-versions/) — the v1.12 multi-document split.
- [Talos versions and output format](https://talm.cozystack.io/configuration/talos-versions/) — which schema a render targets, and the version keys to pin.
- [Templates and values](https://talm.cozystack.io/configuration/templates/) — `lookup`, `--set` vs `--set-string`.
- [Encryption](https://talm.cozystack.io/configuration/encryption/) — age-encrypted secrets and user values.
- [Applying with side-patches](https://talm.cozystack.io/operations/side-patches/) — the `-f` chain.
Expand All @@ -60,3 +60,7 @@ Full documentation lives at **[talm.cozystack.io](https://talm.cozystack.io/)**.
- [CLI reference](https://talm.cozystack.io/reference/) — commands and flags.

The site is built from `docs/` in this repository; the CLI reference under `docs/reference/` is generated from the command tree.

## License

Apache-2.0, except for two files ported from [siderolabs/talos](https://github.com/siderolabs/talos), which is MPL-2.0: `pkg/engine/talos_helpers.go` and `pkg/commands/talos_client.go` carry Talos code that v1.14 stopped exporting, so they stay under MPL-2.0 and say so in their headers. MPL-2.0 section 3.3 covers distributing the combined work under Apache-2.0.
9 changes: 7 additions & 2 deletions charts/generic/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ templateOptions:
fileValues: []
jsonValues: []
literalValues: []
talosVersion: ""
# Pin both: an empty key either renders what the node picks (with a warning)
# or stops the render on newer contracts. The Kubernetes version is the
# default of the pinned Talos line, so a fresh project lands on what that
# line ships and a re-sync does not move the control plane. Replace it with
# the version your cluster runs.
talosVersion: "v1.13"
withSecrets: "secrets.yaml"
kubernetesVersion: ""
kubernetesVersion: "v1.36.2"
full: false
applyOptions:
preserve: false
Expand Down
40 changes: 37 additions & 3 deletions docs/configuration/talos-versions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,46 @@

`templateOptions.talosVersion` in `Chart.yaml` (or `--talos-version` on the command line) selects which Talos config schema talm renders. It changes the shape of every node file.

## What an unset version means

Leaving `templateOptions.talosVersion` empty means the version of Talos the `talm` binary was built against. It is not frozen at a release: upgrade talm, and an unpinned project follows it to whatever Talos that build carries.

That is why the shipped presets pin it. The charts write Kubernetes settings as v1alpha1 fields (`machine.kubelet`, `machine.nodeLabels`), and from v1.14 Talos keeps each of those in a document of its own and rejects a config that carries both shapes. Rendering an unpinned project against v1.14 therefore produces a config the node refuses, with `kubelet config is already set in v1alpha1 config (.machine.kubelet)` and siblings. Network settings made the same move earlier, in v1.12.

Rather than emit that config, the render stops. With both keys empty the Kubernetes version is reported first, since the bundle cannot be serialized without one; pin it and the contract conflict is reported next:

```text
rendered config mixes v1alpha1 fields with the documents that superseded them: ...
hint: templateOptions.talosVersion is unset, so the render targets the Talos version talm was built from.
Pin it to v1.13 or lower in Chart.yaml; above that contract Talos keeps these settings in documents of their own,
which the charts do not emit.
```

A chart can also fail earlier than either guard: the cozystack preset deletes a default node label with `$patch: delete`, and on a contract where `machine.nodeLabels` has moved into `KubeNodeConfig` that path no longer exists, so patching stops with `failed to delete path ...: lookup failed` before any version check runs. The preset happens to pin `v1.12`, which predates that move and sidesteps it.

Pin `templateOptions.talosVersion` in `Chart.yaml`. The rule below still holds — the contract must not be newer than the Talos running on the node — and until the charts emit the typed documents there is a second bound on top of it: keep the pin at or below `v1.13`. Nodes running v1.14 are served by a v1.13 contract, which is the supported direction; the reverse is not. Projects created from the shipped presets already carry a pin.

## The Kubernetes version

`templateOptions.kubernetesVersion` picks the Kubernetes release the generated config targets: the kubelet image and, on contracts that keep them in v1alpha1, the control-plane component images.

Leaving it empty means the node keeps deciding, on contracts where it still can: the render emits no image fields at all, and each component uses the default of the Talos release it runs. The render says so on stderr, because that is a real choice and not a no-op — a node on a newer Talos release moves kubelet and the control plane with it, and the node file shows nothing either way. This is new behaviour, not a restored default: earlier talm substituted its own built-in Kubernetes version whenever the key was empty, so an unpinned project silently followed the binary. It no longer does.

From v1.14 the contract takes that choice away. The Kubernetes settings live in documents of their own and those documents require an image, so an unset version is reported rather than rendered — pin the key.

Pin it in `Chart.yaml` when you want to choose the version yourself, which is what both shipped presets do. A pinned version reaches every component, kubelet included, so they never split across releases.

The presets do not agree on a value. Generic pins `v1.36.2`, the default of the Talos line it targets, so a fresh project lands on what that line ships and a re-sync does not move the control plane. Cozystack pins `v1.34.3` against an older Talos line. Either way the pin is a starting point: set the key to the version your own cluster runs rather than inheriting the preset's.

A project created before those pins existed carries empty values for this key and for `talosVersion`. On the first render after upgrading talm it stops with an error naming the key to set; add both pins to its `Chart.yaml` and it renders again.

## Which format each version gets

Selected via `Chart.yaml` (`templateOptions.talosVersion`) or `--talos-version`:

- **Talos < v1.12** — single YAML document with `machine.network` and `machine.registries` sections (the shape shown in [Node files](node-files.md)).
- **Talos >= v1.12** — multi-document format with separate typed documents instead of the deprecated monolithic fields.
- **Talos >= v1.12** — multi-document format with separate typed documents instead of the deprecated monolithic network and registry fields.
- **Talos >= v1.14** — a second round of the same move, this time for the Kubernetes settings: `machine.kubelet`, `machine.nodeLabels` and the control-plane components each get a document of their own, and a config carrying both shapes is rejected. The shipped charts still write the v1alpha1 fields, which is why the presets pin below this.

## Documents emitted in multi-doc mode

Expand Down Expand Up @@ -39,6 +73,6 @@ Multi-NIC nodes therefore produce one document per NIC, not one document total.

## Version compatibility

!!! danger "The configured version must match the Talos actually running on the node"
!!! danger "The configured version must not be newer than the Talos running on the node"

This setting must match the **Talos version actually running on the target node** — i.e. the maintenance ISO/PXE the node booted from for `apply -i`, or the installed Talos for an authenticated apply. It is **not** the same as `install.image`, which only controls what gets written to disk after a successful apply. When the configured contract is newer than the running binary, machinery injects fields (e.g. `machine.install.grubUseUKICmdline` from v1.12) that the running parser does not know, and the apply fails on the node side with `failed to parse config: unknown keys found during decoding: ...`. `talm apply` runs a best-effort pre-flight check against the running version and prints a `warning: pre-flight: ...` line with a hint when it detects this mismatch; if the warning is missed, the same hint is appended to the apply error. Either reboot the node into a maintenance image that matches the configured contract, or lower `templateOptions.talosVersion` / `--talos-version` to match what is running.
This setting must not exceed the **Talos version actually running on the target node** — i.e. the maintenance ISO/PXE the node booted from for `apply -i`, or the installed Talos for an authenticated apply. It is **not** the same as `install.image`, which only controls what gets written to disk after a successful apply. When the configured contract is newer than the running binary, machinery injects fields (e.g. `machine.install.grubUseUKICmdline` from v1.12) that the running parser does not know, and the apply fails on the node side with `failed to parse config: unknown keys found during decoding: ...`. `talm apply` runs a best-effort pre-flight check against the running version and prints a `warning: pre-flight: ...` line with a hint when it detects this mismatch; if the warning is missed, the same hint is appended to the apply error. Either reboot the node into a maintenance image that matches the configured contract, or lower `templateOptions.talosVersion` / `--talos-version` to match what is running.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,6 @@ talm apply -f nodes/node1.yaml -i

- [Initializing a project](getting-started/init.md) — `--image`, `--cluster-endpoint`, `--root`.
- [Endpoints and VIPs](configuration/endpoints-and-vips.md) — `endpoint`, `floatingIP`, `vipLink`.
- [Talos versions and output format](configuration/talos-versions.md) — the v1.12 multi-document split.
- [Talos versions and output format](configuration/talos-versions.md) — which schema a render targets, and the version keys to pin.
- [Applying with side-patches](operations/side-patches.md) — the `-f` chain.
- [CLI reference](reference/index.md) — generated from the command tree.
Loading
Loading