Reading talosctl apply-config --dry-run from a script
The dry run prints its summary and diff to stderr, no drift is the text No changes, and a regex that anchors at the start of the string makes a role re-apply every node every run. Plus how to find what forces a reboot, and why failed applies must never be logged.
The core of my Talos role is: render the config, ask every node what would change,
apply only where something would. That “ask” is talosctl apply-config --dry-run,
and getting a script to read it correctly took longer than the rest of the role.
Where the output is
The “Dry run summary”, the line “Applied configuration without a reboot” and the
diff all go to stderr. Stdout is empty. A node with nothing to do prints
No changes. after Config diff:. A script has to capture and parse both streams.
An anchored match applied every node every run
Jinja’s regex test anchors at the start of the string. The text I was looking
for sits in the middle of multi-line output, so it never matched, and the role
decided that every node had drifted on every run. Use search:
- when: output is search('Applied configuration without a reboot')Which change forces a reboot
--mode auto decides by itself whether a reboot is needed, and the dry run tells
you which way it would go. I used that to find out why a first apply would reboot
every node of my live cluster. I rendered variants of the config with -e
overrides and dry-ran each against one node, read-only: removing a pin, matching
the installer image, turning off certificate SANs made no difference. Collapsing
the long list of identical machine.disks entries did. Any change to
machine.disks made auto choose a reboot. That meant a rolling reboot of
the whole cluster, and I knew it before touching anything.
A failed apply echoes the whole config
When apply-config fails, the error includes the machine config, certificate
authority keys among it. Run those tasks with no_log, and when debugging by hand
look at only the first lines of the error.
When a command hangs
talosctl etcd members never returns when etcd is half up. The usual perl
one-liner, perl -e 'alarm ...; exec', does nothing here, because Go programs
ignore SIGALRM. A perl fork that kills the child with kill 9 after a deadline
works on Linux and macOS, and needs no coreutils timeout. And in 1.14
--insecure is a flag of the subcommand, so it goes after it: get disks --insecure --nodes <ip>.