--- # WPA2-PSK takes an 8-63 character passphrase, or exactly 64 hex characters as a # precomputed key. NetworkManager stores a shorter one without complaint -- # psk-flags stays 0 and the value sits in the keyfile -- and then refuses to # activate with "Secrets were required, but not provided", which reads like a # missing password rather than an invalid one. # # For the rescue AP that failure is invisible until the day the home network is # down and this is the only way in, so it is checked here instead. Only lengths # are reported, never the values. - name: check the Wi-Fi secrets are usable as WPA2-PSK ansible.builtin.assert: that: - (vars[item] | length >= 8 and vars[item] | length <= 63) or (vars[item] is match('^[0-9a-fA-F]{64}$')) fail_msg: >- {{ item }} is {{ vars[item] | length }} characters, which WPA2 will not accept. Use an 8-63 character passphrase, or a 64-character hex precomputed key. Fix it with `make vault`. quiet: true # The loop carries the variable NAME, never its value: a failed assert prints # the item it was iterating over, so looping over the secrets themselves would # dump both passwords to the terminal on any failure. loop: - stickah_psk - stickah_psk_rescue tags: [labelprint, wifi] # The watchdog can pull the radio out from under this very play if it decides # the Pi is offline while we are mid-deploy over the rescue AP. The hold expires # on its own after {{ labelprint_hold_max_age_secs }}s, so an aborted run cannot # leave the watchdog disabled. - name: hold the radio for the duration of this deploy become: true ansible.builtin.file: path: /run/wifi-rescue.hold state: touch owner: root group: root mode: "0644" changed_when: false tags: [labelprint, wifi] - name: install the home Wi-Fi profile become: true ansible.builtin.template: src: home-wifi.nmconnection.j2 dest: /etc/NetworkManager/system-connections/home-wifi.nmconnection owner: root group: root mode: "0600" notify: reload networkmanager connections tags: [labelprint, wifi] - name: install the rescue access point profile become: true ansible.builtin.template: src: rescue-ap.nmconnection.j2 dest: /etc/NetworkManager/system-connections/rescue-ap.nmconnection owner: root group: root mode: "0600" notify: reload networkmanager connections tags: [labelprint, wifi] # --------------------------------------------------------------------------- # Coexisting with netplan # --------------------------------------------------------------------------- # The hand-built image configures Wi-Fi through cloud-init's network-config, and # on Raspberry Pi OS trixie netplan's NetworkManager integration turns that into # a persistent profile of its own at /etc/netplan/90-NM-.yaml -- not the # /etc/netplan/50-cloud-init.yaml you would expect, and not something a # cloud-init clean removes. # # That profile is deliberately left in place. It carries the same SSID as # home-wifi, and autoconnect-priority decides between them: 100 here against # netplan's 0, so NetworkManager picks ours every time. What netplan's copy buys # is a fallback that predates anything in this role -- if home-wifi is ever # rendered wrong, the Pi still comes back on the LAN instead of stranding itself # on the rescue AP. Its PSK goes stale when the home password changes; that # costs nothing, because a stale profile simply fails and ours is tried first. # # What is worth stopping is cloud-init rewriting the network on a future # re-instance, which would put a third opinion in play. - name: stop cloud-init from rewriting the network config become: true ansible.builtin.copy: dest: /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg content: | network: {config: disabled} owner: root group: root mode: "0644" tags: [labelprint, wifi] # --------------------------------------------------------------------------- # The watchdog # --------------------------------------------------------------------------- - name: install the Wi-Fi rescue watchdog become: true ansible.builtin.template: src: wifi-rescue.sh.j2 dest: /usr/local/sbin/wifi-rescue owner: root group: root mode: "0755" tags: [labelprint, wifi] - name: install the Wi-Fi rescue units become: true ansible.builtin.template: src: "{{ item }}.j2" dest: "/etc/systemd/system/{{ item }}" owner: root group: root mode: "0644" loop: - wifi-rescue.service - wifi-rescue.timer notify: reload systemd tags: [labelprint, wifi] - name: apply pending unit changes ansible.builtin.meta: flush_handlers tags: [labelprint, wifi] - name: enable the Wi-Fi rescue watchdog become: true ansible.builtin.systemd: name: wifi-rescue.timer enabled: true state: started tags: [labelprint, wifi]