You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(init): add --image flag to override the preset values.yaml image (#150)
* feat(init): add --image flag to override the preset values.yaml image
talm init writes the preset chart unchanged, including a hard-coded
installer image (e.g. ghcr.io/cozystack/cozystack/talos:v1.12.6 in
cozystack). Operators using a custom or factory-built Talos image
have to edit values.yaml after every fresh init. The new --image flag
makes the override declarative at init time:
talm init --preset cozystack --name cluster --image \
factory.talos.dev/installer/<sha>:<version>
Implementation is a minimal regex substitution on the preset values
content before write. The helper applyImageOverride is line-anchored,
returns the input unchanged for an empty override OR for a values
file that does not declare image (so a preset without the field is
not silently fabricated), and %q-quotes the override value so a
reference with characters YAML would otherwise re-interpret stays
parsed as a string.
Tests in pkg/commands/init_test.go cover the four contract corners:
empty override, present-image substitution with surrounding content
preserved, missing-image short-circuit, and shell-meta safe quoting.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* docs(init): explain why applyImageOverride keeps a redundant match check
Address review feedback from gemini-code-assist on
pkg/commands/init.go:548: the inner imageLineRe.Match is redundant
under the talm init flow because validateImageOverride runs first
against the same bytes from presetFiles. Document that the guard is
intentional defense in depth so the helper stays safe for direct
callers (unit tests, future code paths that might skip the
validator) instead of dropping it and creating a hidden coupling
between the validator and the helper.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
* refactor(init): use MatchString in validateImageOverride
Address review feedback from gemini-code-assist on
pkg/commands/init.go:574: the input is already a string, so call
imageLineRe.MatchString(content) directly instead of forcing a
[]byte conversion. Tiny allocation saving and the idiomatic Go
form when the regex input arrives as a string.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
---------
Signed-off-by: Aleksei Sviridkin <f@lex.la>
`--image` rewrites the top-level `image:` field in the preset's `values.yaml` before write. The flag is honored on initial `init` only — for an existing project, edit `values.yaml` directly. The `cozystack` preset declares `image:`; the `generic` preset does not, so `--image --preset generic` is rejected up front.
61
+
54
62
Edit `values.yaml` to set your cluster's control-plane endpoint. This is the URL every node's kubelet and kube-proxy will dial. The chart leaves it empty on purpose so a missed override fails loudly instead of silently embedding a placeholder. For cozystack VIP setups set `endpoint` and `floatingIP` together (same IP, single shared VIP); for single-node clusters use that node's routable IP and leave `floatingIP` blank; for multi-node with an external load balancer use the LB URL and leave `floatingIP` blank. When the VIP must sit on a link that does not yet exist on the live system at first apply (typically a VLAN sub-interface), set `vipLink` to that link name — the chart pins `Layer2VIPConfig.link` to it instead of the default-gateway link that discovery would otherwise pick, and emits the document even on a totally fresh node where no default-gateway link has been discovered yet. The chart does not auto-emit a `LinkConfig` or `VLANConfig` for the override link; the operator is responsible for ensuring the link comes up, typically by adding a `LinkConfig` or `VLANConfig` for that link to the per-node body overlay alongside `vipLink`. Subnet-selector fields (`kubelet.validSubnets`, `etcd.advertisedSubnets`) are derived automatically from the node's default-gateway-bearing link, so no override is needed unless you have a multi-homed node that requires a specific subnet pinned.
55
63
56
64
Boot Talos Linux node, let's say it has address `192.0.2.4`. Then:
// In the talm init flow this guard is redundant: RunE invokes
549
+
// validateImageOverride against the same byte content from
550
+
// presetFiles before this loop runs, so a missing image: field
551
+
// fails the command up front. The check is kept as defense in
552
+
// depth for direct callers (unit tests, future code paths that
553
+
// might skip the validator) so the helper is safe in isolation.
554
+
if!imageLineRe.Match(values) {
555
+
returnnil, fmt.Errorf("--image was set but the preset values.yaml does not declare a top-level image: field; remove --image, choose a different preset, or add the image field manually")
returnfmt.Errorf("--image was set but preset %q does not declare a top-level image: field in values.yaml; remove --image or choose a preset that exposes it (e.g. cozystack)", presetName)
582
+
}
583
+
returnnil
584
+
}
585
+
returnfmt.Errorf("--image was set but preset %q has no values.yaml in the embedded chart files", presetName)
586
+
}
587
+
492
588
// askUserOverwrite asks user if they want to overwrite a file
// --image is only honored on initial init (it customizes the
686
+
// preset's values.yaml at write time). Refusing it on --update
687
+
// surfaces the no-op trap explicitly instead of letting the
688
+
// user's flag silently disappear.
689
+
ifinitCmdFlags.image!="" {
690
+
returnfmt.Errorf("--image is honored on initial init only; for an existing project, edit the image field in values.yaml directly")
691
+
}
692
+
589
693
// Determine preset: use -p flag if provided, otherwise try to read from Chart.yaml
590
694
varpresetNamestring
591
695
@@ -680,6 +784,7 @@ func init() {
680
784
initCmd.Flags().StringVar(&initCmdFlags.talosVersion, "talos-version", "", "the desired Talos version to generate config for (backwards compatibility, e.g. v0.8)")
681
785
initCmd.Flags().StringVarP(&initCmdFlags.preset, "preset", "p", "", "preset for file generation (not required with --encrypt, --decrypt, or --update)")
682
786
initCmd.Flags().StringVarP(&initCmdFlags.name, "name", "N", "", "cluster name (not required with --encrypt, --decrypt, or --update)")
787
+
initCmd.Flags().StringVar(&initCmdFlags.image, "image", "", "override the Talos installer image written to the preset's values.yaml (e.g. factory.talos.dev/installer/<sha256>:<version>)")
0 commit comments