--- # Order matches talos/README.md: genconfig → apply all nodes → bootstrap → kubeconfig. - name: Validate talconfig and generate **out/** (talhelper genconfig) when: noble_talos_genconfig | bool block: - name: talhelper validate ansible.builtin.command: argv: - talhelper - validate - talconfig - talconfig.yaml args: chdir: "{{ noble_talos_dir }}" changed_when: false - name: talhelper genconfig -o out ansible.builtin.command: argv: - talhelper - genconfig - -o - out args: chdir: "{{ noble_talos_dir }}" changed_when: true - name: Stat talos/out/talosconfig ansible.builtin.stat: path: "{{ noble_talos_dir }}/out/talosconfig" register: noble_talos_talosconfig - name: Require talos/out/talosconfig ansible.builtin.assert: that: - noble_talos_talosconfig.stat.exists | default(false) fail_msg: >- Missing {{ noble_talos_dir }}/out/talosconfig. Run **talhelper genconfig -o out** in **talos/** (talsecret per talos/README.md §1), or set **noble_talos_genconfig=true** on this playbook. # Maintenance API (**--insecure**) vs joined cluster (**tls: certificate required**) — talos/README §2 A vs B. - name: Set apply path from noble_talos_apply_mode (manual) ansible.builtin.set_fact: noble_talos_apply_insecure: "{{ noble_talos_apply_mode == 'insecure' }}" when: noble_talos_apply_mode | default('auto') in ['insecure', 'secure'] - name: Probe Talos API — apply-config dry-run (insecure / maintenance) ansible.builtin.command: argv: - talosctl - apply-config - --insecure - -n - "{{ noble_talos_nodes[0].ip }}" - -f - "{{ noble_talos_dir }}/out/{{ noble_talos_nodes[0].machine }}" - --dry-run register: noble_talos_probe_insecure failed_when: false changed_when: false when: noble_talos_apply_mode | default('auto') == 'auto' - name: Probe Talos API — apply-config dry-run (TLS / joined) ansible.builtin.command: argv: - talosctl - apply-config - -n - "{{ noble_talos_nodes[0].ip }}" - -f - "{{ noble_talos_dir }}/out/{{ noble_talos_nodes[0].machine }}" - --dry-run environment: TALOSCONFIG: "{{ noble_talos_dir }}/out/talosconfig" register: noble_talos_probe_secure failed_when: false changed_when: false when: - noble_talos_apply_mode | default('auto') == 'auto' - noble_talos_probe_insecure.rc != 0 - name: Resolve apply mode — maintenance (insecure) ansible.builtin.set_fact: noble_talos_apply_insecure: true when: - noble_talos_apply_mode | default('auto') == 'auto' - noble_talos_probe_insecure.rc == 0 - name: Resolve apply mode — joined (TALOSCONFIG, no insecure) ansible.builtin.set_fact: noble_talos_apply_insecure: false when: - noble_talos_apply_mode | default('auto') == 'auto' - noble_talos_probe_insecure.rc != 0 - noble_talos_probe_secure.rc == 0 - name: Fail when Talos API mode cannot be determined ansible.builtin.fail: msg: >- Cannot run **talosctl apply-config --dry-run** on {{ noble_talos_nodes[0].ip }}. Insecure: rc={{ noble_talos_probe_insecure.rc }} {{ noble_talos_probe_insecure.stderr | default('') }}. TLS: rc={{ noble_talos_probe_secure.rc | default('n/a') }} {{ noble_talos_probe_secure.stderr | default('') }}. Check LAN to :50000, node power, and that **out/talosconfig** matches these nodes. Override: **-e noble_talos_apply_mode=secure** (joined) or **insecure** (maintenance ISO). when: - noble_talos_apply_mode | default('auto') == 'auto' - noble_talos_probe_insecure.rc != 0 - noble_talos_probe_secure is not defined or noble_talos_probe_secure.rc != 0 - name: Show resolved Talos apply-config mode ansible.builtin.debug: msg: >- apply-config: {{ 'maintenance (--insecure)' if noble_talos_apply_insecure | bool else 'joined (TALOSCONFIG)' }} (noble_talos_apply_mode={{ noble_talos_apply_mode | default('auto') }}) - name: Apply machine config to each node (first install — insecure) ansible.builtin.command: argv: - talosctl - apply-config - --insecure - -n - "{{ item.ip }}" - --file - "{{ noble_talos_dir }}/out/{{ item.machine }}" loop: "{{ noble_talos_nodes }}" loop_control: label: "{{ item.ip }}" when: noble_talos_apply_insecure | bool changed_when: true - name: Apply machine config to each node (cluster already has TLS — no insecure) ansible.builtin.command: argv: - talosctl - apply-config - -n - "{{ item.ip }}" - --file - "{{ noble_talos_dir }}/out/{{ item.machine }}" environment: TALOSCONFIG: "{{ noble_talos_dir }}/out/talosconfig" loop: "{{ noble_talos_nodes }}" loop_control: label: "{{ item.ip }}" when: not (noble_talos_apply_insecure | bool) changed_when: true # apply-config triggers reboots; apid on :50000 must accept connections before talosctl bootstrap / kubeconfig. - name: Wait for Talos machine API (apid) on bootstrap node ansible.builtin.wait_for: host: "{{ noble_talos_bootstrap_node_ip }}" port: 50000 delay: "{{ noble_talos_apid_wait_delay | int }}" timeout: "{{ noble_talos_apid_wait_timeout | int }}" state: started when: noble_talos_wait_for_apid | default(true) | bool - name: Bootstrap cluster (once per cluster) ansible.builtin.command: argv: - talosctl - bootstrap - -n - "{{ noble_talos_bootstrap_node_ip }}" environment: TALOSCONFIG: "{{ noble_talos_dir }}/out/talosconfig" register: noble_talos_bootstrap_cmd when: not (noble_talos_skip_bootstrap | bool) changed_when: noble_talos_bootstrap_cmd.rc == 0 failed_when: >- noble_talos_bootstrap_cmd.rc != 0 and ('etcd data directory is not empty' not in (noble_talos_bootstrap_cmd.stderr | default(''))) - name: Write Kubernetes admin kubeconfig ansible.builtin.command: argv: - talosctl - kubeconfig - "{{ noble_talos_kubeconfig_out }}" - --force - -n - "{{ noble_talos_kubeconfig_node }}" - -e - "{{ noble_talos_kubeconfig_endpoint }}" - --merge=false environment: TALOSCONFIG: "{{ noble_talos_dir }}/out/talosconfig" changed_when: true - name: Optional — set kubectl cluster server to reachable API (VIP unreachable from this host) ansible.builtin.command: argv: - kubectl - config - set-cluster - "{{ noble_talos_kubectl_cluster_name }}" - --server={{ noble_k8s_api_server_override }} - --kubeconfig={{ noble_talos_kubeconfig_out }} when: noble_k8s_api_server_override | default('') | length > 0 changed_when: true - name: Next — platform stack ansible.builtin.debug: msg: >- Kubeconfig written to {{ noble_talos_kubeconfig_out }}. Export KUBECONFIG={{ noble_talos_kubeconfig_out }} and run: ansible-playbook playbooks/noble.yml (or: ansible-playbook playbooks/deploy.yml for the full pipeline).